diff --git a/bower.json b/bower.json index 2995b60f784afe223b5deb5707a8a3f330119bae..26ce45b551932ad451926a99a7b8a61752329470 100644 --- a/bower.json +++ b/bower.json @@ -3,5 +3,8 @@ "private": "true", "devDependencies": { "ionic": "driftyco/ionic-bower#1.0.1" + }, + "dependencies": { + "angular-messages": "1.3.13" } } diff --git a/ionic.project b/ionic.project index fc436c7b9720493086c3674611c74bc8393c5394..e5e2814615e65b65776eb19601dea3ce03408069 100644 --- a/ionic.project +++ b/ionic.project @@ -1,4 +1,8 @@ { "name": "Cesium", - "app_id": "" -} \ No newline at end of file + "app_id": "", + "watchPatterns": [ + "www/**/*", + "!www/lib/**/*" + ] +} diff --git a/package.json b/package.json index d9d7e3d2455cc1c895d4af91245d8e1e3934276f..ed7b43c4075bd3162618d7381878e0adc66e5538 100644 --- a/package.json +++ b/package.json @@ -22,9 +22,6 @@ "com.ionic.keyboard" ], "cordovaPlatforms": [ - { - "platform": "android", - "locator": "browser" - } + "android" ] -} \ No newline at end of file +} diff --git a/www/css/style.css b/www/css/style.css index 46db401e9cee2a397a558eb8e0abff9b02241640..82fe26c616a01e0dc453bb017199cf3705285339 100644 --- a/www/css/style.css +++ b/www/css/style.css @@ -18,9 +18,6 @@ body { margin-top: 30px; } -#newAccount .button { - height: 50px; -} .badge sub, .badge sup { line-height: inherit; @@ -54,6 +51,17 @@ body { .light { color: grey; } + +/********** + Categories select +**********/ + +.item-category{ + overflow: inherit ; + text-overflow: inherit ; + white-space: normal !important; +} + /*.button {*/ /*height: 50px !important;*/ /*font-size: 18px !important;*/ @@ -67,6 +75,36 @@ body { /*-webkit-transform: initial !important;*/ /*}*/ +/********** + Form validation +**********/ + +.form-errors:first-child { + margin: 5px 0; +} + +.form-errors:last-child { + margin: 5px 0 0; +} + +.form-error { + padding: 8px 16px; + font-size: 12px; + color: red; + vertical-align: middle; + text-align: end; +} + +.form-error i { + font-size: 24px; + color: #B83E2C; + vertical-align: middle; +} + +.item-input-error { + border-bottom: 2px solid red; +} + /********** MODAL **********/ @@ -78,10 +116,9 @@ body { height: 100%; } .slider-slide { - padding-top: 25px; color: #000; background-color: #fff; - text-align: center; + /*text-align: center;*/ font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; font-weight: 300; diff --git a/www/i18n/locale-en.json b/www/i18n/locale-en.json index f44db8824efd42e56034ca5cffbdd586fa82abe8..60ccd00916e692f1e10d5812ab045a7fba085fc4 100644 --- a/www/i18n/locale-en.json +++ b/www/i18n/locale-en.json @@ -5,10 +5,11 @@ "BTN_OK": "OK", "BTN_SHOW": "Show", "BTN_RELATIVE_UNIT": "Use relative unit", - "BTN_BACK": "Back", + "BTN_BACK": " Back", "BTN_CANCEL": "Cancel", "BTN_LOGIN": "Login", - "BTN_LOGOUT": "Logout" + "BTN_LOGOUT": " Logout", + "BTN_ADD_ACCOUNT": "Register" }, "MENU": { "TITLE": "Cesium", @@ -64,8 +65,8 @@ }, "LOGIN": { "TITLE": "Login", - "USERNAME": "Login", - "USERNAME_HELP": "Login (Pass phrase or email)", + "USERNAME": "Email (or sentence)", + "USERNAME_HELP": "joe@domain.com", "PASSWORD": "Password", "PASSWORD_HELP": "Password" }, @@ -74,7 +75,17 @@ "BALANCE": "Balance", "LAST_TX": "Last transactions", "BTN_SEND_MONEY": "Send money", - "BTN_REGISTER": "Register as member" + "BTN_REGISTER": "Register as member", + "NEW": { + "TITLE": "Register", + "SLIDE_2_TITLE": "Kind of account:", + "MEMBER_ACCOUNT": "Member account", + "WALLET_ACCOUNT": "Simple wallet account", + "PSEUDO": "Pseudonym", + "PSEUDO_HELP": "joe123", + "PASSWORD_CONFIRM": "Confirm Password", + "PASSWORD_CONFIRM_HELP": "Confirm Password" + } }, "TRANSFER": { "TITLE": "Transfer", @@ -101,7 +112,7 @@ "TITLE": "" }, "EDIT": { - "TITLE": "New", + "TITLE": "Edit", "BTN_ADD_PICTURES": "Add pictures", "RECORD_TITLE": "Title", "RECORD_TITLE_HELP": "Title", @@ -126,7 +137,7 @@ "TITLE": "" }, "EDIT": { - "TITLE": "New", + "TITLE": "Edit", "BTN_ADD_PICTURES": "Add pictures", "RECORD_TITLE": "Title", "RECORD_TITLE_HELP": "Title", @@ -134,5 +145,16 @@ "RECORD_DESCRIPTION_HELP": "Description", "RECORD_LOCATION": "Location" } + }, + "ERROR": { + "POPUP_TITLE": "Error", + "UNKNOWN_ERROR": "Unknown error", + "CRYPTO_UNKNOWN_ERROR": "Your browser is not compatible with cryptographic features.", + "FIELD_REQUIRED": "This field is required.", + "FIELD_TOO_SHORT": "This field is too short.", + "PASSWORD_NOT_CONFIRMED": "Must match previous password" + }, + "INFO": { + "POPUP_TITLE": "Information" } } diff --git a/www/i18n/locale-fr.json b/www/i18n/locale-fr.json index a93db70421f847cb218a103b7758ad6e95475dd4..7d9781816ab4f3a82072a60baf5c864c4dfd4230 100644 --- a/www/i18n/locale-fr.json +++ b/www/i18n/locale-fr.json @@ -8,7 +8,8 @@ "BTN_BACK": "Retour", "BTN_CANCEL": "Annuler", "BTN_LOGIN": "Se connecter", - "BTN_LOGOUT": "Déconnecter" + "BTN_LOGOUT": "Déconnecter", + "BTN_ADD_ACCOUNT": "S'inscrire" }, "MENU": { "TITLE": "Cesium", @@ -64,8 +65,8 @@ }, "LOGIN": { "TITLE": "Connexion", - "USERNAME": "Phrase de protection", - "USERNAME_HELP": "Phrase de protection (phrase ou email)", + "USERNAME": "Email (ou phrase)", + "USERNAME_HELP": "dupond@domaine.com", "PASSWORD": "Mot de passe", "PASSWORD_HELP": "Mot de passe" }, @@ -74,7 +75,17 @@ "BALANCE": "Solde", "LAST_TX": "Dernières transactions", "BTN_SEND_MONEY": "Payer", - "BTN_REGISTER": "S'inscrire comme membre" + "BTN_REGISTER": "S'inscrire comme membre", + "NEW": { + "TITLE": "Inscription", + "SLIDE_2_TITLE": "Type de compte :", + "MEMBER_ACCOUNT": "Compte membre", + "WALLET_ACCOUNT": "Simple protefeuille anonyme", + "PSEUDO": "Pseudonyme", + "PSEUDO_HELP": "Pseudonyme", + "PASSWORD_CONFIRM": "Confirmation du mot de passe", + "PASSWORD_CONFIRM_HELP": "Confirmation du mot de passe" + } }, "TRANSFER": { "TITLE": "Payer", @@ -101,13 +112,46 @@ "TITLE": "" }, "EDIT": { - "TITLE": "Nouveau", + "TITLE": "Edition", "BTN_ADD_PICTURES": "Ajouter des photos", "RECORD_TITLE": "Titre", "RECORD_TITLE_HELP": "Titre", "RECORD_DESCRIPTION": "Description", "RECORD_DESCRIPTION_HELP": "Description", - "RECORD_LOCATION": "Localiser" + "RECORD_LOCATION": "Ville" } + }, + "REGISTRY": { + "COMMON": { + "CATEGORY": "Catégorie", + "CATEGORIES": "Catégories", + "ISSUER": "Soumis par" + }, + "SEARCH": { + "TITLE": "Annuaire", + "SEARCH_HELP": "Recherche (nom, pseudo, clé publique...)", + "BTN_ADD": "Nouveau", + "BTN_OPTIONS": "Outil de recherche" + }, + "VIEW": { + "TITLE": "" + }, + "EDIT": { + "TITLE": "Edition", + "BTN_ADD_PICTURES": "Ajouter des photos", + "RECORD_TITLE": "Titre", + "RECORD_TITLE_HELP": "Titre", + "RECORD_DESCRIPTION": "Description", + "RECORD_DESCRIPTION_HELP": "Description", + "RECORD_LOCATION": "Ville" + } + }, + "ERROR": { + "POPUP_TITLE": "Erreur", + "UNKNOWN_ERROR": "Erreur inconnue", + "CRYPTO_UNKNOWN_ERROR": "Votre navigateur ne semble pas compatible avec les fonctionnalités de cryptographie." + }, + "INFO": { + "POPUP_TITLE": "Information" } } diff --git a/www/index.html b/www/index.html index 8948db87d52c6f51784f1403a0925aaa65e4416e..f3a35bcf937d4a0bf288605648554cac67b99853 100644 --- a/www/index.html +++ b/www/index.html @@ -18,6 +18,7 @@ <script src="lib/angular-sanitize/angular-sanitize.min.js"></script> <script src="lib/angular-translate/angular-translate.min.js"></script> <script src="lib/angular-translate-loader-static-files/angular-translate-loader-static-files.min.js"></script> + <script src="lib/angular-messages/angular-messages.min.js"></script> <script src="js/vendor/moment.min.js"></script> <script src="js/vendor/numeral.js"></script> <script src="js/vendor/socket-io.js"></script> @@ -60,5 +61,7 @@ </head> <body ng-app="cesium"> <ion-nav-view></ion-nav-view> + </body> + </html> diff --git a/www/js/app.js b/www/js/app.js index 36d0e4e0f2baeac44301a21bb1e8ca48b78aac42..c06b42d84c766c3bbe67875e694bc86d074b795e 100644 --- a/www/js/app.js +++ b/www/js/app.js @@ -4,7 +4,7 @@ // 'starter' is the name of this angular module example (also set in a <body> attribute in index.html) // the 2nd parameter is an array of 'requires' // 'starter.controllers' is found in controllers.js -angular.module('cesium', ['ionic', 'cesium.controllers', 'pascalprecht.translate']) +angular.module('cesium', ['ionic', 'ngMessages', 'pascalprecht.translate', 'cesium.controllers']) .filter('formatInteger', function() { return function(input) { @@ -58,6 +58,27 @@ angular.module('cesium', ['ionic', 'cesium.controllers', 'pascalprecht.translate }) + // Add new compare-to directive (need for form validation) + .directive("compareTo", function() { + return { + require: "ngModel", + scope: { + otherModelValue: "=compareTo" + }, + link: function(scope, element, attributes, ngModel) { + + ngModel.$validators.compareTo = function(modelValue) { + return modelValue == scope.otherModelValue; + }; + + scope.$watch("otherModelValue", function() { + ngModel.$validate(); + }); + } + }; + }) + + .run(function($ionicPlatform) { $ionicPlatform.ready(function() { // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard diff --git a/www/js/controllers/home-controllers.js b/www/js/controllers/home-controllers.js index 5a55420b159970654e113c708afe20daced71b58..cc46ae6bd4b20b30fdc29a00b43f0cfe3fb2ae76 100644 --- a/www/js/controllers/home-controllers.js +++ b/www/js/controllers/home-controllers.js @@ -42,6 +42,7 @@ function LoginController($scope, $ionicModal, Wallet, CryptoUtils, UIUtils, $q, username: null, password: null }; + $scope.loginForm = null; // Login modal $scope.loginModal = "undefined"; @@ -55,6 +56,10 @@ function LoginController($scope, $ionicModal, Wallet, CryptoUtils, UIUtils, $q, $scope.loginModal.hide(); }); + $scope.setLoginForm = function(loginForm) { + $scope.loginForm = loginForm; + } + // Open login modal $scope.login = function(callback) { if ($scope.loginModal != "undefined" && $scope.loginModal != null) { @@ -108,6 +113,10 @@ function LoginController($scope, $ionicModal, Wallet, CryptoUtils, UIUtils, $q, // Login form submit $scope.doLogin = function() { + if(!$scope.loginForm.$valid) { + return; + } + $scope.loginForm = null; $scope.closeLogin(); UIUtils.loading.show(); @@ -186,78 +195,116 @@ function HomeController($scope, $ionicSlideBoxDelegate, $ionicModal, $state, BMA //$scope.$on('$ionicView.enter', function(e) { //}); - //CurrenciesController.call(this, $scope, $state); - //LookupController.call(this, $scope, BMA, $state); LoginController.call(this, $scope, $ionicModal, Wallet, CryptoUtils, UIUtils, $q, $state, $timeout, $ionicSideMenuDelegate); - $scope.accountTypeMember = null; $scope.accounts = []; $scope.search = { text: '', results: {} }; $scope.knownCurrencies = ['meta_brouzouf']; + $scope.newAccountModal = "undefined"; + $scope.slideIndex = 0; + $scope.accountData = {}; + $scope.accountForm = {}; // Called to navigate to the main app $scope.cancel = function() { - $scope.modal.hide(); + $scope.newAccountModal.hide(); $timeout(function(){ - $scope.selectedCurrency = ''; - $scope.accountTypeMember = null; - $scope.search.text = ''; - $scope.search.results = []; + $scope.accountData = {}; + $scope.accountForm = {}; }, 200); }; - $scope.$on('currencySelected', function() { - $ionicSlideBoxDelegate.slide(1); - }); + $scope.setAccountForm = function(accountForm) { + $scope.accountForm = accountForm; + }; - $scope.selectAccountTypeMember = function(bool) { - $scope.accountTypeMember = bool; - $ionicSlideBoxDelegate.slide(2); + // Called each time the slide changes + $scope.slide = function(index) { + $ionicSlideBoxDelegate.slide(index); + $scope.slideIndex = index; + $scope.nextStep = $scope.slideIndex == 2 ? 'Start' : 'Next'; }; $scope.next = function() { - $ionicSlideBoxDelegate.next(); + $scope.slide($scope.slideIndex + 1); }; + $scope.previous = function() { - $ionicSlideBoxDelegate.previous(); + $scope.slide($scope.slideIndex - 1); }; - // Called each time the slide changes - $scope.slideChanged = function(index) { - $scope.slideIndex = index; - $scope.nextStep = $scope.slideIndex == 2 ? 'Start using MyApp' : 'Next'; - }; + $scope.newAccount = function() { + var showModal = function() { + $ionicSlideBoxDelegate.enableSlide(false); + $scope.slide(0); + $scope.newAccountModal.show(); + // TODO: remove default + $timeout(function() { + $scope.accountData.currency = $scope.knownCurrencies[0]; + $scope.accountData.isMember = true; + $scope.next(); + $scope.next(); + }, 300); + } - $scope.addAccount = function() { - $scope.modal.show(); - $scope.slideChanged(0); - $ionicSlideBoxDelegate.slide(0); - $ionicSlideBoxDelegate.enableSlide(false); - // TODO: remove default - //$timeout(function() { - // $scope.selectedCurrency = $scope.knownCurrencies[0]; - // $scope.accountTypeMember = true; - // $scope.searchChanged(); - // $scope.search.text = 'cgeek'; - // $ionicSlideBoxDelegate.next(); - // $ionicSlideBoxDelegate.next(); - //}, 300); - }; + if ($scope.newAccountModal == "undefined") { + UIUtils.loading.show(); + // Create the account modal that we will use later + $ionicModal.fromTemplateUrl('templates/account/new_account.html', { + scope: $scope + }).then(function(modal) { + $scope.newAccountModal = modal; + $scope.newAccountModal.hide() + .then(function(){ + UIUtils.loading.hide(); + showModal(); + }); - // Create the account modal that we will use later - $ionicModal.fromTemplateUrl('templates/account/new_account.html', { - scope: $scope - }).then(function(modal) { - $scope.modal = modal; - $scope.modal.hide(); - // TODO: remove auto add account when done - //$timeout(function() { - // $scope.addAccount(); - //}, 400); - }); + }); + } + else { + showModal(); + } + }; $scope.selectCurrency = function(currency) { - $scope.selectedCurrency = currency; + $scope.accountData.currency = currency; + $ionicSlideBoxDelegate.slide(1); $scope.next(); - } + }; + + $scope.selectAccountTypeMember = function(bool) { + $scope.accountData.isMember = bool; + $scope.next(); + }; + + $scope.showAccountPubkey = function() { + $scope.accountData.computing=true; + CryptoUtils.connect($scope.accountData.username, $scope.accountData.password).then( + function(keypair) { + $scope.accountData.pubkey = CryptoUtils.util.encode_base58(keypair.signPk); + $scope.accountData.computing=false; + } + ) + .catch(function(err) { + $scope.accountData.computing=false; + console.error('>>>>>>>' , err); + UIUtils.alert.error('ERROR.CRYPTO_UNKNOWN_ERROR'); + }); + }; + + $scope.doNewAccount = function() { + $scope.accountForm.$submitted=true; + if(!$scope.accountForm.$valid) { + return; + } + $scope.accountForm = null; + }; + + // TODO: remove auto add account when done + /*$timeout(function() { + $scope.newAccount(); + }, 400); + */ } + diff --git a/www/js/services/utils-services.js b/www/js/services/utils-services.js index 41ce70c4d37e8916198795cca61217d9ad44928a..e72d44d2e35faaeafdce8009ceff1239892712c8 100644 --- a/www/js/services/utils-services.js +++ b/www/js/services/utils-services.js @@ -2,36 +2,42 @@ angular.module('cesium.utils.services', ['ngResource']) -.factory('UIUtils', function($ionicLoading, $ionicPopup) { +.factory('UIUtils', function($ionicLoading, $ionicPopup, $translate) { function alertError(err, subtitle) { - var message = err.message || err; - return $ionicPopup.show({ - template: '<p>' + (message || 'Unknown error') + '</p>', - title: 'Application error', - subTitle: subtitle, - buttons: [ - { - text: '<b>OK</b>', - type: 'button-assertive' - } - ] + $translate([err, 'ERROR.POPUP_TITLE', 'ERROR.UNKNOWN_ERROR', 'COMMON.BTN_OK']) + .then(function (translations) { + var message = err.message || translations[err]; + return $ionicPopup.show({ + template: '<p>' + (message || translations['ERROR.UNKNOWN_ERROR']) + '</p>', + title: translations['ERROR.POPUP_TITLE'], + subTitle: subtitle, + buttons: [ + { + text: '<b>'+translations['COMMON.BTN_OK']+'</b>', + type: 'button-assertive' + } + ] + }); }); } function alertInfo(message, subtitle) { - var message = err.message || err; + $translate([message, 'INFO.POPUP_TITLE', 'COMMON.BTN_OK']) + .then(function (translations) { + var message = translations[message]; return $ionicPopup.show({ template: '<p>' + message + '</p>', - title: 'Information', + title: translations['INFO.POPUP_TITLE'], subTitle: subtitle, buttons: [ { - text: '<b>OK</b>', + text: '<b>'+translations['COMMON.BTN_OK']+'</b>', type: 'button-positive' } ] }); - } + }); + } function hideLoading(){ $ionicLoading.hide(); diff --git a/www/templates/account/new_account.html b/www/templates/account/new_account.html index 82683e11c9c451c79880bb11f99aae5f7b0b5907..91bd5c84e3bf5db01e613d0977ca076856fd6cfe 100644 --- a/www/templates/account/new_account.html +++ b/www/templates/account/new_account.html @@ -1,33 +1,147 @@ -<ion-view class="modal slide-in-up ng-enter active ng-enter-active padding"> +<ion-view class="modal slide-in-up ng-enter active ng-enter-active"> <ion-header-bar class="bar-positive"> - <button class="button button-positive icon ion-chevron-left" ng-click="previous()" ng-show="slideIndex > 0"> Back</button> + <button class="button button-positive icon icon-left ion-chevron-left" ng-click="previous()" ng-show="slideIndex > 0" translate>COMMON.BTN_BACK</button> + <button class="button button-positive" ng-click="cancel()" ng-show="slideIndex == 0" translate>COMMON.BTN_CANCEL</button> - <h1 class="title">New account</h1> + <h1 class="title" translate>ACCOUNT.NEW.TITLE</h1> - <button class="button button-positive" ng-click="cancel()">Cancel</button> + <button class="button button-positive button-icon ion-android-send" ng-click="doNewAccount()" ng-show="slideIndex == 2"></button> </ion-nav-buttons> </ion-header-bar> - <ion-slide-box on-slide-changed="slideChanged(index)" id="newAccount"> - <ion-slide> - <ng-include src="'templates/currency/select_currency.html'"></ng-include> - </ion-slide> + + <ion-slide-box on-slide-changed="slideChanged(index)" id="newAccount" class="has-header"> <ion-slide> - <h1>Kind of account:</h1> - <button class="button button-block button-stable icon ion-person" ng-click="selectAccountTypeMember(true)" ng-class="{ selected: accountTypeMember != null && accountTypeMember }"> Member account</button> - <button class="button button-block button-stable icon ion-card" ng-click="selectAccountTypeMember(false)" ng-class="{ selected: accountTypeMember != null && !accountTypeMember }"> Wallet account</button> + <div class="padding"> + <ng-include src="'templates/currency/select_currency.html'"></ng-include> + </div> </ion-slide> <ion-slide> - <ng-include src="'templates/wot/lookup.html'"></ng-include> + <div class="padding"> + <h1 translate>ACCOUNT.NEW.SLIDE_2_TITLE</h1> + <button class="button button-block button-stable icon icon-left ion-person" ng-click="selectAccountTypeMember(true)" ng-class="{ selected: accountTypeMember != null && accountTypeMember }" translate>ACCOUNT.NEW.MEMBER_ACCOUNT</button> + <button class="button button-block button-stable icon icon-left ion-card" ng-click="selectAccountTypeMember(false)" ng-class="{ selected: accountTypeMember != null && !accountTypeMember }" translate>ACCOUNT.NEW.WALLET_ACCOUNT</button> + </div> </ion-slide> <ion-slide> - <h3>Any questions?</h3> - <p> - Too bad! - </p> + <form name="accountForm" novalidate="" ng-submit="doNewAccount()"> + <div class="list" + ng-init="setAccountForm(accountForm)"> + + <!-- pseudo --> + <label class="item item-input" + ng-class="{'item-input-error': accountForm.$submitted && accountForm.pseudo.$invalid}"> + <span class="input-label" translate>ACCOUNT.NEW.PSEUDO</span> + <input name="pseudo" type="text" placeholder="{{'ACCOUNT.NEW.PSEUDO_HELP' | translate}}" + ng-model="accountData.pseudo" + ng-minlength="3" + required> + </label> + <div class="form-errors" + ng-if="accountForm.$submitted && accountForm.pseudo.$error" + ng-messages="accountForm.pseudo.$error"> + <div class="form-error" ng-message="required"> + <span translate="ERROR.FIELD_REQUIRED"></span> + </div> + <div class="form-error" ng-message="minlength"> + <span translate="ERROR.FIELD_TOO_SHORT"></span> + </div> + </div> + + <!-- salt --> + <label class="item item-input" + ng-class="{ 'item-input-error': accountForm.$submitted && accountForm.username.$invalid}"> + <span class="input-label" translate>LOGIN.USERNAME</span> + <input name="username" type="text" placeholder="{{'LOGIN.USERNAME_HELP' | translate}}" + ng-model="accountData.username" + ng-minlength="8" + required> + </label> + <div class="form-errors" + ng-show="accountForm.$submitted && accountForm.username.$error" + ng-messages="accountForm.username.$error"> + <div class="form-error" ng-message="required"> + <span translate="ERROR.FIELD_REQUIRED"></span> + </div> + <div class="form-error" ng-message="minlength"> + <span translate="ERROR.FIELD_TOO_SHORT"></span> + </div> + </div> + + <!-- password --> + <label class="item item-input" + ng-class="{ 'item-input-error': accountForm.$submitted && accountForm.password.$invalid}"> + <span class="input-label" translate>LOGIN.PASSWORD</span> + <input name="password" type="password" placeholder="{{'LOGIN.PASSWORD_HELP' | translate}}" + ng-model="accountData.password" + ng-minlength="8" + required> + </label> + <div class="form-errors" + ng-show="accountForm.$submitted && accountForm.password.$error" + ng-messages="accountForm.password.$error"> + <div class="form-error" ng-message="required"> + <span translate="ERROR.FIELD_REQUIRED"></span> + </div> + <div class="form-error" ng-message="minlength"> + <span translate="ERROR.FIELD_TOO_SHORT"></span> + </div> + </div> + + <!-- confirm password --> + <label class="item item-input" + ng-class="{ 'item-input-error': accountForm.$submitted && accountForm.confirmPassword.$invalid}"> + <span class="input-label" translate>ACCOUNT.NEW.PASSWORD_CONFIRM</span> + <input name="confirmPassword" type="password" placeholder="{{'ACCOUNT.NEW.PASSWORD_CONFIRM_HELP' | translate}}" ng-model="accountData.confirmPassword" ng-change="loginDataChanged()" + compare-to="accountData.password"> + </label> + <div class="form-errors" + ng-show="accountForm.$submitted && accountForm.confirmPassword.$error" + ng-messages="accountForm.confirmPassword.$error"> + <div class="form-error" ng-message="required"> + <span translate="ERROR.FIELD_REQUIRED"></span> + </div> + <div class="form-error" ng-message="compareTo"> + <span translate="ERROR.PASSWORD_NOT_CONFIRMED"></span> + </div> + </div> + + <!-- Show public key--> + <div class="item item-icon-left item-button-right"> + <i class="icon ion-key"/> + <span translate>COMMON.PUBKEY</span> + <a class="button button-light button-small" + ng-click="showAccountPubkey()" + ng-if="!accountData.pubkey && accountForm.$valid" + class="animate-if" translate> + COMMON.BTN_SHOW + </a> + <span class="badge badge-energized" ng-if="accountData.pubkey"> + {{accountData.pubkey | formatPubkey}} + </span> + </div> + </div> + + <div class="padding"> + <button class="button button-block button-positive" type="submit"> + {{'COMMON.BTN_OK' | translate}} + </button> + </div> + </form> </ion-slide> </ion-slide-box> </ion-view> + +<script type="text/ng-template" id="error-messages"> + <div class="error" ng-message="required"> + <i class="ion-information-circled"></i> + <div translate="ERROR.FIELD_REQUIRED"></div> + </div> + <div class="error" ng-message="minlength"> + <i class="ion-information-circled"></i> + <div translate="ERROR.FIELD_TOO_SHORT"></div> + </div> +</script> \ No newline at end of file diff --git a/www/templates/home.html b/www/templates/home.html index c68e6a3b67a63e31bce9bb187620c75a0d0187e7..13ca7be65629efda027b4eb69934beb53ab30071 100644 --- a/www/templates/home.html +++ b/www/templates/home.html @@ -19,8 +19,14 @@ <a ui-sref="app.explore_currency" class="button button-block button-stable icon icon-left ion-ios-world-outline" translate>HOME.BTN_CURRENCIES</a> - <button ng-click="login()" ng-show="!isLogged()" class="button button-block button-positive icon icon-left ion-log-in" translate>COMMON.BTN_LOGIN</button> - <!-- <button ng-click="addAccount()" ng-show="!isLogged()" class="button button-block button-assertive icon icon-left ion-ios-color-wand">Add an account</button> --> - + <div class="row"> + <div class="col"> + <button ng-click="login()" ng-show="!isLogged()" class="button button-block button-positive icon icon-left ion-log-in" translate>COMMON.BTN_LOGIN</button> + </div> + <div class="col"> + <button ng-click="newAccount()" ng-show="!isLogged()" class="button button-block button-assertive icon icon-left ion-ios-color-wand" translate>COMMON.BTN_ADD_ACCOUNT</button> + </div> + </div> </ion-content> + </ion-view> diff --git a/www/templates/login.html b/www/templates/login.html index 6cc61de36635863d631f5d38705157e7141e9861..58b84bb51515588043cd97eca3170c05d9630d14 100644 --- a/www/templates/login.html +++ b/www/templates/login.html @@ -3,30 +3,56 @@ <button class="button button-positive" ng-click="closeLogin()" translate>COMMON.BTN_CANCEL </button> <h1 class="title" translate>LOGIN.TITLE</h1> - <button class="button button-positive" ng-click="doLogin()" translate>COMMON.BTN_OK - </button> + <button class="button button-positive button-icon ion-android-done" ng-click="doLogin()"></button> </ion-header-bar> <ion-content scroll="false"> - <form ng-submit="doLogin()"> - <div class="list"> - <label class="item item-input item-floating-label"> + <form name="loginForm" novalidate="" ng-submit="doLogin()"> + <div class="list" + ng-init="setLoginForm(loginForm)"> + + <!-- username --> + <label class="item item-input" + ng-class="{ 'item-input-error': loginForm.$submitted && loginForm.username.$invalid}"> <span class="input-label" translate>LOGIN.USERNAME</span> - <input type="text" placeholder="{{'LOGIN.USERNAME_HELP' | translate}}" ng-model="loginData.username" ng-change="loginDataChanged()"> + <input name="username" type="text" placeholder="{{'LOGIN.USERNAME_HELP' | translate}}" + ng-model="loginData.username" + ng-change="loginDataChanged()" + required> </label> - <label class="item item-input item-floating-label"> + <div class="form-errors" + ng-show="loginForm.$submitted && loginForm.username.$error" + ng-messages="loginForm.username.$error"> + <div class="form-error" ng-message="required"> + <span translate="ERROR.FIELD_REQUIRED"></span> + </div> + </div> + + <!-- password--> + <label class="item item-input" + ng-class="{ 'item-input-error': loginForm.$submitted && loginForm.password.$invalid}"> <span class="input-label" translate>LOGIN.PASSWORD</span> - <input type="password" placeholder="{{'LOGIN.PASSWORD_HELP' | translate}}" ng-model="loginData.password" ng-change="loginDataChanged()"> + <input name="password" type="password" placeholder="{{'LOGIN.PASSWORD_HELP' | translate}}" + ng-model="loginData.password" + ng-change="loginDataChanged()" + required> </label> + <div class="form-errors" + ng-show="loginForm.$submitted && loginForm.password.$error" + ng-messages="loginForm.password.$error"> + <div class="form-error" ng-message="required"> + <span translate="ERROR.FIELD_REQUIRED"></span> + </div> + </div> + + <!-- show public key --> <div class="item item-icon-left item-button-right"> <i class="icon ion-key"/> <span translate>COMMON.PUBKEY</span> <a class="button button-light button-small" ng-click="showLoginPubkey()" ng-if="!(loginData.pubkey || loginData.computing || !loginData.username || !loginData.password)" class="animate-if"> {{'COMMON.BTN_SHOW' | translate}} - </a> - </label> - + </a> <span class="badge badge-energized" ng-if="loginData.pubkey"> {{loginData.pubkey | formatPubkey}} </span> diff --git a/www/templates/market/modal_category.html b/www/templates/market/modal_category.html index a27af8575f731a09577f2f9562560449622ed53e..0d9042bbabfab62b84dfdc608c2052fc068b0149 100644 --- a/www/templates/market/modal_category.html +++ b/www/templates/market/modal_category.html @@ -1,6 +1,6 @@ <ion-modal-view> <ion-header-bar class="bar-positive"> - <h1 class="title" translate>RECORD.COMMON.CATEGORIES</h1> + <h1 class="title" translate>MARKET.COMMON.CATEGORIES</h1> <button class="button button-positive" ng-click="closeCategoryModal()" translate>COMMON.BTN_CANCEL</button> </ion-header-bar> diff --git a/www/templates/registry/modal_category.html b/www/templates/registry/modal_category.html index a27af8575f731a09577f2f9562560449622ed53e..b3d7c2ba7cb1a729c64ee56f934447f54d1efa72 100644 --- a/www/templates/registry/modal_category.html +++ b/www/templates/registry/modal_category.html @@ -1,6 +1,6 @@ <ion-modal-view> <ion-header-bar class="bar-positive"> - <h1 class="title" translate>RECORD.COMMON.CATEGORIES</h1> + <h1 class="title" translate>REGISTRY.COMMON.CATEGORIES</h1> <button class="button button-positive" ng-click="closeCategoryModal()" translate>COMMON.BTN_CANCEL</button> </ion-header-bar> @@ -16,7 +16,7 @@ </label> <a class="item" ng-repeat="found in categories" ng-class="{'item-divider': (found.parent==null)}" href="#" ng-click="selectCategory(found)"> - <h2 ng-bind-html="found.name"></h2> + <h2 ng-bind-html="found.name" class="item-category"></h2> </a> </div> </ion-content>