copay-crown
Version:
A Secure Crown Wallet
495 lines (436 loc) • 16.5 kB
text/typescript
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';
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);
}
}