* moved JSON read writes to database.js

+ show commutative price and price per etho
+ use Roboto as the default font
+ use subscribe for new blocks to sync transactions better
This commit is contained in:
Taegus
2018-12-28 08:56:20 +01:00
parent 3315677ede
commit d33f90b738
14 changed files with 343 additions and 171 deletions

View File

@@ -1,5 +1,7 @@
html {
color: #aaa;
font-family: 'Roboto', sans-serif;
-webkit-font-smoothing: antialiased;
}
/* hide / show the body when the loader is finished */
@@ -98,19 +100,22 @@ body.pg-loaded > .inner {
#sumBalance {
float: right;
font-weight: bold;
line-height: 38px;
margin-right: 10px;
}
.modalBody {
margin: 20px;
color: #333;
}
#dlgGeneralError .modalBody {
height: 100px;
}
#dlgGeneralConfirm .modalBody {
height: 100px;
}
#dlgDeleteAddressConfirm .modalBody {
height: 100px;
}
@@ -135,6 +140,10 @@ body.pg-loaded > .inner {
background-color: #333;
}
#dlgAddressList .modalBody {
color: #aaa;
}
.btn-dialog-confirm {
position: absolute;
bottom: 10px;
@@ -240,6 +249,12 @@ div.sidebar svg {
padding-left: 20px;
}
#addressList th {
color: #ccc;
font-size: 1.1em;
font-weight: normal;
}
.sendTXInfo {
height: 30px;
}
@@ -307,12 +322,11 @@ div.sidebar svg {
background-color: #aaa;
}
.sumBalance {
color: white;
background-color: #7A1336;
border: 2px solid #991643;
border-radius: 10px;
padding: 5px;
.sumDollars,
.sumBalance,
.sumCurrency {
color: #ccc;
margin-right: 5px;
}
.cleanText {

View File

@@ -66,7 +66,9 @@ table.dataTable {
*/ }
table.dataTable thead th,
table.dataTable tfoot th {
font-weight: bold; }
color: #ccc;
font-size: 1.1em;
font-weight: normal; }
table.dataTable thead th,
table.dataTable thead td {
padding: 10px 18px;

View File

@@ -18,7 +18,7 @@
<th scope="row" class="colEdit"><button type="button" class="btn btn-etho btnChangAddressName" data-address="{{address}}" data-name="{{name}}">Edit</button></th>
<td>{{name}}</td>
<td><span class="textAddress">{{address}}</span></td>
<td><button type="button" class="btn btn-etho btnDeleteAddress" data-wallet="{{address}}"><i class="far fa-trash-alt"></i></button></td>
<td><button type="button" class="btn btn-etho btnDeleteAddress" data-address="{{address}}"><i class="far fa-trash-alt"></i></button></td>
</tr>
{{/addressData}}
</tbody>

View File

@@ -2,7 +2,10 @@
<button type="button" class="btn btn-etho" id="btnNewAddress"><i class="fas fa-plus"></i></button>
<button type="button" class="btn btn-etho" id="btnExportAccounts"><i class="fas fa-file-export"></i></button>
<button type="button" class="btn btn-etho" id="btnImportAccounts"><i class="fas fa-file-import"></i></button>
<div id="sumBalance">Total ETHO: <span class="sumBalance">{{sumBalance}}</span></div>
<div id="sumBalance">
<span class="sumBalance" id="labelSumBalance">{{sumBalance}}</span>
<span class="sumCurrency" id="labelSumCurrency">ETHO</span>
<span class="sumDollars" id="labelSumDollars">/ 0.00 $ / 0.00 $ per ETHO</span></div>
</div>
<div id="addressList" class="{{#if addressData.length}}walletsWrapper{{else}}noWalletsWrapper{{/if}}">
{{#if addressData.length}}

View File

@@ -3,6 +3,7 @@
<head>
<meta charset="UTF-8">
<title>Ether-1 Desktop Wallet</title>
<link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet">
<link rel="stylesheet" href="./assets/styles/materialize.min.css">
<link rel="stylesheet" href="./assets/styles/datatables.min.css">
<link rel="stylesheet" href="./assets/styles/iziModal.min.css">
@@ -86,6 +87,7 @@
require('./renderer/syncing.js');
require('./renderer/settings.js');
require('./renderer/wallets.js');
require('./renderer/database.js');
require('./renderer/blockchain.js');
require('./renderer/addressBook.js');
require('./renderer/transactions.js');
@@ -102,5 +104,16 @@
<button type="button" class="btn btn-etho btn-dialog-confirm" id="btnGeneralErrorOK">OK</button>
</div>
</div>
<!-- The modal for general confirmation -->
<div id="dlgGeneralConfirm" class="modalDialog" data-iziModal-title="Confirmation" data-iziModal-subtitle="" data-iziModal-icon="icon-home">
<div class="modalBody">
<div class="form-group">
<span id="txtGeneralConfirm"></span>
</div>
<button type="button" class="btn btn-etho btn-dialog-cancel" id="btnGeneralConfirmNo">No</button>
<button type="button" class="btn btn-etho btn-dialog-confirm" id="btnGeneralConfirmYes">Yes</button>
</div>
</div>
</body>
</html>

View File

@@ -5,58 +5,28 @@ class AddressBook {
}
setAddressName(address, name) {
console.log(address);
console.log(name);
var addressBook = ipcRenderer.sendSync('getJSONFile', 'addresses.json');
if (!addressBook) {
addressBook = { names: {} };
}
var addressBook = EthoDatatabse.getAddresses();
// set the wallet name from the dialog box
addressBook.names[address] = name;
ipcRenderer.sendSync('setJSONFile',
{
file: 'addresses.json',
data: addressBook
});
EthoDatatabse.setAddresses(addressBook);
}
getAddressName(address) {
var addressBook = ipcRenderer.sendSync('getJSONFile', 'addresses.json');
if (!addressBook) {
addressBook = { names: {} };
}
var addressBook = EthoDatatabse.getAddresses();
// set the wallet name from the dialog box
return addressBook.names[address] || "";
}
getAddressList() {
var addressBook = ipcRenderer.sendSync('getJSONFile', 'addresses.json');
if (!addressBook) {
addressBook = { names: {} };
}
var addressBook = EthoDatatabse.getAddresses();
return addressBook.names;
}
deleteAddress(address) {
var addressBook = ipcRenderer.sendSync('getJSONFile', 'addresses.json');
if (!addressBook) {
addressBook = { names: {} };
} else {
var addressBook = EthoDatatabse.getAddresses();
delete addressBook.names[address];
}
ipcRenderer.sendSync('setJSONFile',
{
file: 'addresses.json',
data: addressBook
});
EthoDatatabse.setAddresses(addressBook);
}
enableButtonTooltips() {
@@ -93,6 +63,9 @@ $(document).on("render_addressBook", function() {
function doCreateNewWallet() {
$('#dlgCreateAddressAndName').iziModal('close');
if (!EthoBlockchain.isAddress($("#addressHash").val())) {
EthoMainGUI.showGeneralError("Address must be a valid address!");
} else {
EthoAddressBook.setAddressName($("#addressHash").val(), $("#addressName").val());
EthoAddressBook.renderAddressBook();
@@ -102,6 +75,8 @@ $(document).on("render_addressBook", function() {
position: 'topRight',
timeout: 5000
});
}
}
$("#btnCreateAddressConfirm").off('click').on('click', function() {
@@ -141,6 +116,8 @@ $(document).on("render_addressBook", function() {
});
$(".btnDeleteAddress").off('click').on('click', function() {
var deleteAddress = $(this).attr('data-address');
$("#dlgDeleteAddressConfirm").iziModal();
$('#dlgDeleteAddressConfirm').iziModal('open');
@@ -149,8 +126,8 @@ $(document).on("render_addressBook", function() {
});
$("#btnDeleteAddressConfirm").off('click').on('click', function() {
EthoAddressBook.deleteAddress($(this).attr('data-address'));
$('#dlgDeleteAddressConfirm').iziModal('close');
EthoAddressBook.deleteAddress(deleteAddress);
EthoAddressBook.renderAddressBook();
});
});

View File

@@ -2,7 +2,10 @@
const {ipcRenderer} = require('electron');
class Blockchain {
constructor() {}
constructor() {
this.txSubscribe = null;
this.bhSubscribe = null;
}
getBlock(blockToGet, includeData, clbError, clbSuccess) {
web3Local.eth.getBlock(blockToGet, includeData, function(error, block) {
@@ -129,7 +132,7 @@ class Blockchain {
rendererData.sumBalance = 0;
rendererData.addressData = [];
var wallets = ipcRenderer.sendSync('getJSONFile', 'wallets.json');
var wallets = EthoDatatabse.getWallets();
var counter = 0;
web3Local.eth.getAccounts(function(err, res) {
@@ -178,7 +181,7 @@ class Blockchain {
var rendererData = {};
rendererData.addressData = [];
var wallets = ipcRenderer.sendSync('getJSONFile', 'wallets.json');
var wallets = EthoDatatabse.getWallets();
var counter = 0;
web3Local.eth.getAccounts(function(err, res) {
@@ -212,6 +215,54 @@ class Blockchain {
});
}
subsribePendingTransactions(clbError, clbSuccess, clbData) {
this.txSubscribe = web3Local.eth.subscribe('pendingTransactions', function(error, result){
if (error) {
clbError(error);
} else {
clbSuccess(result);
}
}).on("data", function(transaction){
if (clbData) {
clbData(transaction);
}
});
}
unsubsribePendingTransactions(clbError, clbSuccess) {
this.txSubscribe.unsubscribe(function(error, success){
if(error) {
clbError(error);
} else {
clbSuccess(success) ;
}
});
}
subsribeNewBlockHeaders(clbError, clbSuccess, clbData) {
this.bhSubscribe = web3Local.eth.subscribe('newBlockHeaders', function(error, result){
if (error) {
clbError(error);
} else {
clbSuccess(result);
}
}).on("data", function(blockHeader){
if (clbData) {
clbData(blockHeader);
}
});
}
unsubsribeNewBlockHeaders(clbError, clbSuccess) {
this.bhSubscribe.unsubscribe(function(error, success){
if(error) {
clbError(error);
} else {
clbSuccess(success) ;
}
});
}
closeConnection() {
web3Local.currentProvider.connection.close();
}

63
renderer/database.js Normal file
View File

@@ -0,0 +1,63 @@
// In renderer process (web page).
const {ipcRenderer} = require('electron');
class Datatabse {
constructor() {}
getCounters() {
var counters = ipcRenderer.sendSync('getJSONFile', 'counters.json');
if (counters == null) {
counters = {};
}
return counters;
}
setCounters(counters) {
ipcRenderer.sendSync('setJSONFile',
{
file: 'counters.json',
data: counters
});
}
getWallets() {
var wallets = ipcRenderer.sendSync('getJSONFile', 'wallets.json');
if (!wallets) {
wallets = { names: {} };
}
return wallets;
}
setWallets(wallets) {
ipcRenderer.sendSync('setJSONFile',
{
file: 'wallets.json',
data: wallets
});
}
getAddresses() {
var addressBook = ipcRenderer.sendSync('getJSONFile', 'addresses.json');
if (!addressBook) {
addressBook = { names: {} };
}
return addressBook;
}
setAddresses(addresses) {
ipcRenderer.sendSync('setJSONFile',
{
file: 'addresses.json',
data: addresses
});
}
}
// create new account variable
EthoDatatabse = new Datatabse();

View File

@@ -46,6 +46,24 @@ class MainGUI {
});
}
showGeneralConfirmation(confirmText, callback) {
$("#txtGeneralConfirm").html(confirmText);
// create and open the dialog
$("#dlgGeneralConfirm").iziModal();
$('#dlgGeneralConfirm').iziModal('open');
$("#btnGeneralConfirmYes").click(function() {
$('#dlgGeneralConfirm').iziModal('close');
callback(true);
});
$("#btnGeneralConfirmNo").click(function() {
$('#dlgGeneralConfirm').iziModal('close');
callback(false);
});
}
renderTemplate(template, data, container) {
var template = Handlebars.compile(ipcRenderer.sendSync('getTemplateContent', template));

View File

@@ -77,9 +77,20 @@ $(document).on("render_send", function() {
function(error) {
EthoMainGUI.showGeneralError(error);
},
function(data) {
function(addressList) {
var addressBook = EthoAddressBook.getAddressList();
for (var key in addressBook) {
if (addressBook.hasOwnProperty(key)) {
var adddressObject = {};
adddressObject.address = key
adddressObject.name = addressBook[key];
addressList.addressData.push(adddressObject);
}
}
$("#dlgAddressList").iziModal({ width: "800px" });
EthoMainGUI.renderTemplate("addressList.html", data, $("#dlgAddressListBody"));
EthoMainGUI.renderTemplate("addressList.html", addressList, $("#dlgAddressListBody"));
$('#dlgAddressList').iziModal('open');
$(".btnSelectToAddress").off('click').on('click', function() {

View File

@@ -12,7 +12,15 @@ class Settings {
$(document).on("render_settings", function() {
$("#btnSettingsCleanTransactions").off('click').on('click', function() {
EthoMainGUI.showGeneralError("Not implemented yet!");
EthoMainGUI.showGeneralConfirmation("Do you really want to resync transactions?", function(result) {
if (result) {
if (EthoTransactions.getIsSyncing()) {
EthoMainGUI.showGeneralError("Transactions sync is currently in progress");
} else {
EthoTransactions.disableKeepInSync();
}
}
});
});
$("#btnSettingsCleanWallets").off('click').on('click', function() {

View File

@@ -63,9 +63,13 @@ function StartSyncProcess() {
$(document).trigger("onNewAccountTransaction");
alreadyCatchedUp = true;
// enable the keep in sync feature
EthoTransactions.enableKeepInSync();
// sync all the transactions to the current block
EthoTransactions.syncTransactionsForAllAddresses(localBlock.number);
$(document).trigger("onSyncInterval");
// signal that the sync is complete
$(document).trigger("onSyncComplete");
}
}
});
@@ -75,7 +79,7 @@ function StartSyncProcess() {
}).on("data", function(sync){
if ((sync) && (sync.HighestBlock > 0)) {
SyncProgress.animate(sync.CurrentBlock / sync.HighestBlock);
SyncProgress.setText(vsprintf('%d/%d (%d%%)', [sync.CurrentBlock, sync.HighestBlock, Math.round(sync.CurrentBlock / sync.HighestBlock * 100)]));
SyncProgress.setText(vsprintf('%d/%d (%d%%)', [sync.CurrentBlock, sync.HighestBlock, Math.floor(sync.CurrentBlock / sync.HighestBlock * 100)]));
}
}).on("changed", function(isSyncing){
if(isSyncing) {
@@ -84,7 +88,7 @@ function StartSyncProcess() {
web3Local.eth.isSyncing(function(error, sync){
if ((!error) && (sync)) {
SyncProgress.animate(sync.currentBlock / sync.highestBlock);
SyncProgress.setText(vsprintf('%d/%d (%d%%)', [sync.currentBlock, sync.highestBlock, Math.round(sync.currentBlock / sync.highestBlock * 100)]));
SyncProgress.setText(vsprintf('%d/%d (%d%%)', [sync.currentBlock, sync.highestBlock, Math.floor(sync.currentBlock / sync.highestBlock * 100)]));
}
});
}, 2000);

View File

@@ -51,11 +51,7 @@ class Transactions {
} else {
// update the counter and store it back to file system
counters.transactions = lastBlock;
ipcRenderer.sendSync('setJSONFile',
{
file: 'counters.json',
data: counters
});
EthoDatatabse.setCounters(counters);
SyncProgress.setText("Syncing transactions is complete.");
EthoTransactions.setIsSyncing(false);
@@ -63,13 +59,9 @@ class Transactions {
}
syncTransactionsForAllAddresses(lastBlock) {
var counters = ipcRenderer.sendSync('getJSONFile', 'counters.json');
var counters = EthoDatatabse.getCounters();
var counter = 0;
if (counters == null) {
counters = {};
}
EthoBlockchain.getAccounts(
function(error) {
EthoMainGUI.showGeneralError(error);
@@ -109,41 +101,52 @@ class Transactions {
}, 200);
}
enableKeepInSync() {
function processTransaction(data) {
if ((EthoWallets.getAddressExists(data.from)) || (EthoWallets.getAddressExists(data.to))) {
if (data.blockNumber) {
console.log(data.blockNumber);
}
// event that tells us that geth is ready and up
$(document).on("onSyncInterval", function() {
var counters = ipcRenderer.sendSync('getJSONFile', 'counters.json');
if (counters == null) {
counters = {};
var Transaction = {
block: null,
txhash: data.hash.toLowerCase(),
fromaddr: data.from.toLowerCase(),
timestamp: moment.unix(data.timestamp).format('YYYY-MM-DD HH:mm:ss'),
toaddr: data.to.toLowerCase(),
value: Number(data.value).toExponential(5).toString().replace('+','')
}
function finalizeCounters(lastBlock) {
counters.transactions = lastBlock;
// store transaction and notify about new transactions
ipcRenderer.send('storeTransaction', Transaction);
$(document).trigger("onNewAccountTransaction");
ipcRenderer.sendSync('setJSONFile',
{
file: 'counters.json',
data: counters
iziToast.info({
title: 'New Transaction',
message: vsprintf('Transaction from address %s to address %s was just processed', [Transaction.fromaddr, Transaction.toaddr]),
position: 'topRight',
timeout: 10000
});
// render transactions again to show latest
if (EthoMainGUI.getAppState() == "transactions") {
setTimeout(function() {
EthoTransactions.renderTransactions();
}, 500);
}
}
}
function doSyncRemainingBlocks() {
EthoBlockchain.getBlock("latest", false,
EthoBlockchain.subsribeNewBlockHeaders(
function(error) {
EthoMainGUI.showGeneralError(error);
},
function(block) {
var lastBlock = counters.transactions || 1;
if (lastBlock < block.number) {
function getNextBlockTransactions(blockNumber, maxBlock) {
if (blockNumber < maxBlock) {
EthoBlockchain.getBlock(blockNumber, true,
function(data)
{
EthoBlockchain.getBlock(data.number, true,
function(error) {
EthoMainGUI.showGeneralError(error);
getNextBlockTransactions(blockNumber + 1 , maxBlock);
},
function(data) {
if (data.transactions) {
@@ -168,40 +171,32 @@ $(document).on("onSyncInterval", function() {
position: 'topRight',
timeout: 10000
});
if (EthoMainGUI.getAppState() == "transactions") {
setTimeout(function() {
EthoTransactions.renderTransactions();
}, 500);
}
}
});
}
// call the next iteration for the next block
getNextBlockTransactions(blockNumber + 1 , maxBlock);
}
);
} else {
finalizeCounters(blockNumber);
setTimeout(function() {
doSyncRemainingBlocks();
}, 10000);
}
}
// call initial call of function
getNextBlockTransactions(lastBlock, block.number);
} else {
finalizeCounters(lastBlock);
setTimeout(function() {
doSyncRemainingBlocks();
}, 10000);
}
}
);
}
);
}
// do the initial sync
doSyncRemainingBlocks();
});
disableKeepInSync() {
EthoBlockchain.unsubsribeNewBlockHeaders(
function(error) {
EthoMainGUI.showGeneralError(error);
},
function(data) {
// success
}
);
}
}
// create new transactions variable
EthoTransactions = new Transactions();

View File

@@ -3,6 +3,19 @@ const {ipcRenderer} = require('electron');
class Wallets {
constructor() {
this.addressList = [];
$.getJSON("https://min-api.cryptocompare.com/data/price?fsym=ETHO&tsyms=USD", function( price )
{
EthoWallets._setPrice(price.USD);
});
}
_getPrice() {
return this.price;
}
_setPrice(price) {
this.price = price;
}
getAddressList() {
@@ -14,12 +27,18 @@ class Wallets {
}
getAddressExists(address) {
if (address) {
return this.addressList.indexOf(address.toLowerCase()) > -1;
} else {
return false;
}
}
addAddressToList(address) {
if (address) {
this.addressList.push(address.toLowerCase());
}
}
enableButtonTooltips() {
EthoUtils.createToolTip("#btnNewAddress", "Create New Address");
@@ -67,6 +86,8 @@ renderWalletsState() {
EthoMainGUI.renderTemplate("wallets.html", data);
$(document).trigger("render_wallets");
EthoWallets.enableButtonTooltips();
$("#labelSumDollars").html(vsprintf("/ %.2f $ / %.4f $ per ETHO", [data.sumBalance * EthoWallets._getPrice(), EthoWallets._getPrice()]));
}
);
}
@@ -131,19 +152,11 @@ $(document).on("render_wallets", function() {
$('#dlgChangeWalletName').iziModal('open');
function doChangeWalletName() {
var wallets = ipcRenderer.sendSync('getJSONFile', 'wallets.json');
if (!wallets) {
wallets = { names: {} };
}
var wallets = EthoDatatabse.getWallets();
// set the wallet name from the dialog box
wallets.names[walletAddress] = $("#inputWalletName").val();
ipcRenderer.sendSync('setJSONFile',
{
file: 'wallets.json',
data: wallets
});
EthoDatatabse.setWallets(wallets);
$('#dlgChangeWalletName').iziModal('close');
EthoWallets.renderWalletsState();