From c1a13fdb788406d194df43436c06c476c5fdf295 Mon Sep 17 00:00:00 2001 From: blavenie <benoit.lavenier@e-is.pro> Date: Mon, 21 Mar 2016 17:47:27 +0100 Subject: [PATCH] - Registry : Review UI - Registry : Add new record wizard --- www/css/cesium.css | 2 +- www/i18n/locale-en.json | 37 +++- www/i18n/locale-fr.json | 45 +++- www/js/app.js | 3 +- www/js/controllers/home-controllers.js | 55 +++-- www/js/controllers/market-controllers.js | 6 +- www/js/controllers/registry-controllers.js | 205 +++++++++++++++++- www/js/controllers/wallet-controllers.js | 10 +- www/js/controllers/wot-controllers.js | 13 +- www/js/services/utils-services.js | 28 +++ ...w_account.html => new_account_wizard.html} | 2 +- .../{view_transfer.html => new_transfer.html} | 0 www/templates/explore/explore_tabs.html | 2 +- www/templates/market/edit_record.html | 17 +- www/templates/market/lookup.html | 24 +- www/templates/registry/edit_record.html | 76 +------ www/templates/registry/lookup.html | 24 +- www/templates/registry/new_record_wizard.html | 39 ++++ www/templates/registry/record_form.html | 64 ++++++ www/templates/registry/view_record.html | 38 +++- www/templates/wot/lookup.html | 2 +- www/templates/wot/view_identity.html | 4 +- 22 files changed, 516 insertions(+), 180 deletions(-) rename www/templates/account/{new_account.html => new_account_wizard.html} (99%) rename www/templates/account/{view_transfer.html => new_transfer.html} (100%) create mode 100644 www/templates/registry/new_record_wizard.html create mode 100644 www/templates/registry/record_form.html diff --git a/www/css/cesium.css b/www/css/cesium.css index bfe19f0fe..bef322291 100644 --- a/www/css/cesium.css +++ b/www/css/cesium.css @@ -48,7 +48,7 @@ body { } .light { - color: grey; + color: grey !important; } /*.button {*/ /*height: 50px !important;*/ diff --git a/www/i18n/locale-en.json b/www/i18n/locale-en.json index 32e9783b3..5e007e901 100644 --- a/www/i18n/locale-en.json +++ b/www/i18n/locale-en.json @@ -85,7 +85,7 @@ "PSEUDO_HELP": "joe123", "PASSWORD_CONFIRM": "Confirm Password", "PASSWORD_CONFIRM_HELP": "Confirm Password", - "MSG_UID_ALREADY_USED": "This pseudonym is alreadey used by an existing member.<br/>Please choose another one." + "MSG_UID_ALREADY_USED": "This pseudonym is already used by an existing member.<br/>Please choose another one." }, "POPUP_REGISTER": { "TITLE": "Enter a pseudonym", @@ -111,7 +111,10 @@ "TITLE": "Market", "SEARCH_HELP": "Search (car, store)", "BTN_ADD": "New", - "BTN_OPTIONS": "Search tool" + "BTN_OPTIONS": "Search tool", + "BTN_AROUND_ME": "Around me", + "LOCATION": "Location", + "LOCATION_HELP": "City" }, "VIEW": { "TITLE": "" @@ -123,7 +126,8 @@ "RECORD_TITLE_HELP": "Title", "RECORD_DESCRIPTION": "Description", "RECORD_DESCRIPTION_HELP": "Description", - "RECORD_LOCATION": "Location" + "RECORD_LOCATION": "Localization", + "RECORD_LOCATION_HELP": "Address, City" } }, "REGISTRY": { @@ -141,15 +145,22 @@ "VIEW": { "TITLE": "" }, + "NEW": { + "TITLE": "New", + "SELECT_TYPE": "Choose type:", + "TYPE_PARTICULAR": "Private individual", + "TYPE_COMPANY": "Company, organisation or institution" + }, "EDIT": { "TITLE": "Edit", "BTN_ADD_PICTURES": "Add pictures", - "RECORD_TITLE": "Title", - "RECORD_TITLE_HELP": "Title", - "RECORD_DESCRIPTION": "Description", - "RECORD_DESCRIPTION_HELP": "Description", - "RECORD_LOCATION": "Location", - "BTN_IS_COMPANY": "Is Company ?" + "RECORD_TITLE": "Name", + "RECORD_TITLE_HELP": "Name", + "RECORD_DESCRIPTION": "About me", + "RECORD_DESCRIPTION_HELP": "Something about me", + "RECORD_LOCATION": "Localization", + "RECORD_LOCATION_HELP": "Localization (address, city)", + "RECORD_SOCIAL_NETWORKS": "Social networks" } }, "ERROR": { @@ -159,9 +170,13 @@ "FIELD_REQUIRED": "This field is required.", "FIELD_TOO_SHORT": "This field is too short.", "PASSWORD_NOT_CONFIRMED": "Must match previous password", - "SEND_SELF_REGISTRATION": "Error while trying to register" + "SEND_SELF_REGISTRATION": "Error while trying to register", + "SEND_CERTIFICATION_FAILED": "Could not certify identity", + "LOGIN_FAILED": "Error while login", + "LOAD_IDENTITY_FAILED": "Could not load identity" }, "INFO": { - "POPUP_TITLE": "Information" + "POPUP_TITLE": "Information", + "CERTIFICATION_DONE": "Identity successfully signed" } } diff --git a/www/i18n/locale-fr.json b/www/i18n/locale-fr.json index 884a90b2d..3b3fb499f 100644 --- a/www/i18n/locale-fr.json +++ b/www/i18n/locale-fr.json @@ -84,7 +84,12 @@ "PSEUDO": "Pseudonyme", "PSEUDO_HELP": "Pseudonyme", "PASSWORD_CONFIRM": "Confirmation du mot de passe", - "PASSWORD_CONFIRM_HELP": "Confirmation du mot de passe" + "PASSWORD_CONFIRM_HELP": "Confirmation du mot de passe", + "MSG_UID_ALREADY_USED": "Pseudonyme déjà pris par quelqu'un d'autre.<br/>Veuillez en choisir un autre." + }, + "POPUP_REGISTER": { + "TITLE": "Choisissez un pseudonyme", + "HELP": "Un pseudonyme est obligatoire pour devenir membre." } }, "TRANSFER": { @@ -106,7 +111,10 @@ "TITLE": "Offres/Demandes", "SEARCH_HELP": "Recherche (voiture, livre...)", "BTN_ADD": "Nouveau", - "BTN_OPTIONS": "Outil de recherche" + "BTN_OPTIONS": "Outil de recherche", + "BTN_AROUND_ME": "Autour de moi", + "LOCATION": "Localisation", + "LOCATION_HELP": "Ville" }, "VIEW": { "TITLE": "" @@ -118,7 +126,8 @@ "RECORD_TITLE_HELP": "Titre", "RECORD_DESCRIPTION": "Description", "RECORD_DESCRIPTION_HELP": "Description", - "RECORD_LOCATION": "Ville" + "RECORD_LOCATION": "Ville", + "RECORD_LOCATION_HELP": "Adresse, Ville" } }, "REGISTRY": { @@ -136,22 +145,38 @@ "VIEW": { "TITLE": "" }, + "NEW": { + "TITLE": "Nouveau", + "SELECT_TYPE": "Type d'ajout :", + "TYPE_PARTICULAR": "Particulier", + "TYPE_COMPANY": "Entreprise, organisme ou institution" + }, "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" + "RECORD_TITLE": "Nom", + "RECORD_TITLE_HELP": "Nom", + "RECORD_DESCRIPTION": "À propos de moi", + "RECORD_DESCRIPTION_HELP": "À propos de moi", + "RECORD_LOCATION": "Localisation", + "RECORD_LOCATION_HELP": "Localisation (adresse, ville)", + "RECORD_SOCIAL_NETWORKS": "Social networks" } }, "ERROR": { "POPUP_TITLE": "Erreur", "UNKNOWN_ERROR": "Erreur inconnue", - "CRYPTO_UNKNOWN_ERROR": "Votre navigateur ne semble pas compatible avec les fonctionnalités de cryptographie." + "CRYPTO_UNKNOWN_ERROR": "Votre navigateur ne semble pas compatible avec les fonctionnalités de cryptographie.", + "FIELD_REQUIRED": "Champ obligatoire.", + "FIELD_TOO_SHORT": "Valeur trop courte.", + "PASSWORD_NOT_CONFIRMED": "Ne correspond pas au mot de passe", + "SEND_SELF_REGISTRATION": "Erreur pendant l'inscription.", + "SEND_CERTIFICATION_FAILED": "Erreur lors de la certification de l'identité", + "LOGIN_FAILED": "Erreur lors de l'authentification", + "LOAD_IDENTITY_FAILED": "Erreur de chargement de l'identité" }, "INFO": { - "POPUP_TITLE": "Information" + "POPUP_TITLE": "Information", + "CERTIFICATION_DONE": "Certification envoyée" } } diff --git a/www/js/app.js b/www/js/app.js index 95371216f..44f56bf7d 100644 --- a/www/js/app.js +++ b/www/js/app.js @@ -52,7 +52,8 @@ angular.module('cesium', ['ionic', 'ngMessages', 'pascalprecht.translate', 'cesi }) .uniformLanguageTag('bcp47') .determinePreferredLanguage() - .useSanitizeValueStrategy('sanitize') + // Cela fait bugger les placeholder (pb d'affichage des accents en FR) + //.useSanitizeValueStrategy('sanitize') .fallbackLanguage(['en', 'fr']) .useLoaderCache(true); diff --git a/www/js/controllers/home-controllers.js b/www/js/controllers/home-controllers.js index 3c9bb7580..6e8e15aa1 100644 --- a/www/js/controllers/home-controllers.js +++ b/www/js/controllers/home-controllers.js @@ -184,34 +184,13 @@ function LoginController($scope, $ionicModal, Wallet, CryptoUtils, UIUtils, $q, }; } -function HomeController($scope, $ionicSlideBoxDelegate, $ionicModal, $state, $ionicSideMenuDelegate, UIUtils, $q, $timeout, CryptoUtils, BMA, Wallet, Registry, APP_CONFIG) { - // With the new view caching in Ionic, Controllers are only called - // when they are recreated or on app start, instead of every page change. - // To listen for when this page is active (for example, to refresh data), - // listen for the $ionicView.enter event: - //$scope.$on('$ionicView.enter', function(e) { - //}); +function NewAccountWizardController($scope, $ionicSlideBoxDelegate, $ionicModal, $state, $ionicSideMenuDelegate, UIUtils, $q, $timeout, CryptoUtils, BMA, Wallet, Registry) { - LoginController.call(this, $scope, $ionicModal, Wallet, CryptoUtils, UIUtils, $q, $state, $timeout, $ionicSideMenuDelegate); - - $scope.accounts = []; - $scope.search = { text: '', results: {} }; - $scope.knownCurrencies = ['meta_brouzouf']; $scope.slideIndex = 0; $scope.accountData = {}; $scope.accountForm = {}; - var nodeWithES = APP_CONFIG.UCOIN_NODE_ES != "undefined" && APP_CONFIG.UCOIN_NODE_ES != null; - $scope.options = { - market: { - enable: nodeWithES - }, - registry: { - enable: nodeWithES - } - }; - // Called to navigate to the main app $scope.cancel = function() { $scope.newAccountModal.hide(); @@ -257,7 +236,7 @@ function HomeController($scope, $ionicSlideBoxDelegate, $ionicModal, $state, $io if (!$scope.newAccountModal) { UIUtils.loading.show(); // Create the account modal that we will use later - $ionicModal.fromTemplateUrl('templates/account/new_account.html', { + $ionicModal.fromTemplateUrl('templates/account/new_account_wizard.html', { scope: $scope }).then(function(modal) { $scope.newAccountModal = modal; @@ -332,3 +311,33 @@ function HomeController($scope, $ionicSlideBoxDelegate, $ionicModal, $state, $io */ } + + +function HomeController($scope, $ionicSlideBoxDelegate, $ionicModal, $state, $ionicSideMenuDelegate, UIUtils, $q, $timeout, CryptoUtils, BMA, Wallet, Registry, APP_CONFIG) { + + // With the new view caching in Ionic, Controllers are only called + // when they are recreated or on app start, instead of every page change. + // To listen for when this page is active (for example, to refresh data), + // listen for the $ionicView.enter event: + //$scope.$on('$ionicView.enter', function(e) { + //}); + + $scope.accounts = []; + $scope.search = { text: '', results: {} }; + $scope.knownCurrencies = ['meta_brouzouf']; + + var nodeWithES = APP_CONFIG.UCOIN_NODE_ES != "undefined" && APP_CONFIG.UCOIN_NODE_ES != null; + $scope.options = { + market: { + enable: nodeWithES + }, + registry: { + enable: nodeWithES + } + }; + + LoginController.call(this, $scope, $ionicModal, Wallet, CryptoUtils, UIUtils, $q, $state, $timeout, $ionicSideMenuDelegate); + + NewAccountWizardController.call(this, $scope, $ionicSlideBoxDelegate, $ionicModal, $state, $ionicSideMenuDelegate, UIUtils, $q, $timeout, CryptoUtils, BMA, Wallet, Registry); +} + diff --git a/www/js/controllers/market-controllers.js b/www/js/controllers/market-controllers.js index f543ced45..755db59bd 100644 --- a/www/js/controllers/market-controllers.js +++ b/www/js/controllers/market-controllers.js @@ -121,7 +121,7 @@ function MarketCategoryModalController($scope, Market, $state, $ionicModal) { }; } -function MarketLookupController($scope, Market, $state, $ionicModal) { +function MarketLookupController($scope, Market, $state, $ionicModal, $focus) { MarketCategoryModalController.call(this, $scope, Market, $state, $ionicModal); @@ -132,6 +132,10 @@ function MarketLookupController($scope, Market, $state, $ionicModal) { options: false }; + $scope.$on('$ionicView.enter', function(e, $state) { + $focus('searchText'); + }); + $scope.$watch('search.options', $scope.doSearch, true); $scope.isFilter = function(filter) { diff --git a/www/js/controllers/registry-controllers.js b/www/js/controllers/registry-controllers.js index 376b5cd7c..258335c13 100644 --- a/www/js/controllers/registry-controllers.js +++ b/www/js/controllers/registry-controllers.js @@ -120,9 +120,10 @@ function RegistryCategoryModalController($scope, Registry, $state, $ionicModal) }; } -function RegistryLookupController($scope, Registry, $state, $ionicModal) { +function RegistryLookupController($scope, $ionicSlideBoxDelegate, $state, $ionicModal, $focus, $q, $timeout, Registry, UIUtils) { RegistryCategoryModalController.call(this, $scope, Registry, $state, $ionicModal); + RegistryNewRecordWizardController.call(this, $scope, $ionicSlideBoxDelegate, $ionicModal, $state, UIUtils, $q, $timeout, Registry); $scope.search = { text: '', @@ -131,6 +132,10 @@ function RegistryLookupController($scope, Registry, $state, $ionicModal) { options: false }; + $scope.$on('$ionicView.enter', function(e, $state) { + $focus('searchText'); + }); + $scope.$watch('search.options', $scope.doSearch, true); $scope.isFilter = function(filter) { @@ -167,7 +172,7 @@ function RegistryLookupController($scope, Registry, $state, $ionicModal) { }, from: 0, size: 20, - _source: ["title", "time", "description", "pictures"] + _source: ["title", "description", "time", "location", "pictures", "issuer", "isCompany"] }; var matches = []; if ($scope.search.text.length > 1) { @@ -217,7 +222,7 @@ function RegistryLookupController($scope, Registry, $state, $ionicModal) { }; } -function RegistryRecordViewController($scope, $ionicModal, Wallet, Registry, UIUtils, $state, CryptoUtils, $q) { +function RegistryRecordViewController($scope, $ionicModal, Wallet, Registry, UIUtils, $state, CryptoUtils, $q, BMA) { $scope.formData = {}; $scope.id = null; @@ -225,6 +230,8 @@ function RegistryRecordViewController($scope, $ionicModal, Wallet, Registry, UIU $scope.category = {}; $scope.pictures = []; $scope.canEdit = false; + $scope.hasSelf = false; + $scope.identity = null; $scope.$on('$ionicView.enter', function(e, $state) { if ($state.stateParams && $state.stateParams.id) { // Load by id @@ -251,25 +258,76 @@ function RegistryRecordViewController($scope, $ionicModal, Wallet, Registry, UIU }, []); } $scope.canEdit = !$scope.isLogged() || ($scope.formData && $scope.formData.issuer == Wallet.getData().pubkey) - UIUtils.loading.hide(); + + if (!$scope.formData.isCompany) { + BMA.wot.lookup({ search: $scope.formData.issuer }) + .then(function(res){ + $scope.identity = res.results.reduce(function(idties, res) { + return idties.concat(res.uids.reduce(function(uids, idty) { + return uids.concat({ + uid: idty.uid, + pub: res.pubkey, + sigDate: idty.meta.timestamp, + sig: idty.self + }) + }, [])); + }, [])[0]; + $scope.hasSelf = ($scope.identity.uid && $scope.identity.sigDate && $scope.identity.sig); + UIUtils.loading.hide(); + }) + .catch(UIUtils.onError('ERROR.LOAD_IDENTITY_FAILED')); + } + else { + $scope.hasSelf = false; + $scope.identity = null; + UIUtils.loading.hide(); + } }) }) ]).catch(UIUtils.onError('Could not load registry')); }; + // Edit click $scope.edit = function() { $state.go('app.registry_edit_record', {id: $scope.id}); }; + + // Sign click + $scope.signIdentity = function(identity) { + $scope.loadWallet() + .then(function(walletData) { + UIUtils.loading.show(); + Wallet.sign($scope.identity.uid, + $scope.identity.pub, + $scope.identity.sigDate, + $scope.identity.sig) + .then(function() { + UIUtils.loading.hide(); + UIUtils.alertInfo('INFO.CERTIFICATION_DONE'); + }) + .catch(UIUtils.onError('ERROR.SEND_CERTIFICATION_FAILED')); + }) + .catch(UIUtils.onError('ERROR.LOGIN_FAILED')); + }; + + // Transfer click + $scope.transfer = function() { + $state.go('app.new_transfer', { + pubkey: $scope.formData.issuer, + uid: $scope.formData.title + }); + }; } -function RegistryRecordEditController($scope, $ionicModal, Wallet, Registry, UIUtils, $state, CryptoUtils, $q, $ionicPopup) { +function RegistryRecordEditController($scope, $ionicModal, Wallet, Registry, UIUtils, $state, CryptoUtils, $q, $ionicPopup, $translate) { RegistryCategoryModalController.call(this, $scope, Registry, $state, $ionicModal); $scope.walletData = {}; - $scope.formData = { + $scope.recordData = { isCompany: false }; + $scope.recordForm = {}; $scope.id = null; $scope.isMember = false; $scope.category = {}; @@ -282,6 +340,11 @@ function RegistryRecordEditController($scope, $ionicModal, Wallet, Registry, UIU $scope.camera = navigator.camera; }); + + $scope.setRecordForm = function(recordForm) { + $scope.recordForm = recordForm; + }; + $scope.$on('$ionicView.enter', function(e, $state) { $scope.loadWallet() .then(function(walletData) { @@ -302,7 +365,7 @@ function RegistryRecordEditController($scope, $ionicModal, Wallet, Registry, UIU .then(function(categories) { Registry.record.get({id: id}) .then(function (hit) { - $scope.formData = hit._source; + $scope.recordData = hit._source; $scope.category = categories[hit._source.category]; $scope.id= hit._id; if (hit._source.pictures) { @@ -320,11 +383,11 @@ function RegistryRecordEditController($scope, $ionicModal, Wallet, Registry, UIU $scope.save = function() { UIUtils.loading.show(); return $q(function(resolve, reject) { - $scope.formData.pictures = $scope.pictures.reduce(function(res, pic) { + $scope.recordData.pictures = $scope.pictures.reduce(function(res, pic) { return res.concat({src: pic.src}); }, []); if (!$scope.id) { // Create - Registry.record.add($scope.formData, $scope.walletData.keypair) + Registry.record.add($scope.recordData, $scope.walletData.keypair) .then(function(id) { UIUtils.loading.hide(); $state.go('app.registry_view_record', {id: id}) @@ -333,7 +396,7 @@ function RegistryRecordEditController($scope, $ionicModal, Wallet, Registry, UIU .catch(UIUtils.onError('Could not save registry')); } else { // Update - Registry.record.update($scope.formData, {id: $scope.id}, $scope.walletData.keypair) + Registry.record.update($scope.recordData, {id: $scope.id}, $scope.walletData.keypair) .then(function() { UIUtils.loading.hide(); $state.go('app.registry_view_record', {id: $scope.id}) @@ -347,7 +410,7 @@ function RegistryRecordEditController($scope, $ionicModal, Wallet, Registry, UIU $scope.selectCategory = function(cat) { if (!cat.parent) return; $scope.category = cat; - $scope.formData.category = cat.id; + $scope.recordData.category = cat.id; $scope.closeCategoryModal(); }; @@ -448,4 +511,124 @@ function RegistryRecordEditController($scope, $ionicModal, Wallet, Registry, UIU }) .catch(onError('Could not computed authentication token')); }; +} + +function RegistryNewRecordWizardController($scope, $ionicSlideBoxDelegate, $ionicModal, $state, UIUtils, $q, $timeout, Registry) { + + $scope.slideIndex = 0; + $scope.recordData = { + isCompany: null + }; + $scope.recordForm = {}; + $scope.pictures = []; + + // Called to navigate to the main app + $scope.cancel = function() { + $scope.newRecordModal.hide(); + $timeout(function(){ + $scope.recordData = { + isCompany: null + }; + $scope.recordForm = {}; + }, 200); + }; + + $scope.setRecordForm = function(recordForm) { + $scope.recordForm = recordForm; + }; + + // 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() { + $scope.slide($scope.slideIndex + 1); + }; + + $scope.previous = function() { + $scope.slide($scope.slideIndex - 1); + }; + + $scope.newRecord = function() { + var showModal = function() { + $scope.loadWallet() + .then(function(walletData) { + $scope.walletData = walletData; + UIUtils.loading.hide(); + $ionicSlideBoxDelegate.enableSlide(false); + $scope.slide(0); + $scope.newRecordModal.show(); + // TODO: remove default + /*$timeout(function() { + $scope.recordData.isCompany = false; + $scope.recordData.title="Benoit Lavenier"; + $scope.recordData.description="J'aime le Sou !"; + $scope.next(); + }, 300);*/ + }); + } + + if (!$scope.newRecordModal) { + UIUtils.loading.show(); + // Create the account modal that we will use later + $ionicModal.fromTemplateUrl('templates/registry/new_record_wizard.html', { + scope: $scope, + animation: 'slide-in-down' + }).then(function(modal) { + $scope.newRecordModal = modal; + $scope.newRecordModal.hide() + .then(function(){ + UIUtils.loading.hide(); + showModal(); + }); + + }); + } + else { + showModal(); + } + }; + + $scope.setIsCompany = function(bool) { + $scope.recordData.isCompany = bool; + $scope.next(); + }; + + $scope.doNewRecord = function() { + $scope.recordForm.$submitted=true; + if(!$scope.recordForm.$valid) { + return; + } + + UIUtils.loading.show(); + return $q(function(resolve, reject) { + $scope.recordData.pictures = $scope.pictures.reduce(function(res, pic) { + return res.concat({src: pic.src}); + }, []); + Registry.record.add($scope.recordData, $scope.walletData.keypair) + .then(function(id) { + //UIUtils.loading.hide(); + $scope.newRecordModal.hide(); + $scope.newRecordModal.remove(); + $state.go('app.registry_view_record', {id: id}) + resolve(); + }) + .catch(UIUtils.onError('Could not save registry')); + }); + }; + + //Cleanup the modal when hidden + $scope.$on('newRecordModal.hidden', function() { + $scope.newRecordModal.remove(); + $scope.newRecordModal = null; + }); + + // TODO: remove auto add account when done + /*$timeout(function() { + $scope.newRecord(); + }, 400); + */ } \ No newline at end of file diff --git a/www/js/controllers/wallet-controllers.js b/www/js/controllers/wallet-controllers.js index 26594199c..91d8eedb3 100644 --- a/www/js/controllers/wallet-controllers.js +++ b/www/js/controllers/wallet-controllers.js @@ -14,21 +14,21 @@ angular.module('cesium.wallet.controllers', ['cesium.services', 'cesium.currency } }) - .state('app.view_transfer', { + .state('app.new_transfer', { url: "/transfer/:pubkey/:uid", views: { 'menuContent': { - templateUrl: "templates/account/view_transfer.html", + templateUrl: "templates/account/new_transfer.html", controller: 'TransferCtrl' } } }) - .state('app.view_transfer_pubkey', { + .state('app.new_transfer_pubkey', { url: "/transfer/:pubkey", views: { 'menuContent': { - templateUrl: "templates/account/view_transfer.html", + templateUrl: "templates/account/new_transfer.html", controller: 'TransferCtrl' } } @@ -85,7 +85,7 @@ function WalletController($scope, $state, $q, $ionicPopup, UIUtils, Wallet, BMA, // Transfer click $scope.transfer= function() { - $state.go('app.view_transfer'); + $state.go('app.new_transfer'); }; $scope.setRegisterForm = function(registerForm) { diff --git a/www/js/controllers/wot-controllers.js b/www/js/controllers/wot-controllers.js index fbe8e6429..e24291f18 100644 --- a/www/js/controllers/wot-controllers.js +++ b/www/js/controllers/wot-controllers.js @@ -79,9 +79,10 @@ function IdentityController($scope, $state, BMA, Wallet, UIUtils, $q) { $scope.hasSelf = ($scope.identity.uid && $scope.identity.sigDate && $scope.identity.sig); UIUtils.loading.hide(); }) - .catch(UIUtils.onError('Could not load identity')); + .catch(UIUtils.onError('ERROR.LOAD_IDENTITY_FAILED')); }; + // Sign click $scope.signIdentity = function(identity) { $scope.loadWallet() .then(function(walletData) { @@ -92,18 +93,18 @@ function IdentityController($scope, $state, BMA, Wallet, UIUtils, $q) { $scope.identity.sig) .then(function() { UIUtils.loading.hide(); - UIUtils.alertInfo('Identity successfully signed'); + UIUtils.alertInfo('INFO.CERTIFICATION_DONE'); }) - .catch(UIUtils.onError('Could not certify identity')); + .catch(UIUtils.onError('ERROR.SEND_CERTIFICATION_FAILED')); }) - .catch(UIUtils.onError('Error while login')); + .catch(UIUtils.onError('ERROR.LOGIN_FAILED')); }; // Transfer click $scope.transfer = function() { - $state.go('app.view_transfer', { + $state.go('app.new_transfer', { pubkey: $scope.identity.pubkey, - uid: $scope.identity.uid, + uid: $scope.identity.uid }); }; } \ No newline at end of file diff --git a/www/js/services/utils-services.js b/www/js/services/utils-services.js index 2c209d31c..0e6cbf245 100644 --- a/www/js/services/utils-services.js +++ b/www/js/services/utils-services.js @@ -91,4 +91,32 @@ angular.module('cesium.utils.services', ['ngResource']) } }]) +// See http://plnkr.co/edit/vJQXtsZiX4EJ6Uvw9xtG?p=preview +.factory('$focus', function($timeout, $window) { + return function(id) { + // timeout makes sure that it is invoked after any other event has been triggered. + // e.g. click events that need to run before the focus or + // inputs elements that are in a disabled state but are enabled when those events + // are triggered. + $timeout(function() { + var element = $window.document.getElementById(id); + if(element) + element.focus(); + }); + }; +}) + +.directive('eventFocus', function(focus) { + return function(scope, elem, attr) { + elem.on(attr.eventFocus, function() { + focus(attr.eventFocusId); + }); + + // Removes bound events in the element itself + // when the scope is destroyed + scope.$on('$destroy', function() { + elem.off(attr.eventFocus); + }); + }; +}) ; diff --git a/www/templates/account/new_account.html b/www/templates/account/new_account_wizard.html similarity index 99% rename from www/templates/account/new_account.html rename to www/templates/account/new_account_wizard.html index 91bd5c84e..2c65354ae 100644 --- a/www/templates/account/new_account.html +++ b/www/templates/account/new_account_wizard.html @@ -21,7 +21,7 @@ </ion-slide> <ion-slide> <div class="padding"> - <h1 translate>ACCOUNT.NEW.SLIDE_2_TITLE</h1> + <h3 translate>ACCOUNT.NEW.SLIDE_2_TITLE</h3> <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> diff --git a/www/templates/account/view_transfer.html b/www/templates/account/new_transfer.html similarity index 100% rename from www/templates/account/view_transfer.html rename to www/templates/account/new_transfer.html diff --git a/www/templates/explore/explore_tabs.html b/www/templates/explore/explore_tabs.html index 05819a7a9..974d2defd 100644 --- a/www/templates/explore/explore_tabs.html +++ b/www/templates/explore/explore_tabs.html @@ -17,7 +17,7 @@ <ng-include src="'templates/explore/tabs/explore_tab_wot.html'"/> </ion-tab> - <ion-tab title="{{'CURRENCY.VIEW.TAB_NETWORK'|translate}}" icon="ion-network"> + <ion-tab title="{{'CURRENCY.VIEW.TAB_NETWORK'|translate}}" icon="ion-network" > <ion-nav-view name="network-tab"/> <ng-include src="'templates/explore/tabs/explore_tab_network.html'"/> </ion-tab> diff --git a/www/templates/market/edit_record.html b/www/templates/market/edit_record.html index fdf76561f..895774a60 100644 --- a/www/templates/market/edit_record.html +++ b/www/templates/market/edit_record.html @@ -50,11 +50,11 @@ <textarea placeholder="{{'MARKET.EDIT.RECORD_DESCRIPTION_HELP'|translate}}" ng-model="formData.description"></textarea> </div> - <div class="item item-floating-label"> + <div class="item item-floating-label" ng-if="location.enable"> <span class="input-label" translate>MARKET.EDIT.RECORD_LOCATION</span> <div class="item-input-inset"> <label class="item-input-wrapper"> - <input type="text" placeholder="Location" ng-model="formData.location"> + <input type="text" placeholder="{{'MARKET.EDIT.RECORD_LOCATION_HELP'|translate}}" ng-model="formData.location"> </label> <button class="button button-small button-positive" ng-click="localize()" ng-if="location.enable"> <i class="icon ion-pinpoint"></i> @@ -62,16 +62,11 @@ </div> </div> + <div class="item item-input item-floating-label" ng-if="!location.enable"> + <span class="input-label" translate>MARKET.EDIT.RECORD_LOCATION</span> + <textarea placeholder="{{'MARKET.EDIT.RECORD_LOCATION_HELP'|translate}}" ng-model="recordData.location"></textarea> + </div> - <!--<div class="item item-toggle dark"> - Public visibility - <label class="toggle toggle-royal"> - <input type="checkbox" ng-model="formData.public"> - <div class="track"> - <div class="handle"></div> - </div> - </label> - </div>--> </div> <div class="scroll-bar scroll-bar-v"></div> </div> diff --git a/www/templates/market/lookup.html b/www/templates/market/lookup.html index 3164e9e3f..73eec055c 100644 --- a/www/templates/market/lookup.html +++ b/www/templates/market/lookup.html @@ -9,7 +9,7 @@ <ion-content class="lookupForm padding"> <label class="item item-input"> <i class="icon ion-search placeholder-icon"></i> - <input type="text" placeholder="{{'MARKET.SEARCH.SEARCH_HELP'|translate}}" ng-model="search.text" ng-change="searchChanged()"> + <input type="text" placeholder="{{'MARKET.SEARCH.SEARCH_HELP'|translate}}" ng-model="search.text" ng-change="searchChanged()" id="searchText"> </label> <div class="item item-toggle dark" ng-if="search.text"> @@ -28,6 +28,24 @@ <i class="button button-clear ion-chevron-right"></i> </span> + <span class="item item-button-right" ng-if="search.options && location.enable"> + <span translate>MARKET.SEARCH.BTN_AROUND_ME</span> + <label class="toggle toggle-royal"> + <input type="checkbox" ng-model="search.localize"> + <div class="track"> + <div class="handle"></div> + </div> + </label> + </span> + + <span class="item item-button-right" ng-if="search.options && !location.enable"> + <span translate>MARKET.SEARCH.LOCATION</span> + <div class="item-input-inset"> + <label class="item-input-wrapper"> + <input type="text" placeholder="{{'MARKET.SEARCH.LOCATION_HELP'|translate}}" ng-model="search.location" /> + </label> + </div> + </span> <div class="list list-inset"> @@ -35,14 +53,14 @@ <ion-spinner icon="android"></ion-spinner> </label> - <a class="item row item-product" ng-repeat="found in search.results" ng-click="select('{{found.id}}')"> + <a class="item row item-record" ng-repeat="found in search.results" ng-click="select('{{found.id}}')"> <div class="col col-2"> <img style="height:70px" ng-src="{{found.pictures[0].src}}" nf-if="found.pictures && found.pictures > 0"> <span nf-if="!found.pictures || found.pictures == 0"> </span> </div> <div class="col col-80 padding"> <h2 ng-bind-html="found.title"></h2> - <h3 class="light" ng-bind-html="found.description"></h3> + <h3 class="light" ng-bind-html="found.location"></h3> <span class="badge item-note">{{found.time | formatDate}}</span> </div> </a> diff --git a/www/templates/registry/edit_record.html b/www/templates/registry/edit_record.html index 9259c2ddb..022b83ffd 100644 --- a/www/templates/registry/edit_record.html +++ b/www/templates/registry/edit_record.html @@ -8,81 +8,7 @@ <ion-content> <div class="scroll"> - <div class="list"> - - <ion-gallery ion-gallery-items="pictures" - ng-if="pictures && pictures.length>0"></ion-gallery> - - <div class="item item-icon-right" ng-if="camera"> - <span translate>REGISTRY.EDIT.BTN_ADD_PICTURES</span> - <a class="dark" href="#" ng-click="openPicturePopup()"> - <i class="icon ion-camera"></i> - </a> - </div> - - <div class="item item-input item-icon-right" ng-if="!camera" > - <span class="input-label has-input" translate>REGISTRY.EDIT.BTN_ADD_PICTURES</span> - <input type="file" id="file" accept=".png,.jpeg,.jpg" onchange="angular.element(this).scope().fileChanged(event)"/> - <!--a class="dark" href="#" ng-if="!camera" ng-click="addPictureFile()"> - <i class="icon ion-plus"></i> - </a--> - </div> - - <span class="item item-icon-left" ng-if="id && formData.issuer"> - <i class="icon ion-key"></i> - <span translate>REGISTRY.COMMON.ISSUER</span> - <span class="badge">{{formData.issuer | formatPubkey}}</span> - </span> - - <div class="item item-toggle dark"> - {{'REGISTRY.EDIT.BTN_IS_COMPANY' | translate}} - <label class="toggle toggle-royal"> - <input type="checkbox" ng-model="formData.isCompany"> - <div class="track"> - <div class="handle"></div> - </div> - </label> - </div> - - <span class="item item-button-right" ng-click="openCategoryModal()" ng-show="formData.isCompany"> - <span translate>REGISTRY.COMMON.CATEGORY</span> - <span>{{category.name}}</span> - <i class="button button-clear ion-chevron-right"></i> - </span> - - <div class="item item-input item-floating-label"> - <span class="input-label" translate>REGISTRY.EDIT.RECORD_TITLE</span> - <input type="text" placeholder="{{'REGISTRY.EDIT.RECORD_TITLE_HELP'|translate}}" ng-model="formData.title" /> - </div> - - <div class="item item-input item-floating-label"> - <span class="input-label" translate>REGISTRY.EDIT.RECORD_DESCRIPTION</span> - <textarea placeholder="{{'REGISTRY.EDIT.RECORD_DESCRIPTION_HELP'|translate}}" ng-model="formData.description"></textarea> - </div> - - <div class="item item-floating-label"> - <span class="input-label" translate>REGISTRY.EDIT.RECORD_LOCATION</span> - <div class="item-input-inset"> - <label class="item-input-wrapper"> - <input type="text" placeholder="Location" ng-model="formData.location"> - </label> - <button class="button button-small button-positive" ng-click="localize()" ng-if="location.enable"> - <i class="icon ion-pinpoint"></i> - </button> - </div> - </div> - - - <!--<div class="item item-toggle dark"> - Public visibility - <label class="toggle toggle-royal"> - <input type="checkbox" ng-model="formData.public"> - <div class="track"> - <div class="handle"></div> - </div> - </label> - </div>--> - </div> + <ng-include src="'templates/registry/record_form.html'"></ng-include> <div class="scroll-bar scroll-bar-v"></div> </div> </ion-content> diff --git a/www/templates/registry/lookup.html b/www/templates/registry/lookup.html index 32a6f4db5..cb022b392 100644 --- a/www/templates/registry/lookup.html +++ b/www/templates/registry/lookup.html @@ -1,6 +1,6 @@ <ion-view view-title="{{'REGISTRY.SEARCH.TITLE'|translate}}" left-buttons="leftButtons"> <ion-nav-buttons side="secondary"> - <button ui-sref="app.registry_add_record" class="button button-positive"> + <button class="button button-positive" ng-click="newRecord()"> <i class="icon ion-plus"></i> <span translate>REGISTRY.SEARCH.BTN_ADD</span> </button> @@ -9,7 +9,7 @@ <ion-content class="lookupForm padding"> <label class="item item-input"> <i class="icon ion-search placeholder-icon"></i> - <input type="text" placeholder="{{'REGISTRY.SEARCH.SEARCH_HELP'|translate}}" ng-model="search.text" ng-change="searchChanged()"> + <input type="text" placeholder="{{'REGISTRY.SEARCH.SEARCH_HELP'|translate}}" ng-model="search.text" ng-change="searchChanged()" id="searchText"> </label> <div class="item item-toggle dark" ng-if="search.text"> @@ -39,10 +39,22 @@ <img style="height:70px" ng-src="{{found.pictures[0].src}}" nf-if="found.pictures && found.pictures > 0"> <span nf-if="!found.pictures || found.pictures == 0"> </span> </div> - <div class="col col-80 padding"> - <h2 ng-bind-html="found.title"></h2> - <h3 class="light" ng-bind-html="found.description"></h3> - <span class="badge item-note">{{found.time | formatDate}}</span> + <div class="col col-80 padding" ng-if="found.isCompany"> + <h3> + <span ng-bind-html="found.title"></span> + <span class="light" ng-if="found.location">| {{found.location}}</span> + </h3> + <h4 class="light" ng-bind-html="found.location"></h4> + <h4 class="light" ng-bind-html="found.description"></h4> + <span class="badge badge-positive" ng-if="!found.isCompany">{{found.issuer | formatPubkey}}</span> + </div> + <div class="col col-80 padding" ng-if="!found.isCompany"> + <h3> + <span class="positive" ng-bind-html="found.title"></span> + <span class="light responsive-lg" ng-if="found.location">| {{found.location}}</span> + </h3> + <h4 class="light responsive-lg" ng-bind-html="found.description"></h4> + <span class="badge badge-positive" ng-if="!found.isCompany">{{found.issuer | formatPubkey}}</span> </div> </a> diff --git a/www/templates/registry/new_record_wizard.html b/www/templates/registry/new_record_wizard.html new file mode 100644 index 000000000..fb4034466 --- /dev/null +++ b/www/templates/registry/new_record_wizard.html @@ -0,0 +1,39 @@ +<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 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" translate>REGISTRY.NEW.TITLE</h1> + + <button class="button button-positive button-icon ion-android-send" ng-click="doNewRecord()" ng-show="slideIndex == 1"></button> + + </ion-nav-buttons> + </ion-header-bar> + + + <ion-slide-box on-slide-changed="slideChanged(index)" id="newRecord" class="has-header"> + <ion-slide> + <div class="padding"> + <h3 translate>REGISTRY.NEW.SELECT_TYPE</h3> + <button class="button button-block button-stable icon icon-left ion-person" ng-click="setIsCompany(false)" ng-class="{ selected: !recordData.isCompany && recordData.isCompany != null }" translate>REGISTRY.NEW.TYPE_PARTICULAR</button> + <button class="button button-block button-stable icon icon-left ion-android-cart" ng-click="setIsCompany(true)" ng-class="{ selected: recordData.isCompany && recordData.isCompany != null }" translate>REGISTRY.NEW.TYPE_COMPANY</button> + </div> + </ion-slide> + <ion-slide> + <ng-include src="'templates/registry/record_form.html'"></ng-include> + </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/registry/record_form.html b/www/templates/registry/record_form.html new file mode 100644 index 000000000..11c882ed7 --- /dev/null +++ b/www/templates/registry/record_form.html @@ -0,0 +1,64 @@ +<form name="recordForm" novalidate="" ng-submit="doNewRecord()"> + <div class="list" + ng-init="setRecordForm(recordForm)"> + + <ion-gallery ion-gallery-items="pictures" + ng-if="pictures && pictures.length>0"></ion-gallery> + + <div class="item item-icon-right" ng-if="camera"> + <span translate>REGISTRY.EDIT.BTN_ADD_PICTURES</span> + <a class="dark" href="#" ng-click="openPicturePopup()"> + <i class="icon ion-camera"></i> + </a> + </div> + + <div class="item item-input item-icon-right" ng-if="!camera" > + <span class="input-label has-input" translate>REGISTRY.EDIT.BTN_ADD_PICTURES</span> + <input type="file" id="file" accept=".png,.jpeg,.jpg" onchange="angular.element(this).scope().fileChanged(event)"/> + <!--a class="dark" href="#" ng-if="!camera" ng-click="addPictureFile()"> + <i class="icon ion-plus"></i> + </a--> + </div> + + <span class="item item-icon-left" ng-if="id && recordData.issuer"> + <i class="icon ion-key"></i> + <span translate>REGISTRY.COMMON.ISSUER</span> + <span class="badge">{{recordData.issuer | formatPubkey}}</span> + </span> + + <span class="item item-button-right" ng-click="openCategoryModal()" ng-show="recordData.isCompany"> + <span translate>REGISTRY.COMMON.CATEGORY</span> + <span>{{category.name}}</span> + <i class="button button-clear ion-chevron-right"></i> + </span> + + <div class="item item-input item-floating-label"> + <span class="input-label" translate>REGISTRY.EDIT.RECORD_TITLE</span> + <input type="text" placeholder="{{'REGISTRY.EDIT.RECORD_TITLE_HELP'|translate}}" ng-model="recordData.title" /> + </div> + + <div class="item item-input item-floating-label"> + <span class="input-label" translate>REGISTRY.EDIT.RECORD_DESCRIPTION</span> + <textarea placeholder="{{'REGISTRY.EDIT.RECORD_DESCRIPTION_HELP'|translate}}" ng-model="recordData.description"></textarea> + </div> + + <div class="item item-floating-label" ng-if="location.enable"> + <span class="input-label" translate>REGISTRY.EDIT.RECORD_LOCATION</span> + <div class="item-input-inset"> + <label class="item-input-wrapper"> + <input type="text" placeholder="{{'REGISTRY.EDIT.RECORD_LOCATION_HELP'|translate}}" ng-model="recordData.location"> + </label> + <button class="button button-small button-positive" ng-click="localize()" ng-if="location.enable"> + <i class="icon ion-pinpoint"></i> + </button> + </div> + </div> + + <div class="item item-input item-floating-label" ng-if="!location.enable"> + <span class="input-label" translate>REGISTRY.EDIT.RECORD_LOCATION</span> + <textarea placeholder="{{'REGISTRY.EDIT.RECORD_LOCATION_HELP'|translate}}" ng-model="recordData.location"></textarea> + </div> + + + </div> + </form> \ No newline at end of file diff --git a/www/templates/registry/view_record.html b/www/templates/registry/view_record.html index f9bd74d5a..35440917c 100644 --- a/www/templates/registry/view_record.html +++ b/www/templates/registry/view_record.html @@ -13,27 +13,45 @@ <ion-gallery ion-gallery-items="pictures" ng-if="pictures && pictures.length>0"></ion-gallery> <div class="item"> - <h2 ng-bind-html="formData.title"></h2> + <h2 class="positive" ng-bind-html="formData.title"></h2> + <h4 class="light" ng-bind-html="formData.location"></h4> + <span class="badge badge-positive" ng-if="!formData.isCompany">{{formData.issuer | formatPubkey}}</span> </div> <div class="item"> <p ng-bind-html="formData.description"></p> </div> - <div class="item-divider"></div> + <div ng-if="formData.isCompany"> + <div class="item-divider"></div> - <span class="item item-icon-left"> - <i class="icon ion-person"></i> - <span translate>REGISTRY.COMMON.ISSUER</span> - <span class="badge" ng-class="{'badge-positive': isMember, 'badge-assertive': !isMember}">{{formData.issuer | formatPubkey}}</span> - </span> + <span class="item item-icon-left" > + <i class="icon ion-person"></i> + <h3><span translate>REGISTRY.COMMON.ISSUER</span></h3> + <span class="badge" ng-class="{'badge-positive': isMember, 'badge-assertive': !isMember}">{{formData.issuer | formatPubkey}}</span> + </span> - <div class="item"> - <span translate>REGISTRY.COMMON.CATEGORY</span> - <span class="badge badge-positive">{{category.name}}</span> + <div class="item"> + <span translate>REGISTRY.COMMON.CATEGORY</span> + <span class="badge badge-positive">{{category.name}}</span> + </div> </div> + <div class="item-divider"></div> + + <div class="item item-button-right positive" ng-click="transfer()"> + Send money + <a class="button button-clear button-positive" > + <i class="icon-right ion-chevron-right"></i> + </a> + </div> + <div class="item item-button-right positive" ng-click="signIdentity()" ng-if="hasSelf"> + Certify + <a class="button button-clear button-positive" > + <i class="icon-right ion-chevron-right"></i> + </a> + </div> </div> <div class="scroll-bar scroll-bar-v"></div> diff --git a/www/templates/wot/lookup.html b/www/templates/wot/lookup.html index 5f657b3a8..f962dbdd6 100644 --- a/www/templates/wot/lookup.html +++ b/www/templates/wot/lookup.html @@ -2,7 +2,7 @@ <div class="list list-inset"> <label class="item item-input"> <i class="icon ion-search placeholder-icon"></i> - <input type="text" placeholder="{{'WOT.SEARCH_HELP'|translate}}" ng-model="search.text" ng-change="searchChanged()"> + <input type="text" placeholder="{{'WOT.SEARCH_HELP'|translate}}" ng-model="search.text" ng-change="searchChanged()" id="searchWot"> </label> <label class="item center" ng-if="search.looking"> diff --git a/www/templates/wot/view_identity.html b/www/templates/wot/view_identity.html index d8cf130e7..c17dda98c 100644 --- a/www/templates/wot/view_identity.html +++ b/www/templates/wot/view_identity.html @@ -15,9 +15,7 @@ <span class="badge badge-calm">{{identity.sigDate | formatDate}}</span> </span> - <div class="item "> - - </div> + <div class="item-divider"></div> <div class="item item-button-right positive" ng-click="transfer()"> Send money -- GitLab