diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 442761ae1..abfb7d9a2 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -881,6 +881,11 @@ void ApiWrap::gotChatFull(PeerData *peer, const MTPmessages_ChatFull &result, mt } chat->setUserpicPhoto(f.vchat_photo); chat->setInviteLink((f.vexported_invite.type() == mtpc_chatInviteExported) ? qs(f.vexported_invite.c_chatInviteExported().vlink) : QString()); + if (f.has_pinned_msg_id()) { + chat->setPinnedMessageId(f.vpinned_msg_id.v); + } else { + chat->clearPinnedMessage(); + } chat->fullUpdated(); notifySettingReceived(MTP_inputNotifyPeer(peer->input), f.vnotify_settings); @@ -1019,6 +1024,11 @@ void ApiWrap::gotUserFull(UserData *user, const MTPUserFull &result, mtpRequestI } else { user->setBotInfoVersion(-1); } + if (d.has_pinned_msg_id()) { + user->setPinnedMessageId(d.vpinned_msg_id.v); + } else { + user->clearPinnedMessage(); + } user->setBlockStatus(d.is_blocked() ? UserData::BlockStatus::Blocked : UserData::BlockStatus::NotBlocked); user->setCallsStatus(d.is_phone_calls_private() ? UserData::CallsStatus::Private : d.is_phone_calls_available() ? UserData::CallsStatus::Enabled : UserData::CallsStatus::Disabled); user->setAbout(d.has_about() ? qs(d.vabout) : QString()); diff --git a/Telegram/SourceFiles/boxes/confirm_box.cpp b/Telegram/SourceFiles/boxes/confirm_box.cpp index 76f745398..ff09fe94e 100644 --- a/Telegram/SourceFiles/boxes/confirm_box.cpp +++ b/Telegram/SourceFiles/boxes/confirm_box.cpp @@ -403,8 +403,11 @@ void ConvertToSupergroupBox::paintEvent(QPaintEvent *e) { _note.drawLeft(p, st::boxPadding.left(), _textHeight + st::boxPadding.bottom(), _textWidth, width()); } -PinMessageBox::PinMessageBox(QWidget*, ChannelData *channel, MsgId msgId) -: _channel(channel) +PinMessageBox::PinMessageBox( + QWidget*, + not_null peer, + MsgId msgId) +: _peer(peer) , _msgId(msgId) , _text(this, lang(lng_pinned_pin_sure), Ui::FlatLabel::InitType::Simple, st::boxLabel) { } @@ -413,7 +416,7 @@ void PinMessageBox::prepare() { addButton(langFactory(lng_pinned_pin), [this] { pinMessage(); }); addButton(langFactory(lng_cancel), [this] { closeBox(); }); - if (_channel->isMegagroup()) { + if (_peer->isChat() || _peer->isMegagroup()) { _notify.create(this, lang(lng_pinned_notify), true, st::defaultBoxCheckbox); } @@ -443,14 +446,14 @@ void PinMessageBox::keyPressEvent(QKeyEvent *e) { void PinMessageBox::pinMessage() { if (_requestId) return; - auto flags = MTPchannels_UpdatePinnedMessage::Flags(0); + auto flags = MTPmessages_UpdatePinnedMessage::Flags(0); if (_notify && !_notify->checked()) { - flags |= MTPchannels_UpdatePinnedMessage::Flag::f_silent; + flags |= MTPmessages_UpdatePinnedMessage::Flag::f_silent; } _requestId = MTP::send( - MTPchannels_UpdatePinnedMessage( + MTPmessages_UpdatePinnedMessage( MTP_flags(flags), - _channel->inputChannel, + _peer->input, MTP_int(_msgId)), rpcDone(&PinMessageBox::pinDone), rpcFail(&PinMessageBox::pinFail)); diff --git a/Telegram/SourceFiles/boxes/confirm_box.h b/Telegram/SourceFiles/boxes/confirm_box.h index 135072116..19ea8a935 100644 --- a/Telegram/SourceFiles/boxes/confirm_box.h +++ b/Telegram/SourceFiles/boxes/confirm_box.h @@ -142,7 +142,7 @@ private: class PinMessageBox : public BoxContent, public RPCSender { public: - PinMessageBox(QWidget*, ChannelData *channel, MsgId msgId); + PinMessageBox(QWidget*, not_null peer, MsgId msgId); protected: void prepare() override; @@ -155,7 +155,7 @@ private: void pinDone(const MTPUpdates &updates); bool pinFail(const RPCError &error); - ChannelData *_channel; + not_null _peer; MsgId _msgId; object_ptr _text; diff --git a/Telegram/SourceFiles/data/data_peer.cpp b/Telegram/SourceFiles/data/data_peer.cpp index fda4e5c11..e8cc52d20 100644 --- a/Telegram/SourceFiles/data/data_peer.cpp +++ b/Telegram/SourceFiles/data/data_peer.cpp @@ -330,6 +330,39 @@ void PeerData::setUserpicChecked( } } +bool PeerData::canPinMessages() const { + if (const auto user = asUser()) { + return user->isSelf(); + } else if (const auto chat = asChat()) { + return chat->adminsEnabled() ? chat->amAdmin() : chat->amIn(); + } else if (const auto channel = asChannel()) { + using AdminRight = ChannelData::AdminRight; + if (channel->isMegagroup()) { + return (channel->adminRights() & AdminRight::f_pin_messages) + || channel->amCreator(); + } + return (channel->adminRights() & AdminRight::f_edit_messages) + || channel->amCreator(); + } + Unexpected("Peer type in PeerData::canPinMessages."); +} + +void PeerData::setPinnedMessageId(MsgId messageId) { + const auto min = [&] { + if (const auto channel = asChannel()) { + return channel->availableMinId(); + } + return MsgId(0); + }(); + messageId = (messageId > min) ? messageId : MsgId(0); + if (_pinnedMessageId != messageId) { + _pinnedMessageId = messageId; + Notify::peerUpdatedDelayed( + this, + Notify::PeerUpdate::Flag::PinnedMessageChanged); + } +} + void PeerData::fillNames() { _nameWords.clear(); _nameFirstLetters.clear(); @@ -872,25 +905,12 @@ void ChannelData::setAvailableMinId(MsgId availableMinId) { if (auto history = App::historyLoaded(this)) { history->clearUpTill(availableMinId); } - if (_pinnedMessageId <= _availableMinId) { - _pinnedMessageId = MsgId(0); - Notify::peerUpdatedDelayed( - this, - Notify::PeerUpdate::Flag::ChannelPinnedChanged); + if (pinnedMessageId() <= _availableMinId) { + clearPinnedMessage(); } } } -void ChannelData::setPinnedMessageId(MsgId messageId) { - messageId = (messageId > _availableMinId) ? messageId : MsgId(0); - if (_pinnedMessageId != messageId) { - _pinnedMessageId = messageId; - Notify::peerUpdatedDelayed( - this, - Notify::PeerUpdate::Flag::ChannelPinnedChanged); - } -} - void ChannelData::setFeed(not_null feed) { setFeedPointer(feed); } @@ -948,15 +968,6 @@ bool ChannelData::canAddAdmins() const { || amCreator(); } -bool ChannelData::canPinMessages() const { - if (isMegagroup()) { - return (adminRights() & AdminRight::f_pin_messages) - || amCreator(); - } - return (adminRights() & AdminRight::f_edit_messages) - || amCreator(); -} - bool ChannelData::canPublish() const { return (adminRights() & AdminRight::f_post_messages) || amCreator(); diff --git a/Telegram/SourceFiles/data/data_peer.h b/Telegram/SourceFiles/data/data_peer.h index 306bf089d..c44a5cd7c 100644 --- a/Telegram/SourceFiles/data/data_peer.h +++ b/Telegram/SourceFiles/data/data_peer.h @@ -210,6 +210,15 @@ public: ImagePtr currentUserpic() const; + bool canPinMessages() const; + MsgId pinnedMessageId() const { + return _pinnedMessageId; + } + void setPinnedMessageId(MsgId messageId); + void clearPinnedMessage() { + setPinnedMessageId(0); + } + protected: void updateNameDelayed( const QString &newName, @@ -242,6 +251,7 @@ private: base::flat_set _nameFirstLetters; TimeMs _lastFullUpdate = 0; + MsgId _pinnedMessageId = 0; }; @@ -918,7 +928,6 @@ public: bool hiddenPreHistory() const; bool canAddMembers() const; bool canAddAdmins() const; - bool canPinMessages() const; bool canPublish() const; bool canWrite() const; bool canViewMembers() const; @@ -999,14 +1008,6 @@ public: } void setAvailableMinId(MsgId availableMinId); - MsgId pinnedMessageId() const { - return _pinnedMessageId; - } - void setPinnedMessageId(MsgId messageId); - void clearPinnedMessage() { - setPinnedMessageId(0); - } - void setFeed(not_null feed); void clearFeed(); @@ -1031,7 +1032,6 @@ private: int _restrictedCount = 0; int _kickedCount = 0; MsgId _availableMinId = 0; - MsgId _pinnedMessageId = 0; AdminRightFlags _adminRights; RestrictionFlags _restrictions; diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index 7bb3d2c97..ce0f705cd 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -121,12 +121,12 @@ DialogsInner::DialogsInner(QWidget *parent, not_null contro }); using UpdateFlag = Notify::PeerUpdate::Flag; - auto changes = UpdateFlag::PinnedChanged + auto changes = UpdateFlag::ChatPinnedChanged | UpdateFlag::NameChanged | UpdateFlag::PhotoChanged | UpdateFlag::UserIsContact; subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(changes, [this](const Notify::PeerUpdate &update) { - if (update.flags & UpdateFlag::PinnedChanged) { + if (update.flags & UpdateFlag::ChatPinnedChanged) { stopReorderPinned(); } if (update.flags & UpdateFlag::NameChanged) { diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp index 5a5af1990..ce64c3e94 100644 --- a/Telegram/SourceFiles/history/history.cpp +++ b/Telegram/SourceFiles/history/history.cpp @@ -323,10 +323,8 @@ void History::itemVanished(not_null item) { && unreadCount() > 0) { changeUnreadCount(-1); } - if (const auto channel = peer->asChannel()) { - if (channel->pinnedMessageId() == item->id) { - channel->clearPinnedMessage(); - } + if (peer->pinnedMessageId() == item->id) { + peer->clearPinnedMessage(); } } @@ -1216,9 +1214,7 @@ void History::applyServiceChanges( case mtpc_messageActionPinMessage: { if (data.has_reply_to_msg_id() && item) { - if (auto channel = item->history()->peer->asChannel()) { - channel->setPinnedMessageId(data.vreply_to_msg_id.v); - } + item->history()->peer->setPinnedMessageId(data.vreply_to_msg_id.v); } } break; @@ -2764,7 +2760,7 @@ void History::changedInChatListHook(Dialogs::Mode list, bool added) { void History::changedChatListPinHook() { Notify::peerUpdatedDelayed( peer, - Notify::PeerUpdate::Flag::PinnedChanged); + Notify::PeerUpdate::Flag::ChatPinnedChanged); } void History::removeBlock(not_null block) { diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index 7bd419431..f74cd32f2 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -321,20 +321,14 @@ void HistoryItem::setRealId(MsgId newId) { } bool HistoryItem::isPinned() const { - if (auto channel = _history->peer->asChannel()) { - return (channel->pinnedMessageId() == id); - } - return false; + return (_history->peer->pinnedMessageId() == id); } bool HistoryItem::canPin() const { if (id < 0 || !toHistoryMessage()) { return false; } - if (auto channel = _history->peer->asChannel()) { - return channel->canPinMessages(); - } - return false; + return _history->peer->canPinMessages(); } bool HistoryItem::allowsForward() const { diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 142c577ee..29151a931 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -658,7 +658,7 @@ HistoryWidget::HistoryWidget( | UpdateFlag::UnreadViewChanged | UpdateFlag::MigrationChanged | UpdateFlag::RestrictionReasonChanged - | UpdateFlag::ChannelPinnedChanged + | UpdateFlag::PinnedMessageChanged | UpdateFlag::UserIsBlocked | UpdateFlag::AdminsChanged | UpdateFlag::MembersChanged @@ -695,7 +695,7 @@ HistoryWidget::HistoryWidget( return; } } - if (update.flags & UpdateFlag::ChannelPinnedChanged) { + if (update.flags & UpdateFlag::PinnedMessageChanged) { if (pinnedMsgVisibilityUpdated()) { updateHistoryGeometry(); updateControlsVisibility(); @@ -5635,13 +5635,8 @@ void HistoryWidget::updatePinnedBar(bool force) { bool HistoryWidget::pinnedMsgVisibilityUpdated() { auto result = false; - auto pinnedId = [&] { - if (auto channel = _peer ? _peer->asChannel() : nullptr) { - return channel->pinnedMessageId(); - } - return 0; - }(); - if (pinnedId && !_peer->asChannel()->canPinMessages()) { + auto pinnedId = _peer->pinnedMessageId(); + if (pinnedId && !_peer->canPinMessages()) { auto it = Global::HiddenPinnedMessages().constFind(_peer->id); if (it != Global::HiddenPinnedMessages().cend()) { if (it.value() == pinnedId) { @@ -5972,27 +5967,25 @@ void HistoryWidget::editMessage(not_null item) { void HistoryWidget::pinMessage(FullMsgId itemId) { if (const auto item = App::histItemById(itemId)) { if (item->canPin()) { - const auto channel = item->history()->peer->asChannel(); - Assert(channel != nullptr); - Ui::show(Box(channel, item->id)); + Ui::show(Box(item->history()->peer, item->id)); } } } void HistoryWidget::unpinMessage(FullMsgId itemId) { - const auto channel = _peer ? _peer->asChannel() : nullptr; - if (!channel) { + const auto peer = _peer; + if (!peer) { return; } Ui::show(Box(lang(lng_pinned_unpin_sure), lang(lng_pinned_unpin), crl::guard(this, [=] { - channel->clearPinnedMessage(); + peer->clearPinnedMessage(); Ui::hideLayer(); MTP::send( - MTPchannels_UpdatePinnedMessage( + MTPmessages_UpdatePinnedMessage( MTP_flags(0), - channel->inputChannel, + peer->input, MTP_int(0)), rpcDone(&HistoryWidget::unpinDone)); }))); @@ -6005,8 +5998,7 @@ void HistoryWidget::unpinDone(const MTPUpdates &updates) { } void HistoryWidget::onPinnedHide() { - const auto channel = _peer ? _peer->asChannel() : nullptr; - const auto pinnedId = channel ? channel->pinnedMessageId() : MsgId(0); + const auto pinnedId = _peer ? _peer->pinnedMessageId() : MsgId(0); if (!pinnedId) { if (pinnedMsgVisibilityUpdated()) { updateControlsGeometry(); @@ -6015,10 +6007,12 @@ void HistoryWidget::onPinnedHide() { return; } - if (channel->canPinMessages()) { - unpinMessage(FullMsgId(peerToChannel(channel->id), pinnedId)); + if (_peer->canPinMessages()) { + unpinMessage(FullMsgId( + _peer->isChannel() ? peerToChannel(_peer->id) : NoChannel, + pinnedId)); } else { - Global::RefHiddenPinnedMessages().insert(channel->id, pinnedId); + Global::RefHiddenPinnedMessages().insert(_peer->id, pinnedId); Local::writeUserSettings(); if (pinnedMsgVisibilityUpdated()) { updateControlsGeometry(); diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 9d96d44fd..a09708493 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -4705,13 +4705,6 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { } } break; - case mtpc_updateChannelPinnedMessage: { - auto &d = update.c_updateChannelPinnedMessage(); - if (auto channel = App::channelLoaded(d.vchannel_id.v)) { - channel->setPinnedMessageId(d.vid.v); - } - } break; - case mtpc_updateChannelTooLong: { auto &d = update.c_updateChannelTooLong(); if (auto channel = App::channelLoaded(d.vchannel_id.v)) { @@ -4735,6 +4728,28 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { } } break; + // Pinned message. + case mtpc_updateUserPinnedMessage: { + const auto &d = update.c_updateUserPinnedMessage(); + if (const auto user = App::userLoaded(d.vuser_id.v)) { + user->setPinnedMessageId(d.vid.v); + } + } break; + + case mtpc_updateChatPinnedMessage: { + const auto &d = update.c_updateChatPinnedMessage(); + if (const auto chat = App::chatLoaded(d.vchat_id.v)) { + chat->setPinnedMessageId(d.vid.v); + } + } break; + + case mtpc_updateChannelPinnedMessage: { + const auto &d = update.c_updateChannelPinnedMessage(); + if (const auto channel = App::channelLoaded(d.vchannel_id.v)) { + channel->setPinnedMessageId(d.vid.v); + } + } break; + ////// Cloud sticker sets case mtpc_updateNewStickerSet: { auto &d = update.c_updateNewStickerSet(); diff --git a/Telegram/SourceFiles/observer_peer.h b/Telegram/SourceFiles/observer_peer.h index fec57cdcc..bff96e7e9 100644 --- a/Telegram/SourceFiles/observer_peer.h +++ b/Telegram/SourceFiles/observer_peer.h @@ -35,16 +35,17 @@ struct PeerUpdate { AboutChanged = (1 << 3), NotificationsEnabled = (1 << 4), MigrationChanged = (1 << 6), - PinnedChanged = (1 << 7), + ChatPinnedChanged = (1 << 7), RestrictionReasonChanged = (1 << 8), UnreadViewChanged = (1 << 9), + PinnedMessageChanged = (1 << 10), // For chats and channels - InviteLinkChanged = (1 << 10), - MembersChanged = (1 << 11), - AdminsChanged = (1 << 12), - BannedUsersChanged = (1 << 13), - UnreadMentionsChanged = (1 << 14), + InviteLinkChanged = (1 << 11), + MembersChanged = (1 << 12), + AdminsChanged = (1 << 13), + BannedUsersChanged = (1 << 14), + UnreadMentionsChanged = (1 << 15), // For users UserCanShareContact = (1 << 16), @@ -64,8 +65,7 @@ struct PeerUpdate { ChannelAmIn = (1 << 16), ChannelRightsChanged = (1 << 17), ChannelStickersChanged = (1 << 18), - ChannelPinnedChanged = (1 << 19), - ChannelPromotedChanged = (1 << 20), + ChannelPromotedChanged = (1 << 19), }; using Flags = base::flags; friend inline constexpr auto is_flag_type(Flag) { return true; } diff --git a/Telegram/SourceFiles/window/window_peer_menu.cpp b/Telegram/SourceFiles/window/window_peer_menu.cpp index 178c8577c..9700fb6b9 100644 --- a/Telegram/SourceFiles/window/window_peer_menu.cpp +++ b/Telegram/SourceFiles/window/window_peer_menu.cpp @@ -202,7 +202,7 @@ void Filler::addPinToggle() { auto lifetime = Notify::PeerUpdateViewer( peer, - Notify::PeerUpdate::Flag::PinnedChanged + Notify::PeerUpdate::Flag::ChatPinnedChanged ) | rpl::start_with_next([peer, pinAction, pinText] { auto isPinned = App::history(peer)->isPinnedDialog(); pinAction->setText(pinText(isPinned));