Extend pinned messages support.

Support them in saved messages and normal groups.
This commit is contained in:
John Preston 2018-10-31 15:29:14 +04:00
parent 6d65cf2382
commit 78da810114
12 changed files with 122 additions and 99 deletions

View File

@ -881,6 +881,11 @@ void ApiWrap::gotChatFull(PeerData *peer, const MTPmessages_ChatFull &result, mt
} }
chat->setUserpicPhoto(f.vchat_photo); chat->setUserpicPhoto(f.vchat_photo);
chat->setInviteLink((f.vexported_invite.type() == mtpc_chatInviteExported) ? qs(f.vexported_invite.c_chatInviteExported().vlink) : QString()); 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(); chat->fullUpdated();
notifySettingReceived(MTP_inputNotifyPeer(peer->input), f.vnotify_settings); notifySettingReceived(MTP_inputNotifyPeer(peer->input), f.vnotify_settings);
@ -1019,6 +1024,11 @@ void ApiWrap::gotUserFull(UserData *user, const MTPUserFull &result, mtpRequestI
} else { } else {
user->setBotInfoVersion(-1); 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->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->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()); user->setAbout(d.has_about() ? qs(d.vabout) : QString());

View File

@ -403,8 +403,11 @@ void ConvertToSupergroupBox::paintEvent(QPaintEvent *e) {
_note.drawLeft(p, st::boxPadding.left(), _textHeight + st::boxPadding.bottom(), _textWidth, width()); _note.drawLeft(p, st::boxPadding.left(), _textHeight + st::boxPadding.bottom(), _textWidth, width());
} }
PinMessageBox::PinMessageBox(QWidget*, ChannelData *channel, MsgId msgId) PinMessageBox::PinMessageBox(
: _channel(channel) QWidget*,
not_null<PeerData*> peer,
MsgId msgId)
: _peer(peer)
, _msgId(msgId) , _msgId(msgId)
, _text(this, lang(lng_pinned_pin_sure), Ui::FlatLabel::InitType::Simple, st::boxLabel) { , _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_pinned_pin), [this] { pinMessage(); });
addButton(langFactory(lng_cancel), [this] { closeBox(); }); addButton(langFactory(lng_cancel), [this] { closeBox(); });
if (_channel->isMegagroup()) { if (_peer->isChat() || _peer->isMegagroup()) {
_notify.create(this, lang(lng_pinned_notify), true, st::defaultBoxCheckbox); _notify.create(this, lang(lng_pinned_notify), true, st::defaultBoxCheckbox);
} }
@ -443,14 +446,14 @@ void PinMessageBox::keyPressEvent(QKeyEvent *e) {
void PinMessageBox::pinMessage() { void PinMessageBox::pinMessage() {
if (_requestId) return; if (_requestId) return;
auto flags = MTPchannels_UpdatePinnedMessage::Flags(0); auto flags = MTPmessages_UpdatePinnedMessage::Flags(0);
if (_notify && !_notify->checked()) { if (_notify && !_notify->checked()) {
flags |= MTPchannels_UpdatePinnedMessage::Flag::f_silent; flags |= MTPmessages_UpdatePinnedMessage::Flag::f_silent;
} }
_requestId = MTP::send( _requestId = MTP::send(
MTPchannels_UpdatePinnedMessage( MTPmessages_UpdatePinnedMessage(
MTP_flags(flags), MTP_flags(flags),
_channel->inputChannel, _peer->input,
MTP_int(_msgId)), MTP_int(_msgId)),
rpcDone(&PinMessageBox::pinDone), rpcDone(&PinMessageBox::pinDone),
rpcFail(&PinMessageBox::pinFail)); rpcFail(&PinMessageBox::pinFail));

View File

@ -142,7 +142,7 @@ private:
class PinMessageBox : public BoxContent, public RPCSender { class PinMessageBox : public BoxContent, public RPCSender {
public: public:
PinMessageBox(QWidget*, ChannelData *channel, MsgId msgId); PinMessageBox(QWidget*, not_null<PeerData*> peer, MsgId msgId);
protected: protected:
void prepare() override; void prepare() override;
@ -155,7 +155,7 @@ private:
void pinDone(const MTPUpdates &updates); void pinDone(const MTPUpdates &updates);
bool pinFail(const RPCError &error); bool pinFail(const RPCError &error);
ChannelData *_channel; not_null<PeerData*> _peer;
MsgId _msgId; MsgId _msgId;
object_ptr<Ui::FlatLabel> _text; object_ptr<Ui::FlatLabel> _text;

View File

@ -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() { void PeerData::fillNames() {
_nameWords.clear(); _nameWords.clear();
_nameFirstLetters.clear(); _nameFirstLetters.clear();
@ -872,25 +905,12 @@ void ChannelData::setAvailableMinId(MsgId availableMinId) {
if (auto history = App::historyLoaded(this)) { if (auto history = App::historyLoaded(this)) {
history->clearUpTill(availableMinId); history->clearUpTill(availableMinId);
} }
if (_pinnedMessageId <= _availableMinId) { if (pinnedMessageId() <= _availableMinId) {
_pinnedMessageId = MsgId(0); clearPinnedMessage();
Notify::peerUpdatedDelayed(
this,
Notify::PeerUpdate::Flag::ChannelPinnedChanged);
} }
} }
} }
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<Data::Feed*> feed) { void ChannelData::setFeed(not_null<Data::Feed*> feed) {
setFeedPointer(feed); setFeedPointer(feed);
} }
@ -948,15 +968,6 @@ bool ChannelData::canAddAdmins() const {
|| amCreator(); || 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 { bool ChannelData::canPublish() const {
return (adminRights() & AdminRight::f_post_messages) return (adminRights() & AdminRight::f_post_messages)
|| amCreator(); || amCreator();

View File

@ -210,6 +210,15 @@ public:
ImagePtr currentUserpic() const; ImagePtr currentUserpic() const;
bool canPinMessages() const;
MsgId pinnedMessageId() const {
return _pinnedMessageId;
}
void setPinnedMessageId(MsgId messageId);
void clearPinnedMessage() {
setPinnedMessageId(0);
}
protected: protected:
void updateNameDelayed( void updateNameDelayed(
const QString &newName, const QString &newName,
@ -242,6 +251,7 @@ private:
base::flat_set<QChar> _nameFirstLetters; base::flat_set<QChar> _nameFirstLetters;
TimeMs _lastFullUpdate = 0; TimeMs _lastFullUpdate = 0;
MsgId _pinnedMessageId = 0;
}; };
@ -918,7 +928,6 @@ public:
bool hiddenPreHistory() const; bool hiddenPreHistory() const;
bool canAddMembers() const; bool canAddMembers() const;
bool canAddAdmins() const; bool canAddAdmins() const;
bool canPinMessages() const;
bool canPublish() const; bool canPublish() const;
bool canWrite() const; bool canWrite() const;
bool canViewMembers() const; bool canViewMembers() const;
@ -999,14 +1008,6 @@ public:
} }
void setAvailableMinId(MsgId availableMinId); void setAvailableMinId(MsgId availableMinId);
MsgId pinnedMessageId() const {
return _pinnedMessageId;
}
void setPinnedMessageId(MsgId messageId);
void clearPinnedMessage() {
setPinnedMessageId(0);
}
void setFeed(not_null<Data::Feed*> feed); void setFeed(not_null<Data::Feed*> feed);
void clearFeed(); void clearFeed();
@ -1031,7 +1032,6 @@ private:
int _restrictedCount = 0; int _restrictedCount = 0;
int _kickedCount = 0; int _kickedCount = 0;
MsgId _availableMinId = 0; MsgId _availableMinId = 0;
MsgId _pinnedMessageId = 0;
AdminRightFlags _adminRights; AdminRightFlags _adminRights;
RestrictionFlags _restrictions; RestrictionFlags _restrictions;

View File

@ -121,12 +121,12 @@ DialogsInner::DialogsInner(QWidget *parent, not_null<Window::Controller*> contro
}); });
using UpdateFlag = Notify::PeerUpdate::Flag; using UpdateFlag = Notify::PeerUpdate::Flag;
auto changes = UpdateFlag::PinnedChanged auto changes = UpdateFlag::ChatPinnedChanged
| UpdateFlag::NameChanged | UpdateFlag::NameChanged
| UpdateFlag::PhotoChanged | UpdateFlag::PhotoChanged
| UpdateFlag::UserIsContact; | UpdateFlag::UserIsContact;
subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(changes, [this](const Notify::PeerUpdate &update) { subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(changes, [this](const Notify::PeerUpdate &update) {
if (update.flags & UpdateFlag::PinnedChanged) { if (update.flags & UpdateFlag::ChatPinnedChanged) {
stopReorderPinned(); stopReorderPinned();
} }
if (update.flags & UpdateFlag::NameChanged) { if (update.flags & UpdateFlag::NameChanged) {

View File

@ -323,10 +323,8 @@ void History::itemVanished(not_null<HistoryItem*> item) {
&& unreadCount() > 0) { && unreadCount() > 0) {
changeUnreadCount(-1); changeUnreadCount(-1);
} }
if (const auto channel = peer->asChannel()) { if (peer->pinnedMessageId() == item->id) {
if (channel->pinnedMessageId() == item->id) { peer->clearPinnedMessage();
channel->clearPinnedMessage();
}
} }
} }
@ -1216,9 +1214,7 @@ void History::applyServiceChanges(
case mtpc_messageActionPinMessage: { case mtpc_messageActionPinMessage: {
if (data.has_reply_to_msg_id() && item) { if (data.has_reply_to_msg_id() && item) {
if (auto channel = item->history()->peer->asChannel()) { item->history()->peer->setPinnedMessageId(data.vreply_to_msg_id.v);
channel->setPinnedMessageId(data.vreply_to_msg_id.v);
}
} }
} break; } break;
@ -2764,7 +2760,7 @@ void History::changedInChatListHook(Dialogs::Mode list, bool added) {
void History::changedChatListPinHook() { void History::changedChatListPinHook() {
Notify::peerUpdatedDelayed( Notify::peerUpdatedDelayed(
peer, peer,
Notify::PeerUpdate::Flag::PinnedChanged); Notify::PeerUpdate::Flag::ChatPinnedChanged);
} }
void History::removeBlock(not_null<HistoryBlock*> block) { void History::removeBlock(not_null<HistoryBlock*> block) {

View File

@ -321,20 +321,14 @@ void HistoryItem::setRealId(MsgId newId) {
} }
bool HistoryItem::isPinned() const { bool HistoryItem::isPinned() const {
if (auto channel = _history->peer->asChannel()) { return (_history->peer->pinnedMessageId() == id);
return (channel->pinnedMessageId() == id);
}
return false;
} }
bool HistoryItem::canPin() const { bool HistoryItem::canPin() const {
if (id < 0 || !toHistoryMessage()) { if (id < 0 || !toHistoryMessage()) {
return false; return false;
} }
if (auto channel = _history->peer->asChannel()) { return _history->peer->canPinMessages();
return channel->canPinMessages();
}
return false;
} }
bool HistoryItem::allowsForward() const { bool HistoryItem::allowsForward() const {

View File

@ -658,7 +658,7 @@ HistoryWidget::HistoryWidget(
| UpdateFlag::UnreadViewChanged | UpdateFlag::UnreadViewChanged
| UpdateFlag::MigrationChanged | UpdateFlag::MigrationChanged
| UpdateFlag::RestrictionReasonChanged | UpdateFlag::RestrictionReasonChanged
| UpdateFlag::ChannelPinnedChanged | UpdateFlag::PinnedMessageChanged
| UpdateFlag::UserIsBlocked | UpdateFlag::UserIsBlocked
| UpdateFlag::AdminsChanged | UpdateFlag::AdminsChanged
| UpdateFlag::MembersChanged | UpdateFlag::MembersChanged
@ -695,7 +695,7 @@ HistoryWidget::HistoryWidget(
return; return;
} }
} }
if (update.flags & UpdateFlag::ChannelPinnedChanged) { if (update.flags & UpdateFlag::PinnedMessageChanged) {
if (pinnedMsgVisibilityUpdated()) { if (pinnedMsgVisibilityUpdated()) {
updateHistoryGeometry(); updateHistoryGeometry();
updateControlsVisibility(); updateControlsVisibility();
@ -5635,13 +5635,8 @@ void HistoryWidget::updatePinnedBar(bool force) {
bool HistoryWidget::pinnedMsgVisibilityUpdated() { bool HistoryWidget::pinnedMsgVisibilityUpdated() {
auto result = false; auto result = false;
auto pinnedId = [&] { auto pinnedId = _peer->pinnedMessageId();
if (auto channel = _peer ? _peer->asChannel() : nullptr) { if (pinnedId && !_peer->canPinMessages()) {
return channel->pinnedMessageId();
}
return 0;
}();
if (pinnedId && !_peer->asChannel()->canPinMessages()) {
auto it = Global::HiddenPinnedMessages().constFind(_peer->id); auto it = Global::HiddenPinnedMessages().constFind(_peer->id);
if (it != Global::HiddenPinnedMessages().cend()) { if (it != Global::HiddenPinnedMessages().cend()) {
if (it.value() == pinnedId) { if (it.value() == pinnedId) {
@ -5972,27 +5967,25 @@ void HistoryWidget::editMessage(not_null<HistoryItem*> item) {
void HistoryWidget::pinMessage(FullMsgId itemId) { void HistoryWidget::pinMessage(FullMsgId itemId) {
if (const auto item = App::histItemById(itemId)) { if (const auto item = App::histItemById(itemId)) {
if (item->canPin()) { if (item->canPin()) {
const auto channel = item->history()->peer->asChannel(); Ui::show(Box<PinMessageBox>(item->history()->peer, item->id));
Assert(channel != nullptr);
Ui::show(Box<PinMessageBox>(channel, item->id));
} }
} }
} }
void HistoryWidget::unpinMessage(FullMsgId itemId) { void HistoryWidget::unpinMessage(FullMsgId itemId) {
const auto channel = _peer ? _peer->asChannel() : nullptr; const auto peer = _peer;
if (!channel) { if (!peer) {
return; return;
} }
Ui::show(Box<ConfirmBox>(lang(lng_pinned_unpin_sure), lang(lng_pinned_unpin), crl::guard(this, [=] { Ui::show(Box<ConfirmBox>(lang(lng_pinned_unpin_sure), lang(lng_pinned_unpin), crl::guard(this, [=] {
channel->clearPinnedMessage(); peer->clearPinnedMessage();
Ui::hideLayer(); Ui::hideLayer();
MTP::send( MTP::send(
MTPchannels_UpdatePinnedMessage( MTPmessages_UpdatePinnedMessage(
MTP_flags(0), MTP_flags(0),
channel->inputChannel, peer->input,
MTP_int(0)), MTP_int(0)),
rpcDone(&HistoryWidget::unpinDone)); rpcDone(&HistoryWidget::unpinDone));
}))); })));
@ -6005,8 +5998,7 @@ void HistoryWidget::unpinDone(const MTPUpdates &updates) {
} }
void HistoryWidget::onPinnedHide() { void HistoryWidget::onPinnedHide() {
const auto channel = _peer ? _peer->asChannel() : nullptr; const auto pinnedId = _peer ? _peer->pinnedMessageId() : MsgId(0);
const auto pinnedId = channel ? channel->pinnedMessageId() : MsgId(0);
if (!pinnedId) { if (!pinnedId) {
if (pinnedMsgVisibilityUpdated()) { if (pinnedMsgVisibilityUpdated()) {
updateControlsGeometry(); updateControlsGeometry();
@ -6015,10 +6007,12 @@ void HistoryWidget::onPinnedHide() {
return; return;
} }
if (channel->canPinMessages()) { if (_peer->canPinMessages()) {
unpinMessage(FullMsgId(peerToChannel(channel->id), pinnedId)); unpinMessage(FullMsgId(
_peer->isChannel() ? peerToChannel(_peer->id) : NoChannel,
pinnedId));
} else { } else {
Global::RefHiddenPinnedMessages().insert(channel->id, pinnedId); Global::RefHiddenPinnedMessages().insert(_peer->id, pinnedId);
Local::writeUserSettings(); Local::writeUserSettings();
if (pinnedMsgVisibilityUpdated()) { if (pinnedMsgVisibilityUpdated()) {
updateControlsGeometry(); updateControlsGeometry();

View File

@ -4705,13 +4705,6 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
} }
} break; } 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: { case mtpc_updateChannelTooLong: {
auto &d = update.c_updateChannelTooLong(); auto &d = update.c_updateChannelTooLong();
if (auto channel = App::channelLoaded(d.vchannel_id.v)) { if (auto channel = App::channelLoaded(d.vchannel_id.v)) {
@ -4735,6 +4728,28 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
} }
} break; } 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 ////// Cloud sticker sets
case mtpc_updateNewStickerSet: { case mtpc_updateNewStickerSet: {
auto &d = update.c_updateNewStickerSet(); auto &d = update.c_updateNewStickerSet();

View File

@ -35,16 +35,17 @@ struct PeerUpdate {
AboutChanged = (1 << 3), AboutChanged = (1 << 3),
NotificationsEnabled = (1 << 4), NotificationsEnabled = (1 << 4),
MigrationChanged = (1 << 6), MigrationChanged = (1 << 6),
PinnedChanged = (1 << 7), ChatPinnedChanged = (1 << 7),
RestrictionReasonChanged = (1 << 8), RestrictionReasonChanged = (1 << 8),
UnreadViewChanged = (1 << 9), UnreadViewChanged = (1 << 9),
PinnedMessageChanged = (1 << 10),
// For chats and channels // For chats and channels
InviteLinkChanged = (1 << 10), InviteLinkChanged = (1 << 11),
MembersChanged = (1 << 11), MembersChanged = (1 << 12),
AdminsChanged = (1 << 12), AdminsChanged = (1 << 13),
BannedUsersChanged = (1 << 13), BannedUsersChanged = (1 << 14),
UnreadMentionsChanged = (1 << 14), UnreadMentionsChanged = (1 << 15),
// For users // For users
UserCanShareContact = (1 << 16), UserCanShareContact = (1 << 16),
@ -64,8 +65,7 @@ struct PeerUpdate {
ChannelAmIn = (1 << 16), ChannelAmIn = (1 << 16),
ChannelRightsChanged = (1 << 17), ChannelRightsChanged = (1 << 17),
ChannelStickersChanged = (1 << 18), ChannelStickersChanged = (1 << 18),
ChannelPinnedChanged = (1 << 19), ChannelPromotedChanged = (1 << 19),
ChannelPromotedChanged = (1 << 20),
}; };
using Flags = base::flags<Flag>; using Flags = base::flags<Flag>;
friend inline constexpr auto is_flag_type(Flag) { return true; } friend inline constexpr auto is_flag_type(Flag) { return true; }

View File

@ -202,7 +202,7 @@ void Filler::addPinToggle() {
auto lifetime = Notify::PeerUpdateViewer( auto lifetime = Notify::PeerUpdateViewer(
peer, peer,
Notify::PeerUpdate::Flag::PinnedChanged Notify::PeerUpdate::Flag::ChatPinnedChanged
) | rpl::start_with_next([peer, pinAction, pinText] { ) | rpl::start_with_next([peer, pinAction, pinText] {
auto isPinned = App::history(peer)->isPinnedDialog(); auto isPinned = App::history(peer)->isPinnedDialog();
pinAction->setText(pinText(isPinned)); pinAction->setText(pinText(isPinned));