-
Benoit Lavenier authoredBenoit Lavenier authored
app-controllers.js 19.27 KiB
angular.module('cesium.app.controllers', ['cesium.platform', 'cesium.services'])
.config(function($stateProvider, $urlRouterProvider) {
'ngInject';
$stateProvider
.state('app', {
url: "/app",
abstract: true,
templateUrl: "templates/menu.html",
controller: 'AppCtrl',
data: {
large: false
}
})
.state('app.home', {
url: "/home?error",
views: {
'menuContent': {
templateUrl: "templates/home/home.html",
controller: 'HomeCtrl'
}
}
})
.state('app.lock', {
cache: false,
url: "/lock",
views: {
'menuContent': {
templateUrl: "templates/common/view_passcode.html",
controller: 'PassCodeCtrl'
}
}
})
;
// if none of the above states are matched, use this as the fallback
$urlRouterProvider.otherwise('/app/home');
})
.controller('AppCtrl', AppController)
.controller('HomeCtrl', HomeController)
.controller('PluginExtensionPointCtrl', PluginExtensionPointController)
;
/**
* Useful controller that could be reuse in plugin, using $scope.extensionPoint for condition rendered in templates
*/
function PluginExtensionPointController($scope, PluginService) {
'ngInject';
$scope.extensionPoint = PluginService.extensions.points.current.get();
}
/**
* Abstract controller (inherited by other controllers)
*/
function AppController($scope, $rootScope, $state, $ionicSideMenuDelegate, $q, $timeout,
$ionicHistory, $controller, $window, csPlatform, csSettings, CryptoUtils, csCrypto,
UIUtils, BMA, csWallet, Device, Modals, csConfig, csHttp
) {
'ngInject';
$scope.walletData = csWallet.data;
$scope.search = {};
$scope.login = csWallet.isLogin();
$scope.auth = csWallet.isAuth();
$scope.motion = UIUtils.motion.default;
$scope.fullscreen = UIUtils.screen.fullscreen.isEnabled();
$scope.showHome = function() {
$ionicHistory.nextViewOptions({
historyRoot: true
});
return $state.go('app.home')
.then(UIUtils.loading.hide);
};
// removeIf(no-device)
////////////////////////////////////////
// Device only methods
// (code removed when NO device)
////////////////////////////////////////
$scope.scanQrCodeAndGo = function() {
if (!Device.barcode.enable) return;
// Run scan cordova plugin, on device
return Device.barcode.scan()
.then(function(data) {
if (!data) return;
// Try to parse as an URI
return BMA.uri.parse(data)
.then(function(res){
if (!res || !res.pubkey) throw {message: 'ERROR.SCAN_UNKNOWN_FORMAT'};
// If pubkey: open the identity
return $state.go('app.wot_identity', {
pubkey: res.pubkey,
node: res.host ? res.host: null}
);
})
// Not an URI: try WIF or EWIF format
.catch(function(err) {
console.debug("[app] Scan data is not an URI (get error: " + (err && err.message || err) + "). Trying to decode as a WIF or EWIF format...");
// Try to read as WIF format
return csCrypto.keyfile.parseData(data)
.then(function(keypair) {
if (!keypair || !keypair.signPk || !keypair.signSk) throw err; // rethrow the first error (e.g. Bad URI)
var pubkey = CryptoUtils.base58.encode(keypair.signPk);
console.debug("[app] Detected WIF/EWIF format. Will login to wallet {" + pubkey.substring(0, 8) + "}");
// Create a new wallet (if default wallet is already used)
var wallet = !csWallet.isLogin() ? csWallet : csWallet.children.create({store: false});
// Login using keypair
return wallet.login({
silent: true,
forceAuth: true,
minData: false,
authData: {
pubkey: pubkey,
keypair: keypair
}
})
.then(function () {
// Open transfer all wallet
$ionicHistory.nextViewOptions({
historyRoot: true
});
return $state.go('app.new_transfer', {
all: true, // transfer all sources
wallet: !wallet.isDefault() ? wallet.id : undefined
});
});
})
// Unknown format (nor URI, nor WIF/EWIF)
.catch(UIUtils.onError('ERROR.SCAN_UNKNOWN_FORMAT'));
});
})
.catch(UIUtils.onError('ERROR.SCAN_FAILED'));
};
////////////////////////////////////////
// End of device only methods
////////////////////////////////////////
// endRemoveIf(no-device)
////////////////////////////////////////
// Show Help tour
////////////////////////////////////////
$scope.createHelptipScope = function(isTour) {
if (!isTour && ($rootScope.tour || !$rootScope.settings.helptip.enable || UIUtils.screen.isSmall())) {
return; // avoid other helptip to be launched (e.g. csWallet)
}
// Create a new scope for the tour controller
var helptipScope = $scope.$new();
$controller('HelpTipCtrl', { '$scope': helptipScope});
return helptipScope;
};
$scope.startHelpTour = function(event, skipClearCache) {
if (event && event.defaultPrevented) return false; // Event stopped;
$rootScope.tour = true; // to avoid other helptip to be launched (e.g. csWallet)
// Clear cache history
if (!skipClearCache) {
$ionicHistory.clearHistory();
return $ionicHistory.clearCache()
.then(function() {
$scope.startHelpTour(null, true/*continue*/);
});
}
var helptipScope = $scope.createHelptipScope(true/*is tour*/);
return helptipScope.startHelpTour()
.then(function() {
helptipScope.$destroy();
delete $rootScope.tour;
})
.catch(function(err){
delete $rootScope.tour;
});
};
$scope.disableHelpTour = function(event) {
if (event) {
event.preventDefault();
event.stopPropagation();
}
if (csSettings.data.helptip && csSettings.data.helptip.enable) {
$rootScope.settings.helptip.enable = false;
csSettings.store();
}
};
////////////////////////////////////////
// Login & wallet
////////////////////////////////////////
$scope.isLogin = function() {
return $scope.login;
};
// Load wallet data (after login)
$scope.loadWalletData = function(options) {
console.warn("[app-controller] DEPRECATED - Please use csWallet.load() instead of $scope.loadWalletData()", new Error());
options = options || {};
var wallet = options.wallet || csWallet;
return wallet.loadData(options)
.then(function(walletData) {
// cancel login
if (!walletData) throw 'CANCELLED';
return walletData;
});
};
// Login and load wallet
$scope.loadWallet = function(options) {
console.warn("[app-controller] DEPRECATED - Please use csWallet.loginOrLoad() instead of $scope.loadWallet()", new Error());
// Make sure the platform is ready
if (!csPlatform.isStarted()) {
return csPlatform.ready().then(function(){
return $scope.loadWallet(options);
});
}
options = options || {};
var wallet = options.wallet || csWallet;
// If need auth
if (options.auth && !wallet.isAuth()) {
return wallet.auth(options)
.then(function (walletData) {
if (walletData) return walletData;
// failed to auth
throw 'CANCELLED';
});
}
// If need login
else if (!wallet.isLogin()) {
return wallet.login(options)
.then(function (walletData) {
if (walletData) return walletData;
// failed to login
throw 'CANCELLED';
});
}
// Already login or auth
else if (!wallet.isDataLoaded(options)) {
return $scope.loadWalletData(options);
}
else {
return $q.when(wallet.data);
}
};
// Login and go to a state (or wallet if not)
$scope.loginAndGo = function(state, options) {
$scope.closeProfilePopover();
options = options || {};
var wallet = options.wallet || csWallet;
delete options.wallet;
state = state || 'app.view_wallet';
if (!wallet.isLogin()) {
// Make sure to protect login modal, if HTTPS enable - fix #340
if (csConfig.httpsMode && $window.location && $window.location.protocol !== 'https:') {
var href = $window.location.href;
var hashIndex = href.indexOf('#');
var rootPath = (hashIndex != -1) ? href.substr(0, hashIndex) : href;
rootPath = 'https' + rootPath.substr(4);
href = rootPath + $state.href(state);
if (csConfig.httpsModeDebug) {
// Debug mode: just log, then continue
console.debug('[httpsMode] --- Should redirect to: ' + href);
}
else {
$window.location.href = href;
return;
}
}
return wallet.login(options)
.then(function(){
return $state.go(state, options);
})
.then(UIUtils.loading.hide);
}
else {
return $state.go(state, options);
}
};
// Logout
$scope.logout = function(options) {
options = options || {};
var wallet = options.wallet || csWallet;
if (!options.force && $scope.profilePopover) {
// Make the popover if really closed, to avoid UI refresh on popover buttons
return $scope.profilePopover.hide()
.then(function(){
options.force = true;
return $scope.logout(options);
});
}
if (options.askConfirm) {
return UIUtils.alert.confirm('CONFIRM.LOGOUT')
.then(function(confirm) {
if (confirm) {
options.askConfirm=false;
return $scope.logout(options);
}
});
}
UIUtils.loading.show();
return wallet.logout()
.then(function() {
// Close left menu if open
if ($ionicSideMenuDelegate.isOpenLeft()) {
$ionicSideMenuDelegate.toggleLeft();
}
// If default wallet: clear navigation history, then go back to home
if (wallet.isDefault()) {
$ionicHistory.clearHistory();
return $ionicHistory.clearCache()
.then(function() {
return $scope.showHome();
});
}
else {
UIUtils.loading.hide(10);
}
})
.catch(UIUtils.onError('ERROR.LOGOUT'));
};
// Do authentification
$scope.doAuth = function(options) {
var wallet = options && options.wallet || csWallet;
return wallet.auth()
.then(UIUtils.loading.hide);
};
// If connected and same pubkey
$scope.isUserPubkey = function(pubkey) {
return csWallet.isUserPubkey(pubkey);
};
// add listener on wallet event
csWallet.api.data.on.login($scope, function(data, deferred) {
$scope.login = true;
return deferred ? deferred.resolve() : $q.when();
});
csWallet.api.data.on.logout($scope, function() {
$scope.login = false;
});
csWallet.api.data.on.auth($scope, function(data, deferred) {
$scope.auth = true;
return deferred ? deferred.resolve() : $q.when();
});
csWallet.api.data.on.unauth($scope, function() {
$scope.auth = false;
});
////////////////////////////////////////
// Useful modals
////////////////////////////////////////
// Open transfer modal
$scope.showTransferModal = function(parameters) {
return Modals.showTransfer(parameters);
};
$scope.showAboutModal = function() {
return Modals.showAbout();
};
$scope.showJoinModal = function() {
$scope.closeProfilePopover();
return Modals.showJoin();
};
$scope.showSettings = function() {
$scope.closeProfilePopover();
return $state.go('app.settings');
};
$scope.showHelpModal = function(parameters) {
return Modals.showHelp(parameters);
};
////////////////////////////////////////
// Useful popovers
////////////////////////////////////////
$scope.showProfilePopover = function(event) {
return UIUtils.popover.show(event, {
templateUrl :'templates/common/popover_profile.html',
scope: $scope,
autoremove: true,
afterShow: function(popover) {
$scope.profilePopover = popover;
$timeout(function() {
UIUtils.ink({selector: '#profile-popover .ink, #profile-popover .ink-dark'});
}, 100);
}
});
};
$scope.closeProfilePopover = function() {
if ($scope.profilePopover && $scope.profilePopover.isShown()) {
$timeout(function(){$scope.profilePopover.hide();});
}
};
// Change peer info
$scope.showPeerInfoPopover = function(event) {
return UIUtils.popover.show(event, {
templateUrl: 'templates/network/popover_peer_info.html',
autoremove: true,
scope: $scope.$new(true)
});
};
////////////////////////////////////////
// Link management
////////////////////////////////////////
$scope.openLink = function($event, uri, options) {
$event.stopPropagation();
$event.preventDefault();
// Read URL like '@UID' (Used by home page, in feed's author url)
if (uri && uri.startsWith('@')) {
var uid = uri.substr(1);
if (BMA.regexp.USER_ID.test(uid)) {
$state.go('app.wot_identity_uid', {uid: uid});
return false;
}
}
options = options || {};
// If unable to open, just copy value
options.onError = function() {
return UIUtils.popover.copy($event, uri);
};
csHttp.uri.open(uri, options);
return false;
};
////////////////////////////////////////
// Layout Methods
////////////////////////////////////////
$scope.showFab = function(id, timeout) {
UIUtils.motion.toggleOn({selector: '#'+id + '.button-fab'}, timeout);
};
$scope.hideFab = function(id, timeout) {
UIUtils.motion.toggleOff({selector: '#'+id + '.button-fab'}, timeout);
};
// Could be override by subclass
$scope.doMotion = function(options) {
return $scope.motion.show(options);
};
////////////////////////////////////////
// Fullscreen mode
////////////////////////////////////////
$scope.askFullscreen = function() {
var skip = $scope.fullscreen || !UIUtils.screen.isSmall() || !Device.isWeb();
if (skip) return;
return UIUtils.alert.confirm('CONFIRM.FULLSCREEN', undefined, {
cancelText: 'COMMON.BTN_NO',
okText: 'COMMON.BTN_YES'
})
.then(function(confirm) {
if (!confirm) return;
$scope.toggleFullscreen();
});
};
$scope.toggleFullscreen = function() {
$scope.fullscreen = !UIUtils.screen.fullscreen.isEnabled();
UIUtils.screen.fullscreen.toggleAll();
};
// removeIf(device)
// Ask switching fullscreen
$scope.askFullscreen();
// endRemoveIf(device)
}
function HomeController($scope, $state, $timeout, $ionicHistory, $translate, $http, UIUtils,
csConfig, csCache, csPlatform, csCurrency, csSettings) {
'ngInject';
$scope.loading = true;
$scope.locales = angular.copy(csSettings.locales);
$scope.smallscreen = UIUtils.screen.isSmall();
$scope.enter = function(e, state) {
if (ionic.Platform.isIOS()) {
if(window.StatusBar) {
// needed to fix Xcode 9 / iOS 11 issue with blank space at bottom of webview
// https://github.com/meteor/meteor/issues/9041
StatusBar.overlaysWebView(false);
StatusBar.overlaysWebView(true);
}
}
if (state && state.stateParams && state.stateParams.error) { // Error query parameter
$scope.error = state.stateParams.error;
$scope.node = csCurrency.data.node;
$scope.loading = false;
$ionicHistory.nextViewOptions({
disableAnimate: true,
disableBack: true,
historyRoot: true
});
$state.go('app.home', {error: undefined}, {
reload: false,
inherit: true,
notify: false});
}
else {
// Wait platform to be ready
csPlatform.ready()
.then(function() {
$scope.loading = false;
$scope.loadFeeds();
})
.catch(function(err) {
$scope.node = csCurrency.data.node;
$scope.loading = false;
$scope.error = err;
});
}
};
$scope.$on('$ionicView.enter', $scope.enter);
$scope.reload = function() {
$scope.loading = true;
delete $scope.error;
$timeout($scope.enter, 200);
};
$scope.loadFeeds = function() {
var feedUrl = csSettings.getFeedUrl();
if (!feedUrl || typeof feedUrl !== 'string') return; // Skip
var maxContentLength = (csConfig.feed && csConfig.feed.maxContentLength) || 650;
var now = Date.now();
console.debug("[home] Loading feeds from {0}...".format(feedUrl));
$http.get(feedUrl, {responseType: 'json', cache: csCache.get(null, csCache.constants.LONG)})
.success(function(feed) {
console.debug('[home] Feeds loaded in {0}ms'.format(Date.now()-now));
if (!feed || !feed.items || !feed.items.length) return; // skip if empty
feed.items = feed.items.reduce(function(res, item) {
if (!item || (!item.title && !item.content_text && !item.content_html)) return res; // Skip
// Convert UTC time
if (item.date_published) {
item.time = moment.utc(item.date_published).unix();
}
// Convert content to HTML
if (item.content_html) {
item.content = item.content_html;
}
else {
item.content = (item.content_text||'').replace(/\n/g, '<br/>');
}
// Trunc content, if need
if (maxContentLength !== -1 && item.content && item.content.length > maxContentLength) {
var endIndex = Math.max(item.content.lastIndexOf(" ", maxContentLength), item.content.lastIndexOf("<", maxContentLength));
item.content = item.content.substr(0, endIndex) + ' (...)';
item.truncated = true;
}
// If author is missing, copy the main author
item.author = item.author || feed.author;
return res.concat(item);
}, []);
$scope.feed = feed;
})
.error(function(data, status) {
console.error('[home] Failed to load feeds.');
$scope.feed = null;
});
};
/**
* Catch click for quick fix
* @param event
*/
$scope.doQuickFix = function(action) {
if (action === 'settings') {
$ionicHistory.nextViewOptions({
historyRoot: true
});
$state.go('app.settings');
}
};
$scope.changeLanguage = function(langKey) {
$translate.use(langKey);
$scope.hideLocalesPopover();
csSettings.data.locale = _.findWhere($scope.locales, {id: langKey});
csSettings.store();
$scope.loadFeeds();
};
/* -- show/hide locales popup -- */
$scope.showLocalesPopover = function(event) {
UIUtils.popover.show(event, {
templateUrl: 'templates/common/popover_locales.html',
scope: $scope,
autoremove: true,
afterShow: function(popover) {
$scope.localesPopover = popover;
}
});
};
$scope.hideLocalesPopover = function() {
if ($scope.localesPopover) {
$scope.localesPopover.hide();
$scope.localesPopover = null;
}
};
// For DEV ONLY
/*$timeout(function() {
$scope.loginAndGo();
}, 500);*/
}