mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-22 17:17:15 +02:00
Update API scheme on layer 148.
Extract message history corner buttons code.
This commit is contained in:
parent
2c0b5b3210
commit
6a7f030ee7
24 changed files with 751 additions and 444 deletions
|
@ -690,6 +690,8 @@ PRIVATE
|
||||||
history/view/history_view_contact_status.h
|
history/view/history_view_contact_status.h
|
||||||
history/view/history_view_context_menu.cpp
|
history/view/history_view_context_menu.cpp
|
||||||
history/view/history_view_context_menu.h
|
history/view/history_view_context_menu.h
|
||||||
|
history/view/history_view_corner_buttons.cpp
|
||||||
|
history/view/history_view_corner_buttons.h
|
||||||
history/view/history_view_cursor_state.cpp
|
history/view/history_view_cursor_state.cpp
|
||||||
history/view/history_view_cursor_state.h
|
history/view/history_view_cursor_state.h
|
||||||
history/view/history_view_element.cpp
|
history/view/history_view_element.cpp
|
||||||
|
|
|
@ -222,6 +222,7 @@ inputNotifyPeer#b8bc5b0c peer:InputPeer = InputNotifyPeer;
|
||||||
inputNotifyUsers#193b4417 = InputNotifyPeer;
|
inputNotifyUsers#193b4417 = InputNotifyPeer;
|
||||||
inputNotifyChats#4a95e84e = InputNotifyPeer;
|
inputNotifyChats#4a95e84e = InputNotifyPeer;
|
||||||
inputNotifyBroadcasts#b1db7c7e = InputNotifyPeer;
|
inputNotifyBroadcasts#b1db7c7e = InputNotifyPeer;
|
||||||
|
inputNotifyForumTopic#5c467992 peer:InputPeer top_msg_id:int = InputNotifyPeer;
|
||||||
|
|
||||||
inputPeerNotifySettings#df1f002b flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int sound:flags.3?NotificationSound = InputPeerNotifySettings;
|
inputPeerNotifySettings#df1f002b flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int sound:flags.3?NotificationSound = InputPeerNotifySettings;
|
||||||
|
|
||||||
|
@ -1454,7 +1455,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;
|
||||||
|
|
||||||
forumTopic#18a9a864 flags:# my:flags.1?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 = ForumTopic;
|
forumTopic#5920d6dc flags:# my:flags.1?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;
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
|
@ -1704,7 +1705,7 @@ messages.getEmojiKeywords#35a0e062 lang_code:string = EmojiKeywordsDifference;
|
||||||
messages.getEmojiKeywordsDifference#1508b6af lang_code:string from_version:int = EmojiKeywordsDifference;
|
messages.getEmojiKeywordsDifference#1508b6af lang_code:string from_version:int = EmojiKeywordsDifference;
|
||||||
messages.getEmojiKeywordsLanguages#4e9963b2 lang_codes:Vector<string> = Vector<EmojiLanguage>;
|
messages.getEmojiKeywordsLanguages#4e9963b2 lang_codes:Vector<string> = Vector<EmojiLanguage>;
|
||||||
messages.getEmojiURL#d5b10c26 lang_code:string = EmojiURL;
|
messages.getEmojiURL#d5b10c26 lang_code:string = EmojiURL;
|
||||||
messages.getSearchCounters#732eef00 peer:InputPeer filters:Vector<MessagesFilter> = Vector<messages.SearchCounter>;
|
messages.getSearchCounters#ae7cc1 flags:# peer:InputPeer top_msg_id:flags.0?int filters:Vector<MessagesFilter> = Vector<messages.SearchCounter>;
|
||||||
messages.requestUrlAuth#198fb446 flags:# peer:flags.1?InputPeer msg_id:flags.1?int button_id:flags.1?int url:flags.2?string = UrlAuthResult;
|
messages.requestUrlAuth#198fb446 flags:# peer:flags.1?InputPeer msg_id:flags.1?int button_id:flags.1?int url:flags.2?string = UrlAuthResult;
|
||||||
messages.acceptUrlAuth#b12c7125 flags:# write_allowed:flags.0?true peer:flags.1?InputPeer msg_id:flags.1?int button_id:flags.1?int url:flags.2?string = UrlAuthResult;
|
messages.acceptUrlAuth#b12c7125 flags:# write_allowed:flags.0?true peer:flags.1?InputPeer msg_id:flags.1?int button_id:flags.1?int url:flags.2?string = UrlAuthResult;
|
||||||
messages.hidePeerSettingsBar#4facb138 peer:InputPeer = Bool;
|
messages.hidePeerSettingsBar#4facb138 peer:InputPeer = Bool;
|
||||||
|
@ -1754,7 +1755,7 @@ messages.getAvailableReactions#18dea0ac hash:int = messages.AvailableReactions;
|
||||||
messages.setDefaultReaction#4f47a016 reaction:Reaction = Bool;
|
messages.setDefaultReaction#4f47a016 reaction:Reaction = Bool;
|
||||||
messages.translateText#24ce6dee flags:# peer:flags.0?InputPeer msg_id:flags.0?int text:flags.1?string from_lang:flags.2?string to_lang:string = messages.TranslatedText;
|
messages.translateText#24ce6dee flags:# peer:flags.0?InputPeer msg_id:flags.0?int text:flags.1?string from_lang:flags.2?string to_lang:string = messages.TranslatedText;
|
||||||
messages.getUnreadReactions#3223495b 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.getUnreadReactions#3223495b 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.readReactions#82e251d7 peer:InputPeer = messages.AffectedHistory;
|
messages.readReactions#54aa7f8e flags:# peer:InputPeer top_msg_id:flags.0?int = messages.AffectedHistory;
|
||||||
messages.searchSentMedia#107e31a0 q:string filter:MessagesFilter limit:int = messages.Messages;
|
messages.searchSentMedia#107e31a0 q:string filter:MessagesFilter limit:int = messages.Messages;
|
||||||
messages.getAttachMenuBots#16fcc2cb hash:long = AttachMenuBots;
|
messages.getAttachMenuBots#16fcc2cb hash:long = AttachMenuBots;
|
||||||
messages.getAttachMenuBot#77216192 bot:InputUser = AttachMenuBotsBot;
|
messages.getAttachMenuBot#77216192 bot:InputUser = AttachMenuBotsBot;
|
||||||
|
@ -1865,6 +1866,7 @@ channels.createForumTopic#f40c0224 flags:# channel:InputChannel title:string ico
|
||||||
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;
|
||||||
channels.getForumTopicsByID#b0831eb9 channel:InputChannel topics:Vector<int> = messages.ForumTopics;
|
channels.getForumTopicsByID#b0831eb9 channel:InputChannel topics:Vector<int> = messages.ForumTopics;
|
||||||
channels.editForumTopic#8a7f464b flags:# channel:InputChannel topic_id:int title:flags.0?string icon_emoji_id:flags.1?long = Updates;
|
channels.editForumTopic#8a7f464b flags:# channel:InputChannel topic_id:int title:flags.0?string icon_emoji_id:flags.1?long = Updates;
|
||||||
|
channels.deleteTopicHistory#34435f2d channel:InputChannel top_msg_id:int = messages.AffectedHistory;
|
||||||
|
|
||||||
bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON;
|
bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON;
|
||||||
bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool;
|
bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool;
|
||||||
|
|
|
@ -41,24 +41,22 @@ constexpr auto kNextRequestLimit = 100;
|
||||||
UnreadThings::UnreadThings(not_null<ApiWrap*> api) : _api(api) {
|
UnreadThings::UnreadThings(not_null<ApiWrap*> api) : _api(api) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UnreadThings::trackMentions(PeerData *peer) const {
|
bool UnreadThings::trackMentions(DialogsEntry *entry) const {
|
||||||
|
const auto peer = entry ? ResolveHistory(entry)->peer.get() : nullptr;
|
||||||
return peer && (peer->isChat() || peer->isMegagroup());
|
return peer && (peer->isChat() || peer->isMegagroup());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UnreadThings::trackReactions(PeerData *peer) const {
|
bool UnreadThings::trackReactions(DialogsEntry *entry) const {
|
||||||
return trackMentions(peer) || (peer && peer->isUser());
|
const auto peer = entry ? ResolveHistory(entry)->peer.get() : nullptr;
|
||||||
|
return peer && (peer->isChat() || peer->isMegagroup());
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnreadThings::preloadEnough(DialogsEntry *entry) {
|
void UnreadThings::preloadEnough(DialogsEntry *entry) {
|
||||||
if (!entry) {
|
if (trackMentions(entry)) {
|
||||||
return;
|
preloadEnoughMentions(entry);
|
||||||
}
|
}
|
||||||
const auto history = ResolveHistory(entry);
|
if (trackReactions(entry)) {
|
||||||
if (trackMentions(history->peer)) {
|
preloadEnoughReactions(entry);
|
||||||
preloadEnoughMentions(history);
|
|
||||||
}
|
|
||||||
if (trackReactions(history->peer)) {
|
|
||||||
preloadEnoughReactions(history);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,8 +23,8 @@ public:
|
||||||
|
|
||||||
explicit UnreadThings(not_null<ApiWrap*> api);
|
explicit UnreadThings(not_null<ApiWrap*> api);
|
||||||
|
|
||||||
[[nodiscard]] bool trackMentions(PeerData *peer) const;
|
[[nodiscard]] bool trackMentions(DialogsEntry *entry) const;
|
||||||
[[nodiscard]] bool trackReactions(PeerData *peer) const;
|
[[nodiscard]] bool trackReactions(DialogsEntry *entry) const;
|
||||||
|
|
||||||
void preloadEnough(DialogsEntry *entry);
|
void preloadEnough(DialogsEntry *entry);
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ namespace Data {
|
||||||
|
|
||||||
class Session;
|
class Session;
|
||||||
|
|
||||||
class Folder final : public Dialogs::Entry, public base::has_weak_ptr {
|
class Folder final : public Dialogs::Entry {
|
||||||
public:
|
public:
|
||||||
static constexpr auto kId = 1;
|
static constexpr auto kId = 1;
|
||||||
|
|
||||||
|
|
|
@ -239,6 +239,12 @@ void Forum::clearAllUnreadMentions() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Forum::clearAllUnreadReactions() {
|
||||||
|
for (const auto &[rootId, topic] : _topics) {
|
||||||
|
topic->unreadReactions().clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ForumTopic *Forum::topicFor(not_null<const HistoryItem*> item) {
|
ForumTopic *Forum::topicFor(not_null<const HistoryItem*> item) {
|
||||||
const auto maybe = topicFor(item->replyToTop());
|
const auto maybe = topicFor(item->replyToTop());
|
||||||
return maybe ? maybe : topicFor(item->topicRootId());
|
return maybe ? maybe : topicFor(item->topicRootId());
|
||||||
|
|
|
@ -60,6 +60,7 @@ public:
|
||||||
void created(MsgId rootId, MsgId realId);
|
void created(MsgId rootId, MsgId realId);
|
||||||
|
|
||||||
void clearAllUnreadMentions();
|
void clearAllUnreadMentions();
|
||||||
|
void clearAllUnreadReactions();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct TopicRequest {
|
struct TopicRequest {
|
||||||
|
|
|
@ -10,8 +10,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_sparse_ids.h"
|
#include "data/data_sparse_ids.h"
|
||||||
#include "storage/storage_sparse_ids_list.h"
|
#include "storage/storage_sparse_ids_list.h"
|
||||||
#include "storage/storage_shared_media.h"
|
#include "storage/storage_shared_media.h"
|
||||||
#include "base/value_ordering.h"
|
|
||||||
#include "base/timer.h"
|
#include "base/timer.h"
|
||||||
|
#include "base/qt/qt_compare.h"
|
||||||
|
|
||||||
namespace Main {
|
namespace Main {
|
||||||
class Session;
|
class Session;
|
||||||
|
@ -58,13 +58,9 @@ public:
|
||||||
QString query;
|
QString query;
|
||||||
// from_id, min_date, max_date
|
// from_id, min_date, max_date
|
||||||
|
|
||||||
friend inline auto value_ordering_helper(const Query &value) {
|
friend inline std::strong_ordering operator<=>(
|
||||||
return std::tie(
|
const Query &a,
|
||||||
value.peerId,
|
const Query &b) noexcept = default;
|
||||||
value.migratedPeerId,
|
|
||||||
value.type,
|
|
||||||
value.query);
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
struct SavedState {
|
struct SavedState {
|
||||||
|
|
|
@ -7,7 +7,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "base/value_ordering.h"
|
|
||||||
#include "ui/text/text.h" // For QFIXED_MAX
|
#include "ui/text/text.h" // For QFIXED_MAX
|
||||||
#include "data/data_peer_id.h"
|
#include "data/data_peer_id.h"
|
||||||
#include "data/data_msg_id.h"
|
#include "data/data_msg_id.h"
|
||||||
|
@ -84,9 +83,9 @@ struct MessageGroupId {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
friend inline std::pair<uint64, uint64> value_ordering_helper(MessageGroupId value) {
|
friend inline constexpr auto operator<=>(
|
||||||
return std::make_pair(value.value, value.peer.value);
|
MessageGroupId,
|
||||||
}
|
MessageGroupId) noexcept = default;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -131,6 +131,14 @@ const base::flat_set<MsgId> &Entry::unreadMentionsIds() const {
|
||||||
return _unreadThings->mentions.ids();
|
return _unreadThings->mentions.ids();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const base::flat_set<MsgId> &Entry::unreadReactionsIds() const {
|
||||||
|
if (!_unreadThings) {
|
||||||
|
static const auto Result = base::flat_set<MsgId>();
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
return _unreadThings->reactions.ids();
|
||||||
|
}
|
||||||
|
|
||||||
bool Entry::needUpdateInChatList() const {
|
bool Entry::needUpdateInChatList() const {
|
||||||
return inChatList() || shouldBeInChatList();
|
return inChatList() || shouldBeInChatList();
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "base/flat_map.h"
|
#include "base/flat_map.h"
|
||||||
|
#include "base/weak_ptr.h"
|
||||||
#include "dialogs/dialogs_key.h"
|
#include "dialogs/dialogs_key.h"
|
||||||
#include "ui/unread_badge.h"
|
#include "ui/unread_badge.h"
|
||||||
|
|
||||||
|
@ -105,7 +105,7 @@ inline UnreadState operator-(const UnreadState &a, const UnreadState &b) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
class Entry {
|
class Entry : public base::has_weak_ptr {
|
||||||
public:
|
public:
|
||||||
enum class Type : uchar {
|
enum class Type : uchar {
|
||||||
History,
|
History,
|
||||||
|
@ -223,6 +223,7 @@ protected:
|
||||||
void cacheTopPromoted(bool promoted);
|
void cacheTopPromoted(bool promoted);
|
||||||
|
|
||||||
[[nodiscard]] const base::flat_set<MsgId> &unreadMentionsIds() const;
|
[[nodiscard]] const base::flat_set<MsgId> &unreadMentionsIds() const;
|
||||||
|
[[nodiscard]] const base::flat_set<MsgId> &unreadReactionsIds() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum class Flag : uchar {
|
enum class Flag : uchar {
|
||||||
|
|
|
@ -7,8 +7,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "base/value_ordering.h"
|
|
||||||
|
|
||||||
class History;
|
class History;
|
||||||
class PeerData;
|
class PeerData;
|
||||||
|
|
||||||
|
@ -45,29 +43,7 @@ public:
|
||||||
History *parentHistory() const;
|
History *parentHistory() const;
|
||||||
PeerData *peer() const;
|
PeerData *peer() const;
|
||||||
|
|
||||||
inline bool operator<(const Key &other) const {
|
friend inline constexpr auto operator<=>(Key, Key) noexcept = default;
|
||||||
return _value < other._value;
|
|
||||||
}
|
|
||||||
inline bool operator>(const Key &other) const {
|
|
||||||
return (other < *this);
|
|
||||||
}
|
|
||||||
inline bool operator<=(const Key &other) const {
|
|
||||||
return !(other < *this);
|
|
||||||
}
|
|
||||||
inline bool operator>=(const Key &other) const {
|
|
||||||
return !(*this < other);
|
|
||||||
}
|
|
||||||
inline bool operator==(const Key &other) const {
|
|
||||||
return _value == other._value;
|
|
||||||
}
|
|
||||||
inline bool operator!=(const Key &other) const {
|
|
||||||
return !(*this == other);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Not working :(
|
|
||||||
//friend inline auto value_ordering_helper(const Key &key) {
|
|
||||||
// return key.value;
|
|
||||||
//}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Entry *_value = nullptr;
|
Entry *_value = nullptr;
|
||||||
|
|
|
@ -12,7 +12,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "export/output/export_output_result.h"
|
#include "export/output/export_output_result.h"
|
||||||
#include "export/output/export_output_file.h"
|
#include "export/output/export_output_file.h"
|
||||||
#include "mtproto/mtproto_response.h"
|
#include "mtproto/mtproto_response.h"
|
||||||
#include "base/value_ordering.h"
|
|
||||||
#include "base/bytes.h"
|
#include "base/bytes.h"
|
||||||
#include "base/random.h"
|
#include "base/random.h"
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
|
@ -700,6 +700,18 @@ not_null<HistoryItem*> History::addNewLocalMessage(
|
||||||
}
|
}
|
||||||
|
|
||||||
void History::clearUnreadMentionsFor(MsgId topicRootId) {
|
void History::clearUnreadMentionsFor(MsgId topicRootId) {
|
||||||
|
const auto forum = peer->forum();
|
||||||
|
if (!topicRootId) {
|
||||||
|
if (forum) {
|
||||||
|
forum->clearAllUnreadMentions();
|
||||||
|
}
|
||||||
|
unreadMentions().clear();
|
||||||
|
return;
|
||||||
|
} else if (forum) {
|
||||||
|
if (const auto topic = forum->topicFor(topicRootId)) {
|
||||||
|
topic->unreadMentions().clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
const auto &ids = unreadMentionsIds();
|
const auto &ids = unreadMentionsIds();
|
||||||
if (ids.empty()) {
|
if (ids.empty()) {
|
||||||
return;
|
return;
|
||||||
|
@ -720,6 +732,39 @@ void History::clearUnreadMentionsFor(MsgId topicRootId) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void History::clearUnreadReactionsFor(MsgId topicRootId) {
|
||||||
|
const auto forum = peer->forum();
|
||||||
|
if (!topicRootId) {
|
||||||
|
if (forum) {
|
||||||
|
forum->clearAllUnreadReactions();
|
||||||
|
}
|
||||||
|
unreadReactions().clear();
|
||||||
|
return;
|
||||||
|
} else if (forum) {
|
||||||
|
if (const auto topic = forum->topicFor(topicRootId)) {
|
||||||
|
topic->unreadReactions().clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const auto &ids = unreadReactionsIds();
|
||||||
|
if (ids.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto owner = &this->owner();
|
||||||
|
const auto peerId = peer->id;
|
||||||
|
auto items = base::flat_set<MsgId>();
|
||||||
|
items.reserve(ids.size());
|
||||||
|
for (const auto &id : ids) {
|
||||||
|
if (const auto item = owner->message(peerId, id)) {
|
||||||
|
if (item->topicRootId() == topicRootId) {
|
||||||
|
items.emplace(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const auto &id : items) {
|
||||||
|
unreadReactions().erase(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
not_null<HistoryItem*> History::addNewToBack(
|
not_null<HistoryItem*> History::addNewToBack(
|
||||||
not_null<HistoryItem*> item,
|
not_null<HistoryItem*> item,
|
||||||
bool unread) {
|
bool unread) {
|
||||||
|
|
|
@ -331,6 +331,7 @@ public:
|
||||||
|
|
||||||
void clearLastKeyboard();
|
void clearLastKeyboard();
|
||||||
void clearUnreadMentionsFor(MsgId topicRootId);
|
void clearUnreadMentionsFor(MsgId topicRootId);
|
||||||
|
void clearUnreadReactionsFor(MsgId topicRootId);
|
||||||
|
|
||||||
Data::Draft *draft(Data::DraftKey key) const;
|
Data::Draft *draft(Data::DraftKey key) const;
|
||||||
void setDraft(Data::DraftKey key, std::unique_ptr<Data::Draft> &&draft);
|
void setDraft(Data::DraftKey key, std::unique_ptr<Data::Draft> &&draft);
|
||||||
|
|
|
@ -9,7 +9,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
#include "base/runtime_composer.h"
|
#include "base/runtime_composer.h"
|
||||||
#include "base/flags.h"
|
#include "base/flags.h"
|
||||||
#include "base/value_ordering.h"
|
|
||||||
#include "data/data_media_types.h"
|
#include "data/data_media_types.h"
|
||||||
#include "history/history_item_edition.h"
|
#include "history/history_item_edition.h"
|
||||||
#include "history/history_item_reply_markup.h"
|
#include "history/history_item_reply_markup.h"
|
||||||
|
|
|
@ -228,15 +228,10 @@ HistoryWidget::HistoryWidget(
|
||||||
controller->chatStyle()->value(lifetime(), st::historyScroll),
|
controller->chatStyle()->value(lifetime(), st::historyScroll),
|
||||||
false)
|
false)
|
||||||
, _updateHistoryItems([=] { updateHistoryItemsByTimer(); })
|
, _updateHistoryItems([=] { updateHistoryItemsByTimer(); })
|
||||||
, _historyDown(
|
, _cornerButtons(
|
||||||
_scroll,
|
_scroll.data(),
|
||||||
controller->chatStyle()->value(lifetime(), st::historyToDown))
|
controller->chatStyle(),
|
||||||
, _unreadMentions(
|
static_cast<HistoryView::CornerButtonsDelegate*>(this))
|
||||||
_scroll,
|
|
||||||
controller->chatStyle()->value(lifetime(), st::historyUnreadMentions))
|
|
||||||
, _unreadReactions(
|
|
||||||
_scroll,
|
|
||||||
controller->chatStyle()->value(lifetime(), st::historyUnreadReactions))
|
|
||||||
, _fieldAutocomplete(this, controller)
|
, _fieldAutocomplete(this, controller)
|
||||||
, _supportAutocomplete(session().supportMode()
|
, _supportAutocomplete(session().supportMode()
|
||||||
? object_ptr<Support::Autocomplete>(this, &session())
|
? object_ptr<Support::Autocomplete>(this, &session())
|
||||||
|
@ -306,13 +301,6 @@ HistoryWidget::HistoryWidget(
|
||||||
}
|
}
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
_historyDown.widget->addClickHandler([=] { historyDownClicked(); });
|
|
||||||
_unreadMentions.widget->addClickHandler([=] {
|
|
||||||
showNextUnreadMention();
|
|
||||||
});
|
|
||||||
_unreadReactions.widget->addClickHandler([=] {
|
|
||||||
showNextUnreadReaction();
|
|
||||||
});
|
|
||||||
_fieldBarCancel->addClickHandler([=] { cancelFieldAreaState(); });
|
_fieldBarCancel->addClickHandler([=] { cancelFieldAreaState(); });
|
||||||
_send->addClickHandler([=] { sendButtonClicked(); });
|
_send->addClickHandler([=] { sendButtonClicked(); });
|
||||||
|
|
||||||
|
@ -385,16 +373,6 @@ HistoryWidget::HistoryWidget(
|
||||||
_scroll->updateBars();
|
_scroll->updateBars();
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
_historyDown.widget->installEventFilter(this);
|
|
||||||
_unreadMentions.widget->installEventFilter(this);
|
|
||||||
_unreadReactions.widget->installEventFilter(this);
|
|
||||||
SendMenu::SetupUnreadMentionsMenu(_unreadMentions.widget.data(), [=] {
|
|
||||||
return _history ? _history->peer.get() : nullptr;
|
|
||||||
}, MsgId(0));
|
|
||||||
SendMenu::SetupUnreadReactionsMenu(_unreadReactions.widget.data(), [=] {
|
|
||||||
return _history ? _history->peer.get() : nullptr;
|
|
||||||
});
|
|
||||||
|
|
||||||
InitMessageField(controller, _field, [=](
|
InitMessageField(controller, _field, [=](
|
||||||
not_null<DocumentData*> document) {
|
not_null<DocumentData*> document) {
|
||||||
if (_peer && Data::AllowEmojiWithoutPremium(_peer)) {
|
if (_peer && Data::AllowEmojiWithoutPremium(_peer)) {
|
||||||
|
@ -582,7 +560,7 @@ HistoryWidget::HistoryWidget(
|
||||||
) | rpl::filter([=](not_null<ChannelData*> channel) {
|
) | rpl::filter([=](not_null<ChannelData*> channel) {
|
||||||
return _peer == channel.get();
|
return _peer == channel.get();
|
||||||
}) | rpl::start_with_next([=] {
|
}) | rpl::start_with_next([=] {
|
||||||
updateHistoryDownVisibility();
|
_cornerButtons.updateJumpDownVisibility();
|
||||||
preloadHistoryIfNeeded();
|
preloadHistoryIfNeeded();
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
|
@ -648,7 +626,7 @@ HistoryWidget::HistoryWidget(
|
||||||
}
|
}
|
||||||
if ((flags & HistoryUpdateFlag::UnreadMentions)
|
if ((flags & HistoryUpdateFlag::UnreadMentions)
|
||||||
|| (flags & HistoryUpdateFlag::UnreadReactions)) {
|
|| (flags & HistoryUpdateFlag::UnreadReactions)) {
|
||||||
updateUnreadThingsVisibility();
|
_cornerButtons.updateUnreadThingsVisibility();
|
||||||
}
|
}
|
||||||
if (flags & HistoryUpdateFlag::UnreadView) {
|
if (flags & HistoryUpdateFlag::UnreadView) {
|
||||||
unreadCountUpdated();
|
unreadCountUpdated();
|
||||||
|
@ -1007,8 +985,8 @@ void HistoryWidget::initVoiceRecordBar() {
|
||||||
|
|
||||||
_voiceRecordBar->lockShowStarts(
|
_voiceRecordBar->lockShowStarts(
|
||||||
) | rpl::start_with_next([=] {
|
) | rpl::start_with_next([=] {
|
||||||
updateHistoryDownVisibility();
|
_cornerButtons.updateJumpDownVisibility();
|
||||||
updateUnreadThingsVisibility();
|
_cornerButtons.updateUnreadThingsVisibility();
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
_voiceRecordBar->updateSendButtonTypeRequests(
|
_voiceRecordBar->updateSendButtonTypeRequests(
|
||||||
|
@ -1855,73 +1833,25 @@ void HistoryWidget::setupShortcuts() {
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::clearReplyReturns() {
|
|
||||||
_replyReturns.clear();
|
|
||||||
_replyReturn = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HistoryWidget::pushReplyReturn(not_null<HistoryItem*> item) {
|
void HistoryWidget::pushReplyReturn(not_null<HistoryItem*> item) {
|
||||||
if (item->history() == _history) {
|
if (item->history() != _history && item->history() != _migrated) {
|
||||||
_replyReturns.push_back(item->id);
|
|
||||||
} else if (item->history() == _migrated) {
|
|
||||||
_replyReturns.push_back(-item->id);
|
|
||||||
} else {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_replyReturn = item;
|
_cornerButtons.pushReplyReturn(item);
|
||||||
updateControlsVisibility();
|
updateControlsVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<MsgId> HistoryWidget::replyReturns() {
|
QVector<FullMsgId> HistoryWidget::replyReturns() const {
|
||||||
return _replyReturns;
|
return _cornerButtons.replyReturns();
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::setReplyReturns(PeerId peer, const QList<MsgId> &replyReturns) {
|
void HistoryWidget::setReplyReturns(
|
||||||
if (!_peer || _peer->id != peer) return;
|
PeerId peer,
|
||||||
|
QVector<FullMsgId> replyReturns) {
|
||||||
_replyReturns = replyReturns;
|
if (!_peer || _peer->id != peer) {
|
||||||
if (_replyReturns.isEmpty()) {
|
return;
|
||||||
_replyReturn = nullptr;
|
|
||||||
} else if (_replyReturns.back() < 0 && -_replyReturns.back() < ServerMaxMsgId) {
|
|
||||||
_replyReturn = _migrated
|
|
||||||
? session().data().message(_migrated->peer, -_replyReturns.back())
|
|
||||||
: nullptr;
|
|
||||||
} else {
|
|
||||||
_replyReturn = session().data().message(peer, _replyReturns.back());
|
|
||||||
}
|
|
||||||
while (!_replyReturns.isEmpty() && !_replyReturn) {
|
|
||||||
_replyReturns.pop_back();
|
|
||||||
if (_replyReturns.isEmpty()) {
|
|
||||||
_replyReturn = nullptr;
|
|
||||||
} else if (_replyReturns.back() < 0 && -_replyReturns.back() < ServerMaxMsgId) {
|
|
||||||
_replyReturn = _migrated
|
|
||||||
? session().data().message(_migrated->peer, -_replyReturns.back())
|
|
||||||
: nullptr;
|
|
||||||
} else {
|
|
||||||
_replyReturn = session().data().message(peer, _replyReturns.back());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void HistoryWidget::calcNextReplyReturn() {
|
|
||||||
_replyReturn = nullptr;
|
|
||||||
while (!_replyReturns.isEmpty() && !_replyReturn) {
|
|
||||||
_replyReturns.pop_back();
|
|
||||||
if (_replyReturns.isEmpty()) {
|
|
||||||
_replyReturn = nullptr;
|
|
||||||
} else if (_replyReturns.back() < 0 && -_replyReturns.back() < ServerMaxMsgId) {
|
|
||||||
_replyReturn = _migrated
|
|
||||||
? session().data().message(_migrated->peer, -_replyReturns.back())
|
|
||||||
: nullptr;
|
|
||||||
} else {
|
|
||||||
_replyReturn = _peer
|
|
||||||
? session().data().message(_peer, _replyReturns.back())
|
|
||||||
: nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!_replyReturn) {
|
|
||||||
updateControlsVisibility();
|
|
||||||
}
|
}
|
||||||
|
_cornerButtons.setReplyReturns(std::move(replyReturns));
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::fastShowAtEnd(not_null<History*> history) {
|
void HistoryWidget::fastShowAtEnd(not_null<History*> history) {
|
||||||
|
@ -2074,14 +2004,13 @@ void HistoryWidget::showHistory(
|
||||||
}
|
}
|
||||||
|
|
||||||
clearDelayedShowAt();
|
clearDelayedShowAt();
|
||||||
while (_replyReturn) {
|
const auto skipId = (_migrated && showAtMsgId < 0)
|
||||||
if (_replyReturn->history() == _history && _replyReturn->id == showAtMsgId) {
|
? FullMsgId(_migrated->peer->id, -showAtMsgId)
|
||||||
calcNextReplyReturn();
|
: (showAtMsgId > 0)
|
||||||
} else if (_replyReturn->history() == _migrated && -_replyReturn->id == showAtMsgId) {
|
? FullMsgId(_history->peer->id, showAtMsgId)
|
||||||
calcNextReplyReturn();
|
: FullMsgId();
|
||||||
} else {
|
if (skipId) {
|
||||||
break;
|
_cornerButtons.skipReplyReturn(skipId);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setMsgId(showAtMsgId);
|
setMsgId(showAtMsgId);
|
||||||
|
@ -2127,7 +2056,7 @@ void HistoryWidget::showHistory(
|
||||||
session().sendProgressManager().cancelTyping(_history);
|
session().sendProgressManager().cancelTyping(_history);
|
||||||
}
|
}
|
||||||
|
|
||||||
clearReplyReturns();
|
_cornerButtons.clearReplyReturns();
|
||||||
if (_history) {
|
if (_history) {
|
||||||
if (Ui::InFocusChain(_list)) {
|
if (Ui::InFocusChain(_list)) {
|
||||||
// Removing focus from list clears selected and updates top bar.
|
// Removing focus from list clears selected and updates top bar.
|
||||||
|
@ -2632,8 +2561,8 @@ void HistoryWidget::updateControlsVisibility() {
|
||||||
_topShadow->setVisible(_peer != nullptr);
|
_topShadow->setVisible(_peer != nullptr);
|
||||||
_topBar->setVisible(_peer != nullptr);
|
_topBar->setVisible(_peer != nullptr);
|
||||||
}
|
}
|
||||||
updateHistoryDownVisibility();
|
_cornerButtons.updateJumpDownVisibility();
|
||||||
updateUnreadThingsVisibility();
|
_cornerButtons.updateUnreadThingsVisibility();
|
||||||
if (!_history || _a_show.animating()) {
|
if (!_history || _a_show.animating()) {
|
||||||
hideChildWidgets();
|
hideChildWidgets();
|
||||||
return;
|
return;
|
||||||
|
@ -2975,8 +2904,8 @@ void HistoryWidget::unreadCountUpdated() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
updateHistoryDownVisibility();
|
_cornerButtons.updateJumpDownVisibility(
|
||||||
_historyDown.widget->setUnreadCount(_history->chatListUnreadCount());
|
_history->chatListUnreadCount());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3123,16 +3052,13 @@ void HistoryWidget::messagesReceived(PeerData *peer, const MTPmessages_Messages
|
||||||
firstLoadMessages();
|
firstLoadMessages();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
while (_replyReturn) {
|
const auto skipId = (_migrated && _delayedShowAtMsgId < 0)
|
||||||
if (_replyReturn->history() == _history
|
? FullMsgId(_migrated->peer->id, -_delayedShowAtMsgId)
|
||||||
&& _replyReturn->id == _delayedShowAtMsgId) {
|
: (_delayedShowAtMsgId > 0)
|
||||||
calcNextReplyReturn();
|
? FullMsgId(_history->peer->id, _delayedShowAtMsgId)
|
||||||
} else if (_replyReturn->history() == _migrated
|
: FullMsgId();
|
||||||
&& -_replyReturn->id == _delayedShowAtMsgId) {
|
if (skipId) {
|
||||||
calcNextReplyReturn();
|
_cornerButtons.skipReplyReturn(skipId);
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_delayedShowAtRequest = 0;
|
_delayedShowAtRequest = 0;
|
||||||
|
@ -3464,8 +3390,8 @@ void HistoryWidget::preloadHistoryIfNeeded() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateHistoryDownVisibility();
|
_cornerButtons.updateJumpDownVisibility();
|
||||||
updateUnreadThingsVisibility();
|
_cornerButtons.updateUnreadThingsVisibility();
|
||||||
if (!_scrollToAnimation.animating()) {
|
if (!_scrollToAnimation.animating()) {
|
||||||
preloadHistoryByScroll();
|
preloadHistoryByScroll();
|
||||||
checkReplyReturns();
|
checkReplyReturns();
|
||||||
|
@ -3535,19 +3461,32 @@ void HistoryWidget::checkReplyReturns() {
|
||||||
auto scrollTop = _scroll->scrollTop();
|
auto scrollTop = _scroll->scrollTop();
|
||||||
auto scrollTopMax = _scroll->scrollTopMax();
|
auto scrollTopMax = _scroll->scrollTopMax();
|
||||||
auto scrollHeight = _scroll->height();
|
auto scrollHeight = _scroll->height();
|
||||||
while (_replyReturn) {
|
while (const auto replyReturn = _cornerButtons.replyReturn()) {
|
||||||
auto below = (!_replyReturn->mainView() && _replyReturn->history() == _history && !_history->isEmpty() && _replyReturn->id < _history->blocks.back()->messages.back()->data()->id);
|
auto below = !replyReturn->mainView()
|
||||||
|
&& (replyReturn->history() == _history)
|
||||||
|
&& !_history->isEmpty()
|
||||||
|
&& (replyReturn->id
|
||||||
|
< _history->blocks.back()->messages.back()->data()->id);
|
||||||
if (!below) {
|
if (!below) {
|
||||||
below = (!_replyReturn->mainView() && _replyReturn->history() == _migrated && !_history->isEmpty());
|
below = !replyReturn->mainView()
|
||||||
|
&& (replyReturn->history() == _migrated)
|
||||||
|
&& !_history->isEmpty();
|
||||||
}
|
}
|
||||||
if (!below) {
|
if (!below) {
|
||||||
below = (!_replyReturn->mainView() && _migrated && _replyReturn->history() == _migrated && !_migrated->isEmpty() && _replyReturn->id < _migrated->blocks.back()->messages.back()->data()->id);
|
below = !replyReturn->mainView()
|
||||||
|
&& _migrated
|
||||||
|
&& (replyReturn->history() == _migrated)
|
||||||
|
&& !_migrated->isEmpty()
|
||||||
|
&& (replyReturn->id
|
||||||
|
< _migrated->blocks.back()->messages.back()->data()->id);
|
||||||
}
|
}
|
||||||
if (!below && _replyReturn->mainView()) {
|
if (!below && replyReturn->mainView()) {
|
||||||
below = (scrollTop >= scrollTopMax) || (_list->itemTop(_replyReturn) < scrollTop + scrollHeight / 2);
|
below = (scrollTop >= scrollTopMax)
|
||||||
|
|| (_list->itemTop(replyReturn)
|
||||||
|
< scrollTop + scrollHeight / 2);
|
||||||
}
|
}
|
||||||
if (below) {
|
if (below) {
|
||||||
calcNextReplyReturn();
|
_cornerButtons.calculateNextReplyReturn();
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -3574,46 +3513,6 @@ void HistoryWidget::windowIsVisibleChanged() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::historyDownClicked() {
|
|
||||||
if (base::IsCtrlPressed()) {
|
|
||||||
showHistory(_peer->id, ShowAtUnreadMsgId);
|
|
||||||
} else if (_replyReturn && _replyReturn->history() == _history) {
|
|
||||||
showHistory(_peer->id, _replyReturn->id);
|
|
||||||
} else if (_replyReturn && _replyReturn->history() == _migrated) {
|
|
||||||
showHistory(_peer->id, -_replyReturn->id);
|
|
||||||
} else if (_peer) {
|
|
||||||
showHistory(_peer->id, ShowAtUnreadMsgId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void HistoryWidget::showNextUnreadMention() {
|
|
||||||
const auto msgId = _history->unreadMentions().minLoaded();
|
|
||||||
const auto already = (_showAtMsgId == msgId);
|
|
||||||
|
|
||||||
// Mark mention voice/video message as read.
|
|
||||||
// See https://github.com/telegramdesktop/tdesktop/issues/5623
|
|
||||||
if (msgId && already) {
|
|
||||||
const auto item = _history->owner().message(
|
|
||||||
_history->peer->id,
|
|
||||||
msgId);
|
|
||||||
if (const auto media = item ? item->media() : nullptr) {
|
|
||||||
if (const auto document = media->document()) {
|
|
||||||
if (!media->webpage()
|
|
||||||
&& (document->isVoiceMessage()
|
|
||||||
|| document->isVideoMessage())) {
|
|
||||||
document->owner().markMediaRead(document);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
showHistory(_peer->id, msgId);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HistoryWidget::showNextUnreadReaction() {
|
|
||||||
const auto msgId = _history->unreadReactions().minLoaded();
|
|
||||||
showHistory(_peer->id, msgId);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HistoryWidget::saveEditMsg() {
|
void HistoryWidget::saveEditMsg() {
|
||||||
Expects(_history != nullptr);
|
Expects(_history != nullptr);
|
||||||
|
|
||||||
|
@ -3771,7 +3670,7 @@ void HistoryWidget::send(Api::SendOptions options) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!options.scheduled) {
|
if (!options.scheduled) {
|
||||||
clearReplyReturns();
|
_cornerButtons.clearReplyReturns();
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto webPageId = (_previewState != Data::PreviewState::Allowed)
|
const auto webPageId = (_previewState != Data::PreviewState::Allowed)
|
||||||
|
@ -3965,7 +3864,7 @@ void HistoryWidget::showAnimated(
|
||||||
_preserveScrollTop = true;
|
_preserveScrollTop = true;
|
||||||
show();
|
show();
|
||||||
_topBar->finishAnimating();
|
_topBar->finishAnimating();
|
||||||
cornerButtonsAnimationFinish();
|
_cornerButtons.finishAnimations();
|
||||||
if (_pinnedBar) {
|
if (_pinnedBar) {
|
||||||
_pinnedBar->finishAnimating();
|
_pinnedBar->finishAnimating();
|
||||||
}
|
}
|
||||||
|
@ -3999,7 +3898,7 @@ void HistoryWidget::showAnimated(
|
||||||
void HistoryWidget::animationCallback() {
|
void HistoryWidget::animationCallback() {
|
||||||
update();
|
update();
|
||||||
if (!_a_show.animating()) {
|
if (!_a_show.animating()) {
|
||||||
cornerButtonsAnimationFinish();
|
_cornerButtons.finishAnimations();
|
||||||
if (_pinnedBar) {
|
if (_pinnedBar) {
|
||||||
_pinnedBar->finishAnimating();
|
_pinnedBar->finishAnimating();
|
||||||
}
|
}
|
||||||
|
@ -4044,6 +3943,29 @@ void HistoryWidget::doneShow() {
|
||||||
checkSuggestToGigagroup();
|
checkSuggestToGigagroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HistoryWidget::cornerButtonsShowAtPosition(
|
||||||
|
Data::MessagePosition position) {
|
||||||
|
if (position == Data::UnreadMessagePosition) {
|
||||||
|
showHistory(_peer->id, ShowAtUnreadMsgId);
|
||||||
|
} else if (_peer && position.fullId.peer == _peer->id) {
|
||||||
|
showHistory(_peer->id, position.fullId.msg);
|
||||||
|
} else if (_migrated && position.fullId.peer == _migrated->peer->id) {
|
||||||
|
showHistory(_peer->id, -position.fullId.msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Dialogs::Entry *HistoryWidget::cornerButtonsEntry() {
|
||||||
|
return _history;
|
||||||
|
}
|
||||||
|
|
||||||
|
FullMsgId HistoryWidget::cornerButtonsCurrentId() {
|
||||||
|
return (_migrated && _showAtMsgId < 0)
|
||||||
|
? FullMsgId(_migrated->peer->id, -_showAtMsgId)
|
||||||
|
: (_history && _showAtMsgId > 0)
|
||||||
|
? FullMsgId(_history->peer->id, _showAtMsgId)
|
||||||
|
: FullMsgId();
|
||||||
|
}
|
||||||
|
|
||||||
void HistoryWidget::checkSuggestToGigagroup() {
|
void HistoryWidget::checkSuggestToGigagroup() {
|
||||||
const auto group = _peer ? _peer->asMegagroup() : nullptr;
|
const auto group = _peer ? _peer->asMegagroup() : nullptr;
|
||||||
if (!group || !group->owner().suggestToGigagroup(group)) {
|
if (!group || !group->owner().suggestToGigagroup(group)) {
|
||||||
|
@ -4080,14 +4002,7 @@ void HistoryWidget::finishAnimating() {
|
||||||
_a_show.stop();
|
_a_show.stop();
|
||||||
_topShadow->setVisible(_peer != nullptr);
|
_topShadow->setVisible(_peer != nullptr);
|
||||||
_topBar->setVisible(_peer != nullptr);
|
_topBar->setVisible(_peer != nullptr);
|
||||||
cornerButtonsAnimationFinish();
|
_cornerButtons.finishAnimations();
|
||||||
}
|
|
||||||
|
|
||||||
void HistoryWidget::cornerButtonsAnimationFinish() {
|
|
||||||
_historyDown.animation.stop();
|
|
||||||
_unreadMentions.animation.stop();
|
|
||||||
_unreadReactions.animation.stop();
|
|
||||||
updateCornerButtonsPositions();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::chooseAttach(
|
void HistoryWidget::chooseAttach(
|
||||||
|
@ -4320,12 +4235,6 @@ bool HistoryWidget::eventFilter(QObject *obj, QEvent *e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (e->type() == QEvent::Wheel
|
|
||||||
&& (obj == _historyDown.widget
|
|
||||||
|| obj == _unreadMentions.widget
|
|
||||||
|| obj == _unreadReactions.widget)) {
|
|
||||||
return _scroll->viewportEvent(e);
|
|
||||||
}
|
|
||||||
return TWidget::eventFilter(obj, e);
|
return TWidget::eventFilter(obj, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5296,7 +5205,7 @@ void HistoryWidget::updateControlsGeometry() {
|
||||||
|
|
||||||
updateFieldSize();
|
updateFieldSize();
|
||||||
|
|
||||||
updateCornerButtonsPositions();
|
_cornerButtons.updatePositions();
|
||||||
|
|
||||||
if (_membersDropdown) {
|
if (_membersDropdown) {
|
||||||
_membersDropdown->setMaxHeight(countMembersDropdownHeightMax());
|
_membersDropdown->setMaxHeight(countMembersDropdownHeightMax());
|
||||||
|
@ -5324,8 +5233,8 @@ void HistoryWidget::itemRemoved(not_null<const HistoryItem*> item) {
|
||||||
if (item == _replyEditMsg && _replyToId) {
|
if (item == _replyEditMsg && _replyToId) {
|
||||||
cancelReply();
|
cancelReply();
|
||||||
}
|
}
|
||||||
while (item == _replyReturn) {
|
while (item == _cornerButtons.replyReturn()) {
|
||||||
calcNextReplyReturn();
|
_cornerButtons.calculateNextReplyReturn();
|
||||||
}
|
}
|
||||||
if (_kbReplyTo && item == _kbReplyTo) {
|
if (_kbReplyTo && item == _kbReplyTo) {
|
||||||
toggleKeyboard();
|
toggleKeyboard();
|
||||||
|
@ -5514,7 +5423,7 @@ void HistoryWidget::updateHistoryGeometry(
|
||||||
if (_supportAutocomplete) {
|
if (_supportAutocomplete) {
|
||||||
_supportAutocomplete->setBoundings(_scroll->geometry());
|
_supportAutocomplete->setBoundings(_scroll->geometry());
|
||||||
}
|
}
|
||||||
updateCornerButtonsPositions();
|
_cornerButtons.updatePositions();
|
||||||
controller()->floatPlayerAreaUpdated();
|
controller()->floatPlayerAreaUpdated();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5856,75 +5765,24 @@ int HistoryWidget::computeMaxFieldHeight() const {
|
||||||
return std::min(st::historyComposeFieldMaxHeight, available);
|
return std::min(st::historyComposeFieldMaxHeight, available);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::updateCornerButtonsPositions() {
|
bool HistoryWidget::cornerButtonsIgnoreVisibility() {
|
||||||
const auto checkVisibility = [](CornerButton &button) {
|
return _a_show.animating();
|
||||||
const auto shouldBeHidden = !button.shown
|
|
||||||
&& !button.animation.animating();
|
|
||||||
if (shouldBeHidden != button.widget->isHidden()) {
|
|
||||||
button.widget->setVisible(!shouldBeHidden);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const auto shown = [](CornerButton &button) {
|
|
||||||
return button.animation.value(button.shown ? 1. : 0.);
|
|
||||||
};
|
|
||||||
|
|
||||||
// All corner buttons is a child widgets of _scroll, not me.
|
|
||||||
|
|
||||||
const auto historyDownShown = shown(_historyDown);
|
|
||||||
const auto unreadMentionsShown = shown(_unreadMentions);
|
|
||||||
const auto unreadReactionsShown = shown(_unreadReactions);
|
|
||||||
const auto skip = st::historyUnreadThingsSkip;
|
|
||||||
{
|
|
||||||
const auto top = anim::interpolate(
|
|
||||||
0,
|
|
||||||
_historyDown.widget->height() + st::historyToDownPosition.y(),
|
|
||||||
historyDownShown);
|
|
||||||
_historyDown.widget->moveToRight(
|
|
||||||
st::historyToDownPosition.x(),
|
|
||||||
_scroll->height() - top);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
const auto right = anim::interpolate(
|
|
||||||
-_unreadMentions.widget->width(),
|
|
||||||
st::historyToDownPosition.x(),
|
|
||||||
unreadMentionsShown);
|
|
||||||
const auto shift = anim::interpolate(
|
|
||||||
0,
|
|
||||||
_historyDown.widget->height() + skip,
|
|
||||||
historyDownShown);
|
|
||||||
const auto top = _scroll->height()
|
|
||||||
- _unreadMentions.widget->height()
|
|
||||||
- st::historyToDownPosition.y()
|
|
||||||
- shift;
|
|
||||||
_unreadMentions.widget->moveToRight(right, top);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
const auto right = anim::interpolate(
|
|
||||||
-_unreadReactions.widget->width(),
|
|
||||||
st::historyToDownPosition.x(),
|
|
||||||
unreadReactionsShown);
|
|
||||||
const auto shift = anim::interpolate(
|
|
||||||
0,
|
|
||||||
_historyDown.widget->height() + skip,
|
|
||||||
historyDownShown
|
|
||||||
) + anim::interpolate(
|
|
||||||
0,
|
|
||||||
_unreadMentions.widget->height() + skip,
|
|
||||||
unreadMentionsShown);
|
|
||||||
const auto top = _scroll->height()
|
|
||||||
- _unreadReactions.widget->height()
|
|
||||||
- st::historyToDownPosition.y()
|
|
||||||
- shift;
|
|
||||||
_unreadReactions.widget->moveToRight(right, top);
|
|
||||||
}
|
|
||||||
|
|
||||||
checkVisibility(_historyDown);
|
|
||||||
checkVisibility(_unreadMentions);
|
|
||||||
checkVisibility(_unreadReactions);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::updateHistoryDownVisibility() {
|
bool HistoryWidget::cornerButtonsDownShown() {
|
||||||
if (_a_show.animating()) return;
|
if (!_list || _firstLoadRequest) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (_voiceRecordBar->isLockPresent()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!_history->loadedAtBottom() || _cornerButtons.replyReturn()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const auto top = _scroll->scrollTop() + st::historyToDownShownAfter;
|
||||||
|
if (top < _scroll->scrollTopMax()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
const auto haveUnreadBelowBottom = [&](History *history) {
|
const auto haveUnreadBelowBottom = [&](History *history) {
|
||||||
if (!_list || !history || history->unreadCount() <= 0) {
|
if (!_list || !history || history->unreadCount() <= 0) {
|
||||||
|
@ -5937,75 +5795,15 @@ void HistoryWidget::updateHistoryDownVisibility() {
|
||||||
const auto top = _list->itemTop(unread);
|
const auto top = _list->itemTop(unread);
|
||||||
return (top >= _scroll->scrollTop() + _scroll->height());
|
return (top >= _scroll->scrollTop() + _scroll->height());
|
||||||
};
|
};
|
||||||
updateCornerButtonVisibility(_historyDown, [&] {
|
if (haveUnreadBelowBottom(_history)
|
||||||
if (!_list || _firstLoadRequest) {
|
|| haveUnreadBelowBottom(_migrated)) {
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
if (_voiceRecordBar->isLockPresent()) {
|
return false;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!_history->loadedAtBottom() || _replyReturn) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
const auto top = _scroll->scrollTop() + st::historyToDownShownAfter;
|
|
||||||
if (top < _scroll->scrollTopMax()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (haveUnreadBelowBottom(_history)
|
|
||||||
|| haveUnreadBelowBottom(_migrated)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::updateCornerButtonVisibility(
|
bool HistoryWidget::cornerButtonsUnreadMayBeShown() {
|
||||||
CornerButton &button,
|
return !_firstLoadRequest && !_voiceRecordBar->isLockPresent();
|
||||||
bool shown) {
|
|
||||||
if (button.shown != shown) {
|
|
||||||
button.shown = shown;
|
|
||||||
button.animation.start(
|
|
||||||
[=] { updateCornerButtonsPositions(); },
|
|
||||||
shown ? 0. : 1.,
|
|
||||||
shown ? 1. : 0.,
|
|
||||||
st::historyToDownDuration);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void HistoryWidget::updateUnreadThingsVisibility() {
|
|
||||||
if (_a_show.animating()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto &unreadThings = session().api().unreadThings();
|
|
||||||
unreadThings.preloadEnough(_history);
|
|
||||||
|
|
||||||
const auto updateWithLoadedCount = [&](CornerButton &button, int count) {
|
|
||||||
updateCornerButtonVisibility(button, (count > 0)
|
|
||||||
&& !_firstLoadRequest
|
|
||||||
&& !_voiceRecordBar->isLockPresent());
|
|
||||||
};
|
|
||||||
if (unreadThings.trackMentions(_peer)) {
|
|
||||||
if (const auto count = _history->unreadMentions().count(0)) {
|
|
||||||
_unreadMentions.widget->setUnreadCount(count);
|
|
||||||
}
|
|
||||||
updateWithLoadedCount(
|
|
||||||
_unreadMentions,
|
|
||||||
_history->unreadMentions().loadedCount());
|
|
||||||
} else {
|
|
||||||
updateCornerButtonVisibility(_unreadMentions, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (unreadThings.trackReactions(_peer)) {
|
|
||||||
if (const auto count = _history->unreadReactions().count(0)) {
|
|
||||||
_unreadReactions.widget->setUnreadCount(count);
|
|
||||||
}
|
|
||||||
updateWithLoadedCount(
|
|
||||||
_unreadReactions,
|
|
||||||
_history->unreadReactions().loadedCount());
|
|
||||||
} else {
|
|
||||||
updateCornerButtonVisibility(_unreadReactions, false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::mousePressEvent(QMouseEvent *e) {
|
void HistoryWidget::mousePressEvent(QMouseEvent *e) {
|
||||||
|
|
|
@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "history/view/history_view_corner_buttons.h"
|
||||||
#include "history/history_drag_area.h"
|
#include "history/history_drag_area.h"
|
||||||
#include "history/history_view_highlight_manager.h"
|
#include "history/history_view_highlight_manager.h"
|
||||||
#include "history/history_view_top_toast.h"
|
#include "history/history_view_top_toast.h"
|
||||||
|
@ -107,7 +108,9 @@ class HistoryInner;
|
||||||
|
|
||||||
extern const char kOptionAutoScrollInactiveChat[];
|
extern const char kOptionAutoScrollInactiveChat[];
|
||||||
|
|
||||||
class HistoryWidget final : public Window::AbstractSectionWidget {
|
class HistoryWidget final
|
||||||
|
: public Window::AbstractSectionWidget
|
||||||
|
, private HistoryView::CornerButtonsDelegate {
|
||||||
public:
|
public:
|
||||||
using FieldHistoryAction = Ui::InputField::HistoryAction;
|
using FieldHistoryAction = Ui::InputField::HistoryAction;
|
||||||
using RecordLock = HistoryView::Controls::RecordLock;
|
using RecordLock = HistoryView::Controls::RecordLock;
|
||||||
|
@ -193,11 +196,9 @@ public:
|
||||||
void updateForwarding();
|
void updateForwarding();
|
||||||
void updateForwardingTexts();
|
void updateForwardingTexts();
|
||||||
|
|
||||||
void clearReplyReturns();
|
|
||||||
void pushReplyReturn(not_null<HistoryItem*> item);
|
void pushReplyReturn(not_null<HistoryItem*> item);
|
||||||
QList<MsgId> replyReturns();
|
[[nodiscard]] QVector<FullMsgId> replyReturns() const;
|
||||||
void setReplyReturns(PeerId peer, const QList<MsgId> &replyReturns);
|
void setReplyReturns(PeerId peer, QVector<FullMsgId> replyReturns);
|
||||||
void calcNextReplyReturn();
|
|
||||||
|
|
||||||
void updatePreview();
|
void updatePreview();
|
||||||
void previewCancel();
|
void previewCancel();
|
||||||
|
@ -321,15 +322,15 @@ private:
|
||||||
};
|
};
|
||||||
using TextUpdateEvents = base::flags<TextUpdateEvent>;
|
using TextUpdateEvents = base::flags<TextUpdateEvent>;
|
||||||
friend inline constexpr bool is_flag_type(TextUpdateEvent) { return true; };
|
friend inline constexpr bool is_flag_type(TextUpdateEvent) { return true; };
|
||||||
struct CornerButton {
|
|
||||||
template <typename ...Args>
|
|
||||||
CornerButton(Args &&...args) : widget(std::forward<Args>(args)...) {
|
|
||||||
}
|
|
||||||
|
|
||||||
Ui::Animations::Simple animation;
|
void cornerButtonsShowAtPosition(
|
||||||
bool shown = false;
|
Data::MessagePosition position) override;
|
||||||
object_ptr<Ui::HistoryDownButton> widget;
|
Dialogs::Entry *cornerButtonsEntry() override;
|
||||||
};
|
FullMsgId cornerButtonsCurrentId() override;
|
||||||
|
bool cornerButtonsIgnoreVisibility() override;
|
||||||
|
bool cornerButtonsDownShown() override;
|
||||||
|
bool cornerButtonsUnreadMayBeShown() override;
|
||||||
|
|
||||||
void checkSuggestToGigagroup();
|
void checkSuggestToGigagroup();
|
||||||
|
|
||||||
void initTabbedSelector();
|
void initTabbedSelector();
|
||||||
|
@ -380,9 +381,6 @@ private:
|
||||||
void fullInfoUpdated();
|
void fullInfoUpdated();
|
||||||
void toggleTabbedSelectorMode();
|
void toggleTabbedSelectorMode();
|
||||||
void recountChatWidth();
|
void recountChatWidth();
|
||||||
void historyDownClicked();
|
|
||||||
void showNextUnreadMention();
|
|
||||||
void showNextUnreadReaction();
|
|
||||||
void handlePeerUpdate();
|
void handlePeerUpdate();
|
||||||
void setMembersShowAreaActive(bool active);
|
void setMembersShowAreaActive(bool active);
|
||||||
void handleHistoryChange(not_null<const History*> history);
|
void handleHistoryChange(not_null<const History*> history);
|
||||||
|
@ -410,16 +408,10 @@ private:
|
||||||
void animationCallback();
|
void animationCallback();
|
||||||
void updateOverStates(QPoint pos);
|
void updateOverStates(QPoint pos);
|
||||||
void chooseAttach(std::optional<bool> overrideSendImagesAsPhotos = {});
|
void chooseAttach(std::optional<bool> overrideSendImagesAsPhotos = {});
|
||||||
void cornerButtonsAnimationFinish();
|
|
||||||
void sendButtonClicked();
|
void sendButtonClicked();
|
||||||
void newItemAdded(not_null<HistoryItem*> item);
|
void newItemAdded(not_null<HistoryItem*> item);
|
||||||
void maybeMarkReactionsRead(not_null<HistoryItem*> item);
|
void maybeMarkReactionsRead(not_null<HistoryItem*> item);
|
||||||
|
|
||||||
void updateCornerButtonsPositions();
|
|
||||||
void updateHistoryDownVisibility();
|
|
||||||
void updateUnreadThingsVisibility();
|
|
||||||
void updateCornerButtonVisibility(CornerButton &button, bool shown);
|
|
||||||
|
|
||||||
bool canSendFiles(not_null<const QMimeData*> data) const;
|
bool canSendFiles(not_null<const QMimeData*> data) const;
|
||||||
bool confirmSendingFiles(
|
bool confirmSendingFiles(
|
||||||
const QStringList &files,
|
const QStringList &files,
|
||||||
|
@ -665,9 +657,6 @@ private:
|
||||||
|
|
||||||
bool _replyForwardPressed = false;
|
bool _replyForwardPressed = false;
|
||||||
|
|
||||||
HistoryItem *_replyReturn = nullptr;
|
|
||||||
QList<MsgId> _replyReturns;
|
|
||||||
|
|
||||||
PeerData *_peer = nullptr;
|
PeerData *_peer = nullptr;
|
||||||
|
|
||||||
bool _canSendMessages = false;
|
bool _canSendMessages = false;
|
||||||
|
@ -701,9 +690,7 @@ private:
|
||||||
bool _synteticScrollEvent = false;
|
bool _synteticScrollEvent = false;
|
||||||
Ui::Animations::Simple _scrollToAnimation;
|
Ui::Animations::Simple _scrollToAnimation;
|
||||||
|
|
||||||
CornerButton _historyDown;
|
HistoryView::CornerButtons _cornerButtons;
|
||||||
CornerButton _unreadMentions;
|
|
||||||
CornerButton _unreadReactions;
|
|
||||||
|
|
||||||
const object_ptr<FieldAutocomplete> _fieldAutocomplete;
|
const object_ptr<FieldAutocomplete> _fieldAutocomplete;
|
||||||
object_ptr<Support::Autocomplete> _supportAutocomplete;
|
object_ptr<Support::Autocomplete> _supportAutocomplete;
|
||||||
|
|
|
@ -0,0 +1,335 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop application for the Telegram messaging service.
|
||||||
|
|
||||||
|
For license and copyright information please follow this link:
|
||||||
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
*/
|
||||||
|
#include "history/view/history_view_corner_buttons.h"
|
||||||
|
|
||||||
|
#include "ui/widgets/scroll_area.h"
|
||||||
|
#include "ui/chat/chat_style.h"
|
||||||
|
#include "ui/special_buttons.h"
|
||||||
|
#include "base/qt/qt_key_modifiers.h"
|
||||||
|
#include "history/history.h"
|
||||||
|
#include "history/history_item.h"
|
||||||
|
#include "history/history_unread_things.h"
|
||||||
|
#include "dialogs/dialogs_entry.h"
|
||||||
|
#include "main/main_session.h"
|
||||||
|
#include "menu/menu_send.h"
|
||||||
|
#include "apiwrap.h"
|
||||||
|
#include "api/api_unread_things.h"
|
||||||
|
#include "data/data_document.h"
|
||||||
|
#include "data/data_messages.h"
|
||||||
|
#include "data/data_session.h"
|
||||||
|
#include "data/data_forum_topic.h"
|
||||||
|
#include "styles/style_chat.h"
|
||||||
|
|
||||||
|
namespace HistoryView {
|
||||||
|
|
||||||
|
CornerButtons::CornerButtons(
|
||||||
|
not_null<Ui::ScrollArea*> parent,
|
||||||
|
not_null<const Ui::ChatStyle*> st,
|
||||||
|
not_null<CornerButtonsDelegate*> delegate)
|
||||||
|
: down(
|
||||||
|
parent,
|
||||||
|
st->value(parent->lifetime(), st::historyToDown))
|
||||||
|
, mentions(
|
||||||
|
parent,
|
||||||
|
st->value(parent->lifetime(), st::historyUnreadMentions))
|
||||||
|
, reactions(
|
||||||
|
parent,
|
||||||
|
st->value(parent->lifetime(), st::historyUnreadReactions))
|
||||||
|
, _scroll(parent)
|
||||||
|
, _delegate(delegate) {
|
||||||
|
down.widget->addClickHandler([=] { downClick(); });
|
||||||
|
mentions.widget->addClickHandler([=] { mentionsClick(); });
|
||||||
|
reactions.widget->addClickHandler([=] { reactionsClick(); });
|
||||||
|
|
||||||
|
const auto filterScroll = [&](CornerButton &button) {
|
||||||
|
button.widget->installEventFilter(this);
|
||||||
|
};
|
||||||
|
filterScroll(down);
|
||||||
|
filterScroll(mentions);
|
||||||
|
filterScroll(reactions);
|
||||||
|
|
||||||
|
SendMenu::SetupUnreadMentionsMenu(mentions.widget.data(), [=] {
|
||||||
|
return _delegate->cornerButtonsEntry();
|
||||||
|
});
|
||||||
|
SendMenu::SetupUnreadReactionsMenu(reactions.widget.data(), [=] {
|
||||||
|
return _delegate->cornerButtonsEntry();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CornerButtons::eventFilter(QObject *o, QEvent *e) {
|
||||||
|
if (e->type() == QEvent::Wheel
|
||||||
|
&& (o == down.widget
|
||||||
|
|| o == mentions.widget
|
||||||
|
|| o == reactions.widget)) {
|
||||||
|
return _scroll->viewportEvent(e);
|
||||||
|
}
|
||||||
|
return QObject::eventFilter(o, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CornerButtons::downClick() {
|
||||||
|
if (base::IsCtrlPressed() || !_replyReturn) {
|
||||||
|
_delegate->cornerButtonsShowAtPosition(Data::UnreadMessagePosition);
|
||||||
|
} else {
|
||||||
|
_delegate->cornerButtonsShowAtPosition(_replyReturn->position());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CornerButtons::mentionsClick() {
|
||||||
|
const auto history = lookupHistory();
|
||||||
|
if (!history) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto entry = _delegate->cornerButtonsEntry();
|
||||||
|
const auto msgId = entry->unreadMentions().minLoaded();
|
||||||
|
const auto already = (_delegate->cornerButtonsCurrentId().msg == msgId);
|
||||||
|
|
||||||
|
// Mark mention voice/video message as read.
|
||||||
|
// See https://github.com/telegramdesktop/tdesktop/issues/5623
|
||||||
|
if (msgId && already) {
|
||||||
|
if (const auto item = entry->owner().message(history->peer, msgId)) {
|
||||||
|
if (const auto media = item->media()) {
|
||||||
|
if (const auto document = media->document()) {
|
||||||
|
if (!media->webpage()
|
||||||
|
&& (document->isVoiceMessage()
|
||||||
|
|| document->isVideoMessage())) {
|
||||||
|
document->owner().markMediaRead(document);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
showAt(msgId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CornerButtons::reactionsClick() {
|
||||||
|
const auto history = lookupHistory();
|
||||||
|
if (!history) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto entry = _delegate->cornerButtonsEntry();
|
||||||
|
showAt(entry->unreadReactions().minLoaded());
|
||||||
|
}
|
||||||
|
|
||||||
|
void CornerButtons::clearReplyReturns() {
|
||||||
|
_replyReturns.clear();
|
||||||
|
_replyReturn = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<FullMsgId> CornerButtons::replyReturns() const {
|
||||||
|
return _replyReturns;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CornerButtons::setReplyReturns(QVector<FullMsgId> replyReturns) {
|
||||||
|
_replyReturns = std::move(replyReturns);
|
||||||
|
computeCurrentReplyReturn();
|
||||||
|
if (!_replyReturn) {
|
||||||
|
calculateNextReplyReturn();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CornerButtons::computeCurrentReplyReturn() {
|
||||||
|
const auto entry = _delegate->cornerButtonsEntry();
|
||||||
|
_replyReturn = (!entry || _replyReturns.empty())
|
||||||
|
? nullptr
|
||||||
|
: entry->owner().message(_replyReturns.back());
|
||||||
|
}
|
||||||
|
|
||||||
|
void CornerButtons::skipReplyReturn(FullMsgId id) {
|
||||||
|
while (_replyReturn) {
|
||||||
|
if (_replyReturn->fullId() == id) {
|
||||||
|
calculateNextReplyReturn();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CornerButtons::calculateNextReplyReturn() {
|
||||||
|
_replyReturn = nullptr;
|
||||||
|
while (!_replyReturns.empty() && !_replyReturn) {
|
||||||
|
_replyReturns.pop_back();
|
||||||
|
computeCurrentReplyReturn();
|
||||||
|
}
|
||||||
|
if (!_replyReturn) {
|
||||||
|
updateJumpDownVisibility();
|
||||||
|
updateUnreadThingsVisibility();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CornerButtons::pushReplyReturn(not_null<HistoryItem*> item) {
|
||||||
|
_replyReturns.push_back(item->fullId());
|
||||||
|
_replyReturn = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
CornerButton &CornerButtons::buttonByType(CornerButtonType type) {
|
||||||
|
switch (type) {
|
||||||
|
case CornerButtonType::Down: return down;
|
||||||
|
case CornerButtonType::Mentions: return mentions;
|
||||||
|
case CornerButtonType::Reactions: return reactions;
|
||||||
|
}
|
||||||
|
Unexpected("Type in CornerButtons::buttonByType.");
|
||||||
|
}
|
||||||
|
|
||||||
|
History *CornerButtons::lookupHistory() const {
|
||||||
|
const auto entry = _delegate->cornerButtonsEntry();
|
||||||
|
if (!entry) {
|
||||||
|
return nullptr;
|
||||||
|
} else if (const auto history = entry->asHistory()) {
|
||||||
|
return history;
|
||||||
|
} else if (const auto topic = entry->asTopic()) {
|
||||||
|
return topic->history();
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CornerButtons::showAt(MsgId id) {
|
||||||
|
if (const auto history = lookupHistory()) {
|
||||||
|
if (const auto item = history->owner().message(history->peer, id)) {
|
||||||
|
_delegate->cornerButtonsShowAtPosition(item->position());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CornerButtons::updateVisibility(
|
||||||
|
CornerButtonType type,
|
||||||
|
bool shown) {
|
||||||
|
auto &button = buttonByType(type);
|
||||||
|
if (button.shown != shown) {
|
||||||
|
button.shown = shown;
|
||||||
|
button.animation.start(
|
||||||
|
[=] { updatePositions(); },
|
||||||
|
shown ? 0. : 1.,
|
||||||
|
shown ? 1. : 0.,
|
||||||
|
st::historyToDownDuration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CornerButtons::updateUnreadThingsVisibility() {
|
||||||
|
if (_delegate->cornerButtonsIgnoreVisibility()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto entry = _delegate->cornerButtonsEntry();
|
||||||
|
if (!entry) {
|
||||||
|
updateVisibility(CornerButtonType::Mentions, false);
|
||||||
|
updateVisibility(CornerButtonType::Reactions, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto &unreadThings = entry->session().api().unreadThings();
|
||||||
|
unreadThings.preloadEnough(entry);
|
||||||
|
|
||||||
|
const auto updateWithCount = [&](CornerButtonType type, int count) {
|
||||||
|
updateVisibility(
|
||||||
|
type,
|
||||||
|
(count > 0) && _delegate->cornerButtonsUnreadMayBeShown());
|
||||||
|
};
|
||||||
|
if (unreadThings.trackMentions(entry)) {
|
||||||
|
if (const auto count = entry->unreadMentions().count(0)) {
|
||||||
|
mentions.widget->setUnreadCount(count);
|
||||||
|
}
|
||||||
|
updateWithCount(
|
||||||
|
CornerButtonType::Mentions,
|
||||||
|
entry->unreadMentions().loadedCount());
|
||||||
|
} else {
|
||||||
|
updateVisibility(CornerButtonType::Mentions, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unreadThings.trackReactions(entry)) {
|
||||||
|
if (const auto count = entry->unreadReactions().count(0)) {
|
||||||
|
reactions.widget->setUnreadCount(count);
|
||||||
|
}
|
||||||
|
updateWithCount(
|
||||||
|
CornerButtonType::Reactions,
|
||||||
|
entry->unreadReactions().loadedCount());
|
||||||
|
} else {
|
||||||
|
updateVisibility(CornerButtonType::Reactions, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CornerButtons::updateJumpDownVisibility(std::optional<int> counter) {
|
||||||
|
const auto shown = _delegate->cornerButtonsDownShown();
|
||||||
|
updateVisibility(CornerButtonType::Down, shown);
|
||||||
|
if (counter) {
|
||||||
|
down.widget->setUnreadCount(*counter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CornerButtons::updatePositions() {
|
||||||
|
const auto checkVisibility = [](CornerButton &button) {
|
||||||
|
const auto shouldBeHidden = !button.shown
|
||||||
|
&& !button.animation.animating();
|
||||||
|
if (shouldBeHidden != button.widget->isHidden()) {
|
||||||
|
button.widget->setVisible(!shouldBeHidden);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const auto shown = [](CornerButton &button) {
|
||||||
|
return button.animation.value(button.shown ? 1. : 0.);
|
||||||
|
};
|
||||||
|
|
||||||
|
// All corner buttons is a child widgets of _scroll, not me.
|
||||||
|
|
||||||
|
const auto historyDownShown = shown(down);
|
||||||
|
const auto unreadMentionsShown = shown(mentions);
|
||||||
|
const auto unreadReactionsShown = shown(reactions);
|
||||||
|
const auto skip = st::historyUnreadThingsSkip;
|
||||||
|
{
|
||||||
|
const auto top = anim::interpolate(
|
||||||
|
0,
|
||||||
|
down.widget->height() + st::historyToDownPosition.y(),
|
||||||
|
historyDownShown);
|
||||||
|
down.widget->moveToRight(
|
||||||
|
st::historyToDownPosition.x(),
|
||||||
|
_scroll->height() - top);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const auto right = anim::interpolate(
|
||||||
|
-mentions.widget->width(),
|
||||||
|
st::historyToDownPosition.x(),
|
||||||
|
unreadMentionsShown);
|
||||||
|
const auto shift = anim::interpolate(
|
||||||
|
0,
|
||||||
|
down.widget->height() + skip,
|
||||||
|
historyDownShown);
|
||||||
|
const auto top = _scroll->height()
|
||||||
|
- mentions.widget->height()
|
||||||
|
- st::historyToDownPosition.y()
|
||||||
|
- shift;
|
||||||
|
mentions.widget->moveToRight(right, top);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const auto right = anim::interpolate(
|
||||||
|
-reactions.widget->width(),
|
||||||
|
st::historyToDownPosition.x(),
|
||||||
|
unreadReactionsShown);
|
||||||
|
const auto shift = anim::interpolate(
|
||||||
|
0,
|
||||||
|
down.widget->height() + skip,
|
||||||
|
historyDownShown
|
||||||
|
) + anim::interpolate(
|
||||||
|
0,
|
||||||
|
mentions.widget->height() + skip,
|
||||||
|
unreadMentionsShown);
|
||||||
|
const auto top = _scroll->height()
|
||||||
|
- reactions.widget->height()
|
||||||
|
- st::historyToDownPosition.y()
|
||||||
|
- shift;
|
||||||
|
reactions.widget->moveToRight(right, top);
|
||||||
|
}
|
||||||
|
|
||||||
|
checkVisibility(down);
|
||||||
|
checkVisibility(mentions);
|
||||||
|
checkVisibility(reactions);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CornerButtons::finishAnimations() {
|
||||||
|
down.animation.stop();
|
||||||
|
mentions.animation.stop();
|
||||||
|
reactions.animation.stop();
|
||||||
|
updatePositions();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace HistoryView
|
110
Telegram/SourceFiles/history/view/history_view_corner_buttons.h
Normal file
110
Telegram/SourceFiles/history/view/history_view_corner_buttons.h
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop application for the Telegram messaging service.
|
||||||
|
|
||||||
|
For license and copyright information please follow this link:
|
||||||
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ui/effects/animations.h"
|
||||||
|
#include "base/object_ptr.h"
|
||||||
|
|
||||||
|
class History;
|
||||||
|
class HistoryItem;
|
||||||
|
struct FullMsgId;
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class ChatStyle;
|
||||||
|
class ScrollArea;
|
||||||
|
class HistoryDownButton;
|
||||||
|
} // namespace Ui
|
||||||
|
|
||||||
|
namespace Data {
|
||||||
|
struct MessagePosition;
|
||||||
|
} // namespace Data
|
||||||
|
|
||||||
|
namespace Dialogs {
|
||||||
|
class Entry;
|
||||||
|
} // namespace Dialogs
|
||||||
|
|
||||||
|
namespace HistoryView {
|
||||||
|
|
||||||
|
struct CornerButton {
|
||||||
|
template <typename ...Args>
|
||||||
|
CornerButton(Args &&...args) : widget(std::forward<Args>(args)...) {
|
||||||
|
}
|
||||||
|
|
||||||
|
object_ptr<Ui::HistoryDownButton> widget;
|
||||||
|
Ui::Animations::Simple animation;
|
||||||
|
bool shown = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class CornerButtonType {
|
||||||
|
Down,
|
||||||
|
Mentions,
|
||||||
|
Reactions,
|
||||||
|
};
|
||||||
|
|
||||||
|
class CornerButtonsDelegate {
|
||||||
|
public:
|
||||||
|
virtual void cornerButtonsShowAtPosition(
|
||||||
|
Data::MessagePosition position) = 0;
|
||||||
|
[[nodiscard]] virtual Dialogs::Entry *cornerButtonsEntry() = 0;
|
||||||
|
[[nodiscard]] virtual FullMsgId cornerButtonsCurrentId() = 0;
|
||||||
|
[[nodiscard]] virtual bool cornerButtonsIgnoreVisibility() = 0;
|
||||||
|
[[nodiscard]] virtual bool cornerButtonsDownShown() = 0;
|
||||||
|
[[nodiscard]] virtual bool cornerButtonsUnreadMayBeShown() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CornerButtons final : private QObject {
|
||||||
|
public:
|
||||||
|
CornerButtons(
|
||||||
|
not_null<Ui::ScrollArea*> parent,
|
||||||
|
not_null<const Ui::ChatStyle*> st,
|
||||||
|
not_null<CornerButtonsDelegate*> delegate);
|
||||||
|
|
||||||
|
void downClick();
|
||||||
|
void mentionsClick();
|
||||||
|
void reactionsClick();
|
||||||
|
|
||||||
|
void clearReplyReturns();
|
||||||
|
[[nodiscard]] QVector<FullMsgId> replyReturns() const;
|
||||||
|
void setReplyReturns(QVector<FullMsgId> replyReturns);
|
||||||
|
void pushReplyReturn(not_null<HistoryItem*> item);
|
||||||
|
void skipReplyReturn(FullMsgId id);
|
||||||
|
void calculateNextReplyReturn();
|
||||||
|
|
||||||
|
void updateVisibility(CornerButtonType type, bool shown);
|
||||||
|
void updateUnreadThingsVisibility();
|
||||||
|
void updateJumpDownVisibility(std::optional<int> counter = {});
|
||||||
|
void updatePositions();
|
||||||
|
|
||||||
|
void finishAnimations();
|
||||||
|
|
||||||
|
[[nodiscard]] HistoryItem *replyReturn() const {
|
||||||
|
return _replyReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
CornerButton down;
|
||||||
|
CornerButton mentions;
|
||||||
|
CornerButton reactions;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool eventFilter(QObject *o, QEvent *e) override;
|
||||||
|
|
||||||
|
void computeCurrentReplyReturn();
|
||||||
|
|
||||||
|
[[nodiscard]] CornerButton &buttonByType(CornerButtonType type);
|
||||||
|
[[nodiscard]] History *lookupHistory() const;
|
||||||
|
void showAt(MsgId id);
|
||||||
|
|
||||||
|
const not_null<Ui::ScrollArea*> _scroll;
|
||||||
|
const not_null<CornerButtonsDelegate*> _delegate;
|
||||||
|
|
||||||
|
HistoryItem *_replyReturn = nullptr;
|
||||||
|
QVector<FullMsgId> _replyReturns;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace HistoryView
|
|
@ -158,7 +158,7 @@ public:
|
||||||
StackItemHistory(
|
StackItemHistory(
|
||||||
not_null<History*> history,
|
not_null<History*> history,
|
||||||
MsgId msgId,
|
MsgId msgId,
|
||||||
QList<MsgId> replyReturns)
|
QVector<FullMsgId> replyReturns)
|
||||||
: StackItem(history->peer)
|
: StackItem(history->peer)
|
||||||
, history(history)
|
, history(history)
|
||||||
, msgId(msgId)
|
, msgId(msgId)
|
||||||
|
@ -171,7 +171,7 @@ public:
|
||||||
|
|
||||||
not_null<History*> history;
|
not_null<History*> history;
|
||||||
MsgId msgId;
|
MsgId msgId;
|
||||||
QList<MsgId> replyReturns;
|
QVector<FullMsgId> replyReturns;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1854,7 +1854,9 @@ void MainWidget::showBackFromStack(
|
||||||
historyItem->peer()->id,
|
historyItem->peer()->id,
|
||||||
params.withWay(SectionShow::Way::Backward),
|
params.withWay(SectionShow::Way::Backward),
|
||||||
ShowAtUnreadMsgId);
|
ShowAtUnreadMsgId);
|
||||||
_history->setReplyReturns(historyItem->peer()->id, historyItem->replyReturns);
|
_history->setReplyReturns(
|
||||||
|
historyItem->peer()->id,
|
||||||
|
std::move(historyItem->replyReturns));
|
||||||
} else if (item->type() == SectionStackItem) {
|
} else if (item->type() == SectionStackItem) {
|
||||||
auto sectionItem = static_cast<StackItemSection*>(item.get());
|
auto sectionItem = static_cast<StackItemSection*>(item.get());
|
||||||
showNewSection(
|
showNewSection(
|
||||||
|
|
|
@ -152,27 +152,30 @@ void SetupMenuAndShortcuts(
|
||||||
|
|
||||||
void SetupReadAllMenu(
|
void SetupReadAllMenu(
|
||||||
not_null<Ui::RpWidget*> button,
|
not_null<Ui::RpWidget*> button,
|
||||||
Fn<PeerData*()> currentPeer,
|
Fn<Dialogs::Entry*()> currentEntry,
|
||||||
const QString &text,
|
const QString &text,
|
||||||
Fn<void(not_null<PeerData*>, Fn<void()>)> sendReadRequest) {
|
Fn<void(not_null<Dialogs::Entry*>, Fn<void()>)> sendReadRequest) {
|
||||||
struct State {
|
struct State {
|
||||||
base::unique_qptr<Ui::PopupMenu> menu;
|
base::unique_qptr<Ui::PopupMenu> menu;
|
||||||
base::flat_set<not_null<PeerData*>> sentForPeers;
|
base::flat_set<base::weak_ptr<Dialogs::Entry>> sentForEntries;
|
||||||
};
|
};
|
||||||
const auto state = std::make_shared<State>();
|
const auto state = std::make_shared<State>();
|
||||||
const auto showMenu = [=] {
|
const auto showMenu = [=] {
|
||||||
const auto peer = currentPeer();
|
const auto entry = base::make_weak(currentEntry());
|
||||||
if (!peer) {
|
if (!entry) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
state->menu = base::make_unique_q<Ui::PopupMenu>(
|
state->menu = base::make_unique_q<Ui::PopupMenu>(
|
||||||
button,
|
button,
|
||||||
st::popupMenuWithIcons);
|
st::popupMenuWithIcons);
|
||||||
state->menu->addAction(text, [=] {
|
state->menu->addAction(text, [=] {
|
||||||
if (!state->sentForPeers.emplace(peer).second) {
|
const auto strong = entry.get();
|
||||||
|
if (!strong || !state->sentForEntries.emplace(entry).second) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
sendReadRequest(peer, [=] { state->sentForPeers.remove(peer); });
|
sendReadRequest(strong, [=] {
|
||||||
|
state->sentForEntries.remove(entry);
|
||||||
|
});
|
||||||
}, &st::menuIconMarkRead);
|
}, &st::menuIconMarkRead);
|
||||||
state->menu->popup(QCursor::pos());
|
state->menu->popup(QCursor::pos());
|
||||||
};
|
};
|
||||||
|
@ -188,52 +191,88 @@ void SetupReadAllMenu(
|
||||||
|
|
||||||
void SetupUnreadMentionsMenu(
|
void SetupUnreadMentionsMenu(
|
||||||
not_null<Ui::RpWidget*> button,
|
not_null<Ui::RpWidget*> button,
|
||||||
Fn<PeerData*()> currentPeer,
|
Fn<Dialogs::Entry*()> currentEntry) {
|
||||||
MsgId topicRootId) {
|
|
||||||
const auto text = tr::lng_context_mark_read_mentions_all(tr::now);
|
const auto text = tr::lng_context_mark_read_mentions_all(tr::now);
|
||||||
const auto sendRequest = [=](not_null<PeerData*> peer, Fn<void()> done) {
|
const auto sendOne = [=](
|
||||||
|
base::weak_ptr<Dialogs::Entry> weakEntry,
|
||||||
|
Fn<void()> done,
|
||||||
|
auto resend) -> void {
|
||||||
|
const auto entry = weakEntry.get();
|
||||||
|
if (!entry) {
|
||||||
|
done();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto history = entry->asHistory();
|
||||||
|
const auto topic = entry->asTopic();
|
||||||
|
Assert(history || topic);
|
||||||
|
const auto peer = (history ? history : topic->history().get())->peer;
|
||||||
|
const auto rootId = topic ? topic->rootId() : 0;
|
||||||
using Flag = MTPmessages_ReadMentions::Flag;
|
using Flag = MTPmessages_ReadMentions::Flag;
|
||||||
peer->session().api().request(MTPmessages_ReadMentions(
|
peer->session().api().request(MTPmessages_ReadMentions(
|
||||||
MTP_flags(topicRootId ? Flag::f_top_msg_id : Flag()),
|
MTP_flags(rootId ? Flag::f_top_msg_id : Flag()),
|
||||||
peer->input,
|
peer->input,
|
||||||
MTP_int(topicRootId)
|
MTP_int(rootId)
|
||||||
)).done([=](const MTPmessages_AffectedHistory &result) {
|
)).done([=](const MTPmessages_AffectedHistory &result) {
|
||||||
done();
|
const auto offset = peer->session().api().applyAffectedHistory(
|
||||||
peer->session().api().applyAffectedHistory(peer, result);
|
peer,
|
||||||
const auto forum = peer->forum();
|
result);
|
||||||
const auto history = peer->owner().history(peer);
|
if (offset > 0) {
|
||||||
if (!topicRootId) {
|
resend(weakEntry, done, resend);
|
||||||
history->unreadMentions().clear();
|
|
||||||
if (forum) {
|
|
||||||
forum->clearAllUnreadMentions();
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (forum) {
|
done();
|
||||||
if (const auto topic = forum->topicFor(topicRootId)) {
|
peer->owner().history(peer)->clearUnreadMentionsFor(rootId);
|
||||||
topic->unreadMentions().clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
history->clearUnreadMentionsFor(topicRootId);
|
|
||||||
}
|
}
|
||||||
}).fail(done).send();
|
}).fail(done).send();
|
||||||
};
|
};
|
||||||
SetupReadAllMenu(button, currentPeer, text, sendRequest);
|
const auto sendRequest = [=](
|
||||||
|
not_null<Dialogs::Entry*> entry,
|
||||||
|
Fn<void()> done) {
|
||||||
|
sendOne(base::make_weak(entry.get()), std::move(done), sendOne);
|
||||||
|
};
|
||||||
|
SetupReadAllMenu(button, currentEntry, text, sendRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetupUnreadReactionsMenu(
|
void SetupUnreadReactionsMenu(
|
||||||
not_null<Ui::RpWidget*> button,
|
not_null<Ui::RpWidget*> button,
|
||||||
Fn<PeerData*()> currentPeer) {
|
Fn<Dialogs::Entry*()> currentEntry) {
|
||||||
const auto text = tr::lng_context_mark_read_reactions_all(tr::now);
|
const auto text = tr::lng_context_mark_read_reactions_all(tr::now);
|
||||||
const auto sendRequest = [=](not_null<PeerData*> peer, Fn<void()> done) {
|
const auto sendOne = [=](
|
||||||
peer->session().api().request(MTPmessages_ReadReactions(
|
base::weak_ptr<Dialogs::Entry> weakEntry,
|
||||||
peer->input
|
Fn<void()> done,
|
||||||
)).done([=](const MTPmessages_AffectedHistory &result) {
|
auto resend) -> void {
|
||||||
|
const auto entry = weakEntry.get();
|
||||||
|
if (!entry) {
|
||||||
done();
|
done();
|
||||||
peer->session().api().applyAffectedHistory(peer, result);
|
return;
|
||||||
peer->owner().history(peer)->unreadReactions().clear();
|
}
|
||||||
|
const auto history = entry->asHistory();
|
||||||
|
const auto topic = entry->asTopic();
|
||||||
|
Assert(history || topic);
|
||||||
|
const auto peer = (history ? history : topic->history().get())->peer;
|
||||||
|
const auto rootId = topic ? topic->rootId() : 0;
|
||||||
|
using Flag = MTPmessages_ReadReactions::Flag;
|
||||||
|
peer->session().api().request(MTPmessages_ReadReactions(
|
||||||
|
MTP_flags(rootId ? Flag::f_top_msg_id : Flag(0)),
|
||||||
|
peer->input,
|
||||||
|
MTP_int(rootId)
|
||||||
|
)).done([=](const MTPmessages_AffectedHistory &result) {
|
||||||
|
const auto offset = peer->session().api().applyAffectedHistory(
|
||||||
|
peer,
|
||||||
|
result);
|
||||||
|
if (offset > 0) {
|
||||||
|
resend(weakEntry, done, resend);
|
||||||
|
} else {
|
||||||
|
done();
|
||||||
|
peer->owner().history(peer)->clearUnreadReactionsFor(rootId);
|
||||||
|
}
|
||||||
}).fail(done).send();
|
}).fail(done).send();
|
||||||
};
|
};
|
||||||
SetupReadAllMenu(button, currentPeer, text, sendRequest);
|
const auto sendRequest = [=](
|
||||||
|
not_null<Dialogs::Entry*> entry,
|
||||||
|
Fn<void()> done) {
|
||||||
|
sendOne(base::make_weak(entry.get()), std::move(done), sendOne);
|
||||||
|
};
|
||||||
|
SetupReadAllMenu(button, currentEntry, text, sendRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace SendMenu
|
} // namespace SendMenu
|
||||||
|
|
|
@ -16,6 +16,10 @@ class PopupMenu;
|
||||||
class RpWidget;
|
class RpWidget;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
|
namespace Dialogs {
|
||||||
|
class Entry;
|
||||||
|
} // namespace Dialogs
|
||||||
|
|
||||||
namespace SendMenu {
|
namespace SendMenu {
|
||||||
|
|
||||||
enum class Type {
|
enum class Type {
|
||||||
|
@ -51,11 +55,10 @@ void SetupMenuAndShortcuts(
|
||||||
|
|
||||||
void SetupUnreadMentionsMenu(
|
void SetupUnreadMentionsMenu(
|
||||||
not_null<Ui::RpWidget*> button,
|
not_null<Ui::RpWidget*> button,
|
||||||
Fn<PeerData*()> currentPeer,
|
Fn<Dialogs::Entry*()> currentEntry);
|
||||||
MsgId topicRootId);
|
|
||||||
|
|
||||||
void SetupUnreadReactionsMenu(
|
void SetupUnreadReactionsMenu(
|
||||||
not_null<Ui::RpWidget*> button,
|
not_null<Ui::RpWidget*> button,
|
||||||
Fn<PeerData*()> currentPeer);
|
Fn<Dialogs::Entry*()> currentEntry);
|
||||||
|
|
||||||
} // namespace SendMenu
|
} // namespace SendMenu
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 1b524981f0caf2dc2f21c004694f63025fe96a71
|
Subproject commit 44923c8b12bab26c707e8a7077ed82541a444f71
|
Loading…
Add table
Reference in a new issue