diff --git a/core/language/us.json b/core/language/us.json index 8676082d..bc27604e 100644 --- a/core/language/us.json +++ b/core/language/us.json @@ -398,7 +398,8 @@ "wchange56": "WARNING!", "wchange57": "Memo", "wchange58": "New Address", - "wchange59": "Coin" + "wchange59": "Coin", + "wchange60": "Reload txs" }, "tradepage": { "tchange1": "Trade Portal", diff --git a/core/src/components/app-view.js b/core/src/components/app-view.js index 1bf6a5fa..ff27a441 100644 --- a/core/src/components/app-view.js +++ b/core/src/components/app-view.js @@ -46,6 +46,7 @@ import './notification-view/notification-bell-general.js' import './friends-view/friends-side-panel-parent.js' import './friends-view/save-settings-qdn.js' import './friends-view/core-sync-status.js' +import './controllers/coin-balances-controller.js' const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) class AppView extends connect(store)(LitElement) { @@ -675,7 +676,7 @@ class AppView extends connect(store)(LitElement) {
- + ` } diff --git a/core/src/components/controllers/coin-balances-controller.js b/core/src/components/controllers/coin-balances-controller.js new file mode 100644 index 00000000..d07c7c5a --- /dev/null +++ b/core/src/components/controllers/coin-balances-controller.js @@ -0,0 +1,326 @@ +import { LitElement, html, css } from 'lit'; +import '@material/mwc-icon'; +import { store } from '../../store'; +import { connect } from 'pwa-helpers'; +import '@vaadin/tooltip'; +import { get } from 'lit-translate'; +import { parentEpml } from '../show-plugin'; +import { setCoinBalances } from '../../redux/app/app-actions'; + +class CoinBalancesController extends connect(store)(LitElement) { + static get properties() { + return { + coinList: { type: Object }, + }; + } + + constructor() { + super(); + this.coinList = {} + this.nodeUrl = this.getNodeUrl(); + this.myNode = this.getMyNode(); + this.fetchBalance = this.fetchBalance.bind(this) + this._updateCoinList = this._updateCoinList.bind(this) + this.stop = false + } + + getNodeUrl() { + const myNode = + store.getState().app.nodeConfig.knownNodes[ + store.getState().app.nodeConfig.node + ]; + + const nodeUrl = + myNode.protocol + '://' + myNode.domain + ':' + myNode.port; + return nodeUrl; + } + getMyNode() { + const myNode = + store.getState().app.nodeConfig.knownNodes[ + store.getState().app.nodeConfig.node + ]; + + return myNode; + } + + + async updateArrrWalletBalance() { + let _url = `/crosschain/arrr/walletbalance?apiKey=${this.myNode.apiKey}` + let _body = store.getState().app.selectedAddress.arrrWallet.seed58 + + await parentEpml.request('apiCall', { + url: _url, + method: 'POST', + body: _body, + }).then((res) => { + if (isNaN(Number(res))) { + //... + } else { + this.arrrWalletBalance = (Number(res) / 1e8).toFixed(8) + store.dispatch( + setCoinBalances({ + type: 'arrr', + fullValue: Number(res) + }) + ); + } + }).catch(()=> { + console.log('error') + }) + } + async updateQortWalletBalance() { + let qortAddress = store.getState().app.selectedAddress.address + + await parentEpml.request('apiCall', { + url: `/addresses/balance/${qortAddress}?apiKey=${this.myNode.apiKey}`, + }).then((res) => { + this.qortWalletBalance = res + store.dispatch( + setCoinBalances({ + type: 'qort', + fullValue: Number(res) + }) + ); + }).catch(()=> { + console.log('error') + }) + } + + async updateRvnWalletBalance() { + let _url = `/crosschain/rvn/walletbalance?apiKey=${this.myNode.apiKey}` + let _body = store.getState().app.selectedAddress.rvnWallet.derivedMasterPublicKey + + await parentEpml.request('apiCall', { + url: _url, + method: 'POST', + body: _body, + }).then((res) => { + if (isNaN(Number(res))) { + //... + } else { + this.rvnWalletBalance = (Number(res) / 1e8).toFixed(8) + store.dispatch( + setCoinBalances({ + type: 'rvn', + fullValue: Number(res) + }) + ); + } + }).catch(()=> { + console.log('error') + }) + } + + async updateDgbWalletBalance() { + let _url = `/crosschain/dgb/walletbalance?apiKey=${this.myNode.apiKey}` + let _body = store.getState().app.selectedAddress.dgbWallet.derivedMasterPublicKey + + await parentEpml.request('apiCall', { + url: _url, + method: 'POST', + body: _body, + }).then((res) => { + if (isNaN(Number(res))) { + //... + } else { + this.dgbWalletBalance = (Number(res) / 1e8).toFixed(8) + store.dispatch( + setCoinBalances({ + type: 'dgb', + fullValue: Number(res) + }) + ); + } + }).catch(()=> { + console.log('error') + }) + } + + async updateDogeWalletBalance() { + let _url = `/crosschain/doge/walletbalance?apiKey=${this.myNode.apiKey}` + let _body = store.getState().app.selectedAddress.dogeWallet.derivedMasterPublicKey + + await parentEpml.request('apiCall', { + url: _url, + method: 'POST', + body: _body, + }).then((res) => { + if (isNaN(Number(res))) { + //... + } else { + this.dogeWalletBalance = (Number(res) / 1e8).toFixed(8) + store.dispatch( + setCoinBalances({ + type: 'doge', + fullValue: Number(res) + }) + ); + } + }).catch(()=> { + console.log('error') + }) + } + + async updateBtcWalletBalance() { + let _url = `/crosschain/btc/walletbalance?apiKey=${this.myNode.apiKey}` + let _body = store.getState().app.selectedAddress.btcWallet.derivedMasterPublicKey + + await parentEpml.request('apiCall', { + url: _url, + method: 'POST', + body: _body, + }).then((res) => { + if (isNaN(Number(res))) { + //... + } else { + this.btcWalletBalance = (Number(res) / 1e8).toFixed(8) + store.dispatch( + setCoinBalances({ + type: 'btc', + fullValue: Number(res) + }) + ); + } + }).catch(()=> { + console.log('error') + }) + } + + async updateLtcWalletBalance() { + let _url = `/crosschain/ltc/walletbalance?apiKey=${this.myNode.apiKey}` + let _body = store.getState().app.selectedAddress.ltcWallet.derivedMasterPublicKey + + await parentEpml.request('apiCall', { + url: _url, + method: 'POST', + body: _body, + }).then((res) => { + if (isNaN(Number(res))) { + //... + } else { + this.ltcWalletBalance = (Number(res) / 1e8).toFixed(8) + store.dispatch( + setCoinBalances({ + type: 'ltc', + fullValue: Number(res) + }) + ); + + } + }).catch(()=> { + console.log('error') + }) + } + + _updateCoinList(event) { + const copyCoinList = {...this.coinList} + const coin = event.detail + if(!copyCoinList[coin]){ + try { + if(coin === 'ltc'){ + this.updateLtcWalletBalance() + } else if(coin === 'qort'){ + this.updateQortWalletBalance() + } else if(coin === 'doge'){ + this.updateDogeWalletBalance() + } else if(coin === 'btc'){ + this.updateBtcWalletBalance() + } else if(coin === 'dgb'){ + this.updateDgbWalletBalance() + } else if(coin === 'rvn'){ + this.updateRvnWalletBalance() + }else if(coin === 'arrr'){ + this.updateArrrWalletBalance() + } + } catch (error) { + + } + } + copyCoinList[coin] = Date.now() + 120000; + this.coinList = copyCoinList + + this.requestUpdate() + } + + + async fetchCoins(arrayOfCoins){ + const getCoinBalances = (arrayOfCoins || []).map( + async (coin) => { + if(coin === 'ltc'){ + await this.updateLtcWalletBalance() + } else if(coin === 'qort'){ + this.updateQortWalletBalance() + } else if(coin === 'doge'){ + this.updateDogeWalletBalance() + } else if(coin === 'btc'){ + this.updateBtcWalletBalance() + } else if(coin === 'dgb'){ + this.updateDgbWalletBalance() + } else if(coin === 'rvn'){ + this.updateRvnWalletBalance() + }else if(coin === 'arrr'){ + this.updateArrrWalletBalance() + } + }) + + await Promise.all(getCoinBalances); + + } + + async fetchBalance(){ + try { + let arrayOfCoins = [] + const copyObject = {...this.coinList} + const currentDate = Date.now() + const array = Object.keys(this.coinList) + for (const key of array) { + const item = this.coinList[key] + + if(item < currentDate){ + delete copyObject[key] + } else { + arrayOfCoins.push(key) + } + } + if(!this.stop){ + this.stop = true + await this.fetchCoins(arrayOfCoins) + this.stop = false + } + this.coinList = copyObject + } catch (error) { + this.stop = false + } + } + + connectedCallback() { + super.connectedCallback(); + this.intervalID = setInterval(this.fetchBalance, 45000); + window.addEventListener( + 'ping-coin-controller-with-coin', + this._updateCoinList + ); + } + + disconnectedCallback() { + + super.disconnectedCallback(); + window.removeEventListener( + 'ping-coin-controller-with-coin', + this._updateCoinList + ); + if(this.intervalID){ + clearInterval(this.intervalID); + + } + + } + + + + render() { + return html``; + } +} + +customElements.define('coin-balances-controller', CoinBalancesController); diff --git a/core/src/components/friends-view/friends-view.js b/core/src/components/friends-view/friends-view.js index ab90fe32..fd4f8acc 100644 --- a/core/src/components/friends-view/friends-view.js +++ b/core/src/components/friends-view/friends-view.js @@ -114,16 +114,13 @@ class FriendsView extends connect(store)(LitElement) { this.friendList = detail } _updateFeed(event) { - console.log({event}) const detail = event.detail - console.log({detail}) this.mySelectedFeeds = detail this.requestUpdate() } connectedCallback() { super.connectedCallback() - console.log('callback') window.addEventListener('friends-my-friend-list-event', this._updateFriends) window.addEventListener('friends-my-selected-feeds-event', this._updateFeed) } @@ -317,7 +314,6 @@ class FriendsView extends connect(store)(LitElement) { } render() { - console.log('rendered1') return html`
diff --git a/core/src/plugins/streams.js b/core/src/plugins/streams.js index bc4bae3a..aae100e1 100644 --- a/core/src/plugins/streams.js +++ b/core/src/plugins/streams.js @@ -9,6 +9,7 @@ const CHAT_HEADS_STREAM_NAME = 'chat_heads' const NODE_CONFIG_STREAM_NAME = 'node_config' const CHAT_LAST_SEEN = 'chat_last_seen' const SIDE_EFFECT_ACTION = 'side_effect_action' +const COIN_BALANCES_ACTION = 'coin_balances' export const loggedInStream = new EpmlStream(LOGIN_STREAM_NAME, () => store.getState().app.loggedIn) export const configStream = new EpmlStream(CONFIG_STREAM_NAME, () => store.getState().config) @@ -18,6 +19,8 @@ export const chatHeadsStateStream = new EpmlStream(CHAT_HEADS_STREAM_NAME, () => export const nodeConfigStream = new EpmlStream(NODE_CONFIG_STREAM_NAME, () => store.getState().app.nodeConfig) export const chatLastSeenStream = new EpmlStream(CHAT_LAST_SEEN, () => store.getState().app.chatLastSeen) export const sideEffectActionStream = new EpmlStream(SIDE_EFFECT_ACTION, () => store.getState().app.sideEffectAction) +export const coinBalancesActionStream = new EpmlStream(COIN_BALANCES_ACTION, () => store.getState().app.coinBalances) + @@ -62,6 +65,9 @@ store.subscribe(() => { if (oldState.app.sideEffectAction !== state.app.sideEffectAction) { sideEffectActionStream.emit(state.app.sideEffectAction) } + if (oldState.app.coinBalances !== state.app.coinBalances) { + coinBalancesActionStream.emit(state.app.coinBalances) + } oldState = state diff --git a/core/src/redux/app/actions/app-core.js b/core/src/redux/app/actions/app-core.js index fa2e8380..53e9d547 100644 --- a/core/src/redux/app/actions/app-core.js +++ b/core/src/redux/app/actions/app-core.js @@ -1,5 +1,5 @@ // Core App Actions here... -import { UPDATE_BLOCK_INFO, UPDATE_NODE_STATUS, UPDATE_NODE_INFO, CHAT_HEADS, ACCOUNT_INFO, ADD_AUTO_LOAD_IMAGES_CHAT, REMOVE_AUTO_LOAD_IMAGES_CHAT, ALLOW_QAPP_AUTO_AUTH, REMOVE_QAPP_AUTO_AUTH, SET_CHAT_LAST_SEEN, ADD_CHAT_LAST_SEEN, ALLOW_QAPP_AUTO_LISTS, REMOVE_QAPP_AUTO_LISTS, SET_NEW_TAB, ADD_TAB_INFO, SET_TAB_NOTIFICATIONS, IS_OPEN_DEV_DIALOG, SET_NEW_NOTIFICATION, SET_SIDE_EFFECT } from '../app-action-types.js' +import { UPDATE_BLOCK_INFO, UPDATE_NODE_STATUS, UPDATE_NODE_INFO, CHAT_HEADS, ACCOUNT_INFO, ADD_AUTO_LOAD_IMAGES_CHAT, REMOVE_AUTO_LOAD_IMAGES_CHAT, ALLOW_QAPP_AUTO_AUTH, REMOVE_QAPP_AUTO_AUTH, SET_CHAT_LAST_SEEN, ADD_CHAT_LAST_SEEN, ALLOW_QAPP_AUTO_LISTS, REMOVE_QAPP_AUTO_LISTS, SET_NEW_TAB, ADD_TAB_INFO, SET_TAB_NOTIFICATIONS, IS_OPEN_DEV_DIALOG, SET_NEW_NOTIFICATION, SET_SIDE_EFFECT, SET_COIN_BALANCES } from '../app-action-types.js' export const doUpdateBlockInfo = (blockObj) => { return (dispatch, getState) => { @@ -157,4 +157,11 @@ export const setSideEffectAction = (payload)=> { type: SET_SIDE_EFFECT, payload } +} + +export const setCoinBalances = (payload)=> { + return { + type: SET_COIN_BALANCES, + payload + } } \ No newline at end of file diff --git a/core/src/redux/app/app-action-types.js b/core/src/redux/app/app-action-types.js index fd5e06f7..97165152 100644 --- a/core/src/redux/app/app-action-types.js +++ b/core/src/redux/app/app-action-types.js @@ -33,3 +33,4 @@ export const SET_TAB_NOTIFICATIONS = 'SET_TAB_NOTIFICATIONS' export const IS_OPEN_DEV_DIALOG = 'IS_OPEN_DEV_DIALOG' export const SET_NEW_NOTIFICATION = 'SET_NEW_NOTIFICATION' export const SET_SIDE_EFFECT= 'SET_SIDE_EFFECT' +export const SET_COIN_BALANCES= 'SET_COIN_BALANCES' diff --git a/core/src/redux/app/app-reducer.js b/core/src/redux/app/app-reducer.js index f7ce35a2..e67826dd 100644 --- a/core/src/redux/app/app-reducer.js +++ b/core/src/redux/app/app-reducer.js @@ -1,6 +1,6 @@ // Loading state, login state, isNavDrawOpen state etc. None of this needs to be saved to localstorage. import { loadStateFromLocalStorage, saveStateToLocalStorage } from '../../localStorageHelpers.js' -import { LOG_IN, LOG_OUT, NETWORK_CONNECTION_STATUS, INIT_WORKERS, ADD_PLUGIN_URL, ADD_PLUGIN, ADD_NEW_PLUGIN_URL, NAVIGATE, SELECT_ADDRESS, ACCOUNT_INFO, CHAT_HEADS, UPDATE_BLOCK_INFO, UPDATE_NODE_STATUS, UPDATE_NODE_INFO, LOAD_NODE_CONFIG, SET_NODE, ADD_NODE, PAGE_URL, ADD_AUTO_LOAD_IMAGES_CHAT, REMOVE_AUTO_LOAD_IMAGES_CHAT, ALLOW_QAPP_AUTO_AUTH, REMOVE_QAPP_AUTO_AUTH, SET_CHAT_LAST_SEEN, ADD_CHAT_LAST_SEEN, ALLOW_QAPP_AUTO_LISTS, REMOVE_QAPP_AUTO_LISTS, SET_NEW_TAB, ADD_TAB_INFO, SET_TAB_NOTIFICATIONS, IS_OPEN_DEV_DIALOG, REMOVE_NODE, EDIT_NODE, SET_NEW_NOTIFICATION, SET_SIDE_EFFECT } from './app-action-types.js' +import { LOG_IN, LOG_OUT, NETWORK_CONNECTION_STATUS, INIT_WORKERS, ADD_PLUGIN_URL, ADD_PLUGIN, ADD_NEW_PLUGIN_URL, NAVIGATE, SELECT_ADDRESS, ACCOUNT_INFO, CHAT_HEADS, UPDATE_BLOCK_INFO, UPDATE_NODE_STATUS, UPDATE_NODE_INFO, LOAD_NODE_CONFIG, SET_NODE, ADD_NODE, PAGE_URL, ADD_AUTO_LOAD_IMAGES_CHAT, REMOVE_AUTO_LOAD_IMAGES_CHAT, ALLOW_QAPP_AUTO_AUTH, REMOVE_QAPP_AUTO_AUTH, SET_CHAT_LAST_SEEN, ADD_CHAT_LAST_SEEN, ALLOW_QAPP_AUTO_LISTS, REMOVE_QAPP_AUTO_LISTS, SET_NEW_TAB, ADD_TAB_INFO, SET_TAB_NOTIFICATIONS, IS_OPEN_DEV_DIALOG, REMOVE_NODE, EDIT_NODE, SET_NEW_NOTIFICATION, SET_SIDE_EFFECT, SET_COIN_BALANCES } from './app-action-types.js' import { initWorkersReducer } from './reducers/init-workers.js' import { loginReducer } from './reducers/login-reducer.js' import { setNode, addNode, removeNode, editNode } from './reducers/manage-node.js' @@ -52,7 +52,8 @@ const INITIAL_STATE = { tabInfo: {}, isOpenDevDialog: false, newNotification: null, - sideEffectAction: null + sideEffectAction: null, + coinBalances: {} } export default (state = INITIAL_STATE, action) => { @@ -293,6 +294,17 @@ export default (state = INITIAL_STATE, action) => { sideEffectAction: action.payload } } + case SET_COIN_BALANCES: { + const copyBalances = {...state.coinBalances} + copyBalances[action.payload.type] = { + value: action.payload.value, + fullValue: action.payload.fullValue + } + return { + ...state, + coinBalances: copyBalances + } + } default: return state diff --git a/plugins/plugins/core/trade-portal/trade-portal.src.js b/plugins/plugins/core/trade-portal/trade-portal.src.js index 5d9b91b1..335cdfd3 100644 --- a/plugins/plugins/core/trade-portal/trade-portal.src.js +++ b/plugins/plugins/core/trade-portal/trade-portal.src.js @@ -904,6 +904,7 @@ class TradePortal extends LitElement { this.myTradeLockScreenPass = '' this.myTradeLockScreenSet = '' this.tradeHelperMessage = '' + this.pingCoinBalancesController = this.pingCoinBalancesController.bind(this) } historicTradesTemplate() { @@ -1416,6 +1417,52 @@ class TradePortal extends LitElement { ` } + pingCoinBalancesController(){ + if(!this.selectedCoin) return + let coin = '' + switch (this.selectedCoin) { + case 'BITCOIN': + coin ='btc' + break + case 'LITECOIN': + coin = 'ltc' + break + case 'DOGECOIN': + coin = 'doge' + break + case 'DIGIBYTE': + coin = 'dgb' + break + case 'RAVENCOIN': + coin = 'rnv' + break + case 'PIRATECHAIN': + coin = 'arrr' + break + default: + break + } + const customEvent = new CustomEvent('ping-coin-controller-with-coin', { + detail: coin + }); + window.parent.dispatchEvent(customEvent); + } + + connectedCallback() { + super.connectedCallback(); + this.intervalID = setInterval(this.pingCoinBalancesController, 30000); + + } + + disconnectedCallback() { + + super.disconnectedCallback(); + if(this.intervalID){ + clearInterval(this.intervalID); + + } + } + firstUpdated() { let _this = this @@ -1585,7 +1632,6 @@ class TradePortal extends LitElement { this.dgbWallet = window.parent.reduxStore.getState().app.selectedAddress.dgbWallet.address this.rvnWallet = window.parent.reduxStore.getState().app.selectedAddress.rvnWallet.address this.arrrWallet = window.parent.reduxStore.getState().app.selectedAddress.arrrWallet.address - this.updateAccountBalance() }) @@ -1602,6 +1648,41 @@ class TradePortal extends LitElement { } this.config = JSON.parse(c) }) + parentEpml.subscribe('coin_balances', async (payload) => { + const coinBalances = JSON.parse(payload) + let coin = '' + switch (this.selectedCoin) { + case 'BITCOIN': + coin ='btc' + break + case 'LITECOIN': + coin = 'ltc' + break + case 'DOGECOIN': + coin = 'doge' + break + case 'DIGIBYTE': + coin = 'dgb' + break + case 'RAVENCOIN': + coin = 'rnv' + break + case 'PIRATECHAIN': + coin = 'arrr' + break + default: + break + } + if(coinBalances[coin]){ + const res = coinBalances[coin].fullValue + let value = (Number(res) / 1e8).toFixed(8) + if(coin !== 'qort'){ + value = (Number(res) / 1e8).toFixed(8) + } + this.listedCoins.get(this.selectedCoin).balance = value + this.requestUpdate() + } + }) let coinSelectionMenu = this.shadowRoot.getElementById("coinSelectionMenu") diff --git a/plugins/plugins/core/wallet/wallet-app.src.js b/plugins/plugins/core/wallet/wallet-app.src.js index 5199d62e..2e4dce96 100644 --- a/plugins/plugins/core/wallet/wallet-app.src.js +++ b/plugins/plugins/core/wallet/wallet-app.src.js @@ -866,7 +866,22 @@ class MultiWallet extends LitElement { this.wallets.get('rvn').wallet = window.parent.reduxStore.getState().app.selectedAddress.rvnWallet this.wallets.get('arrr').wallet = window.parent.reduxStore.getState().app.selectedAddress.arrrWallet }) + parentEpml.subscribe('coin_balances', async (payload) => { + const coinBalances = JSON.parse(payload) + if(coinBalances[this._selectedWallet]){ + const res = coinBalances[this._selectedWallet].fullValue + let value = Number(res).toFixed(8) + if(this._selectedWallet !== 'qort'){ + value = (Number(res) / 1e8).toFixed(8) + } + this.wallets.get(this._selectedWallet).balance = value + this.balanceString = this.wallets.get(this._selectedWallet).balance + " " + this._selectedWallet.toLocaleUpperCase() + this.balance = this.wallets.get(this._selectedWallet).balance + } + }) }) + + this.pingCoinBalancesController = this.pingCoinBalancesController.bind(this) } render() { @@ -939,6 +954,9 @@ class MultiWallet extends LitElement {
+
+ this.fetchWalletDetails(this._selectedWallet)}> ${translate("walletpage.wchange60")} +
${this.loading ? html`` : ''}
@@ -2821,6 +2839,7 @@ class MultiWallet extends LitElement { } firstUpdated() { + this.changeTheme() this.changeLanguage() this.paymentFee() @@ -2936,6 +2955,30 @@ class MultiWallet extends LitElement { } } + + pingCoinBalancesController(){ + if(!this._selectedWallet) return + const customEvent = new CustomEvent('ping-coin-controller-with-coin', { + detail: this._selectedWallet + }); + window.parent.dispatchEvent(customEvent); + } + + connectedCallback() { + super.connectedCallback(); + this.intervalID = setInterval(this.pingCoinBalancesController, 30000); + + } + + disconnectedCallback() { + + super.disconnectedCallback(); + if(this.intervalID){ + clearInterval(this.intervalID); + + } + } + renderWalletLockButton() { if (this.myWalletLockScreenPass === false && this.myWalletLockScreenSet === false) { return html`