import {Component, OnInit, NgZone, Renderer2, OnDestroy, ViewChild} from '@angular/core'; import {HttpClient} from '@angular/common/http'; import {TranslateService} from '@ngx-translate/core'; import {BackendService} from './_helpers/services/backend.service'; import {Router} from '@angular/router'; import {VariablesService} from './_helpers/services/variables.service'; import {ContextMenuComponent} from 'ngx-contextmenu'; import {IntToMoneyPipe} from './_helpers/pipes/int-to-money.pipe'; import {BigNumber} from 'bignumber.js'; import {ModalService} from './_helpers/services/modal.service'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'] }) export class AppComponent implements OnInit, OnDestroy { intervalUpdateContractsState; expMedTsEvent; onQuitRequest = false; firstOnlineState = false; translateUsed = false; needOpenWallets = []; @ViewChild('allContextMenu') public allContextMenu: ContextMenuComponent; @ViewChild('onlyCopyContextMenu') public onlyCopyContextMenu: ContextMenuComponent; constructor( private http: HttpClient, private renderer: Renderer2, public translate: TranslateService, private backend: BackendService, private router: Router, public variablesService: VariablesService, private ngZone: NgZone, private intToMoneyPipe: IntToMoneyPipe, private modalService: ModalService ) { translate.addLangs(['en', 'fr']); translate.setDefaultLang('en'); // const browserLang = translate.getBrowserLang(); // translate.use(browserLang.match(/en|fr/) ? browserLang : 'en'); translate.use('en').subscribe(() => { this.translateUsed = true; }); } setBackendLocalization() { if (this.translateUsed) { const stringsArray = [ this.translate.instant('BACKEND_LOCALIZATION.QUIT'), this.translate.instant('BACKEND_LOCALIZATION.IS_RECEIVED'), this.translate.instant('BACKEND_LOCALIZATION.IS_CONFIRMED'), this.translate.instant('BACKEND_LOCALIZATION.INCOME_TRANSFER_UNCONFIRMED'), this.translate.instant('BACKEND_LOCALIZATION.INCOME_TRANSFER_CONFIRMED'), this.translate.instant('BACKEND_LOCALIZATION.MINED'), this.translate.instant('BACKEND_LOCALIZATION.LOCKED'), this.translate.instant('BACKEND_LOCALIZATION.IS_MINIMIZE'), this.translate.instant('BACKEND_LOCALIZATION.RESTORE'), this.translate.instant('BACKEND_LOCALIZATION.TRAY_MENU_SHOW'), this.translate.instant('BACKEND_LOCALIZATION.TRAY_MENU_MINIMIZE') ]; this.backend.setBackendLocalization(stringsArray, 'en'); } else { console.warn('wait translate use'); setTimeout(() => { this.setBackendLocalization(); }, 10000); } } ngOnInit() { this.variablesService.allContextMenu = this.allContextMenu; this.variablesService.onlyCopyContextMenu = this.onlyCopyContextMenu; this.backend.initService().subscribe(initMessage => { console.log('Init message: ', initMessage); this.backend.webkitLaunchedScript(); this.backend.start_backend(false, '127.0.0.1', 11512, (st2, dd2) => { console.log(st2, dd2); }); this.backend.eventSubscribe('quit_requested', () => { if (!this.onQuitRequest) { this.ngZone.run(() => { this.router.navigate(['/']); }); this.needOpenWallets = []; this.variablesService.daemon_state = 5; const saveFunction = () => { this.backend.storeAppData(() => { const recursionCloseWallets = () => { if (this.variablesService.wallets.length) { const lastIndex = this.variablesService.wallets.length - 1; this.backend.closeWallet(this.variablesService.wallets[lastIndex].wallet_id, () => { this.variablesService.wallets.splice(lastIndex, 1); recursionCloseWallets(); }); } else { this.backend.quitRequest(); } }; recursionCloseWallets(); }); }; if (this.variablesService.appPass) { this.backend.storeSecureAppData(() => { saveFunction(); }); } else { saveFunction(); } } this.onQuitRequest = true; }); this.backend.eventSubscribe('update_wallet_status', (data) => { console.log('----------------- update_wallet_status -----------------'); console.log(data); const wallet_state = data.wallet_state; const is_mining = data.is_mining; const wallet = this.variablesService.getWallet(data.wallet_id); // 1-synch, 2-ready, 3 - error if (wallet) { this.ngZone.run(() => { wallet.loaded = false; wallet.staking = is_mining; if (wallet_state === 2) { // ready wallet.loaded = true; } if (wallet_state === 3) { // error // wallet.error = true; } wallet.balance = data.balance; wallet.unlocked_balance = data.unlocked_balance; wallet.mined_total = data.minied_total; wallet.alias_available = data.is_alias_operations_available; }); } }); this.backend.eventSubscribe('wallet_sync_progress', (data) => { console.log('----------------- wallet_sync_progress -----------------'); console.log(data); const wallet = this.variablesService.getWallet(data.wallet_id); if (wallet) { this.ngZone.run(() => { wallet.progress = (data.progress < 0) ? 0 : ((data.progress > 100) ? 100 : data.progress); if (wallet.progress === 0) { wallet.loaded = false; } else if (wallet.progress === 100) { wallet.loaded = true; } }); } }); this.backend.eventSubscribe('update_daemon_state', (data) => { console.log('----------------- update_daemon_state -----------------'); console.log('DAEMON:' + data.daemon_network_state); console.log(data); // this.variablesService.exp_med_ts = data['expiration_median_timestamp'] + 600 + 1; this.variablesService.setExpMedTs(data['expiration_median_timestamp'] + 600 + 1); this.variablesService.net_time_delta_median = data.net_time_delta_median; this.variablesService.last_build_available = data.last_build_available; this.variablesService.last_build_displaymode = data.last_build_displaymode; this.variablesService.setHeightApp(data.height); this.ngZone.run(() => { this.variablesService.daemon_state = data['daemon_network_state']; if (data['daemon_network_state'] === 1) { const max = data['max_net_seen_height'] - data['synchronization_start_height']; const current = data.height - data['synchronization_start_height']; const return_val = Math.floor((current * 100 / max) * 100) / 100; if (max === 0 || return_val < 0) { this.variablesService.sync.progress_value = 0; this.variablesService.sync.progress_value_text = '0.00'; } else if (return_val >= 100) { this.variablesService.sync.progress_value = 100; this.variablesService.sync.progress_value_text = '99.99'; } else { this.variablesService.sync.progress_value = return_val; this.variablesService.sync.progress_value_text = return_val.toFixed(2); } } }); if (!this.firstOnlineState && data['daemon_network_state'] === 2) { this.getAliases(); this.backend.getContactAlias(); this.backend.getDefaultFee((status_fee, data_fee) => { this.variablesService.default_fee_big = new BigNumber(data_fee); this.variablesService.default_fee = this.intToMoneyPipe.transform(data_fee); }); this.firstOnlineState = true; } }); this.backend.eventSubscribe('money_transfer', (data) => { console.log('----------------- money_transfer -----------------'); console.log(data); if (!data.ti) { return; } const wallet_id = data.wallet_id; const tr_info = data.ti; const wallet = this.variablesService.getWallet(wallet_id); if (wallet) { this.ngZone.run(() => { if (!wallet.loaded) { wallet.balance = data.balance; wallet.unlocked_balance = data.unlocked_balance; } else { wallet.balance = data.balance; wallet.unlocked_balance = data.unlocked_balance; } if (tr_info.tx_type === 6) { this.variablesService.setRefreshStacking(wallet_id); } let tr_exists = wallet.excluded_history.some(elem => elem.tx_hash === tr_info.tx_hash); tr_exists = (!tr_exists) ? wallet.history.some(elem => elem.tx_hash === tr_info.tx_hash) : tr_exists; wallet.prepareHistory([tr_info]); if (tr_info.hasOwnProperty('contract')) { const exp_med_ts = this.variablesService.exp_med_ts; const height_app = this.variablesService.height_app; const contract = tr_info.contract[0]; if (tr_exists) { for (let i = 0; i < wallet.contracts.length; i++) { if (wallet.contracts[i].contract_id === contract.contract_id && wallet.contracts[i].is_a === contract.is_a) { wallet.contracts[i].cancel_expiration_time = contract.cancel_expiration_time; wallet.contracts[i].expiration_time = contract.expiration_time; wallet.contracts[i].height = contract.height; wallet.contracts[i].timestamp = contract.timestamp; break; } } // $rootScope.getContractsRecount(); return; } if (contract.state === 1 && contract.expiration_time < exp_med_ts) { contract.state = 110; } else if (contract.state === 5 && contract.cancel_expiration_time < exp_med_ts) { contract.state = 130; } else if (contract.state === 1) { const searchResult2 = this.variablesService.settings.notViewedContracts.find(elem => elem.state === 110 && elem.is_a === contract.is_a && elem.contract_id === contract.contract_id); if (searchResult2) { if (searchResult2.time === contract.expiration_time) { contract.state = 110; } else { for (let j = 0; j < this.variablesService.settings.notViewedContracts.length; j++) { if (this.variablesService.settings.notViewedContracts[j].contract_id === contract.contract_id && this.variablesService.settings.notViewedContracts[j].is_a === contract.is_a) { this.variablesService.settings.notViewedContracts.splice(j, 1); break; } } for (let j = 0; j < this.variablesService.settings.viewedContracts.length; j++) { if (this.variablesService.settings.viewedContracts[j].contract_id === contract.contract_id && this.variablesService.settings.viewedContracts[j].is_a === contract.is_a) { this.variablesService.settings.viewedContracts.splice(j, 1); break; } } } } } else if (contract.state === 2 && (contract.height === 0 || (height_app - contract.height) < 10)) { contract.state = 201; } else if (contract.state === 2) { const searchResult3 = this.variablesService.settings.viewedContracts.some(elem => elem.state === 120 && elem.is_a === contract.is_a && elem.contract_id === contract.contract_id); if (searchResult3) { contract.state = 120; } } else if (contract.state === 5) { const searchResult4 = this.variablesService.settings.notViewedContracts.find(elem => elem.state === 130 && elem.is_a === contract.is_a && elem.contract_id === contract.contract_id); if (searchResult4) { if (searchResult4.time === contract.cancel_expiration_time) { contract.state = 130; } else { for (let j = 0; j < this.variablesService.settings.notViewedContracts.length; j++) { if (this.variablesService.settings.notViewedContracts[j].contract_id === contract.contract_id && this.variablesService.settings.notViewedContracts[j].is_a === contract.is_a) { this.variablesService.settings.notViewedContracts.splice(j, 1); break; } } for (let j = 0; j < this.variablesService.settings.viewedContracts.length; j++) { if (this.variablesService.settings.viewedContracts[j].contract_id === contract.contract_id && this.variablesService.settings.viewedContracts[j].is_a === contract.is_a) { this.variablesService.settings.viewedContracts.splice(j, 1); break; } } } } } else if (contract.state === 6 && (contract.height === 0 || (height_app - contract.height) < 10)) { contract.state = 601; } const searchResult = this.variablesService.settings.viewedContracts.some(elem => elem.state === contract.state && elem.is_a === contract.is_a && elem.contract_id === contract.contract_id); contract.is_new = !searchResult; let findContract = false; for (let i = 0; i < wallet.contracts.length; i++) { if (wallet.contracts[i].contract_id === contract.contract_id && wallet.contracts[i].is_a === contract.is_a) { for (const prop in contract) { if (contract.hasOwnProperty(prop)) { wallet.contracts[i][prop] = contract[prop]; } } findContract = true; break; } } if (findContract === false) { wallet.contracts.push(contract); } wallet.recountNewContracts(); } }); } }); this.backend.eventSubscribe('money_transfer_cancel', (data) => { console.log('----------------- money_transfer_cancel -----------------'); console.log(data); if (!data.ti) { return; } const wallet_id = data.wallet_id; const tr_info = data.ti; const wallet = this.variablesService.getWallet(wallet_id); if (wallet) { if (tr_info.hasOwnProperty('contract')) { for (let i = 0; i < wallet.contracts.length; i++) { if (wallet.contracts[i].contract_id === tr_info.contract[0].contract_id && wallet.contracts[i].is_a === tr_info.contract[0].is_a) { if (wallet.contracts[i].state === 1 || wallet.contracts[i].state === 110) { wallet.contracts[i].is_new = true; wallet.contracts[i].state = 140; wallet.recountNewContracts(); } break; } } } wallet.removeFromHistory(tr_info.tx_hash); let error_tr = ''; switch (tr_info.tx_type) { case 0: error_tr = this.translate.instant('ERRORS.TX_TYPE_NORMAL') + '
' + tr_info.tx_hash + '
' + wallet.name + '
' + wallet.address + '
' + this.translate.instant('ERRORS.TX_TYPE_NORMAL_TO') + ' ' + this.intToMoneyPipe.transform(tr_info.amount) + ' ' + this.translate.instant('ERRORS.TX_TYPE_NORMAL_END'); break; case 1: // this.translate.instant('ERRORS.TX_TYPE_PUSH_OFFER'); break; case 2: // this.translate.instant('ERRORS.TX_TYPE_UPDATE_OFFER'); break; case 3: // this.translate.instant('ERRORS.TX_TYPE_CANCEL_OFFER'); break; case 4: error_tr = this.translate.instant('ERRORS.TX_TYPE_NEW_ALIAS') + '
' + tr_info.tx_hash + '
' + wallet.name + '
' + wallet.address + '
' + this.translate.instant('ERRORS.TX_TYPE_NEW_ALIAS_END'); break; case 5: error_tr = this.translate.instant('ERRORS.TX_TYPE_UPDATE_ALIAS') + '
' + tr_info.tx_hash + '
' + wallet.name + '
' + wallet.address + '
' + this.translate.instant('ERRORS.TX_TYPE_NEW_ALIAS_END'); break; case 6: error_tr = this.translate.instant('ERRORS.TX_TYPE_COIN_BASE'); break; } if (error_tr) { this.modalService.prepareModal('error', error_tr); } } }); this.backend.eventSubscribe('on_core_event', (data) => { console.log('----------------- on_core_event -----------------'); console.log(data); data = JSON.parse(data); if (data.events != null) { for (let i = 0, length = data.events.length; i < length; i++) { switch (data.events[i].method) { case 'CORE_EVENT_BLOCK_ADDED': break; case 'CORE_EVENT_ADD_ALIAS': if (this.variablesService.aliasesChecked[data.events[i].details.address] != null) { this.variablesService.aliasesChecked[data.events[i].details.address]['name'] = '@' + data.events[i].details.alias; this.variablesService.aliasesChecked[data.events[i].details.address]['address'] = data.events[i].details.address; this.variablesService.aliasesChecked[data.events[i].details.address]['comment'] = data.events[i].details.comment; } if (this.variablesService.enableAliasSearch) { const newAlias = { name: '@' + data.events[i].details.alias, address: data.events[i].details.address, comment: data.events[i].details.comment }; this.variablesService.aliases = this.variablesService.aliases.concat(newAlias); this.variablesService.changeAliases(); } break; case 'CORE_EVENT_UPDATE_ALIAS': for (const address in this.variablesService.aliasesChecked) { if (this.variablesService.aliasesChecked.hasOwnProperty(address)) { if (this.variablesService.aliasesChecked[address].name === '@' + data.events[i].details.alias) { if (this.variablesService.aliasesChecked[address].address !== data.events[i].details.details.address) { delete this.variablesService.aliasesChecked[address]['name']; delete this.variablesService.aliasesChecked[address]['address']; delete this.variablesService.aliasesChecked[address]['comment']; } else { this.variablesService.aliasesChecked[address].comment = data.events[i].details.details.comment; } break; } } } if (this.variablesService.aliasesChecked[data.events[i].details.details.address] != null) { this.variablesService.aliasesChecked[data.events[i].details.details.address]['name'] = '@' + data.events[i].details.alias; this.variablesService.aliasesChecked[data.events[i].details.details.address]['address'] = data.events[i].details.details.address; this.variablesService.aliasesChecked[data.events[i].details.details.address]['comment'] = data.events[i].details.details.comment; } if (this.variablesService.enableAliasSearch) { const CurrentAlias = this.variablesService.aliases.find((element) => element.name === '@' + data.events[i].details.alias); if (CurrentAlias) { CurrentAlias.address = data.events[i].details.details.address; CurrentAlias.comment = data.events[i].details.details.comment; } } this.variablesService.changeAliases(); break; default: break; } } } }); this.intervalUpdateContractsState = setInterval(() => { this.variablesService.wallets.forEach((wallet) => { wallet.contracts.forEach((contract) => { if (contract.state === 201 && contract.height !== 0 && (this.variablesService.height_app - contract.height) >= 10) { contract.state = 2; contract.is_new = true; console.warn('need check state in contracts'); } else if (contract.state === 601 && contract.height !== 0 && (this.variablesService.height_app - contract.height) >= 10) { contract.state = 6; contract.is_new = true; } }); }); }, 30000); this.expMedTsEvent = this.variablesService.getExpMedTsEvent.subscribe((newTimestamp: number) => { this.variablesService.wallets.forEach((wallet) => { wallet.contracts.forEach((contract) => { if (contract.state === 1 && contract.expiration_time <= newTimestamp) { contract.state = 110; contract.is_new = true; wallet.recountNewContracts(); } else if (contract.state === 5 && contract.cancel_expiration_time <= newTimestamp) { contract.state = 130; contract.is_new = true; wallet.recountNewContracts(); } }); }); }); this.backend.getAppData((status, data) => { if (data && Object.keys(data).length > 0) { for (const key in data) { if (data.hasOwnProperty(key) && this.variablesService.settings.hasOwnProperty(key)) { this.variablesService.settings[key] = data[key]; } } if (this.variablesService.settings.hasOwnProperty('theme') && ['dark', 'white', 'gray'].indexOf(this.variablesService.settings.theme) !== -1) { this.renderer.addClass(document.body, 'theme-' + this.variablesService.settings.theme); } else { this.renderer.addClass(document.body, 'theme-' + this.variablesService.defaultTheme); } if (this.variablesService.settings.hasOwnProperty('scale') && [7.5, 10, 12.5, 15].indexOf(this.variablesService.settings.scale) !== -1) { this.renderer.setStyle(document.documentElement, 'font-size', this.variablesService.settings.scale + 'px'); } } else { this.variablesService.settings.theme = this.variablesService.defaultTheme; this.renderer.addClass(document.body, 'theme-' + this.variablesService.settings.theme); } this.setBackendLocalization(); this.backend.setLogLevel(this.variablesService.settings.appLog); if (this.router.url !== '/login') { this.backend.haveSecureAppData((statusPass) => { if (statusPass) { this.ngZone.run(() => { this.router.navigate(['/login'], {queryParams: {type: 'auth'}}); }); } else { if (Object.keys(data).length !== 0) { this.needOpenWallets = JSON.parse(JSON.stringify(this.variablesService.settings.wallets)); this.ngZone.run(() => { this.variablesService.appLogin = true; this.router.navigate(['/']); }); } else { this.ngZone.run(() => { this.router.navigate(['/login'], {queryParams: {type: 'reg'}}); }); } } }); } }); }, error => { console.log(error); }); this.getMoneyEquivalent(); } getMoneyEquivalent() { this.http.get('https://api.coingecko.com/api/v3/ping').subscribe( () => { this.http.get('https://api.coingecko.com/api/v3/simple/price?ids=zano&vs_currencies=usd').subscribe( data => { this.variablesService.moneyEquivalent = data['zano']['usd']; }, error => { console.warn('api.coingecko.com price error: ', error); } ); }, error => { console.warn('api.coingecko.com error: ', error); setTimeout(() => { this.getMoneyEquivalent(); }, 60000); } ) } getAliases() { this.backend.getAllAliases((status, data, error) => { console.warn(error); if (error === 'CORE_BUSY') { window.setTimeout(() => { this.getAliases(); }, 10000); } else if (error === 'OVERFLOW') { this.variablesService.aliases = []; this.variablesService.enableAliasSearch = false; this.variablesService.wallets.forEach(wallet => { wallet.alias = this.backend.getWalletAlias(wallet.address); }); } else { this.variablesService.enableAliasSearch = true; if (data.aliases && data.aliases.length) { this.variablesService.aliases = []; data.aliases.forEach(alias => { const newAlias = { name: '@' + alias.alias, address: alias.address, comment: alias.comment }; this.variablesService.aliases.push(newAlias); }); this.variablesService.wallets.forEach(wallet => { wallet.alias = this.backend.getWalletAlias(wallet.address); }); this.variablesService.aliases = this.variablesService.aliases.sort((a, b) => { if (a.name.length > b.name.length) { return 1; } if (a.name.length < b.name.length) { return -1; } if (a.name > b.name) { return 1; } if (a.name < b.name) { return -1; } return 0; }); this.variablesService.changeAliases(); } } }); } contextMenuCopy(target) { if (target && (target['nodeName'].toUpperCase() === 'TEXTAREA' || target['nodeName'].toUpperCase() === 'INPUT')) { const start = (target['contextSelectionStart']) ? 'contextSelectionStart' : 'selectionStart'; const end = (target['contextSelectionEnd']) ? 'contextSelectionEnd' : 'selectionEnd'; const canUseSelection = ((target[start]) || (target[start] === '0')); const SelectedText = (canUseSelection) ? target['value'].substring(target[start], target[end]) : target['value']; this.backend.setClipboard(String(SelectedText)); } } contextMenuOnlyCopy(text) { if (text) { this.backend.setClipboard(String(text)); } } contextMenuPaste(target) { if (target && (target['nodeName'].toUpperCase() === 'TEXTAREA' || target['nodeName'].toUpperCase() === 'INPUT')) { this.backend.getClipboard((status, clipboard) => { clipboard = String(clipboard); if (typeof clipboard !== 'string' || clipboard.length) { const start = (target['contextSelectionStart']) ? 'contextSelectionStart' : 'selectionStart'; const end = (target['contextSelectionEnd']) ? 'contextSelectionEnd' : 'selectionEnd'; const _pre = target['value'].substring(0, target[start]); const _aft = target['value'].substring(target[end], target['value'].length); let text = _pre + clipboard + _aft; const cursorPosition = (_pre + clipboard).length; if (target['maxLength'] && parseInt(target['maxLength'], 10) > 0) { text = text.substr(0, parseInt(target['maxLength'], 10)); } target['value'] = text; target.setSelectionRange(cursorPosition, cursorPosition); target.dispatchEvent(new Event('input')); target['focus'](); } }); } } contextMenuSelect(target) { if (target && (target['nodeName'].toUpperCase() === 'TEXTAREA' || target['nodeName'].toUpperCase() === 'INPUT')) { target['focus'](); setTimeout(() => { target['select'](); }); } } ngOnDestroy() { if (this.intervalUpdateContractsState) { clearInterval(this.intervalUpdateContractsState); } this.expMedTsEvent.unsubscribe(); } }