UNPKG

copay-crown

Version:

A Secure Crown Wallet

495 lines (436 loc) 16.5 kB
import { Component, NgZone } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; import { Events, ModalController, NavController } from 'ionic-angular'; import { Logger } from '../../providers/logger/logger'; // Pages import { AddPage } from "../add/add"; import { CopayersPage } from '../add/copayers/copayers'; import { AmazonPage } from '../integrations/amazon/amazon'; import { BitPayCardPage } from '../integrations/bitpay-card/bitpay-card'; import { BitPayCardIntroPage } from '../integrations/bitpay-card/bitpay-card-intro/bitpay-card-intro'; import { CoinbasePage } from '../integrations/coinbase/coinbase'; import { GlideraPage } from '../integrations/glidera/glidera'; import { MercadoLibrePage } from '../integrations/mercado-libre/mercado-libre'; import { ShapeshiftPage } from '../integrations/shapeshift/shapeshift'; import { TxDetailsPage } from '../tx-details/tx-details'; import { TxpDetailsPage } from '../txp-details/txp-details'; import { WalletDetailsPage } from '../wallet-details/wallet-details'; import { ActivityPage } from './activity/activity'; import { ProposalsPage } from './proposals/proposals'; // Providers import { AddressBookProvider } from '../../providers/address-book/address-book'; import { AppProvider } from '../../providers/app/app'; import { BitPayCardProvider } from '../../providers/bitpay-card/bitpay-card'; import { BwcErrorProvider } from '../../providers/bwc-error/bwc-error'; import { ConfigProvider } from '../../providers/config/config'; import { ExternalLinkProvider } from '../../providers/external-link/external-link'; import { FeedbackProvider } from '../../providers/feedback/feedback'; import { HomeIntegrationsProvider } from '../../providers/home-integrations/home-integrations'; import { IncomingDataProvider } from '../../providers/incoming-data/incoming-data'; import { OnGoingProcessProvider } from '../../providers/on-going-process/on-going-process'; import { PersistenceProvider } from '../../providers/persistence/persistence'; import { PlatformProvider } from '../../providers/platform/platform'; import { PopupProvider } from '../../providers/popup/popup'; import { ProfileProvider } from '../../providers/profile/profile'; import { PushNotificationsProvider } from '../../providers/push-notifications/push-notifications'; import { ReleaseProvider } from '../../providers/release/release'; import { WalletProvider } from '../../providers/wallet/wallet'; import * as _ from 'lodash'; import * as moment from 'moment'; @Component({ selector: 'page-home', templateUrl: 'home.html' }) export class HomePage { public wallets: any; public walletsBtc: any; public walletsBch: any; public cachedBalanceUpdateOn: string; public recentTransactionsEnabled: boolean; public txps: any; public txpsN: number; public notifications: any; public notificationsN: number; public config: any; public serverMessage: any; public addressbook: any; public newRelease: boolean; public updateText: string; public homeIntegrations: any[]; public bitpayCardItems: any; public showRateCard: boolean; public homeTip: boolean; public showReorderBtc: boolean; public showReorderBch: boolean; public showIntegration: any; private isNW: boolean; private updatingWalletId: object; private zone: any; constructor( private navCtrl: NavController, private profileProvider: ProfileProvider, private releaseProvider: ReleaseProvider, private walletProvider: WalletProvider, private bwcErrorProvider: BwcErrorProvider, private logger: Logger, private events: Events, private configProvider: ConfigProvider, private pushNotificationsProvider: PushNotificationsProvider, private externalLinkProvider: ExternalLinkProvider, private onGoingProcessProvider: OnGoingProcessProvider, private popupProvider: PopupProvider, private modalCtrl: ModalController, private addressBookProvider: AddressBookProvider, private app: AppProvider, private platformProvider: PlatformProvider, private homeIntegrationsProvider: HomeIntegrationsProvider, private persistenceProvider: PersistenceProvider, private feedbackProvider: FeedbackProvider, private bitPayCardProvider: BitPayCardProvider, private translate: TranslateService, private incomingDataProvider: IncomingDataProvider ) { this.updatingWalletId = {}; this.cachedBalanceUpdateOn = ''; this.isNW = this.platformProvider.isNW; this.showReorderBtc = false; this.showReorderBch = false; this.zone = new NgZone({ enableLongStackTrace: false }); } ionViewWillEnter() { this.config = this.configProvider.get(); this.pushNotificationsProvider.init(); this.homeIntegrations = this.homeIntegrationsProvider.get(); this.showIntegration = this.config.showIntegration; this.homeIntegrations.forEach((integration: any) => { integration.show = this.showIntegration[integration.name]; }); this.homeIntegrations = _.filter(this.homeIntegrations, (homeIntegrations) => { return homeIntegrations.show == true; }); // Update Tx Notifications this.recentTransactionsEnabled = this.config.recentTransactions.enabled; if (this.recentTransactionsEnabled) this.getNotifications(); // BWS Events: Update Status per Wallet // NewBlock, NewCopayer, NewAddress, NewTxProposal, TxProposalAcceptedBy, TxProposalRejectedBy, txProposalFinallyRejected, // txProposalFinallyAccepted, TxProposalRemoved, NewIncomingTx, NewOutgoingTx this.events.subscribe('bwsEvent', (walletId: string) => { if (this.recentTransactionsEnabled) this.getNotifications(); this.updateWallet(walletId); }); // Create, Join, Import and Delete -> Get Wallets -> Update Status for All Wallets this.events.subscribe('status:updated', () => { this.setWallets(); }); // Hide stars to rate this.events.subscribe('feedback:hide', () => { this.showRateCard = false; }); this.bitPayCardProvider.get({}, (err, cards) => { this.bitpayCardItems = cards; }); } ionViewDidEnter() { if (this.isNW) this.checkUpdate(); this.checkHomeTip(); this.checkFeedbackInfo(); this.addressBookProvider.list().then((ab: any) => { this.addressbook = ab || {}; }).catch((err) => { this.logger.error(err); }); if (this.platformProvider.isCordova) { this.handleDeepLinks(); } } ionViewWillLeave() { this.events.unsubscribe('feedback:hide'); } ionViewDidLoad() { this.logger.info('ionViewDidLoad HomePage'); this.setWallets(); } private handleDeepLinks() { // Check if app was resume by custom url scheme (window as any).handleOpenURL = (url: string) => { setTimeout(() => { this.zone.run(() => { this.logger.info("App was resumed by custom url scheme"); this.handleOpenUrl(url); }); }, 0); }; // Check if app was opened by custom url scheme const lastUrl: string = (window as any).handleOpenURL_LastURL || ""; if (lastUrl && lastUrl !== "") { delete (window as any).handleOpenURL_LastURL; setTimeout(() => { this.logger.info("App was opened by custom url scheme"); this.handleOpenUrl(lastUrl); }, 0) } } private handleOpenUrl(url: string) { if (!this.incomingDataProvider.redir(url)) { this.logger.warn('Unknown URL! : ' + url); } } private startUpdatingWalletId(walletId: string) { this.updatingWalletId[walletId] = true; } private stopUpdatingWalletId(walletId: string) { setTimeout(() => { this.updatingWalletId[walletId] = false; }, 10000); } private setWallets = _.debounce(() => { this.wallets = this.profileProvider.getWallets(); this.walletsBtc = this.profileProvider.getWallets({ coin: 'btc' }); this.walletsBch = this.profileProvider.getWallets({ coin: 'bch' }); this.updateAllWallets(); }, 5000, { 'leading': true }); public checkHomeTip(): void { this.persistenceProvider.getHomeTipAccepted().then((value: string) => { this.homeTip = (value == 'accepted') ? false : true; }); } public hideHomeTip(): void { this.persistenceProvider.setHomeTipAccepted('accepted'); this.homeTip = false; } private checkFeedbackInfo() { this.persistenceProvider.getFeedbackInfo().then((info: any) => { if (!info) { this.initFeedBackInfo(); } else { let feedbackInfo = info; // Check if current version is greater than saved version let currentVersion = this.releaseProvider.getCurrentAppVersion(); let savedVersion = feedbackInfo.version; let isVersionUpdated = this.feedbackProvider.isVersionUpdated(currentVersion, savedVersion); if (!isVersionUpdated) { this.initFeedBackInfo(); return; } let now = moment().unix(); let timeExceeded = (now - feedbackInfo.time) >= 24 * 7 * 60 * 60; this.showRateCard = timeExceeded && !feedbackInfo.sent; } }); } private initFeedBackInfo() { let feedbackInfo: any = {}; feedbackInfo.time = moment().unix(); feedbackInfo.version = this.releaseProvider.getCurrentAppVersion(); feedbackInfo.sent = false; this.showRateCard = false; this.persistenceProvider.setFeedbackInfo(feedbackInfo); } private updateWallet(walletId: string): void { if (this.updatingWalletId[walletId]) return; this.startUpdatingWalletId(walletId); let wallet = this.profileProvider.getWallet(walletId); this.walletProvider.getStatus(wallet, {}).then((status: any) => { wallet.status = status; wallet.error = null; this.profileProvider.setLastKnownBalance(wallet.id, wallet.status.availableBalanceStr); this.updateTxps(); this.stopUpdatingWalletId(walletId); }).catch((err: any) => { this.logger.error(err); this.stopUpdatingWalletId(walletId); }); } private updateTxps = _.debounce(() => { this.profileProvider.getTxps({ limit: 3 }).then((data: any) => { this.zone.run(() => { this.txps = data.txps; this.txpsN = data.n; }); }).catch((err: any) => { this.logger.error(err); }); }, 5000, { 'leading': true }); private getNotifications = _.debounce(() => { this.profileProvider.getNotifications({ limit: 3 }).then((data: any) => { this.zone.run(() => { this.notifications = data.notifications; this.notificationsN = data.total; }); }).catch((err: any) => { this.logger.error(err); }); }, 5000, { 'leading': true }); private updateAllWallets(): void { let wallets: any[] = []; let foundMessage = false _.each(this.walletsBtc, (wBtc) => { wallets.push(wBtc); }); _.each(this.walletsBch, (wBch) => { wallets.push(wBch); }); if (_.isEmpty(wallets)) return; let i = wallets.length; let j = 0; let pr = ((wallet, cb) => { this.walletProvider.getStatus(wallet, {}).then((status: any) => { wallet.status = status; wallet.error = null; if (!foundMessage && !_.isEmpty(status.serverMessage)) { this.serverMessage = status.serverMessage; foundMessage = true; } this.profileProvider.setLastKnownBalance(wallet.id, wallet.status.availableBalanceStr); return cb(); }).catch((err) => { wallet.error = (err === 'WALLET_NOT_REGISTERED') ? 'Wallet not registered' : this.bwcErrorProvider.msg(err); this.logger.warn(this.bwcErrorProvider.msg(err, 'Error updating status for ' + wallet.name)); return cb(); }); }).bind(this); _.each(wallets, (wallet: any) => { pr(wallet, () => { if (++j == i) { this.updateTxps(); } }); }); } private checkUpdate(): void { // TODO check if new update this.releaseProvider.getLatestAppVersion().toPromise() .then((version) => { this.logger.debug('Current app version:', version); var result = this.releaseProvider.checkForUpdates(version); this.logger.debug('Update available:', result.updateAvailable); if (result.updateAvailable) { this.newRelease = true; this.updateText = 'There is a new version of ' + this.app.info.nameCase + ' available'; } }) .catch((err) => { this.logger.warn('Error:', err); }) } public openServerMessageLink(): void { let url = this.serverMessage.link; this.externalLinkProvider.open(url); } public goToAddView(coin?: string): void { this.navCtrl.push(AddPage, { coin }); } public goToWalletDetails(wallet: any): void { if (this.showReorderBtc || this.showReorderBch) return; if (!wallet.isComplete()) { this.navCtrl.push(CopayersPage, { walletId: wallet.credentials.walletId }); return; } this.navCtrl.push(WalletDetailsPage, { walletId: wallet.credentials.walletId }); } public openNotificationModal(n: any) { let wallet = this.profileProvider.getWallet(n.walletId); if (n.txid) { this.navCtrl.push(TxDetailsPage, { walletId: n.walletId, txid: n.txid }); } else { var txp = _.find(this.txps, { id: n.txpId }); if (txp) { this.openTxpModal(txp); } else { this.onGoingProcessProvider.set('loadingTxInfo'); this.walletProvider.getTxp(wallet, n.txpId).then((txp: any) => { var _txp = txp; this.onGoingProcessProvider.clear(); this.openTxpModal(_txp); }).catch((err: any) => { this.onGoingProcessProvider.clear(); this.logger.warn('No txp found'); let title = this.translate.instant('Error'); let subtitle = this.translate.instant('Transaction not found'); return this.popupProvider.ionicAlert(title, subtitle); }); } } } public reorderBtc(): void { this.showReorderBtc = !this.showReorderBtc; } public reorderBch(): void { this.showReorderBch = !this.showReorderBch; } public reorderWalletsBtc(indexes): void { let element = this.walletsBtc[indexes.from]; this.walletsBtc.splice(indexes.from, 1); this.walletsBtc.splice(indexes.to, 0, element); _.each(this.walletsBtc, (wallet: any, index: number) => { this.profileProvider.setWalletOrder(wallet.id, index); }); }; public reorderWalletsBch(indexes): void { let element = this.walletsBch[indexes.from]; this.walletsBch.splice(indexes.from, 1); this.walletsBch.splice(indexes.to, 0, element); _.each(this.walletsBch, (wallet: any, index: number) => { this.profileProvider.setWalletOrder(wallet.id, index); }); }; public goToDownload(): void { let url = 'https://github.com/bitpay/copay/releases/latest'; let optIn = true; let title = this.translate.instant('Update Available'); let message = this.translate.instant('An update to this app is available. For your security, please update to the latest version.'); let okText = this.translate.instant('View Update'); let cancelText = this.translate.instant('Go Back'); this.externalLinkProvider.open(url, optIn, title, message, okText, cancelText); } public openTxpModal(tx: any): void { let modal = this.modalCtrl.create(TxpDetailsPage, { tx }, { showBackdrop: false, enableBackdropDismiss: false }); modal.present(); } public openProposalsPage(): void { this.navCtrl.push(ProposalsPage); } public openActivityPage(): void { this.navCtrl.push(ActivityPage); } public goTo(page): void { switch (page) { case 'AmazonPage': this.navCtrl.push(AmazonPage); break; case 'BitPayCardIntroPage': this.navCtrl.push(BitPayCardIntroPage); break; case 'CoinbasePage': this.navCtrl.push(CoinbasePage); break; case 'GlideraPage': this.navCtrl.push(GlideraPage); break; case 'MercadoLibrePage': this.navCtrl.push(MercadoLibrePage); break; case 'ShapeshiftPage': this.navCtrl.push(ShapeshiftPage); break; } } public goToCard(cardId): void { this.navCtrl.push(BitPayCardPage, { id: cardId }); } public doRefresh(refresher) { refresher.pullMin = 90; this.updateAllWallets(); setTimeout(() => { refresher.complete(); }, 2000); } }