angular.module('cesium.es.message.controllers', ['cesium.es.services']) .config(function($stateProvider) { 'ngInject'; $stateProvider .state('app.user_message', { url: "/user/message?type", views: { 'menuContent': { templateUrl: "plugins/es/templates/message/list.html", controller: 'ESMessageListCtrl' } }, data: { auth: true, minData: true } }) .state('app.user_new_message', { cache: false, url: "/user/message/new?pubkey&uid&title&content", views: { 'menuContent': { templateUrl: "plugins/es/templates/message/compose.html", controller: 'ESMessageComposeCtrl' } } }) .state('app.user_view_message', { cache: false, url: "/user/message/view/:type/:id", views: { 'menuContent': { templateUrl: "plugins/es/templates/message/view_message.html", controller: 'ESMessageViewCtrl' } }, data: { auth: true, minData: true } }) ; }) .controller('ESMessageListCtrl', ESMessageListController) .controller('ESMessageComposeCtrl', ESMessageComposeController) .controller('ESMessageComposeModalCtrl', ESMessageComposeModalController) .controller('ESMessageViewCtrl', ESMessageViewController) .controller('PopoverMessageCtrl', PopoverMessageController) ; function ESMessageListController($scope, $state, $translate, $ionicHistory, $ionicPopover, $timeout, esModals, UIUtils, esMessage) { 'ngInject'; $scope.loading = true; $scope.messages = []; $scope.$on('$ionicView.enter', function(e, state) { $scope.loadWallet({minData: true}) .then(function() { if (!$scope.entered) { $scope.entered = true; $scope.type = state.stateParams && state.stateParams.type || 'inbox'; $scope.load(); } $scope.showFab('fab-add-message-record'); }) .catch(function(err) { if ('CANCELLED' === err) { $ionicHistory.nextViewOptions({ historyRoot: true }); $state.go('app.home'); } }); }); $scope.load = function(size, offset) { var options = {}; options.from = offset || 0; options.size = size || 20; options.type = $scope.type; $scope.loading = true; return esMessage.load(options) .then(function(messages) { $scope.messages = messages; UIUtils.loading.hide(); $scope.loading = false; if (messages.length > 0) { $scope.motion.show({selector: '.view-messages .list .item'}); } }) .catch(function(err) { UIUtils.onError('MESSAGE.ERROR.LOAD_MESSAGES_FAILED')(err); $scope.messages = []; $scope.loading = false; }); }; $scope.setType = function(type) { $scope.type = type; $scope.load(); }; $scope.markAllAsRead = function() { $scope.hideActionsPopover(); if (!$scope.messages || !$scope.messages.length) return; UIUtils.alert.confirm('MESSAGE.CONFIRM.MARK_ALL_AS_READ') .then(function(confirm) { if (confirm) { esMessage.markAllAsRead() .then(function () { _.forEach($scope.messages, function(msg){ msg.read = true; }); }) .catch(UIUtils.onError('MESSAGE.ERROR.MARK_ALL_AS_READ_FAILED')); } }); }; $scope.delete = function(index) { var message = $scope.messages[index]; if (!message) return; UIUtils.alert.confirm('MESSAGE.CONFIRM.REMOVE') .then(function(confirm) { if (confirm) { esMessage.remove(message.id, $scope.type) .then(function () { $scope.messages.splice(index,1); // remove from messages array UIUtils.toast.show('MESSAGE.INFO.MESSAGE_REMOVED'); }) .catch(UIUtils.onError('MESSAGE.ERROR.REMOVE_MESSAGE_FAILED')); } }); }; $scope.deleteAll = function() { $scope.hideActionsPopover(); if (!$scope.messages || !$scope.messages.length) return; UIUtils.alert.confirm('MESSAGE.CONFIRM.REMOVE_ALL') .then(function(confirm) { if (confirm) { esMessage.removeAll($scope.type) .then(function () { $scope.messages.splice(0,$scope.messages.length); // reset array UIUtils.toast.show('MESSAGE.INFO.All_MESSAGE_REMOVED'); }) .catch(UIUtils.onError('MESSAGE.ERROR.REMOVE_All_MESSAGES_FAILED')); } }); }; /* -- Modals -- */ $scope.showNewMessageModal = function(parameters) { return $scope.loadWallet({minData: true}) .then(function() { UIUtils.loading.hide(); return esModals.showMessageCompose(parameters) .then(function(id) { if (id) UIUtils.toast.show('MESSAGE.INFO.MESSAGE_SENT'); }); }); }; $scope.showReplyModal = function(index) { var message = $scope.messages[index]; if (!message) return; $translate('MESSAGE.REPLY_TITLE_PREFIX') .then(function (prefix) { var content = message.content ? message.content.replace(/^/g, ' > ') : null; content = content ? content.replace(/\n/g, '\n > ') : null; content = content ? content +'\n' : null; return esModals.showMessageCompose({ destPub: message.issuer, destUid: message.name||message.uid, title: prefix + message.title, content: content, isReply: true }); }) .then(function(sent) { if (sent) UIUtils.toast.show('MESSAGE.INFO.MESSAGE_SENT'); }); }; /* -- Popover -- */ $scope.showActionsPopover = function(event) { if (!$scope.actionsPopover) { $ionicPopover.fromTemplateUrl('plugins/es/templates/message/lookup_popover_actions.html', { scope: $scope }).then(function(popover) { $scope.actionsPopover = popover; //Cleanup the popover when we're done with it! $scope.$on('$destroy', function() { $scope.actionsPopover.remove(); }); $scope.actionsPopover.show(event); }); } else { $scope.actionsPopover.show(event); } }; $scope.hideActionsPopover = function() { if ($scope.actionsPopover) { $scope.actionsPopover.hide(); } }; /* -- watch events (delete, received, sent) -- */ // Message deletion $scope.onMessageDelete = function(id) { var index = _.findIndex($scope.messages, function(msg) { return msg.id == id; }); if (index) { $scope.messages.splice(index,1); // remove from messages array } }; esMessage.api.data.on.delete($scope, $scope.onMessageDelete); // Watch user sent message $scope.onNewOutboxMessage = function(id) { if ($scope.type != 'outbox') return; // Add message sent to list $scope.loading = true; return $timeout(function() { // Load the message sent return esMessage.get(id, {type: $scope.type, summary: true}); }, 500 /*waiting ES propagation*/) .then(function(msg) { $scope.messages.splice(0,0,msg); $scope.loading = false; $scope.motion.show({selector: '.view-messages .list .item'}); }) .catch(function() { $scope.loading = false; }); }; esMessage.api.data.on.sent($scope, $scope.onNewOutboxMessage); // Watch received message $scope.onNewInboxMessage = function(notification) { if ($scope.type != 'inbox') return; // Add message sent to list $scope.loading = true; console.log(notification); // Load the the message return esMessage.get(notification.id, {type: $scope.type, summary: true}) .then(function(msg) { $scope.messages.splice(0,0,msg); $scope.loading = false; $scope.motion.show({selector: '.view-messages .list .item'}); }) .catch(function() { $scope.loading = false; }); }; esMessage.api.data.on.new($scope, $scope.onNewInboxMessage); // for DEV only /*$timeout(function() { $scope.showNewMessageModal(); }, 900); */ } function ESMessageComposeController($scope, $controller, UIUtils) { 'ngInject'; // Initialize the super class and extend it. angular.extend(this, $controller('ESMessageComposeModalCtrl', {$scope: $scope, parameters: {}})); $scope.$on('$ionicView.enter', function(e, state) { if (state.stateParams) { if (state.stateParams.pubkey) { $scope.formData.destPub = state.stateParams.pubkey; if (state.stateParams.uid) { $scope.destUid = state.stateParams.uid; $scope.destPub = ''; } else { $scope.destUid = ''; $scope.destPub = $scope.formData.destPub; } } if (state.stateParams.title) { $scope.formData.title = state.stateParams.title; } if (state.stateParams.content) { $scope.formData.content = state.stateParams.content; } } $scope.loadWallet({minData: true}) .then(function() { UIUtils.loading.hide(); }) .catch(function(err){ if (err === 'CANCELLED') { $scope.showHome(); } }); }); $scope.cancel = function() { $scope.showHome(); }; $scope.setForm = function(form) { $scope.form = form; }; $scope.closeModal = function() { $scope.showHome(); }; } function ESMessageComposeModalController($scope, Modals, UIUtils, csWallet, esHttp, esMessage, parameters) { 'ngInject'; $scope.formData = { title: parameters ? parameters.title : null, content: parameters ? parameters.content : null, destPub: parameters ? parameters.destPub : null }; $scope.destUid = parameters ? parameters.destUid : null; $scope.destPub = (parameters && !parameters.destUid) ? parameters.destPub : null; $scope.isResponse = parameters ? parameters.isResponse : false; $scope.doSend = function(forceNoContent) { $scope.form.$submitted=true; if(!$scope.form.$valid /*|| !$scope.formData.destPub*/) { return; } // Ask user confirmation if no content if (!forceNoContent && (!$scope.formData.content || !$scope.formData.content.trim().length)) { return UIUtils.alert.confirm('MESSAGE.COMPOSE.CONTENT_CONFIRMATION') .then(function(confirm) { if (confirm) { $scope.doSend(true); } }); } UIUtils.loading.show(); var data = { issuer: csWallet.data.pubkey, recipient: $scope.formData.destPub, title: $scope.formData.title, content: $scope.formData.content, time: esHttp.date.now() }; esMessage.send(data, csWallet.data.keypair) .then(function(id) { $scope.id=id; UIUtils.loading.hide(); $scope.closeModal(id); }) .catch(UIUtils.onError('MESSAGE.ERROR.SEND_MSG_FAILED')); }; /* -- Modals -- */ $scope.showWotLookupModal = function() { Modals.showWotLookup() .then(function(result){ if (result) { if (result.uid) { $scope.destUid = result.uid; $scope.destPub = ''; } else { $scope.destUid = ''; $scope.destPub = result.pubkey; } $scope.formData.destPub = result.pubkey; // TODO focus on title field //$focus(''); } }); }; $scope.cancel = function() { $scope.closeModal(); }; // TODO : for DEV only /*$timeout(function() { $scope.formData.destPub = 'G2CBgZBPLe6FSFUgpx2Jf1Aqsgta6iib3vmDRA1yLiqU'; $scope.formData.title = 'test'; $scope.formData.content = 'test'; $scope.destPub = $scope.formData.destPub; $timeout(function() { //$scope.doSend(); }, 800); }, 100); */ } function ESMessageViewController($scope, $state, $timeout, $translate, $ionicHistory, UIUtils, esModals, esMessage) { 'ngInject'; $scope.formData = {}; $scope.id = null; $scope.loading = true; $scope.$on('$ionicView.enter', function (e, state) { if (state.stateParams && state.stateParams.id) { // Load by id if ($scope.loading) { // prevent reload if same id $scope.type = state.stateParams.type || 'inbox'; $scope.load(state.stateParams.id, $scope.type) .then(function(message) { $scope.loading = false; UIUtils.loading.hide(); if (!message) return; $scope.id = message.id; $scope.formData = message; $scope.canDelete = true; $scope.motion.show({selector: '.view-message .list .item'}); // Mark as read if (!message.read) { $timeout(function() { // Message has NOT changed if ($scope.id === message.id) { esMessage.markAsRead(message, $scope.type) .then(function() { console.debug("[message] marked as read"); }) .catch(UIUtils.onError('MESSAGE.ERROR.MARK_AS_READ_FAILED')); } }, 2000); // 2s } }); } $scope.showFab('fab-view-message-reply'); } else { $state.go('app.user_message'); } }); $scope.load = function(id, type) { type = type || 'inbox'; return $scope.loadWallet({minData: true}) .then(function() { return esMessage.get(id, {type: type}); }) .catch(UIUtils.onError('MESSAGE.ERROR.LOAD_MESSAGE_FAILED')) .then(function(message) { if (!message.valid) { return UIUtils.alert.error(!$scope.isUserPubkey(message.recipient) ? 'MESSAGE.ERROR.USER_NOT_RECIPIENT' : 'MESSAGE.ERROR.NOT_AUTHENTICATED_MESSAGE', 'MESSAGE.ERROR.MESSAGE_NOT_READABLE') .then(function () { $state.go('app.user_message', {type: type}); }); } return message; }); }; $scope.delete = function() { if ($scope.actionsPopover) { $scope.actionsPopover.hide(); } UIUtils.alert.confirm('MESSAGE.CONFIRM.REMOVE') .then(function(confirm) { if (confirm) { esMessage.remove($scope.id, $scope.type) .then(function () { $ionicHistory.nextViewOptions({ historyRoot: true }); $state.go('app.user_message', {type: $scope.type}); UIUtils.toast.show('MESSAGE.INFO.MESSAGE_REMOVED'); }) .catch(UIUtils.onError('MESSAGE.ERROR.REMOVE_MESSAGE_FAILED')); } }); }; /* -- Modals -- */ $scope.showReplyModal = function() { var recipientField = ($scope.type == 'inbox') ? 'issuer' : 'recipient'; $translate('MESSAGE.REPLY_TITLE_PREFIX') .then(function (prefix) { var content = $scope.formData.content ? $scope.formData.content.replace(/^/g, ' > ') : null; content = content ? content.replace(/\n/g, '\n > ') : null; content = content ? content +'\n' : null; return esModals.showMessageCompose({ destPub: $scope.formData[recipientField], destUid: $scope.formData.name||$scope.formData.uid, title: prefix + $scope.formData.title, content: content, isReply: true }); }) .then(function(sent) { if (sent) { UIUtils.toast.show('MESSAGE.INFO.MESSAGE_SENT') .then(function() { $ionicHistory.goBack(); }); } }) ; }; } function PopoverMessageController($scope, UIUtils, $state, csWallet, esHttp, esMessage, esModals) { 'ngInject'; var defaultSearchLimit = 40; $scope.search = { loading : true, results: null, hasMore : false, loadingMore : false, limit: defaultSearchLimit }; $scope.$on('popover.shown', function() { if ($scope.search.loading) { $scope.load(); } }); $scope.load = function(from, size) { var options = {}; options.from = from || 0; options.size = size || defaultSearchLimit; return esMessage.notifications.load(options) .then(function(notifications) { if (!from) { $scope.search.results = notifications; } else { $scope.search.results = $scope.search.results.concat(notifications); } $scope.search.loading = false; $scope.search.hasMore = ($scope.search.results && $scope.search.results.length >= $scope.search.limit); $scope.updateView(); }) .catch(function(err) { $scope.search.loading = false; if (!from) { $scope.search.results = []; } $scope.search.hasMore = false; UIUtils.onError('MESSAGE.ERROR.LOAD_NOTIFICATIONS_FAILED')(err); }); }; $scope.updateView = function() { if ($scope.motion && $scope.search.results && $scope.search.results.length) { $scope.motion.show({selector: '.popover-notification .item'}); } }; $scope.showMore = function() { $scope.search.limit = $scope.search.limit || defaultSearchLimit; $scope.search.limit = $scope.search.limit * 2; if ($scope.search.limit < defaultSearchLimit) { $scope.search.limit = defaultSearchLimit; } $scope.search.loadingMore = true; $scope.load( $scope.search.results.length, // from $scope.search.limit) .then(function() { $scope.search.loadingMore = false; $scope.$broadcast('scroll.infiniteScrollComplete'); }); }; // Listen notifications changes $scope.onNewMessageNotification = function(notification) { if ($scope.search.loading || $scope.search.loadingMore) return; $scope.search.results.splice(0,0,notification); $scope.updateView(); }; $scope.select = function(notification) { if (!notification.read) notification.read = true; $state.go('app.user_view_message', {id: notification.id}); $scope.closePopover(notification); }; $scope.resetData = function() { if ($scope.search.loading) return; console.debug("[ES] [messages] Resetting data (settings or account may have changed)"); $scope.search.hasMore = false; $scope.search.results = []; $scope.search.loading = true; delete $scope.search.limit; }; /* -- Modals -- */ $scope.showNewMessageModal = function(parameters) { $scope.closePopover(); return esModals.showMessageCompose(parameters) .then(function(id) { if (id) UIUtils.toast.show('MESSAGE.INFO.MESSAGE_SENT'); }); }; /* -- listeners -- */ csWallet.api.data.on.logout($scope, $scope.resetData); esHttp.api.node.on.stop($scope, $scope.resetData); esHttp.api.node.on.start($scope, $scope.load); esMessage.api.data.on.new($scope, $scope.onNewMessageNotification); }