From 629d49b44596cb9358d52e06f20e2b37410e636f Mon Sep 17 00:00:00 2001 From: Igor Zhukov Date: Sat, 1 Mar 2014 17:54:53 +0100 Subject: [PATCH] Added dialogs modal, added connection status bar, added forward button, invite users to chat, kick users from chat --- app/css/app.css | 151 ++++++++++++++++-- app/js/controllers.js | 230 ++++++++++++++++++++++++++-- app/js/directives.js | 47 +++++- app/js/lib/mtproto.js | 23 ++- app/js/services.js | 100 ++++++++++-- app/partials/chat_create_modal.html | 30 ++++ app/partials/chat_modal.html | 7 +- app/partials/contacts_modal.html | 53 +++++-- app/partials/dialog.html | 2 +- app/partials/head.html | 11 +- app/partials/im.html | 1 + app/partials/peer_select.html | 28 ++++ 12 files changed, 617 insertions(+), 66 deletions(-) create mode 100644 app/partials/chat_create_modal.html create mode 100644 app/partials/peer_select.html diff --git a/app/css/app.css b/app/css/app.css index 48c621b8..d61e2d77 100644 --- a/app/css/app.css +++ b/app/css/app.css @@ -109,6 +109,7 @@ fieldset[disabled] .btn-tg:active, .btn-tg.disabled.active, .btn-tg[disabled].active, fieldset[disabled] .btn-tg.active { + color: #DDD; background-color: #999; border-color: #999; } @@ -145,6 +146,19 @@ fieldset[disabled] .btn-tg.active { line-height: 0; height: auto; } +.navbar-offline { + max-width: 250px; + margin: 0 auto; + float: none; +} +.navbar-offline-text { + padding: 12px 15px; + /*color: #FFF;*/ + color: #b9cfe3; + font-size: 13px; + display: block; + line-height: 20px; +} .tg_head_logo { @@ -438,7 +452,6 @@ fieldset[disabled] .btn-tg.active { /* Dialogs list */ .im_dialogs_col { - /*min-width: 315px;*/ margin-right: -7px; } .im_dialogs_col .nano > .pane { @@ -588,6 +601,9 @@ a.im_dialog:hover .im_dialog_message_text { color: #428bca; background-color: #fff; } +.im_dialogs_modal_col .im_dialog_badge { + display: none; +} .im_dialog_unread { background: #c1d6e5; @@ -649,11 +665,13 @@ a.im_dialog:hover .im_dialog_date { .im_history_col { } -.im_history_col .nano > .pane { +.im_history_col .nano > .pane, +.contacts_modal_col .nano > .pane, +.im_dialogs_modal_col .nano > .pane { background : rgba(3,36,64,0.08); width : 9px; - top: 10px; - right: 8px; + right: 0; + top: 0; -webkit-transition : .2s; -moz-transition : .2s; -o-transition : .2s; @@ -662,7 +680,14 @@ a.im_dialog:hover .im_dialog_date { -webkit-border-radius : 2px; border-radius : 2px; } -.im_history_col .nano > .pane > .slider { + +.im_history_col .nano > .pane { + top: 10px; + right: 8px; +} +.im_history_col .nano > .pane > .slider, +.contacts_modal_col .nano > .pane > .slider, +.im_dialogs_modal_col .nano > .pane > .slider { background : rgba(3,46,79,0.22); margin: 0; -moz-border-radius : 2px; @@ -1103,7 +1128,8 @@ div.im_message_video_thumb { .im_content_message_wrap { - margin: 10px 0px 5px 16px; + /*margin: 10px 0px 5px 16px;*/ + margin: 8px 0px 8px 16px } .icon-message-status { background: #43A4DB; @@ -1150,6 +1176,7 @@ div.im_message_video_thumb { .im_message_date { color: #adadad; font-size: 0.85em; + padding-bottom: 20px; } div.im_message_author, div.im_message_body { @@ -1498,6 +1525,10 @@ img.img_fullsize { padding: 8px 7px; border-top: 1px solid #F0F0F0; } +.chat_modal_participant_kick { + padding: 11px 0; + display: block; +} .chat_modal_participant_name { display: block; color: #3C6E97; @@ -1777,13 +1808,38 @@ img.img_fullsize { opacity: 1; } -.contacts_modal_contact_wrap { - padding: 8px 7px; - border-top: 1px solid #F0F0F0; +.contacts_modal_col { + margin-right: -17px; +} +.contacts_scrollable_wrap { + padding: 0 17px 0 0; + outline: none ! important; +} + + +.contacts_modal_members_list .contacts_modal_contact_wrap { + /*margin-top: 0;*/ +} +.contacts_modal_members_list a.contacts_modal_contact { + clear: both; + overflow: hidden; + color: #000; + padding: 8px 9px; + border-radius: 0; +} +.contacts_modal_members_list a.contacts_modal_contact:hover { + border-radius: 2px; + background: #f2f6fa; } -.contacts_modal_contact_wrap:first-child { - border-top: 0; +.contacts_modal_members_list .active a.contacts_modal_contact { + border-radius: 2px; + background-color: #6490b1; } +.contacts_modal_members_list .active a.contacts_modal_contact:hover { + background-color: #6490b1; +} + + .contacts_modal_contact_name { display: block; color: #3C6E97; @@ -1793,9 +1849,6 @@ img.img_fullsize { .non_osx .contacts_modal_contact_name { font-size: 12px; } -.contacts_modal_contact_status { - color: #999; -} .contacts_modal_contact_photo { width: 40px; height: 40px; @@ -1803,6 +1856,50 @@ img.img_fullsize { overflow: hidden; } +.contacts_modal_contact_status { + color: #999; +} +a.contacts_modal_contact:hover .contacts_modal_contact_status { + color: #91a6ba; +} + +.contacts_modal_members_list .active .contacts_modal_contact_name, +.contacts_modal_members_list .active a.contacts_modal_contact .contacts_modal_contact_status { + color: #FFF; +} + +.icon-contact-tick { + position: absolute; + right: 10px; + top: 22px; + width: 17px; + height: 15px; + /*margin: 10px 0 0 -75px;*/ + background: url(../img/icons/IconsetW.png?1) -13px -343px no-repeat; + background-size: 42px 460px; +} +.is_1x .icon-contact-tick { + background-image: url(../img/icons/IconsetW_1x.png?2); +} + +.contacts_modal_members_list .active .icon-contact-tick, +.contacts_modal_members_list a.contacts_modal_contact:hover .icon-contact-tick { + background-position: -13px -367px; + opacity: 0.5; +} +.contacts_modal_members_list .active .icon-contact-tick { + opacity: 1 !important; +} + +.contacts_modal_panel { + padding-top: 10px; +} + +.contacts_modal_actions { + padding-top: 10px; +} + + /* Messages edit panel */ .im_edit_panel_wrap { @@ -1816,6 +1913,7 @@ img.img_fullsize { width: 100%; } .im_edit_delete_link, +.im_edit_forward_link, .im_edit_cancel_link { display: block; padding: 8px 17px; @@ -1823,11 +1921,13 @@ img.img_fullsize { .im_edit_cancel_link { float: left; } -.im_edit_delete_link { +.im_edit_delete_link, +.im_edit_forward_link { float: right; } .im_edit_delete_link:hover, +.im_edit_forward_link:hover, .im_edit_cancel_link:hover { background: #f2f6fa; text-decoration: none; @@ -1898,8 +1998,11 @@ img.img_fullsize { .is_1x .icon-select-tick { background-image: url(../img/icons/IconsetW_1x.png?2); } -.im_history_selectable .icon-select-tick { - display: inline-block; + +@media (min-width: 1024px) { + .im_history_selectable .icon-select-tick { + display: inline-block; + } } .im_message_selected .icon-select-tick, @@ -2067,4 +2170,18 @@ img.img_fullsize { .im_emoji_btn { display: none; } +} + + + +/* Dialogs modal */ +.peer_select_window .modal-dialog { + max-width: 506px; +} +.peer_select_modal_wrap .modal-body { + padding: 10px 10px 15px; +} + +.text-invisible { + visibility: hidden; } \ No newline at end of file diff --git a/app/js/controllers.js b/app/js/controllers.js index e8271814..397061b7 100644 --- a/app/js/controllers.js +++ b/app/js/controllers.js @@ -151,7 +151,7 @@ angular.module('myApp.controllers', []) }; }) - .controller('AppIMController', function ($scope, $location, $routeParams, $modal, $rootScope, $modalStack, MtpApiManager) { + .controller('AppIMController', function ($scope, $location, $routeParams, $modal, $rootScope, $modalStack, MtpApiManager, AppUsersManager, ContactsSelectService) { $scope.$on('$routeUpdate', updateCurDialog); @@ -176,14 +176,35 @@ angular.module('myApp.controllers', []) } $scope.openContacts = function () { - $modal.open({ - templateUrl: 'partials/contacts_modal.html?3', - controller: 'ContactsModalController', - scope: $rootScope.$new(), - windowClass: 'contacts_modal_window' + ContactsSelectService.selectContact().then(function (userID) { + $scope.dialogSelect(AppUsersManager.getUserString(userID)); }); } + $scope.openGroup = function () { + ContactsSelectService.selectContacts().then(function (userIDs) { + + if (userIDs.length == 1) { + $scope.dialogSelect(AppUsersManager.getUserString(userIDs[0])); + } else if (userIDs.length > 1) { + var scope = $rootScope.$new(); + scope.userIDs = userIDs; + + $modal.open({ + templateUrl: 'partials/chat_create_modal.html?3', + controller: 'ChatCreateModalController', + scope: scope, + windowClass: 'contacts_modal_window' + }); + } + + }); + } + + $scope.dialogSelect = function (peerString) { + $rootScope.$broadcast('history_focus', {peerString: peerString}); + }; + updateCurDialog(); function updateCurDialog() { @@ -300,11 +321,11 @@ angular.module('myApp.controllers', []) $scope.$broadcast('ui_dialogs_append'); }); - } + }; }) - .controller('AppImHistoryController', function ($scope, $location, $timeout, $rootScope, MtpApiManager, AppUsersManager, AppChatsManager, AppMessagesManager, AppPeersManager, ApiUpdatesManager, IdleManager, StatusManager) { + .controller('AppImHistoryController', function ($scope, $location, $timeout, $rootScope, MtpApiManager, AppUsersManager, AppChatsManager, AppMessagesManager, AppPeersManager, ApiUpdatesManager, PeersSelectService, IdleManager, StatusManager) { $scope.$watch('curDialog.peer', applyDialogSelect); @@ -324,6 +345,7 @@ angular.module('myApp.controllers', []) $scope.toggleMessage = toggleMessage; $scope.selectedDelete = selectedDelete; + $scope.selectedForward = selectedForward; $scope.selectedCancel = selectedCancel; $scope.toggleEdit = toggleEdit; $scope.toggleMedia = toggleMedia; @@ -391,16 +413,14 @@ angular.module('myApp.controllers', []) if (!hasMore || !offset) { return; } - // console.trace('load history'); + console.trace('load history'); var inputMediaFilter = $scope.mediaType && {_: inputMediaFilters[$scope.mediaType]}, getMessagesPromise = inputMediaFilter - ? AppMessagesManager.getSearch($scope.curDialog.inputPeer, '', inputMediaFilter, maxID, startLimit) - : AppMessagesManager.getHistory($scope.curDialog.inputPeer, maxID, startLimit); + ? AppMessagesManager.getSearch($scope.curDialog.inputPeer, '', inputMediaFilter, maxID, limit) + : AppMessagesManager.getHistory($scope.curDialog.inputPeer, maxID, limit); getMessagesPromise.then(function (historyResult) { - console.log('got', maxID, historyResult); - offset += limit; hasMore = offset < historyResult.count; maxID = historyResult.history[historyResult.history.length - 1]; @@ -497,6 +517,24 @@ angular.module('myApp.controllers', []) } } + + function selectedForward () { + if ($scope.selectedCount > 0) { + var selectedMessageIDs = []; + angular.forEach($scope.selectedMsgs, function (t, messageID) { + selectedMessageIDs.push(messageID); + }); + + PeersSelectService.selectPeer().then(function (peerString) { + var inputPeer = AppPeersManager.getInputPeer(peerString); + AppMessagesManager.forwardMessages(selectedMessageIDs, inputPeer).then(function () { + selectedCancel(); + }); + }); + + } + } + function toggleEdit () { if ($scope.selectActions) { selectedCancel(); @@ -757,7 +795,7 @@ angular.module('myApp.controllers', []) }; }) - .controller('ChatModalController', function ($scope, $timeout, $rootScope, AppUsersManager, AppChatsManager, MtpApiManager, NotificationsManager, AppMessagesManager, AppPeersManager, ApiUpdatesManager) { + .controller('ChatModalController', function ($scope, $timeout, $rootScope, AppUsersManager, AppChatsManager, MtpApiManager, NotificationsManager, AppMessagesManager, AppPeersManager, ApiUpdatesManager, ContactsSelectService) { $scope.chatFull = AppChatsManager.wrapForFull($scope.chatID, {}); @@ -826,6 +864,73 @@ angular.module('myApp.controllers', []) }; + $scope.inviteToGroup = function () { + var disabled = []; + angular.forEach($scope.chatFull.participants.participants, function(participant){ + disabled.push(participant.user_id); + }); + + ContactsSelectService.selectContacts({disabled: disabled}).then(function (userIDs) { + angular.forEach(userIDs, function () { + MtpApiManager.invokeApi('messages.addChatUser', { + chat_id: $scope.chatID, + user_id: {_: 'inputUserContact', user_id: userIDs}, + fwd_limit: 100 + }).then(function (addResult) { + AppUsersManager.saveApiUsers(addResult.users); + AppChatsManager.saveApiChats(addResult.chats); + + if (ApiUpdatesManager.saveSeq(addResult.seq)) { + ApiUpdatesManager.saveUpdate({ + _: 'updateNewMessage', + message: addResult.message, + pts: addResult.pts + }); + } + }); + }); + + $rootScope.$broadcast('history_focus', {peerString: $scope.chatFull.peerString}); + }); + + MtpApiManager.invokeApi('messages.addChatUser', { + chat_id: $scope.chatID, + user_id: {_: 'inputUserSelf'} + }).then(function (result) { + if (ApiUpdatesManager.saveSeq(result.seq)) { + ApiUpdatesManager.saveUpdate({ + _: 'updateNewMessage', + message: result.message, + pts: result.pts + }); + } + + $rootScope.$broadcast('history_focus', {peerString: $scope.chatFull.peerString}); + }); + }; + + $scope.kickFromGroup = function (userID) { + var user = AppUsersManager.getUser(userID); + + console.log({_: 'inputUserForeign', user_id: userID, access_hash: user.access_hash || '0'}, user); + + MtpApiManager.invokeApi('messages.deleteChatUser', { + chat_id: $scope.chatID, + user_id: {_: 'inputUserForeign', user_id: userID, access_hash: user.access_hash || '0'} + }).then(function (result) { + if (ApiUpdatesManager.saveSeq(result.seq)) { + ApiUpdatesManager.saveUpdate({ + _: 'updateNewMessage', + message: result.message, + pts: result.pts + }); + } + + $rootScope.$broadcast('history_focus', {peerString: $scope.chatFull.peerString}); + }); + }; + + $scope.flushHistory = function () { if (confirm('Are you sure? This can not be undone!') !== true) { @@ -931,9 +1036,29 @@ angular.module('myApp.controllers', []) } }) - .controller('ContactsModalController', function ($scope, AppUsersManager) { + .controller('ContactsModalController', function ($scope, $modalInstance, AppUsersManager) { $scope.contacts = []; - $scope.search = []; + $scope.search = {}; + + $scope.selectedContacts = {}; + $scope.disabledContacts = {}; + $scope.selectedCount = 0; + + if ($scope.disabled) { + for (var i = 0; i < $scope.disabled.length; i++) { + $scope.disabledContacts[$scope.disabled[i]] = true; + } + } + console.log($scope.disabled, $scope.disabledContacts); + + if ($scope.selected) { + for (var i = 0; i < $scope.selected.length; i++) { + if (!$scope.selectedContacts[$scope.selected[i]]) { + $scope.selectedContacts[$scope.selected[i]] = true; + $scope.selectedCount++; + } + } + } $scope.$watch('search.query', function (newValue) { AppUsersManager.getContacts(newValue).then(function (contactsList) { @@ -946,10 +1071,81 @@ angular.module('myApp.controllers', []) } $scope.contacts.push(contact); }); + $scope.$broadcast('contacts_change'); }); - }) + }); + + $scope.contactSelect = function (userID) { + if ($scope.disabledContacts[userID]) { + return false; + } + if (!$scope.multiSelect) { + return $modalInstance.close(userID); + } + if ($scope.selectedContacts[userID]) { + delete $scope.selectedContacts[userID]; + $scope.selectedCount--; + } else { + $scope.selectedContacts[userID] = true; + $scope.selectedCount++; + } + }; + + $scope.submitSelected = function () { + if ($scope.selectedCount > 0) { + var selectedUserIDs = []; + angular.forEach($scope.selectedContacts, function (t, userID) { + selectedUserIDs.push(userID); + }); + return $modalInstance.close(selectedUserIDs); + } + } }) + .controller('PeerSelectController', function ($scope, $modalInstance) { + + $scope.dialogSelect = function (peerString) { + $modalInstance.close(peerString); + }; + }) + .controller('ChatCreateModalController', function ($scope, $modalInstance, $rootScope, MtpApiManager, AppChatsManager) { + $scope.group = {name: ''}; + + $scope.createGroup = function () { + if (!$scope.group.name) { + return; + } + var inputUsers = []; + angular.forEach($scope.userIDs, function(userID) { + inputUsers.push({_: 'inputUserContact', user_id: userID}); + }); + return MtpApiManager.invokeApi('messages.createChat', { + title: $scope.group.name, + users: inputUsers + }).then(function (createdResult) { + $modalInstance.close(); + + AppUsersManager.saveApiUsers(createdResult.users); + AppChatsManager.saveApiChats(createdResult.chats); + + if (ApiUpdatesManager.saveSeq(createdResult.seq)) { + ApiUpdatesManager.saveUpdate({ + _: 'updateNewMessage', + message: createdResult.message, + pts: createdResult.pts + }); + } + + var peerString = AppChatsManager.getChatString(message.to_id.chat_id); + $rootScope.$broadcast('history_focus', {peerString: peerString}); + }); + }; + + $scope.back = function () { + $modalInstance.dismiss(); + }; + + }) diff --git a/app/js/directives.js b/app/js/directives.js index 7308be7a..27053a78 100644 --- a/app/js/directives.js +++ b/app/js/directives.js @@ -81,9 +81,18 @@ angular.module('myApp.directives', ['myApp.filters']) function updateSizes () { + if (attrs.modal) { + $(element).css({ + height: $($window).height() - 200 + }); + updateScroller(); + return; + } + $(element).css({ height: $($window).height() - footer.offsetHeight - (headWrap ? headWrap.offsetHeight : 50) - 72 }); + updateScroller(); if (!headWrap) { headWrap = $('.tg_page_head')[0]; } @@ -96,6 +105,38 @@ angular.module('myApp.directives', ['myApp.filters']) }) + .directive('myContactsList', function($window, $timeout) { + + return { + link: link + }; + + + function link (scope, element, attrs) { + var searchWrap = $('.contacts_modal_search')[0], + panelWrap = $('.contacts_modal_panel')[0], + contactsWrap = $('.contacts_wrap', element)[0]; + + onContentLoaded(function () { + $(contactsWrap).nanoScroller({preventPageScrolling: true, tabIndex: -1, iOSNativeScrolling: true}); + updateSizes(); + }); + + function updateSizes () { + $(element).css({ + height: $($window).height() - (panelWrap && panelWrap.offsetHeight || 0) - (searchWrap && searchWrap.offsetHeight || 0) - 200 + }); + $(contactsWrap).nanoScroller(); + } + + $($window).on('resize', updateSizes); + scope.$on('contacts_change', function () { + onContentLoaded(updateSizes) + }); + }; + + }) + .directive('myHistory', function ($window, $timeout) { return { @@ -711,7 +752,11 @@ angular.module('myApp.directives', ['myApp.filters']) } else if (time % 1000 <= 600) { cnt = 2; } - element.html((new Array(cnt + 1)).join('.')); + + var text = '...', + html = text.substr(0, cnt + 1) + (cnt < 2 ? ('' + text.substr(cnt + 1) + '') : ''); + + element.html(html); }, 200); scope.$on('$destroy', function cleanup() { diff --git a/app/js/lib/mtproto.js b/app/js/lib/mtproto.js index 4c91d0d1..55ab9707 100644 --- a/app/js/lib/mtproto.js +++ b/app/js/lib/mtproto.js @@ -893,12 +893,12 @@ factory('MtpDcConfigurator', function () { var dcOptions = window._testMode ? [ {id: 1, host: '173.240.5.253', port: 80}, - {id: 2, host: '95.142.192.65', port: 80}, + {id: 2, host: '109.239.131.195', port: 80}, {id: 3, host: '174.140.142.5', port: 80} ] : [ {id: 1, host: '173.240.5.1', port: 80}, - {id: 2, host: '95.142.192.66', port: 80}, + {id: 2, host: '109.239.131.193', port: 80}, {id: 3, host: '174.140.142.6', port: 80}, {id: 4, host: '31.210.235.12', port: 80}, {id: 5, host: '116.51.22.2', port: 80}, @@ -1500,11 +1500,16 @@ factory('MtpSha1Service', function ($q) { } }). -factory('MtpNetworkerFactory', function (MtpDcConfigurator, MtpMessageIdGenerator, MtpSecureRandom, MtpSha1Service, MtpAesService, AppConfigManager, $http, $q, $timeout, $interval) { +factory('MtpNetworkerFactory', function (MtpDcConfigurator, MtpMessageIdGenerator, MtpSecureRandom, MtpSha1Service, MtpAesService, AppConfigManager, $http, $q, $timeout, $interval, $rootScope) { var updatesProcessor, iii = 0, - offline = false; + offline; + + $rootScope.offline = true; + $rootScope.retryOnline = function () { + $(document.body).trigger('online'); + } function MtpNetworker(dcID, authKey, serverSalt, options) { options = options || {}; @@ -1759,6 +1764,8 @@ factory('MtpNetworkerFactory', function (MtpDcConfigurator, MtpMessageIdGenerato }; MtpNetworker.prototype.checkConnection = function(event) { + $rootScope.offlineConnecting = true; + console.log('check connection', event); $timeout.cancel(this.checkConnectionPromise); @@ -1775,21 +1782,26 @@ factory('MtpNetworkerFactory', function (MtpDcConfigurator, MtpMessageIdGenerato var self = this; this.sendEncryptedRequest(pingMessage).then(function (result) { + delete $rootScope.offlineConnecting; self.toggleOffline(false); }, function () { console.log('delay ', self.checkConnectionPeriod * 1000); self.checkConnectionPromise = $timeout(self.checkConnection.bind(self), parseInt(self.checkConnectionPeriod * 1000)); self.checkConnectionPeriod = Math.min(60, self.checkConnectionPeriod * 1.5); + $timeout(function () { + delete $rootScope.offlineConnecting; + }, 1000); }) }; MtpNetworker.prototype.toggleOffline = function(enabled) { console.log('toggle ', enabled, this.dcID, this.iii); - if (this.offline == enabled) { + if (this.offline !== undefined && this.offline == enabled) { return false; } this.offline = enabled; + $rootScope.offline = enabled; if (this.offline) { $timeout.cancel(this.nextReqPromise); @@ -1912,6 +1924,7 @@ factory('MtpNetworkerFactory', function (MtpDcConfigurator, MtpMessageIdGenerato var self = this; this.sendEncryptedRequest(message).then(function (result) { + self.toggleOffline(false); self.parseResponse(result.data).then(function (response) { if (window._debugMode) { console.log('Server response', self.dcID, response); diff --git a/app/js/services.js b/app/js/services.js index b2d1c4a2..77fc1470 100644 --- a/app/js/services.js +++ b/app/js/services.js @@ -118,7 +118,7 @@ angular.module('myApp.services', []) }; }) -.service('AppUsersManager', function ($rootScope, $modal, $modalStack, MtpApiFileManager, MtpApiManager, RichTextProcessor, SearchIndexManager) { +.service('AppUsersManager', function ($rootScope, $modal, $modalStack, $filter, MtpApiFileManager, MtpApiManager, RichTextProcessor, SearchIndexManager) { var users = {}, contactsFillPromise, contactsIndex = SearchIndexManager.createIndex(); @@ -180,12 +180,16 @@ angular.module('myApp.services', []) return; } + if (apiUser.phone) { + apiUser.rPhone = $filter('phoneNumber')(apiUser.phone); + } + if (apiUser.first_name) { apiUser.rFirstName = RichTextProcessor.wrapRichText(apiUser.first_name, {noLinks: true, noLinebreaks: true}); apiUser.rFullName = RichTextProcessor.wrapRichText(apiUser.first_name + ' ' + (apiUser.last_name || ''), {noLinks: true, noLinebreaks: true}); } else { - apiUser.rFirstName = RichTextProcessor.wrapRichText(apiUser.last_name, {noLinks: true, noLinebreaks: true}) || 'DELETED'; - apiUser.rFullName = RichTextProcessor.wrapRichText(apiUser.last_name, {noLinks: true, noLinebreaks: true}) || 'DELETED'; + apiUser.rFirstName = RichTextProcessor.wrapRichText(apiUser.last_name, {noLinks: true, noLinebreaks: true}) || apiUser.rPhone || 'DELETED'; + apiUser.rFullName = RichTextProcessor.wrapRichText(apiUser.last_name, {noLinks: true, noLinebreaks: true}) || apiUser.rPhone || 'DELETED'; } apiUser.sortName = $.trim((apiUser.last_name || '') + ' ' + apiUser.first_name); apiUser.sortStatus = apiUser.status && (apiUser.status.expires || apiUser.status.was_online) || 0; @@ -361,11 +365,15 @@ angular.module('myApp.services', []) var chatFull = angular.copy(fullChat), chat = getChat(id); + if (chatFull.participants && chatFull.participants._ == 'chatParticipants') { - angular.forEach(chatFull.participants.participants, function(participant){ - participant.user = AppUsersManager.getUser(participant.user_id); - participant.userPhoto = AppUsersManager.getUserPhoto(participant.user_id, 'User'); - participant.inviter = AppUsersManager.getUser(participant.inviter_id); + MtpApiManager.getUserID().then(function (myID) { + angular.forEach(chatFull.participants.participants, function(participant){ + participant.user = AppUsersManager.getUser(participant.user_id); + participant.userPhoto = AppUsersManager.getUserPhoto(participant.user_id, 'User'); + participant.inviter = AppUsersManager.getUser(participant.inviter_id); + participant.canKick = myID == chat.admin_id || myID == participant.inviter_id; + }); }); } @@ -1126,6 +1134,28 @@ angular.module('myApp.services', []) pendingByRandomID[randomIDS] = [peerID, messageID]; } + function forwardMessages (msgIDs, inputPeer) { + return MtpApiManager.invokeApi('messages.forwardMessages', { + peer: inputPeer, + id: msgIDs + }).then(function (forwardResult) { + AppUsersManager.saveApiUsers(forwardResult.users); + AppChatsManager.saveApiChats(forwardResult.chats); + + if (ApiUpdatesManager.saveSeq(forwardResult.seq)) { + angular.forEach(forwardResult.messages, function(apiMessage) { + + ApiUpdatesManager.saveUpdate({ + _: 'updateNewMessage', + message: apiMessage, + pts: forwardResult.pts + }); + + }); + } + + }); + }; function finalizePendingMessage(randomID, finalMessage) { var pendingData = pendingByRandomID[randomID]; @@ -1178,7 +1208,7 @@ angular.module('myApp.services', []) if (toID < 0) { return toID; } else if (message.out) { - return toID + return toID; } return message.from_id; } @@ -1533,6 +1563,7 @@ angular.module('myApp.services', []) saveMessages: saveMessages, sendText: sendText, sendFile: sendFile, + forwardMessages: forwardMessages, getMessagePeer: getMessagePeer, wrapForDialog: wrapForDialog, wrapForHistory: wrapForHistory @@ -2231,7 +2262,7 @@ angular.module('myApp.services', []) '', - encodeEntities((match[2] != 'http' ? match[2] + '://' : '') + match[4]), + encodeEntities(match[2] + '://' + match[4]), '' ); } @@ -2591,3 +2622,54 @@ angular.module('myApp.services', []) showSimpleError: showSimpleError } }) + + + +.service('PeersSelectService', function ($rootScope, $modal) { + + function selectPeer () { + var scope = $rootScope.$new(); + // angular.extend(scope, params); + + return $modal.open({ + templateUrl: 'partials/peer_select.html', + controller: 'PeerSelectController', + scope: scope, + windowClass: 'peer_select_window' + }).result; + } + + + return { + selectPeer: selectPeer + } +}) + + +.service('ContactsSelectService', function ($rootScope, $modal) { + + function select (multiSelect, options) { + options = options || {}; + + var scope = $rootScope.$new(); + scope.multiSelect = multiSelect; + angular.extend(scope, options); + + return $modal.open({ + templateUrl: 'partials/contacts_modal.html', + controller: 'ContactsModalController', + scope: scope, + windowClass: 'contacts_modal_window' + }).result; + } + + + return { + selectContacts: function (options) { + return select (true, options); + }, + selectContact: function (options) { + return select (false, options); + }, + } +}) diff --git a/app/partials/chat_create_modal.html b/app/partials/chat_create_modal.html new file mode 100644 index 00000000..b1bc3dbf --- /dev/null +++ b/app/partials/chat_create_modal.html @@ -0,0 +1,30 @@ +
+ + + + + +
\ No newline at end of file diff --git a/app/partials/chat_modal.html b/app/partials/chat_modal.html index d8faf49e..843c9833 100644 --- a/app/partials/chat_modal.html +++ b/app/partials/chat_modal.html @@ -41,14 +41,19 @@
Return to group
+ -
Members
+
+ Add participant + Members +
-
- -
- - - - -
- + +
+ +
+ -
{{contact.user | userStatus}}
+ +
+ + + +
+
\ No newline at end of file diff --git a/app/partials/dialog.html b/app/partials/dialog.html index 1ded7010..7066c83a 100644 --- a/app/partials/dialog.html +++ b/app/partials/dialog.html @@ -1,4 +1,4 @@ - + diff --git a/app/partials/im.html b/app/partials/im.html index a114a6d3..36f23b90 100644 --- a/app/partials/im.html +++ b/app/partials/im.html @@ -79,6 +79,7 @@
+ Forward Cancel

+ + + + + +

\ No newline at end of file