Merge pull request #2036 from matiu/bug/nativation/pin

Bug/nativation/pin
This commit is contained in:
Gustavo Maximiliano Cortez 2014-12-07 16:28:27 -03:00
commit 75b23e66bb
24 changed files with 199 additions and 145 deletions

View file

@ -42,7 +42,7 @@ var defaultConfig = {
// local encryption/security config
passphraseConfig: {
iterations: 1000,
iterations: 5000,
storageSalt: 'mjuBtGybi/4=',
},

View file

@ -1,8 +1,8 @@
<?xml version='1.0' encoding='utf-8'?>
<widget id="com.bitpay.copay"
version="0.8.2"
version="0.8.3"
android-versionCode="17"
ios-CFBundleVersion="0.8.2">
ios-CFBundleVersion="0.8.3">
<name>Copay</name>
<description>
A secure bitcoin wallet for friends and companies.

View file

@ -57,11 +57,11 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>vRC0.9.0</string>
<string>0.8.3</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>vRC0.9.0</string>
<string>0.8.3</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSMainNibFile</key>

View file

@ -43,7 +43,7 @@
<p class="text-gray size-18">Your session is about to expire due to inactivity in {{countdown}} seconds</p>
</div>
<div class="off-canvas-wrap" ng-show="!signingOut">
<div class="off-canvas-wrap" id="off-canvas-wrap" ng-show="!signingOut">
<div class="inner-wrap">
<span class="status" ng-if="$root.reconnecting">
<i class="fi-loop icon-rotate"></i>
@ -62,7 +62,7 @@
<section class="left-small">
<a class="left-off-canvas-toggle menu-icon" ><span></span></a>
</section>
<section class="right-small" ng-if="$root.iden && $root.iden.listWallets().length >1">
<section class="right-small" ng-show="$root.iden && $root.iden.listWallets().length >1">
<a class="right-off-canvas-toggle p10"><i class="icon-wallet size-24"></i></a>
</section>
@ -73,13 +73,13 @@
</section>
</nav>
<aside class="left-off-canvas-menu">
<nav class="left-off-canvas-menu" ng-show="$root.iden">
<div ng-include="'views/includes/sidebar-mobile.html'"></div>
</aside>
</nav>
<aside class="right-off-canvas-menu" ng-if="$root.iden && $root.iden.listWallets().length >1">
<nav class="right-off-canvas-menu" ng-show="$root.iden && $root.iden.listWallets().length >1">
<div ng-include="'views/includes/walletbar-mobile.html'"></div>
</aside>
</nav>
<div
ng-if="$root.iden"
ng-include="'views/includes/sidebar.html'"

View file

@ -63,7 +63,9 @@ angular.module('copayApp.controllers').controller('CreateController',
}
}
$rootScope.$digest();
$timeout(function(){
$rootScope.$digest();
},1);
});
};
});

View file

@ -75,6 +75,7 @@ angular.module('copayApp.controllers').controller('CreateProfileController', fun
$scope.userOrEmail = $scope.useLocalstorage ? form.username.$modelValue : form.email.$modelValue;
preconditions.checkState($scope.userOrEmail);
$scope.error = null;
$scope.createStep = 'pass';
$timeout(function() {
$scope.$digest();
@ -111,6 +112,7 @@ angular.module('copayApp.controllers').controller('CreateProfileController', fun
var msg = err.toString();
if (msg.indexOf('EEXIST') >= 0 || msg.indexOf('BADC') >= 0) {
msg = 'This profile already exists'
$scope.createStep = 'email';
}
$scope.error = msg;
} else {
@ -156,6 +158,8 @@ angular.module('copayApp.controllers').controller('CreateProfileController', fun
return;
}
$scope.saveSettings(function(err) {
preconditions.checkState(!err,err);
$scope._doCreateProfile($scope.userOrEmail, form.password.$modelValue, function(err) {
$timeout(function() {
form.password.$setViewValue('');

View file

@ -15,7 +15,6 @@ angular.module('copayApp.controllers').controller('HeadController', function($sc
};
$scope.signout = function() {
$rootScope.signingOut = true;
identityService.signout();
};

View file

@ -1,10 +1,11 @@
'use strict';
angular.module('copayApp.controllers').controller('HomeController', function($scope, $rootScope, $location, $timeout, notification, identityService, Compatibility, pinService, applicationService, isMobile) {
angular.module('copayApp.controllers').controller('HomeController', function($scope, $rootScope, $timeout, go, notification, identityService, Compatibility, pinService, applicationService, isMobile) {
// Global functions (TODO should be somewhere else)
// Global go. This should be in a better place TODO
// We dont do a 'go' directive, to use the benefits of ng-touch with ng-click
$rootScope.go = function (path) {
$location.path(path);
go.go(path);
};
var _credentials, _firstpin;
@ -66,13 +67,14 @@ angular.module('copayApp.controllers').controller('HomeController', function($sc
$scope.error = 'Please enter the required fields';
return;
}
$rootScope.starting = true;
var credentials = pinService.get(pin, function(err, credentials) {
if (err || !credentials) {
$rootScope.starting = false;
$scope.error = 'Wrong PIN';
return;
}
$rootScope.starting = true;
$scope.open(credentials.email, credentials.password);
});
};
@ -114,7 +116,7 @@ angular.module('copayApp.controllers').controller('HomeController', function($sc
pinService.clear(function() {
copay.logger.debug('PIN erased');
delete $rootScope['hasPin'];
applicationService.reload();
applicationService.restart();
});
};
@ -162,7 +164,9 @@ angular.module('copayApp.controllers').controller('HomeController', function($sc
$scope.askForPin = 1;
$rootScope.starting = false;
$rootScope.hideNavigation = true;
$rootScope.$digest();
$timeout(function(){
$rootScope.$digest();
});
return;
}
// no mobile

View file

@ -21,7 +21,7 @@ angular.module('copayApp.controllers').controller('SettingsController', function
name: 'In the cloud (Insight server)',
pluginName: 'EncryptedInsightStorage',
}, {
name: 'In this device (localstorage)',
name: 'On this device (localstorage)',
pluginName: 'EncryptedLocalStorage',
},
// {

View file

@ -27,7 +27,6 @@ angular.module('copayApp.controllers').controller('SidebarController', function(
}];
$scope.signout = function() {
$rootScope.signingOut = true;
identityService.signout();
};

View file

@ -1,13 +1,21 @@
'use strict';
angular.element(document).ready(function() {
var startAngular = function () {
var startAngular = function() {
angular.bootstrap(document, ['copayApp']);
};
/* Cordova specific Init */
if (window.cordova !== undefined) {
document.addEventListener('deviceready', function() {
setTimeout(function(){ navigator.splashscreen.hide(); }, 2000);
document.addEventListener('pause', function() {
window.location = '#!';
});
setTimeout(function() {
navigator.splashscreen.hide();
}, 2000);
function handleBitcoinURI(url) {
if (!url) return;

View file

@ -113,16 +113,17 @@ angular
$idleProvider.warningDuration(40); // in seconds
$keepaliveProvider.interval(30); // in seconds
})
.run(function($rootScope, $location, $idle, gettextCatalog, uriHandler) {
.run(function($rootScope, $location, $idle, gettextCatalog, uriHandler, isCordova) {
gettextCatalog.currentLanguage = config.defaultLanguage;
// not for mobileApp
if (!window.cordova) {
// Register URI handler, not for mobileApp
if (!isCordova) {
$idle.watch();
uriHandler.register();
}
$rootScope.$on('$routeChangeStart', function(event, next, current) {
if (!ls || ls.length < 1) {
$location.path('unsupported');
} else {

View file

@ -1,22 +1,27 @@
'use strict';
angular.module('copayApp.services')
.factory('applicationService', function() {
.factory('applicationService', function($rootScope, $location, $timeout, go, isCordova) {
var root = {};
var isChromeApp = window.chrome && chrome.runtime && chrome.runtime.id;
root.restart = function() {
// Go home reloading the application
var hashIndex = window.location.href.indexOf('#!/');
if (isChromeApp) {
chrome.runtime.reload();
if (isCordova) {
$rootScope.iden = $rootScope.wallet = undefined;
go.go('/');
$timeout(function(){
$rootScope.$digest();
},1);
} else {
window.location = window.location.href.substr(0, hashIndex);
}
};
root.reload = function() {
window.location.reload();
// Go home reloading the application
var hashIndex = window.location.href.indexOf('#!/');
if (isChromeApp) {
chrome.runtime.reload();
} else {
window.location = window.location.href.substr(0, hashIndex);
}
}
};
return root;

26
js/services/go.js Normal file
View file

@ -0,0 +1,26 @@
'use strict';
angular.module('copayApp.services').factory('go', function($window, $location) {
var root = {};
var hideSidebars = function() {
if (typeof document === 'undefined')
return;
// hack to hide sidebars and use ng-click (no href=)
var win = angular.element($window);
var elem = angular.element(document.querySelector('#off-canvas-wrap'))
elem.removeClass('move-right');
elem.removeClass('move-left');
};
root.go = function(path) {
var parts = path.split('#');
$location.path(parts[0]);
if (parts[1])
$location.hash(parts[1]);
hideSidebars();
};
return root;
});

View file

@ -1,6 +1,6 @@
'use strict';
angular.module('copayApp.services')
.factory('identityService', function($rootScope, $location, $timeout, $filter, pluginManager, notification, pendingTxsService, balanceService, applicationService) {
.factory('identityService', function($rootScope, $location, $timeout, $filter, pluginManager, notification, pendingTxsService, balanceService, applicationService, go) {
notification.enableHtml5Mode(); // for chrome: if support, enable it
// TODO:
@ -328,11 +328,13 @@ angular.module('copayApp.services')
};
root.signout = function() {
$rootScope.signingOut = true;
if ($rootScope.iden) {
$rootScope.iden.store({
noWallets: true
}, function() {
$rootScope.iden.close();
$rootScope.signingOut = false;
$rootScope.iden.close(); // Will trigger 'closed'
});
}
};

3
js/services/isCordova.js Normal file
View file

@ -0,0 +1,3 @@
'use strict';
angular.module('copayApp.services').value('isCordova', window.cordova ? true : false);

View file

@ -5,7 +5,7 @@ angular.module('copayApp.services')
var KEY = 'pinDATA';
var SALT = '4gllotIKguqi0EkIslC0';
var ITER = 2000;
var ITER = 5000;
var ls = localstorageService;
var root = {};

View file

@ -76,7 +76,7 @@ module.exports = {
try {
return sjcl.decrypt(key, sjclEncryptedJson);
} catch (e) {
log.info('Decryption failed due to error: ' + e.message);
log.debug('Decryption failed due to error: ' + e.message);
return null;
}
}

View file

@ -2,7 +2,7 @@
"name": "copay",
"description": "A multisignature wallet",
"author": "BitPay",
"version": "0.8.2",
"version": "0.8.3",
"keywords": [
"wallet",
"copay",
@ -41,7 +41,8 @@
"setup-shell": "node shell/scripts/download-atom-shell.js",
"postinstall": "./node_modules/.bin/grunt",
"sign": "gpg -u 1112CFA1 --output browser-extensions/firefox/copay.xpi.sig --detach-sig browser-extensions/firefox/copay.xpi; gpg -u 1112CFA1 --output browser-extensions/chrome/copay-chrome-extension.zip.sig --detach-sig browser-extensions/chrome/copay-chrome-extension.zip",
"verify": "gpg --verify browser-extensions/firefox/copay.xpi.sig browser-extensions/firefox/copay.xpi; gpg --verify browser-extensions/chrome/copay-chrome-extension.zip.sig browser-extensions/chrome/copay-chrome-extension.zip"
"verify": "gpg --verify browser-extensions/firefox/copay.xpi.sig browser-extensions/firefox/copay.xpi; gpg --verify browser-extensions/chrome/copay-chrome-extension.zip.sig browser-extensions/chrome/copay-chrome-extension.zip",
"ios": "cordova/build.sh && cd cordova/project && cordova build ios && open platforms/ios/Copay.xcodeproj"
},
"devDependencies": {
"angular-gravatar": "*",

View file

@ -81,7 +81,7 @@ describe('crypto utils', function() {
});
it('should generate a passphrase using default salt/iter', function() {
var phrase = cryptoUtils.kdf('Pwd123!@#$%^&*(){}[]\|/?.>,<=+-_`~åéþ䲤þçæ¶');
var expected = 'ml+mMtjgcvL2pdfDwQqW2qONRNjZ3YD8KnGeV3aFjyOoM0ByOmoREw9zBvowC/ZXsfrezbRXX/W/XIzKOqdrXA==';
var expected = 'n9QYDBJvRCHfpAfp8X/Z1XDA00CnZtnehLKOVrtNYTLt9H+hlcyaZgbAGGgJ/dVRCsVtIBzYwaACNPckknMiCg==';
phrase.should.equal(expected);
});

View file

@ -23,9 +23,34 @@
<div class="large-5 large-centered medium-6 medium-centered columns m20b" ng-show="!loading && !askForPin">
<div class="logo-setup hide-for-small-only">
<img src="img/logo-negative-beta.svg" alt="Copay" width="100">
<div ng-include="'views/includes/version.html'"></div>
</div>
<div>
<div class="clipo" ng-show="createStep == 'storage' ">
<img src="img/clipo-signup1.png" alt="clipo" width="311">
</div>
<div ng-show="createStep == 'email'">
<div class="clipo" ng-if="useLocalstorage">
<img src="img/clipo-signup2-1.png" alt="clipo" width="373">
</div>
<div class="clipo" ng-if="!useLocalstorage">
<img src="img/clipo-signup2.png" alt="clipo" width="373">
</div>
<h2 ng-if="!useLocalstorage"> Creating in the cloud </h2>
<h2 ng-if="useLocalstorage"> Creating on this device </h2>
</div>
<div ng-show="createStep == 'pass'">
<div class="clipo">
<img src="img/clipo-signup3.png" alt="clipo" width="380">
</div>
<h2 ng-if="useLocalstorage"> Creating on this device </h2>
<h2 ng-if="!useLocalstorage"> Creating in the cloud </h2>
<div class="text-gray text-center m20b">{{userOrEmail}}</div>
</div>
<div class="box-notification" ng-show="error">
<div class="box-icon error">
<i class="fi-x size-24"></i>
@ -37,54 +62,52 @@
<form ng-show="createStep == 'storage' " novalidate>
<div class="clipo">
<img src="img/clipo-signup1.png" alt="clipo" width="311">
</div>
<tabset>
<tab style="width: 50%;" select="selectStorage('remote')">
<tab-heading>
<span class="text-bold">In the Cloud </span><br>
<span class="text-bold">In the Cloud </span>
<br>
<span class="size-10 text-gray">( Recommended )</span>
</tab-heading>
<div class="content-item">
<div class="bg-circle"><i class="icon-wallet"></i>
</div>
<span class="text-gray">Access your wallets anywhere</span>
<div class="content-item">
<div class="bg-circle"><i class="icon-wallet"></i>
</div>
<div class="content-item">
<div class="bg-circle"><i class="icon-download"></i>
</div>
<span class="text-gray">Backups managed by the server</span>
<span class="text-gray">Access your wallets anywhere</span>
</div>
<div class="content-item">
<div class="bg-circle"><i class="icon-download"></i>
</div>
<div class="content-item line-none">
<div class="bg-circle"><i class="icon-email"></i>
</div>
<span class="text-gray">Email address confirmation needed</span>
<span class="text-gray">Backups managed by the server</span>
</div>
<div class="content-item line-none">
<div class="bg-circle"><i class="icon-email"></i>
</div>
<span class="text-gray">Email address confirmation needed</span>
</div>
</tab>
<tab style="width: 50%;" select="selectStorage('local')">
<tab-heading>
<div class="m5t text-bold">On this Device </div>
<div class="m5t text-bold">On this Device</div>
</tab-heading>
<div class="content-item">
<div class="bg-circle"><i class="icon-locked"></i>
</div>
<span class="text-gray">Your private keys never leave this device</span>
<div class="content-item">
<div class="bg-circle"><i class="icon-locked"></i>
</div>
<div class="content-item">
<div class="bg-circle"><i class="icon-person"></i>
</div>
<span class="text-gray">No email required</span>
<span class="text-gray">Your private keys never leave this device</span>
</div>
<div class="content-item">
<div class="bg-circle"><i class="icon-person"></i>
</div>
<div class="content-item line-none">
<div class="bg-circle"><i class="icon-download"></i>
</div>
<span class="text-gray">Need to be careful with backups</span>
<span class="text-gray">No email required</span>
</div>
<div class="content-item line-none">
<div class="bg-circle"><i class="icon-download"></i>
</div>
<span class="text-gray">Need to be careful with backups</span>
</div>
</tab>
</tabset>
<button translate class="button primary radius expand m0" ng-click="goToEmail()">
<button translate class="button primary radius expand m0" ng-click="goToEmail()">
<span ng-if="!useLocalstorage"> Create in the cloud</span>
<span ng-if="useLocalstorage"> Create on this device</span>
</button>
@ -97,25 +120,14 @@
</a>
</div>
<div class="right">
<a class="text-gray" href="https://copay.io/profile-storage"
<span translate>Learn more about this option</span>
<a class="text-gray" href="https://copay.io/profile-storage" <span translate>Learn more about this option</span>
</a>
</div>
</div>
</form>
<form ng-show="createStep == 'email'" name="emailForm" ng-submit="setEmailOrUsername(emailForm)" novalidate>
<div class="clipo" ng-if="useLocalstorage">
<img src="img/clipo-signup2-1.png" alt="clipo" width="373">
</div>
<div class="clipo" ng-if="!useLocalstorage">
<img src="img/clipo-signup2.png" alt="clipo" width="373">
</div>
<h2 ng-if="!useLocalstorage"> Creating in the cloud </h2>
<h2 ng-if="useLocalstorage"> Creating on this device </h2>
<div class="input" ng-if="useEmail">
<input type="email" ng-model="email" class="form-control fi-email" name="email" placeholder="Email" required auto-focus="!isMobile">
<i class="icon-email"></i>
@ -128,7 +140,8 @@
</div>
</span>
<div class="" ng-show="!emailForm.email.$invalid &&
!emailForm.email.$pristine"><i class="fi-check"></i></div>
!emailForm.email.$pristine"><i class="fi-check"></i>
</div>
</div>
</div>
@ -139,9 +152,7 @@
<button translate type="submit" class="button primary radius expand m0" ng-disabled="(useEmail && emailForm.email.$invalid) || (!useEmail && emailForm.username.$invalid)">
Next
</button
>
</button>
<div class="box-setup-footer">
<div class="left">
<a class="text-gray" ng-click="setStep('storage')">
@ -150,19 +161,10 @@
</a>
</div>
</div>
</form>
<form ng-show="createStep == 'pass'" name="passForm" ng-submit="createProfile(passForm)" novalidate>
<div class="clipo">
<img src="img/clipo-signup3.png" alt="clipo" width="380">
</div>
<h2 ng-if="useLocalstorage"> Creating on this device </h2>
<h2 ng-if="!useLocalstorage"> Creating in the cloud </h2>
<div class="text-gray text-center m20b"> {{userOrEmail}} </div>
<div class="input">
<input id="password" type="password" ng-model="$parent.password" class="form-control" name="password" placeholder="{{'Choose a password'|translate}}" check-strength="passwordStrength" tooltip-html-unsafe="Password strength: <b>{{passwordStrength}}</b><br/><span class='size-12'>Tip: Use lower and uppercase, numbers and symbols</span>" tooltip-trigger="focus" required tooltip-placement="top">
<i class="icon-locked"></i>
@ -180,7 +182,8 @@
</div>
</span>
<div class="" ng-show="passForm.repeatpassword.$dirty &&
!passForm.repeatpassword.$invalid"><i class="fi-check"></i></div>
!passForm.repeatpassword.$invalid"><i class="fi-check"></i>
</div>
</div>
</div>
@ -202,45 +205,43 @@
</div>
<div class="large-4 large-centered medium-6 medium-centered columns m20b" ng-show="!loading && askForPin">
<div class="box-setup">
<h1><span translate>Set up a </span> <b> PIN </b>?</h1>
<p class="size-14">Enter a 4-digit number for easier access from this device</p>
<h2><span translate>Set up a </span> <b> PIN </b>?</h2>
<p class="size-14 text-gray">Enter a 4-digit number for easier access from this device</p>
<div class="box-notification" ng-show="error">
<div class="box-icon error">
<i class="fi-x size-24"></i>
</div>
<span class="text-warning size-14">
<div class="box-notification" ng-show="error">
<div class="box-icon error">
<i class="fi-x size-24"></i>
</div>
<span class="text-warning size-14">
{{error|translate}}
</span>
</div>
<form name="setPinForm" ng-submit="createPin(setPinForm)" novalidate>
<div class="input" ng-show="askForPin == 1">
<input id="newpin" type="tel" ng-model="newpin" class="form-control" ng-maxlength="4" ng-minlength="4" maxlength="4" ng-pattern="/^[0-9]{1,4}$/" placeholder="PIN" name="newpin" required show-focus="askForPin == 1">
<i class="icon-locked"></i>
</div>
<div class="input" ng-show="askForPin == 2">
<input id="repeatpin" type="tel" ng-model="repeatpin" class="form-control" ng-maxlength="4" ng-minlength="4" maxlength="4" ng-pattern="/^[0-9]{1,4}$/" placeholder="Confirm your PIN" name="repeatpin" required show-focus="askForPin == 2">
<i class="icon-locked"></i>
</div>
<form name="setPinForm" ng-submit="createPin(setPinForm)" novalidate>
<div class="input" ng-show="askForPin == 1">
<input id="newpin" type="tel" ng-model="newpin" class="form-control" ng-maxlength="4" ng-minlength="4" maxlength="4" ng-pattern="/^[0-9]{1,4}$/" placeholder="PIN" name="newpin" required show-focus="askForPin == 1">
<i class="icon-locked"></i>
<div class="box-setup-footer row collapse">
<div class="large-6 medium-6 small-6 columns">
<a class="button secondary radius m0" ng-click="createDefaultWallet()">
<span translate>Skip</span>
</a>
</div>
<div class="input" ng-show="askForPin == 2">
<input id="repeatpin" type="tel" ng-model="repeatpin" class="form-control" ng-maxlength="4" ng-minlength="4" maxlength="4" ng-pattern="/^[0-9]{1,4}$/" placeholder="Confirm your PIN" name="repeatpin" required show-focus="askForPin == 2">
<i class="icon-locked"></i>
</div>
<div class="box-setup-footer row collapse">
<div class="large-6 medium-6 small-6 columns">
<a class="button secondary radius m0" ng-click="createDefaultWallet()">
<span translate>Skip</span>
</a>
</div>
<div class="large-6 medium-6 small-6 columns text-right">
<button translate type="submit" class="button primary radius expand m0" ng-disabled="setPinForm.$invalid || error">
OK
</button>
</div>
<div class="large-6 medium-6 small-6 columns text-right">
<button translate type="submit" class="button primary radius expand m0" ng-disabled="setPinForm.$invalid || error">
OK
</button>
</div>
</div>
</form>
</div>
</form>
</div>
</div>

View file

@ -23,7 +23,7 @@
<div class="large-5 large-centered medium-7 medium-centered columns" ng-show="!$root.starting">
<div class="logo-setup" ng-show="!$root.iden">
<img src="img/logo-negative-beta.svg" alt="Copay" width="100">
<div ng-include="'views/includes/version.html'"></div>
<div class="text-gray" ng-include="'views/includes/version.html'"></div>
</div>
<div class="p10 box-setup bg-success m10b text-white" ng-show="confirmedEmail">
@ -115,7 +115,6 @@
<div class="clipo">
<img src="img/clipo-signin.png" alt="clipo" width="310">
</div>
<h2 translate>Sign in to Copay</h2>
<div class="p10 m20b size-14 box-setup bg-success text-white" ng-show="anyWallet && !confirmedEmail && !error">
<div class="left">
<i class="size-36 fi-alert m10r"></i>

View file

@ -1,7 +1,7 @@
<div>
<ul class="off-canvas-list">
<li>
<a href="#!/profile" class="db p20h nav-item text-center" title="Create new wallet">
<a ng-click="$root.go('profile')" class="db p20h nav-item text-center" title="Create new wallet">
<div class="photo-container m20t">
<img gravatar-src="'{{$root.iden.getName()}}'" gravatar-size="35">
</div>
@ -14,23 +14,23 @@
</li>
<li>
<a href="#!/create" class="db p20h nav-item" title="Create new wallet">
<a ng-click="$root.go('create')" class="db p20h nav-item" title="Create new wallet">
<i class="size-24 m20r fi-plus"></i> {{'Create new wallet' | translate }}</a>
</li>
<li>
<a href="#!/join" class="db p20h nav-item" title="Join shared wallet">
<a ng-click="$root.go('join')" class="db p20h nav-item" title="Join shared wallet">
<i class="size-24 m20r fi-torsos-all"></i> {{'Join shared wallet' | translate }}</a>
</li>
<li>
<a href="#!/import" class="db p20h nav-item" title="Import wallet">
<a ng-click="$root.go('import')" class="db p20h nav-item" title="Import wallet">
<i class="size-24 m20r fi-download"></i> {{'Import a wallet' | translate }}</a>
</li>
<li ng-if="$root.wallet">
<a href="#!/more" class="db p20h nav-item" title="Settings">
<a ng-click="$root.go('more')" class="db p20h nav-item" title="Settings">
<i class="size-24 m20r fi-widget"></i> {{'Wallet Settings' | translate }}</a>
</li>
<li>
<a href="#!/" class="db p20h nav-item" title="Close" ng-click="signout()">
<a class="db p20h nav-item" title="Close" ng-click="signout()">
<span ng-if="!$root.hasPin"><i class="size-24 m20r fi-power"></i> {{'Close'|translate}}</span>
<span ng-if="$root.hasPin"><i class="size-24 m20r fi-lock"></i> {{'Lock'|translate}}</span>
</a>

View file

@ -11,7 +11,7 @@
<div class="avatar-wallet">{{(item.name || item.id) | limitTo: 1}}</div>
</div>
<div class="col2">
<a href="#!/homeWallet#{{item.id}}" class="size-12 wallet-item">
<a ng-click="$root.go('/homeWallet#{{item.id}}')" class="size-12 wallet-item">
<div class="oh">
<div class="right size-10 type-wallet">
[ {{item.requiredCopayers}} of {{item.totalCopayers}} ]</div>