mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Update API scheme on layer 148: Drafts in topics.
This commit is contained in:
parent
791addd0ee
commit
89d0a71591
60 changed files with 861 additions and 541 deletions
|
@ -336,7 +336,7 @@ updateBotCallbackQuery#b9cfc48d flags:# query_id:long user_id:long peer:Peer msg
|
||||||
updateEditMessage#e40370a3 message:Message pts:int pts_count:int = Update;
|
updateEditMessage#e40370a3 message:Message pts:int pts_count:int = Update;
|
||||||
updateInlineBotCallbackQuery#691e9052 flags:# query_id:long user_id:long msg_id:InputBotInlineMessageID chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update;
|
updateInlineBotCallbackQuery#691e9052 flags:# query_id:long user_id:long msg_id:InputBotInlineMessageID chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update;
|
||||||
updateReadChannelOutbox#b75f99a9 channel_id:long max_id:int = Update;
|
updateReadChannelOutbox#b75f99a9 channel_id:long max_id:int = Update;
|
||||||
updateDraftMessage#ee2bb969 peer:Peer draft:DraftMessage = Update;
|
updateDraftMessage#1b49ec6d flags:# peer:Peer top_msg_id:flags.0?int draft:DraftMessage = Update;
|
||||||
updateReadFeaturedStickers#571d2742 = Update;
|
updateReadFeaturedStickers#571d2742 = Update;
|
||||||
updateRecentStickers#9a422c20 = Update;
|
updateRecentStickers#9a422c20 = Update;
|
||||||
updateConfig#a229dd06 = Update;
|
updateConfig#a229dd06 = Update;
|
||||||
|
@ -389,7 +389,7 @@ updateGroupCallConnection#b783982 flags:# presentation:flags.0?true params:DataJ
|
||||||
updateBotCommands#4d712f2e peer:Peer bot_id:long commands:Vector<BotCommand> = Update;
|
updateBotCommands#4d712f2e peer:Peer bot_id:long commands:Vector<BotCommand> = Update;
|
||||||
updatePendingJoinRequests#7063c3db peer:Peer requests_pending:int recent_requesters:Vector<long> = Update;
|
updatePendingJoinRequests#7063c3db peer:Peer requests_pending:int recent_requesters:Vector<long> = Update;
|
||||||
updateBotChatInviteRequester#11dfa986 peer:Peer date:int user_id:long about:string invite:ExportedChatInvite qts:int = Update;
|
updateBotChatInviteRequester#11dfa986 peer:Peer date:int user_id:long about:string invite:ExportedChatInvite qts:int = Update;
|
||||||
updateMessageReactions#154798c3 peer:Peer msg_id:int reactions:MessageReactions = Update;
|
updateMessageReactions#5e1b3cb8 flags:# peer:Peer msg_id:int top_msg_id:flags.0?int reactions:MessageReactions = Update;
|
||||||
updateAttachMenuBots#17b7a20b = Update;
|
updateAttachMenuBots#17b7a20b = Update;
|
||||||
updateWebViewResultSent#1592b79d query_id:long = Update;
|
updateWebViewResultSent#1592b79d query_id:long = Update;
|
||||||
updateBotMenuButton#14b85813 bot_id:long button:BotMenuButton = Update;
|
updateBotMenuButton#14b85813 bot_id:long button:BotMenuButton = Update;
|
||||||
|
@ -593,6 +593,7 @@ inputStickerSetAnimatedEmojiAnimations#cde3739 = InputStickerSet;
|
||||||
inputStickerSetPremiumGifts#c88b3b02 = InputStickerSet;
|
inputStickerSetPremiumGifts#c88b3b02 = InputStickerSet;
|
||||||
inputStickerSetEmojiGenericAnimations#4c4d4ce = InputStickerSet;
|
inputStickerSetEmojiGenericAnimations#4c4d4ce = InputStickerSet;
|
||||||
inputStickerSetEmojiDefaultStatuses#29d0f5ee = InputStickerSet;
|
inputStickerSetEmojiDefaultStatuses#29d0f5ee = InputStickerSet;
|
||||||
|
inputStickerSetEmojiDefaultTopicIcons#44c1f8e9 = InputStickerSet;
|
||||||
|
|
||||||
stickerSet#2dd14edc flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true animated:flags.5?true videos:flags.6?true emojis:flags.7?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumbs:flags.4?Vector<PhotoSize> thumb_dc_id:flags.4?int thumb_version:flags.4?int thumb_document_id:flags.8?long count:int hash:int = StickerSet;
|
stickerSet#2dd14edc flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true animated:flags.5?true videos:flags.6?true emojis:flags.7?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumbs:flags.4?Vector<PhotoSize> thumb_dc_id:flags.4?int thumb_version:flags.4?int thumb_document_id:flags.8?long count:int hash:int = StickerSet;
|
||||||
|
|
||||||
|
@ -958,12 +959,17 @@ channelAdminLogEventActionToggleNoForwards#cb2ac766 new_value:Bool = ChannelAdmi
|
||||||
channelAdminLogEventActionSendMessage#278f2868 message:Message = ChannelAdminLogEventAction;
|
channelAdminLogEventActionSendMessage#278f2868 message:Message = ChannelAdminLogEventAction;
|
||||||
channelAdminLogEventActionChangeAvailableReactions#be4e0ef8 prev_value:ChatReactions new_value:ChatReactions = ChannelAdminLogEventAction;
|
channelAdminLogEventActionChangeAvailableReactions#be4e0ef8 prev_value:ChatReactions new_value:ChatReactions = ChannelAdminLogEventAction;
|
||||||
channelAdminLogEventActionChangeUsernames#f04fb3a9 prev_value:Vector<string> new_value:Vector<string> = ChannelAdminLogEventAction;
|
channelAdminLogEventActionChangeUsernames#f04fb3a9 prev_value:Vector<string> new_value:Vector<string> = ChannelAdminLogEventAction;
|
||||||
|
channelAdminLogEventActionToggleForum#2cc6383 new_value:Bool = ChannelAdminLogEventAction;
|
||||||
|
channelAdminLogEventActionCreateTopic#58707d28 topic:ForumTopic = ChannelAdminLogEventAction;
|
||||||
|
channelAdminLogEventActionEditTopic#f06fe208 prev_topic:ForumTopic new_topic:ForumTopic = ChannelAdminLogEventAction;
|
||||||
|
channelAdminLogEventActionDeleteTopic#ae168909 topic:ForumTopic = ChannelAdminLogEventAction;
|
||||||
|
channelAdminLogEventActionPinTopic#5d8d353b flags:# prev_topic:flags.0?ForumTopic new_topic:flags.1?ForumTopic = ChannelAdminLogEventAction;
|
||||||
|
|
||||||
channelAdminLogEvent#1fad68cd id:long date:int user_id:long action:ChannelAdminLogEventAction = ChannelAdminLogEvent;
|
channelAdminLogEvent#1fad68cd id:long date:int user_id:long action:ChannelAdminLogEventAction = ChannelAdminLogEvent;
|
||||||
|
|
||||||
channels.adminLogResults#ed8af74d events:Vector<ChannelAdminLogEvent> chats:Vector<Chat> users:Vector<User> = channels.AdminLogResults;
|
channels.adminLogResults#ed8af74d events:Vector<ChannelAdminLogEvent> chats:Vector<Chat> users:Vector<User> = channels.AdminLogResults;
|
||||||
|
|
||||||
channelAdminLogEventsFilter#ea107ae4 flags:# join:flags.0?true leave:flags.1?true invite:flags.2?true ban:flags.3?true unban:flags.4?true kick:flags.5?true unkick:flags.6?true promote:flags.7?true demote:flags.8?true info:flags.9?true settings:flags.10?true pinned:flags.11?true edit:flags.12?true delete:flags.13?true group_call:flags.14?true invites:flags.15?true send:flags.16?true = ChannelAdminLogEventsFilter;
|
channelAdminLogEventsFilter#ea107ae4 flags:# join:flags.0?true leave:flags.1?true invite:flags.2?true ban:flags.3?true unban:flags.4?true kick:flags.5?true unkick:flags.6?true promote:flags.7?true demote:flags.8?true info:flags.9?true settings:flags.10?true pinned:flags.11?true edit:flags.12?true delete:flags.13?true group_call:flags.14?true invites:flags.15?true send:flags.16?true forums:flags.17?true = ChannelAdminLogEventsFilter;
|
||||||
|
|
||||||
popularContact#5ce14175 client_id:long importers:int = PopularContact;
|
popularContact#5ce14175 client_id:long importers:int = PopularContact;
|
||||||
|
|
||||||
|
@ -1322,7 +1328,7 @@ account.resetPasswordFailedWait#e3779861 retry_date:int = account.ResetPasswordR
|
||||||
account.resetPasswordRequestedWait#e9effc7d until_date:int = account.ResetPasswordResult;
|
account.resetPasswordRequestedWait#e9effc7d until_date:int = account.ResetPasswordResult;
|
||||||
account.resetPasswordOk#e926d63e = account.ResetPasswordResult;
|
account.resetPasswordOk#e926d63e = account.ResetPasswordResult;
|
||||||
|
|
||||||
sponsoredMessage#3a836df8 flags:# recommended:flags.5?true random_id:bytes from_id:flags.3?Peer chat_invite:flags.4?ChatInvite chat_invite_hash:flags.4?string channel_post:flags.2?int start_param:flags.0?string message:string entities:flags.1?Vector<MessageEntity> = SponsoredMessage;
|
sponsoredMessage#3a836df8 flags:# recommended:flags.5?true show_peer_photo:flags.6?true random_id:bytes from_id:flags.3?Peer chat_invite:flags.4?ChatInvite chat_invite_hash:flags.4?string channel_post:flags.2?int start_param:flags.0?string message:string entities:flags.1?Vector<MessageEntity> = SponsoredMessage;
|
||||||
|
|
||||||
messages.sponsoredMessages#65a4c7d5 messages:Vector<SponsoredMessage> chats:Vector<Chat> users:Vector<User> = messages.SponsoredMessages;
|
messages.sponsoredMessages#65a4c7d5 messages:Vector<SponsoredMessage> chats:Vector<Chat> users:Vector<User> = messages.SponsoredMessages;
|
||||||
|
|
||||||
|
@ -1459,7 +1465,7 @@ stickerKeyword#fcfeb29c document_id:long keyword:Vector<string> = StickerKeyword
|
||||||
username#b4073647 flags:# editable:flags.0?true active:flags.1?true username:string = Username;
|
username#b4073647 flags:# editable:flags.0?true active:flags.1?true username:string = Username;
|
||||||
|
|
||||||
forumTopicDeleted#23f109b id:int = ForumTopic;
|
forumTopicDeleted#23f109b id:int = ForumTopic;
|
||||||
forumTopic#5920d6dc flags:# my:flags.1?true closed:flags.2?true pinned:flags.3?true id:int date:int title:string icon_color:int icon_emoji_id:flags.0?long top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int from_id:Peer notify_settings:PeerNotifySettings = ForumTopic;
|
forumTopic#71701da9 flags:# my:flags.1?true closed:flags.2?true pinned:flags.3?true id:int date:int title:string icon_color:int icon_emoji_id:flags.0?long top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int from_id:Peer notify_settings:PeerNotifySettings draft:flags.4?DraftMessage = ForumTopic;
|
||||||
|
|
||||||
messages.forumTopics#367617d3 flags:# order_by_create_date:flags.0?true count:int topics:Vector<ForumTopic> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> pts:int = messages.ForumTopics;
|
messages.forumTopics#367617d3 flags:# order_by_create_date:flags.0?true count:int topics:Vector<ForumTopic> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> pts:int = messages.ForumTopics;
|
||||||
|
|
||||||
|
@ -1611,8 +1617,8 @@ messages.deleteHistory#b08f922a flags:# just_clear:flags.0?true revoke:flags.1?t
|
||||||
messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector<int> = messages.AffectedMessages;
|
messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector<int> = messages.AffectedMessages;
|
||||||
messages.receivedMessages#5a954c0 max_id:int = Vector<ReceivedNotifyMessage>;
|
messages.receivedMessages#5a954c0 max_id:int = Vector<ReceivedNotifyMessage>;
|
||||||
messages.setTyping#58943ee2 flags:# peer:InputPeer top_msg_id:flags.0?int action:SendMessageAction = Bool;
|
messages.setTyping#58943ee2 flags:# peer:InputPeer top_msg_id:flags.0?int action:SendMessageAction = Bool;
|
||||||
messages.sendMessage#d9d75a4 flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.10?int send_as:flags.13?InputPeer = Updates;
|
messages.sendMessage#6460114f flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true peer:InputPeer reply_to_msg_id:flags.0?int top_msg_id:flags.8?int message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.10?int send_as:flags.13?InputPeer = Updates;
|
||||||
messages.sendMedia#e25ff8e0 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.10?int send_as:flags.13?InputPeer = Updates;
|
messages.sendMedia#a2e8e1de flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true peer:InputPeer reply_to_msg_id:flags.0?int top_msg_id:flags.8?int media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.10?int send_as:flags.13?InputPeer = Updates;
|
||||||
messages.forwardMessages#cc30290b flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true drop_author:flags.11?true drop_media_captions:flags.12?true noforwards:flags.14?true from_peer:InputPeer id:Vector<int> random_id:Vector<long> to_peer:InputPeer schedule_date:flags.10?int send_as:flags.13?InputPeer = Updates;
|
messages.forwardMessages#cc30290b flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true drop_author:flags.11?true drop_media_captions:flags.12?true noforwards:flags.14?true from_peer:InputPeer id:Vector<int> random_id:Vector<long> to_peer:InputPeer schedule_date:flags.10?int send_as:flags.13?InputPeer = Updates;
|
||||||
messages.reportSpam#cf1592db peer:InputPeer = Bool;
|
messages.reportSpam#cf1592db peer:InputPeer = Bool;
|
||||||
messages.getPeerSettings#efd9a6a2 peer:InputPeer = messages.PeerSettings;
|
messages.getPeerSettings#efd9a6a2 peer:InputPeer = messages.PeerSettings;
|
||||||
|
@ -1656,14 +1662,14 @@ messages.getSavedGifs#5cf09635 hash:long = messages.SavedGifs;
|
||||||
messages.saveGif#327a30cb id:InputDocument unsave:Bool = Bool;
|
messages.saveGif#327a30cb id:InputDocument unsave:Bool = Bool;
|
||||||
messages.getInlineBotResults#514e999d flags:# bot:InputUser peer:InputPeer geo_point:flags.0?InputGeoPoint query:string offset:string = messages.BotResults;
|
messages.getInlineBotResults#514e999d flags:# bot:InputUser peer:InputPeer geo_point:flags.0?InputGeoPoint query:string offset:string = messages.BotResults;
|
||||||
messages.setInlineBotResults#eb5ea206 flags:# gallery:flags.0?true private:flags.1?true query_id:long results:Vector<InputBotInlineResult> cache_time:int next_offset:flags.2?string switch_pm:flags.3?InlineBotSwitchPM = Bool;
|
messages.setInlineBotResults#eb5ea206 flags:# gallery:flags.0?true private:flags.1?true query_id:long results:Vector<InputBotInlineResult> cache_time:int next_offset:flags.2?string switch_pm:flags.3?InlineBotSwitchPM = Bool;
|
||||||
messages.sendInlineBotResult#7aa11297 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true hide_via:flags.11?true peer:InputPeer reply_to_msg_id:flags.0?int random_id:long query_id:long id:string schedule_date:flags.10?int send_as:flags.13?InputPeer = Updates;
|
messages.sendInlineBotResult#15b11c73 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true hide_via:flags.11?true peer:InputPeer reply_to_msg_id:flags.0?int top_msg_id:flags.8?int random_id:long query_id:long id:string schedule_date:flags.10?int send_as:flags.13?InputPeer = Updates;
|
||||||
messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData;
|
messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData;
|
||||||
messages.editMessage#48f71778 flags:# no_webpage:flags.1?true peer:InputPeer id:int message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.15?int = Updates;
|
messages.editMessage#48f71778 flags:# no_webpage:flags.1?true peer:InputPeer id:int message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.15?int = Updates;
|
||||||
messages.editInlineBotMessage#83557dba flags:# no_webpage:flags.1?true id:InputBotInlineMessageID message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Bool;
|
messages.editInlineBotMessage#83557dba flags:# no_webpage:flags.1?true id:InputBotInlineMessageID message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Bool;
|
||||||
messages.getBotCallbackAnswer#9342ca07 flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes password:flags.2?InputCheckPasswordSRP = messages.BotCallbackAnswer;
|
messages.getBotCallbackAnswer#9342ca07 flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes password:flags.2?InputCheckPasswordSRP = messages.BotCallbackAnswer;
|
||||||
messages.setBotCallbackAnswer#d58f130a flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string cache_time:int = Bool;
|
messages.setBotCallbackAnswer#d58f130a flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string cache_time:int = Bool;
|
||||||
messages.getPeerDialogs#e470bcfd peers:Vector<InputDialogPeer> = messages.PeerDialogs;
|
messages.getPeerDialogs#e470bcfd peers:Vector<InputDialogPeer> = messages.PeerDialogs;
|
||||||
messages.saveDraft#bc39e14b flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int peer:InputPeer message:string entities:flags.3?Vector<MessageEntity> = Bool;
|
messages.saveDraft#b4331e3f flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int top_msg_id:flags.2?int peer:InputPeer message:string entities:flags.3?Vector<MessageEntity> = Bool;
|
||||||
messages.getAllDrafts#6a3f8d65 = Updates;
|
messages.getAllDrafts#6a3f8d65 = Updates;
|
||||||
messages.getFeaturedStickers#64780b14 hash:long = messages.FeaturedStickers;
|
messages.getFeaturedStickers#64780b14 hash:long = messages.FeaturedStickers;
|
||||||
messages.readFeaturedStickers#5b118126 id:Vector<long> = Bool;
|
messages.readFeaturedStickers#5b118126 id:Vector<long> = Bool;
|
||||||
|
@ -1692,7 +1698,7 @@ messages.faveSticker#b9ffc55b id:InputDocument unfave:Bool = Bool;
|
||||||
messages.getUnreadMentions#f107e790 flags:# peer:InputPeer top_msg_id:flags.0?int offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages;
|
messages.getUnreadMentions#f107e790 flags:# peer:InputPeer top_msg_id:flags.0?int offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages;
|
||||||
messages.readMentions#36e5bf4d flags:# peer:InputPeer top_msg_id:flags.0?int = messages.AffectedHistory;
|
messages.readMentions#36e5bf4d flags:# peer:InputPeer top_msg_id:flags.0?int = messages.AffectedHistory;
|
||||||
messages.getRecentLocations#702a40e0 peer:InputPeer limit:int hash:long = messages.Messages;
|
messages.getRecentLocations#702a40e0 peer:InputPeer limit:int hash:long = messages.Messages;
|
||||||
messages.sendMultiMedia#f803138f flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true peer:InputPeer reply_to_msg_id:flags.0?int multi_media:Vector<InputSingleMedia> schedule_date:flags.10?int send_as:flags.13?InputPeer = Updates;
|
messages.sendMultiMedia#68463a19 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true peer:InputPeer reply_to_msg_id:flags.0?int top_msg_id:flags.8?int multi_media:Vector<InputSingleMedia> schedule_date:flags.10?int send_as:flags.13?InputPeer = Updates;
|
||||||
messages.uploadEncryptedFile#5057c497 peer:InputEncryptedChat file:InputEncryptedFile = EncryptedFile;
|
messages.uploadEncryptedFile#5057c497 peer:InputEncryptedChat file:InputEncryptedFile = EncryptedFile;
|
||||||
messages.searchStickerSets#35705b8a flags:# exclude_featured:flags.0?true q:string hash:long = messages.FoundStickerSets;
|
messages.searchStickerSets#35705b8a flags:# exclude_featured:flags.0?true q:string hash:long = messages.FoundStickerSets;
|
||||||
messages.getSplitRanges#1cff7e08 = Vector<MessageRange>;
|
messages.getSplitRanges#1cff7e08 = Vector<MessageRange>;
|
||||||
|
@ -1865,6 +1871,7 @@ channels.toggleJoinToSend#e4cb9580 channel:InputChannel enabled:Bool = Updates;
|
||||||
channels.toggleJoinRequest#4c2985b6 channel:InputChannel enabled:Bool = Updates;
|
channels.toggleJoinRequest#4c2985b6 channel:InputChannel enabled:Bool = Updates;
|
||||||
channels.reorderUsernames#b45ced1d channel:InputChannel order:Vector<string> = Bool;
|
channels.reorderUsernames#b45ced1d channel:InputChannel order:Vector<string> = Bool;
|
||||||
channels.toggleUsername#50f24105 channel:InputChannel username:string active:Bool = Bool;
|
channels.toggleUsername#50f24105 channel:InputChannel username:string active:Bool = Bool;
|
||||||
|
channels.deactivateAllUsernames#a245dd3 channel:InputChannel = Bool;
|
||||||
channels.toggleForum#a4298b29 channel:InputChannel enabled:Bool = Updates;
|
channels.toggleForum#a4298b29 channel:InputChannel enabled:Bool = Updates;
|
||||||
channels.createForumTopic#f40c0224 flags:# channel:InputChannel title:string icon_color:flags.0?int icon_emoji_id:flags.3?long random_id:long send_as:flags.2?InputPeer = Updates;
|
channels.createForumTopic#f40c0224 flags:# channel:InputChannel title:string icon_color:flags.0?int icon_emoji_id:flags.3?long random_id:long send_as:flags.2?InputPeer = Updates;
|
||||||
channels.getForumTopics#de560d1 flags:# channel:InputChannel q:flags.0?string offset_date:int offset_id:int offset_topic:int limit:int = messages.ForumTopics;
|
channels.getForumTopics#de560d1 flags:# channel:InputChannel q:flags.0?string offset_date:int offset_id:int offset_topic:int limit:int = messages.ForumTopics;
|
||||||
|
|
|
@ -351,6 +351,7 @@ void ActivateBotCommand(ClickHandlerContext context, int row, int column) {
|
||||||
case ButtonType::RequestPhone: {
|
case ButtonType::RequestPhone: {
|
||||||
HideSingleUseKeyboard(controller, item);
|
HideSingleUseKeyboard(controller, item);
|
||||||
const auto itemId = item->id;
|
const auto itemId = item->id;
|
||||||
|
const auto topicRootId = item->topicRootId();
|
||||||
const auto history = item->history();
|
const auto history = item->history();
|
||||||
controller->show(Ui::MakeConfirmBox({
|
controller->show(Ui::MakeConfirmBox({
|
||||||
.text = tr::lng_bot_share_phone(),
|
.text = tr::lng_bot_share_phone(),
|
||||||
|
@ -362,6 +363,7 @@ void ActivateBotCommand(ClickHandlerContext context, int row, int column) {
|
||||||
auto action = Api::SendAction(history);
|
auto action = Api::SendAction(history);
|
||||||
action.clearDraft = false;
|
action.clearDraft = false;
|
||||||
action.replyTo = itemId;
|
action.replyTo = itemId;
|
||||||
|
action.topicRootId = topicRootId;
|
||||||
history->session().api().shareContact(
|
history->session().api().shareContact(
|
||||||
history->session().user(),
|
history->session().user(),
|
||||||
action);
|
action);
|
||||||
|
@ -381,10 +383,12 @@ void ActivateBotCommand(ClickHandlerContext context, int row, int column) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const auto replyToId = MsgId(0);
|
const auto replyToId = MsgId(0);
|
||||||
|
const auto topicRootId = MsgId(0);
|
||||||
Window::PeerMenuCreatePoll(
|
Window::PeerMenuCreatePoll(
|
||||||
controller,
|
controller,
|
||||||
item->history()->peer,
|
item->history()->peer,
|
||||||
replyToId,
|
replyToId,
|
||||||
|
topicRootId,
|
||||||
chosen,
|
chosen,
|
||||||
disabled);
|
disabled);
|
||||||
} break;
|
} break;
|
||||||
|
|
|
@ -37,6 +37,7 @@ struct SendAction {
|
||||||
not_null<History*> history;
|
not_null<History*> history;
|
||||||
SendOptions options;
|
SendOptions options;
|
||||||
MsgId replyTo = 0;
|
MsgId replyTo = 0;
|
||||||
|
MsgId topicRootId = 0;
|
||||||
bool clearDraft = true;
|
bool clearDraft = true;
|
||||||
bool generateLocal = true;
|
bool generateLocal = true;
|
||||||
MsgId replaceMediaOf = 0;
|
MsgId replaceMediaOf = 0;
|
||||||
|
|
|
@ -42,16 +42,20 @@ void Polls::create(
|
||||||
|
|
||||||
const auto history = action.history;
|
const auto history = action.history;
|
||||||
const auto peer = history->peer;
|
const auto peer = history->peer;
|
||||||
|
const auto topicRootId = action.replyTo ? action.topicRootId : 0;
|
||||||
auto sendFlags = MTPmessages_SendMedia::Flags(0);
|
auto sendFlags = MTPmessages_SendMedia::Flags(0);
|
||||||
if (action.replyTo) {
|
if (action.replyTo) {
|
||||||
sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to_msg_id;
|
sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to_msg_id;
|
||||||
|
if (topicRootId) {
|
||||||
|
sendFlags |= MTPmessages_SendMedia::Flag::f_top_msg_id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const auto clearCloudDraft = action.clearDraft;
|
const auto clearCloudDraft = action.clearDraft;
|
||||||
if (clearCloudDraft) {
|
if (clearCloudDraft) {
|
||||||
sendFlags |= MTPmessages_SendMedia::Flag::f_clear_draft;
|
sendFlags |= MTPmessages_SendMedia::Flag::f_clear_draft;
|
||||||
history->clearLocalDraft();
|
history->clearLocalDraft(topicRootId);
|
||||||
history->clearCloudDraft();
|
history->clearCloudDraft(topicRootId);
|
||||||
history->startSavingCloudDraft();
|
history->startSavingCloudDraft(topicRootId);
|
||||||
}
|
}
|
||||||
const auto silentPost = ShouldSendSilent(peer, action.options);
|
const auto silentPost = ShouldSendSilent(peer, action.options);
|
||||||
if (silentPost) {
|
if (silentPost) {
|
||||||
|
@ -65,16 +69,17 @@ void Polls::create(
|
||||||
sendFlags |= MTPmessages_SendMedia::Flag::f_send_as;
|
sendFlags |= MTPmessages_SendMedia::Flag::f_send_as;
|
||||||
}
|
}
|
||||||
auto &histories = history->owner().histories();
|
auto &histories = history->owner().histories();
|
||||||
const auto replyTo = action.replyTo;
|
|
||||||
const auto randomId = base::RandomValue<uint64>();
|
const auto randomId = base::RandomValue<uint64>();
|
||||||
histories.sendPreparedMessage(
|
histories.sendPreparedMessage(
|
||||||
history,
|
history,
|
||||||
replyTo,
|
action.replyTo,
|
||||||
|
topicRootId,
|
||||||
randomId,
|
randomId,
|
||||||
Data::Histories::PrepareMessage<MTPmessages_SendMedia>(
|
Data::Histories::PrepareMessage<MTPmessages_SendMedia>(
|
||||||
MTP_flags(sendFlags),
|
MTP_flags(sendFlags),
|
||||||
peer->input,
|
peer->input,
|
||||||
Data::Histories::ReplyToPlaceholder(),
|
Data::Histories::ReplyToPlaceholder(),
|
||||||
|
Data::Histories::TopicRootPlaceholder(),
|
||||||
PollDataToInputMedia(&data),
|
PollDataToInputMedia(&data),
|
||||||
MTP_string(),
|
MTP_string(),
|
||||||
MTP_long(randomId),
|
MTP_long(randomId),
|
||||||
|
@ -85,6 +90,7 @@ void Polls::create(
|
||||||
), [=](const MTPUpdates &result, const MTP::Response &response) {
|
), [=](const MTPUpdates &result, const MTP::Response &response) {
|
||||||
if (clearCloudDraft) {
|
if (clearCloudDraft) {
|
||||||
history->finishSavingCloudDraft(
|
history->finishSavingCloudDraft(
|
||||||
|
topicRootId,
|
||||||
UnixtimeFromMsgId(response.outerMsgId));
|
UnixtimeFromMsgId(response.outerMsgId));
|
||||||
}
|
}
|
||||||
_session->changes().historyUpdated(
|
_session->changes().historyUpdated(
|
||||||
|
@ -96,6 +102,7 @@ void Polls::create(
|
||||||
}, [=](const MTP::Error &error, const MTP::Response &response) {
|
}, [=](const MTP::Error &error, const MTP::Response &response) {
|
||||||
if (clearCloudDraft) {
|
if (clearCloudDraft) {
|
||||||
history->finishSavingCloudDraft(
|
history->finishSavingCloudDraft(
|
||||||
|
topicRootId,
|
||||||
UnixtimeFromMsgId(response.outerMsgId));
|
UnixtimeFromMsgId(response.outerMsgId));
|
||||||
}
|
}
|
||||||
fail();
|
fail();
|
||||||
|
|
|
@ -86,6 +86,9 @@ void SendExistingMedia(
|
||||||
if (message.action.replyTo) {
|
if (message.action.replyTo) {
|
||||||
flags |= MessageFlag::HasReplyInfo;
|
flags |= MessageFlag::HasReplyInfo;
|
||||||
sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to_msg_id;
|
sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to_msg_id;
|
||||||
|
if (message.action.topicRootId) {
|
||||||
|
sendFlags |= MTPmessages_SendMedia::Flag::f_top_msg_id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const auto anonymousPost = peer->amAnonymous();
|
const auto anonymousPost = peer->amAnonymous();
|
||||||
const auto silentPost = ShouldSendSilent(peer, message.action.options);
|
const auto silentPost = ShouldSendSilent(peer, message.action.options);
|
||||||
|
@ -118,7 +121,6 @@ void SendExistingMedia(
|
||||||
if (!sentEntities.v.isEmpty()) {
|
if (!sentEntities.v.isEmpty()) {
|
||||||
sendFlags |= MTPmessages_SendMedia::Flag::f_entities;
|
sendFlags |= MTPmessages_SendMedia::Flag::f_entities;
|
||||||
}
|
}
|
||||||
const auto replyTo = message.action.replyTo;
|
|
||||||
const auto captionText = caption.text;
|
const auto captionText = caption.text;
|
||||||
|
|
||||||
if (message.action.options.scheduled) {
|
if (message.action.options.scheduled) {
|
||||||
|
@ -133,7 +135,7 @@ void SendExistingMedia(
|
||||||
newId.msg,
|
newId.msg,
|
||||||
flags,
|
flags,
|
||||||
viaBotId,
|
viaBotId,
|
||||||
replyTo,
|
message.action.replyTo,
|
||||||
HistoryItem::NewMessageDate(message.action.options.scheduled),
|
HistoryItem::NewMessageDate(message.action.options.scheduled),
|
||||||
messageFromId,
|
messageFromId,
|
||||||
messagePostAuthor,
|
messagePostAuthor,
|
||||||
|
@ -146,12 +148,14 @@ void SendExistingMedia(
|
||||||
const auto usedFileReference = media->fileReference();
|
const auto usedFileReference = media->fileReference();
|
||||||
histories.sendPreparedMessage(
|
histories.sendPreparedMessage(
|
||||||
history,
|
history,
|
||||||
replyTo,
|
message.action.replyTo,
|
||||||
|
message.action.topicRootId,
|
||||||
randomId,
|
randomId,
|
||||||
Data::Histories::PrepareMessage<MTPmessages_SendMedia>(
|
Data::Histories::PrepareMessage<MTPmessages_SendMedia>(
|
||||||
MTP_flags(sendFlags),
|
MTP_flags(sendFlags),
|
||||||
peer->input,
|
peer->input,
|
||||||
Data::Histories::ReplyToPlaceholder(),
|
Data::Histories::ReplyToPlaceholder(),
|
||||||
|
Data::Histories::TopicRootPlaceholder(),
|
||||||
inputMedia(),
|
inputMedia(),
|
||||||
MTP_string(captionText),
|
MTP_string(captionText),
|
||||||
MTP_long(randomId),
|
MTP_long(randomId),
|
||||||
|
@ -269,6 +273,9 @@ bool SendDice(MessageToSend &message) {
|
||||||
if (message.action.replyTo) {
|
if (message.action.replyTo) {
|
||||||
flags |= MessageFlag::HasReplyInfo;
|
flags |= MessageFlag::HasReplyInfo;
|
||||||
sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to_msg_id;
|
sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to_msg_id;
|
||||||
|
if (message.action.topicRootId) {
|
||||||
|
sendFlags |= MTPmessages_SendMedia::Flag::f_top_msg_id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const auto replyHeader = NewMessageReplyHeader(message.action);
|
const auto replyHeader = NewMessageReplyHeader(message.action);
|
||||||
const auto anonymousPost = peer->amAnonymous();
|
const auto anonymousPost = peer->amAnonymous();
|
||||||
|
@ -289,7 +296,6 @@ bool SendDice(MessageToSend &message) {
|
||||||
const auto messagePostAuthor = peer->isBroadcast()
|
const auto messagePostAuthor = peer->isBroadcast()
|
||||||
? session->user()->name()
|
? session->user()->name()
|
||||||
: QString();
|
: QString();
|
||||||
const auto replyTo = message.action.replyTo;
|
|
||||||
|
|
||||||
if (message.action.options.scheduled) {
|
if (message.action.options.scheduled) {
|
||||||
flags |= MessageFlag::IsOrWasScheduled;
|
flags |= MessageFlag::IsOrWasScheduled;
|
||||||
|
@ -312,12 +318,14 @@ bool SendDice(MessageToSend &message) {
|
||||||
HistoryMessageMarkupData());
|
HistoryMessageMarkupData());
|
||||||
histories.sendPreparedMessage(
|
histories.sendPreparedMessage(
|
||||||
history,
|
history,
|
||||||
replyTo,
|
message.action.replyTo,
|
||||||
|
message.action.topicRootId,
|
||||||
randomId,
|
randomId,
|
||||||
Data::Histories::PrepareMessage<MTPmessages_SendMedia>(
|
Data::Histories::PrepareMessage<MTPmessages_SendMedia>(
|
||||||
MTP_flags(sendFlags),
|
MTP_flags(sendFlags),
|
||||||
peer->input,
|
peer->input,
|
||||||
Data::Histories::ReplyToPlaceholder(),
|
Data::Histories::ReplyToPlaceholder(),
|
||||||
|
Data::Histories::TopicRootPlaceholder(),
|
||||||
MTP_inputMediaDice(MTP_string(emoji)),
|
MTP_inputMediaDice(MTP_string(emoji)),
|
||||||
MTP_string(),
|
MTP_string(),
|
||||||
MTP_long(randomId),
|
MTP_long(randomId),
|
||||||
|
@ -368,9 +376,13 @@ void SendConfirmedFile(
|
||||||
const auto peer = history->peer;
|
const auto peer = history->peer;
|
||||||
|
|
||||||
if (!isEditing) {
|
if (!isEditing) {
|
||||||
file->to.replyTo = session->data().histories().convertTopicReplyTo(
|
const auto histories = &session->data().histories();
|
||||||
|
file->to.replyTo = histories->convertTopicReplyTo(
|
||||||
history,
|
history,
|
||||||
file->to.replyTo);
|
file->to.replyTo);
|
||||||
|
file->to.topicRootId = histories->convertTopicReplyTo(
|
||||||
|
history,
|
||||||
|
file->to.topicRootId);
|
||||||
}
|
}
|
||||||
|
|
||||||
session->uploader().upload(newId, file);
|
session->uploader().upload(newId, file);
|
||||||
|
@ -378,6 +390,7 @@ void SendConfirmedFile(
|
||||||
auto action = SendAction(history, file->to.options);
|
auto action = SendAction(history, file->to.options);
|
||||||
action.clearDraft = false;
|
action.clearDraft = false;
|
||||||
action.replyTo = file->to.replyTo;
|
action.replyTo = file->to.replyTo;
|
||||||
|
action.topicRootId = file->to.topicRootId;
|
||||||
action.generateLocal = true;
|
action.generateLocal = true;
|
||||||
session->api().sendAction(action);
|
session->api().sendAction(action);
|
||||||
|
|
||||||
|
|
|
@ -2443,12 +2443,14 @@ void Updates::feedUpdate(const MTPUpdate &update) {
|
||||||
case mtpc_updateDraftMessage: {
|
case mtpc_updateDraftMessage: {
|
||||||
const auto &data = update.c_updateDraftMessage();
|
const auto &data = update.c_updateDraftMessage();
|
||||||
const auto peerId = peerFromMTP(data.vpeer());
|
const auto peerId = peerFromMTP(data.vpeer());
|
||||||
|
const auto topicRootId = data.vtop_msg_id().value_or_empty();
|
||||||
data.vdraft().match([&](const MTPDdraftMessage &data) {
|
data.vdraft().match([&](const MTPDdraftMessage &data) {
|
||||||
Data::ApplyPeerCloudDraft(&session(), peerId, data);
|
Data::ApplyPeerCloudDraft(&session(), peerId, topicRootId, data);
|
||||||
}, [&](const MTPDdraftMessageEmpty &data) {
|
}, [&](const MTPDdraftMessageEmpty &data) {
|
||||||
Data::ClearPeerCloudDraft(
|
Data::ClearPeerCloudDraft(
|
||||||
&session(),
|
&session(),
|
||||||
peerId,
|
peerId,
|
||||||
|
topicRootId,
|
||||||
data.vdate().value_or_empty());
|
data.vdate().value_or_empty());
|
||||||
});
|
});
|
||||||
} break;
|
} break;
|
||||||
|
|
|
@ -562,7 +562,7 @@ bool WhoReadExists(not_null<HistoryItem*> item) {
|
||||||
}
|
}
|
||||||
const auto type = DetectSeenType(item);
|
const auto type = DetectSeenType(item);
|
||||||
const auto unseen = (type == Ui::WhoReadType::Seen)
|
const auto unseen = (type == Ui::WhoReadType::Seen)
|
||||||
? item->unread()
|
? item->unread(item->history())
|
||||||
: item->isUnreadMedia();
|
: item->isUnreadMedia();
|
||||||
if (unseen) {
|
if (unseen) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -1812,8 +1812,8 @@ void ApiWrap::sendNotifySettingsUpdates() {
|
||||||
session().mtp().sendAnything();
|
session().mtp().sendAnything();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApiWrap::saveDraftToCloudDelayed(not_null<History*> history) {
|
void ApiWrap::saveDraftToCloudDelayed(not_null<Data::Thread*> thread) {
|
||||||
_draftsSaveRequestIds.emplace(history, 0);
|
_draftsSaveRequestIds.emplace(base::make_weak(thread.get()), 0);
|
||||||
if (!_draftsSaveTimer.isActive()) {
|
if (!_draftsSaveTimer.isActive()) {
|
||||||
_draftsSaveTimer.callOnce(kSaveCloudDraftTimeout);
|
_draftsSaveTimer.callOnce(kSaveCloudDraftTimeout);
|
||||||
}
|
}
|
||||||
|
@ -2004,33 +2004,46 @@ void ApiWrap::saveCurrentDraftToCloud() {
|
||||||
Core::App().saveCurrentDraftsToHistories();
|
Core::App().saveCurrentDraftsToHistories();
|
||||||
|
|
||||||
for (const auto &controller : _session->windows()) {
|
for (const auto &controller : _session->windows()) {
|
||||||
if (const auto history = controller->activeChatCurrent().history()) {
|
if (const auto thread = controller->activeChatCurrent().thread()) {
|
||||||
|
const auto history = thread->owningHistory();
|
||||||
_session->local().writeDrafts(history);
|
_session->local().writeDrafts(history);
|
||||||
|
|
||||||
const auto localDraft = history->localDraft();
|
const auto topicRootId = thread->topicRootId();
|
||||||
const auto cloudDraft = history->cloudDraft();
|
const auto localDraft = history->localDraft(topicRootId);
|
||||||
if (!Data::draftsAreEqual(localDraft, cloudDraft)
|
const auto cloudDraft = history->cloudDraft(topicRootId);
|
||||||
|
if (!Data::DraftsAreEqual(localDraft, cloudDraft)
|
||||||
&& !_session->supportMode()) {
|
&& !_session->supportMode()) {
|
||||||
saveDraftToCloudDelayed(history);
|
saveDraftToCloudDelayed(thread);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApiWrap::saveDraftsToCloud() {
|
void ApiWrap::saveDraftsToCloud() {
|
||||||
for (auto i = _draftsSaveRequestIds.begin(), e = _draftsSaveRequestIds.end(); i != e; ++i) {
|
for (auto i = begin(_draftsSaveRequestIds); i != end(_draftsSaveRequestIds);) {
|
||||||
if (i->second) continue; // sent already
|
const auto weak = i->first;
|
||||||
|
const auto thread = weak.get();
|
||||||
|
if (!thread) {
|
||||||
|
i = _draftsSaveRequestIds.erase(i);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto &requestId = i->second;
|
||||||
|
++i;
|
||||||
|
if (requestId) {
|
||||||
|
continue; // sent already
|
||||||
|
}
|
||||||
|
|
||||||
auto history = i->first;
|
const auto history = thread->owningHistory();
|
||||||
auto cloudDraft = history->cloudDraft();
|
const auto topicRootId = thread->topicRootId();
|
||||||
auto localDraft = history->localDraft();
|
auto cloudDraft = history->cloudDraft(topicRootId);
|
||||||
|
auto localDraft = history->localDraft(topicRootId);
|
||||||
if (cloudDraft && cloudDraft->saveRequestId) {
|
if (cloudDraft && cloudDraft->saveRequestId) {
|
||||||
request(base::take(cloudDraft->saveRequestId)).cancel();
|
request(base::take(cloudDraft->saveRequestId)).cancel();
|
||||||
}
|
}
|
||||||
if (!_session->supportMode()) {
|
if (!_session->supportMode()) {
|
||||||
cloudDraft = history->createCloudDraft(localDraft);
|
cloudDraft = history->createCloudDraft(topicRootId, localDraft);
|
||||||
} else if (!cloudDraft) {
|
} else if (!cloudDraft) {
|
||||||
cloudDraft = history->createCloudDraft(nullptr);
|
cloudDraft = history->createCloudDraft(topicRootId, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto flags = MTPmessages_SaveDraft::Flags(0);
|
auto flags = MTPmessages_SaveDraft::Flags(0);
|
||||||
|
@ -2040,6 +2053,9 @@ void ApiWrap::saveDraftsToCloud() {
|
||||||
}
|
}
|
||||||
if (cloudDraft->msgId) {
|
if (cloudDraft->msgId) {
|
||||||
flags |= MTPmessages_SaveDraft::Flag::f_reply_to_msg_id;
|
flags |= MTPmessages_SaveDraft::Flag::f_reply_to_msg_id;
|
||||||
|
if (cloudDraft->topicRootId) {
|
||||||
|
flags |= MTPmessages_SaveDraft::Flag::f_top_msg_id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!textWithTags.tags.isEmpty()) {
|
if (!textWithTags.tags.isEmpty()) {
|
||||||
flags |= MTPmessages_SaveDraft::Flag::f_entities;
|
flags |= MTPmessages_SaveDraft::Flag::f_entities;
|
||||||
|
@ -2049,44 +2065,45 @@ void ApiWrap::saveDraftsToCloud() {
|
||||||
TextUtilities::ConvertTextTagsToEntities(textWithTags.tags),
|
TextUtilities::ConvertTextTagsToEntities(textWithTags.tags),
|
||||||
Api::ConvertOption::SkipLocal);
|
Api::ConvertOption::SkipLocal);
|
||||||
|
|
||||||
history->startSavingCloudDraft();
|
history->startSavingCloudDraft(topicRootId);
|
||||||
cloudDraft->saveRequestId = request(MTPmessages_SaveDraft(
|
cloudDraft->saveRequestId = request(MTPmessages_SaveDraft(
|
||||||
MTP_flags(flags),
|
MTP_flags(flags),
|
||||||
MTP_int(cloudDraft->msgId),
|
MTP_int(cloudDraft->msgId),
|
||||||
|
MTP_int(cloudDraft->topicRootId),
|
||||||
history->peer->input,
|
history->peer->input,
|
||||||
MTP_string(textWithTags.text),
|
MTP_string(textWithTags.text),
|
||||||
entities
|
entities
|
||||||
)).done([=](const MTPBool &result, const MTP::Response &response) {
|
)).done([=](const MTPBool &result, const MTP::Response &response) {
|
||||||
history->finishSavingCloudDraft(
|
|
||||||
UnixtimeFromMsgId(response.outerMsgId));
|
|
||||||
|
|
||||||
const auto requestId = response.requestId;
|
const auto requestId = response.requestId;
|
||||||
if (const auto cloudDraft = history->cloudDraft()) {
|
history->finishSavingCloudDraft(
|
||||||
|
topicRootId,
|
||||||
|
UnixtimeFromMsgId(response.outerMsgId));
|
||||||
|
if (const auto cloudDraft = history->cloudDraft(topicRootId)) {
|
||||||
if (cloudDraft->saveRequestId == requestId) {
|
if (cloudDraft->saveRequestId == requestId) {
|
||||||
cloudDraft->saveRequestId = 0;
|
cloudDraft->saveRequestId = 0;
|
||||||
history->draftSavedToCloud();
|
history->draftSavedToCloud(topicRootId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto i = _draftsSaveRequestIds.find(history);
|
const auto i = _draftsSaveRequestIds.find(weak);
|
||||||
if (i != _draftsSaveRequestIds.cend()
|
if (i != _draftsSaveRequestIds.cend()
|
||||||
&& i->second == requestId) {
|
&& i->second == requestId) {
|
||||||
_draftsSaveRequestIds.erase(history);
|
_draftsSaveRequestIds.erase(i);
|
||||||
checkQuitPreventFinished();
|
checkQuitPreventFinished();
|
||||||
}
|
}
|
||||||
}).fail([=](const MTP::Error &error, const MTP::Response &response) {
|
}).fail([=](const MTP::Error &error, const MTP::Response &response) {
|
||||||
history->finishSavingCloudDraft(
|
|
||||||
UnixtimeFromMsgId(response.outerMsgId));
|
|
||||||
|
|
||||||
const auto requestId = response.requestId;
|
const auto requestId = response.requestId;
|
||||||
if (const auto cloudDraft = history->cloudDraft()) {
|
history->finishSavingCloudDraft(
|
||||||
|
topicRootId,
|
||||||
|
UnixtimeFromMsgId(response.outerMsgId));
|
||||||
|
if (const auto cloudDraft = history->cloudDraft(topicRootId)) {
|
||||||
if (cloudDraft->saveRequestId == requestId) {
|
if (cloudDraft->saveRequestId == requestId) {
|
||||||
history->clearCloudDraft();
|
history->clearCloudDraft(topicRootId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto i = _draftsSaveRequestIds.find(history);
|
const auto i = _draftsSaveRequestIds.find(weak);
|
||||||
if (i != _draftsSaveRequestIds.cend()
|
if (i != _draftsSaveRequestIds.cend()
|
||||||
&& i->second == requestId) {
|
&& i->second == requestId) {
|
||||||
_draftsSaveRequestIds.erase(history);
|
_draftsSaveRequestIds.erase(i);
|
||||||
checkQuitPreventFinished();
|
checkQuitPreventFinished();
|
||||||
}
|
}
|
||||||
}).send();
|
}).send();
|
||||||
|
@ -3420,6 +3437,9 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||||
if (action.replyTo) {
|
if (action.replyTo) {
|
||||||
flags |= MessageFlag::HasReplyInfo;
|
flags |= MessageFlag::HasReplyInfo;
|
||||||
sendFlags |= MTPmessages_SendMessage::Flag::f_reply_to_msg_id;
|
sendFlags |= MTPmessages_SendMessage::Flag::f_reply_to_msg_id;
|
||||||
|
if (action.topicRootId) {
|
||||||
|
sendFlags |= MTPmessages_SendMessage::Flag::f_top_msg_id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const auto replyHeader = NewMessageReplyHeader(action);
|
const auto replyHeader = NewMessageReplyHeader(action);
|
||||||
MTPMessageMedia media = MTP_messageMediaEmpty();
|
MTPMessageMedia media = MTP_messageMediaEmpty();
|
||||||
|
@ -3446,10 +3466,11 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||||
sendFlags |= MTPmessages_SendMessage::Flag::f_entities;
|
sendFlags |= MTPmessages_SendMessage::Flag::f_entities;
|
||||||
}
|
}
|
||||||
const auto clearCloudDraft = action.clearDraft;
|
const auto clearCloudDraft = action.clearDraft;
|
||||||
|
const auto topicRootId = action.topicRootId;
|
||||||
if (clearCloudDraft) {
|
if (clearCloudDraft) {
|
||||||
sendFlags |= MTPmessages_SendMessage::Flag::f_clear_draft;
|
sendFlags |= MTPmessages_SendMessage::Flag::f_clear_draft;
|
||||||
history->clearCloudDraft();
|
history->clearCloudDraft(topicRootId);
|
||||||
history->startSavingCloudDraft();
|
history->startSavingCloudDraft(topicRootId);
|
||||||
}
|
}
|
||||||
const auto sendAs = action.options.sendAs;
|
const auto sendAs = action.options.sendAs;
|
||||||
const auto messageFromId = sendAs
|
const auto messageFromId = sendAs
|
||||||
|
@ -3468,12 +3489,11 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||||
sendFlags |= MTPmessages_SendMessage::Flag::f_schedule_date;
|
sendFlags |= MTPmessages_SendMessage::Flag::f_schedule_date;
|
||||||
}
|
}
|
||||||
const auto viaBotId = UserId();
|
const auto viaBotId = UserId();
|
||||||
const auto replyTo = action.replyTo;
|
|
||||||
lastMessage = history->addNewLocalMessage(
|
lastMessage = history->addNewLocalMessage(
|
||||||
newId.msg,
|
newId.msg,
|
||||||
flags,
|
flags,
|
||||||
viaBotId,
|
viaBotId,
|
||||||
replyTo,
|
action.replyTo,
|
||||||
HistoryItem::NewMessageDate(action.options.scheduled),
|
HistoryItem::NewMessageDate(action.options.scheduled),
|
||||||
messageFromId,
|
messageFromId,
|
||||||
messagePostAuthor,
|
messagePostAuthor,
|
||||||
|
@ -3482,12 +3502,14 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||||
HistoryMessageMarkupData());
|
HistoryMessageMarkupData());
|
||||||
histories.sendPreparedMessage(
|
histories.sendPreparedMessage(
|
||||||
history,
|
history,
|
||||||
replyTo,
|
action.replyTo,
|
||||||
|
topicRootId,
|
||||||
randomId,
|
randomId,
|
||||||
Data::Histories::PrepareMessage<MTPmessages_SendMessage>(
|
Data::Histories::PrepareMessage<MTPmessages_SendMessage>(
|
||||||
MTP_flags(sendFlags),
|
MTP_flags(sendFlags),
|
||||||
peer->input,
|
peer->input,
|
||||||
Data::Histories::ReplyToPlaceholder(),
|
Data::Histories::ReplyToPlaceholder(),
|
||||||
|
Data::Histories::TopicRootPlaceholder(),
|
||||||
msgText,
|
msgText,
|
||||||
MTP_long(randomId),
|
MTP_long(randomId),
|
||||||
MTPReplyMarkup(),
|
MTPReplyMarkup(),
|
||||||
|
@ -3497,6 +3519,7 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||||
), [=](const MTPUpdates &result, const MTP::Response &response) {
|
), [=](const MTPUpdates &result, const MTP::Response &response) {
|
||||||
if (clearCloudDraft) {
|
if (clearCloudDraft) {
|
||||||
history->finishSavingCloudDraft(
|
history->finishSavingCloudDraft(
|
||||||
|
topicRootId,
|
||||||
UnixtimeFromMsgId(response.outerMsgId));
|
UnixtimeFromMsgId(response.outerMsgId));
|
||||||
}
|
}
|
||||||
}, [=](const MTP::Error &error, const MTP::Response &response) {
|
}, [=](const MTP::Error &error, const MTP::Response &response) {
|
||||||
|
@ -3507,6 +3530,7 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||||
}
|
}
|
||||||
if (clearCloudDraft) {
|
if (clearCloudDraft) {
|
||||||
history->finishSavingCloudDraft(
|
history->finishSavingCloudDraft(
|
||||||
|
topicRootId,
|
||||||
UnixtimeFromMsgId(response.outerMsgId));
|
UnixtimeFromMsgId(response.outerMsgId));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -3573,12 +3597,16 @@ void ApiWrap::sendInlineResult(
|
||||||
? (*localMessageId)
|
? (*localMessageId)
|
||||||
: _session->data().nextLocalMessageId());
|
: _session->data().nextLocalMessageId());
|
||||||
const auto randomId = base::RandomValue<uint64>();
|
const auto randomId = base::RandomValue<uint64>();
|
||||||
|
const auto topicRootId = action.replyTo ? action.topicRootId : 0;
|
||||||
|
|
||||||
auto flags = NewMessageFlags(peer);
|
auto flags = NewMessageFlags(peer);
|
||||||
auto sendFlags = MTPmessages_SendInlineBotResult::Flag::f_clear_draft | 0;
|
auto sendFlags = MTPmessages_SendInlineBotResult::Flag::f_clear_draft | 0;
|
||||||
if (action.replyTo) {
|
if (action.replyTo) {
|
||||||
flags |= MessageFlag::HasReplyInfo;
|
flags |= MessageFlag::HasReplyInfo;
|
||||||
sendFlags |= MTPmessages_SendInlineBotResult::Flag::f_reply_to_msg_id;
|
sendFlags |= MTPmessages_SendInlineBotResult::Flag::f_reply_to_msg_id;
|
||||||
|
if (topicRootId) {
|
||||||
|
sendFlags |= MTPmessages_SendInlineBotResult::Flag::f_top_msg_id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const auto anonymousPost = peer->amAnonymous();
|
const auto anonymousPost = peer->amAnonymous();
|
||||||
const auto silentPost = ShouldSendSilent(peer, action.options);
|
const auto silentPost = ShouldSendSilent(peer, action.options);
|
||||||
|
@ -3618,19 +3646,20 @@ void ApiWrap::sendInlineResult(
|
||||||
action.replyTo,
|
action.replyTo,
|
||||||
messagePostAuthor);
|
messagePostAuthor);
|
||||||
|
|
||||||
history->clearCloudDraft();
|
history->clearCloudDraft(topicRootId);
|
||||||
history->startSavingCloudDraft();
|
history->startSavingCloudDraft(topicRootId);
|
||||||
|
|
||||||
auto &histories = history->owner().histories();
|
auto &histories = history->owner().histories();
|
||||||
const auto replyTo = action.replyTo;
|
|
||||||
histories.sendPreparedMessage(
|
histories.sendPreparedMessage(
|
||||||
history,
|
history,
|
||||||
replyTo,
|
action.replyTo,
|
||||||
|
topicRootId,
|
||||||
randomId,
|
randomId,
|
||||||
Data::Histories::PrepareMessage<MTPmessages_SendInlineBotResult>(
|
Data::Histories::PrepareMessage<MTPmessages_SendInlineBotResult>(
|
||||||
MTP_flags(sendFlags),
|
MTP_flags(sendFlags),
|
||||||
peer->input,
|
peer->input,
|
||||||
Data::Histories::ReplyToPlaceholder(),
|
Data::Histories::ReplyToPlaceholder(),
|
||||||
|
Data::Histories::TopicRootPlaceholder(),
|
||||||
MTP_long(randomId),
|
MTP_long(randomId),
|
||||||
MTP_long(data->getQueryId()),
|
MTP_long(data->getQueryId()),
|
||||||
MTP_string(data->getId()),
|
MTP_string(data->getId()),
|
||||||
|
@ -3638,10 +3667,12 @@ void ApiWrap::sendInlineResult(
|
||||||
(sendAs ? sendAs->input : MTP_inputPeerEmpty())
|
(sendAs ? sendAs->input : MTP_inputPeerEmpty())
|
||||||
), [=](const MTPUpdates &result, const MTP::Response &response) {
|
), [=](const MTPUpdates &result, const MTP::Response &response) {
|
||||||
history->finishSavingCloudDraft(
|
history->finishSavingCloudDraft(
|
||||||
|
topicRootId,
|
||||||
UnixtimeFromMsgId(response.outerMsgId));
|
UnixtimeFromMsgId(response.outerMsgId));
|
||||||
}, [=](const MTP::Error &error, const MTP::Response &response) {
|
}, [=](const MTP::Error &error, const MTP::Response &response) {
|
||||||
sendMessageFail(error, peer, randomId, newId);
|
sendMessageFail(error, peer, randomId, newId);
|
||||||
history->finishSavingCloudDraft(
|
history->finishSavingCloudDraft(
|
||||||
|
topicRootId,
|
||||||
UnixtimeFromMsgId(response.outerMsgId));
|
UnixtimeFromMsgId(response.outerMsgId));
|
||||||
});
|
});
|
||||||
finishForwarding(action);
|
finishForwarding(action);
|
||||||
|
@ -3740,6 +3771,7 @@ void ApiWrap::sendMediaWithRandomId(
|
||||||
uint64 randomId) {
|
uint64 randomId) {
|
||||||
const auto history = item->history();
|
const auto history = item->history();
|
||||||
const auto replyTo = item->replyToId();
|
const auto replyTo = item->replyToId();
|
||||||
|
const auto topicRootId = item->topicRootId();
|
||||||
|
|
||||||
auto caption = item->originalText();
|
auto caption = item->originalText();
|
||||||
TextUtilities::Trim(caption);
|
TextUtilities::Trim(caption);
|
||||||
|
@ -3750,22 +3782,16 @@ void ApiWrap::sendMediaWithRandomId(
|
||||||
|
|
||||||
const auto updateRecentStickers = Api::HasAttachedStickers(media);
|
const auto updateRecentStickers = Api::HasAttachedStickers(media);
|
||||||
|
|
||||||
const auto flags = MTPmessages_SendMedia::Flags(0)
|
using Flag = MTPmessages_SendMedia::Flag;
|
||||||
| (replyTo
|
const auto flags = Flag(0)
|
||||||
? MTPmessages_SendMedia::Flag::f_reply_to_msg_id
|
| (replyTo ? Flag::f_reply_to_msg_id : Flag(0))
|
||||||
: MTPmessages_SendMedia::Flag(0))
|
| (topicRootId ? Flag::f_top_msg_id : Flag(0))
|
||||||
| (ShouldSendSilent(history->peer, options)
|
| (ShouldSendSilent(history->peer, options)
|
||||||
? MTPmessages_SendMedia::Flag::f_silent
|
? Flag::f_silent
|
||||||
: MTPmessages_SendMedia::Flag(0))
|
: Flag(0))
|
||||||
| (!sentEntities.v.isEmpty()
|
| (!sentEntities.v.isEmpty() ? Flag::f_entities : Flag(0))
|
||||||
? MTPmessages_SendMedia::Flag::f_entities
|
| (options.scheduled ? Flag::f_schedule_date : Flag(0))
|
||||||
: MTPmessages_SendMedia::Flag(0))
|
| (options.sendAs ? Flag::f_send_as : Flag(0));
|
||||||
| (options.scheduled
|
|
||||||
? MTPmessages_SendMedia::Flag::f_schedule_date
|
|
||||||
: MTPmessages_SendMedia::Flag(0))
|
|
||||||
| (options.sendAs
|
|
||||||
? MTPmessages_SendMedia::Flag::f_send_as
|
|
||||||
: MTPmessages_SendMedia::Flag(0));
|
|
||||||
|
|
||||||
auto &histories = history->owner().histories();
|
auto &histories = history->owner().histories();
|
||||||
const auto peer = history->peer;
|
const auto peer = history->peer;
|
||||||
|
@ -3773,11 +3799,13 @@ void ApiWrap::sendMediaWithRandomId(
|
||||||
histories.sendPreparedMessage(
|
histories.sendPreparedMessage(
|
||||||
history,
|
history,
|
||||||
replyTo,
|
replyTo,
|
||||||
|
topicRootId,
|
||||||
randomId,
|
randomId,
|
||||||
Data::Histories::PrepareMessage<MTPmessages_SendMedia>(
|
Data::Histories::PrepareMessage<MTPmessages_SendMedia>(
|
||||||
MTP_flags(flags),
|
MTP_flags(flags),
|
||||||
peer->input,
|
peer->input,
|
||||||
Data::Histories::ReplyToPlaceholder(),
|
Data::Histories::ReplyToPlaceholder(),
|
||||||
|
Data::Histories::TopicRootPlaceholder(),
|
||||||
media,
|
media,
|
||||||
MTP_string(caption.text),
|
MTP_string(caption.text),
|
||||||
MTP_long(randomId),
|
MTP_long(randomId),
|
||||||
|
@ -3859,30 +3887,29 @@ void ApiWrap::sendAlbumIfReady(not_null<SendingAlbum*> album) {
|
||||||
}
|
}
|
||||||
const auto history = sample->history();
|
const auto history = sample->history();
|
||||||
const auto replyTo = sample->replyToId();
|
const auto replyTo = sample->replyToId();
|
||||||
|
const auto topicRootId = sample->topicRootId();
|
||||||
const auto sendAs = album->options.sendAs;
|
const auto sendAs = album->options.sendAs;
|
||||||
const auto flags = MTPmessages_SendMultiMedia::Flags(0)
|
using Flag = MTPmessages_SendMultiMedia::Flag;
|
||||||
| (replyTo
|
const auto flags = Flag(0)
|
||||||
? MTPmessages_SendMultiMedia::Flag::f_reply_to_msg_id
|
| (replyTo ? Flag::f_reply_to_msg_id : Flag(0))
|
||||||
: MTPmessages_SendMultiMedia::Flag(0))
|
| (topicRootId ? Flag::f_top_msg_id : Flag(0))
|
||||||
| (ShouldSendSilent(history->peer, album->options)
|
| (ShouldSendSilent(history->peer, album->options)
|
||||||
? MTPmessages_SendMultiMedia::Flag::f_silent
|
? Flag::f_silent
|
||||||
: MTPmessages_SendMultiMedia::Flag(0))
|
: Flag(0))
|
||||||
| (album->options.scheduled
|
| (album->options.scheduled ? Flag::f_schedule_date : Flag(0))
|
||||||
? MTPmessages_SendMultiMedia::Flag::f_schedule_date
|
| (sendAs ? Flag::f_send_as : Flag(0));
|
||||||
: MTPmessages_SendMultiMedia::Flag(0))
|
|
||||||
| (sendAs
|
|
||||||
? MTPmessages_SendMultiMedia::Flag::f_send_as
|
|
||||||
: MTPmessages_SendMultiMedia::Flag(0));
|
|
||||||
auto &histories = history->owner().histories();
|
auto &histories = history->owner().histories();
|
||||||
const auto peer = history->peer;
|
const auto peer = history->peer;
|
||||||
histories.sendPreparedMessage(
|
histories.sendPreparedMessage(
|
||||||
history,
|
history,
|
||||||
replyTo,
|
replyTo,
|
||||||
|
topicRootId,
|
||||||
uint64(0), // randomId
|
uint64(0), // randomId
|
||||||
Data::Histories::PrepareMessage<MTPmessages_SendMultiMedia>(
|
Data::Histories::PrepareMessage<MTPmessages_SendMultiMedia>(
|
||||||
MTP_flags(flags),
|
MTP_flags(flags),
|
||||||
peer->input,
|
peer->input,
|
||||||
Data::Histories::ReplyToPlaceholder(),
|
Data::Histories::ReplyToPlaceholder(),
|
||||||
|
Data::Histories::TopicRootPlaceholder(),
|
||||||
MTP_vector<MTPInputSingleMedia>(medias),
|
MTP_vector<MTPInputSingleMedia>(medias),
|
||||||
MTP_int(album->options.scheduled),
|
MTP_int(album->options.scheduled),
|
||||||
(sendAs ? sendAs->input : MTP_inputPeerEmpty())
|
(sendAs ? sendAs->input : MTP_inputPeerEmpty())
|
||||||
|
@ -3905,6 +3932,7 @@ FileLoadTo ApiWrap::fileLoadTaskOptions(const SendAction &action) const {
|
||||||
peer->id,
|
peer->id,
|
||||||
action.options,
|
action.options,
|
||||||
action.replyTo,
|
action.replyTo,
|
||||||
|
action.topicRootId,
|
||||||
action.replaceMediaOf);
|
action.replaceMediaOf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -245,7 +245,7 @@ public:
|
||||||
void updateNotifySettingsDelayed(not_null<const Data::Thread*> thread);
|
void updateNotifySettingsDelayed(not_null<const Data::Thread*> thread);
|
||||||
void updateNotifySettingsDelayed(not_null<const PeerData*> peer);
|
void updateNotifySettingsDelayed(not_null<const PeerData*> peer);
|
||||||
void updateNotifySettingsDelayed(Data::DefaultNotify type);
|
void updateNotifySettingsDelayed(Data::DefaultNotify type);
|
||||||
void saveDraftToCloudDelayed(not_null<History*> history);
|
void saveDraftToCloudDelayed(not_null<Data::Thread*> thread);
|
||||||
|
|
||||||
static int OnlineTillFromStatus(
|
static int OnlineTillFromStatus(
|
||||||
const MTPUserStatus &status,
|
const MTPUserStatus &status,
|
||||||
|
@ -563,7 +563,9 @@ private:
|
||||||
};
|
};
|
||||||
base::flat_map<NotifySettingsKey, mtpRequestId> _notifySettingRequests;
|
base::flat_map<NotifySettingsKey, mtpRequestId> _notifySettingRequests;
|
||||||
|
|
||||||
base::flat_map<not_null<History*>, mtpRequestId> _draftsSaveRequestIds;
|
base::flat_map<
|
||||||
|
base::weak_ptr<Data::Thread>,
|
||||||
|
mtpRequestId> _draftsSaveRequestIds;
|
||||||
base::Timer _draftsSaveTimer;
|
base::Timer _draftsSaveTimer;
|
||||||
|
|
||||||
base::flat_set<mtpRequestId> _stickerSetDisenableRequests;
|
base::flat_set<mtpRequestId> _stickerSetDisenableRequests;
|
||||||
|
|
|
@ -65,14 +65,17 @@ void ShareBotGame(
|
||||||
auto &histories = history->owner().histories();
|
auto &histories = history->owner().histories();
|
||||||
const auto randomId = base::RandomValue<uint64>();
|
const auto randomId = base::RandomValue<uint64>();
|
||||||
const auto replyTo = 0;
|
const auto replyTo = 0;
|
||||||
|
const auto topicRootId = 0;
|
||||||
histories.sendPreparedMessage(
|
histories.sendPreparedMessage(
|
||||||
history,
|
history,
|
||||||
replyTo,
|
replyTo,
|
||||||
|
topicRootId,
|
||||||
randomId,
|
randomId,
|
||||||
Data::Histories::PrepareMessage<MTPmessages_SendMedia>(
|
Data::Histories::PrepareMessage<MTPmessages_SendMedia>(
|
||||||
MTP_flags(0),
|
MTP_flags(0),
|
||||||
chat->input,
|
chat->input,
|
||||||
Data::Histories::ReplyToPlaceholder(),
|
Data::Histories::ReplyToPlaceholder(),
|
||||||
|
Data::Histories::TopicRootPlaceholder(),
|
||||||
MTP_inputMediaGame(
|
MTP_inputMediaGame(
|
||||||
MTP_inputGameShortName(
|
MTP_inputGameShortName(
|
||||||
bot->inputUser,
|
bot->inputUser,
|
||||||
|
|
|
@ -127,7 +127,7 @@ void DicePack::generateLocal(int index, const QString &name) {
|
||||||
QByteArray(),
|
QByteArray(),
|
||||||
nullptr,
|
nullptr,
|
||||||
SendMediaType::File,
|
SendMediaType::File,
|
||||||
FileLoadTo(0, {}, 0, 0),
|
FileLoadTo(0, {}, 0, 0, 0),
|
||||||
{});
|
{});
|
||||||
task.process({ .generateGoodThumbnail = false });
|
task.process({ .generateGoodThumbnail = false });
|
||||||
const auto result = task.peekResult();
|
const auto result = task.peekResult();
|
||||||
|
|
|
@ -151,8 +151,9 @@ struct TopicUpdate {
|
||||||
Notifications = (1U << 4),
|
Notifications = (1U << 4),
|
||||||
Title = (1U << 5),
|
Title = (1U << 5),
|
||||||
Icon = (1U << 6),
|
Icon = (1U << 6),
|
||||||
|
CloudDraft = (1U << 7),
|
||||||
|
|
||||||
LastUsedBit = (1U << 4),
|
LastUsedBit = (1U << 7),
|
||||||
};
|
};
|
||||||
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; }
|
||||||
|
|
|
@ -19,29 +19,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
namespace Data {
|
namespace Data {
|
||||||
|
|
||||||
DraftKey DraftKey::FromSerializedOld(int32 value) {
|
|
||||||
return !value
|
|
||||||
? DraftKey::None()
|
|
||||||
: (value == kLocalDraftIndex + kEditDraftShiftOld)
|
|
||||||
? DraftKey::LocalEdit()
|
|
||||||
: (value == kScheduledDraftIndex + kEditDraftShiftOld)
|
|
||||||
? DraftKey::ScheduledEdit()
|
|
||||||
: (value > 0 && value < 0x4000'0000)
|
|
||||||
? DraftKey::Replies(int64(value))
|
|
||||||
: (value > kEditDraftShiftOld
|
|
||||||
&& value < kEditDraftShiftOld + 0x4000'000)
|
|
||||||
? DraftKey::RepliesEdit(int64(value - kEditDraftShiftOld))
|
|
||||||
: DraftKey::None();
|
|
||||||
}
|
|
||||||
|
|
||||||
Draft::Draft(
|
Draft::Draft(
|
||||||
const TextWithTags &textWithTags,
|
const TextWithTags &textWithTags,
|
||||||
MsgId msgId,
|
MsgId msgId,
|
||||||
|
MsgId topicRootId,
|
||||||
const MessageCursor &cursor,
|
const MessageCursor &cursor,
|
||||||
PreviewState previewState,
|
PreviewState previewState,
|
||||||
mtpRequestId saveRequestId)
|
mtpRequestId saveRequestId)
|
||||||
: textWithTags(textWithTags)
|
: textWithTags(textWithTags)
|
||||||
, msgId(msgId)
|
, msgId(msgId)
|
||||||
|
, topicRootId(topicRootId)
|
||||||
, cursor(cursor)
|
, cursor(cursor)
|
||||||
, previewState(previewState)
|
, previewState(previewState)
|
||||||
, saveRequestId(saveRequestId) {
|
, saveRequestId(saveRequestId) {
|
||||||
|
@ -50,10 +37,12 @@ Draft::Draft(
|
||||||
Draft::Draft(
|
Draft::Draft(
|
||||||
not_null<const Ui::InputField*> field,
|
not_null<const Ui::InputField*> field,
|
||||||
MsgId msgId,
|
MsgId msgId,
|
||||||
|
MsgId topicRootId,
|
||||||
PreviewState previewState,
|
PreviewState previewState,
|
||||||
mtpRequestId saveRequestId)
|
mtpRequestId saveRequestId)
|
||||||
: textWithTags(field->getTextWithTags())
|
: textWithTags(field->getTextWithTags())
|
||||||
, msgId(msgId)
|
, msgId(msgId)
|
||||||
|
, topicRootId(topicRootId)
|
||||||
, cursor(field)
|
, cursor(field)
|
||||||
, previewState(previewState) {
|
, previewState(previewState) {
|
||||||
}
|
}
|
||||||
|
@ -61,10 +50,11 @@ Draft::Draft(
|
||||||
void ApplyPeerCloudDraft(
|
void ApplyPeerCloudDraft(
|
||||||
not_null<Main::Session*> session,
|
not_null<Main::Session*> session,
|
||||||
PeerId peerId,
|
PeerId peerId,
|
||||||
|
MsgId topicRootId,
|
||||||
const MTPDdraftMessage &draft) {
|
const MTPDdraftMessage &draft) {
|
||||||
const auto history = session->data().history(peerId);
|
const auto history = session->data().history(peerId);
|
||||||
const auto date = draft.vdate().v;
|
const auto date = draft.vdate().v;
|
||||||
if (history->skipCloudDraftUpdate(date)) {
|
if (history->skipCloudDraftUpdate(topicRootId, date)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto textWithTags = TextWithTags{
|
const auto textWithTags = TextWithTags{
|
||||||
|
@ -78,6 +68,7 @@ void ApplyPeerCloudDraft(
|
||||||
auto cloudDraft = std::make_unique<Draft>(
|
auto cloudDraft = std::make_unique<Draft>(
|
||||||
textWithTags,
|
textWithTags,
|
||||||
replyTo,
|
replyTo,
|
||||||
|
topicRootId,
|
||||||
MessageCursor(QFIXED_MAX, QFIXED_MAX, QFIXED_MAX),
|
MessageCursor(QFIXED_MAX, QFIXED_MAX, QFIXED_MAX),
|
||||||
(draft.is_no_webpage()
|
(draft.is_no_webpage()
|
||||||
? Data::PreviewState::Cancelled
|
? Data::PreviewState::Cancelled
|
||||||
|
@ -85,20 +76,21 @@ void ApplyPeerCloudDraft(
|
||||||
cloudDraft->date = date;
|
cloudDraft->date = date;
|
||||||
|
|
||||||
history->setCloudDraft(std::move(cloudDraft));
|
history->setCloudDraft(std::move(cloudDraft));
|
||||||
history->applyCloudDraft();
|
history->applyCloudDraft(topicRootId);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClearPeerCloudDraft(
|
void ClearPeerCloudDraft(
|
||||||
not_null<Main::Session*> session,
|
not_null<Main::Session*> session,
|
||||||
PeerId peerId,
|
PeerId peerId,
|
||||||
|
MsgId topicRootId,
|
||||||
TimeId date) {
|
TimeId date) {
|
||||||
const auto history = session->data().history(peerId);
|
const auto history = session->data().history(peerId);
|
||||||
if (history->skipCloudDraftUpdate(date)) {
|
if (history->skipCloudDraftUpdate(topicRootId, date)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
history->clearCloudDraft();
|
history->clearCloudDraft(topicRootId);
|
||||||
history->applyCloudDraft();
|
history->applyCloudDraft(topicRootId);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Data
|
} // namespace Data
|
||||||
|
|
|
@ -20,10 +20,12 @@ namespace Data {
|
||||||
void ApplyPeerCloudDraft(
|
void ApplyPeerCloudDraft(
|
||||||
not_null<Main::Session*> session,
|
not_null<Main::Session*> session,
|
||||||
PeerId peerId,
|
PeerId peerId,
|
||||||
|
MsgId topicRootId,
|
||||||
const MTPDdraftMessage &draft);
|
const MTPDdraftMessage &draft);
|
||||||
void ClearPeerCloudDraft(
|
void ClearPeerCloudDraft(
|
||||||
not_null<Main::Session*> session,
|
not_null<Main::Session*> session,
|
||||||
PeerId peerId,
|
PeerId peerId,
|
||||||
|
MsgId topicRootId,
|
||||||
TimeId date);
|
TimeId date);
|
||||||
|
|
||||||
enum class PreviewState : char {
|
enum class PreviewState : char {
|
||||||
|
@ -37,18 +39,21 @@ struct Draft {
|
||||||
Draft(
|
Draft(
|
||||||
const TextWithTags &textWithTags,
|
const TextWithTags &textWithTags,
|
||||||
MsgId msgId,
|
MsgId msgId,
|
||||||
|
MsgId topicRootId,
|
||||||
const MessageCursor &cursor,
|
const MessageCursor &cursor,
|
||||||
PreviewState previewState,
|
PreviewState previewState,
|
||||||
mtpRequestId saveRequestId = 0);
|
mtpRequestId saveRequestId = 0);
|
||||||
Draft(
|
Draft(
|
||||||
not_null<const Ui::InputField*> field,
|
not_null<const Ui::InputField*> field,
|
||||||
MsgId msgId,
|
MsgId msgId,
|
||||||
|
MsgId topicRootId,
|
||||||
PreviewState previewState,
|
PreviewState previewState,
|
||||||
mtpRequestId saveRequestId = 0);
|
mtpRequestId saveRequestId = 0);
|
||||||
|
|
||||||
TimeId date = 0;
|
TimeId date = 0;
|
||||||
TextWithTags textWithTags;
|
TextWithTags textWithTags;
|
||||||
MsgId msgId = 0; // replyToId for message draft, editMsgId for edit draft
|
MsgId msgId = 0; // replyToId for message draft, editMsgId for edit draft
|
||||||
|
MsgId topicRootId = 0;
|
||||||
MessageCursor cursor;
|
MessageCursor cursor;
|
||||||
PreviewState previewState = PreviewState::Allowed;
|
PreviewState previewState = PreviewState::Allowed;
|
||||||
mtpRequestId saveRequestId = 0;
|
mtpRequestId saveRequestId = 0;
|
||||||
|
@ -56,70 +61,93 @@ struct Draft {
|
||||||
|
|
||||||
class DraftKey {
|
class DraftKey {
|
||||||
public:
|
public:
|
||||||
[[nodiscard]] static DraftKey None() {
|
[[nodiscard]] static constexpr DraftKey None() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
[[nodiscard]] static DraftKey Local() {
|
[[nodiscard]] static constexpr DraftKey Local(MsgId topicRootId) {
|
||||||
return kLocalDraftIndex;
|
return (topicRootId < 0 || topicRootId >= ServerMaxMsgId)
|
||||||
|
? None()
|
||||||
|
: (topicRootId ? topicRootId.bare : kLocalDraftIndex);
|
||||||
}
|
}
|
||||||
[[nodiscard]] static DraftKey LocalEdit() {
|
[[nodiscard]] static constexpr DraftKey LocalEdit(MsgId topicRootId) {
|
||||||
return kLocalDraftIndex + kEditDraftShift;
|
return (topicRootId < 0 || topicRootId >= ServerMaxMsgId)
|
||||||
|
? None()
|
||||||
|
: ((topicRootId ? topicRootId.bare : kLocalDraftIndex)
|
||||||
|
+ kEditDraftShift);
|
||||||
}
|
}
|
||||||
[[nodiscard]] static DraftKey Cloud() {
|
[[nodiscard]] static constexpr DraftKey Cloud(MsgId topicRootId) {
|
||||||
return kCloudDraftIndex;
|
return (topicRootId < 0 || topicRootId >= ServerMaxMsgId)
|
||||||
|
? None()
|
||||||
|
: topicRootId
|
||||||
|
? (kCloudDraftShift + topicRootId.bare)
|
||||||
|
: kCloudDraftIndex;
|
||||||
}
|
}
|
||||||
[[nodiscard]] static DraftKey Scheduled() {
|
[[nodiscard]] static constexpr DraftKey Scheduled() {
|
||||||
return kScheduledDraftIndex;
|
return kScheduledDraftIndex;
|
||||||
}
|
}
|
||||||
[[nodiscard]] static DraftKey ScheduledEdit() {
|
[[nodiscard]] static constexpr DraftKey ScheduledEdit() {
|
||||||
return kScheduledDraftIndex + kEditDraftShift;
|
return kScheduledDraftIndex + kEditDraftShift;
|
||||||
}
|
}
|
||||||
[[nodiscard]] static DraftKey Replies(MsgId rootId) {
|
|
||||||
return rootId.bare;
|
|
||||||
}
|
|
||||||
[[nodiscard]] static DraftKey RepliesEdit(MsgId rootId) {
|
|
||||||
return rootId.bare + kEditDraftShift;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] static DraftKey FromSerialized(qint64 value) {
|
[[nodiscard]] static constexpr DraftKey FromSerialized(qint64 value) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
[[nodiscard]] qint64 serialize() const {
|
[[nodiscard]] constexpr qint64 serialize() const {
|
||||||
return _value;
|
return _value;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] static DraftKey FromSerializedOld(int32 value);
|
[[nodiscard]] static constexpr DraftKey FromSerializedOld(int32 value) {
|
||||||
|
return !value
|
||||||
|
? None()
|
||||||
|
: (value == kLocalDraftIndex + kEditDraftShiftOld)
|
||||||
|
? LocalEdit(0)
|
||||||
|
: (value == kScheduledDraftIndex + kEditDraftShiftOld)
|
||||||
|
? ScheduledEdit()
|
||||||
|
: (value > 0 && value < 0x4000'0000)
|
||||||
|
? Local(MsgId(value))
|
||||||
|
: (value > kEditDraftShiftOld
|
||||||
|
&& value < kEditDraftShiftOld + 0x4000'000)
|
||||||
|
? LocalEdit(int64(value - kEditDraftShiftOld))
|
||||||
|
: None();
|
||||||
|
}
|
||||||
|
[[nodiscard]] constexpr bool isLocal() const {
|
||||||
|
return (_value == kLocalDraftIndex)
|
||||||
|
|| (_value > 0 && _value < ServerMaxMsgId.bare);
|
||||||
|
}
|
||||||
|
[[nodiscard]] constexpr bool isCloud() const {
|
||||||
|
return (_value == kCloudDraftIndex)
|
||||||
|
|| (_value > kCloudDraftShift
|
||||||
|
&& _value < kCloudDraftShift + ServerMaxMsgId.bare);
|
||||||
|
}
|
||||||
|
|
||||||
inline bool operator<(const DraftKey &other) const {
|
[[nodiscard]] constexpr MsgId topicRootId() const {
|
||||||
return _value < other._value;
|
const auto max = ServerMaxMsgId.bare;
|
||||||
}
|
if (_value > kCloudDraftShift && _value < kCloudDraftShift + max) {
|
||||||
inline bool operator==(const DraftKey &other) const {
|
return (_value - kCloudDraftShift);
|
||||||
return _value == other._value;
|
} else if (_value > kEditDraftShift && _value < kEditDraftShift + max) {
|
||||||
}
|
return (_value - kEditDraftShift);
|
||||||
inline bool operator>(const DraftKey &other) const {
|
} else if (_value > 0 && _value < max) {
|
||||||
return (other < *this);
|
return _value;
|
||||||
}
|
}
|
||||||
inline bool operator<=(const DraftKey &other) const {
|
return 0;
|
||||||
return !(other < *this);
|
|
||||||
}
|
|
||||||
inline bool operator>=(const DraftKey &other) const {
|
|
||||||
return !(*this < other);
|
|
||||||
}
|
|
||||||
inline bool operator!=(const DraftKey &other) const {
|
|
||||||
return !(*this == other);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
friend inline constexpr auto operator<=>(DraftKey, DraftKey) = default;
|
||||||
|
|
||||||
inline explicit operator bool() const {
|
inline explicit operator bool() const {
|
||||||
return _value != 0;
|
return _value != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DraftKey(int64 value) : _value(value) {
|
constexpr DraftKey(int64 value) : _value(value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr auto kLocalDraftIndex = -1;
|
static constexpr auto kLocalDraftIndex = -1;
|
||||||
static constexpr auto kCloudDraftIndex = -2;
|
static constexpr auto kCloudDraftIndex = -2;
|
||||||
static constexpr auto kScheduledDraftIndex = -3;
|
static constexpr auto kScheduledDraftIndex = -3;
|
||||||
static constexpr auto kEditDraftShift = ServerMaxMsgId.bare;
|
static constexpr auto kEditDraftShift = ServerMaxMsgId.bare;
|
||||||
|
static constexpr auto kCloudDraftShift = 2 * ServerMaxMsgId.bare;
|
||||||
static constexpr auto kEditDraftShiftOld = 0x3FFF'FFFF;
|
static constexpr auto kEditDraftShiftOld = 0x3FFF'FFFF;
|
||||||
|
|
||||||
int64 _value = 0;
|
int64 _value = 0;
|
||||||
|
@ -128,7 +156,7 @@ private:
|
||||||
|
|
||||||
using HistoryDrafts = base::flat_map<DraftKey, std::unique_ptr<Draft>>;
|
using HistoryDrafts = base::flat_map<DraftKey, std::unique_ptr<Draft>>;
|
||||||
|
|
||||||
inline bool draftStringIsEmpty(const QString &text) {
|
[[nodiscard]] inline bool DraftStringIsEmpty(const QString &text) {
|
||||||
for (const auto &ch : text) {
|
for (const auto &ch : text) {
|
||||||
if (!ch.isSpace()) {
|
if (!ch.isSpace()) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -137,20 +165,19 @@ inline bool draftStringIsEmpty(const QString &text) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool draftIsNull(const Draft *draft) {
|
[[nodiscard]] inline bool DraftIsNull(const Draft *draft) {
|
||||||
return !draft
|
return !draft
|
||||||
|| (draftStringIsEmpty(draft->textWithTags.text) && !draft->msgId);
|
|| (!draft->msgId && DraftStringIsEmpty(draft->textWithTags.text));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool draftsAreEqual(const Draft *a, const Draft *b) {
|
[[nodiscard]] inline bool DraftsAreEqual(const Draft *a, const Draft *b) {
|
||||||
bool aIsNull = draftIsNull(a);
|
const auto aIsNull = DraftIsNull(a);
|
||||||
bool bIsNull = draftIsNull(b);
|
const auto bIsNull = DraftIsNull(b);
|
||||||
if (aIsNull) {
|
if (aIsNull) {
|
||||||
return bIsNull;
|
return bIsNull;
|
||||||
} else if (bIsNull) {
|
} else if (bIsNull) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (a->textWithTags == b->textWithTags)
|
return (a->textWithTags == b->textWithTags)
|
||||||
&& (a->msgId == b->msgId)
|
&& (a->msgId == b->msgId)
|
||||||
&& (a->previewState == b->previewState);
|
&& (a->previewState == b->previewState);
|
||||||
|
|
|
@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_forum.h"
|
#include "data/data_forum.h"
|
||||||
#include "data/data_histories.h"
|
#include "data/data_histories.h"
|
||||||
#include "data/data_replies_list.h"
|
#include "data/data_replies_list.h"
|
||||||
|
#include "data/data_send_action.h"
|
||||||
#include "data/notify/data_notify_settings.h"
|
#include "data/notify/data_notify_settings.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/stickers/data_custom_emoji.h"
|
#include "data/stickers/data_custom_emoji.h"
|
||||||
|
@ -142,10 +143,15 @@ ForumTopic::ForumTopic(not_null<Forum*> forum, MsgId rootId)
|
||||||
, _forum(forum)
|
, _forum(forum)
|
||||||
, _list(_forum->topicsList())
|
, _list(_forum->topicsList())
|
||||||
, _replies(std::make_shared<RepliesList>(history(), rootId))
|
, _replies(std::make_shared<RepliesList>(history(), rootId))
|
||||||
|
, _sendActionPainter(owner().sendActionManager().repliesPainter(
|
||||||
|
history(),
|
||||||
|
rootId))
|
||||||
, _rootId(rootId)
|
, _rootId(rootId)
|
||||||
, _lastKnownServerMessageId(rootId) {
|
, _lastKnownServerMessageId(rootId) {
|
||||||
Thread::setMuted(owner().notifySettings().isMuted(this));
|
Thread::setMuted(owner().notifySettings().isMuted(this));
|
||||||
|
|
||||||
|
_sendActionPainter->setTopic(this);
|
||||||
|
|
||||||
_replies->unreadCountValue(
|
_replies->unreadCountValue(
|
||||||
) | rpl::combine_previous(
|
) | rpl::combine_previous(
|
||||||
) | rpl::filter([=] {
|
) | rpl::filter([=] {
|
||||||
|
@ -161,6 +167,7 @@ ForumTopic::ForumTopic(not_null<Forum*> forum, MsgId rootId)
|
||||||
}
|
}
|
||||||
|
|
||||||
ForumTopic::~ForumTopic() {
|
ForumTopic::~ForumTopic() {
|
||||||
|
_sendActionPainter->setTopic(nullptr);
|
||||||
session().api().unreadThings().cancelRequests(this);
|
session().api().unreadThings().cancelRequests(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,11 +198,24 @@ MsgId ForumTopic::rootId() const {
|
||||||
return _rootId;
|
return _rootId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ForumTopic::creating() const {
|
||||||
|
return _forum->creating(_rootId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ForumTopic::discard() {
|
||||||
|
Expects(creating());
|
||||||
|
|
||||||
|
_forum->discardCreatingId(_rootId);
|
||||||
|
}
|
||||||
|
|
||||||
void ForumTopic::setRealRootId(MsgId realId) {
|
void ForumTopic::setRealRootId(MsgId realId) {
|
||||||
if (_rootId != realId) {
|
if (_rootId != realId) {
|
||||||
_rootId = realId;
|
_rootId = realId;
|
||||||
_lastKnownServerMessageId = realId;
|
_lastKnownServerMessageId = realId;
|
||||||
_replies = std::make_shared<RepliesList>(history(), _rootId);
|
_replies = std::make_shared<RepliesList>(history(), _rootId);
|
||||||
|
_sendActionPainter = owner().sendActionManager().repliesPainter(
|
||||||
|
history(),
|
||||||
|
_rootId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,6 +241,15 @@ void ForumTopic::applyTopic(const MTPDforumTopic &data) {
|
||||||
|
|
||||||
owner().notifySettings().apply(this, data.vnotify_settings());
|
owner().notifySettings().apply(this, data.vnotify_settings());
|
||||||
|
|
||||||
|
const auto draft = data.vdraft();
|
||||||
|
if (draft && draft->type() == mtpc_draftMessage) {
|
||||||
|
Data::ApplyPeerCloudDraft(
|
||||||
|
&session(),
|
||||||
|
channel()->id,
|
||||||
|
_rootId,
|
||||||
|
draft->c_draftMessage());
|
||||||
|
}
|
||||||
|
|
||||||
_replies->setInboxReadTill(
|
_replies->setInboxReadTill(
|
||||||
data.vread_inbox_max_id().v,
|
data.vread_inbox_max_id().v,
|
||||||
data.vunread_count().v);
|
data.vunread_count().v);
|
||||||
|
@ -390,13 +419,11 @@ void ForumTopic::requestChatListMessage() {
|
||||||
|
|
||||||
TimeId ForumTopic::adjustedChatListTimeId() const {
|
TimeId ForumTopic::adjustedChatListTimeId() const {
|
||||||
const auto result = chatListTimeId();
|
const auto result = chatListTimeId();
|
||||||
#if 0 // #TODO forum draft
|
if (const auto draft = history()->cloudDraft(_rootId)) {
|
||||||
if (const auto draft = cloudDraft()) {
|
if (!Data::DraftIsNull(draft) && !session().supportMode()) {
|
||||||
if (!Data::draftIsNull(draft) && !session().supportMode()) {
|
|
||||||
return std::max(result, draft->date);
|
return std::max(result, draft->date);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -480,6 +507,17 @@ void ForumTopic::applyItemAdded(not_null<HistoryItem*> item) {
|
||||||
setLastMessage(item);
|
setLastMessage(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ForumTopic::maybeSetLastMessage(not_null<HistoryItem*> item) {
|
||||||
|
Expects(item->topicRootId() == _rootId);
|
||||||
|
|
||||||
|
if (!_lastMessage
|
||||||
|
|| ((*_lastMessage)->date() < item->date())
|
||||||
|
|| ((*_lastMessage)->date() == item->date()
|
||||||
|
&& (*_lastMessage)->id < item->id)) {
|
||||||
|
setLastMessage(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ForumTopic::applyItemRemoved(MsgId id) {
|
void ForumTopic::applyItemRemoved(MsgId id) {
|
||||||
if (const auto lastItem = lastMessage()) {
|
if (const auto lastItem = lastMessage()) {
|
||||||
if (lastItem->id == id) {
|
if (lastItem->id == id) {
|
||||||
|
@ -499,6 +537,11 @@ void ForumTopic::applyItemRemoved(MsgId id) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ForumTopic::isServerSideUnread(
|
||||||
|
not_null<const HistoryItem*> item) const {
|
||||||
|
return _replies->isServerSideUnread(item);
|
||||||
|
}
|
||||||
|
|
||||||
int ForumTopic::unreadCount() const {
|
int ForumTopic::unreadCount() const {
|
||||||
return _replies->unreadCountCurrent();
|
return _replies->unreadCountCurrent();
|
||||||
}
|
}
|
||||||
|
@ -544,6 +587,10 @@ void ForumTopic::setUnreadMark(bool unread) {
|
||||||
Thread::setUnreadMark(unread);
|
Thread::setUnreadMark(unread);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
not_null<HistoryView::SendActionPainter*> ForumTopic::sendActionPainter() {
|
||||||
|
return _sendActionPainter.get();
|
||||||
|
}
|
||||||
|
|
||||||
int ForumTopic::chatListUnreadCount() const {
|
int ForumTopic::chatListUnreadCount() const {
|
||||||
const auto state = chatListUnreadState();
|
const auto state = chatListUnreadState();
|
||||||
return state.marks
|
return state.marks
|
||||||
|
|
|
@ -25,6 +25,10 @@ namespace Main {
|
||||||
class Session;
|
class Session;
|
||||||
} // namespace Main
|
} // namespace Main
|
||||||
|
|
||||||
|
namespace HistoryView {
|
||||||
|
class SendActionPainter;
|
||||||
|
} // namespace HistoryView
|
||||||
|
|
||||||
namespace Data {
|
namespace Data {
|
||||||
|
|
||||||
class RepliesList;
|
class RepliesList;
|
||||||
|
@ -57,6 +61,9 @@ public:
|
||||||
[[nodiscard]] rpl::producer<> destroyed() const;
|
[[nodiscard]] rpl::producer<> destroyed() const;
|
||||||
[[nodiscard]] MsgId rootId() const;
|
[[nodiscard]] MsgId rootId() const;
|
||||||
|
|
||||||
|
[[nodiscard]] bool creating() const;
|
||||||
|
void discard();
|
||||||
|
|
||||||
void setRealRootId(MsgId realId);
|
void setRealRootId(MsgId realId);
|
||||||
|
|
||||||
void applyTopic(const MTPDforumTopic &data);
|
void applyTopic(const MTPDforumTopic &data);
|
||||||
|
@ -91,6 +98,7 @@ public:
|
||||||
void applyColorId(int32 colorId);
|
void applyColorId(int32 colorId);
|
||||||
void applyItemAdded(not_null<HistoryItem*> item);
|
void applyItemAdded(not_null<HistoryItem*> item);
|
||||||
void applyItemRemoved(MsgId id);
|
void applyItemRemoved(MsgId id);
|
||||||
|
void maybeSetLastMessage(not_null<HistoryItem*> item);
|
||||||
|
|
||||||
[[nodiscard]] PeerNotifySettings ¬ify() {
|
[[nodiscard]] PeerNotifySettings ¬ify() {
|
||||||
return _notify;
|
return _notify;
|
||||||
|
@ -105,6 +113,9 @@ public:
|
||||||
std::shared_ptr<CloudImageView> &view,
|
std::shared_ptr<CloudImageView> &view,
|
||||||
const Dialogs::Ui::PaintContext &context) const override;
|
const Dialogs::Ui::PaintContext &context) const override;
|
||||||
|
|
||||||
|
[[nodiscard]] bool isServerSideUnread(
|
||||||
|
not_null<const HistoryItem*> item) const override;
|
||||||
|
|
||||||
[[nodiscard]] int unreadCount() const;
|
[[nodiscard]] int unreadCount() const;
|
||||||
[[nodiscard]] bool unreadCountKnown() const;
|
[[nodiscard]] bool unreadCountKnown() const;
|
||||||
|
|
||||||
|
@ -113,6 +124,9 @@ public:
|
||||||
void setMuted(bool muted) override;
|
void setMuted(bool muted) override;
|
||||||
void setUnreadMark(bool unread) override;
|
void setUnreadMark(bool unread) override;
|
||||||
|
|
||||||
|
[[nodiscard]] auto sendActionPainter()
|
||||||
|
->not_null<HistoryView::SendActionPainter*> override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void indexTitleParts();
|
void indexTitleParts();
|
||||||
void validateDefaultIcon() const;
|
void validateDefaultIcon() const;
|
||||||
|
@ -132,6 +146,7 @@ private:
|
||||||
const not_null<Forum*> _forum;
|
const not_null<Forum*> _forum;
|
||||||
const not_null<Dialogs::MainList*> _list;
|
const not_null<Dialogs::MainList*> _list;
|
||||||
std::shared_ptr<RepliesList> _replies;
|
std::shared_ptr<RepliesList> _replies;
|
||||||
|
std::shared_ptr<HistoryView::SendActionPainter> _sendActionPainter;
|
||||||
MsgId _rootId = 0;
|
MsgId _rootId = 0;
|
||||||
MsgId _lastKnownServerMessageId = 0;
|
MsgId _lastKnownServerMessageId = 0;
|
||||||
|
|
||||||
|
|
|
@ -247,7 +247,7 @@ void Histories::readInboxOnNewMessage(not_null<HistoryItem*> item) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Histories::readClientSideMessage(not_null<HistoryItem*> item) {
|
void Histories::readClientSideMessage(not_null<HistoryItem*> item) {
|
||||||
if (item->out() || !item->unread()) {
|
if (item->out() || !item->unread(item->history())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto history = item->history();
|
const auto history = item->history();
|
||||||
|
@ -886,20 +886,22 @@ bool Histories::isCreatingTopic(
|
||||||
int Histories::sendPreparedMessage(
|
int Histories::sendPreparedMessage(
|
||||||
not_null<History*> history,
|
not_null<History*> history,
|
||||||
MsgId replyTo,
|
MsgId replyTo,
|
||||||
|
MsgId topicRootId,
|
||||||
uint64 randomId,
|
uint64 randomId,
|
||||||
Fn<PreparedMessage(MsgId replyTo)> message,
|
Fn<PreparedMessage(MsgId replyTo, MsgId topicRootId)> message,
|
||||||
Fn<void(const MTPUpdates&, const MTP::Response&)> done,
|
Fn<void(const MTPUpdates&, const MTP::Response&)> done,
|
||||||
Fn<void(const MTP::Error&, const MTP::Response&)> fail) {
|
Fn<void(const MTP::Error&, const MTP::Response&)> fail) {
|
||||||
if (isCreatingTopic(history, replyTo)) {
|
if (isCreatingTopic(history, topicRootId)) {
|
||||||
const auto id = ++_requestAutoincrement;
|
const auto id = ++_requestAutoincrement;
|
||||||
const auto creatingId = FullMsgId(history->peer->id, replyTo);
|
const auto creatingId = FullMsgId(history->peer->id, topicRootId);
|
||||||
auto i = _creatingTopics.find(creatingId);
|
auto i = _creatingTopics.find(creatingId);
|
||||||
if (i == end(_creatingTopics)) {
|
if (i == end(_creatingTopics)) {
|
||||||
sendCreateTopicRequest(history, replyTo);
|
sendCreateTopicRequest(history, topicRootId);
|
||||||
i = _creatingTopics.emplace(creatingId).first;
|
i = _creatingTopics.emplace(creatingId).first;
|
||||||
}
|
}
|
||||||
i->second.push_back({
|
i->second.push_back({
|
||||||
.randomId = randomId,
|
.randomId = randomId,
|
||||||
|
.replyTo = replyTo,
|
||||||
.message = std::move(message),
|
.message = std::move(message),
|
||||||
.done = std::move(done),
|
.done = std::move(done),
|
||||||
.fail = std::move(fail),
|
.fail = std::move(fail),
|
||||||
|
@ -908,8 +910,9 @@ int Histories::sendPreparedMessage(
|
||||||
_creatingTopicRequests.emplace(id);
|
_creatingTopicRequests.emplace(id);
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
const auto realTo = convertTopicReplyTo(history, replyTo);
|
const auto realReply = convertTopicReplyTo(history, replyTo);
|
||||||
return v::match(message(realTo), [&](const auto &request) {
|
const auto realRoot = convertTopicReplyTo(history, topicRootId);
|
||||||
|
return v::match(message(realReply, realRoot), [&](const auto &request) {
|
||||||
const auto type = RequestType::Send;
|
const auto type = RequestType::Send;
|
||||||
return sendRequest(history, type, [=](Fn<void()> finish) {
|
return sendRequest(history, type, [=](Fn<void()> finish) {
|
||||||
const auto session = &_owner->session();
|
const auto session = &_owner->session();
|
||||||
|
@ -935,38 +938,38 @@ int Histories::sendPreparedMessage(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Histories::checkTopicCreated(FullMsgId rootId, MsgId realId) {
|
void Histories::checkTopicCreated(FullMsgId rootId, MsgId realRoot) {
|
||||||
const auto i = _creatingTopics.find(rootId);
|
const auto i = _creatingTopics.find(rootId);
|
||||||
if (i != end(_creatingTopics)) {
|
if (i != end(_creatingTopics)) {
|
||||||
auto scheduled = base::take(i->second);
|
auto scheduled = base::take(i->second);
|
||||||
_creatingTopics.erase(i);
|
_creatingTopics.erase(i);
|
||||||
|
|
||||||
_createdTopicIds.emplace(rootId, realId);
|
_createdTopicIds.emplace(rootId, realRoot);
|
||||||
|
|
||||||
if (const auto forum = _owner->peer(rootId.peer)->forum()) {
|
if (const auto forum = _owner->peer(rootId.peer)->forum()) {
|
||||||
forum->created(rootId.msg, realId);
|
forum->created(rootId.msg, realRoot);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto history = _owner->history(rootId.peer);
|
const auto history = _owner->history(rootId.peer);
|
||||||
for (auto &entry : scheduled) {
|
for (auto &entry : scheduled) {
|
||||||
_creatingTopicRequests.erase(entry.requestId);
|
_creatingTopicRequests.erase(entry.requestId);
|
||||||
AssertIsDebug();
|
sendPreparedMessage(
|
||||||
//sendPreparedMessage(
|
history,
|
||||||
// history,
|
entry.replyTo,
|
||||||
// realId,
|
realRoot,
|
||||||
// entry.randomId,
|
entry.randomId,
|
||||||
// std::move(entry.message),
|
std::move(entry.message),
|
||||||
// std::move(entry.done),
|
std::move(entry.done),
|
||||||
// std::move(entry.fail));
|
std::move(entry.fail));
|
||||||
}
|
}
|
||||||
for (const auto &item : history->clientSideMessages()) {
|
for (const auto &item : history->clientSideMessages()) {
|
||||||
const auto replace = [&](MsgId nowId) {
|
const auto replace = [&](MsgId nowId) {
|
||||||
return (nowId == rootId.msg) ? realId : nowId;
|
return (nowId == rootId.msg) ? realRoot : nowId;
|
||||||
};
|
};
|
||||||
if (item->replyToTop() == rootId.msg) {
|
if (item->topicRootId() == rootId.msg) {
|
||||||
item->setReplyFields(
|
item->setReplyFields(
|
||||||
replace(item->replyToId()),
|
replace(item->replyToId()),
|
||||||
realId,
|
realRoot,
|
||||||
true);
|
true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,22 +103,25 @@ public:
|
||||||
int sendPreparedMessage(
|
int sendPreparedMessage(
|
||||||
not_null<History*> history,
|
not_null<History*> history,
|
||||||
MsgId replyTo,
|
MsgId replyTo,
|
||||||
|
MsgId topicRootId,
|
||||||
uint64 randomId,
|
uint64 randomId,
|
||||||
Fn<PreparedMessage(MsgId replyTo)> message,
|
Fn<PreparedMessage(MsgId replyTo, MsgId topicRootId)> message,
|
||||||
Fn<void(const MTPUpdates&, const MTP::Response&)> done,
|
Fn<void(const MTPUpdates&, const MTP::Response&)> done,
|
||||||
Fn<void(const MTP::Error&, const MTP::Response&)> fail);
|
Fn<void(const MTP::Error&, const MTP::Response&)> fail);
|
||||||
|
|
||||||
struct ReplyToPlaceholder {
|
struct ReplyToPlaceholder {
|
||||||
};
|
};
|
||||||
|
struct TopicRootPlaceholder {
|
||||||
|
};
|
||||||
template <typename RequestType, typename ...Args>
|
template <typename RequestType, typename ...Args>
|
||||||
static Fn<Histories::PreparedMessage(MsgId)> PrepareMessage(
|
static Fn<Histories::PreparedMessage(MsgId, MsgId)> PrepareMessage(
|
||||||
const Args &...args) {
|
const Args &...args) {
|
||||||
return [=](MsgId replyTo) {
|
return [=](MsgId replyTo, MsgId topicRootId) -> RequestType {
|
||||||
return RequestType(ReplaceReplyTo(args, replyTo)...);
|
return { ReplaceReplyIds(args, replyTo, topicRootId)... };
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void checkTopicCreated(FullMsgId rootId, MsgId realId);
|
void checkTopicCreated(FullMsgId rootId, MsgId realRoot);
|
||||||
[[nodiscard]] MsgId convertTopicReplyTo(
|
[[nodiscard]] MsgId convertTopicReplyTo(
|
||||||
not_null<History*> history,
|
not_null<History*> history,
|
||||||
MsgId replyTo) const;
|
MsgId replyTo) const;
|
||||||
|
@ -147,7 +150,8 @@ private:
|
||||||
};
|
};
|
||||||
struct DelayedByTopicMessage {
|
struct DelayedByTopicMessage {
|
||||||
uint64 randomId = 0;
|
uint64 randomId = 0;
|
||||||
Fn<PreparedMessage(MsgId replyTo)> message;
|
MsgId replyTo = 0;
|
||||||
|
Fn<PreparedMessage(MsgId replyTo, MsgId topicRootId)> message;
|
||||||
Fn<void(const MTPUpdates&, const MTP::Response&)> done;
|
Fn<void(const MTPUpdates&, const MTP::Response&)> done;
|
||||||
Fn<void(const MTP::Error&, const MTP::Response&)> fail;
|
Fn<void(const MTP::Error&, const MTP::Response&)> fail;
|
||||||
int requestId = 0;
|
int requestId = 0;
|
||||||
|
@ -162,9 +166,11 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Arg>
|
template <typename Arg>
|
||||||
static auto ReplaceReplyTo(Arg arg, MsgId replyTo) {
|
static auto ReplaceReplyIds(Arg arg, MsgId replyTo, MsgId topicRootId) {
|
||||||
if constexpr (std::is_same_v<Arg, ReplyToPlaceholder>) {
|
if constexpr (std::is_same_v<Arg, ReplyToPlaceholder>) {
|
||||||
return MTP_int(replyTo);
|
return MTP_int(replyTo);
|
||||||
|
} else if constexpr (std::is_same_v<Arg, TopicRootPlaceholder>) {
|
||||||
|
return MTP_int(topicRootId);
|
||||||
} else {
|
} else {
|
||||||
return arg;
|
return arg;
|
||||||
}
|
}
|
||||||
|
|
|
@ -765,6 +765,14 @@ void RepliesList::setUnreadCount(std::optional<int> count) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool RepliesList::isServerSideUnread(
|
||||||
|
not_null<const HistoryItem*> item) const {
|
||||||
|
const auto till = item->out()
|
||||||
|
? computeOutboxReadTillFull()
|
||||||
|
: computeInboxReadTillFull();
|
||||||
|
return (item->id > till);
|
||||||
|
}
|
||||||
|
|
||||||
void RepliesList::checkReadTillEnd() {
|
void RepliesList::checkReadTillEnd() {
|
||||||
if (_unreadCount.current() != 0
|
if (_unreadCount.current() != 0
|
||||||
&& _skippedAfter == 0
|
&& _skippedAfter == 0
|
||||||
|
|
|
@ -43,6 +43,9 @@ public:
|
||||||
void setOutboxReadTill(MsgId readTillId);
|
void setOutboxReadTill(MsgId readTillId);
|
||||||
[[nodiscard]] MsgId computeOutboxReadTillFull() const;
|
[[nodiscard]] MsgId computeOutboxReadTillFull() const;
|
||||||
|
|
||||||
|
[[nodiscard]] bool isServerSideUnread(
|
||||||
|
not_null<const HistoryItem*> item) const;
|
||||||
|
|
||||||
[[nodiscard]] std::optional<int> computeUnreadCountLocally(
|
[[nodiscard]] std::optional<int> computeUnreadCountLocally(
|
||||||
MsgId afterId) const;
|
MsgId afterId) const;
|
||||||
void requestUnreadCount();
|
void requestUnreadCount();
|
||||||
|
|
|
@ -75,7 +75,7 @@ auto SendActionManager::repliesPainter(
|
||||||
if (auto strong = weak.lock()) {
|
if (auto strong = weak.lock()) {
|
||||||
return strong;
|
return strong;
|
||||||
}
|
}
|
||||||
auto result = std::make_shared<SendActionPainter>(history);
|
auto result = std::make_shared<SendActionPainter>(history, rootId);
|
||||||
weak = result;
|
weak = result;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,10 +17,12 @@ class SendActionPainter;
|
||||||
|
|
||||||
namespace Data {
|
namespace Data {
|
||||||
|
|
||||||
|
class Thread;
|
||||||
|
|
||||||
class SendActionManager final {
|
class SendActionManager final {
|
||||||
public:
|
public:
|
||||||
struct AnimationUpdate {
|
struct AnimationUpdate {
|
||||||
not_null<History*> history;
|
not_null<Thread*> thread;
|
||||||
int left = 0;
|
int left = 0;
|
||||||
int width = 0;
|
int width = 0;
|
||||||
int height = 0;
|
int height = 0;
|
||||||
|
|
|
@ -3820,7 +3820,7 @@ void Session::refreshChatListEntry(Dialogs::Key key) {
|
||||||
const auto mainList = chatsListFor(entry);
|
const auto mainList = chatsListFor(entry);
|
||||||
auto event = ChatListEntryRefresh{ .key = key };
|
auto event = ChatListEntryRefresh{ .key = key };
|
||||||
const auto creating = event.existenceChanged = !entry->inChatList();
|
const auto creating = event.existenceChanged = !entry->inChatList();
|
||||||
if (creating && topic && topic->forum()->creating(topic->rootId())) {
|
if (creating && topic && topic->creating()) {
|
||||||
return;
|
return;
|
||||||
} else if (event.existenceChanged) {
|
} else if (event.existenceChanged) {
|
||||||
const auto mainRow = entry->addToChatList(0, mainList);
|
const auto mainRow = entry->addToChatList(0, mainList);
|
||||||
|
|
|
@ -17,6 +17,13 @@ namespace Data {
|
||||||
|
|
||||||
Thread::~Thread() = default;
|
Thread::~Thread() = default;
|
||||||
|
|
||||||
|
MsgId Thread::topicRootId() const {
|
||||||
|
if (const auto topic = asTopic()) {
|
||||||
|
return topic->rootId();
|
||||||
|
}
|
||||||
|
return MsgId();
|
||||||
|
}
|
||||||
|
|
||||||
not_null<PeerData*> Thread::peer() const {
|
not_null<PeerData*> Thread::peer() const {
|
||||||
return owningHistory()->peer;
|
return owningHistory()->peer;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,10 @@ class Proxy;
|
||||||
class ConstProxy;
|
class ConstProxy;
|
||||||
} // namespace HistoryUnreadThings
|
} // namespace HistoryUnreadThings
|
||||||
|
|
||||||
|
namespace HistoryView {
|
||||||
|
class SendActionPainter;
|
||||||
|
} // namespace HistoryView
|
||||||
|
|
||||||
namespace st {
|
namespace st {
|
||||||
extern const int &dialogsTextWidthMin;
|
extern const int &dialogsTextWidthMin;
|
||||||
} // namespace st
|
} // namespace st
|
||||||
|
@ -57,6 +61,7 @@ public:
|
||||||
[[nodiscard]] not_null<const History*> owningHistory() const {
|
[[nodiscard]] not_null<const History*> owningHistory() const {
|
||||||
return const_cast<Thread*>(this)->owningHistory();
|
return const_cast<Thread*>(this)->owningHistory();
|
||||||
}
|
}
|
||||||
|
[[nodiscard]] MsgId topicRootId() const;
|
||||||
[[nodiscard]] not_null<PeerData*> peer() const;
|
[[nodiscard]] not_null<PeerData*> peer() const;
|
||||||
[[nodiscard]] PeerNotifySettings ¬ify();
|
[[nodiscard]] PeerNotifySettings ¬ify();
|
||||||
[[nodiscard]] const PeerNotifySettings ¬ify() const;
|
[[nodiscard]] const PeerNotifySettings ¬ify() const;
|
||||||
|
@ -87,6 +92,9 @@ public:
|
||||||
}
|
}
|
||||||
virtual void setUnreadMark(bool unread);
|
virtual void setUnreadMark(bool unread);
|
||||||
|
|
||||||
|
[[nodiscard]] virtual bool isServerSideUnread(
|
||||||
|
not_null<const HistoryItem*> item) const = 0;
|
||||||
|
|
||||||
[[nodiscard]] const base::flat_set<MsgId> &unreadMentionsIds() const;
|
[[nodiscard]] const base::flat_set<MsgId> &unreadMentionsIds() const;
|
||||||
[[nodiscard]] const base::flat_set<MsgId> &unreadReactionsIds() const;
|
[[nodiscard]] const base::flat_set<MsgId> &unreadReactionsIds() const;
|
||||||
|
|
||||||
|
@ -97,6 +105,9 @@ public:
|
||||||
return _lastItemDialogsView;
|
return _lastItemDialogsView;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] virtual auto sendActionPainter()
|
||||||
|
-> not_null<HistoryView::SendActionPainter*> = 0;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum class Flag : uchar {
|
enum class Flag : uchar {
|
||||||
UnreadMark = (1 << 0),
|
UnreadMark = (1 << 0),
|
||||||
|
|
|
@ -185,7 +185,7 @@ InnerWidget::InnerWidget(
|
||||||
width(),
|
width(),
|
||||||
update.textUpdated);
|
update.textUpdated);
|
||||||
updateDialogRow(
|
updateDialogRow(
|
||||||
RowDescriptor(update.history, FullMsgId()),
|
RowDescriptor(update.thread, FullMsgId()),
|
||||||
updateRect,
|
updateRect,
|
||||||
UpdateRowSection::Default | UpdateRowSection::Filtered);
|
UpdateRowSection::Default | UpdateRowSection::Filtered);
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
@ -2394,8 +2394,10 @@ void InnerWidget::refreshEmptyLabel() {
|
||||||
const auto data = &session().data();
|
const auto data = &session().data();
|
||||||
const auto state = !shownDialogs()->empty()
|
const auto state = !shownDialogs()->empty()
|
||||||
? EmptyState::None
|
? EmptyState::None
|
||||||
: (_openedForum && _openedForum->topicsList()->loaded())
|
: _openedForum
|
||||||
? EmptyState::EmptyForum
|
? (_openedForum->topicsList()->loaded()
|
||||||
|
? EmptyState::EmptyForum
|
||||||
|
: EmptyState::Loading)
|
||||||
: (!_filterId && data->contactsLoaded().current())
|
: (!_filterId && data->contactsLoaded().current())
|
||||||
? EmptyState::NoContacts
|
? EmptyState::NoContacts
|
||||||
: (_filterId > 0) && data->chatsList()->loaded()
|
: (_filterId > 0) && data->chatsList()->loaded()
|
||||||
|
|
|
@ -19,12 +19,18 @@ Key::Key(History *history) : _value(history) {
|
||||||
Key::Key(Data::Folder *folder) : _value(folder) {
|
Key::Key(Data::Folder *folder) : _value(folder) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Key::Key(Data::Thread *thread) : _value(thread) {
|
||||||
|
}
|
||||||
|
|
||||||
Key::Key(Data::ForumTopic *topic) : _value(topic) {
|
Key::Key(Data::ForumTopic *topic) : _value(topic) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Key::Key(not_null<History*> history) : _value(history) {
|
Key::Key(not_null<History*> history) : _value(history) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Key::Key(not_null<Data::Thread*> thread) : _value(thread) {
|
||||||
|
}
|
||||||
|
|
||||||
Key::Key(not_null<Data::Folder*> folder) : _value(folder) {
|
Key::Key(not_null<Data::Folder*> folder) : _value(folder) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,10 +27,12 @@ public:
|
||||||
}
|
}
|
||||||
Key(History *history);
|
Key(History *history);
|
||||||
Key(Data::Folder *folder);
|
Key(Data::Folder *folder);
|
||||||
|
Key(Data::Thread *thread);
|
||||||
Key(Data::ForumTopic *topic);
|
Key(Data::ForumTopic *topic);
|
||||||
Key(not_null<Entry*> entry) : _value(entry) {
|
Key(not_null<Entry*> entry) : _value(entry) {
|
||||||
}
|
}
|
||||||
Key(not_null<History*> history);
|
Key(not_null<History*> history);
|
||||||
|
Key(not_null<Data::Thread*> thread);
|
||||||
Key(not_null<Data::Folder*> folder);
|
Key(not_null<Data::Folder*> folder);
|
||||||
Key(not_null<Data::ForumTopic*> topic);
|
Key(not_null<Data::ForumTopic*> topic);
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,8 @@ const auto kPsaBadgePrefix = "cloud_lng_badge_psa_";
|
||||||
return user->isBot() && !user->isSupport() && !user->isRepliesChat();
|
return user->isBot() && !user->isSupport() && !user->isRepliesChat();
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] bool ShowSendActionInDialogs(History *history) {
|
[[nodiscard]] bool ShowSendActionInDialogs(Data::Thread *thread) {
|
||||||
|
const auto history = thread ? thread->owningHistory().get() : nullptr;
|
||||||
return history
|
return history
|
||||||
&& (!history->peer->isUser()
|
&& (!history->peer->isUser()
|
||||||
|| history->peer->asUser()->onlineTill > 0);
|
|| history->peer->asUser()->onlineTill > 0);
|
||||||
|
@ -465,8 +466,8 @@ void PaintRow(
|
||||||
: context.selected
|
: context.selected
|
||||||
? st::dialogsTextFgServiceOver
|
? st::dialogsTextFgServiceOver
|
||||||
: st::dialogsTextFgService;
|
: st::dialogsTextFgService;
|
||||||
if (!ShowSendActionInDialogs(history)
|
if (!ShowSendActionInDialogs(thread)
|
||||||
|| !history->sendActionPainter()->paint(
|
|| !thread->sendActionPainter()->paint(
|
||||||
p,
|
p,
|
||||||
nameleft,
|
nameleft,
|
||||||
texttop,
|
texttop,
|
||||||
|
@ -474,7 +475,8 @@ void PaintRow(
|
||||||
context.width,
|
context.width,
|
||||||
color,
|
color,
|
||||||
context.paused)) {
|
context.paused)) {
|
||||||
if (history->cloudDraftTextCache().isEmpty()) {
|
auto &cache = thread->cloudDraftTextCache();
|
||||||
|
if (cache.isEmpty()) {
|
||||||
using namespace TextUtilities;
|
using namespace TextUtilities;
|
||||||
auto draftWrapped = Text::PlainLink(
|
auto draftWrapped = Text::PlainLink(
|
||||||
tr::lng_dialogs_text_from_wrapped(
|
tr::lng_dialogs_text_from_wrapped(
|
||||||
|
@ -496,10 +498,10 @@ void PaintRow(
|
||||||
}),
|
}),
|
||||||
Text::WithEntities);
|
Text::WithEntities);
|
||||||
const auto context = Core::MarkedTextContext{
|
const auto context = Core::MarkedTextContext{
|
||||||
.session = &history->session(),
|
.session = &thread->session(),
|
||||||
.customEmojiRepaint = customEmojiRepaint,
|
.customEmojiRepaint = customEmojiRepaint,
|
||||||
};
|
};
|
||||||
history->cloudDraftTextCache().setMarkedText(
|
cache.setMarkedText(
|
||||||
st::dialogsTextStyle,
|
st::dialogsTextStyle,
|
||||||
draftText,
|
draftText,
|
||||||
DialogTextOptions(),
|
DialogTextOptions(),
|
||||||
|
@ -510,7 +512,7 @@ void PaintRow(
|
||||||
: context.selected
|
: context.selected
|
||||||
? st::dialogsTextFgOver
|
? st::dialogsTextFgOver
|
||||||
: st::dialogsTextFg);
|
: st::dialogsTextFg);
|
||||||
history->cloudDraftTextCache().draw(p, {
|
cache.draw(p, {
|
||||||
.position = { nameleft, texttop },
|
.position = { nameleft, texttop },
|
||||||
.availableWidth = availableWidth,
|
.availableWidth = availableWidth,
|
||||||
.palette = &(supportMode
|
.palette = &(supportMode
|
||||||
|
@ -549,8 +551,8 @@ void PaintRow(
|
||||||
? st::dialogsTextFgServiceOver
|
? st::dialogsTextFgServiceOver
|
||||||
: st::dialogsTextFgService;
|
: st::dialogsTextFgService;
|
||||||
p.setFont(st::dialogsTextFont);
|
p.setFont(st::dialogsTextFont);
|
||||||
if (!ShowSendActionInDialogs(history)
|
if (!ShowSendActionInDialogs(thread)
|
||||||
|| !history->sendActionPainter()->paint(
|
|| !thread->sendActionPainter()->paint(
|
||||||
p,
|
p,
|
||||||
nameleft,
|
nameleft,
|
||||||
texttop,
|
texttop,
|
||||||
|
@ -575,8 +577,10 @@ void PaintRow(
|
||||||
: st::dialogsPinnedIcon;
|
: st::dialogsPinnedIcon;
|
||||||
icon.paint(p, context.width - context.st->padding.right() - icon.width(), texttop, context.width);
|
icon.paint(p, context.width - context.st->padding.right() - icon.width(), texttop, context.width);
|
||||||
}
|
}
|
||||||
auto sendStateIcon = [&]() -> const style::icon* {
|
const auto sendStateIcon = [&]() -> const style::icon* {
|
||||||
if (draft) {
|
if (!thread) {
|
||||||
|
return nullptr;
|
||||||
|
} else if (draft) {
|
||||||
if (draft->saveRequestId) {
|
if (draft->saveRequestId) {
|
||||||
return &(context.active
|
return &(context.active
|
||||||
? st::dialogsSendingIconActive
|
? st::dialogsSendingIconActive
|
||||||
|
@ -586,7 +590,7 @@ void PaintRow(
|
||||||
}
|
}
|
||||||
} else if (item && !item->isEmpty() && item->needCheck()) {
|
} else if (item && !item->isEmpty() && item->needCheck()) {
|
||||||
if (!item->isSending() && !item->hasFailed()) {
|
if (!item->isSending() && !item->hasFailed()) {
|
||||||
if (item->unread()) {
|
if (item->unread(thread)) {
|
||||||
return &(context.active
|
return &(context.active
|
||||||
? st::dialogsSentIconActive
|
? st::dialogsSentIconActive
|
||||||
: context.selected
|
: context.selected
|
||||||
|
@ -607,7 +611,7 @@ void PaintRow(
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}();
|
}();
|
||||||
if (sendStateIcon && history) {
|
if (sendStateIcon) {
|
||||||
rectForName.setWidth(rectForName.width() - st::dialogsSendStateSkip);
|
rectForName.setWidth(rectForName.width() - st::dialogsSendStateSkip);
|
||||||
sendStateIcon->paint(p, rectForName.topLeft() + QPoint(rectForName.width(), 0), context.width);
|
sendStateIcon->paint(p, rectForName.topLeft() + QPoint(rectForName.width(), 0), context.width);
|
||||||
}
|
}
|
||||||
|
@ -892,12 +896,12 @@ void RowPainter::Paint(
|
||||||
const auto unreadMuted = entry->chatListMutedBadge();
|
const auto unreadMuted = entry->chatListMutedBadge();
|
||||||
const auto item = entry->chatListMessage();
|
const auto item = entry->chatListMessage();
|
||||||
const auto cloudDraft = [&]() -> const Data::Draft*{
|
const auto cloudDraft = [&]() -> const Data::Draft*{
|
||||||
if (history && (!item || (!unreadCount && !unreadMark))) {
|
if (thread && (!item || (!unreadCount && !unreadMark))) {
|
||||||
// Draw item, if there are unread messages.
|
// Draw item, if there are unread messages.
|
||||||
if (const auto draft = history->cloudDraft()) {
|
const auto draft = thread->owningHistory()->cloudDraft(
|
||||||
if (!Data::draftIsNull(draft)) {
|
thread->topicRootId());
|
||||||
return draft;
|
if (!Data::DraftIsNull(draft)) {
|
||||||
}
|
return draft;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -977,8 +981,8 @@ void RowPainter::Paint(
|
||||||
texttop,
|
texttop,
|
||||||
availableWidth,
|
availableWidth,
|
||||||
st::dialogsTextFont->height);
|
st::dialogsTextFont->height);
|
||||||
const auto actionWasPainted = ShowSendActionInDialogs(history)
|
const auto actionWasPainted = ShowSendActionInDialogs(thread)
|
||||||
? history->sendActionPainter()->paint(
|
? thread->sendActionPainter()->paint(
|
||||||
p,
|
p,
|
||||||
rect.x(),
|
rect.x(),
|
||||||
rect.y(),
|
rect.y(),
|
||||||
|
|
|
@ -654,7 +654,7 @@ bool InnerWidget::elementHideReply(not_null<const Element*> view) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InnerWidget::elementShownUnread(not_null<const Element*> view) {
|
bool InnerWidget::elementShownUnread(not_null<const Element*> view) {
|
||||||
return view->data()->unread();
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InnerWidget::elementSendBotCommand(
|
void InnerWidget::elementSendBotCommand(
|
||||||
|
|
|
@ -695,9 +695,14 @@ void GenerateItems(
|
||||||
using LogJoinByRequest =
|
using LogJoinByRequest =
|
||||||
MTPDchannelAdminLogEventActionParticipantJoinByRequest;
|
MTPDchannelAdminLogEventActionParticipantJoinByRequest;
|
||||||
using LogNoForwards = MTPDchannelAdminLogEventActionToggleNoForwards;
|
using LogNoForwards = MTPDchannelAdminLogEventActionToggleNoForwards;
|
||||||
using LogActionSendMessage = MTPDchannelAdminLogEventActionSendMessage;
|
using LogSendMessage = MTPDchannelAdminLogEventActionSendMessage;
|
||||||
using LogEventActionChangeAvailableReactions = MTPDchannelAdminLogEventActionChangeAvailableReactions;
|
using LogChangeAvailableReactions = MTPDchannelAdminLogEventActionChangeAvailableReactions;
|
||||||
using LogEventActionChangeUsernames = MTPDchannelAdminLogEventActionChangeUsernames;
|
using LogChangeUsernames = MTPDchannelAdminLogEventActionChangeUsernames;
|
||||||
|
using LogToggleForum = MTPDchannelAdminLogEventActionToggleForum;
|
||||||
|
using LogCreateTopic = MTPDchannelAdminLogEventActionCreateTopic;
|
||||||
|
using LogEditTopic = MTPDchannelAdminLogEventActionEditTopic;
|
||||||
|
using LogDeleteTopic = MTPDchannelAdminLogEventActionDeleteTopic;
|
||||||
|
using LogPinTopic = MTPDchannelAdminLogEventActionPinTopic;
|
||||||
|
|
||||||
const auto session = &history->session();
|
const auto session = &history->session();
|
||||||
const auto id = event.vid().v;
|
const auto id = event.vid().v;
|
||||||
|
@ -972,7 +977,7 @@ void GenerateItems(
|
||||||
ExtractSentDate(action.vmessage()));
|
ExtractSentDate(action.vmessage()));
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto createParticipantJoin = [&]() {
|
const auto createParticipantJoin = [&](const LogJoin&) {
|
||||||
const auto text = (channel->isMegagroup()
|
const auto text = (channel->isMegagroup()
|
||||||
? tr::lng_admin_log_participant_joined
|
? tr::lng_admin_log_participant_joined
|
||||||
: tr::lng_admin_log_participant_joined_channel)(
|
: tr::lng_admin_log_participant_joined_channel)(
|
||||||
|
@ -983,7 +988,7 @@ void GenerateItems(
|
||||||
addSimpleServiceMessage(text);
|
addSimpleServiceMessage(text);
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto createParticipantLeave = [&]() {
|
const auto createParticipantLeave = [&](const LogLeave&) {
|
||||||
const auto text = (channel->isMegagroup()
|
const auto text = (channel->isMegagroup()
|
||||||
? tr::lng_admin_log_participant_left
|
? tr::lng_admin_log_participant_left
|
||||||
: tr::lng_admin_log_participant_left_channel)(
|
: tr::lng_admin_log_participant_left_channel)(
|
||||||
|
@ -1457,7 +1462,7 @@ void GenerateItems(
|
||||||
addSimpleServiceMessage(text);
|
addSimpleServiceMessage(text);
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto createSendMessage = [&](const LogActionSendMessage &data) {
|
const auto createSendMessage = [&](const LogSendMessage &data) {
|
||||||
const auto text = tr::lng_admin_log_sent_message(
|
const auto text = tr::lng_admin_log_sent_message(
|
||||||
tr::now,
|
tr::now,
|
||||||
lt_from,
|
lt_from,
|
||||||
|
@ -1476,7 +1481,7 @@ void GenerateItems(
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto createChangeAvailableReactions = [&](
|
const auto createChangeAvailableReactions = [&](
|
||||||
const LogEventActionChangeAvailableReactions &data) {
|
const LogChangeAvailableReactions &data) {
|
||||||
const auto text = data.vnew_value().match([&](
|
const auto text = data.vnew_value().match([&](
|
||||||
const MTPDchatReactionsNone&) {
|
const MTPDchatReactionsNone&) {
|
||||||
return tr::lng_admin_log_reactions_disabled(
|
return tr::lng_admin_log_reactions_disabled(
|
||||||
|
@ -1514,87 +1519,74 @@ void GenerateItems(
|
||||||
addSimpleServiceMessage(text);
|
addSimpleServiceMessage(text);
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto createChangeUsernames = [&](
|
const auto createChangeUsernames = [&](const LogChangeUsernames &data) {
|
||||||
const LogEventActionChangeUsernames &data) {
|
|
||||||
// #TODO usernames
|
// #TODO usernames
|
||||||
addSimpleServiceMessage({ "changed usernames" });
|
addSimpleServiceMessage({ "changed usernames" });
|
||||||
};
|
};
|
||||||
|
|
||||||
action.match([&](const LogTitle &data) {
|
const auto createToggleForum = [&](const LogToggleForum &data) {
|
||||||
createChangeTitle(data);
|
|
||||||
}, [&](const LogAbout &data) {
|
};
|
||||||
createChangeAbout(data);
|
|
||||||
}, [&](const LogUsername &data) {
|
const auto createCreateTopic = [&](const LogCreateTopic &data) {
|
||||||
createChangeUsername(data);
|
|
||||||
}, [&](const LogPhoto &data) {
|
};
|
||||||
createChangePhoto(data);
|
|
||||||
}, [&](const LogInvites &data) {
|
const auto createEditTopic = [&](const LogEditTopic &data) {
|
||||||
createToggleInvites(data);
|
|
||||||
}, [&](const LogSign &data) {
|
};
|
||||||
createToggleSignatures(data);
|
|
||||||
}, [&](const LogPin &data) {
|
const auto createDeleteTopic = [&](const LogDeleteTopic &data) {
|
||||||
createUpdatePinned(data);
|
|
||||||
}, [&](const LogEdit &data) {
|
};
|
||||||
createEditMessage(data);
|
|
||||||
}, [&](const LogDelete &data) {
|
const auto createPinTopic = [&](const LogPinTopic &data) {
|
||||||
createDeleteMessage(data);
|
|
||||||
}, [&](const LogJoin &) {
|
};
|
||||||
createParticipantJoin();
|
|
||||||
}, [&](const LogLeave &) {
|
action.match(
|
||||||
createParticipantLeave();
|
createChangeTitle,
|
||||||
}, [&](const LogInvite &data) {
|
createChangeAbout,
|
||||||
createParticipantInvite(data);
|
createChangeUsername,
|
||||||
}, [&](const LogBan &data) {
|
createChangePhoto,
|
||||||
createParticipantToggleBan(data);
|
createToggleInvites,
|
||||||
}, [&](const LogPromote &data) {
|
createToggleSignatures,
|
||||||
createParticipantToggleAdmin(data);
|
createUpdatePinned,
|
||||||
}, [&](const LogSticker &data) {
|
createEditMessage,
|
||||||
createChangeStickerSet(data);
|
createDeleteMessage,
|
||||||
}, [&](const LogPreHistory &data) {
|
createParticipantJoin,
|
||||||
createTogglePreHistoryHidden(data);
|
createParticipantLeave,
|
||||||
}, [&](const LogPermissions &data) {
|
createParticipantInvite,
|
||||||
createDefaultBannedRights(data);
|
createParticipantToggleBan,
|
||||||
}, [&](const LogPoll &data) {
|
createParticipantToggleAdmin,
|
||||||
createStopPoll(data);
|
createChangeStickerSet,
|
||||||
}, [&](const LogDiscussion &data) {
|
createTogglePreHistoryHidden,
|
||||||
createChangeLinkedChat(data);
|
createDefaultBannedRights,
|
||||||
}, [&](const LogLocation &data) {
|
createStopPoll,
|
||||||
createChangeLocation(data);
|
createChangeLinkedChat,
|
||||||
}, [&](const LogSlowMode &data) {
|
createChangeLocation,
|
||||||
createToggleSlowMode(data);
|
createToggleSlowMode,
|
||||||
}, [&](const LogStartCall &data) {
|
createStartGroupCall,
|
||||||
createStartGroupCall(data);
|
createDiscardGroupCall,
|
||||||
}, [&](const LogDiscardCall &data) {
|
createParticipantMute,
|
||||||
createDiscardGroupCall(data);
|
createParticipantUnmute,
|
||||||
}, [&](const LogMute &data) {
|
createToggleGroupCallSetting,
|
||||||
createParticipantMute(data);
|
createParticipantJoinByInvite,
|
||||||
}, [&](const LogUnmute &data) {
|
createExportedInviteDelete,
|
||||||
createParticipantUnmute(data);
|
createExportedInviteRevoke,
|
||||||
}, [&](const LogCallSetting &data) {
|
createExportedInviteEdit,
|
||||||
createToggleGroupCallSetting(data);
|
createParticipantVolume,
|
||||||
}, [&](const LogJoinByInvite &data) {
|
createChangeHistoryTTL,
|
||||||
createParticipantJoinByInvite(data);
|
createParticipantJoinByRequest,
|
||||||
}, [&](const LogInviteDelete &data) {
|
createToggleNoForwards,
|
||||||
createExportedInviteDelete(data);
|
createSendMessage,
|
||||||
}, [&](const LogInviteRevoke &data) {
|
createChangeAvailableReactions,
|
||||||
createExportedInviteRevoke(data);
|
createChangeUsernames,
|
||||||
}, [&](const LogInviteEdit &data) {
|
createToggleForum,
|
||||||
createExportedInviteEdit(data);
|
createCreateTopic,
|
||||||
}, [&](const LogVolume &data) {
|
createEditTopic,
|
||||||
createParticipantVolume(data);
|
createDeleteTopic,
|
||||||
}, [&](const LogTTL &data) {
|
createPinTopic);
|
||||||
createChangeHistoryTTL(data);
|
|
||||||
}, [&](const LogJoinByRequest &data) {
|
|
||||||
createParticipantJoinByRequest(data);
|
|
||||||
}, [&](const LogNoForwards &data) {
|
|
||||||
createToggleNoForwards(data);
|
|
||||||
}, [&](const LogActionSendMessage &data) {
|
|
||||||
createSendMessage(data);
|
|
||||||
}, [&](const LogEventActionChangeAvailableReactions &data) {
|
|
||||||
createChangeAvailableReactions(data);
|
|
||||||
}, [&](const LogEventActionChangeUsernames &data) {
|
|
||||||
createChangeUsernames(data);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace AdminLog
|
} // namespace AdminLog
|
||||||
|
|
|
@ -157,53 +157,56 @@ void History::itemVanished(not_null<HistoryItem*> item) {
|
||||||
clearLastKeyboard();
|
clearLastKeyboard();
|
||||||
}
|
}
|
||||||
if ((!item->out() || item->isPost())
|
if ((!item->out() || item->isPost())
|
||||||
&& item->unread()
|
&& item->unread(this)
|
||||||
&& unreadCount() > 0) {
|
&& unreadCount() > 0) {
|
||||||
setUnreadCount(unreadCount() - 1);
|
setUnreadCount(unreadCount() - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void History::takeLocalDraft(not_null<History*> from) {
|
void History::takeLocalDraft(not_null<History*> from) {
|
||||||
const auto i = from->_drafts.find(Data::DraftKey::Local());
|
const auto topicRootId = MsgId(0);
|
||||||
|
const auto i = from->_drafts.find(Data::DraftKey::Local(topicRootId));
|
||||||
if (i == end(from->_drafts)) {
|
if (i == end(from->_drafts)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto &draft = i->second;
|
auto &draft = i->second;
|
||||||
if (!draft->textWithTags.text.isEmpty()
|
if (!draft->textWithTags.text.isEmpty()
|
||||||
&& !_drafts.contains(Data::DraftKey::Local())) {
|
&& !_drafts.contains(Data::DraftKey::Local(topicRootId))) {
|
||||||
// Edit and reply to drafts can't migrate.
|
// Edit and reply to drafts can't migrate.
|
||||||
// Cloud drafts do not migrate automatically.
|
// Cloud drafts do not migrate automatically.
|
||||||
draft->msgId = 0;
|
draft->msgId = 0;
|
||||||
|
|
||||||
setLocalDraft(std::move(draft));
|
setLocalDraft(std::move(draft));
|
||||||
}
|
}
|
||||||
from->clearLocalDraft();
|
from->clearLocalDraft(topicRootId);
|
||||||
session().api().saveDraftToCloudDelayed(from);
|
session().api().saveDraftToCloudDelayed(from);
|
||||||
}
|
}
|
||||||
|
|
||||||
void History::createLocalDraftFromCloud() {
|
void History::createLocalDraftFromCloud(MsgId topicRootId) {
|
||||||
const auto draft = cloudDraft();
|
const auto draft = cloudDraft(topicRootId);
|
||||||
if (!draft) {
|
if (!draft) {
|
||||||
clearLocalDraft();
|
clearLocalDraft(topicRootId);
|
||||||
return;
|
return;
|
||||||
} else if (Data::draftIsNull(draft) || !draft->date) {
|
} else if (Data::DraftIsNull(draft) || !draft->date) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto existing = localDraft();
|
auto existing = localDraft(topicRootId);
|
||||||
if (Data::draftIsNull(existing)
|
if (Data::DraftIsNull(existing)
|
||||||
|| !existing->date
|
|| !existing->date
|
||||||
|| draft->date >= existing->date) {
|
|| draft->date >= existing->date) {
|
||||||
if (!existing) {
|
if (!existing) {
|
||||||
setLocalDraft(std::make_unique<Data::Draft>(
|
setLocalDraft(std::make_unique<Data::Draft>(
|
||||||
draft->textWithTags,
|
draft->textWithTags,
|
||||||
draft->msgId,
|
draft->msgId,
|
||||||
|
topicRootId,
|
||||||
draft->cursor,
|
draft->cursor,
|
||||||
draft->previewState));
|
draft->previewState));
|
||||||
existing = localDraft();
|
existing = localDraft(topicRootId);
|
||||||
} else if (existing != draft) {
|
} else if (existing != draft) {
|
||||||
existing->textWithTags = draft->textWithTags;
|
existing->textWithTags = draft->textWithTags;
|
||||||
existing->msgId = draft->msgId;
|
existing->msgId = draft->msgId;
|
||||||
|
existing->topicRootId = draft->topicRootId;
|
||||||
existing->cursor = draft->cursor;
|
existing->cursor = draft->cursor;
|
||||||
existing->previewState = draft->previewState;
|
existing->previewState = draft->previewState;
|
||||||
}
|
}
|
||||||
|
@ -219,18 +222,22 @@ Data::Draft *History::draft(Data::DraftKey key) const {
|
||||||
return (i != _drafts.end()) ? i->second.get() : nullptr;
|
return (i != _drafts.end()) ? i->second.get() : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void History::setDraft(Data::DraftKey key, std::unique_ptr<Data::Draft> &&draft) {
|
void History::setDraft(
|
||||||
|
Data::DraftKey key,
|
||||||
|
std::unique_ptr<Data::Draft> &&draft) {
|
||||||
if (!key) {
|
if (!key) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto changingCloudDraft = (key == Data::DraftKey::Cloud());
|
const auto cloudThread = key.isCloud()
|
||||||
if (changingCloudDraft) {
|
? threadFor(key.topicRootId())
|
||||||
cloudDraftTextCache().clear();
|
: nullptr;
|
||||||
|
if (cloudThread) {
|
||||||
|
cloudThread->cloudDraftTextCache().clear();
|
||||||
}
|
}
|
||||||
if (draft) {
|
if (draft) {
|
||||||
_drafts[key] = std::move(draft);
|
_drafts[key] = std::move(draft);
|
||||||
} else if (_drafts.remove(key) && changingCloudDraft) {
|
} else if (_drafts.remove(key) && cloudThread) {
|
||||||
updateChatListSortPosition();
|
cloudThread->updateChatListSortPosition();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,31 +257,38 @@ void History::clearDraft(Data::DraftKey key) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void History::clearDrafts() {
|
void History::clearDrafts() {
|
||||||
const auto changingCloudDraft = _drafts.contains(Data::DraftKey::Cloud());
|
for (auto &[key, draft] : base::take(_drafts)) {
|
||||||
_drafts.clear();
|
const auto cloudThread = key.isCloud()
|
||||||
if (changingCloudDraft) {
|
? threadFor(key.topicRootId())
|
||||||
cloudDraftTextCache().clear();
|
: nullptr;
|
||||||
updateChatListSortPosition();
|
if (cloudThread) {
|
||||||
|
cloudThread->cloudDraftTextCache().clear();
|
||||||
|
cloudThread->updateChatListSortPosition();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Data::Draft *History::createCloudDraft(const Data::Draft *fromDraft) {
|
Data::Draft *History::createCloudDraft(
|
||||||
if (Data::draftIsNull(fromDraft)) {
|
MsgId topicRootId,
|
||||||
|
const Data::Draft *fromDraft) {
|
||||||
|
if (Data::DraftIsNull(fromDraft)) {
|
||||||
setCloudDraft(std::make_unique<Data::Draft>(
|
setCloudDraft(std::make_unique<Data::Draft>(
|
||||||
TextWithTags(),
|
TextWithTags(),
|
||||||
0,
|
0,
|
||||||
|
topicRootId,
|
||||||
MessageCursor(),
|
MessageCursor(),
|
||||||
Data::PreviewState::Allowed));
|
Data::PreviewState::Allowed));
|
||||||
cloudDraft()->date = TimeId(0);
|
cloudDraft(topicRootId)->date = TimeId(0);
|
||||||
} else {
|
} else {
|
||||||
auto existing = cloudDraft();
|
auto existing = cloudDraft(topicRootId);
|
||||||
if (!existing) {
|
if (!existing) {
|
||||||
setCloudDraft(std::make_unique<Data::Draft>(
|
setCloudDraft(std::make_unique<Data::Draft>(
|
||||||
fromDraft->textWithTags,
|
fromDraft->textWithTags,
|
||||||
fromDraft->msgId,
|
fromDraft->msgId,
|
||||||
|
topicRootId,
|
||||||
fromDraft->cursor,
|
fromDraft->cursor,
|
||||||
fromDraft->previewState));
|
fromDraft->previewState));
|
||||||
existing = cloudDraft();
|
existing = cloudDraft(topicRootId);
|
||||||
} else if (existing != fromDraft) {
|
} else if (existing != fromDraft) {
|
||||||
existing->textWithTags = fromDraft->textWithTags;
|
existing->textWithTags = fromDraft->textWithTags;
|
||||||
existing->msgId = fromDraft->msgId;
|
existing->msgId = fromDraft->msgId;
|
||||||
|
@ -284,42 +298,60 @@ Data::Draft *History::createCloudDraft(const Data::Draft *fromDraft) {
|
||||||
existing->date = base::unixtime::now();
|
existing->date = base::unixtime::now();
|
||||||
}
|
}
|
||||||
|
|
||||||
cloudDraftTextCache().clear();
|
if (const auto thread = threadFor(topicRootId)) {
|
||||||
updateChatListSortPosition();
|
thread->cloudDraftTextCache().clear();
|
||||||
|
thread->updateChatListSortPosition();
|
||||||
return cloudDraft();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool History::skipCloudDraftUpdate(TimeId date) const {
|
|
||||||
return (_savingCloudDraftRequests > 0)
|
|
||||||
|| (date < _acceptCloudDraftsAfter);
|
|
||||||
}
|
|
||||||
|
|
||||||
void History::startSavingCloudDraft() {
|
|
||||||
++_savingCloudDraftRequests;
|
|
||||||
}
|
|
||||||
|
|
||||||
void History::finishSavingCloudDraft(TimeId savedAt) {
|
|
||||||
if (_savingCloudDraftRequests > 0) {
|
|
||||||
--_savingCloudDraftRequests;
|
|
||||||
}
|
}
|
||||||
const auto acceptAfter = savedAt + kSkipCloudDraftsFor;
|
|
||||||
_acceptCloudDraftsAfter = std::max(_acceptCloudDraftsAfter, acceptAfter);
|
return cloudDraft(topicRootId);
|
||||||
}
|
}
|
||||||
|
|
||||||
void History::applyCloudDraft() {
|
bool History::skipCloudDraftUpdate(MsgId topicRootId, TimeId date) const {
|
||||||
if (session().supportMode()) {
|
const auto i = _acceptCloudDraftsAfter.find(topicRootId);
|
||||||
|
return _savingCloudDraftRequests.contains(topicRootId)
|
||||||
|
|| (i != _acceptCloudDraftsAfter.end() && date < i->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
void History::startSavingCloudDraft(MsgId topicRootId) {
|
||||||
|
++_savingCloudDraftRequests[topicRootId];
|
||||||
|
}
|
||||||
|
|
||||||
|
void History::finishSavingCloudDraft(MsgId topicRootId, TimeId savedAt) {
|
||||||
|
const auto i = _savingCloudDraftRequests.find(topicRootId);
|
||||||
|
if (i != _savingCloudDraftRequests.end()) {
|
||||||
|
if (--i->second <= 0) {
|
||||||
|
_savingCloudDraftRequests.erase(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto &after = _acceptCloudDraftsAfter[topicRootId];
|
||||||
|
after = std::max(after, savedAt + kSkipCloudDraftsFor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void History::applyCloudDraft(MsgId topicRootId) {
|
||||||
|
if (!topicRootId && session().supportMode()) {
|
||||||
updateChatListEntry();
|
updateChatListEntry();
|
||||||
session().supportHelper().cloudDraftChanged(this);
|
session().supportHelper().cloudDraftChanged(this);
|
||||||
} else {
|
} else {
|
||||||
createLocalDraftFromCloud();
|
createLocalDraftFromCloud(topicRootId);
|
||||||
updateChatListSortPosition();
|
if (const auto thread = threadFor(topicRootId)) {
|
||||||
session().changes().historyUpdated(this, UpdateFlag::CloudDraft);
|
thread->updateChatListSortPosition();
|
||||||
|
if (!topicRootId) {
|
||||||
|
session().changes().historyUpdated(
|
||||||
|
this,
|
||||||
|
UpdateFlag::CloudDraft);
|
||||||
|
} else {
|
||||||
|
session().changes().topicUpdated(
|
||||||
|
thread->asTopic(),
|
||||||
|
Data::TopicUpdate::Flag::CloudDraft);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void History::draftSavedToCloud() {
|
void History::draftSavedToCloud(MsgId topicRootId) {
|
||||||
updateChatListEntry();
|
if (const auto thread = threadFor(topicRootId)) {
|
||||||
|
thread->updateChatListEntry();
|
||||||
|
}
|
||||||
session().local().writeDrafts(this);
|
session().local().writeDrafts(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1143,20 +1175,22 @@ void History::newItemAdded(not_null<HistoryItem*> item) {
|
||||||
const auto stillShow = item->showNotification(); // Could be read already.
|
const auto stillShow = item->showNotification(); // Could be read already.
|
||||||
if (stillShow) {
|
if (stillShow) {
|
||||||
Core::App().notifications().schedule(notification);
|
Core::App().notifications().schedule(notification);
|
||||||
if (!item->out() && item->unread()) {
|
}
|
||||||
|
if (item->out()) {
|
||||||
|
destroyUnreadBar();
|
||||||
|
if (!item->unread(this)) {
|
||||||
|
outboxRead(item);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (item->unread(this)) {
|
||||||
if (unreadCountKnown()) {
|
if (unreadCountKnown()) {
|
||||||
setUnreadCount(unreadCount() + 1);
|
setUnreadCount(unreadCount() + 1);
|
||||||
} else {
|
} else {
|
||||||
owner().histories().requestDialogEntry(this);
|
owner().histories().requestDialogEntry(this);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
inboxRead(item);
|
||||||
}
|
}
|
||||||
} else if (item->out()) {
|
|
||||||
destroyUnreadBar();
|
|
||||||
} else if (!item->unread()) {
|
|
||||||
inboxRead(item);
|
|
||||||
}
|
|
||||||
if (item->out() && !item->unread()) {
|
|
||||||
outboxRead(item);
|
|
||||||
}
|
}
|
||||||
item->incrementReplyToTopCounter();
|
item->incrementReplyToTopCounter();
|
||||||
if (!folderKnown()) {
|
if (!folderKnown()) {
|
||||||
|
@ -1879,8 +1913,8 @@ void History::applyPinnedUpdate(const MTPDupdateDialogPinned &data) {
|
||||||
|
|
||||||
TimeId History::adjustedChatListTimeId() const {
|
TimeId History::adjustedChatListTimeId() const {
|
||||||
const auto result = chatListTimeId();
|
const auto result = chatListTimeId();
|
||||||
if (const auto draft = cloudDraft()) {
|
if (const auto draft = cloudDraft(MsgId(0))) {
|
||||||
if (!Data::draftIsNull(draft) && !session().supportMode()) {
|
if (!Data::DraftIsNull(draft) && !session().supportMode()) {
|
||||||
return std::max(result, draft->date);
|
return std::max(result, draft->date);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2601,6 +2635,7 @@ void History::applyDialog(
|
||||||
Data::ApplyPeerCloudDraft(
|
Data::ApplyPeerCloudDraft(
|
||||||
&session(),
|
&session(),
|
||||||
peer->id,
|
peer->id,
|
||||||
|
MsgId(0), // topicRootId
|
||||||
draft->c_draftMessage());
|
draft->c_draftMessage());
|
||||||
}
|
}
|
||||||
owner().histories().dialogEntryApplied(this);
|
owner().histories().dialogEntryApplied(this);
|
||||||
|
@ -2823,6 +2858,16 @@ void History::forceFullResize() {
|
||||||
_flags |= Flag::HasPendingResizedItems;
|
_flags |= Flag::HasPendingResizedItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Data::Thread *History::threadFor(MsgId topicRootId) {
|
||||||
|
return topicRootId
|
||||||
|
? peer->forumTopicFor(topicRootId)
|
||||||
|
: static_cast<Data::Thread*>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Data::Thread *History::threadFor(MsgId topicRootId) const {
|
||||||
|
return const_cast<History*>(this)->threadFor(topicRootId);
|
||||||
|
}
|
||||||
|
|
||||||
not_null<History*> History::migrateToOrMe() const {
|
not_null<History*> History::migrateToOrMe() const {
|
||||||
if (const auto to = peer->migrateTo()) {
|
if (const auto to = peer->migrateTo()) {
|
||||||
return owner().history(to);
|
return owner().history(to);
|
||||||
|
|
|
@ -80,6 +80,8 @@ public:
|
||||||
not_null<History*> owningHistory() override {
|
not_null<History*> owningHistory() override {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
[[nodiscard]] Data::Thread *threadFor(MsgId topicRootId);
|
||||||
|
[[nodiscard]] const Data::Thread *threadFor(MsgId topicRootId) const;
|
||||||
|
|
||||||
[[nodiscard]] auto delegateMixin() const
|
[[nodiscard]] auto delegateMixin() const
|
||||||
-> not_null<HistoryMainElementDelegateMixin*> {
|
-> not_null<HistoryMainElementDelegateMixin*> {
|
||||||
|
@ -229,12 +231,13 @@ public:
|
||||||
void inboxRead(not_null<const HistoryItem*> wasRead);
|
void inboxRead(not_null<const HistoryItem*> wasRead);
|
||||||
void outboxRead(MsgId upTo);
|
void outboxRead(MsgId upTo);
|
||||||
void outboxRead(not_null<const HistoryItem*> wasRead);
|
void outboxRead(not_null<const HistoryItem*> wasRead);
|
||||||
[[nodiscard]] bool isServerSideUnread(
|
|
||||||
not_null<const HistoryItem*> item) const;
|
|
||||||
[[nodiscard]] MsgId loadAroundId() const;
|
[[nodiscard]] MsgId loadAroundId() const;
|
||||||
[[nodiscard]] MsgId inboxReadTillId() const;
|
[[nodiscard]] MsgId inboxReadTillId() const;
|
||||||
[[nodiscard]] MsgId outboxReadTillId() const;
|
[[nodiscard]] MsgId outboxReadTillId() const;
|
||||||
|
|
||||||
|
[[nodiscard]] bool isServerSideUnread(
|
||||||
|
not_null<const HistoryItem*> item) const override;
|
||||||
|
|
||||||
[[nodiscard]] bool trackUnreadMessages() const;
|
[[nodiscard]] bool trackUnreadMessages() const;
|
||||||
[[nodiscard]] int unreadCount() const;
|
[[nodiscard]] int unreadCount() const;
|
||||||
[[nodiscard]] bool unreadCountKnown() const;
|
[[nodiscard]] bool unreadCountKnown() const;
|
||||||
|
@ -301,7 +304,7 @@ public:
|
||||||
void setHasPendingResizedItems();
|
void setHasPendingResizedItems();
|
||||||
|
|
||||||
[[nodiscard]] auto sendActionPainter()
|
[[nodiscard]] auto sendActionPainter()
|
||||||
-> not_null<HistoryView::SendActionPainter*> {
|
-> not_null<HistoryView::SendActionPainter*> override {
|
||||||
return &_sendActionPainter;
|
return &_sendActionPainter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -316,41 +319,51 @@ public:
|
||||||
[[nodiscard]] const Data::HistoryDrafts &draftsMap() const;
|
[[nodiscard]] const Data::HistoryDrafts &draftsMap() const;
|
||||||
void setDraftsMap(Data::HistoryDrafts &&map);
|
void setDraftsMap(Data::HistoryDrafts &&map);
|
||||||
|
|
||||||
Data::Draft *localDraft() const {
|
Data::Draft *localDraft(MsgId topicRootId) const {
|
||||||
return draft(Data::DraftKey::Local());
|
return draft(Data::DraftKey::Local(topicRootId));
|
||||||
}
|
}
|
||||||
Data::Draft *localEditDraft() const {
|
Data::Draft *localEditDraft(MsgId topicRootId) const {
|
||||||
return draft(Data::DraftKey::LocalEdit());
|
return draft(Data::DraftKey::LocalEdit(topicRootId));
|
||||||
}
|
}
|
||||||
Data::Draft *cloudDraft() const {
|
Data::Draft *cloudDraft(MsgId topicRootId) const {
|
||||||
return draft(Data::DraftKey::Cloud());
|
return draft(Data::DraftKey::Cloud(topicRootId));
|
||||||
}
|
}
|
||||||
void setLocalDraft(std::unique_ptr<Data::Draft> &&draft) {
|
void setLocalDraft(std::unique_ptr<Data::Draft> &&draft) {
|
||||||
setDraft(Data::DraftKey::Local(), std::move(draft));
|
setDraft(
|
||||||
|
Data::DraftKey::Local(draft->topicRootId),
|
||||||
|
std::move(draft));
|
||||||
}
|
}
|
||||||
void setLocalEditDraft(std::unique_ptr<Data::Draft> &&draft) {
|
void setLocalEditDraft(std::unique_ptr<Data::Draft> &&draft) {
|
||||||
setDraft(Data::DraftKey::LocalEdit(), std::move(draft));
|
setDraft(
|
||||||
|
Data::DraftKey::LocalEdit(draft->topicRootId),
|
||||||
|
std::move(draft));
|
||||||
}
|
}
|
||||||
void setCloudDraft(std::unique_ptr<Data::Draft> &&draft) {
|
void setCloudDraft(std::unique_ptr<Data::Draft> &&draft) {
|
||||||
setDraft(Data::DraftKey::Cloud(), std::move(draft));
|
setDraft(
|
||||||
|
Data::DraftKey::Cloud(draft->topicRootId),
|
||||||
|
std::move(draft));
|
||||||
}
|
}
|
||||||
void clearLocalDraft() {
|
void clearLocalDraft(MsgId topicRootId) {
|
||||||
clearDraft(Data::DraftKey::Local());
|
clearDraft(Data::DraftKey::Local(topicRootId));
|
||||||
}
|
}
|
||||||
void clearCloudDraft() {
|
void clearCloudDraft(MsgId topicRootId) {
|
||||||
clearDraft(Data::DraftKey::Cloud());
|
clearDraft(Data::DraftKey::Cloud(topicRootId));
|
||||||
}
|
}
|
||||||
void clearLocalEditDraft() {
|
void clearLocalEditDraft(MsgId topicRootId) {
|
||||||
clearDraft(Data::DraftKey::LocalEdit());
|
clearDraft(Data::DraftKey::LocalEdit(topicRootId));
|
||||||
}
|
}
|
||||||
void clearDrafts();
|
void clearDrafts();
|
||||||
Data::Draft *createCloudDraft(const Data::Draft *fromDraft);
|
Data::Draft *createCloudDraft(
|
||||||
bool skipCloudDraftUpdate(TimeId date) const;
|
MsgId topicRootId,
|
||||||
void startSavingCloudDraft();
|
const Data::Draft *fromDraft);
|
||||||
void finishSavingCloudDraft(TimeId savedAt);
|
[[nodiscard]] bool skipCloudDraftUpdate(
|
||||||
|
MsgId topicRootId,
|
||||||
|
TimeId date) const;
|
||||||
|
void startSavingCloudDraft(MsgId topicRootId);
|
||||||
|
void finishSavingCloudDraft(MsgId topicRootId, TimeId savedAt);
|
||||||
void takeLocalDraft(not_null<History*> from);
|
void takeLocalDraft(not_null<History*> from);
|
||||||
void applyCloudDraft();
|
void applyCloudDraft(MsgId topicRootId);
|
||||||
void draftSavedToCloud();
|
void draftSavedToCloud(MsgId topicRootId);
|
||||||
|
|
||||||
[[nodiscard]] const Data::ForwardDraft &forwardDraft() const {
|
[[nodiscard]] const Data::ForwardDraft &forwardDraft() const {
|
||||||
return _forwardDraft;
|
return _forwardDraft;
|
||||||
|
@ -553,7 +566,7 @@ private:
|
||||||
|
|
||||||
void viewReplaced(not_null<const Element*> was, Element *now);
|
void viewReplaced(not_null<const Element*> was, Element *now);
|
||||||
|
|
||||||
void createLocalDraftFromCloud();
|
void createLocalDraftFromCloud(MsgId topicRootId);
|
||||||
|
|
||||||
HistoryService *insertJoinedMessage();
|
HistoryService *insertJoinedMessage();
|
||||||
void insertMessageToBlocks(not_null<HistoryItem*> item);
|
void insertMessageToBlocks(not_null<HistoryItem*> item);
|
||||||
|
@ -603,8 +616,8 @@ private:
|
||||||
std::unique_ptr<BuildingBlock> _buildingFrontBlock;
|
std::unique_ptr<BuildingBlock> _buildingFrontBlock;
|
||||||
|
|
||||||
Data::HistoryDrafts _drafts;
|
Data::HistoryDrafts _drafts;
|
||||||
TimeId _acceptCloudDraftsAfter = 0;
|
base::flat_map<MsgId, TimeId> _acceptCloudDraftsAfter;
|
||||||
int _savingCloudDraftRequests = 0;
|
base::flat_map<MsgId, int> _savingCloudDraftRequests;
|
||||||
Data::ForwardDraft _forwardDraft;
|
Data::ForwardDraft _forwardDraft;
|
||||||
|
|
||||||
QString _topPromotedMessage;
|
QString _topPromotedMessage;
|
||||||
|
|
|
@ -227,7 +227,7 @@ public:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool elementShownUnread(not_null<const Element*> view) override {
|
bool elementShownUnread(not_null<const Element*> view) override {
|
||||||
return view->data()->unread();
|
return view->data()->unread(view->data()->history());
|
||||||
}
|
}
|
||||||
void elementSendBotCommand(
|
void elementSendBotCommand(
|
||||||
const QString &command,
|
const QString &command,
|
||||||
|
@ -983,7 +983,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
|
||||||
const auto item = view->data();
|
const auto item = view->data();
|
||||||
const auto isSponsored = item->isSponsored();
|
const auto isSponsored = item->isSponsored();
|
||||||
const auto isUnread = !item->out()
|
const auto isUnread = !item->out()
|
||||||
&& item->unread()
|
&& item->unread(_history)
|
||||||
&& (item->history() == _history);
|
&& (item->history() == _history);
|
||||||
const auto withReaction = item->hasUnreadReaction();
|
const auto withReaction = item->hasUnreadReaction();
|
||||||
const auto yShown = [&](int y) {
|
const auto yShown = [&](int y) {
|
||||||
|
|
|
@ -1217,22 +1217,22 @@ bool HistoryItem::needCheck() const {
|
||||||
return (out() && !isEmpty()) || (!isRegular() && history()->peer->isSelf());
|
return (out() && !isEmpty()) || (!isRegular() && history()->peer->isSelf());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HistoryItem::unread() const {
|
bool HistoryItem::unread(not_null<Data::Thread*> thread) const {
|
||||||
// Messages from myself are always read, unless scheduled.
|
// Messages from myself are always read, unless scheduled.
|
||||||
if (history()->peer->isSelf() && !isFromScheduled()) {
|
if (history()->peer->isSelf() && !isFromScheduled()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (out()) {
|
// All messages in converted chats are always read.
|
||||||
// Outgoing messages in converted chats are always read.
|
if (history()->peer->migrateTo()) {
|
||||||
if (history()->peer->migrateTo()) {
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isRegular()) {
|
||||||
|
if (!thread->isServerSideUnread(this)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (out()) {
|
||||||
if (isRegular()) {
|
|
||||||
if (!history()->isServerSideUnread(this)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (const auto user = history()->peer->asUser()) {
|
if (const auto user = history()->peer->asUser()) {
|
||||||
if (user->isBot() && !user->isSupport()) {
|
if (user->isBot() && !user->isSupport()) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -1246,13 +1246,7 @@ bool HistoryItem::unread() const {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isRegular()) {
|
return out() || (_flags & MessageFlag::ClientSideUnread);
|
||||||
if (!history()->isServerSideUnread(this)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return (_flags & MessageFlag::ClientSideUnread);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HistoryItem::showNotification() const {
|
bool HistoryItem::showNotification() const {
|
||||||
|
@ -1262,7 +1256,7 @@ bool HistoryItem::showNotification() const {
|
||||||
}
|
}
|
||||||
return (out() || _history->peer->isSelf())
|
return (out() || _history->peer->isSelf())
|
||||||
? isFromScheduled()
|
? isFromScheduled()
|
||||||
: unread();
|
: unread(notificationThread());
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryItem::markClientSideAsRead() {
|
void HistoryItem::markClientSideAsRead() {
|
||||||
|
|
|
@ -150,7 +150,7 @@ public:
|
||||||
[[nodiscard]] bool isPinned() const {
|
[[nodiscard]] bool isPinned() const {
|
||||||
return _flags & MessageFlag::Pinned;
|
return _flags & MessageFlag::Pinned;
|
||||||
}
|
}
|
||||||
[[nodiscard]] bool unread() const;
|
[[nodiscard]] bool unread(not_null<Data::Thread*> thread) const;
|
||||||
[[nodiscard]] bool showNotification() const;
|
[[nodiscard]] bool showNotification() const;
|
||||||
void markClientSideAsRead();
|
void markClientSideAsRead();
|
||||||
[[nodiscard]] bool mentionsMe() const;
|
[[nodiscard]] bool mentionsMe() const;
|
||||||
|
|
|
@ -1773,6 +1773,9 @@ void HistoryMessage::setReplyFields(
|
||||||
&& !IsServerMsgId(reply->replyToMsgTop)) {
|
&& !IsServerMsgId(reply->replyToMsgTop)) {
|
||||||
reply->replyToMsgTop = replyToTop;
|
reply->replyToMsgTop = replyToTop;
|
||||||
changeReplyToTopCounter(reply, 1);
|
changeReplyToTopCounter(reply, 1);
|
||||||
|
if (const auto topic = this->topic()) {
|
||||||
|
topic->maybeSetLastMessage(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1342,10 +1342,19 @@ void HistoryService::setReplyFields(
|
||||||
MsgId replyToTop,
|
MsgId replyToTop,
|
||||||
bool isForumPost) {
|
bool isForumPost) {
|
||||||
const auto data = GetDependentData();
|
const auto data = GetDependentData();
|
||||||
if (!data || IsServerMsgId(data->topId) || isScheduled()) {
|
if (!data
|
||||||
|
|| (data->topId == replyToTop)
|
||||||
|
|| IsServerMsgId(data->topId)
|
||||||
|
|| isScheduled()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
data->topId = replyToTop;
|
data->topId = replyToTop;
|
||||||
|
if (isForumPost) {
|
||||||
|
data->topicPost = true;
|
||||||
|
}
|
||||||
|
if (const auto topic = this->topic()) {
|
||||||
|
topic->maybeSetLastMessage(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<HistoryView::Element> HistoryService::createView(
|
std::unique_ptr<HistoryView::Element> HistoryService::createView(
|
||||||
|
|
|
@ -948,7 +948,7 @@ void HistoryWidget::initVoiceRecordBar() {
|
||||||
});
|
});
|
||||||
|
|
||||||
const auto applyLocalDraft = [=] {
|
const auto applyLocalDraft = [=] {
|
||||||
if (_history && _history->localDraft()) {
|
if (_history && _history->localDraft({})) {
|
||||||
applyDraft();
|
applyDraft();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1657,10 +1657,12 @@ void HistoryWidget::saveDraft(bool delayed) {
|
||||||
void HistoryWidget::saveFieldToHistoryLocalDraft() {
|
void HistoryWidget::saveFieldToHistoryLocalDraft() {
|
||||||
if (!_history) return;
|
if (!_history) return;
|
||||||
|
|
||||||
|
const auto topicRootId = MsgId();
|
||||||
if (_editMsgId) {
|
if (_editMsgId) {
|
||||||
_history->setLocalEditDraft(std::make_unique<Data::Draft>(
|
_history->setLocalEditDraft(std::make_unique<Data::Draft>(
|
||||||
_field,
|
_field,
|
||||||
_editMsgId,
|
_editMsgId,
|
||||||
|
topicRootId,
|
||||||
_previewState,
|
_previewState,
|
||||||
_saveEditMsgRequestId));
|
_saveEditMsgRequestId));
|
||||||
} else {
|
} else {
|
||||||
|
@ -1668,11 +1670,12 @@ void HistoryWidget::saveFieldToHistoryLocalDraft() {
|
||||||
_history->setLocalDraft(std::make_unique<Data::Draft>(
|
_history->setLocalDraft(std::make_unique<Data::Draft>(
|
||||||
_field,
|
_field,
|
||||||
_replyToId,
|
_replyToId,
|
||||||
|
topicRootId,
|
||||||
_previewState));
|
_previewState));
|
||||||
} else {
|
} else {
|
||||||
_history->clearLocalDraft();
|
_history->clearLocalDraft({});
|
||||||
}
|
}
|
||||||
_history->clearLocalEditDraft();
|
_history->clearLocalEditDraft({});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1760,7 +1763,8 @@ bool HistoryWidget::notify_switchInlineBotButtonReceived(const QString &query, U
|
||||||
MessageCursor cursor = { int(textWithTags.text.size()), int(textWithTags.text.size()), QFIXED_MAX };
|
MessageCursor cursor = { int(textWithTags.text.size()), int(textWithTags.text.size()), QFIXED_MAX };
|
||||||
_history->setLocalDraft(std::make_unique<Data::Draft>(
|
_history->setLocalDraft(std::make_unique<Data::Draft>(
|
||||||
textWithTags,
|
textWithTags,
|
||||||
0,
|
0, // replyTo
|
||||||
|
0, // topicRootId
|
||||||
cursor,
|
cursor,
|
||||||
Data::PreviewState::Allowed));
|
Data::PreviewState::Allowed));
|
||||||
applyDraft();
|
applyDraft();
|
||||||
|
@ -1782,21 +1786,19 @@ bool HistoryWidget::notify_switchInlineBotButtonReceived(const QString &query, U
|
||||||
auto draft = std::make_unique<Data::Draft>(
|
auto draft = std::make_unique<Data::Draft>(
|
||||||
textWithTags,
|
textWithTags,
|
||||||
to.currentReplyToId,
|
to.currentReplyToId,
|
||||||
|
to.rootId,
|
||||||
cursor,
|
cursor,
|
||||||
Data::PreviewState::Allowed);
|
Data::PreviewState::Allowed);
|
||||||
|
|
||||||
if (to.section == Section::Replies) {
|
if (to.section == Section::Scheduled) {
|
||||||
history->setDraft(
|
|
||||||
Data::DraftKey::Replies(to.rootId),
|
|
||||||
std::move(draft));
|
|
||||||
controller()->showRepliesForMessage(history, to.rootId);
|
|
||||||
} else if (to.section == Section::Scheduled) {
|
|
||||||
history->setDraft(Data::DraftKey::Scheduled(), std::move(draft));
|
history->setDraft(Data::DraftKey::Scheduled(), std::move(draft));
|
||||||
controller()->showSection(
|
controller()->showSection(
|
||||||
std::make_shared<HistoryView::ScheduledMemento>(history));
|
std::make_shared<HistoryView::ScheduledMemento>(history));
|
||||||
} else {
|
} else {
|
||||||
history->setLocalDraft(std::move(draft));
|
history->setLocalDraft(std::move(draft));
|
||||||
if (history == _history) {
|
if (to.section == Section::Replies) {
|
||||||
|
controller()->showRepliesForMessage(history, to.rootId);
|
||||||
|
} else if (history == _history) {
|
||||||
applyDraft();
|
applyDraft();
|
||||||
} else {
|
} else {
|
||||||
controller()->showPeerHistory(history->peer);
|
controller()->showPeerHistory(history->peer);
|
||||||
|
@ -1878,13 +1880,14 @@ void HistoryWidget::applyDraft(FieldHistoryAction fieldHistoryAction) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto draft = !_history
|
const auto editDraft = _history ? _history->localEditDraft({}) : nullptr;
|
||||||
? nullptr
|
const auto draft = editDraft
|
||||||
: _history->localEditDraft()
|
? editDraft
|
||||||
? _history->localEditDraft()
|
: _history
|
||||||
: _history->localDraft();
|
? _history->localDraft({})
|
||||||
|
: nullptr;
|
||||||
auto fieldAvailable = canWriteMessage();
|
auto fieldAvailable = canWriteMessage();
|
||||||
if (!draft || (!_history->localEditDraft() && !fieldAvailable)) {
|
if (!draft || (!_history->localEditDraft({}) && !fieldAvailable)) {
|
||||||
auto fieldWillBeHiddenAfterEdit = (!fieldAvailable && _editMsgId != 0);
|
auto fieldWillBeHiddenAfterEdit = (!fieldAvailable && _editMsgId != 0);
|
||||||
clearFieldText(0, fieldHistoryAction);
|
clearFieldText(0, fieldHistoryAction);
|
||||||
_field->setFocus();
|
_field->setFocus();
|
||||||
|
@ -1913,11 +1916,11 @@ void HistoryWidget::applyDraft(FieldHistoryAction fieldHistoryAction) {
|
||||||
_previewState = draft->previewState;
|
_previewState = draft->previewState;
|
||||||
|
|
||||||
_replyEditMsg = nullptr;
|
_replyEditMsg = nullptr;
|
||||||
if (const auto editDraft = _history->localEditDraft()) {
|
if (const auto editDraft = _history->localEditDraft({})) {
|
||||||
setEditMsgId(editDraft->msgId);
|
setEditMsgId(editDraft->msgId);
|
||||||
_replyToId = 0;
|
_replyToId = 0;
|
||||||
} else {
|
} else {
|
||||||
_replyToId = readyToForward() ? 0 : _history->localDraft()->msgId;
|
_replyToId = readyToForward() ? 0 : _history->localDraft({})->msgId;
|
||||||
setEditMsgId(0);
|
setEditMsgId(0);
|
||||||
}
|
}
|
||||||
updateCmdStartShown();
|
updateCmdStartShown();
|
||||||
|
@ -2036,7 +2039,7 @@ void HistoryWidget::showHistory(
|
||||||
info->inlineReturnTo = wasDialogsEntryState;
|
info->inlineReturnTo = wasDialogsEntryState;
|
||||||
}
|
}
|
||||||
sendBotStartCommand();
|
sendBotStartCommand();
|
||||||
_history->clearLocalDraft();
|
_history->clearLocalDraft({});
|
||||||
applyDraft();
|
applyDraft();
|
||||||
_send->finishAnimating();
|
_send->finishAnimating();
|
||||||
}
|
}
|
||||||
|
@ -2356,10 +2359,10 @@ void HistoryWidget::unregisterDraftSources() {
|
||||||
}
|
}
|
||||||
session().local().unregisterDraftSource(
|
session().local().unregisterDraftSource(
|
||||||
_history,
|
_history,
|
||||||
Data::DraftKey::Local());
|
Data::DraftKey::Local({}));
|
||||||
session().local().unregisterDraftSource(
|
session().local().unregisterDraftSource(
|
||||||
_history,
|
_history,
|
||||||
Data::DraftKey::LocalEdit());
|
Data::DraftKey::LocalEdit({}));
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::registerDraftSource() {
|
void HistoryWidget::registerDraftSource() {
|
||||||
|
@ -2380,7 +2383,9 @@ void HistoryWidget::registerDraftSource() {
|
||||||
};
|
};
|
||||||
session().local().registerDraftSource(
|
session().local().registerDraftSource(
|
||||||
_history,
|
_history,
|
||||||
editMsgId ? Data::DraftKey::LocalEdit() : Data::DraftKey::Local(),
|
(editMsgId
|
||||||
|
? Data::DraftKey::LocalEdit({})
|
||||||
|
: Data::DraftKey::Local({})),
|
||||||
std::move(draftSource));
|
std::move(draftSource));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3564,16 +3569,16 @@ void HistoryWidget::saveEditMsg() {
|
||||||
cancelEdit();
|
cancelEdit();
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
if (const auto editDraft = history->localEditDraft()) {
|
if (const auto editDraft = history->localEditDraft({})) {
|
||||||
if (editDraft->saveRequestId == requestId) {
|
if (editDraft->saveRequestId == requestId) {
|
||||||
history->clearLocalEditDraft();
|
history->clearLocalEditDraft({});
|
||||||
history->session().local().writeDrafts(history);
|
history->session().local().writeDrafts(history);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto fail = [=](const QString &error, mtpRequestId requestId) {
|
const auto fail = [=](const QString &error, mtpRequestId requestId) {
|
||||||
if (const auto editDraft = history->localEditDraft()) {
|
if (const auto editDraft = history->localEditDraft({})) {
|
||||||
if (editDraft->saveRequestId == requestId) {
|
if (editDraft->saveRequestId == requestId) {
|
||||||
editDraft->saveRequestId = 0;
|
editDraft->saveRequestId = 0;
|
||||||
}
|
}
|
||||||
|
@ -3648,6 +3653,7 @@ Api::SendAction HistoryWidget::prepareSendAction(
|
||||||
Api::SendOptions options) const {
|
Api::SendOptions options) const {
|
||||||
auto result = Api::SendAction(_history, options);
|
auto result = Api::SendAction(_history, options);
|
||||||
result.replyTo = replyToId();
|
result.replyTo = replyToId();
|
||||||
|
result.topicRootId = 0;
|
||||||
result.options.sendAs = _sendAs
|
result.options.sendAs = _sendAs
|
||||||
? _history->session().sendAsPeers().resolveChosen(
|
? _history->session().sendAsPeers().resolveChosen(
|
||||||
_history->peer).get()
|
_history->peer).get()
|
||||||
|
@ -6650,12 +6656,13 @@ void HistoryWidget::replyToMessage(not_null<HistoryItem*> item) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_editMsgId) {
|
if (_editMsgId) {
|
||||||
if (auto localDraft = _history->localDraft()) {
|
if (const auto localDraft = _history->localDraft({})) {
|
||||||
localDraft->msgId = item->id;
|
localDraft->msgId = item->id;
|
||||||
} else {
|
} else {
|
||||||
_history->setLocalDraft(std::make_unique<Data::Draft>(
|
_history->setLocalDraft(std::make_unique<Data::Draft>(
|
||||||
TextWithTags(),
|
TextWithTags(),
|
||||||
item->id,
|
item->id,
|
||||||
|
MsgId(), // topicRootId
|
||||||
MessageCursor(),
|
MessageCursor(),
|
||||||
Data::PreviewState::Allowed));
|
Data::PreviewState::Allowed));
|
||||||
}
|
}
|
||||||
|
@ -6708,9 +6715,10 @@ void HistoryWidget::editMessage(not_null<HistoryItem*> item) {
|
||||||
_history->setLocalDraft(std::make_unique<Data::Draft>(
|
_history->setLocalDraft(std::make_unique<Data::Draft>(
|
||||||
_field,
|
_field,
|
||||||
_replyToId,
|
_replyToId,
|
||||||
|
MsgId(), // topicRootId
|
||||||
_previewState));
|
_previewState));
|
||||||
} else {
|
} else {
|
||||||
_history->clearLocalDraft();
|
_history->clearLocalDraft({});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6732,6 +6740,7 @@ void HistoryWidget::editMessage(not_null<HistoryItem*> item) {
|
||||||
_history->setLocalEditDraft(std::make_unique<Data::Draft>(
|
_history->setLocalEditDraft(std::make_unique<Data::Draft>(
|
||||||
editData,
|
editData,
|
||||||
item->id,
|
item->id,
|
||||||
|
MsgId(), // topicRootId
|
||||||
cursor,
|
cursor,
|
||||||
previewState));
|
previewState));
|
||||||
applyDraft();
|
applyDraft();
|
||||||
|
@ -6811,10 +6820,10 @@ bool HistoryWidget::cancelReply(bool lastKeyboardUsed) {
|
||||||
refreshTopBarActiveChat();
|
refreshTopBarActiveChat();
|
||||||
updateControlsGeometry();
|
updateControlsGeometry();
|
||||||
update();
|
update();
|
||||||
} else if (auto localDraft = (_history ? _history->localDraft() : nullptr)) {
|
} else if (const auto localDraft = (_history ? _history->localDraft({}) : nullptr)) {
|
||||||
if (localDraft->msgId) {
|
if (localDraft->msgId) {
|
||||||
if (localDraft->textWithTags.text.isEmpty()) {
|
if (localDraft->textWithTags.text.isEmpty()) {
|
||||||
_history->clearLocalDraft();
|
_history->clearLocalDraft({});
|
||||||
} else {
|
} else {
|
||||||
localDraft->msgId = 0;
|
localDraft->msgId = 0;
|
||||||
}
|
}
|
||||||
|
@ -6856,7 +6865,7 @@ void HistoryWidget::cancelEdit() {
|
||||||
|
|
||||||
_replyEditMsg = nullptr;
|
_replyEditMsg = nullptr;
|
||||||
setEditMsgId(0);
|
setEditMsgId(0);
|
||||||
_history->clearLocalEditDraft();
|
_history->clearLocalEditDraft({});
|
||||||
applyDraft();
|
applyDraft();
|
||||||
|
|
||||||
if (_saveEditMsgRequestId) {
|
if (_saveEditMsgRequestId) {
|
||||||
|
|
|
@ -1169,16 +1169,18 @@ void ComposeControls::setFieldText(
|
||||||
|
|
||||||
void ComposeControls::saveFieldToHistoryLocalDraft() {
|
void ComposeControls::saveFieldToHistoryLocalDraft() {
|
||||||
const auto key = draftKeyCurrent();
|
const auto key = draftKeyCurrent();
|
||||||
if (!_history || key == Data::DraftKey::None()) {
|
if (!_history || !key) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto id = _header->getDraftMessageId();
|
const auto id = _header->getDraftMessageId();
|
||||||
if (_preview && (id || !_field->empty())) {
|
if (_preview && (id || !_field->empty())) {
|
||||||
|
const auto key = draftKeyCurrent();
|
||||||
_history->setDraft(
|
_history->setDraft(
|
||||||
draftKeyCurrent(),
|
key,
|
||||||
std::make_unique<Data::Draft>(
|
std::make_unique<Data::Draft>(
|
||||||
_field,
|
_field,
|
||||||
_header->getDraftMessageId(),
|
_header->getDraftMessageId(),
|
||||||
|
key.topicRootId(),
|
||||||
_preview->state()));
|
_preview->state()));
|
||||||
} else {
|
} else {
|
||||||
_history->clearDraft(draftKeyCurrent());
|
_history->clearDraft(draftKeyCurrent());
|
||||||
|
@ -1680,15 +1682,14 @@ Data::DraftKey ComposeControls::draftKey(DraftType type) const {
|
||||||
|
|
||||||
switch (_currentDialogsEntryState.section) {
|
switch (_currentDialogsEntryState.section) {
|
||||||
case Section::History:
|
case Section::History:
|
||||||
return (type == DraftType::Edit) ? Key::LocalEdit() : Key::Local();
|
case Section::Replies:
|
||||||
|
return (type == DraftType::Edit)
|
||||||
|
? Key::LocalEdit(_currentDialogsEntryState.rootId)
|
||||||
|
: Key::Local(_currentDialogsEntryState.rootId);
|
||||||
case Section::Scheduled:
|
case Section::Scheduled:
|
||||||
return (type == DraftType::Edit)
|
return (type == DraftType::Edit)
|
||||||
? Key::ScheduledEdit()
|
? Key::ScheduledEdit()
|
||||||
: Key::Scheduled();
|
: Key::Scheduled();
|
||||||
case Section::Replies:
|
|
||||||
return (type == DraftType::Edit)
|
|
||||||
? Key::RepliesEdit(_currentDialogsEntryState.rootId)
|
|
||||||
: Key::Replies(_currentDialogsEntryState.rootId);
|
|
||||||
}
|
}
|
||||||
return Key::None();
|
return Key::None();
|
||||||
}
|
}
|
||||||
|
@ -2380,11 +2381,13 @@ void ComposeControls::editMessage(not_null<HistoryItem*> item) {
|
||||||
const auto previewState = previewPage
|
const auto previewState = previewPage
|
||||||
? Data::PreviewState::Allowed
|
? Data::PreviewState::Allowed
|
||||||
: Data::PreviewState::EmptyOnEdit;
|
: Data::PreviewState::EmptyOnEdit;
|
||||||
|
const auto key = draftKey(DraftType::Edit);
|
||||||
_history->setDraft(
|
_history->setDraft(
|
||||||
draftKey(DraftType::Edit),
|
key,
|
||||||
std::make_unique<Data::Draft>(
|
std::make_unique<Data::Draft>(
|
||||||
editData,
|
editData,
|
||||||
item->id,
|
item->id,
|
||||||
|
key.topicRootId(),
|
||||||
cursor,
|
cursor,
|
||||||
previewState));
|
previewState));
|
||||||
applyDraft();
|
applyDraft();
|
||||||
|
@ -2424,6 +2427,7 @@ void ComposeControls::replyToMessage(FullMsgId id) {
|
||||||
std::make_unique<Data::Draft>(
|
std::make_unique<Data::Draft>(
|
||||||
TextWithTags(),
|
TextWithTags(),
|
||||||
id.msg,
|
id.msg,
|
||||||
|
key.topicRootId(),
|
||||||
MessageCursor(),
|
MessageCursor(),
|
||||||
Data::PreviewState::Allowed));
|
Data::PreviewState::Allowed));
|
||||||
}
|
}
|
||||||
|
@ -2438,7 +2442,6 @@ void ComposeControls::replyToMessage(FullMsgId id) {
|
||||||
|
|
||||||
void ComposeControls::cancelReplyMessage() {
|
void ComposeControls::cancelReplyMessage() {
|
||||||
Expects(_history != nullptr);
|
Expects(_history != nullptr);
|
||||||
Expects(draftKeyCurrent() != Data::DraftKey::None());
|
|
||||||
|
|
||||||
const auto wasReply = replyingToMessage();
|
const auto wasReply = replyingToMessage();
|
||||||
_header->replyToMessage({});
|
_header->replyToMessage({});
|
||||||
|
|
|
@ -645,7 +645,7 @@ BottomInfo::Data BottomInfoDataFromMessage(not_null<Message*> message) {
|
||||||
if (forwarded && forwarded->imported) {
|
if (forwarded && forwarded->imported) {
|
||||||
result.flags |= Flag::Imported;
|
result.flags |= Flag::Imported;
|
||||||
}
|
}
|
||||||
// We don't want to pass and update it in Date for now.
|
// We don't want to pass and update it in Data for now.
|
||||||
//if (item->unread()) {
|
//if (item->unread()) {
|
||||||
// result.flags |= Flag::Unread;
|
// result.flags |= Flag::Unread;
|
||||||
//}
|
//}
|
||||||
|
|
|
@ -185,7 +185,7 @@ bool SimpleElementDelegate::elementHideReply(not_null<const Element*> view) {
|
||||||
|
|
||||||
bool SimpleElementDelegate::elementShownUnread(
|
bool SimpleElementDelegate::elementShownUnread(
|
||||||
not_null<const Element*> view) {
|
not_null<const Element*> view) {
|
||||||
return view->data()->unread();
|
return view->data()->unread(view->data()->history());
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimpleElementDelegate::elementSendBotCommand(
|
void SimpleElementDelegate::elementSendBotCommand(
|
||||||
|
|
|
@ -553,7 +553,7 @@ bool PinnedWidget::listElementHideReply(not_null<const Element*> view) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PinnedWidget::listElementShownUnread(not_null<const Element*> view) {
|
bool PinnedWidget::listElementShownUnread(not_null<const Element*> view) {
|
||||||
return view->data()->unread();
|
return view->data()->unread(view->data()->history());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PinnedWidget::listIsGoodForAroundPosition(
|
bool PinnedWidget::listIsGoodForAroundPosition(
|
||||||
|
|
|
@ -351,8 +351,8 @@ RepliesWidget::RepliesWidget(
|
||||||
}
|
}
|
||||||
|
|
||||||
RepliesWidget::~RepliesWidget() {
|
RepliesWidget::~RepliesWidget() {
|
||||||
if (_topic && _topic->forum()->creating(_rootId)) {
|
if (_topic && _topic->creating()) {
|
||||||
_topic->forum()->discardCreatingId(_rootId);
|
_topic->discard();
|
||||||
_topic = nullptr;
|
_topic = nullptr;
|
||||||
}
|
}
|
||||||
base::take(_sendAction);
|
base::take(_sendAction);
|
||||||
|
@ -434,15 +434,20 @@ void RepliesWidget::setupRootView() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RepliesWidget::setupTopicViewer() {
|
void RepliesWidget::setupTopicViewer() {
|
||||||
_history->owner().itemIdChanged(
|
const auto owner = &_history->owner();
|
||||||
|
owner->itemIdChanged(
|
||||||
) | rpl::start_with_next([=](const Data::Session::IdChange &change) {
|
) | rpl::start_with_next([=](const Data::Session::IdChange &change) {
|
||||||
if (_rootId == change.oldId) {
|
if (_rootId == change.oldId) {
|
||||||
_rootId = change.newId.msg;
|
_rootId = change.newId.msg;
|
||||||
|
_sendAction = owner->sendActionManager().repliesPainter(
|
||||||
|
_history,
|
||||||
|
_rootId);
|
||||||
_root = lookupRoot();
|
_root = lookupRoot();
|
||||||
if (_topic && _topic->rootId() == change.oldId) {
|
if (_topic && _topic->rootId() == change.oldId) {
|
||||||
setTopic(_topic->forum()->topicFor(change.newId.msg));
|
setTopic(_topic->forum()->topicFor(change.newId.msg));
|
||||||
} else {
|
} else {
|
||||||
refreshReplies();
|
refreshReplies();
|
||||||
|
refreshTopBarActiveChat();
|
||||||
}
|
}
|
||||||
_inner->update();
|
_inner->update();
|
||||||
}
|
}
|
||||||
|
@ -1007,6 +1012,7 @@ Api::SendAction RepliesWidget::prepareSendAction(
|
||||||
Api::SendOptions options) const {
|
Api::SendOptions options) const {
|
||||||
auto result = Api::SendAction(_history, options);
|
auto result = Api::SendAction(_history, options);
|
||||||
result.replyTo = replyToId();
|
result.replyTo = replyToId();
|
||||||
|
result.topicRootId = _rootId;
|
||||||
result.options.sendAs = _composeControls->sendAsPeer();
|
result.options.sendAs = _composeControls->sendAsPeer();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -1440,7 +1446,7 @@ bool RepliesWidget::preventsClose(Fn<void()> &&continueCallback) const {
|
||||||
return true;
|
return true;
|
||||||
} else if (!_newTopicDiscarded
|
} else if (!_newTopicDiscarded
|
||||||
&& _topic
|
&& _topic
|
||||||
&& _topic->forum()->creating(_rootId)) {
|
&& _topic->creating()) {
|
||||||
const auto weak = Ui::MakeWeak(this);
|
const auto weak = Ui::MakeWeak(this);
|
||||||
auto sure = [=](Fn<void()> &&close) {
|
auto sure = [=](Fn<void()> &&close) {
|
||||||
if (const auto strong = weak.data()) {
|
if (const auto strong = weak.data()) {
|
||||||
|
@ -1943,14 +1949,7 @@ bool RepliesWidget::listElementHideReply(not_null<const Element*> view) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RepliesWidget::listElementShownUnread(not_null<const Element*> view) {
|
bool RepliesWidget::listElementShownUnread(not_null<const Element*> view) {
|
||||||
if (!_root) {
|
return _replies->isServerSideUnread(view->data());
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const auto item = view->data();
|
|
||||||
const auto till = item->out()
|
|
||||||
? _replies->computeOutboxReadTillFull()
|
|
||||||
: _replies->computeInboxReadTillFull();
|
|
||||||
return (item->id > till);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RepliesWidget::listIsGoodForAroundPosition(
|
bool RepliesWidget::listIsGoodForAroundPosition(
|
||||||
|
|
|
@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
#include "data/data_send_action.h"
|
#include "data/data_send_action.h"
|
||||||
|
#include "data/data_forum_topic.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "history/history.h"
|
#include "history/history.h"
|
||||||
|
@ -39,13 +40,20 @@ constexpr auto kStatusShowClientsideSpeaking = 6 * crl::time(1000);
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
SendActionPainter::SendActionPainter(not_null<History*> history)
|
SendActionPainter::SendActionPainter(
|
||||||
|
not_null<History*> history,
|
||||||
|
MsgId rootId)
|
||||||
: _history(history)
|
: _history(history)
|
||||||
|
, _rootId(rootId)
|
||||||
, _weak(&_history->session())
|
, _weak(&_history->session())
|
||||||
, _st(st::dialogsTextStyle)
|
, _st(st::dialogsTextStyle)
|
||||||
, _sendActionText(st::dialogsTextWidthMin) {
|
, _sendActionText(st::dialogsTextWidthMin) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SendActionPainter::setTopic(Data::ForumTopic *topic) {
|
||||||
|
_topic = topic;
|
||||||
|
}
|
||||||
|
|
||||||
bool SendActionPainter::updateNeedsAnimating(
|
bool SendActionPainter::updateNeedsAnimating(
|
||||||
not_null<UserData*> user,
|
not_null<UserData*> user,
|
||||||
const MTPSendMessageAction &action) {
|
const MTPSendMessageAction &action) {
|
||||||
|
@ -382,7 +390,7 @@ bool SendActionPainter::updateNeedsAnimating(crl::time now, bool force) {
|
||||||
st::normalFont->height,
|
st::normalFont->height,
|
||||||
st::dialogsMiniPreviewTop + st::dialogsMiniPreview);
|
st::dialogsMiniPreviewTop + st::dialogsMiniPreview);
|
||||||
_history->peer->owner().sendActionManager().updateAnimation({
|
_history->peer->owner().sendActionManager().updateAnimation({
|
||||||
_history,
|
_topic ? ((Data::Thread*)_topic) : _history,
|
||||||
0,
|
0,
|
||||||
_sendActionAnimation.width() + _animationLeft,
|
_sendActionAnimation.width() + _animationLeft,
|
||||||
height,
|
height,
|
||||||
|
|
|
@ -16,6 +16,10 @@ namespace Main {
|
||||||
class Session;
|
class Session;
|
||||||
} // namespace Main
|
} // namespace Main
|
||||||
|
|
||||||
|
namespace Data {
|
||||||
|
class ForumTopic;
|
||||||
|
} // namespace Data
|
||||||
|
|
||||||
namespace Api {
|
namespace Api {
|
||||||
enum class SendProgressType;
|
enum class SendProgressType;
|
||||||
struct SendProgress;
|
struct SendProgress;
|
||||||
|
@ -25,7 +29,9 @@ namespace HistoryView {
|
||||||
|
|
||||||
class SendActionPainter final {
|
class SendActionPainter final {
|
||||||
public:
|
public:
|
||||||
explicit SendActionPainter(not_null<History*> history);
|
explicit SendActionPainter(not_null<History*> history, MsgId rootId = 0);
|
||||||
|
|
||||||
|
void setTopic(Data::ForumTopic *topic);
|
||||||
|
|
||||||
bool paint(
|
bool paint(
|
||||||
Painter &p,
|
Painter &p,
|
||||||
|
@ -53,8 +59,10 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const not_null<History*> _history;
|
const not_null<History*> _history;
|
||||||
|
const MsgId _rootId = 0;
|
||||||
const base::weak_ptr<Main::Session> _weak;
|
const base::weak_ptr<Main::Session> _weak;
|
||||||
const style::TextStyle &_st;
|
const style::TextStyle &_st;
|
||||||
|
Data::ForumTopic *_topic = nullptr;
|
||||||
base::flat_map<not_null<UserData*>, crl::time> _typing;
|
base::flat_map<not_null<UserData*>, crl::time> _typing;
|
||||||
base::flat_map<not_null<UserData*>, crl::time> _speaking;
|
base::flat_map<not_null<UserData*>, crl::time> _speaking;
|
||||||
base::flat_map<not_null<UserData*>, Api::SendProgress> _sendActions;
|
base::flat_map<not_null<UserData*>, Api::SendProgress> _sendActions;
|
||||||
|
|
|
@ -152,7 +152,7 @@ TopBarWidget::TopBarWidget(
|
||||||
using AnimationUpdate = Data::SendActionManager::AnimationUpdate;
|
using AnimationUpdate = Data::SendActionManager::AnimationUpdate;
|
||||||
session().data().sendActionManager().animationUpdated(
|
session().data().sendActionManager().animationUpdated(
|
||||||
) | rpl::filter([=](const AnimationUpdate &update) {
|
) | rpl::filter([=](const AnimationUpdate &update) {
|
||||||
return (update.history == _activeChat.key.history());
|
return (update.thread == _activeChat.key.thread());
|
||||||
}) | rpl::start_with_next([=] {
|
}) | rpl::start_with_next([=] {
|
||||||
update();
|
update();
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
@ -722,6 +722,7 @@ void TopBarWidget::backClicked() {
|
||||||
void TopBarWidget::setActiveChat(
|
void TopBarWidget::setActiveChat(
|
||||||
ActiveChat activeChat,
|
ActiveChat activeChat,
|
||||||
SendActionPainter *sendAction) {
|
SendActionPainter *sendAction) {
|
||||||
|
_sendAction = sendAction;
|
||||||
if (_activeChat.key == activeChat.key
|
if (_activeChat.key == activeChat.key
|
||||||
&& _activeChat.section == activeChat.section) {
|
&& _activeChat.section == activeChat.section) {
|
||||||
_activeChat = activeChat;
|
_activeChat = activeChat;
|
||||||
|
@ -733,7 +734,6 @@ void TopBarWidget::setActiveChat(
|
||||||
!= activeChat.key.history());
|
!= activeChat.key.history());
|
||||||
|
|
||||||
_activeChat = activeChat;
|
_activeChat = activeChat;
|
||||||
_sendAction = sendAction;
|
|
||||||
_titlePeerText.clear();
|
_titlePeerText.clear();
|
||||||
_back->clearState();
|
_back->clearState();
|
||||||
update();
|
update();
|
||||||
|
|
|
@ -204,29 +204,35 @@ void Controller::setupMigrationViewer() {
|
||||||
) | rpl::filter([=] {
|
) | rpl::filter([=] {
|
||||||
return peer->migrateTo() || (peer->migrateFrom() != _migrated);
|
return peer->migrateTo() || (peer->migrateFrom() != _migrated);
|
||||||
}) | rpl::start_with_next([=] {
|
}) | rpl::start_with_next([=] {
|
||||||
const auto window = parentController();
|
replaceWith(std::make_shared<Memento>(peer, _section));
|
||||||
const auto section = _section;
|
|
||||||
auto params = Window::SectionShow(
|
|
||||||
Window::SectionShow::Way::Backward,
|
|
||||||
anim::type::instant,
|
|
||||||
anim::activation::background);
|
|
||||||
if (wrap() == Wrap::Side) {
|
|
||||||
params.thirdColumn = true;
|
|
||||||
}
|
|
||||||
InvokeQueued(_widget, [=] {
|
|
||||||
window->showSection(
|
|
||||||
std::make_shared<Memento>(peer, section),
|
|
||||||
params);
|
|
||||||
});
|
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Controller::replaceWith(std::shared_ptr<Memento> memento) {
|
||||||
|
const auto window = parentController();
|
||||||
|
const auto section = _section;
|
||||||
|
auto params = Window::SectionShow(
|
||||||
|
Window::SectionShow::Way::Backward,
|
||||||
|
anim::type::instant,
|
||||||
|
anim::activation::background);
|
||||||
|
if (wrap() == Wrap::Side) {
|
||||||
|
params.thirdColumn = true;
|
||||||
|
}
|
||||||
|
InvokeQueued(_widget, [=, memento = std::move(memento)]() mutable {
|
||||||
|
window->showSection(std::move(memento), params);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void Controller::setupTopicViewer() {
|
void Controller::setupTopicViewer() {
|
||||||
session().data().itemIdChanged(
|
session().data().itemIdChanged(
|
||||||
) | rpl::start_with_next([=](const Data::Session::IdChange &change) {
|
) | rpl::start_with_next([=](const Data::Session::IdChange &change) {
|
||||||
if (const auto topic = _key.topic()) {
|
if (const auto topic = _key.topic()) {
|
||||||
if (topic->rootId() == change.oldId) {
|
if (topic->rootId() == change.oldId
|
||||||
_key = Key(topic->forum()->topicFor(change.newId.msg));
|
|| (topic->peer()->id == change.newId.peer
|
||||||
|
&& topic->rootId() == change.newId.msg)) {
|
||||||
|
const auto now = topic->forum()->topicFor(change.newId.msg);
|
||||||
|
_key = Key(now);
|
||||||
|
replaceWith(std::make_shared<Memento>(now, _section));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, _lifetime);
|
}, _lifetime);
|
||||||
|
|
|
@ -240,6 +240,8 @@ private:
|
||||||
void setupMigrationViewer();
|
void setupMigrationViewer();
|
||||||
void setupTopicViewer();
|
void setupTopicViewer();
|
||||||
|
|
||||||
|
void replaceWith(std::shared_ptr<Memento> memento);
|
||||||
|
|
||||||
not_null<WrapWidget*> _widget;
|
not_null<WrapWidget*> _widget;
|
||||||
Key _key;
|
Key _key;
|
||||||
PeerData *_migrated = nullptr;
|
PeerData *_migrated = nullptr;
|
||||||
|
|
|
@ -577,6 +577,8 @@ Ui::MultiSlideTracker DetailsFiller::fillChannelButtons(
|
||||||
}
|
}
|
||||||
|
|
||||||
object_ptr<Ui::RpWidget> DetailsFiller::fill() {
|
object_ptr<Ui::RpWidget> DetailsFiller::fill() {
|
||||||
|
Expects(!_topic || !_topic->creating());
|
||||||
|
|
||||||
add(object_ptr<Ui::BoxContentDivider>(_wrap));
|
add(object_ptr<Ui::BoxContentDivider>(_wrap));
|
||||||
add(CreateSkipWidget(_wrap));
|
add(CreateSkipWidget(_wrap));
|
||||||
add(setupInfo());
|
add(setupInfo());
|
||||||
|
@ -585,6 +587,7 @@ object_ptr<Ui::RpWidget> DetailsFiller::fill() {
|
||||||
}
|
}
|
||||||
setupMainButtons();
|
setupMainButtons();
|
||||||
add(CreateSkipWidget(_wrap));
|
add(CreateSkipWidget(_wrap));
|
||||||
|
|
||||||
return std::move(_wrap);
|
return std::move(_wrap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -83,6 +83,9 @@ object_ptr<Ui::RpWidget> InnerWidget::setupContent(
|
||||||
}, _cover->lifetime());
|
}, _cover->lifetime());
|
||||||
_cover->setOnlineCount(rpl::single(0));
|
_cover->setOnlineCount(rpl::single(0));
|
||||||
if (_topic) {
|
if (_topic) {
|
||||||
|
if (_topic->creating()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
result->add(SetupDetails(_controller, parent, _topic));
|
result->add(SetupDetails(_controller, parent, _topic));
|
||||||
} else {
|
} else {
|
||||||
result->add(SetupDetails(_controller, parent, _peer));
|
result->add(SetupDetails(_controller, parent, _peer));
|
||||||
|
|
|
@ -555,12 +555,14 @@ bool MainWidget::shareUrl(
|
||||||
QFIXED_MAX
|
QFIXED_MAX
|
||||||
};
|
};
|
||||||
const auto history = peer->owner().history(peer);
|
const auto history = peer->owner().history(peer);
|
||||||
|
const auto topicRootId = 0;
|
||||||
history->setLocalDraft(std::make_unique<Data::Draft>(
|
history->setLocalDraft(std::make_unique<Data::Draft>(
|
||||||
textWithTags,
|
textWithTags,
|
||||||
0,
|
0, // replyTo
|
||||||
|
topicRootId,
|
||||||
cursor,
|
cursor,
|
||||||
Data::PreviewState::Allowed));
|
Data::PreviewState::Allowed));
|
||||||
history->clearLocalEditDraft();
|
history->clearLocalEditDraft(topicRootId);
|
||||||
history->session().changes().historyUpdated(
|
history->session().changes().historyUpdated(
|
||||||
history,
|
history,
|
||||||
Data::HistoryUpdate::Flag::LocalDraftSet);
|
Data::HistoryUpdate::Flag::LocalDraftSet);
|
||||||
|
@ -587,12 +589,14 @@ bool MainWidget::inlineSwitchChosen(
|
||||||
int(botAndQuery.size()),
|
int(botAndQuery.size()),
|
||||||
QFIXED_MAX
|
QFIXED_MAX
|
||||||
};
|
};
|
||||||
|
const auto topicRootId = 0;
|
||||||
h->setLocalDraft(std::make_unique<Data::Draft>(
|
h->setLocalDraft(std::make_unique<Data::Draft>(
|
||||||
textWithTags,
|
textWithTags,
|
||||||
0,
|
0, // replyTo
|
||||||
|
topicRootId,
|
||||||
cursor,
|
cursor,
|
||||||
Data::PreviewState::Allowed));
|
Data::PreviewState::Allowed));
|
||||||
h->clearLocalEditDraft();
|
h->clearLocalEditDraft(topicRootId);
|
||||||
h->session().changes().historyUpdated(
|
h->session().changes().historyUpdated(
|
||||||
h,
|
h,
|
||||||
Data::HistoryUpdate::Flag::LocalDraftSet);
|
Data::HistoryUpdate::Flag::LocalDraftSet);
|
||||||
|
|
|
@ -1587,7 +1587,7 @@ void FormController::uploadEncryptedFile(
|
||||||
auto prepared = std::make_shared<FileLoadResult>(
|
auto prepared = std::make_shared<FileLoadResult>(
|
||||||
TaskId(),
|
TaskId(),
|
||||||
file.uploadData->fileId,
|
file.uploadData->fileId,
|
||||||
FileLoadTo(PeerId(), Api::SendOptions(), MsgId(), MsgId()),
|
FileLoadTo(PeerId(), Api::SendOptions(), MsgId(), MsgId(), MsgId()),
|
||||||
TextWithTags(),
|
TextWithTags(),
|
||||||
std::shared_ptr<SendingAlbum>(nullptr));
|
std::shared_ptr<SendingAlbum>(nullptr));
|
||||||
prepared->type = SendMediaType::Secure;
|
prepared->type = SendMediaType::Secure;
|
||||||
|
|
|
@ -200,15 +200,18 @@ struct FileLoadTo {
|
||||||
PeerId peer,
|
PeerId peer,
|
||||||
Api::SendOptions options,
|
Api::SendOptions options,
|
||||||
MsgId replyTo,
|
MsgId replyTo,
|
||||||
|
MsgId topicRootId,
|
||||||
MsgId replaceMediaOf)
|
MsgId replaceMediaOf)
|
||||||
: peer(peer)
|
: peer(peer)
|
||||||
, options(options)
|
, options(options)
|
||||||
, replyTo(replyTo)
|
, replyTo(replyTo)
|
||||||
|
, topicRootId(topicRootId)
|
||||||
, replaceMediaOf(replaceMediaOf) {
|
, replaceMediaOf(replaceMediaOf) {
|
||||||
}
|
}
|
||||||
PeerId peer;
|
PeerId peer;
|
||||||
Api::SendOptions options;
|
Api::SendOptions options;
|
||||||
MsgId replyTo;
|
MsgId replyTo;
|
||||||
|
MsgId topicRootId;
|
||||||
MsgId replaceMediaOf;
|
MsgId replaceMediaOf;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1025,17 +1025,20 @@ std::unique_ptr<MTP::Config> Account::readMtpConfig() {
|
||||||
template <typename Callback>
|
template <typename Callback>
|
||||||
void EnumerateDrafts(
|
void EnumerateDrafts(
|
||||||
const Data::HistoryDrafts &map,
|
const Data::HistoryDrafts &map,
|
||||||
Data::Draft *cloudDraft,
|
|
||||||
bool supportMode,
|
bool supportMode,
|
||||||
const base::flat_map<Data::DraftKey, MessageDraftSource> &sources,
|
const base::flat_map<Data::DraftKey, MessageDraftSource> &sources,
|
||||||
Callback &&callback) {
|
Callback &&callback) {
|
||||||
for (const auto &[key, draft] : map) {
|
for (const auto &[key, draft] : map) {
|
||||||
if (key == Data::DraftKey::Cloud() || sources.contains(key)) {
|
if (key.isCloud() || sources.contains(key)) {
|
||||||
continue;
|
|
||||||
} else if (key == Data::DraftKey::Local()
|
|
||||||
&& !supportMode
|
|
||||||
&& Data::draftsAreEqual(draft.get(), cloudDraft)) {
|
|
||||||
continue;
|
continue;
|
||||||
|
} else if (key.isLocal()
|
||||||
|
&& (!supportMode || key.topicRootId())) {
|
||||||
|
const auto i = map.find(
|
||||||
|
Data::DraftKey::Cloud(key.topicRootId()));
|
||||||
|
const auto cloud = (i != end(map)) ? i->second.get() : nullptr;
|
||||||
|
if (Data::DraftsAreEqual(draft.get(), cloud)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
callback(
|
callback(
|
||||||
key,
|
key,
|
||||||
|
@ -1085,10 +1088,6 @@ void Account::unregisterDraftSource(
|
||||||
void Account::writeDrafts(not_null<History*> history) {
|
void Account::writeDrafts(not_null<History*> history) {
|
||||||
const auto peerId = history->peer->id;
|
const auto peerId = history->peer->id;
|
||||||
const auto &map = history->draftsMap();
|
const auto &map = history->draftsMap();
|
||||||
const auto cloudIt = map.find(Data::DraftKey::Cloud());
|
|
||||||
const auto cloudDraft = (cloudIt != end(map))
|
|
||||||
? cloudIt->second.get()
|
|
||||||
: nullptr;
|
|
||||||
const auto supportMode = _owner->session().supportMode();
|
const auto supportMode = _owner->session().supportMode();
|
||||||
const auto sourcesIt = _draftSources.find(history);
|
const auto sourcesIt = _draftSources.find(history);
|
||||||
const auto &sources = (sourcesIt != _draftSources.end())
|
const auto &sources = (sourcesIt != _draftSources.end())
|
||||||
|
@ -1097,7 +1096,6 @@ void Account::writeDrafts(not_null<History*> history) {
|
||||||
auto count = 0;
|
auto count = 0;
|
||||||
EnumerateDrafts(
|
EnumerateDrafts(
|
||||||
map,
|
map,
|
||||||
cloudDraft,
|
|
||||||
supportMode,
|
supportMode,
|
||||||
sources,
|
sources,
|
||||||
[&](auto&&...) { ++count; });
|
[&](auto&&...) { ++count; });
|
||||||
|
@ -1133,7 +1131,6 @@ void Account::writeDrafts(not_null<History*> history) {
|
||||||
};
|
};
|
||||||
EnumerateDrafts(
|
EnumerateDrafts(
|
||||||
map,
|
map,
|
||||||
cloudDraft,
|
|
||||||
supportMode,
|
supportMode,
|
||||||
sources,
|
sources,
|
||||||
sizeCallback);
|
sizeCallback);
|
||||||
|
@ -1159,7 +1156,6 @@ void Account::writeDrafts(not_null<History*> history) {
|
||||||
};
|
};
|
||||||
EnumerateDrafts(
|
EnumerateDrafts(
|
||||||
map,
|
map,
|
||||||
cloudDraft,
|
|
||||||
supportMode,
|
supportMode,
|
||||||
sources,
|
sources,
|
||||||
writeCallback);
|
writeCallback);
|
||||||
|
@ -1173,10 +1169,6 @@ void Account::writeDrafts(not_null<History*> history) {
|
||||||
void Account::writeDraftCursors(not_null<History*> history) {
|
void Account::writeDraftCursors(not_null<History*> history) {
|
||||||
const auto peerId = history->peer->id;
|
const auto peerId = history->peer->id;
|
||||||
const auto &map = history->draftsMap();
|
const auto &map = history->draftsMap();
|
||||||
const auto cloudIt = map.find(Data::DraftKey::Cloud());
|
|
||||||
const auto cloudDraft = (cloudIt != end(map))
|
|
||||||
? cloudIt->second.get()
|
|
||||||
: nullptr;
|
|
||||||
const auto supportMode = _owner->session().supportMode();
|
const auto supportMode = _owner->session().supportMode();
|
||||||
const auto sourcesIt = _draftSources.find(history);
|
const auto sourcesIt = _draftSources.find(history);
|
||||||
const auto &sources = (sourcesIt != _draftSources.end())
|
const auto &sources = (sourcesIt != _draftSources.end())
|
||||||
|
@ -1185,7 +1177,6 @@ void Account::writeDraftCursors(not_null<History*> history) {
|
||||||
auto count = 0;
|
auto count = 0;
|
||||||
EnumerateDrafts(
|
EnumerateDrafts(
|
||||||
map,
|
map,
|
||||||
cloudDraft,
|
|
||||||
supportMode,
|
supportMode,
|
||||||
sources,
|
sources,
|
||||||
[&](auto&&...) { ++count; });
|
[&](auto&&...) { ++count; });
|
||||||
|
@ -1223,7 +1214,6 @@ void Account::writeDraftCursors(not_null<History*> history) {
|
||||||
};
|
};
|
||||||
EnumerateDrafts(
|
EnumerateDrafts(
|
||||||
map,
|
map,
|
||||||
cloudDraft,
|
|
||||||
supportMode,
|
supportMode,
|
||||||
sources,
|
sources,
|
||||||
writeCallback);
|
writeCallback);
|
||||||
|
@ -1282,7 +1272,7 @@ void Account::readDraftCursors(PeerId peerId, Data::HistoryDrafts &map) {
|
||||||
? Data::DraftKey::FromSerialized(keyValue)
|
? Data::DraftKey::FromSerialized(keyValue)
|
||||||
: keysOld
|
: keysOld
|
||||||
? Data::DraftKey::FromSerializedOld(keyValueOld)
|
? Data::DraftKey::FromSerializedOld(keyValueOld)
|
||||||
: Data::DraftKey::Local();
|
: Data::DraftKey::Local(0);
|
||||||
qint32 position = 0, anchor = 0, scroll = QFIXED_MAX;
|
qint32 position = 0, anchor = 0, scroll = QFIXED_MAX;
|
||||||
draft.stream >> position >> anchor >> scroll;
|
draft.stream >> position >> anchor >> scroll;
|
||||||
if (const auto i = map.find(key); i != end(map)) {
|
if (const auto i = map.find(key); i != end(map)) {
|
||||||
|
@ -1309,13 +1299,14 @@ void Account::readDraftCursorsLegacy(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (const auto i = map.find(Data::DraftKey::Local()); i != end(map)) {
|
if (const auto i = map.find(Data::DraftKey::Local({})); i != end(map)) {
|
||||||
i->second->cursor = MessageCursor(
|
i->second->cursor = MessageCursor(
|
||||||
localPosition,
|
localPosition,
|
||||||
localAnchor,
|
localAnchor,
|
||||||
localScroll);
|
localScroll);
|
||||||
}
|
}
|
||||||
if (const auto i = map.find(Data::DraftKey::LocalEdit()); i != end(map)) {
|
if (const auto i = map.find(Data::DraftKey::LocalEdit({}))
|
||||||
|
; i != end(map)) {
|
||||||
i->second->cursor = MessageCursor(
|
i->second->cursor = MessageCursor(
|
||||||
editPosition,
|
editPosition,
|
||||||
editAnchor,
|
editAnchor,
|
||||||
|
@ -1327,7 +1318,7 @@ void Account::readDraftsWithCursors(not_null<History*> history) {
|
||||||
const auto guard = gsl::finally([&] {
|
const auto guard = gsl::finally([&] {
|
||||||
if (const auto migrated = history->migrateFrom()) {
|
if (const auto migrated = history->migrateFrom()) {
|
||||||
readDraftsWithCursors(migrated);
|
readDraftsWithCursors(migrated);
|
||||||
migrated->clearLocalEditDraft();
|
migrated->clearLocalEditDraft({});
|
||||||
history->takeLocalDraft(migrated);
|
history->takeLocalDraft(migrated);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1396,10 +1387,11 @@ void Account::readDraftsWithCursors(not_null<History*> history) {
|
||||||
const auto key = keysOld
|
const auto key = keysOld
|
||||||
? Data::DraftKey::FromSerializedOld(keyValueOld)
|
? Data::DraftKey::FromSerializedOld(keyValueOld)
|
||||||
: Data::DraftKey::FromSerialized(keyValue);
|
: Data::DraftKey::FromSerialized(keyValue);
|
||||||
if (key && key != Data::DraftKey::Cloud()) {
|
if (key && !key.isCloud()) {
|
||||||
map.emplace(key, std::make_unique<Data::Draft>(
|
map.emplace(key, std::make_unique<Data::Draft>(
|
||||||
data,
|
data,
|
||||||
messageId,
|
messageId,
|
||||||
|
key.topicRootId(),
|
||||||
MessageCursor(),
|
MessageCursor(),
|
||||||
previewState));
|
previewState));
|
||||||
}
|
}
|
||||||
|
@ -1457,24 +1449,31 @@ void Account::readDraftsWithCursorsLegacy(
|
||||||
editTagsSerialized,
|
editTagsSerialized,
|
||||||
editData.text.size());
|
editData.text.size());
|
||||||
|
|
||||||
|
const auto topicRootId = MsgId();
|
||||||
auto map = base::flat_map<Data::DraftKey, std::unique_ptr<Data::Draft>>();
|
auto map = base::flat_map<Data::DraftKey, std::unique_ptr<Data::Draft>>();
|
||||||
if (!msgData.text.isEmpty() || msgReplyTo) {
|
if (!msgData.text.isEmpty() || msgReplyTo) {
|
||||||
map.emplace(Data::DraftKey::Local(), std::make_unique<Data::Draft>(
|
map.emplace(
|
||||||
msgData,
|
Data::DraftKey::Local(topicRootId),
|
||||||
msgReplyTo,
|
std::make_unique<Data::Draft>(
|
||||||
MessageCursor(),
|
msgData,
|
||||||
(msgPreviewCancelled
|
msgReplyTo,
|
||||||
? Data::PreviewState::Cancelled
|
topicRootId,
|
||||||
: Data::PreviewState::Allowed)));
|
MessageCursor(),
|
||||||
|
(msgPreviewCancelled
|
||||||
|
? Data::PreviewState::Cancelled
|
||||||
|
: Data::PreviewState::Allowed)));
|
||||||
}
|
}
|
||||||
if (editMsgId) {
|
if (editMsgId) {
|
||||||
map.emplace(Data::DraftKey::LocalEdit(), std::make_unique<Data::Draft>(
|
map.emplace(
|
||||||
editData,
|
Data::DraftKey::LocalEdit(topicRootId),
|
||||||
editMsgId,
|
std::make_unique<Data::Draft>(
|
||||||
MessageCursor(),
|
editData,
|
||||||
(editPreviewCancelled
|
editMsgId,
|
||||||
? Data::PreviewState::Cancelled
|
topicRootId,
|
||||||
: Data::PreviewState::Allowed)));
|
MessageCursor(),
|
||||||
|
(editPreviewCancelled
|
||||||
|
? Data::PreviewState::Cancelled
|
||||||
|
: Data::PreviewState::Allowed)));
|
||||||
}
|
}
|
||||||
readDraftCursors(peerId, map);
|
readDraftCursors(peerId, map);
|
||||||
history->setDraftsMap(std::move(map));
|
history->setDraftsMap(std::move(map));
|
||||||
|
|
|
@ -47,6 +47,7 @@ namespace {
|
||||||
constexpr auto kOccupyFor = TimeId(60);
|
constexpr auto kOccupyFor = TimeId(60);
|
||||||
constexpr auto kReoccupyEach = 30 * crl::time(1000);
|
constexpr auto kReoccupyEach = 30 * crl::time(1000);
|
||||||
constexpr auto kMaxSupportInfoLength = MaxMessageSize * 4;
|
constexpr auto kMaxSupportInfoLength = MaxMessageSize * 4;
|
||||||
|
constexpr auto kTopicRootId = MsgId(0);
|
||||||
|
|
||||||
class EditInfoBox : public Ui::BoxContent {
|
class EditInfoBox : public Ui::BoxContent {
|
||||||
public:
|
public:
|
||||||
|
@ -157,7 +158,8 @@ Data::Draft OccupiedDraft(const QString &normalizedName) {
|
||||||
+ QString::number(OccupationTag())
|
+ QString::number(OccupationTag())
|
||||||
+ ";n:"
|
+ ";n:"
|
||||||
+ normalizedName },
|
+ normalizedName },
|
||||||
MsgId(0),
|
MsgId(0), // replyTo
|
||||||
|
kTopicRootId,
|
||||||
MessageCursor(),
|
MessageCursor(),
|
||||||
Data::PreviewState::Allowed
|
Data::PreviewState::Allowed
|
||||||
};
|
};
|
||||||
|
@ -176,7 +178,7 @@ uint32 ParseOccupationTag(History *history) {
|
||||||
if (!TrackHistoryOccupation(history)) {
|
if (!TrackHistoryOccupation(history)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
const auto draft = history->cloudDraft();
|
const auto draft = history->cloudDraft(kTopicRootId);
|
||||||
if (!draft) {
|
if (!draft) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -202,7 +204,7 @@ QString ParseOccupationName(History *history) {
|
||||||
if (!TrackHistoryOccupation(history)) {
|
if (!TrackHistoryOccupation(history)) {
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
const auto draft = history->cloudDraft();
|
const auto draft = history->cloudDraft(kTopicRootId);
|
||||||
if (!draft) {
|
if (!draft) {
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
|
@ -228,7 +230,7 @@ TimeId OccupiedBySomeoneTill(History *history) {
|
||||||
if (!TrackHistoryOccupation(history)) {
|
if (!TrackHistoryOccupation(history)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
const auto draft = history->cloudDraft();
|
const auto draft = history->cloudDraft(kTopicRootId);
|
||||||
if (!draft) {
|
if (!draft) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -340,7 +342,7 @@ void Helper::updateOccupiedHistory(
|
||||||
not_null<Window::SessionController*> controller,
|
not_null<Window::SessionController*> controller,
|
||||||
History *history) {
|
History *history) {
|
||||||
if (isOccupiedByMe(_occupiedHistory)) {
|
if (isOccupiedByMe(_occupiedHistory)) {
|
||||||
_occupiedHistory->clearCloudDraft();
|
_occupiedHistory->clearCloudDraft(kTopicRootId);
|
||||||
_session->api().saveDraftToCloudDelayed(_occupiedHistory);
|
_session->api().saveDraftToCloudDelayed(_occupiedHistory);
|
||||||
}
|
}
|
||||||
_occupiedHistory = history;
|
_occupiedHistory = history;
|
||||||
|
@ -364,7 +366,7 @@ void Helper::occupyInDraft() {
|
||||||
&& !isOccupiedBySomeone(_occupiedHistory)
|
&& !isOccupiedBySomeone(_occupiedHistory)
|
||||||
&& !_supportName.isEmpty()) {
|
&& !_supportName.isEmpty()) {
|
||||||
const auto draft = OccupiedDraft(_supportNameNormalized);
|
const auto draft = OccupiedDraft(_supportNameNormalized);
|
||||||
_occupiedHistory->createCloudDraft(&draft);
|
_occupiedHistory->createCloudDraft(kTopicRootId, &draft);
|
||||||
_session->api().saveDraftToCloudDelayed(_occupiedHistory);
|
_session->api().saveDraftToCloudDelayed(_occupiedHistory);
|
||||||
_reoccupyTimer.callEach(kReoccupyEach);
|
_reoccupyTimer.callEach(kReoccupyEach);
|
||||||
}
|
}
|
||||||
|
@ -373,7 +375,7 @@ void Helper::occupyInDraft() {
|
||||||
void Helper::reoccupy() {
|
void Helper::reoccupy() {
|
||||||
if (isOccupiedByMe(_occupiedHistory)) {
|
if (isOccupiedByMe(_occupiedHistory)) {
|
||||||
const auto draft = OccupiedDraft(_supportNameNormalized);
|
const auto draft = OccupiedDraft(_supportNameNormalized);
|
||||||
_occupiedHistory->createCloudDraft(&draft);
|
_occupiedHistory->createCloudDraft(kTopicRootId, &draft);
|
||||||
_session->api().saveDraftToCloudDelayed(_occupiedHistory);
|
_session->api().saveDraftToCloudDelayed(_occupiedHistory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -979,6 +979,10 @@ void Manager::notificationActivated(
|
||||||
const auto window = session->windows().front();
|
const auto window = session->windows().front();
|
||||||
const auto history = session->data().history(
|
const auto history = session->data().history(
|
||||||
id.contextId.peerId);
|
id.contextId.peerId);
|
||||||
|
const auto item = history->owner().message(
|
||||||
|
history->peer,
|
||||||
|
id.msgId);
|
||||||
|
const auto topic = item ? item->topic() : nullptr;
|
||||||
if (!reply.text.isEmpty()) {
|
if (!reply.text.isEmpty()) {
|
||||||
// #TODO forum notifications
|
// #TODO forum notifications
|
||||||
const auto replyToId = (id.msgId > 0
|
const auto replyToId = (id.msgId > 0
|
||||||
|
@ -988,6 +992,7 @@ void Manager::notificationActivated(
|
||||||
auto draft = std::make_unique<Data::Draft>(
|
auto draft = std::make_unique<Data::Draft>(
|
||||||
reply,
|
reply,
|
||||||
replyToId,
|
replyToId,
|
||||||
|
(topic ? topic->rootId() : 0),
|
||||||
MessageCursor{
|
MessageCursor{
|
||||||
int(reply.text.size()),
|
int(reply.text.size()),
|
||||||
int(reply.text.size()),
|
int(reply.text.size()),
|
||||||
|
@ -1057,16 +1062,18 @@ void Manager::notificationReplied(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto history = session->data().history(id.contextId.peerId);
|
const auto history = session->data().history(id.contextId.peerId);
|
||||||
|
const auto item = history->owner().message(history->peer, id.msgId);
|
||||||
|
const auto topic = item ? item->topic() : nullptr;
|
||||||
|
|
||||||
auto message = Api::MessageToSend(Api::SendAction(history));
|
auto message = Api::MessageToSend(Api::SendAction(history));
|
||||||
message.textWithTags = reply;
|
message.textWithTags = reply;
|
||||||
message.action.replyTo = (id.msgId > 0 && !history->peer->isUser())
|
message.action.replyTo = (id.msgId > 0 && !history->peer->isUser())
|
||||||
? id.msgId
|
? id.msgId
|
||||||
: id.contextId.topicRootId;
|
: id.contextId.topicRootId;
|
||||||
|
message.action.topicRootId = topic ? topic->rootId() : 0;
|
||||||
message.action.clearDraft = false;
|
message.action.clearDraft = false;
|
||||||
history->session().api().sendMessage(std::move(message));
|
history->session().api().sendMessage(std::move(message));
|
||||||
|
|
||||||
const auto item = history->owner().message(history->peer, id.msgId);
|
|
||||||
if (item && item->isUnreadMention() && !item->isIncomingUnreadMedia()) {
|
if (item && item->isUnreadMention() && !item->isIncomingUnreadMedia()) {
|
||||||
history->session().api().markContentsRead(item);
|
history->session().api().markContentsRead(item);
|
||||||
}
|
}
|
||||||
|
|
|
@ -844,14 +844,16 @@ void Filler::addCreatePoll() {
|
||||||
? SendMenu::Type::SilentOnly
|
? SendMenu::Type::SilentOnly
|
||||||
: SendMenu::Type::Scheduled;
|
: SendMenu::Type::Scheduled;
|
||||||
const auto flag = PollData::Flags();
|
const auto flag = PollData::Flags();
|
||||||
|
const auto topicRootId = _request.rootId;
|
||||||
const auto replyToId = _request.currentReplyToId
|
const auto replyToId = _request.currentReplyToId
|
||||||
? _request.currentReplyToId
|
? _request.currentReplyToId
|
||||||
: _request.rootId;
|
: topicRootId;
|
||||||
auto callback = [=] {
|
auto callback = [=] {
|
||||||
PeerMenuCreatePoll(
|
PeerMenuCreatePoll(
|
||||||
controller,
|
controller,
|
||||||
peer,
|
peer,
|
||||||
replyToId,
|
replyToId,
|
||||||
|
topicRootId,
|
||||||
flag,
|
flag,
|
||||||
flag,
|
flag,
|
||||||
source,
|
source,
|
||||||
|
@ -1168,6 +1170,7 @@ void PeerMenuCreatePoll(
|
||||||
not_null<Window::SessionController*> controller,
|
not_null<Window::SessionController*> controller,
|
||||||
not_null<PeerData*> peer,
|
not_null<PeerData*> peer,
|
||||||
MsgId replyToId,
|
MsgId replyToId,
|
||||||
|
MsgId topicRootId,
|
||||||
PollData::Flags chosen,
|
PollData::Flags chosen,
|
||||||
PollData::Flags disabled,
|
PollData::Flags disabled,
|
||||||
Api::SendType sendType,
|
Api::SendType sendType,
|
||||||
|
@ -1194,8 +1197,9 @@ void PeerMenuCreatePoll(
|
||||||
result.options);
|
result.options);
|
||||||
action.clearDraft = false;
|
action.clearDraft = false;
|
||||||
action.replyTo = replyToId;
|
action.replyTo = replyToId;
|
||||||
if (const auto localDraft = action.history->localDraft()) {
|
action.topicRootId = topicRootId;
|
||||||
action.clearDraft = localDraft->textWithTags.text.isEmpty();
|
if (const auto local = action.history->localDraft(topicRootId)) {
|
||||||
|
action.clearDraft = local->textWithTags.text.isEmpty();
|
||||||
}
|
}
|
||||||
const auto api = &peer->session().api();
|
const auto api = &peer->session().api();
|
||||||
api->polls().create(result.poll, action, crl::guard(weak, [=] {
|
api->polls().create(result.poll, action, crl::guard(weak, [=] {
|
||||||
|
|
|
@ -69,6 +69,7 @@ void PeerMenuCreatePoll(
|
||||||
not_null<Window::SessionController*> controller,
|
not_null<Window::SessionController*> controller,
|
||||||
not_null<PeerData*> peer,
|
not_null<PeerData*> peer,
|
||||||
MsgId replyToId = 0,
|
MsgId replyToId = 0,
|
||||||
|
MsgId topicRootId = 0,
|
||||||
PollData::Flags chosen = PollData::Flags(),
|
PollData::Flags chosen = PollData::Flags(),
|
||||||
PollData::Flags disabled = PollData::Flags(),
|
PollData::Flags disabled = PollData::Flags(),
|
||||||
Api::SendType sendType = Api::SendType::Normal,
|
Api::SendType sendType = Api::SendType::Normal,
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 9ab11ccb36b7d03a3a24ebcd18d2f13b03fc3682
|
Subproject commit d8b1f46715e5fcaf781b76ecbc386cbe31492287
|
Loading…
Add table
Reference in a new issue