From 77630dcf5c8c7d47e7d1b3c0d21fe6fe504f905b Mon Sep 17 00:00:00 2001 From: Igor Zhukov Date: Fri, 29 Dec 2017 21:11:09 +0400 Subject: [PATCH] Supported pinned messages Closes #1088 --- app/js/controllers.js | 10 +- app/js/directives.js | 64 ++++++++- app/js/directives_mobile.js | 8 +- app/js/lib/utils.js | 3 +- app/js/messages_manager.js | 2 +- app/js/services.js | 129 +++++++++++------- app/less/app.less | 36 +++++ app/partials/desktop/channel_modal.html | 4 +- app/partials/desktop/im.html | 3 +- .../desktop/peer_pinned_message_bar.html | 4 + app/partials/mobile/channel_modal.html | 4 +- app/partials/mobile/im.html | 8 +- 12 files changed, 214 insertions(+), 61 deletions(-) create mode 100644 app/partials/desktop/peer_pinned_message_bar.html diff --git a/app/js/controllers.js b/app/js/controllers.js index ba5333c9..b8b81537 100644 --- a/app/js/controllers.js +++ b/app/js/controllers.js @@ -3793,8 +3793,6 @@ angular.module('myApp.controllers', ['myApp.i18n']) $scope.needMigrate = true } - NotificationsManager.savePeerSettings(-$scope.chatID, chatFull.notify_settings) - NotificationsManager.getPeerMuted(-$scope.chatID).then(function (muted) { $scope.settings.notifications = !muted @@ -3953,8 +3951,6 @@ angular.module('myApp.controllers', ['myApp.i18n']) $scope.chatFull = AppChatsManager.wrapForFull($scope.chatID, chatFull) $scope.$broadcast('ui_height') - NotificationsManager.savePeerSettings(-$scope.chatID, chatFull.notify_settings) - NotificationsManager.getPeerMuted(-$scope.chatID).then(function (muted) { $scope.settings.notifications = !muted @@ -3983,6 +3979,12 @@ angular.module('myApp.controllers', ['myApp.i18n']) } }) + AppProfileManager.getChannelParticipants($scope.chatID).then(function (participants) { + $scope.participants = AppChatsManager.wrapParticipants($scope.chatID, participants) + $scope.$broadcast('ui_height') + }) + + function onChatUpdated (updates) { ApiUpdatesManager.processUpdateMessage(updates) $rootScope.$broadcast('history_focus', {peerString: $scope.chatFull.peerString}) diff --git a/app/js/directives.js b/app/js/directives.js index f9cd9968..dc8a14f8 100755 --- a/app/js/directives.js +++ b/app/js/directives.js @@ -586,6 +586,7 @@ angular.module('myApp.directives', ['myApp.filters']) function checkMessage ($scope, element, mid, isEdit) { var message = $scope.replyMessage = AppMessagesManager.wrapSingleMessage(mid) + $scope.thumb = false $scope.isEdit = isEdit || false if (message.loading) { var stopWaiting = $scope.$on('messages_downloaded', function (e, mids) { @@ -668,6 +669,60 @@ angular.module('myApp.directives', ['myApp.filters']) } }) + .directive('myPeerPinnedMessageBar', function (AppMessagesManager, AppPeersManager, AppProfileManager) { + + return { + templateUrl: templateUrl('peer_pinned_message_bar'), + scope: {}, + link: link + } + + function updatePeerID(peerID, $scope, force) { + if (force) { + $scope.pinnedMessageID = 0 + $scope.$emit('ui_height') + } + if (!AppPeersManager.isChannel(peerID)) { + return + } + var channelID = -peerID + var jump = ++$scope.jump + AppProfileManager.getChannelPinnedMessage(channelID).then(function (pinnedMessageID) { + if (jump != $scope.jump) { + return + } + $scope.pinnedMessageID = pinnedMessageID || 0 + $scope.$emit('ui_height') + }) + } + + function link ($scope, element, attrs) { + $scope.jump = 0 + + $scope.$parent.$watch(attrs.myPeerPinnedMessageBar, function (peerID) { + $scope.peerID = peerID + updatePeerID(peerID, $scope, true) + }) + + $scope.$on('peer_pinned_message', function (e, updPeerID) { + if (updPeerID == $scope.peerID) { + updatePeerID($scope.peerID, $scope) + } + }) + $scope.$on('chat_full_update', function (e, updChatID) { + if (updChatID == -$scope.peerID) { + updatePeerID($scope.peerID, $scope) + } + }) + + $scope.hidePinned = function () { + AppProfileManager.hideChannelPinnedMessage(-$scope.peerID, $scope.pinnedMessageID) + $scope.pinnedMessageID = 0 + $scope.$emit('ui_height') + } + } + }) + .directive('myForwardedMessages', function (AppPhotosManager, AppMessagesManager, AppPeersManager, $rootScope) { return { templateUrl: templateUrl('forwarded_messages'), @@ -1213,6 +1268,7 @@ angular.module('myApp.directives', ['myApp.filters']) var scrollableWrap = $('.im_history_scrollable_wrap', element)[0] var scrollable = $('.im_history_scrollable', element)[0] var emptyWrapEl = $('.im_history_empty_wrap', element)[0] + var pinnedPanelEl = $('.im_history_pinned_panel', element)[0] var bottomPanelWrap = $('.im_bottom_panel_wrap', element)[0] var sendFormWrap = $('.im_send_form_wrap', element)[0] var headWrap = $('.tg_page_head')[0] @@ -1545,11 +1601,17 @@ angular.module('myApp.directives', ['myApp.filters']) if (!footer || !footer.offsetHeight) { footer = $('.footer_wrap')[0] } + if (!pinnedPanelEl || !pinnedPanelEl.offsetHeight) { + pinnedPanelEl = $('.im_history_pinned_panel', element)[0] + } + var footerHeight = footer ? footer.offsetHeight : 0 if (footerHeight) { footerHeight++ // Border bottom } - var historyH = $($window).height() - bottomPanelWrap.offsetHeight - (headWrap ? headWrap.offsetHeight : 48) - footerHeight + var pinnedHeight = pinnedPanelEl && pinnedPanelEl.offsetHeight || 0 + var historyH = $($window).height() - bottomPanelWrap.offsetHeight - (headWrap ? headWrap.offsetHeight : 48) - footerHeight - pinnedHeight + $(historyWrap).css({ height: historyH }) diff --git a/app/js/directives_mobile.js b/app/js/directives_mobile.js index a5d90501..f2de88fa 100644 --- a/app/js/directives_mobile.js +++ b/app/js/directives_mobile.js @@ -105,6 +105,7 @@ angular.module('myApp.directives') var bottomPanelWrap = $('.im_bottom_panel_wrap', element)[0] var sendFormWrap = $('.im_send_form_wrap', element)[0] var headWrap = $('.tg_page_head')[0] + var pinnedPanelEl = $('.im_history_pinned_panel', element)[0] var sendForm = $('.im_send_form', element)[0] var moreNotified = false var lessNotified = false @@ -306,7 +307,12 @@ angular.module('myApp.directives') if (!headWrap || !headWrap.offsetHeight) { headWrap = $('.tg_page_head')[0] } - var historyH = $($window).height() - bottomPanelWrap.offsetHeight - (headWrap ? headWrap.offsetHeight : 46) + if (!pinnedPanelEl || !pinnedPanelEl.offsetHeight) { + pinnedPanelEl = $('.im_history_pinned_panel', element)[0] + } + var pinnedHeight = pinnedPanelEl && pinnedPanelEl.offsetHeight || 0 + + var historyH = $($window).height() - bottomPanelWrap.offsetHeight - (headWrap ? headWrap.offsetHeight : 46) - pinnedHeight $(historyWrap).css({ height: historyH }) diff --git a/app/js/lib/utils.js b/app/js/lib/utils.js index 3e76b746..cbb6655d 100644 --- a/app/js/lib/utils.js +++ b/app/js/lib/utils.js @@ -393,7 +393,8 @@ function templateUrl (tplName) { channel_edit_modal: 'desktop', megagroup_edit_modal: 'desktop', inline_results: 'desktop', - composer_dropdown: 'desktop' + composer_dropdown: 'desktop', + peer_pinned_message_bar: 'desktop' } var layout = forceLayout[tplName] || (Config.Mobile ? 'mobile' : 'desktop') return 'partials/' + layout + '/' + tplName + '.html' diff --git a/app/js/messages_manager.js b/app/js/messages_manager.js index 3d8b4db2..e2a77ddb 100644 --- a/app/js/messages_manager.js +++ b/app/js/messages_manager.js @@ -2365,7 +2365,7 @@ angular.module('myApp.services') } if (message.message && message.message.length) { - message.richMessage = RichTextProcessor.wrapRichText(message.message.substr(0, 64), {noLinks: true, noLinebreaks: true}) + message.richMessage = RichTextProcessor.wrapRichText(message.message.substr(0, 128), {noLinks: true, noLinebreaks: true}) } message.dateText = dateOrTimeFilter(message.date) diff --git a/app/js/services.js b/app/js/services.js index 116bdcbc..1dfdc876 100755 --- a/app/js/services.js +++ b/app/js/services.js @@ -773,45 +773,51 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils']) var chatFull = angular.copy(fullChat) var chat = getChat(id) - console.warn(chat, chatFull) if (!chatFull.participants_count) { chatFull.participants_count = chat.participants_count } - if (chatFull.participants && chatFull.participants._ == 'chatParticipants') { - MtpApiManager.getUserID().then(function (myID) { - var isAdmin = chat.pFlags.creator || chat.pFlags.admins_enabled && chat.pFlags.admin - angular.forEach(chatFull.participants.participants, function (participant) { - participant.canLeave = myID == participant.user_id - participant.canKick = !participant.canLeave && ( - chat.pFlags.creator || - participant._ == 'chatParticipant' && (isAdmin || myID == participant.inviter_id) - ) + if (chatFull.participants && + chatFull.participants._ == 'chatParticipants') { + chatFull.participants.participants = wrapParticipants(id, chatFull.participants.participants) + } - // just for order by last seen - participant.user = AppUsersManager.getUser(participant.user_id) - }) - }) + if (chatFull.about) { + chatFull.rAbout = RichTextProcessor.wrapRichText(chatFull.about, {noLinebreaks: true}) } - if (chatFull.participants && chatFull.participants._ == 'channelParticipants') { + + chatFull.peerString = getChatString(id) + chatFull.chat = chat + + return chatFull + } + + function wrapParticipants(id, participants) { + var chat = getChat(id) + if (isChannel(id)) { var isAdmin = chat.pFlags.creator || chat.pFlags.editor || chat.pFlags.moderator - angular.forEach(chatFull.participants.participants, function (participant) { + angular.forEach(participants, function (participant) { participant.canLeave = participant._ == 'channelParticipantSelf' participant.canKick = isAdmin && participant._ == 'channelParticipant' // just for order by last seen participant.user = AppUsersManager.getUser(participant.user_id) }) - } + } else { + var myID = AppUsersManager.getSelf().id + var isAdmin = chat.pFlags.creator || chat.pFlags.admins_enabled && chat.pFlags.admin + angular.forEach(participants, function (participant) { + participant.canLeave = myID == participant.user_id + participant.canKick = !participant.canLeave && ( + chat.pFlags.creator || + participant._ == 'chatParticipant' && (isAdmin || myID == participant.inviter_id) + ) - if (chatFull.about) { - chatFull.rAbout = RichTextProcessor.wrapRichText(chatFull.about, {noLinebreaks: true}) + // just for order by last seen + participant.user = AppUsersManager.getUser(participant.user_id) + }) } - - chatFull.peerString = getChatString(id) - chatFull.chat = chat - - return chatFull + return participants } function openChat (chatID, accessHash) { @@ -862,6 +868,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils']) resolveUsername: resolveUsername, hasChat: hasChat, wrapForFull: wrapForFull, + wrapParticipants: wrapParticipants, openChat: openChat } }) @@ -1042,7 +1049,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils']) } }) - .service('AppProfileManager', function ($q, $rootScope, AppUsersManager, AppChatsManager, AppPeersManager, AppPhotosManager, NotificationsManager, MtpApiManager, ApiUpdatesManager, RichTextProcessor) { + .service('AppProfileManager', function ($q, $rootScope, AppUsersManager, AppChatsManager, AppMessagesIDsManager, AppPeersManager, AppPhotosManager, NotificationsManager, MtpApiManager, ApiUpdatesManager, RichTextProcessor, Storage) { var botInfos = {} var chatsFull = {} var chatFullPromises = {} @@ -1191,6 +1198,14 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils']) var promiseKey = [id, filter._, offset, limit].join('_') var promiseData = chatParticipantsPromises[promiseKey] + if (filter._ == 'channelParticipantsRecent') { + var chat = AppChatsManager.getChat(id) + if (chat.pFlags.kicked || + chat.pFlags.broadcast && !chat.pFlags.creator && !chat.admin_rights) { + return $q.reject() + } + } + var fetchParticipants = function (cachedParticipants) { var hash = 0 if (cachedParticipants) { @@ -1279,32 +1294,21 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils']) AppChatsManager.saveApiChats(result.chats) AppUsersManager.saveApiUsers(result.users) var fullChannel = result.full_chat - var chat = AppChatsManager.getChat(id) if (fullChannel && fullChannel.chat_photo.id) { AppPhotosManager.savePhoto(fullChannel.chat_photo) } NotificationsManager.savePeerSettings(-id, fullChannel.notify_settings) - var participantsPromise - if (fullChannel.flags & 8) { - participantsPromise = getChannelParticipants(id).then(function (participants) { - delete chatFullPromises[id] - fullChannel.participants = { - _: 'channelParticipants', - participants: participants - } - }, function (error) { - error.handled = true - }) - } else { - participantsPromise = $q.when() + + if (fullChannel.pinned_msg_id) { + fullChannel.pinned_msg_id = AppMessagesIDsManager.getFullMessageID(fullChannel.pinned_msg_id, id) } - return participantsPromise.then(function () { - delete chatFullPromises[id] - chatsFull[id] = fullChannel - $rootScope.$broadcast('chat_full_update', id) - return fullChannel - }) + delete chatFullPromises[id] + chatsFull[id] = fullChannel + $rootScope.$broadcast('chat_full_update', id) + + return fullChannel + }, function (error) { switch (error.type) { case 'CHANNEL_PRIVATE': @@ -1325,6 +1329,28 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils']) }) } + function getChannelPinnedMessage(id) { + return getChannelFull(id).then(function (fullChannel) { + var pinnedMessageID = fullChannel && fullChannel.pinned_msg_id + if (!pinnedMessageID) { + return false + } + return Storage.get('pinned_hidden' + id).then(function (hiddenMessageID) { + if (AppMessagesIDsManager.getMessageLocalID(pinnedMessageID) == hiddenMessageID) { + return false + } + return pinnedMessageID + }) + }) + } + + function hideChannelPinnedMessage(id, pinnedMessageID) { + var setKeys = {} + setKeys['pinned_hidden' + id] = AppMessagesIDsManager.getMessageLocalID(pinnedMessageID) + Storage.set(setKeys) + $rootScope.$broadcast('peer_pinned_message', -id) + } + $rootScope.$on('apiUpdate', function (e, update) { // console.log('on apiUpdate', update) switch (update._) { @@ -1372,6 +1398,15 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils']) } break + case 'updateChannelPinnedMessage': + var channelID = update.channel_id + var fullChannel = chatsFull[channelID] + if (fullChannel !== undefined) { + fullChannel.pinned_msg_id = AppMessagesIDsManager.getFullMessageID(update.id, channelID) + $rootScope.$broadcast('peer_pinned_message', -channelID) + } + break + } }) @@ -1404,7 +1439,9 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils']) getChatInviteLink: getChatInviteLink, getChatFull: getChatFull, getChannelFull: getChannelFull, - getChannelParticipants: getChannelParticipants + getChannelParticipants: getChannelParticipants, + getChannelPinnedMessage: getChannelPinnedMessage, + hideChannelPinnedMessage: hideChannelPinnedMessage } }) diff --git a/app/less/app.less b/app/less/app.less index 76f7961f..a86ae35f 100644 --- a/app/less/app.less +++ b/app/less/app.less @@ -1499,6 +1499,42 @@ a.im_dialog_selected { } } +.im_history_pinned_wrap { + padding: 7px 10px 7px 20px; + border-bottom: 1px solid #E9EBED; +} +.im_history_pinned_message { + cursor: pointer; +} +.im_history_pinned_message:hover { + text-decoration: none; +} +.im_history_pinned_hide { + float: right; + display: block; + width: 18px; + height: 18px; + margin-right: 6px; + margin-top: 11px; + -webkit-transform: translate3d(0, 0, 0); + padding-top: 7px; + + .icon-reply-bar { + display: block; + background: #999; + width: 18px; + height: 2px; + transform-origin: 50% 50%; + } + + &:hover { + .icon-reply-bar { + background: #44a1e8; + } + } +} + + .im_history { // padding: 20px 0 0 0; padding: 0; diff --git a/app/partials/desktop/channel_modal.html b/app/partials/desktop/channel_modal.html index 2ae2fe04..ca303936 100644 --- a/app/partials/desktop/channel_modal.html +++ b/app/partials/desktop/channel_modal.html @@ -126,7 +126,7 @@ -
+
@@ -135,7 +135,7 @@
-
+
diff --git a/app/partials/desktop/im.html b/app/partials/desktop/im.html index 803e4116..33f1034f 100644 --- a/app/partials/desktop/im.html +++ b/app/partials/desktop/im.html @@ -92,8 +92,6 @@ -
@@ -130,6 +128,7 @@
+
diff --git a/app/partials/desktop/peer_pinned_message_bar.html b/app/partials/desktop/peer_pinned_message_bar.html new file mode 100644 index 00000000..b7fbeb31 --- /dev/null +++ b/app/partials/desktop/peer_pinned_message_bar.html @@ -0,0 +1,4 @@ +
+ + +
\ No newline at end of file diff --git a/app/partials/mobile/channel_modal.html b/app/partials/mobile/channel_modal.html index 3eb82ff7..65b1c948 100644 --- a/app/partials/mobile/channel_modal.html +++ b/app/partials/mobile/channel_modal.html @@ -132,13 +132,13 @@
-
+

-
+
diff --git a/app/partials/mobile/im.html b/app/partials/mobile/im.html index 6d1997f8..8258d152 100644 --- a/app/partials/mobile/im.html +++ b/app/partials/mobile/im.html @@ -58,7 +58,11 @@
- + + + + +
@@ -84,6 +88,8 @@
+ +