Merge branch 'ref/design' of https://github.com/bitpay/bitpay-wallet into feature/onboarding_last_steps

# Conflicts:
#	public/views/onboarding/terms.html
#	src/sass/views/onboarding/terms-of-use.scss
This commit is contained in:
Jamal Jackson 2016-09-06 10:46:47 -04:00
commit 229e2fd8ec
83 changed files with 831 additions and 970 deletions

View File

@ -69,7 +69,7 @@ module.exports = function(grunt) {
tasks: ['concat:css']
},
sass: {
files: ['src/sass/**/*.scss'],
files: ['src/sass/**/**/*.scss'],
tasks: ['sass', 'concat:css']
},
main: {

View File

@ -26,6 +26,7 @@ plugins:
cordova plugin add cordova-plugin-screen-orientation
cordova plugin add ionic-plugin-keyboard
cordova plugin add cordova-plugin-whitelist
cordova plugin add https://github.com/driftyco/cordova-plugin-wkwebview-engine.git --save

View File

@ -21,9 +21,8 @@
<preference name="AutoHideSplashScreen" value="false" />
<preference name="FadeSplashScreen" value="true" />
<preference name="FadeSplashScreenDuration" value="1" />
<preference name="BackgroundColor" value="#2C3E50" />
<preference name="StatusBarOverlaysWebView" value="false" />
<preference name="StatusBarBackgroundColor" value="#2C3E50" />
<preference name="StatusBarOverlaysWebView" value="true" />
<preference name="StatusBarBackgroundColor" value="#1e3186" />
<preference name="StatusBarStyle" value="lightcontent" />
<preference name="BackupWebStorage" value="none"/>
<preference name="windows-target-version" value="8.1"/>

View File

@ -5,6 +5,8 @@
"nameCase": "Copay",
"nameCaseNoSpace": "Copay",
"bundleName": "copay",
"gitHubRepoName": "copay",
"disclaimerUrl": "https://copay.io/disclaimer",
"url": "https://copay.io",
"appDescription": "Copay Bitcoin Wallet",
"winAppName": "CopayWallet",

View File

@ -42,7 +42,7 @@
"url": "https://github.com/bitpay/copay/issues"
},
"dependencies": {
"bitcore-wallet-client": "4.1.0",
"bitcore-wallet-client": "4.2.0",
"coveralls": "^2.11.9",
"express": "^4.11.2",
"fs": "0.0.2",

View File

@ -45,7 +45,7 @@
"url": "https://github.com/bitpay/copay/issues"
},
"dependencies": {
"bitcore-wallet-client": "4.1.0",
"bitcore-wallet-client": "4.2.0",
"coveralls": "^2.11.9",
"express": "^4.11.2",
"fs": "0.0.2",

View File

@ -6,7 +6,6 @@
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no">
<meta name="msapplication-tap-highlight" content="no">
<meta name="format-detection" content="telephone=no">
<link rel="stylesheet" type="text/css" href="css/ionic.min.css">
<link rel="stylesheet" type="text/css" href="css/copay.css">
<title>{{appConfig.nameCase}} - {{appConfig.description}}</title>
<link rel="shortcut icon" href="img/favicon.ico">

View File

@ -10,7 +10,7 @@
<ion-content>
<ion-list>
<a class="item item-remove-animate item-icon-right" type="item-text-wrap" ui-sref="tabs.create.personal">
<a class="item item-remove-animate item-icon-right" type="item-text-wrap" ui-sref="tabs.create">
<h2 translate>Create new wallet</h2>
<i class="icon ion-ios-arrow-right nav-item-arrow-right"></i>
</a>

View File

@ -49,7 +49,7 @@
</div>
</div>
<button class="item button button-block button-balanced" ng-click="approve()" ng-disabled="!txp">
<button class="item button button-block button-balanced" ng-click="approve()">
<span translate>Send</span>
</button>
</ion-content>

View File

@ -1,13 +1,22 @@
<ion-view >
<ion-tabs class="tabs-striped tabs-color-positive tabs-color-active-positive tabs-top">
<ion-view>
<ion-nav-bar class="bar-royal">
<ion-nav-title>{{'Create new wallet' | translate}}</ion-nav-title>
<ion-nav-back-button>
<i class="icon ion-ios-arrow-thin-left"></i>
</ion-nav-back-button>
</ion-nav-bar>
<ion-tab title="Personal Wallet" ui-sref="tabs.create.personal">
<ion-nav-view name="tab-create-personal"></ion-nav-view>
</ion-tab>
<ion-content ng-controller="createController" ng-init="personal = true; init()">
<div class="row text-center">
<div class="col" ng-click="personal = true; setTotalCopayers(1)" ng-style="personal && {'border-bottom': '2px solid'}">
<span class="" translate>Personal Wallet</span>
</div>
<div class="col" ng-click="personal = false; setTotalCopayers(3)" ng-style="!personal && {'border-bottom': '2px solid'}">
<span class="" translate>Shared Wallet</span>
</div>
</div>
<ion-tab title="Shared Wallet" ui-sref="tabs.create.shared">
<ion-nav-view name="tab-create-shared"></ion-nav-view>
</ion-tab>
</ion-tabs>
<div ng-include="'views/tab-create-personal.html'" ng-if="personal"></div>
<div ng-include="'views/tab-create-shared.html'" ng-if="!personal"></div>
</ion-content>
</ion-view>

View File

@ -1,7 +1,7 @@
<div>
<h1 translate>Screenshots are not secure</h1>
<span translate>if you take a screenshot, your backup may be viewed by others apps. You can make a safe backup with paper and a pen.</span>
<button ng-click="close()" class="button button-block button-light" translate>
<button ng-click="close()" class="button button-block no-border" translate>
Got it
</button>
</div>

View File

@ -1,23 +1,31 @@
<i class="icon ion-ios-circle-filled" ng-show="tx.pendingForUs" ng-style="{'color':tx.wallet.color}"></i>
<span ng-show="!tx.merchant">
<span ng-show="addressbook[tx.toAddress] && !tx.message">
{{addressbook[tx.toAddress]}}
</span>
<span class="ellipsis" ng-show="!addressbook[tx.toAddress] && tx.message">
{{tx.message}}
</span>
<span ng-show="!addressbook[tx.toAddress] && !tx.message" translate>
Sending
</span>
</span>
<span ng-show="tx.merchant">
<span ng-show="tx.merchant.pr.ca"><i class="fi-lock"></i> {{tx.merchant.domain}}</span>
<span ng-show="!tx.merchant.pr.ca"><i class="fi-unlock"></i> {{tx.merchant.domain}}</span>
</span>
<span>
- {{tx.amountStr}}
</span>
<div class="item-note">
{{tx.wallet.name}} &middot; <time>{{ (tx.ts || tx.createdOn ) * 1000 | amTimeAgo}}</time>
</div>
<div class="wallet-activity" ng-class="{'wallet-activity-not-pending':!tx.pendingForUs}">
<span ng-show="!tx.merchant">
<span ng-show="addressbook[tx.toAddress] && !tx.message">
{{addressbook[tx.toAddress]}}
</span>
<span class="ellipsis" ng-show="!addressbook[tx.toAddress] && tx.message">
{{tx.message}}
</span>
<span ng-show="!addressbook[tx.toAddress] && !tx.message" translate>
Sending
</span>
</span>
<span ng-show="tx.merchant">
<span ng-show="tx.merchant.pr.ca"><i class="fi-lock"></i> {{tx.merchant.domain}}</span>
<span ng-show="!tx.merchant.pr.ca"><i class="fi-unlock"></i> {{tx.merchant.domain}}</span>
</span>
<span>
</span>
<div class="wallet-activity-amount">
{{tx.amountStr}}
</div>
<p class="wallet-activity-note">
<i class="icon ion-record wallet-activity-note-child" ng-style="{'color':tx.wallet.color}"></i>
<span class="wallet-activity-note-child">{{tx.wallet.name}}</span>
<time class="wallet-activity-note-child">{{tx.createdOn * 1000 | amTimeAgo}}</time>
</p>
</div>

View File

@ -1,13 +1,13 @@
<ion-modal-view ng-controller="addressbookModalController" ng-init="initAddressbook()">
<ion-header-bar align-title="center" class="bar-royal">
<button class="button back-button" ng-click="closeAddressbookModal()">
<i class="icon ion-ios-arrow-thin-left"></i>
<button class="button button-clear" ng-click="closeAddressbookModal()">
Close
</button>
<div class="h1 title">
<span ng-show="!addAddressbookEntry" translate>Addressbook</span>
<span ng-show="addAddressbookEntry" translate>Add entry</span>
</div>
<button class="button button-clear button-positive"
<button class="button button-clear"
ng-click="toggleAddAddressbookEntry()">
<i ng-show="!addAddressbookEntry" class="icon ion-ios-plus-empty"></i>
<span ng-show="addAddressbookEntry" translate>Cancel</span>

View File

@ -1,7 +1,7 @@
<ion-view id="onboarding-backup-request" class="onboarding">
<ion-content ng-controller="backupRequestController">
<div class="row">
<img src="../../img/onboarding-warning.svg" class="col col-75 warning">
<img src="img/onboarding-warning.svg" class="col col-75 warning">
</div>
<div class="row text-center">
<h3 translate class="col-75 col">
@ -17,7 +17,8 @@
<i class="ion-ios-arrow-thin-down light-blue col col-60" id="arrow-down"></i>
</div>
<div class="row">
<button class="button button-block button-positive col-75 col" href ui-sref="onboarding.backupWarning" translate>Backup wallet</button>
<button class="button button-block button-positive col-75 col" href
ui-sref="onboarding.backupWarning({walletId: walletId})" translate>Backup wallet</button>
</div>
<div class="row">
<button class="button button-block button-transparent col-75 col" ng-click="openPopup()" translate>I'll backup my wallet later</button>

View File

@ -1,12 +1,12 @@
<ion-view id="onboarding-backup-warning" class="onboarding">
<ion-nav-bar class="bar-stable">
<ion-view id="onboarding-backup-warning" class="onboarding" ng-controller="backupWarningController">
<ion-nav-bar>
<ion-nav-buttons side="primary">
<button class="button no-border" href ui-sref="onboarding.backupRequest">
<button class="button button-back no-border" href ui-sref="onboarding.backupRequest({walletId: walletId})">
<i class="icon ion-ios-arrow-thin-left"></i>
</button>
</ion-nav-buttons>
</ion-nav-bar>
<ion-content ng-controller="backupWarningController">
<ion-content>
<div class="row text-center">
<h3 translate class="col col-75">
Are you being watched?
@ -18,7 +18,7 @@
</p>
</div>
<div class="row">
<img src="../../img/onboarding-backup-warning.svg" class="col col-60">
<img src="img/onboarding-backup-warning.svg" class="col col-60">
</div>
<div class="row text-center">
<p class="col col-60">

View File

@ -1,29 +1,27 @@
<ion-view ng-controller="collectEmailController" id="onboarding-collect-email" class="onboarding">
<ion-nav-bar class="bar-stable">
<ion-nav-buttons side="secondary">
<button class="button no-border" ng-click="onboardingMailSkip()">
{{'Skip' | translate}}
</button>
</ion-nav-buttons>
</ion-nav-bar>
<ion-content>
<div class="row">
<img src="../../img/onboarding-success.svg" class="col col-75" id="success-image" />
<img src="img/onboarding-success.svg" class="col col-75" id="success-image" />
</div>
<div class="row text-center">
<h3 translate class="col">Wallet Created</h3>
</div>
</ion-content>
<div id="collect-email">
<div class="row text-center">
<p translate class="col col-75">Where would you like to receive email notifications about payments </p>
<div id="collect-email">
<div class="row text-center">
<p translate class="col col-75">Where would you like to receive email notifications about payments </p>
</div>
<form name="emailForm" ng-submit="save(emailForm)" novalidate>
<label class="item item-input col col-75">
<i class="icon ion-arrow-right-c"></i>
<input type="email" id="email" name="email" ng-model="email" required></input>
</label>
</form>
<div class="text-center">
<button class="button button-back no-border" ng-click="onboardingMailSkip()">
{{'Skip' | translate}}
</button>
</div>
</div>
<form name="emailForm" ng-submit="save(emailForm)" novalidate>
<label class="item item-input col col-75">
<i class="icon ion-arrow-right-c"></i>
<input type="email" id="email" name="email" ng-model="email" required></input>
</label>
</form>
</div>
<div class="overlay"></div>
<div class="overlay"></div>
</ion-content>
</ion-view>

View File

@ -10,7 +10,7 @@
</span>
<button class="button button-block button-positive" ng-click="allowNotif()" translate>Allow notifications</button>
<button class="button button-block button-light" href ui-sref="onboarding.requestBackup" translate>Not now</button>
<button class="button button-block button-light" href ui-sref="onboarding.backupRequest({walletId: walletId})" translate>Not now</button>
</div>
</ion-content>
</ion-view>

View File

@ -2,12 +2,12 @@
<ion-nav-bar class="bar-stable">
<ion-nav-title></ion-nav-title>
<ion-nav-buttons side="primary">
<button class="button no-border" ng-click="goBack()">
<button class="button back-button no-border" ng-click="goBack()">
<i class="icon ion-ios-arrow-thin-left"></i>
</button>
</ion-nav-buttons>
<ion-nav-buttons side="secondary">
<button class="button no-border" ng-show="data.index == 0" ng-click="createDefaultWallet()">
<button class="button back-button no-border" ng-show="data.index == 0" ng-click="createDefaultWallet()">
{{'Skip' | translate}}
</button>
</ion-nav-buttons>

View File

@ -3,7 +3,7 @@
<qr-scanner id="shopping-24" on-scan="goImport(data)"></qr-scanner>
<div class="text-center">
<div class="row">
<img src='../../img/bitpay-logo.svg' class="logo col col-50" />
<img src='img/bitpay-logo.svg' class="logo col col-50" />
</div>
<div class="row">
<p translate class="text-center col col-60">

View File

@ -6,33 +6,24 @@
</ion-nav-bar>
<ion-content ng-controller="preferencesController" ng-init="init()">
<div class="list">
<div class="item item-divider">
Preferences
</div>
<div class="item item-divider"></div>
<div class="item item-icon-right" href ui-sref="tabs.preferences.preferencesAlias">
<span translate>Wallet Name</span>
<span translate>Name</span>
<span class="item-note">
{{alias||wallet.walletName}}
{{wallet.name}}
</span>
<i class="icon ion-ios-arrow-right"></i>
</div>
<div class="item">
<span translate>Wallet Type</span>
<span class="item-note">
{{wallet.m}}-of-{{wallet.n}}
</span>
</div>
<div class="item" ng-show="wallet.isPrivKeyExternal()">
<span translate>Hardware wallet</span>
<span translate>Hardware Wallet</span>
<span class="item-note">
{{wallet.externalSource}}
</span>
</div>
<div class="item item-icon-right" href ui-sref="tabs.preferences.preferencesColor">
<span ng-style="{'color': wallet.color}">&block;</span>
<span translate>Wallet Color</span>
<span class="item-note">
{{wallet.alias||wallet.walletName}}
<span translate>Color</span>
<span class="item-note" ng-style="{'color': wallet.color}">
&block;
</span>
<i class="icon ion-ios-arrow-right"></i>
</div>
@ -65,9 +56,7 @@
<span translate>Delete recovery phrase</span>
<i class="icon ion-ios-arrow-right"></i>
</div>
<div class="item item-divider" translate>
Advanced
</div>
<div class="item item-divider"></div>
<div class="item item-icon-right" href ui-sref="tabs.preferences.preferencesAdvanced">
<span translate>Advanced</span>
<i class="icon ion-ios-arrow-right"></i>

View File

@ -7,36 +7,41 @@
</ion-nav-buttons>
</ion-nav-bar>
<ion-content ng-controller="preferencesAbout">
<div class="item item-divider" translate>
Release information
</div>
<div class="item item-icon-left">
<i class="icon ion-ios-film-outline"></i>
<span translate>Version</span>
<span class="item-note">
v{{v.version}}
</span>
</div>
<div class="item item-icon-left" ng-click="$root.openExternalLink('https://github.com/bitpay/copay/tree/'+v.commitHash)">
<i class="icon ion-ios-film-outline"></i>
<span translate>Commit hash</span>
<span class="item-note">
#{{v.commitHash}}
</span>
</div>
<div class="item item-divider">
</div>
<div class="item item-icon-left" href ui-sref="tabs.termsOfUse">
<i class="icon ion-ios-bell-outline"></i>
<span translate>Terms of Use</span>
</div>
<div class="item item-icon-left" href ui-sref="tabs.translators">
<i class="icon ion-ios-bell-outline"></i>
<span translate>Translators</span>
</div>
<div class="item item-icon-left" href ui-sref="tabs.logs">
<i class="icon ion-ios-bell-outline"></i>
<span translate>Session log</span>
<div class="list">
<div class="item item-divider" translate>
Release information
</div>
<div class="item item-icon-left">
<i class="icon ion-ios-download-outline"></i>
<span translate>Version</span>
<span class="item-note">
v{{version}}
</span>
</div>
<div class="item item-icon-left" ng-click="openExternalLink('https://github.com/bitpay/'+name+'/tree/'+commitHash)">
<i class="icon ion-social-github-outline"></i>
<span translate>Commit hash</span>
<span class="item-note">
#{{commitHash}}
</span>
</div>
<div class="item item-divider">
</div>
<div class="item item-icon-left item-icon-right" href ui-sref="tabs.termsOfUse">
<i class="icon ion-ios-list-outline"></i>
<span translate>Terms of Use</span>
<i class="icon ion-ios-arrow-right"></i>
</div>
<div class="item item-icon-left item-icon-right" href ui-sref="tabs.translators">
<i class="icon ion-ios-people-outline"></i>
<span translate>Translators</span>
<i class="icon ion-ios-arrow-right"></i>
</div>
<div class="item item-icon-left item-icon-right" href ui-sref="tabs.logs">
<i class="icon ion-ios-copy-outline"></i>
<span translate>Session log</span>
<i class="icon ion-ios-arrow-right"></i>
</div>
</div>
</ion-content>
</ion-view>

View File

@ -6,12 +6,18 @@
</ion-nav-bar>
<ion-content ng-controller="preferencesAliasController" >
<form name="aliasForm" ng-submit="save(aliasForm)" novalidate>
<label class="item item-input item-stacked-label">
<span class="input-label" transalate>Alias for {{walletName}}</span>
<input type="text" id="alias" name="alias" ng-model="alias" placeholder="John" required></input>
</label>
<input type="submit" class="button button-block button-stable" value="{{'Save'|translate}}" ng-disabled="aliasForm.$invalid">
<div class="card list">
<label class="item item-input item-stacked-label">
<span class="input-label" transalate>Alias for {{walletName}}</span>
<input type="text" id="alias" name="alias" ng-model="alias" placeholder="John" required>
</label>
</div>
<button type="submit"
class="button button-block button-positive"
ng-disabled="aliasForm.$invalid" translate>
Save
</button>
</form>
<div translate>Changing wallet alias only affects the local wallet name.</div>
<div class="text-center" translate>Changing wallet alias only affects the local wallet name.</div>
</ion-content>
</ion-view>

View File

@ -6,17 +6,15 @@
</ion-nav-bar>
<ion-content ng-controller="preferencesBwsUrlController">
<div class="row no-border">
<div class="col col-90">
<label class="item item-input item-stacked-label no-border">
<span class="input-label" transalate>Wallet Service URL</span>
<input type="text" id="bwsurl" type="text" name="bwsurl" ng-model="bwsurl">
</label>
</div>
<div class="col">
<i class="icon ion-ios-reload" ng-click="resetDefaultUrl()"></i>
</div>
<div class="card list">
<label class="item item-input item-stacked-label no-border">
<span class="input-label">Wallet Service URL</span>
<input type="text" id="bwsurl" type="text" name="bwsurl" ng-model="bwsurl">
<a class="postfix" on-tap="resetDefaultUrl()">
<i class="icon ion-ios-reload"></i>
</a>
</label>
</div>
<button class="button button-block button-balanced" ng-click="save()" translate>Save</button>
<button class="button button-block button-positive" ng-click="save()" translate>Save</button>
</ion-content>
</ion-view>

View File

@ -4,12 +4,14 @@
<i class="icon ion-ios-arrow-thin-left"></i>
</ion-nav-back-button>
</ion-nav-bar>
<ion-content class="has-header" ng-controller="preferencesDeleteWalletController" >
<div translate>Warning!</div>
<div translate>Permanently delete this wallet. THIS ACTION CANNOT BE REVERSED</div>
<div class="right" ng-style="{'color':backgroundColor}" ng-show="!isDeletingWallet">
<span ng-show="alias">{{alias}}</span>{{walletName}}
<ion-content ng-controller="preferencesDeleteWalletController" >
<div class="card">
<h1 class="text-center" translate>Warning!</h2>
<div class="assertive padding" translate>Permanently delete this wallet. THIS ACTION CANNOT BE REVERSED</div>
<div class="text-center padding">
<span ng-show="alias">{{alias}}</span>{{walletName}}
</div>
</div>
<button class="button button-block button-stable" ng-click="showDeletePopup()"translate>Delete wallet</button>
<button class="button button-block button-assertive" ng-click="showDeletePopup()"translate>Delete</button>
</ion-content>
</ion-view>

View File

@ -6,13 +6,19 @@
</ion-nav-bar>
<ion-content ng-controller="preferencesEmailController" >
<form name="emailForm" ng-submit="save(emailForm)" novalidate>
<label class="item item-input item-stacked-label">
<span class="input-label" transalate>Email for wallet notifications</span>
<input type="email" id="email" name="email" ng-model="email" required></input>
</label>
<input type="submit" class="button button-block button-stable" value="{{'Save'|translate}}" ng-disabled="emailForm.$invalid">
<div class="card list">
<label class="item item-input item-stacked-label">
<span class="input-label" transalate>Email for wallet notifications</span>
<input type="email" id="email" name="email" ng-model="email" required></input>
</label>
</div>
<button type="submit"
class="button button-block button-positive"
ng-disabled="emailForm.$invalid" translate>
Save
</button>
</form>
<div translate>Setting up email notifications could weaken your privacy, if the wallet service provider is compromised. Information available to an attacker would include your wallet addresses and its balance, but no more.
<div class="text-center" translate>Setting up email notifications could weaken your privacy, if the wallet service provider is compromised. Information available to an attacker would include your wallet addresses and its balance, but no more.
</div>
</ion-content>
</ion-view>

View File

@ -6,19 +6,17 @@
</ion-nav-bar>
<ion-content ng-controller="preferencesFeeController" ng-init="init()">
<div ng-show="loading">
<ion-spinner class="spinner-dark" icon="lines">Loading...</ion-spinner>
</div>
<ion-radio ng-repeat="fee in feeLevels.livenet" ng-value="fee.level" ng-model="currentFeeLevel" ng-click="save(fee)">{{feeOpts[fee.level]|translate}}
<ion-radio ng-repeat="fee in feeLevels.livenet" ng-value="fee.level" ng-model="currentFeeLevel" ng-click="save(fee)">
{{feeOpts[fee.level]|translate}}
</ion-radio>
<div ng-repeat="fee in feeLevels.livenet" ng-if="fee.level == currentFeeLevel">
<div ng-show="fee.nbBlocks">
<span translate>Average confirmation time: {{fee.nbBlocks * 10}} minutes</span>.
</div>
<span translate>Current fee rate for this policy: {{fee.feePerKBUnit}}/kiB</span>
</div>
<div translate>
Bitcoin transactions may include a fee collected by miners on the network. The higher the fee, the greater the incentive a miner has to include that transaction in a block. Current fees are determined based on network load and the selected policy.
<div class="padding text-center positive" ng-repeat="fee in feeLevels.livenet" ng-if="fee.level == currentFeeLevel">
<div ng-show="fee.nbBlocks">
<span translate>Average confirmation time: {{fee.nbBlocks * 10}} minutes</span>.
</div>
<span translate>Current fee rate for this policy: {{fee.feePerKBUnit}}/kiB</span>
</div>
<div class="padding" translate>
Bitcoin transactions may include a fee collected by miners on the network. The higher the fee, the greater the incentive a miner has to include that transaction in a block. Current fees are determined based on network load and the selected policy.
</div>
</ion-content>
</ion-view>

View File

@ -6,7 +6,7 @@
</ion-nav-bar>
<ion-content ng-controller="preferencesHistory" ng-init="index.updatingTxHistory ? null : csvHistory()">
<div class="item item-divider"></div>
<div class="item" ng-show="csvReady && !index.isCordova" ng-csv="csvContent" csv-header="csvHeader" filename="Copay-{{index.alias || index.walletName}}.csv">
<div class="item" ng-show="csvReady && !index.isCordova" ng-csv="csvContent" csv-header="csvHeader" filename="Copay-{{wallet.name}}.csv">
<span translate>Export to file</span>
</div>
<div class="item" ng-show="!csvReady && !index.isCordova">
@ -15,7 +15,7 @@
preparing...
</span>
</div>
<div class="item" ng-click="clearTransactionHistory()">
<div class="item assertive" ng-click="clearTransactionHistory()">
<span translate>Clear cache</span>
</div>
</ion-content>

View File

@ -6,9 +6,7 @@
</ion-nav-bar>
<ion-content ng-controller="preferencesInformation" ng-init="init()">
<div class="list">
<div class="item item-divider">
Wallet Information
</div>
<div class="item item-divider"></div>
<div class="item" ng-click="saveBlack()">
<span translate>Wallet Name (at creation)</span>
<span class="item-note">
@ -64,23 +62,23 @@
</span>
</div>
<div class="item item-divider">
<div ng-show="wallet.cachedStatus.wallet.copayers[0]" class="item item-divider">
Copayers
</div>
<div class="item item-icon-right" ng-repeat="copayer in wallet.copayers">
<span ng-show="copayer.id == wallet.copayerId" translate>{{copayer.name}} ({{'Me'|translate}})</span>
<span ng-style="{'color': 'grey';}" ng-show="copayer.id != wallet.copayerId" translate>{{copayer.name}}</span>
<i class="icon ion-ios-checkmark-outline"></i>
<div class="item item-icon-right" ng-repeat="copayer in wallet.cachedStatus.wallet.copayers">
{{copayer.name}}
<span ng-show="copayer.id == wallet.copayerId">
({{'Me'|translate}})
</span>
</div>
<div class="item item-divider">
<div class="item item-divider" translate>
Extended Public Keys
</div>
<div class="item" ng-repeat="pk in pubKeys" copy-to-clipboard="pk">
<span translate>Copayer {{$index}}<</span>
<i class="icon ion-ios-checkmark-outline"></i>
<span translate>Copayer {{$index}}</span>
<span class="item-note">
<span>Copayer {{$index}}</span>
<span>{{pk}}</span>
@ -89,27 +87,27 @@
</div>
<div ng-show="addrs">
<div class="item item-divider">
<div class="item item-divider" translate>
Last Wallet Addresses
</div>
<div class="item" ng-repeat="a in addrs" class="oh" copy-to-clipboard="a.address">
<span>{{a.address}}</span>
<span>{{a.path}} &middot; {{a.createdOn *1000 | amDateFormat:'MMMM Do YYYY, h:mm a' }}</span>
<i class="icon ion-ios-checkmark-outline"></i>
<span>{{a.address}}</span>
<span class="item-note">{{a.path}} &middot; {{a.createdOn *1000 | amDateFormat:'MMMM Do YYYY, h:mm a' }}</span>
</div>
<div translate>
<div class="padding text-center" translate>
Only Main (not change) addresses are shown. The addresses on this list were not verified locally at this time.
</div>
<button class="button button-block button-positive" href ui-sref="walletHome" ng-click="scan()" translate>
Scan addresses for funds
</button>
<button class="button button-block button-positive" ng-click="scan()" translate>
Scan addresses for funds
</button>
<button class="button button-block button-positive" ng-show="isCordova" ng-click="sendAddrs()" translate>
Send addresses by email
</button>
Send addresses by email
</button>
</div>
<div ng-show="wallet.balanceByAddress" ng-if="wallet.balanceByAddress[0]">
<div class="item item-divider">
<div ng-show="wallet.balanceByAddress[0]">
<div class="item item-divider" translate>
Balance By Address
</div>
<div class="item" ng-repeat="a in wallet.balanceByAddress" copy-to-clipboard="a.address">

View File

@ -8,10 +8,12 @@
<ion-radio ng-repeat="lang in availableLanguages" ng-value="lang.isoCode" ng-model="currentLanguage"
ng-click="save(lang.isoCode)">{{lang.name}}
</ion-radio>
<span translate>All contributions to Copay's translation are welcome. Sign up at crowdin.com and join the Copay project at</span>
<a ng-click="$root.openExternalLink('https://crowdin.com/project/copay', '_system')">https://crowdin.com/project/copay</a>.
<span translate>
Don't see your language on Crowdin? Contact the Owner on Crowdin! We'd love to support your language.
</span>
<div class="padding">
<span translate>All contributions to Copay's translation are welcome. Sign up at crowdin.com and join the Copay project at</span>
<a ng-click="openExternalLink('https://crowdin.com/project/copay', '_system')">https://crowdin.com/project/copay</a>.
<span translate>
Don't see your language on Crowdin? Contact the Owner on Crowdin! We'd love to support your language.
</span>
</div>
</ion-content>
</ion-view>

View File

@ -4,16 +4,25 @@
<i class="icon ion-ios-arrow-thin-left"></i>
</ion-nav-back-button>
</ion-nav-bar>
<ion-content ng-controller="preferencesLogs" ng-init="init()" >
<button ng-show="isCordova" ng-click="logs.sendLogs()"><i class="fi-mail"></i>
<span translate>Send by email</span>
<ion-content ng-controller="preferencesLogs" ng-init="init()">
<div class="card">
<div class="item item-text-wrap">
<ul>
<li ng-repeat="l in logs">
<span ng-class="{'energized': l.level=='warn', 'dark': l.level=='debug', 'positive': l.level=='info', 'assertive': l.level=='error' }">
{{l.msg}}
</span>
</li>
</ul>
</div>
</div>
<button class="button button-block button-positive" copy-to-clipboard="prepare()">
<i class="icon ion-clipboard"></i>
<span translate>Copy to clipboard</span>
</button>
<button class="button button-block button-positive" ng-show="isCordova" ng-click="sendLogs()">
<i class="icon ion-ios-email-outline"></i>
<span translate>Send by email</span>
</button>
<ul>
<li ng-repeat="l in logs">
<span ng-class="{'text-warning': l.level=='warn', 'text-secondary': l.level=='debug', 'text-primary': l.level=='info', 'text-alert': l.level=='error' }">
{{l.msg}}
</span>
</li>
</ul>
</ion-content>
</ion-view>

View File

@ -11,7 +11,7 @@
<ion-content class="padding" ng-controller="proposalsController" ng-init="init()">
<div class="list card">
<a ng-repeat="tx in txps" class="item item-icon-left" ng-click="openTxpModal(tx)">
<a ng-repeat="tx in txps" class="item" ng-click="openTxpModal(tx)">
<span ng-include="'views/includes/txp.html'"></span>
</a>

View File

@ -1,125 +1,88 @@
<ion-view>
<ion-nav-bar class="bar-royal">
<ion-nav-buttons side="primary">
<button class="button back-button" ui-sref="tabs.add">
<i class="icon ion-ios-arrow-thin-left"></i>
</button>
</ion-nav-buttons>
<ion-nav-title>{{'Create new wallet' | translate}}</ion-nav-title>
</ion-nav-bar>
<form name="setupForm" ng-submit="create(setupForm)" novalidate>
<div class="card list">
<label class="item item-input item-stacked-label">
<span class="input-label" translate>Wallet name</span>
<input type="text"
placeholder="{{'Family vacation funds'|translate}}"
ng-model="formData.walletName"
ng-required="true"
ng-focus="formFocus('wallet-name')"
ng-blur="formFocus(false)">
</label>
<ion-content ng-controller="createController as create" ng-init="create.setTotalCopayers(1)">
<ion-toggle ng-model="showAdv" toggle-class="toggle-stable" ng-change="showAdvChange()">
<span translate ng-show="!showAdv">Show advanced options</span>
<span translate ng-show="showAdv">Hide advanced options</span>
</ion-toggle>
<form name="setupForm" ng-submit="create.create(setupForm)" novalidate>
<div ng-show="showAdv">
<label class="item item-input item-stacked-label">
<span class="input-label">Wallet Service URL</span>
<input type="text" ng-model="formData.bwsurl" placeholder="https://bws.bitpay.com/bws/api">
</label>
<div class="card list">
<label ng-hide="create.hideWalletName" class="item item-input item-stacked-label">
<span class="input-label" translate>Wallet name</span>
<input type="text"
placeholder="{{'Family vacation funds'|translate}}"
name="walletName"
ng-model="walletName"
ng-required="true"
ng-focus="create.formFocus('wallet-name')"
ng-blur="create.formFocus(false)">
</label>
<label class="item item-input item-select">
<div class="input-label" translate>
Wallet Key
</div>
<select class="m10t" ng-model="seedSource" ng-options="seed as seed.label for seed in seedOptions"></select>
</label>
<ion-toggle ng-model="showAdv" toggle-class="toggle-stable" ng-change="showAdvChange()">
<span translate ng-show="!showAdv">Show advanced options</span>
<span translate ng-show="showAdv">Hide advanced options</span>
</ion-toggle>
<label class="item item-input item-stacked-label" ng-show="seedSource.id == 'trezor' || seedSource.id == 'ledger'">
<span class="input-label" translate>Account Number</span>
<input type="number" ng-model="formData.account" ignore-mouse-wheel>
</label>
<div ng-show="showAdv">
<div class="card" ng-show="seedSource.id == 'new' && createPassphrase">
<div class="item item-text-wrap" translate>
WARNING: The password cannot be recovered. <b>Be sure to write it down</b>. The wallet can not be restored without the password.
</div>
</div>
<label class="item item-input item-stacked-label">
<span class="input-label">Wallet Service URL</span>
<input type="text" id="bwsurl" name="bwsurl" ng-model="bwsurl">
</label>
<label class="item item-input item-stacked-label" ng-show="seedSource.id == 'new'">
<span class="input-label" translate>Add a Password</span>
<input type="text"
placeholder="{{'Add an optional password to secure the recovery phrase'|translate}}"
autocapitalize="off"
ng-model="formData.createPassphrase">
</label>
<label class="item item-input item-select">
<div class="input-label" translate>
Wallet Key
</div>
<select class="m10t"
ng-model="seedSource"
ng-options="seed as seed.label for seed in create.seedOptions"
ng-change="create.setSeedSource()">
</select>
</label>
<label class="item item-input item-stacked-label" ng-show="seedSource.id == 'set'">
<span class="input-label" translate>Wallet Recovery Phrase</span>
<input placeholder="{{'Enter the recovery phrase (BIP39)'|translate}}"
autocapitalize="off"
type="text"
ng-model="formData.privateKey">
</label>
<label class="item item-input item-stacked-label"
ng-show="create.seedSourceId == 'trezor' || create.seedSourceId == 'ledger'">
<span class="input-label" translate>Account Number</span>
<input type="number" id="account" ng-model="account" ignore-mouse-wheel>
</label>
<label class="item item-input item-stacked-label" ng-show="seedSource.id == 'set'">
<span class="input-label" translate>Password</span>
<input type="text"
placeholder="{{'The recovery phrase could require a password to be imported'|translate}}"
autocapitalize="off"
ng-model="formData.passphrase">
</label>
<div class="card" ng-show="create.seedSourceId=='new' && createPassphrase">
<div class="item item-text-wrap" translate>
WARNING: The password cannot be recovered. <b>Be sure to write it down</b>. The wallet can not be restored without the password.
</div>
</div>
<label class="item item-input item-stacked-label" ng-show="seedSource.id == 'set'">
<span class="input-label" translate>Derivation Path</span>
<input type="text"
placeholder="{{'BIP32 path for address derivation'|translate}}"
ng-model="formData.derivationPath">
</label>
<label class="item item-input item-stacked-label" ng-show="create.seedSourceId=='new'">
<span class="input-label" translate>Add a Password</span>
<input type="text"
placeholder="{{'Add an optional password to secure the recovery phrase'|translate}}"
autocapitalize="off"
name="createPassphrase"
ng-model="createPassphrase">
</label>
<ion-toggle ng-show="seedSource.id == 'new'" ng-model="formData.testnetEnabled" toggle-class="toggle-positive">
<span translate>Testnet</span>
</ion-toggle>
<ion-toggle ng-model="formData.singleAddressEnabled" toggle-class="toggle-positive">
<span translate>Single Address Wallet</span>
<small translate>For audit purposes</small>
</ion-toggle>
<label class="item item-input item-stacked-label" ng-show="create.seedSourceId=='set'">
<span class="input-label" translate>Wallet Recovery Phrase</span>
<input id="ext-master"
placeholder="{{'Enter the recovery phrase (BIP39)'|translate}}"
autocapitalize="off"
type="text"
name="privateKey"
ng-model="privateKey">
</label>
</div> <!-- advanced -->
</div> <!-- list -->
<label class="item item-input item-stacked-label" ng-show="create.seedSourceId=='set'">
<span class="input-label" translate>Password</span>
<input type="text"
placeholder="{{'The recovery phrase could require a password to be imported'|translate}}"
autocapitalize="off"
name="passphrase"
ng-model="passphrase">
</label>
<label class="item item-input item-stacked-label" ng-show="create.seedSourceId == 'set'">
<span class="input-label" translate>Derivation Path</span>
<input type="text"
placeholder="{{'BIP32 path for address derivation'|translate}}"
name="derivationPath"
ng-model="derivationPath">
</label>
<ion-toggle ng-show="create.seedSourceId == 'new'" ng-model="testnetEnabled" toggle-class="toggle-positive">
Testnet
</ion-toggle>
<ion-toggle ng-model="singleAddressEnabled" toggle-class="toggle-positive">
<span translate>Single Address Wallet</span>
<small translate>For audit purposes</small>
</ion-toggle>
</div> <!-- advanced -->
</div> <!-- list -->
<button type="submit"
class="button button-block button-positive"
ng-show="totalCopayers != 1" ng-disabled="setupForm.$invalid">
<span translate>Create {{requiredCopayers}}-of-{{totalCopayers}} wallet</span>
</button>
<button type="submit"
class="button button-block button-positive"
ng-show="totalCopayers == 1" ng-disabled="setupForm.$invalid">
<span translate>Create new wallet</span>
</button>
</form>
</ion-content>
</ion-view>
<button type="submit" class="button button-block button-positive" ng-disabled="setupForm.$invalid">
<span translate>Create new wallet</span>
</button>
</form>

View File

@ -1,159 +1,119 @@
<ion-view>
<ion-nav-bar class="bar-royal">
<ion-nav-buttons side="primary">
<button class="button back-button" ui-sref="tabs.add">
<i class="icon ion-ios-arrow-thin-left"></i>
</button>
</ion-nav-buttons>
<ion-nav-title>{{'Create new wallet' | translate}}</ion-nav-title>
</ion-nav-bar>
<form name="setupForm" ng-submit="create(setupForm)" novalidate>
<div class="card list">
<label class="item item-input item-stacked-label">
<span class="input-label" translate>Wallet name</span>
<input type="text"
placeholder="{{'Family vacation funds'|translate}}"
ng-model="formData.walletName"
ng-required="true"
ng-focus="formFocus('wallet-name')"
ng-blur="formFocus(false)">
</label>
<ion-content ng-controller="createController as create" ng-init="create.setTotalCopayers(3)">
<label class="item item-input item-stacked-label">
<span class="input-label" translate>Your nickname</span>
<input type="text"
placeholder="{{'John'|translate}}"
ng-model="formData.myName"
ng-required="formData.totalCopayers != 1"
ng-disabled="formData.totalCopayers == 1"
ng-focus="formFocus('my-name')"
ng-blur="formFocus(false)">
</label>
<form name="setupForm" ng-submit="create.create(setupForm)" novalidate>
<label class="item item-input item-select">
<div class="input-label" translate>
Total number of copayers
</div>
<select class="m10t" ng-model="formData.totalCopayers" ng-options="totalCopayers as totalCopayers for totalCopayers in TCValues"
ng-change="setTotalCopayers(formData.totalCopayers)">
</select>
</label>
<div class="card list">
<label ng-hide="create.hideWalletName" class="item item-input item-stacked-label">
<span class="input-label" translate>Wallet name</span>
<input type="text"
placeholder="{{'Family vacation funds'|translate}}"
name="walletName"
ng-model="walletName"
ng-required="true"
ng-focus="create.formFocus('wallet-name')"
ng-blur="create.formFocus(false)">
</label>
<label class="item item-input item-select">
<div class="input-label" translate>
Required number of signatures
</div>
<select class="m10t"
ng-model="formData.requiredCopayers" ng-options="requiredCopayers as requiredCopayers for requiredCopayers in RCValues"
ng-disabled="formData.totalCopayers == 1">
</select>
</label>
<label ng-show="totalCopayers != 1" class="item item-input item-stacked-label">
<span class="input-label" translate>Your nickname</span>
<input type="text"
placeholder="{{'John'|translate}}"
name="myName"
ng-model="myName"
ng-required="totalCopayers != 1"
ng-disabled="totalCopayers == 1"
ng-focus="create.formFocus('my-name')"
ng-blur="create.formFocus(false)">
</label>
<ion-toggle ng-model="showAdv" toggle-class="toggle-stable" ng-change="showAdvChange()">
<span translate ng-show="!showAdv">Show advanced options</span>
<span translate ng-show="showAdv">Hide advanced options</span>
</ion-toggle>
<label ng-show="totalCopayers != 1" class="item item-input item-select">
<div class="input-label" translate>
Total number of copayers
</div>
<select class="m10t"
ng-model="totalCopayers"
ng-options="totalCopayers as totalCopayers for totalCopayers in create.TCValues"
ng-change="create.setTotalCopayers(totalCopayers)">
</select>
</label>
<div ng-show="showAdv">
<label class="item item-input item-stacked-label">
<span class="input-label">Wallet Service URL</span>
<input type="text" ng-model="formData.bwsurl">
</label>
<label ng-show="totalCopayers != 1" class="item item-input item-select">
<div class="input-label" translate>
Required number of signatures
</div>
<select class="m10t"
ng-model="requiredCopayers"
ng-options="requiredCopayers as requiredCopayers for requiredCopayers in create.RCValues"
ng-disabled="totalCopayers == 1">
</select>
</label>
<label class="item item-input item-select">
<div class="input-label" translate>
Wallet Key
</div>
<select class="m10t" ng-model="seedSource" ng-options="seed as seed.label for seed in seedOptions"></select>
</label>
<ion-toggle ng-model="showAdv" toggle-class="toggle-stable" ng-change="showAdvChange()">
<span translate ng-show="!showAdv">Show advanced options</span>
<span translate ng-show="showAdv">Hide advanced options</span>
</ion-toggle>
<label class="item item-input item-stacked-label" ng-show="seedSource.id == 'trezor' || seedSource.id == 'ledger'">
<span class="input-label" translate>Account Number</span>
<input type="number" ng-model="formData.account" ignore-mouse-wheel>
</label>
<div ng-show="showAdv">
<div class="card" ng-show="seedSource.id =='new' && formData.createPassphrase">
<div class="item item-text-wrap" translate>
WARNING: The password cannot be recovered. <b>Be sure to write it down</b>. The wallet can not be restored without the password.
</div>
</div>
<label class="item item-input item-stacked-label">
<span class="input-label">Wallet Service URL</span>
<input type="text" id="bwsurl" name="bwsurl" ng-model="bwsurl">
</label>
<label class="item item-input item-select">
<div class="input-label" translate>
Wallet Key
</div>
<select class="m10t"
ng-model="seedSource"
ng-options="seed as seed.label for seed in create.seedOptions"
ng-change="create.setSeedSource()">
</select>
</label>
<label class="item item-input item-stacked-label"
ng-show="create.seedSourceId == 'trezor' || create.seedSourceId == 'ledger'">
<span class="input-label" translate>Account Number</span>
<input type="number" id="account" ng-model="account" ignore-mouse-wheel>
</label>
<div class="card" ng-show="create.seedSourceId=='new' && createPassphrase">
<div class="item item-text-wrap" translate>
WARNING: The password cannot be recovered. <b>Be sure to write it down</b>. The wallet can not be restored without the password.
</div>
</div>
<label class="item item-input item-stacked-label" ng-show="create.seedSourceId=='new'">
<span class="input-label" translate>Add a Password</span>
<input type="text"
placeholder="{{'Add an optional password to secure the recovery phrase'|translate}}"
autocapitalize="off"
name="createPassphrase"
ng-model="createPassphrase">
</label>
<label class="item item-input item-stacked-label" ng-show="seedSource.id == 'new'">
<span class="input-label" translate>Add a Password</span>
<input type="text"
placeholder="{{'Add an optional password to secure the recovery phrase'|translate}}"
autocapitalize="off"
ng-model="formData.createPassphrase">
</label>
<label class="item item-input item-stacked-label" ng-show="create.seedSourceId=='set'">
<span class="input-label" translate>Wallet Recovery Phrase</span>
<input id="ext-master"
placeholder="{{'Enter the recovery phrase (BIP39)'|translate}}"
autocapitalize="off"
type="text"
name="privateKey"
ng-model="privateKey">
</label>
<label class="item item-input item-stacked-label" ng-show="seedSource.id == 'set'">
<span class="input-label" translate>Wallet Recovery Phrase</span>
<input placeholder="{{'Enter the recovery phrase (BIP39)'|translate}}"
autocapitalize="off"
type="text"
ng-model="formData.privateKey">
</label>
<label class="item item-input item-stacked-label" ng-show="create.seedSourceId=='set'">
<span class="input-label" translate>Password</span>
<input type="text"
placeholder="{{'The recovery phrase could require a password to be imported'|translate}}"
autocapitalize="off"
name="passphrase"
ng-model="passphrase">
</label>
<label class="item item-input item-stacked-label" ng-show="seedSource.id == 'set'">
<span class="input-label" translate>Password</span>
<input type="text"
placeholder="{{'The recovery phrase could require a password to be imported'|translate}}"
autocapitalize="off"
ng-model="formData.passphrase">
</label>
<label class="item item-input item-stacked-label" ng-show="create.seedSourceId == 'set'">
<span class="input-label" translate>Derivation Path</span>
<input type="text"
placeholder="{{'BIP32 path for address derivation'|translate}}"
name="derivationPath"
ng-model="derivationPath">
</label>
<label class="item item-input item-stacked-label" ng-show="seedSource.id == 'set'">
<span class="input-label" translate>Derivation Path</span>
<input type="text"
placeholder="{{'BIP32 path for address derivation'|translate}}"
ng-model="formData.derivationPath">
</label>
<ion-toggle ng-show="create.seedSourceId == 'new'" ng-model="testnetEnabled" toggle-class="toggle-positive">
Testnet
</ion-toggle>
<ion-toggle ng-show="seedSource.id == 'new'" ng-model="formData.testnetEnabled" toggle-class="toggle-positive">
Testnet
</ion-toggle>
<ion-toggle ng-model="singleAddressEnabled" toggle-class="toggle-positive">
<span translate>Single Address Wallet</span>
<small translate>For audit purposes</small>
</ion-toggle>
<ion-toggle ng-model="formData.singleAddressEnabled" toggle-class="toggle-positive">
<span translate>Single Address Wallet</span>
<small translate>For audit purposes</small>
</ion-toggle>
</div> <!-- advanced -->
</div> <!-- list -->
</div> <!-- advanced -->
</div> <!-- list -->
<button type="submit"
class="button button-block button-positive"
ng-show="totalCopayers != 1" ng-disabled="setupForm.$invalid">
<span translate>Create {{requiredCopayers}}-of-{{totalCopayers}} wallet</span>
</button>
<button type="submit"
class="button button-block button-positive"
ng-show="totalCopayers == 1" ng-disabled="setupForm.$invalid">
<span translate>Create new wallet</span>
</button>
</form>
</ion-content>
</ion-view>
<button type="submit" class="button button-block button-positive" ng-disabled="setupForm.$invalid">
<span translate>Create {{formData.requiredCopayers}}-of-{{formData.totalCopayers}} wallet</span>
</button>
</form>

View File

@ -7,20 +7,20 @@
<div class="list card" ng-hide="!txps[0]">
<a class="item item-icon-right item-heading" ui-sref="proposals" translate>
<a class="item item-icon-right item-heading" ui-sref="tabs.proposals" translate>
Payment Proposals
<i class="icon ion-ios-arrow-right nav-item-arrow-right"></i>
<span class="badge badge-assertive" ng-show="txpsN>3" translate> {{txpsN}}</span>
</a>
<a ng-repeat="tx in txps" class="item item-icon-left" ng-click="openTxpModal(tx)">
<a ng-repeat="tx in txps" class="item" ng-click="openTxpModal(tx)">
<span ng-include="'views/includes/txp.html'"></span>
</a>
</div>
<div class="list card">
<a class="item item-icon-right item-heading" ui-sref="activity" translate>
<a class="item item-icon-right item-heading" ui-sref="tabs.activity" translate>
Recent Activity
<i class="icon ion-ios-arrow-right nav-item-arrow-right"></i>
</a>
@ -28,7 +28,7 @@
<ion-spinner icon="lines"></ion-spinner>
<div translate>Updating activity. Please stand by</div>
</span>
<a ng-if="!fetchingNotifications" class="item" ng-repeat="x in notifications" ng-click="x.action()">
<a ng-if="notifications[0]" class="item" ng-repeat="x in notifications" ng-click="x.action()">
<span ng-include="'views/includes/walletActivity.html'"></span>
</a>
</div>
@ -118,5 +118,9 @@
</a>
</div>
<p class="padding" style="text-align:center; color:#999">
{{name}} v{{version}}
</p>
</ion-content>
</ion-view>

View File

@ -6,7 +6,6 @@
<ion-content ng-controller="tabSettingsController" ng-init="init()">
<div class="list">
<div class="item item-divider"></div>
<div class="item item-icon-left" ng-click="openAddressbookModal()">
<i class="icon ion-ios-book-outline"></i>
<span translate>Address Book</span>
@ -14,36 +13,40 @@
<div class="item item-divider" translate>Preferences</div>
<div class="item item-icon-left" href ui-sref="tabs.language">
<div class="item item-icon-left item-icon-right" ui-sref="tabs.language">
<i class="icon ion-ios-chatbubble-outline"></i>
<span translate>Language</span>
<span class="item-note">
{{currentLanguageName|translate}}
</span>
<i class="icon ion-ios-arrow-right"></i>
</div>
<div class="item item-icon-left" href ui-sref="tabs.unit">
<div class="item item-icon-left item-icon-right" ui-sref="tabs.unit">
<i class="icon ion-ios-calculator-outline"></i>
<span translate>Unit</span>
<span class="item-note">
{{unitName}}
</span>
<i class="icon ion-ios-arrow-right"></i>
</div>
<div class="item item-icon-left" href ui-sref="tabs.altCurrency">
<div class="item item-icon-left item-icon-right" ui-sref="tabs.altCurrency">
<i class="icon ion-social-usd-outline"></i>
<span translate>Alternative Currency</span>
<span class="item-note">
{{selectedAlternative.name}}
</span>
<i class="icon ion-ios-arrow-right"></i>
</div>
<div class="item item-icon-left" href ui-sref="tabs.fee">
<i class="icon ion-ios-film-outline"></i>
<div class="item item-icon-left item-icon-right" ui-sref="tabs.fee">
<i class="icon ion-social-bitcoin-outline"></i>
<span translate>Bitcoin Network Fee Policy</span>
<span class="item-note">
{{feeOpts[currentFeeLevel]|translate}}
</span>
<i class="icon ion-ios-arrow-right"></i>
</div>
<div ng-show="usePushNotifications && PNEnabledByUser">
@ -80,8 +83,8 @@
<span class="toggle-label" translate>Use Unconfirmed Funds</span>
</ion-toggle>
<div class="item item-divider" translate>Wallets Settings</div>
<div class="item item-icon-left" href
<div class="item item-divider" translate>Wallets Preferences</div>
<div class="item item-icon-left item-icon-right" href
ui-sref="tabs.preferences.main({'walletId': item.id})"
ng-repeat="item in wallets track by $index">
<i class="icon ion-briefcase size-21" ng-style="{'color':item.color}"></i>
@ -92,14 +95,15 @@
<span class="badge badge-assertive" ng-show="!item.isComplete()" translate>
Incomplete
</span>
<i class="icon ion-ios-arrow-right"></i>
</div>
<div class="item item-divider"></div>
<div class="item item-icon-left" href ui-sref="tabs.about">
<i class="icon ion-ios-film-outline"></i>
<span translate>About Bitpay Wallet</span>
<div class="item item-icon-left item-icon-right" href ui-sref="tabs.about">
<i class="icon ion-ios-information-outline"></i>
<span translate>About</span> {{appName}}
<i class="icon ion-ios-arrow-right"></i>
</div>
<div class="item item-divider"></div>
</div>
</ion-content>
</ion-view>

View File

@ -5,14 +5,14 @@
</ion-nav-back-button>
</ion-nav-bar>
<ion-content ng-controller="termOfUseController" cache-view="false">
<p>
<div ng-include="'views/includes/terms.html'"></div>
</p>
<div class="row">
<p ng-show="lang != 'en'">
<a ng-click="$root.openExternalLink('https://copay.io/disclaimer')" translate>Official English Disclaimer</a>
</p>
</div>
<ion-content class="padding" ng-controller="termOfUseController">
<div class="card">
<div class="item item-text-wrap" ng-include="'views/includes/terms.html'"></div>
</div>
<button class="button button-block button-positive"
ng-show="lang != 'en'"
ng-click="openExternalLink(disclaimerUrl)" translate>
Official English Disclaimer
</button>
</ion-content>
</ion-view>

View File

@ -5,29 +5,29 @@
<i class="icon ion-ios-arrow-thin-left"></i>
</ion-nav-back-button>
</ion-nav-bar>
<ion-content>
<h4 translate>Translation Credits</h4>
<ul>
<li >kinoshitajona<span translate>Japanese</span></li>
<li >Kirvx<span translate>French</span></li>
<li >saschad<span translate>German</span></li>
<li >cmgustavo83<span translate>Spanish</span></li>
<li >RussianNeuroMancer<span translate>Russian</span></li>
<li >HostFat<span translate>Italian</span></li>
<li >xm2hi<span translate>Chinese</span></li>
<li >Pirx1618<span translate>Polish</span></li>
<li >mareksip<span translate>Czech</span></li>
</ul>
<div class="row">
<div class="columns">
<p>
<span translate>All contributions to Copay's translation are welcome. Sign up at crowdin.com and join the Copay project at</span>
<a ng-click="$root.openExternalLink('https://crowdin.com/project/copay', '_system')">https://crowdin.com/project/copay</a>.
</p>
<spantranslate>
Don't see your language on Crowdin? Contact the Owner on Crowdin! We'd love to support your language.
</span>
</div>
<ion-content ng-controller="translatorsController">
<div class="list">
<div class="item item-divider" translate>
Translation Credits
</div>
<div class="item">kinoshitajona<span class="item-note" translate>Japanese</span></div>
<div class="item">Kirvx<span class="item-note" translate>French</span></div>
<div class="item">saschad<span class="item-note" translate>German</span></div>
<div class="item">cmgustavo83<span class="item-note" translate>Spanish</span></div>
<div class="item">RussianNeuroMancer<span class="item-note" translate>Russian</span></div>
<div class="item">HostFat<span class="item-note" translate>Italian</span></div>
<div class="item">xm2hi<span class="item-note" translate>Chinese</span></div>
<div class="item">Pirx1618<span class="item-note" translate>Polish</span></div>
<div class="item">mareksip<span class="item-note" translate>Czech</span></div>
</div>
<div class="padding">
<p>
<span translate>All contributions to Copay's translation are welcome. Sign up at crowdin.com and join the Copay project at</span>
<a ng-click="openExternalLink('https://crowdin.com/project/copay', '_system')">https://crowdin.com/project/copay</a>.
</p>
<span translate>
Don't see your language on Crowdin? Contact the Owner on Crowdin! We'd love to support your language.
</span>
</div>
</ion-content>
</ion-view>

View File

@ -94,7 +94,7 @@
</div>
</div>
<div class="release size-12" ng-show="newRelease" ng-click="$root.openExternalLink('https://github.com/bitpay/copay/releases/latest')">
<div class="release size-12" ng-show="newRelease" ng-click="openExternalLink('https://github.com/bitpay/copay/releases/latest')">
<span>{{newRelease}}</span><i class="icon-arrow-right3 right size-18"></i>
</div>

View File

@ -1,15 +1,10 @@
'use strict';
angular.module('copayApp.controllers').controller('amazonController',
function($scope, $timeout, $ionicModal, $log, lodash, bwcError, amazonService, platformInfo, nodeWebkit, popupService) {
function($scope, $timeout, $ionicModal, $log, lodash, bwcError, amazonService, platformInfo, externalLinkService, popupService) {
$scope.openExternalLink = function(url, target) {
if (platformInfo.isNW) {
nodeWebkit.openExternalLink(url);
} else {
target = target || '_blank';
var ref = window.open(url, target, 'location=no');
}
externalLinkService.open(url, target);
};
this.init = function() {

View File

@ -1,7 +1,7 @@
'use strict';
angular.module('copayApp.controllers').controller('buyAmazonController',
function($scope, $log, $timeout, $state, lodash, profileService, bwcError, gettextCatalog, configService, walletService, amazonService, ongoingProcess, platformInfo, nodeWebkit, popupService) {
function($scope, $log, $timeout, $state, lodash, profileService, bwcError, gettextCatalog, configService, walletService, amazonService, ongoingProcess, platformInfo, externalLinkService, popupService) {
var self = this;
var wallet;
@ -16,12 +16,7 @@ angular.module('copayApp.controllers').controller('buyAmazonController',
});
$scope.openExternalLink = function(url, target) {
if (platformInfo.isNW) {
nodeWebkit.openExternalLink(url);
} else {
target = target || '_blank';
var ref = window.open(url, target, 'location=no');
}
externalLinkService.open(url, target);
};
this.init = function() {

View File

@ -5,6 +5,17 @@ angular.module('copayApp.controllers').controller('confirmController', function(
var cachedTxp = {};
var isChromeApp = platformInfo.isChromeApp;
$scope.$on('Wallet/Changed', function(event, wallet) {
if (lodash.isEmpty(wallet)) {
$log.debug('No wallet provided');
return;
}
$log.debug('Wallet changed: ' + wallet.name);
setWallet(wallet, true);
});
$scope.showDescriptionPopup = function() {
var commentPopup = $ionicPopup.show({
templateUrl: "views/includes/note.html",
@ -17,13 +28,6 @@ angular.module('copayApp.controllers').controller('confirmController', function(
$scope.commentPopupSave = function(description) {
$log.debug('Saving description: ' + description);
$scope.description = description;
$scope.txp = null;
createTx($scope.wallet, function(err, txp) {
if (err) return;
cachedTxp[$scope.wallet.id] = txp;
apply(txp);
});
commentPopup.close();
};
};
@ -137,15 +141,6 @@ angular.module('copayApp.controllers').controller('confirmController', function(
});
};
$scope.$on('Wallet/Changed', function(event, wallet) {
if (lodash.isEmpty(wallet)) {
$log.debug('No wallet provided');
return;
}
$log.debug('Wallet changed: ' + wallet.name);
setWallet(wallet, true);
});
function setWallet(wallet, delayed) {
var stop;
$scope.wallet = wallet;
@ -165,7 +160,7 @@ angular.module('copayApp.controllers').controller('confirmController', function(
apply(cachedTxp[wallet.id]);
} else {
stop = $timeout(function() {
createTx(wallet, function(err, txp) {
createTx(wallet, true, function(err, txp) {
if (err) return;
cachedTxp[wallet.id] = txp;
apply(txp);
@ -184,7 +179,7 @@ angular.module('copayApp.controllers').controller('confirmController', function(
$scope.$apply();
};
var createTx = function(wallet, cb) {
var createTx = function(wallet, dryRun, cb) {
var config = configService.getSync().wallet;
var currentSpendUnconfirmed = config.spendUnconfirmed;
var outputs = [];
@ -227,6 +222,7 @@ angular.module('copayApp.controllers').controller('confirmController', function(
txp.payProUrl = paypro;
txp.excludeUnconfirmedUtxos = config.spendUnconfirmed ? false : true;
txp.feeLevel = config.settings.feeLevel || 'normal';
txp.dryRun = dryRun;
walletService.createTx(wallet, txp, function(err, ctxp) {
if (err) {
@ -247,14 +243,10 @@ angular.module('copayApp.controllers').controller('confirmController', function(
$scope.approve = function() {
var wallet = $scope.wallet;
var txp = $scope.txp;
if (!wallet) {
return setSendError(gettextCatalog.getString('No wallet selected'));
};
if (!txp) {
return setSendError(gettextCatalog.getString('No transaction'));
};
if (!wallet.canSign() && !wallet.isPrivKeyExternal()) {
$log.info('No signing proposal: No private key');
@ -265,9 +257,14 @@ angular.module('copayApp.controllers').controller('confirmController', function(
});
}
walletService.publishAndSign(wallet, txp, function(err, txp) {
if (err) return setSendError(err);
$state.transitionTo('tabs.home');
ongoingProcess.set('creatingTx', true);
createTx(wallet, false, function(err, txp) {
ongoingProcess.set('creatingTx', false);
if (err) return;
walletService.publishAndSign(wallet, txp, function(err, txp) {
if (err) return setSendError(err);
$state.transitionTo('tabs.home');
});
});
};

View File

@ -7,11 +7,6 @@ angular.module('copayApp.controllers').controller('createController',
var isCordova = platformInfo.isCordova;
var isDevel = platformInfo.isDevel;
var self = this;
var defaults = configService.getDefaults();
this.isWindowsPhoneApp = platformInfo.isWP && isCordova;
$scope.account = 1;
/* For compressed keys, m*73 + n*34 <= 496 */
var COPAYER_PAIR_LIMITS = {
1: 1,
@ -28,96 +23,91 @@ angular.module('copayApp.controllers').controller('createController',
12: 1,
};
var defaults = configService.getDefaults();
$scope.bwsurl = defaults.bws.url;
$scope.derivationPath = derivationPathHelper.default;
// ng-repeat defined number of times instead of repeating over array?
this.getNumber = function(num) {
return new Array(num);
}
$scope.init = function() {
$scope.formData = {};
var defaults = configService.getDefaults();
$scope.formData.account = 1;
$scope.formData.bwsurl = defaults.bws.url;
$scope.TCValues = lodash.range(2, defaults.limits.totalCopayers + 1);
$scope.formData.totalCopayers = defaults.wallet.totalCopayers;
$scope.formData.derivationPath = derivationPathHelper.default;
$scope.setTotalCopayers(1);
updateRCSelect(1);
updateSeedSourceSelect(1);
};
$scope.showAdvChange = function() {
$ionicScrollDelegate.resize();
};
var updateRCSelect = function(n) {
$scope.totalCopayers = n;
function updateRCSelect(n) {
$scope.formData.totalCopayers = n;
var maxReq = COPAYER_PAIR_LIMITS[n];
self.RCValues = lodash.range(1, maxReq + 1);
$scope.requiredCopayers = Math.min(parseInt(n / 2 + 1), maxReq);
$scope.RCValues = lodash.range(1, maxReq + 1);
$scope.formData.requiredCopayers = Math.min(parseInt(n / 2 + 1), maxReq);
};
var updateSeedSourceSelect = function(n) {
self.seedOptions = [{
function updateSeedSourceSelect(n) {
var seedOptions = [{
id: 'new',
label: gettext('Random'),
}, {
id: 'set',
label: gettext('Specify Recovery Phrase...'),
}];
$scope.seedSource = self.seedOptions[0];
$scope.seedSource = seedOptions[0];
if (n > 1 && isChromeApp)
self.seedOptions.push({
seedOptions.push({
id: 'ledger',
label: 'Ledger Hardware Wallet',
});
if (isChromeApp || isDevel) {
self.seedOptions.push({
seedOptions.push({
id: 'trezor',
label: 'Trezor Hardware Wallet',
});
}
$scope.seedOptions = seedOptions;
};
this.TCValues = lodash.range(2, defaults.limits.totalCopayers + 1);
$scope.totalCopayers = defaults.wallet.totalCopayers;
this.setTotalCopayers = function(tc) {
$scope.setTotalCopayers = function(tc) {
$scope.formData.totalCopayers = tc;
updateRCSelect(tc);
updateSeedSourceSelect(tc);
self.seedSourceId = $scope.seedSource.id;
};
this.setSeedSource = function(src) {
self.seedSourceId = $scope.seedSource.id;
$timeout(function() {
$rootScope.$apply();
});
};
this.create = function(form) {
$scope.create = function(form) {
if (form && form.$invalid) {
popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Please enter the required fields'));
return;
}
var opts = {
m: $scope.requiredCopayers,
n: $scope.totalCopayers,
name: $scope.walletName,
myName: $scope.totalCopayers > 1 ? $scope.myName : null,
networkName: $scope.testnetEnabled ? 'testnet' : 'livenet',
bwsurl: $scope.bwsurl,
singleAddress: $scope.singleAddressEnabled,
walletPrivKey: $scope._walletPrivKey, // Only for testing
name: $scope.formData.walletName,
m: $scope.formData.requiredCopayers,
n: $scope.formData.totalCopayers,
myName: $scope.formData.totalCopayers > 1 ? $scope.formData.myName : null,
networkName: $scope.formData.testnetEnabled ? 'testnet' : 'livenet',
bwsurl: $scope.formData.bwsurl,
singleAddress: $scope.formData.singleAddressEnabled,
walletPrivKey: $scope.formData._walletPrivKey, // Only for testing
};
var setSeed = self.seedSourceId == 'set';
var setSeed = $scope.seedSource.id == 'set';
if (setSeed) {
var words = $scope.privateKey || '';
var words = $scope.formData.privateKey || '';
if (words.indexOf(' ') == -1 && words.indexOf('prv') == 1 && words.length > 108) {
opts.extendedPrivateKey = words;
} else {
opts.mnemonic = words;
}
opts.passphrase = $scope.passphrase;
opts.passphrase = $scope.formData.passphrase;
var pathData = derivationPathHelper.parse($scope.derivationPath);
var pathData = derivationPathHelper.parse($scope.formData.derivationPath);
if (!pathData) {
popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Invalid derivation path'));
return;
@ -128,7 +118,7 @@ angular.module('copayApp.controllers').controller('createController',
opts.derivationStrategy = pathData.derivationStrategy;
} else {
opts.passphrase = $scope.createPassphrase;
opts.passphrase = $scope.formData.createPassphrase;
}
if (setSeed && !opts.mnemonic && !opts.extendedPrivateKey) {
@ -136,36 +126,36 @@ angular.module('copayApp.controllers').controller('createController',
return;
}
if (self.seedSourceId == 'ledger' || self.seedSourceId == 'trezor') {
var account = $scope.account;
if ($scope.seedSource.id == 'ledger' || $scope.seedSource.id == 'trezor') {
var account = $scope.formData.account;
if (!account || account < 1) {
popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Invalid account number'));
return;
}
if (self.seedSourceId == 'trezor')
if ($scope.seedSource.id == 'trezor')
account = account - 1;
opts.account = account;
ongoingProcess.set('connecting' + self.seedSourceId, true);
ongoingProcess.set('connecting' + $scope.seedSource.id, true);
var src = self.seedSourceId == 'ledger' ? ledger : trezor;
var src = $scope.seedSource.id == 'ledger' ? ledger : trezor;
src.getInfoForNewWallet(opts.n > 1, account, function(err, lopts) {
ongoingProcess.set('connecting' + self.seedSourceId, false);
ongoingProcess.set('connecting' + $scope.seedSource.id, false);
if (err) {
popupService.showAlert(gettextCatalog.getString('Error'), err);
return;
}
opts = lodash.assign(lopts, opts);
self._create(opts);
_create(opts);
});
} else {
self._create(opts);
_create(opts);
}
};
this._create = function(opts) {
function _create(opts) {
ongoingProcess.set('creatingWallet', true);
$timeout(function() {
@ -182,35 +172,11 @@ angular.module('copayApp.controllers').controller('createController',
});
if (self.seedSourceId == 'set') {
if ($scope.seedSource.id == 'set') {
profileService.setBackupFlag(client.credentials.walletId);
}
$state.go('tabs.home')
});
}, 100);
}
this.formFocus = function(what) {
if (!this.isWindowsPhoneApp) return
if (what && what == 'my-name') {
this.hideWalletName = true;
this.hideTabs = true;
} else if (what && what == 'wallet-name') {
this.hideTabs = true;
} else {
this.hideWalletName = false;
this.hideTabs = false;
}
$timeout(function() {
$rootScope.$digest();
}, 1);
};
$scope.$on("$destroy", function() {
$rootScope.hideWalletNavigation = false;
});
updateSeedSourceSelect(1);
self.setSeedSource();
});

View File

@ -1,7 +1,7 @@
'use strict';
angular.module('copayApp.controllers').controller('exportController',
function($rootScope, $scope, $timeout, $log, lodash, backupService, walletService, storageService, profileService, platformInfo, gettext, gettextCatalog, $state, $stateParams, popupService) {
function($rootScope, $scope, $timeout, $log, $ionicHistory, lodash, backupService, walletService, storageService, profileService, platformInfo, gettext, gettextCatalog, $state, $stateParams, popupService) {
var prevState;
var isWP = platformInfo.isWP;
var isAndroid = platformInfo.isAndroid;
@ -63,6 +63,7 @@ angular.module('copayApp.controllers').controller('exportController',
popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Failed to export'));
return;
}
$ionicHistory.clearHistory();
$state.go('tabs.home');
});
});

View File

@ -1,15 +1,10 @@
'use strict';
angular.module('copayApp.controllers').controller('glideraController',
function($scope, $timeout, $ionicModal, $log, storageService, glideraService, ongoingProcess, platformInfo, nodeWebkit, popupService, gettextCatalog) {
function($scope, $timeout, $ionicModal, $log, storageService, glideraService, ongoingProcess, platformInfo, externalLinkService, popupService, gettextCatalog) {
$scope.openExternalLink = function(url, target) {
if (platformInfo.isNW) {
nodeWebkit.openExternalLink(url);
} else {
target = target || '_blank';
var ref = window.open(url, target, 'location=no');
}
externalLinkService.open(url, target);
};
$scope.init = function(accessToken) {

View File

@ -1,6 +1,6 @@
'use strict';
angular.module('copayApp.controllers').controller('txDetailsController', function($rootScope, $log, $scope, $filter, $stateParams, $ionicPopup, gettextCatalog, profileService, configService, lodash, txFormatService, platformInfo) {
angular.module('copayApp.controllers').controller('txDetailsController', function($rootScope, $log, $scope, $filter, $stateParams, $ionicPopup, gettextCatalog, profileService, configService, lodash, txFormatService, platformInfo, externalLinkService) {
var self = $scope.self;
var wallet = profileService.getWallet($stateParams.walletId);
@ -81,12 +81,7 @@ angular.module('copayApp.controllers').controller('txDetailsController', functio
};
$scope.openExternalLink = function(url, target) {
if (platformInfo.isNW) {
nodeWebkit.openExternalLink(url);
} else {
target = target || '_blank';
var ref = window.open(url, target, 'location=no');
}
externalLinkService.open(url, target);
};
$scope.getShortNetworkName = function() {

View File

@ -32,12 +32,9 @@ angular.module('copayApp.controllers').controller('txpDetailsController', functi
$scope.sign = function() {
$scope.loading = true;
walletService.publishAndSign($scope.wallet, $scope.tx, function(err, txp) {
console.log('[txpDetails.js.35] AFTER publush'); //TODO
$scope.$emit('UpdateTx');
if (err) return setSendError(err);
$scope.close(txp);
$scope.close();
});
};
@ -53,7 +50,7 @@ console.log('[txpDetails.js.35] AFTER publush'); //TODO
if (err)
return setError(err, gettextCatalog.getString('Could not reject payment'));
$scope.close(txpr);
$scope.close();
});
@ -90,7 +87,7 @@ console.log('[txpDetails.js.35] AFTER publush'); //TODO
return setError(err, gettextCatalog.getString('Could not broadcast payment'));
}
$scope.close(txpb);
$scope.close();
});
}, 10);
};
@ -175,7 +172,7 @@ console.log('[txpDetails.js.35] AFTER publush'); //TODO
});
};
$scope.close = function(txp) {
$scope.close = function() {
$scope.loading = null;
$scope.txpDetailsModal.hide();
};

View File

@ -1,7 +1,8 @@
'use strict';
angular.module('copayApp.controllers').controller('backupRequestController', function($scope, $state, $ionicPopup) {
angular.module('copayApp.controllers').controller('backupRequestController', function($scope, $state, $stateParams, $ionicPopup) {
$scope.walletId = $stateParams.walletId;
$scope.openPopup = function() {
var backupLaterPopup = $ionicPopup.show({
templateUrl: "views/includes/backupLaterPopup.html",

View File

@ -1,7 +1,8 @@
'use strict';
angular.module('copayApp.controllers').controller('backupWarningController', function($scope, $state, $ionicPopup, $stateParams, profileService) {
angular.module('copayApp.controllers').controller('backupWarningController', function($scope, $state, $stateParams, $ionicPopup, profileService) {
$scope.walletId = $stateParams.walletId;
$scope.openPopup = function() {
var backupWarningPopup = $ionicPopup.show({
templateUrl: "views/includes/backupWarningPopup.html",
@ -10,7 +11,7 @@ angular.module('copayApp.controllers').controller('backupWarningController', fun
$scope.close = function() {
backupWarningPopup.close();
$state.go('onboarding.backup');
$state.go('onboarding.backup', {walletId: $stateParams.walletId, fromOnboarding: true});
};
}
});

View File

@ -25,9 +25,13 @@ angular.module('copayApp.controllers').controller('collectEmailController', func
if (err) $log.warn(err);
configService.set(opts, function(err) {
if (err) $log.warn(err);
if (!usePushNotifications) $state.go('onboarding.backupRequest');
else $state.go('onboarding.notifications');
if (!usePushNotifications) $state.go('onboarding.backupRequest', {walletId: walletId});
else $state.go('onboarding.notifications', {walletId: walletId});
});
});
};
$scope.onboardingMailSkip = function() {
$state.go('onboarding.backupRequest', {walletId: walletId});
};
});

View File

@ -1,7 +1,8 @@
'use strict';
angular.module('copayApp.controllers').controller('notificationsController', function($scope, $state, profileService) {
angular.module('copayApp.controllers').controller('notificationsController', function($scope, $state, $stateParams, profileService) {
$scope.walletId = $stateParams.walletId;
$scope.allowNotif = function() {
profileService.pushNotificationsInit();
$state.go('onboarding.backupRequest');

View File

@ -1,6 +1,6 @@
'use strict';
angular.module('copayApp.controllers').controller('termsController', function($scope, $log, $state, uxLanguage, profileService) {
angular.module('copayApp.controllers').controller('termsController', function($scope, $log, $state, uxLanguage, profileService, externalLinkService) {
$scope.lang = uxLanguage.currentLanguage;
$scope.confirm = function() {
@ -12,4 +12,8 @@ angular.module('copayApp.controllers').controller('termsController', function($s
});
};
$scope.openExternalLink = function(url, target) {
externalLinkService.open(url, target);
};
});

View File

@ -1,5 +1,5 @@
angular.module('copayApp.controllers').controller('paperWalletController',
function($scope, $timeout, $log, $ionicModal, configService, profileService, $state, addressService, bitcore, ongoingProcess, txFormatService, $stateParams, walletService) {
function($scope, $timeout, $log, $ionicModal, $ionicHistory, configService, profileService, $state, addressService, bitcore, ongoingProcess, txFormatService, $stateParams, walletService) {
var wallet = profileService.getWallet($stateParams.walletId);
var rawTx;
@ -102,6 +102,7 @@ angular.module('copayApp.controllers').controller('paperWalletController',
} else {
var type = walletService.getViewStatus(wallet, txp);
$scope.openStatusModal(type, txp, function() {
$ionicHistory.clearHistory();
$state.go('tabs.home');
});
}

View File

@ -1,6 +1,6 @@
'use strict';
angular.module('copayApp.controllers').controller('paymentUriController',
function($rootScope, $scope, $stateParams, $location, $timeout, profileService, configService, lodash, bitcore, $state) {
function($rootScope, $scope, $stateParams, $location, $timeout, $ionicHistory, profileService, configService, lodash, bitcore, $state) {
function strip(number) {
return (parseFloat(number.toPrecision(12)));
};
@ -47,6 +47,7 @@ angular.module('copayApp.controllers').controller('paymentUriController',
this.selectWallet = function(wid) {
var self = this;
profileService.setAndStoreFocus(wid, function() {});
$ionicHistory.clearHistory();
$state.go('tabs.home');
$timeout(function() {
$rootScope.$emit('paymentUri', self.bitcoinURI);

View File

@ -2,7 +2,7 @@
angular.module('copayApp.controllers').controller('preferencesController',
function($scope, $rootScope, $timeout, $log, $stateParams, $ionicHistory, $ionicNavBarDelegate, gettextCatalog, configService, profileService, fingerprintService, walletService) {
$ionicNavBarDelegate.title(gettextCatalog.getString('Preferences'));
$ionicNavBarDelegate.title(gettextCatalog.getString('Wallet Preferences'));
var wallet = profileService.getWallet($stateParams.walletId);
var walletId = wallet.credentials.walletId;
$scope.wallet = wallet;
@ -14,9 +14,6 @@ angular.module('copayApp.controllers').controller('preferencesController',
return $ionicHistory.goBack();
var config = configService.getSync();
config.aliasFor = config.aliasFor || {};
$scope.alias = config.aliasFor[walletId] || wallet.credentials.walletName;
$scope.color = config.colorFor[walletId] || '#4A90E2';
$scope.encryptEnabled = walletService.isEncrypted(wallet);
if (wallet.isPrivKeyExternal)

View File

@ -1,6 +1,14 @@
'use strict';
angular.module('copayApp.controllers').controller('preferencesAbout',
function($ionicNavBarDelegate, gettextCatalog) {
$ionicNavBarDelegate.title(gettextCatalog.getString('About Copay'));
function($scope, $window, $ionicNavBarDelegate, gettextCatalog, externalLinkService) {
$ionicNavBarDelegate.title(gettextCatalog.getString('About') + ' ' + $window.appConfig.nameCase);
$scope.version = $window.version;
$scope.commitHash = $window.commitHash;
$scope.name = $window.appConfig.gitHubRepoName;
$scope.openExternalLink = function(url, target) {
externalLinkService.open(url, target);
};
});

View File

@ -8,9 +8,8 @@ angular.module('copayApp.controllers').controller('preferencesAliasController',
var walletId = wallet.credentials.walletId;
var config = configService.getSync();
config.aliasFor = config.aliasFor || {};
$scope.walletName = wallet.credentials.walletName;
$scope.alias = config.aliasFor[walletId] || wallet.walletName;
$scope.alias = (config.aliasFor && config.aliasFor[walletId]) || wallet.walletName;
$scope.save = function() {
var opts = {

View File

@ -1,32 +1,17 @@
'use strict';
angular.module('copayApp.controllers').controller('preferencesDeleteWalletController',
function($scope, $ionicPopup, $stateParams, $ionicNavBarDelegate, gettextCatalog, lodash, profileService, $state, ongoingProcess, popupService) {
$ionicNavBarDelegate.title(gettextCatalog.getString('Delete Wallet'));
function($scope, $stateParams, $ionicNavBarDelegate, $ionicHistory, gettextCatalog, lodash, profileService, $state, ongoingProcess, popupService) {
$ionicNavBarDelegate.title(gettextCatalog.getString('Delete'));
var wallet = profileService.getWallet($stateParams.walletId);
$scope.alias = lodash.isEqual(wallet.name, wallet.credentials.walletName) ? null : wallet.name + ' ';
$scope.walletName = '[' + wallet.credentials.walletName + ']';
$scope.showDeletePopup = function() {
var popup = $ionicPopup.show({
template: '<span>' + gettextCatalog.getString('Are you sure you want to delete this wallet?') + '</span>',
title: gettextCatalog.getString('Confirm'),
buttons: [
{
text: gettextCatalog.getString('Cancel'),
onTap: function(e) {
popup.close();
}
},
{
text: gettextCatalog.getString('Accept'),
type: 'button-positive',
onTap: function(e) {
deleteWallet();
popup.close();
}
}
]
var title = gettextCatalog.getString('Warning!');
var message = gettextCatalog.getString('Are you sure you want to delete this wallet?');
popupService.showConfirm(title, message, function(res) {
if (res) deleteWallet();
});
};
@ -37,6 +22,7 @@ angular.module('copayApp.controllers').controller('preferencesDeleteWalletContro
if (err) {
popupService.showAlert(gettextCatalog.getString('Error'), err.message || err);
} else {
$ionicHistory.clearHistory();
$state.go('tabs.home');
}
});

View File

@ -1,12 +1,12 @@
'use strict';
angular.module('copayApp.controllers').controller('preferencesFeeController', function($scope, $timeout, $ionicHistory, $ionicNavBarDelegate, gettextCatalog, configService, feeService) {
$ionicNavBarDelegate.title(gettextCatalog.getString('Preferences fee'));
angular.module('copayApp.controllers').controller('preferencesFeeController', function($scope, $timeout, $ionicHistory, $ionicNavBarDelegate, gettextCatalog, configService, feeService, ongoingProcess) {
$ionicNavBarDelegate.title(gettextCatalog.getString('Bitcoin Network Fee Policy'));
$scope.init = function() {
$scope.loading = true;
ongoingProcess.set('gettingFeeLevels', true);
feeService.getFeeLevels(function(levels) {
$scope.loading = false;
ongoingProcess.set('gettingFeeLevels', false);
$scope.feeOpts = feeService.feeOpts;
$scope.currentFeeLevel = feeService.getCurrentFeeLevel();
$scope.feeLevels = levels;
@ -29,7 +29,7 @@ angular.module('copayApp.controllers').controller('preferencesFeeController', fu
$ionicHistory.goBack();
$timeout(function() {
$scope.$apply();
}, 10);
}, 100);
});
};
});

View File

@ -1,17 +1,16 @@
'use strict';
angular.module('copayApp.controllers').controller('preferencesHistory',
function($scope, $log, $stateParams, $timeout, $ionicNavBarDelegate, gettextCatalog, storageService, $state, profileService, lodash) {
function($scope, $log, $stateParams, $timeout, $ionicNavBarDelegate, gettextCatalog, storageService, $state, $ionicHistory, profileService, lodash) {
$ionicNavBarDelegate.title(gettextCatalog.getString('Transaction History'));
var wallet = profileService.getWallet($stateParams.walletId);
var c = wallet.credentials;
$scope.wallet = profileService.getWallet($stateParams.walletId);
$scope.csvReady = false;
$scope.csvHistory = function(cb) {
var allTxs = [];
function getHistory(cb) {
storageService.getTxHistory(c.walletId, function(err, txs) {
storageService.getTxHistory($scope.wallet.id, function(err, txs) {
if (err) return cb(err);
var txsFromLocal = [];
@ -22,7 +21,7 @@ angular.module('copayApp.controllers').controller('preferencesHistory',
}
allTxs.push(txsFromLocal);
return cb(null, lodash.flatten(allTxs));
return cb(null, lodash.compact(lodash.flatten(allTxs)));
});
};
@ -40,7 +39,7 @@ angular.module('copayApp.controllers').controller('preferencesHistory',
var data = txs;
var satToBtc = 1 / 100000000;
$scope.csvContent = [];
$scope.csvFilename = 'Copay-' + ($scope.alias || $scope.walletName) + '.csv';
$scope.csvFilename = 'Copay-' + $scope.wallet.name + '.csv';
$scope.csvHeader = ['Date', 'Destination', 'Description', 'Amount', 'Currency', 'Txid', 'Creator', 'Copayers', 'Comment'];
var _amount, _note, _copayers, _creator, _comment;
@ -118,7 +117,7 @@ angular.module('copayApp.controllers').controller('preferencesHistory',
};
$scope.clearTransactionHistory = function() {
storageService.removeTxHistory(c.walletId, function(err) {
storageService.removeTxHistory($scope.wallet.id, function(err) {
if (err) {
$log.error(err);
return;
@ -126,6 +125,7 @@ angular.module('copayApp.controllers').controller('preferencesHistory',
$scope.$emit('Local/ClearHistory');
$timeout(function() {
$ionicHistory.clearHistory();
$state.go('tabs.home');
}, 100);
});

View File

@ -1,7 +1,7 @@
'use strict';
angular.module('copayApp.controllers').controller('preferencesInformation',
function($scope, $log, $timeout, $ionicNavBarDelegate, platformInfo, gettextCatalog, lodash, profileService, configService, $stateParams, walletService, $state) {
function($scope, $log, $timeout, $ionicNavBarDelegate, $ionicHistory, platformInfo, gettextCatalog, lodash, profileService, configService, $stateParams, walletService, $state) {
$ionicNavBarDelegate.title(gettextCatalog.getString('Wallet Information'));
var base = 'xpub';
var wallet = profileService.getWallet($stateParams.walletId);
@ -105,6 +105,7 @@ angular.module('copayApp.controllers').controller('preferencesInformation',
opts.colorFor[walletId] = color;
configService.set(opts, function(err) {
$ionicHistory.clearHistory();
$state.go('tabs.home');
if (err) $log.warn(err);
});
@ -116,6 +117,7 @@ angular.module('copayApp.controllers').controller('preferencesInformation',
$scope.scan = function() {
walletService.startScan(wallet);
$ionicHistory.clearHistory();
$state.go('tabs.home');
};

View File

@ -1,9 +1,13 @@
'use strict';
angular.module('copayApp.controllers').controller('preferencesLanguageController',
function($scope, $log, $ionicNavBarDelegate, $ionicHistory, gettextCatalog, configService, profileService, uxLanguage, walletService) {
function($scope, $log, $ionicNavBarDelegate, $ionicHistory, gettextCatalog, configService, profileService, uxLanguage, walletService, externalLinkService) {
$ionicNavBarDelegate.title(gettextCatalog.getString('Language'));
$scope.openExternalLink = function(url, target) {
externalLinkService.open(url, target);
};
$scope.init = function() {
$scope.availableLanguages = uxLanguage.getLanguages();
$scope.currentLanguage = uxLanguage.getCurrentLanguage();
@ -22,7 +26,7 @@ angular.module('copayApp.controllers').controller('preferencesLanguageController
if (err) $log.warn(err);
$ionicHistory.goBack();
uxLanguage.update(function() {
uxLanguage.init(function() {
walletService.updateRemotePreferences(profileService.getWallets(), {}, function() {
$log.debug('Remote preferences saved');
});

View File

@ -8,13 +8,19 @@ angular.module('copayApp.controllers').controller('preferencesLogs',
$scope.logs = historicLog.get();
}
$scope.sendLogs = function() {
var body = 'Copay Session Logs\n Be careful, this could contain sensitive private data\n\n';
body += '\n\n';
body += $scope.logs.map(function(v) {
$scope.prepare = function() {
var log = 'Copay Session Logs\n Be careful, this could contain sensitive private data\n\n';
log += '\n\n';
log += $scope.logs.map(function(v) {
return v.msg;
}).join('\n');
return log;
};
$scope.sendLogs = function() {
var body = $scope.prepare();
window.plugins.socialsharing.shareViaEmail(
body,
'Copay Logs',

View File

@ -1,23 +1,30 @@
'use strict';
angular.module('copayApp.controllers').controller('tabHomeController',
function($rootScope, $timeout, $scope, $state, $ionicScrollDelegate, lodash, profileService, walletService, configService, txFormatService, $ionicModal, $log, platformInfo, storageService, txpModalService) {
function($rootScope, $timeout, $scope, $state, $ionicScrollDelegate, lodash, profileService, walletService, configService, txFormatService, $ionicModal, $log, platformInfo, storageService, txpModalService, $window) {
$scope.externalServices = {};
$scope.bitpayCardEnabled = true; // TODO
function updateTxps() {
profileService.getTxps({
limit: 3
}, function(err, txps, n) {
if (err) {
console.log('[tab-home.js.35:err:]', $log.error(err)); //TODO
}
$scope.txps = txps;
$scope.txpsN = n;
$ionicScrollDelegate.resize();
var setPendingTxps = function(txps) {
if (!txps) {
$scope.txps = [];
return;
}
$scope.txps = lodash.sortBy(txps, 'createdOn').reverse();
$timeout(function() {
$scope.$apply();
}, 1);
})
};
$scope.updateAllWallets = function() {
$scope.wallets = profileService.getWallets();
if (lodash.isEmpty($scope.wallets)) return;
@ -35,20 +42,7 @@ angular.module('copayApp.controllers').controller('tabHomeController',
wallet.status = status;
}
if (++j==i) {
profileService.getTxps({
limit: 3
}, function(err, txps, n) {
if (err) {
console.log('[tab-home.js.35:err:]', $log.error(err)); //TODO
}
$scope.txps = txps;
$scope.txpsN = n;
$ionicScrollDelegate.resize();
$timeout(function() {
$scope.$apply();
}, 1);
});
updateTxps();
}
});
});
@ -81,29 +75,18 @@ angular.module('copayApp.controllers').controller('tabHomeController',
}
wallet.status = status;
$scope.fetchingNotifications = true;
profileService.getNotifications({
limit: 3
}, function(err, notifications) {
$scope.fetchingNotifications = false;
if (err) {
console.log('[tab-home.js.35:err:]', $log.error(err)); //TODO
return;
}
$scope.notifications = notifications;
profileService.getTxps({
limit: 3
}, function(err, txps, n) {
if (err) {
console.log('[tab-home.js.35:err:]', $log.error(err)); //TODO
}
$scope.txps = txps;
$scope.txpsN = n;
$ionicScrollDelegate.resize();
$timeout(function() {
$scope.$apply();
}, 1);
})
updateTxps();
})
});
};
@ -123,6 +106,7 @@ angular.module('copayApp.controllers').controller('tabHomeController',
$scope.updateWallet(wallet);
}),
$rootScope.$on('Local/TxAction', function(e, walletId) {
$log.debug('Got action for wallet '+ walletId);
var wallet = profileService.getWallet(walletId);
$scope.updateWallet(wallet);
}),
@ -143,5 +127,9 @@ angular.module('copayApp.controllers').controller('tabHomeController',
$scope.openTxpModal = txpModalService.open;
$scope.version = $window.version;
$scope.name = $window.appConfig.nameCase;
});

View File

@ -1,6 +1,6 @@
'use strict';
angular.module('copayApp.controllers').controller('tabSettingsController', function($scope, $rootScope, $log, $ionicModal, lodash, configService, uxLanguage, platformInfo, pushNotificationsService, profileService, feeService) {
angular.module('copayApp.controllers').controller('tabSettingsController', function($scope, $rootScope, $log, $ionicModal, $window, lodash, configService, uxLanguage, platformInfo, pushNotificationsService, profileService, feeService) {
$scope.init = function() {
@ -9,6 +9,8 @@ angular.module('copayApp.controllers').controller('tabSettingsController', funct
var isWP = platformInfo.isWP;
var isIOS = platformInfo.isIOS;
$scope.appName = $window.appConfig.nameCase;
$scope.unitName = config.wallet.settings.unitName;
$scope.currentLanguageName = uxLanguage.getCurrentLanguageName();
$scope.selectedAlternative = {
@ -30,9 +32,6 @@ angular.module('copayApp.controllers').controller('tabSettingsController', funct
$scope.glideraEnabled = config.glidera.enabled;
$scope.coinbaseEnabled = config.coinbase.enabled;
$scope.pushNotifications = config.pushNotifications.enabled;
if (isCordova && StatusBar.isVisible) {
StatusBar.backgroundColorByHexString("#4B6178");
}
$scope.otherWallets = lodash.filter(profileService.getWallets(self.network), function(w) {
return w.id != self.walletId;
});

View File

@ -1,7 +1,12 @@
'use strict';
angular.module('copayApp.controllers').controller('termOfUseController',
function($scope, uxLanguage, $ionicNavBarDelegate, gettextCatalog) {
$ionicNavBarDelegate.title(gettextCatalog.getString('About Copay'));
function($scope, $window, uxLanguage, $ionicNavBarDelegate, gettextCatalog, externalLinkService) {
$ionicNavBarDelegate.title(gettextCatalog.getString('Terms Of Use'));
$scope.lang = uxLanguage.currentLanguage;
$scope.disclaimerUrl = $window.appConfig.disclaimerUrl;
$scope.openExternalLink = function(url, target) {
externalLinkService.open(url, target);
};
});

View File

@ -0,0 +1,8 @@
'use strict';
angular.module('copayApp.controllers').controller('translatorsController',
function($scope, externalLinkService) {
$scope.openExternalLink = function(url, target) {
externalLinkService.open(url, target);
};
});

View File

@ -1,6 +1,6 @@
'use strict';
angular.module('copayApp.controllers').controller('walletDetailsController', function($scope, $rootScope, $interval, $timeout, $filter, $log, $ionicModal, $ionicPopover, $ionicNavBarDelegate, $state, $stateParams, bwcError, profileService, lodash, configService, gettext, gettextCatalog, platformInfo, walletService, $ionicPopup, txpModalService) {
angular.module('copayApp.controllers').controller('walletDetailsController', function($scope, $rootScope, $interval, $timeout, $filter, $log, $ionicModal, $ionicPopover, $ionicNavBarDelegate, $state, $stateParams, bwcError, profileService, lodash, configService, gettext, gettextCatalog, platformInfo, walletService, $ionicPopup, txpModalService, externalLinkService) {
var isCordova = platformInfo.isCordova;
var isWP = platformInfo.isWP;
@ -12,6 +12,9 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun
var HISTORY_SHOW_LIMIT = 10;
$scope.txps = [];
$scope.openExternalLink = function(url, target) {
externalLinkService.open(url, target);
};
var setPendingTxps = function(txps) {
if (!txps) {

View File

@ -1,7 +1,7 @@
'use strict';
angular.module('copayApp.directives')
.directive('copyToClipboard', function(platformInfo, nodeWebkit, gettextCatalog, ionicToast, clipboard) {
.directive('copyToClipboard', function(platformInfo, nodeWebkitService, gettextCatalog, ionicToast, clipboard) {
return {
restrict: 'A',
scope: {
@ -22,7 +22,7 @@ angular.module('copayApp.directives')
window.cordova.plugins.clipboard.copy(data);
window.plugins.toast.showShortCenter(msg);
} else if (isNW) {
nodeWebkit.writeToClipboard(data);
nodeWebkitService.writeToClipboard(data);
scope.$apply(function() {
ionicToast.show(msg, 'bottom', false, 1000);
});

View File

@ -143,14 +143,6 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
url: '/uri-coinbase/:url',
templateUrl: 'views/coinbaseUri.html'
})
.state('activity', {
url: '/activity',
templateUrl: 'views/activity.html'
})
.state('proposals', {
url: '/proposals',
templateUrl: 'views/proposals.html'
})
/*
*
@ -159,17 +151,33 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
*/
.state('tabs.details', {
url: '/details/{walletId}/{fromOnboarding}',
views: {
'tab-home': {
templateUrl: 'views/walletDetails.html'
url: '/details/{walletId}/{fromOnboarding}',
views: {
'tab-home': {
templateUrl: 'views/walletDetails.html'
}
},
params: {
txid: null,
txpId: null,
},
})
.state('tabs.activity', {
url: '/activity',
views: {
'tab-home': {
templateUrl: 'views/activity.html',
}
}
},
params: {
txid: null,
txpId: null,
},
})
})
.state('tabs.proposals', {
url: '/proposals',
views: {
'tab-home': {
templateUrl: 'views/proposals.html',
}
}
})
/*
*
@ -254,12 +262,7 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
url: '/add',
views: {
'tab-home': {
templateUrl: 'views/add.html',
controller: function(platformInfo) {
if (platformInfo.isCordova && StatusBar.isVisible) {
StatusBar.backgroundColorByHexString("#4B6178");
}
}
templateUrl: 'views/add.html'
}
}
})
@ -306,30 +309,12 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
})
.state('tabs.create', {
url: '/create',
abstract: true,
templateUrl: 'views/create.html',
views: {
'tab-home': {
templateUrl: 'views/create.html'
},
}
})
.state('tabs.create.personal', {
url: '/tab-create-personal',
views: {
'tab-create-personal': {
templateUrl: 'views/tab-create-personal.html',
},
}
})
.state('tabs.create.shared', {
url: '/tab-create-shared',
views: {
'tab-create-shared': {
templateUrl: 'views/tab-create-shared.html',
},
}
})
/*
*
@ -565,11 +550,7 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
.state('onboarding', {
url: '/onboarding',
abstract: true,
template: '<ion-nav-view name="onboarding"></ion-nav-view>',
params: {
walletId: null,
fromOnboarding: null,
},
template: '<ion-nav-view name="onboarding"></ion-nav-view>'
})
.state('onboarding.welcome', {
url: '/welcome',
@ -588,7 +569,7 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
}
})
.state('onboarding.collectEmail', {
url: '/collectEmail',
url: '/collectEmail/:walletId',
views: {
'onboarding': {
templateUrl: 'views/onboarding/collectEmail.html'
@ -596,7 +577,7 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
}
})
.state('onboarding.notifications', {
url: '/notifications',
url: '/notifications/:walletId',
views: {
'onboarding': {
templateUrl: 'views/onboarding/notifications.html'
@ -604,7 +585,7 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
}
})
.state('onboarding.backupRequest', {
url: '/backupRequest',
url: '/backupRequest/:walletId',
views: {
'onboarding': {
templateUrl: 'views/onboarding/backupRequest.html'
@ -612,7 +593,7 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
}
})
.state('onboarding.backupWarning', {
url: '/backupWarning',
url: '/backupWarning/:walletId',
views: {
'onboarding': {
templateUrl: 'views/onboarding/backupWarning.html'
@ -620,7 +601,7 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
}
})
.state('onboarding.backup', {
url: '/backup',
url: '/backup/:walletId/:fromOnboarding',
views: {
'onboarding': {
templateUrl: 'views/backup.html'
@ -652,7 +633,8 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
},
},
params: {
code: null
code: null,
fromOnboarding: null
},
})
.state('onboarding.import.phrase', {
@ -807,74 +789,35 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
})
.run(function($rootScope, $state, $location, $log, $timeout, $ionicHistory, $ionicPlatform, lodash, platformInfo, profileService, uxLanguage, gettextCatalog, openURLService) {
if (platformInfo.isCordova) {
if (screen.width < 768) {
screen.lockOrientation('portrait');
} else {
window.addEventListener("orientationchange", function() {
var leftMenuWidth = document.querySelector("ion-side-menu[side='left']").clientWidth;
if (screen.orientation.includes('portrait')) {
// Portrait
document.querySelector("ion-side-menu-content").style.width = (screen.width - leftMenuWidth) + "px";
} else {
// Landscape
document.querySelector("ion-side-menu-content").style.width = (screen.height - leftMenuWidth) + "px";
}
});
}
} else {
if (screen.width >= 768) {
window.addEventListener('resize', lodash.throttle(function() {
$rootScope.$emit('Local/WindowResize');
}, 100));
}
}
uxLanguage.init();
openURLService.init();
$ionicPlatform.ready(function() {
if (platformInfo.isCordova) {
window.addEventListener('native.keyboardhide', function() {
$timeout(function() {
$rootScope.shouldHideMenuBar = false; //show menu bar when keyboard is hidden with back button action on send screen
}, 100);
});
window.addEventListener('native.keyboardshow', function() {
$timeout(function() {
$rootScope.shouldHideMenuBar = true; //hide menu bar when keyboard opens with back button action on send screen
}, 300);
});
if (window.cordova && window.cordova.plugins && window.cordova.plugins.Keyboard) {
cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
cordova.plugins.Keyboard.disableScroll(true);
}
if (window.StatusBar) {
StatusBar.styleLightContent();
}
$ionicPlatform.registerBackButtonAction(function(e) {
var fromDisclaimer = $ionicHistory.currentStateName().match(/disclaimer/) ? 'true' : '';
var fromTabs = $ionicHistory.currentStateName().match(/tabs/) ? 'true' : '';
var fromDisclaimer = $ionicHistory.currentStateName().match(/disclaimer/) ? 'true' : '';
var fromTabs = $ionicHistory.currentStateName().match(/tabs/) ? 'true' : '';
if ($rootScope.backButtonPressedOnceToExit || fromDisclaimer) {
ionic.Platform.exitApp();
} else if ($ionicHistory.backView() && !fromTabs) {
$ionicHistory.goBack();
} else {
$rootScope.backButtonPressedOnceToExit = true;
window.plugins.toast.showShortBottom(gettextCatalog.getString('Press again to exit'));
setInterval(function() {
$rootScope.backButtonPressedOnceToExit = false;
}, 5000);
}
e.preventDefault();
},
101);
if ($rootScope.backButtonPressedOnceToExit || fromDisclaimer) {
ionic.Platform.exitApp();
} else if ($ionicHistory.backView() && !fromTabs) {
$ionicHistory.goBack();
} else {
$rootScope.backButtonPressedOnceToExit = true;
window.plugins.toast.showShortBottom(gettextCatalog.getString('Press again to exit'));
setInterval(function() {
$rootScope.backButtonPressedOnceToExit = false;
}, 5000);
}
e.preventDefault();
}, 101);
$ionicPlatform.on('pause', function() {
// Nothing to do
@ -890,7 +833,7 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
setTimeout(function() {
navigator.splashscreen.hide();
}, 1000);
}, 500);
}

View File

@ -1,6 +1,6 @@
'use strict';
angular.module('copayApp.services')
.factory('applicationService', function($rootScope, $timeout, platformInfo, $state) {
.factory('applicationService', function($rootScope, $timeout, $ionicHistory, platformInfo, $state) {
var root = {};
var isChromeApp = platformInfo.isChromeApp;
@ -19,6 +19,7 @@ angular.module('copayApp.services')
if (isChromeApp) {
chrome.runtime.reload();
} else if (isNW) {
$ionicHistory.clearHistory();
$state.go('tabs.home');
$timeout(function() {
var win = require('nw.gui').Window.get();

View File

@ -0,0 +1,14 @@
'use strict';
angular.module('copayApp.services').service('externalLinkService', function(platformInfo, nodeWebkitService) {
this.open = function(url, target) {
if (platformInfo.isNW) {
nodeWebkitService.openExternalLink(url);
} else {
target = target || '_blank';
var ref = window.open(url, target, 'location=no');
}
};
});

View File

@ -1,6 +1,6 @@
'use strict';
angular.module('copayApp.services').factory('incomingData', function($log, $ionicModal, $state, bitcore) {
angular.module('copayApp.services').factory('incomingData', function($log, $ionicModal, $state, $window, bitcore) {
var root = {};
@ -63,10 +63,10 @@ angular.module('copayApp.services').factory('incomingData', function($log, $ioni
return $state.go('send.amount', {toAddress: data})
// copay: protocol
} else if (data.indexOf('copay://glidera')==0) {
// Protocol
} else if (data.indexOf($window.appConfig.name + '://glidera')==0) {
return $state.go('uriglidera', {url: data})
} else if (data.indexOf('copay://coinbase')==0) {
} else if (data.indexOf($window.appConfig.name + '://coinbase')==0) {
return $state.go('uricoinbase', {url: data})
// Join

View File

@ -1,38 +0,0 @@
'use strict';
angular.module('copayApp.services').factory('nodeWebkit', function nodeWebkitFactory() {
var root = {};
var isNodeWebkit = function() {
var isNode = (typeof process !== "undefined" && typeof require !== "undefined");
if(isNode) {
try {
return (typeof require('nw.gui') !== "undefined");
} catch(e) {
return false;
}
}
};
root.readFromClipboard = function() {
if (!isNodeWebkit()) return;
var gui = require('nw.gui');
var clipboard = gui.Clipboard.get();
return clipboard.get();
};
root.writeToClipboard = function(text) {
if (!isNodeWebkit()) return;
var gui = require('nw.gui');
var clipboard = gui.Clipboard.get();
return clipboard.set(text);
};
root.openExternalLink = function(url) {
if (!isNodeWebkit()) return;
var gui = require('nw.gui');
return gui.Shell.openExternal(url);
};
return root;
});

View File

@ -0,0 +1,22 @@
'use strict';
angular.module('copayApp.services').service('nodeWebkitService', function() {
this.readFromClipboard = function() {
var gui = require('nw.gui');
var clipboard = gui.Clipboard.get();
return clipboard.get();
};
this.writeToClipboard = function(text) {
var gui = require('nw.gui');
var clipboard = gui.Clipboard.get();
return clipboard.set(text);
};
this.openExternalLink = function(url) {
var gui = require('nw.gui');
return gui.Shell.openExternal(url);
};
});

View File

@ -31,6 +31,7 @@ angular.module('copayApp.services').factory('ongoingProcess', function($log, $ti
'sweepingWallet': gettext('Sweeping Wallet...'),
'deletingWallet': gettext('Deleting Wallet...'),
'extractingWalletInfo': gettext('Extracting Wallet Information...'),
'gettingFeeLevels': gettext('Getting fee levels...'),
};
root.clear = function() {

View File

@ -30,13 +30,12 @@ angular.module('copayApp.services')
root.updateWalletSettings = function(wallet) {
var defaults = configService.getDefaults();
var config = configService.getSync();
wallet.usingCustomBWS = config.bwsFor && config.bwsFor[wallet.id] && (config.bwsFor[wallet.id] != defaults.bws.url);
wallet.name = config.aliasFor && (config.aliasFor[wallet.id] || wallet.credentials.walletName);
wallet.color = config.colorFor && (config.colorFor[wallet.id] || '#4A90E2');
wallet.email = config.emailFor && config.emailFor[wallet.id];
configService.whenAvailable(function(config){
wallet.usingCustomBWS = config.bwsFor && config.bwsFor[wallet.id] && (config.bwsFor[wallet.id] != defaults.bws.url);
wallet.name = (config.aliasFor && config.aliasFor[wallet.id]) || wallet.credentials.walletName;
wallet.color = (config.colorFor && config.colorFor[wallet.id]) || '#4A90E2';
wallet.email = config.emailFor && config.emailFor[wallet.id];
});
}
root.setBackupFlag = function(walletId) {
@ -78,7 +77,7 @@ angular.module('copayApp.services')
var opts = opts || {};
var walletId = wallet.credentials.walletId;
if ((root.wallet[walletId] && root.wallet[walletId].started) || opts.force) {
if ((root.wallet[walletId] && root.wallet[walletId].started) && !opts.force) {
return false;
}
@ -123,7 +122,6 @@ angular.module('copayApp.services')
if (wallet.cachedActivity)
wallet.cachedActivity.isValid = false;
if (wallet.cachedTxps)
wallet.cachedTxps.isValid = false;
@ -908,22 +906,14 @@ angular.module('copayApp.services')
var txps = [];
function process(notifications) {
if (!notifications) return [];
var shown = lodash.sortBy(notifications, 'createdOn').reverse();
shown = shown.splice(0, opts.limit || MAX);
return shown;
};
lodash.each(w, function(x) {
if (x.pendingTxps)
txps = txps.concat(x.pendingTxps);
});
txps = lodash.sortBy(txps, 'createdOn');
txps = lodash.sortBy(txps, 'pendingForUs', 'createdOn');
txps = lodash.compact(lodash.flatten(txps)).slice(0,MAX);
var n = txps.length;
return cb(null, process(txps), n);
return cb(null, txps, n);
};
return root;

View File

@ -73,6 +73,7 @@ angular.module('copayApp.services')
$log.debug('Setting default language: ' + lang);
gettextCatalog.setCurrentLanguage(lang);
root.currentLanguage = lang;
if (lang == 'zh') lang = lang + '-CN'; // Fix for Chinese Simplified
amMoment.changeLocale(lang);
};
@ -95,31 +96,19 @@ angular.module('copayApp.services')
return root.availableLanguages;
};
root.init = function() {
root._detect(function(lang) {
root._set(lang);
});
};
root.init = function(cb) {
configService.whenAvailable(function(config) {
var userLang = config.wallet.settings.defaultLanguage;
root.update = function(cb) {
var userLang = configService.getSync().wallet.settings.defaultLanguage;
if (!userLang) {
root._detect(function(lang) {
userLang = lang;
if (userLang != root.currentLanguage) {
root._set(lang);
}
if (cb) return cb(userLang);
});
} else {
if (userLang != root.currentLanguage) {
if (userLang && userLang != root.currentLanguage) {
root._set(userLang);
} else {
root._detect(function(lang) {
root._set(lang);
});
}
if (cb) return cb(userLang);
}
if (cb) return cb();
});
};
root.getName = function(lang) {

View File

@ -92,13 +92,17 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
root.invalidateCache = function(wallet) {
if (wallet.cachedStatus) {
if (wallet.cachedStatus)
wallet.cachedStatus.isValid = false;
}
if (wallet.completeHistory) {
if (wallet.completeHistory)
wallet.completeHistory.isValid = false;
}
if (wallet.cachedActivity)
wallet.cachedActivity.isValid = false;
if (wallet.cachedTxps)
wallet.cachedTxps.isValid = false;
};
root.getStatus = function(wallet, opts, cb) {
@ -623,6 +627,10 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
wallet.removeTxProposal(txp, function(err) {
$log.debug('Transaction removed');
root.invalidateCache(wallet);
$rootScope.$emit('Local/TxAction', wallet.id);
return cb(err);
});
};
@ -852,6 +860,8 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
askPassword(wallet.name, gettext('Enter Spending Password'), function(password) {
if (!password) return cb('no password');
if (!wallet.checkPassword(password)) return cb('wrong password');
return cb(null, password);
});
@ -862,8 +872,8 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
ongoingProcess.set('rejectTx', true);
root.rejectTx(wallet, txp, function(err, txpr) {
root.invalidateCache(wallet);
ongoingProcess.set('rejectTx', false);
if (err) return cb(err);
$rootScope.$emit('Local/TxAction', wallet.id);
@ -933,6 +943,7 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
var msg = err.message ?
err.message :
gettext('The payment was created but could not be completed. Please try again from home screen');
$rootScope.$emit('Local/TxAction', wallet.id);
return cb(msg);
}
@ -943,18 +954,18 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
ongoingProcess.set('broadcastingTx', false);
if (err) return cb('sign error' + err);
$rootScope.$emit('Local/TxAction', wallet.id);
var type = root.getViewStatus(wallet, broadcastedTxp);
root.openStatusModal(type, broadcastedTxp, function() {
$rootScope.$emit('Local/TxAction', wallet.id);
});
return cb(null, broadcastedTxp)
});
} else {
$rootScope.$emit('Local/TxAction', wallet.id);
var type = root.getViewStatus(wallet, signedTxp);
root.openStatusModal(type, signedTxp, function() {
root.invalidateCache(wallet);
$rootScope.$emit('Local/TxAction', wallet.id);
});
return cb(null, signedTxp);
}

View File

@ -1,5 +1,9 @@
.wallet-activity {
&-not-pending {
background-color:#eee;
}
&-amount {
float: right;
font-size: 18px;

View File

@ -1,5 +1,8 @@
#onboarding-collect-email {
background: rgb(17, 209, 166);
.scroll {
height: 100%;
}
#success-image {
margin-top: 4rem;
}
@ -11,17 +14,18 @@
opacity: 1;
background: #fff;
color: rgb(108, 108, 108);
height: 11rem;
height: 13rem;
animation-name: topBottom;
animation-iteration-count: 1;
animation-timing-function: ease-in;
animation-duration: 1s;
animation-delay: 2s;
position: absolute;
bottom: -100%;
bottom: -13rem;
animation-fill-mode: forwards;
z-index: 5;
margin-top: 0;
width: 100%;
label {
background: rgba(200, 200, 200, 0.20);
height: 3rem;

View File

@ -7,7 +7,7 @@
#shopping-24 {
content: url("../img/onboarding-welcome-shopping24.png");
position: absolute;
top: 2%;
top: 5%;
right: 5%;
width: 35px;
height: auto;
@ -17,7 +17,7 @@
@include center-block();
}
.logo {
margin-top: 15rem;
margin-top: 13rem;
}
button {
@include center-block(1rem);

View File

@ -34,7 +34,7 @@
background-size: contain;
width: 100%;
clear: both;
height: 20rem;
height: 23rem;
margin-bottom: -3rem;
background-position: center;
background-repeat: no-repeat;

View File

@ -3,8 +3,8 @@
background: #fff;
box-shadow: 0px 3px 3px 0px rgba(50, 50, 50, 0.2);
}
ion-content {
margin-top: 1.5rem;
ion-content{
padding-top: 1.5rem;
color: rgba(86, 86, 86, 0.77);
p {
padding: 0 2.5%;