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->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());

View file

@ -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<PeerData*> 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));

View file

@ -142,7 +142,7 @@ private:
class PinMessageBox : public BoxContent, public RPCSender {
public:
PinMessageBox(QWidget*, ChannelData *channel, MsgId msgId);
PinMessageBox(QWidget*, not_null<PeerData*> 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<PeerData*> _peer;
MsgId _msgId;
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() {
_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<Data::Feed*> 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();

View file

@ -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<QChar> _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<Data::Feed*> feed);
void clearFeed();
@ -1031,7 +1032,6 @@ private:
int _restrictedCount = 0;
int _kickedCount = 0;
MsgId _availableMinId = 0;
MsgId _pinnedMessageId = 0;
AdminRightFlags _adminRights;
RestrictionFlags _restrictions;

View file

@ -121,12 +121,12 @@ DialogsInner::DialogsInner(QWidget *parent, not_null<Window::Controller*> 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) {

View file

@ -323,10 +323,8 @@ void History::itemVanished(not_null<HistoryItem*> 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<HistoryBlock*> block) {

View file

@ -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 {

View file

@ -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<HistoryItem*> 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<PinMessageBox>(channel, item->id));
Ui::show(Box<PinMessageBox>(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<ConfirmBox>(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();

View file

@ -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();

View file

@ -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<Flag>;
friend inline constexpr auto is_flag_type(Flag) { return true; }

View file

@ -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));