mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-15 21:57:10 +02:00
Support per-topic notification settings.
This commit is contained in:
parent
24843e3acd
commit
92a4b27e65
31 changed files with 713 additions and 293 deletions
|
@ -37,6 +37,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_photo.h"
|
||||
#include "data/data_web_page.h"
|
||||
#include "data/data_folder.h"
|
||||
#include "data/data_forum_topic.h"
|
||||
#include "data/data_media_types.h"
|
||||
#include "data/data_sparse_ids.h"
|
||||
#include "data/data_search_controller.h"
|
||||
|
@ -150,7 +151,7 @@ ApiWrap::ApiWrap(not_null<Main::Session*> session)
|
|||
, _dialogsLoadState(std::make_unique<DialogsLoadState>())
|
||||
, _fileLoader(std::make_unique<TaskQueue>(kFileLoaderQueueStopTimeout))
|
||||
, _topPromotionTimer([=] { refreshTopPromotion(); })
|
||||
, _updateNotifySettingsTimer([=] { sendNotifySettingsUpdates(); })
|
||||
, _updateNotifyTimer([=] { sendNotifySettingsUpdates(); })
|
||||
, _authorizations(std::make_unique<Api::Authorizations>(this))
|
||||
, _attachedStickers(std::make_unique<Api::AttachedStickers>(this))
|
||||
, _blockedPeers(std::make_unique<Api::BlockedPeers>(this))
|
||||
|
@ -1323,27 +1324,25 @@ void ApiWrap::deleteAllFromParticipantSend(
|
|||
|
||||
void ApiWrap::scheduleStickerSetRequest(uint64 setId, uint64 access) {
|
||||
if (!_stickerSetRequests.contains(setId)) {
|
||||
_stickerSetRequests.insert(setId, qMakePair(access, 0));
|
||||
_stickerSetRequests.emplace(setId, StickerSetRequest{ access });
|
||||
}
|
||||
}
|
||||
|
||||
void ApiWrap::requestStickerSets() {
|
||||
for (auto i = _stickerSetRequests.begin(), j = i, e = _stickerSetRequests.end(); i != e; i = j) {
|
||||
++j;
|
||||
if (i.value().second) continue;
|
||||
|
||||
auto waitMs = (j == e) ? 0 : kSmallDelayMs;
|
||||
const auto id = MTP_inputStickerSetID(
|
||||
MTP_long(i.key()),
|
||||
MTP_long(i.value().first));
|
||||
i.value().second = request(MTPmessages_GetStickerSet(
|
||||
id,
|
||||
for (auto &[id, info] : _stickerSetRequests) {
|
||||
if (info.id) {
|
||||
continue;
|
||||
}
|
||||
info.id = request(MTPmessages_GetStickerSet(
|
||||
MTP_inputStickerSetID(
|
||||
MTP_long(id),
|
||||
MTP_long(info.accessHash)),
|
||||
MTP_int(0) // hash
|
||||
)).done([=, setId = i.key()](const MTPmessages_StickerSet &result) {
|
||||
)).done([=, setId = id](const MTPmessages_StickerSet &result) {
|
||||
gotStickerSet(setId, result);
|
||||
}).fail([=, setId = i.key()] {
|
||||
}).fail([=, setId = id] {
|
||||
_stickerSetRequests.remove(setId);
|
||||
}).afterDelay(waitMs).send();
|
||||
}).afterDelay(kSmallDelayMs).send();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1671,7 +1670,7 @@ void ApiWrap::joinChannel(not_null<ChannelData*> channel) {
|
|||
_channelAmInRequests.remove(channel);
|
||||
}).send();
|
||||
|
||||
_channelAmInRequests.insert(channel, requestId);
|
||||
_channelAmInRequests.emplace(channel, requestId);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1690,44 +1689,48 @@ void ApiWrap::leaveChannel(not_null<ChannelData*> channel) {
|
|||
_channelAmInRequests.remove(channel);
|
||||
}).send();
|
||||
|
||||
_channelAmInRequests.insert(channel, requestId);
|
||||
_channelAmInRequests.emplace(channel, requestId);
|
||||
}
|
||||
}
|
||||
|
||||
void ApiWrap::requestNotifySettings(const MTPInputNotifyPeer &peer) {
|
||||
const auto key = [&] {
|
||||
switch (peer.type()) {
|
||||
case mtpc_inputNotifyUsers: return peerFromUser(0);
|
||||
case mtpc_inputNotifyChats: return peerFromChat(0);
|
||||
case mtpc_inputNotifyBroadcasts: return peerFromChannel(0);
|
||||
case mtpc_inputNotifyPeer: {
|
||||
const auto &inner = peer.c_inputNotifyPeer().vpeer();
|
||||
switch (inner.type()) {
|
||||
case mtpc_inputPeerSelf:
|
||||
return _session->userPeerId();
|
||||
case mtpc_inputPeerEmpty:
|
||||
return PeerId(0);
|
||||
case mtpc_inputPeerChannel:
|
||||
return peerFromChannel(
|
||||
inner.c_inputPeerChannel().vchannel_id());
|
||||
case mtpc_inputPeerChat:
|
||||
return peerFromChat(inner.c_inputPeerChat().vchat_id());
|
||||
case mtpc_inputPeerUser:
|
||||
return peerFromUser(inner.c_inputPeerUser().vuser_id());
|
||||
}
|
||||
const auto peerFromInput = [&](const MTPInputPeer &inputPeer) {
|
||||
return inputPeer.match([&](const MTPDinputPeerSelf &) {
|
||||
return _session->userPeerId();
|
||||
}, [](const MTPDinputPeerEmpty &) {
|
||||
return PeerId(0);
|
||||
}, [](const MTPDinputPeerChannel &data) {
|
||||
return peerFromChannel(data.vchannel_id());
|
||||
}, [](const MTPDinputPeerChat &data) {
|
||||
return peerFromChat(data.vchat_id());
|
||||
}, [](const MTPDinputPeerUser &data) {
|
||||
return peerFromUser(data.vuser_id());
|
||||
}, [](const auto &) -> PeerId {
|
||||
Unexpected("Type in ApiRequest::requestNotifySettings peer.");
|
||||
} break;
|
||||
}
|
||||
Unexpected("Type in ApiRequest::requestNotifySettings.");
|
||||
}();
|
||||
if (_notifySettingRequests.find(key) != end(_notifySettingRequests)) {
|
||||
});
|
||||
};
|
||||
const auto key = peer.match([](const MTPDinputNotifyUsers &) {
|
||||
return NotifySettingsKey{ peerFromUser(1) };
|
||||
}, [](const MTPDinputNotifyChats &) {
|
||||
return NotifySettingsKey{ peerFromChat(1) };
|
||||
}, [](const MTPDinputNotifyBroadcasts &) {
|
||||
return NotifySettingsKey{ peerFromChannel(1) };
|
||||
}, [&](const MTPDinputNotifyPeer &data) {
|
||||
return NotifySettingsKey{ peerFromInput(data.vpeer()) };
|
||||
}, [&](const MTPDinputNotifyForumTopic &data) {
|
||||
return NotifySettingsKey{
|
||||
peerFromInput(data.vpeer()),
|
||||
data.vtop_msg_id().v,
|
||||
};
|
||||
});
|
||||
if (_notifySettingRequests.contains(key)) {
|
||||
return;
|
||||
}
|
||||
const auto requestId = request(MTPaccount_GetNotifySettings(
|
||||
peer
|
||||
)).done([=](const MTPPeerNotifySettings &result) {
|
||||
applyNotifySettings(peer, result);
|
||||
_notifySettingRequests.erase(key);
|
||||
_notifySettingRequests.remove(key);
|
||||
}).fail([=] {
|
||||
applyNotifySettings(
|
||||
peer,
|
||||
|
@ -1741,34 +1744,50 @@ void ApiWrap::requestNotifySettings(const MTPInputNotifyPeer &peer) {
|
|||
MTPNotificationSound()));
|
||||
_notifySettingRequests.erase(key);
|
||||
}).send();
|
||||
|
||||
_notifySettingRequests.emplace(key, requestId);
|
||||
}
|
||||
|
||||
void ApiWrap::updateNotifySettingsDelayed(not_null<const PeerData*> peer) {
|
||||
_updateNotifySettingsPeers.emplace(peer);
|
||||
_updateNotifySettingsTimer.callOnce(kNotifySettingSaveTimeout);
|
||||
void ApiWrap::updateNotifySettingsDelayed(
|
||||
not_null<const Data::ForumTopic*> topic) {
|
||||
if (_updateNotifyTopics.emplace(topic).second) {
|
||||
topic->destroyed(
|
||||
) | rpl::start_with_next([=] {
|
||||
_updateNotifyTopics.remove(topic);
|
||||
}, _updateNotifyQueueLifetime);
|
||||
_updateNotifyTimer.callOnce(kNotifySettingSaveTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
void ApiWrap::updateDefaultNotifySettingsDelayed(Data::DefaultNotify type) {
|
||||
_updateNotifySettingsDefaults.emplace(type);
|
||||
_updateNotifySettingsTimer.callOnce(kNotifySettingSaveTimeout);
|
||||
void ApiWrap::updateNotifySettingsDelayed(not_null<const PeerData*> peer) {
|
||||
if (_updateNotifyPeers.emplace(peer).second) {
|
||||
_updateNotifyTimer.callOnce(kNotifySettingSaveTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
void ApiWrap::updateNotifySettingsDelayed(Data::DefaultNotify type) {
|
||||
if (_updateNotifyDefaults.emplace(type).second) {
|
||||
_updateNotifyTimer.callOnce(kNotifySettingSaveTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
void ApiWrap::sendNotifySettingsUpdates() {
|
||||
while (!_updateNotifySettingsPeers.empty()) {
|
||||
const auto peer = *_updateNotifySettingsPeers.begin();
|
||||
_updateNotifySettingsPeers.erase(_updateNotifySettingsPeers.begin());
|
||||
_updateNotifyQueueLifetime.destroy();
|
||||
for (const auto topic : base::take(_updateNotifyTopics)) {
|
||||
request(MTPaccount_UpdateNotifySettings(
|
||||
MTP_inputNotifyForumTopic(
|
||||
topic->channel()->input,
|
||||
MTP_int(topic->rootId())),
|
||||
topic->notify().serialize()
|
||||
)).afterDelay(kSmallDelayMs).send();
|
||||
}
|
||||
for (const auto peer : base::take(_updateNotifyPeers)) {
|
||||
request(MTPaccount_UpdateNotifySettings(
|
||||
MTP_inputNotifyPeer(peer->input),
|
||||
peer->notifySerialize()
|
||||
)).afterDelay(_updateNotifySettingsPeers.empty() ? 0 : 10).send();
|
||||
peer->notify().serialize()
|
||||
)).afterDelay(kSmallDelayMs).send();
|
||||
}
|
||||
const auto &settings = session().data().notifySettings();
|
||||
while (!_updateNotifySettingsDefaults.empty()) {
|
||||
const auto type = *_updateNotifySettingsDefaults.begin();
|
||||
_updateNotifySettingsDefaults.erase(
|
||||
_updateNotifySettingsDefaults.begin());
|
||||
for (const auto type : base::take(_updateNotifyDefaults)) {
|
||||
const auto input = [&] {
|
||||
switch (type) {
|
||||
case Data::DefaultNotify::User: return MTP_inputNotifyUsers();
|
||||
|
@ -1781,8 +1800,9 @@ void ApiWrap::sendNotifySettingsUpdates() {
|
|||
request(MTPaccount_UpdateNotifySettings(
|
||||
input,
|
||||
settings.defaultSettings(type).serialize()
|
||||
)).afterDelay(_updateNotifySettingsDefaults.empty() ? 0 : 10).send();
|
||||
)).afterDelay(kSmallDelayMs).send();
|
||||
}
|
||||
session().mtp().sendAnything();
|
||||
}
|
||||
|
||||
void ApiWrap::saveDraftToCloudDelayed(not_null<History*> history) {
|
||||
|
@ -2147,7 +2167,9 @@ void ApiWrap::applyNotifySettings(
|
|||
Core::App().notifications().checkDelayed();
|
||||
}
|
||||
|
||||
void ApiWrap::gotStickerSet(uint64 setId, const MTPmessages_StickerSet &result) {
|
||||
void ApiWrap::gotStickerSet(
|
||||
uint64 setId,
|
||||
const MTPmessages_StickerSet &result) {
|
||||
_stickerSetRequests.remove(setId);
|
||||
result.match([&](const MTPDmessages_stickerSet &data) {
|
||||
_session->data().stickers().feedSetFull(data);
|
||||
|
@ -2156,18 +2178,20 @@ void ApiWrap::gotStickerSet(uint64 setId, const MTPmessages_StickerSet &result)
|
|||
});
|
||||
}
|
||||
|
||||
void ApiWrap::requestWebPageDelayed(WebPageData *page) {
|
||||
if (page->pendingTill <= 0) return;
|
||||
_webPagesPending.insert(page, 0);
|
||||
void ApiWrap::requestWebPageDelayed(not_null<WebPageData*> page) {
|
||||
if (page->pendingTill <= 0) {
|
||||
return;
|
||||
}
|
||||
_webPagesPending.emplace(page, 0);
|
||||
auto left = (page->pendingTill - base::unixtime::now()) * 1000;
|
||||
if (!_webPagesTimer.isActive() || left <= _webPagesTimer.remainingTime()) {
|
||||
_webPagesTimer.callOnce((left < 0 ? 0 : left) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void ApiWrap::clearWebPageRequest(WebPageData *page) {
|
||||
void ApiWrap::clearWebPageRequest(not_null<WebPageData*> page) {
|
||||
_webPagesPending.remove(page);
|
||||
if (_webPagesPending.isEmpty() && _webPagesTimer.isActive()) {
|
||||
if (_webPagesPending.empty() && _webPagesTimer.isActive()) {
|
||||
_webPagesTimer.cancel();
|
||||
}
|
||||
}
|
||||
|
@ -2185,11 +2209,12 @@ void ApiWrap::resolveWebPages() {
|
|||
|
||||
ids.reserve(_webPagesPending.size());
|
||||
int32 t = base::unixtime::now(), m = INT_MAX;
|
||||
for (auto i = _webPagesPending.begin(); i != _webPagesPending.cend(); ++i) {
|
||||
if (i.value() > 0) continue;
|
||||
if (i.key()->pendingTill <= t) {
|
||||
const auto item = _session->data().findWebPageItem(i.key());
|
||||
if (item) {
|
||||
for (auto &[page, requestId] : _webPagesPending) {
|
||||
if (requestId > 0) {
|
||||
continue;
|
||||
}
|
||||
if (page->pendingTill <= t) {
|
||||
if (const auto item = _session->data().findWebPageItem(page)) {
|
||||
if (const auto channel = item->history()->peer->asChannel()) {
|
||||
auto channelMap = idsByChannel.find(channel);
|
||||
if (channelMap == idsByChannel.cend()) {
|
||||
|
@ -2204,14 +2229,14 @@ void ApiWrap::resolveWebPages() {
|
|||
channelMap->second.second.push_back(
|
||||
MTP_inputMessageID(MTP_int(item->id)));
|
||||
}
|
||||
i.value() = -channelMap->second.first - 2;
|
||||
requestId = -channelMap->second.first - 2;
|
||||
} else {
|
||||
ids.push_back(MTP_inputMessageID(MTP_int(item->id)));
|
||||
i.value() = -1;
|
||||
requestId = -1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
m = qMin(m, i.key()->pendingTill - t);
|
||||
m = std::min(m, page->pendingTill - t);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2237,9 +2262,10 @@ void ApiWrap::resolveWebPages() {
|
|||
}).afterDelay(kSmallDelayMs).send();
|
||||
}
|
||||
if (requestId || !reqsByIndex.isEmpty()) {
|
||||
for (auto &pendingRequestId : _webPagesPending) {
|
||||
if (pendingRequestId > 0) continue;
|
||||
if (pendingRequestId < 0) {
|
||||
for (auto &[page, pendingRequestId] : _webPagesPending) {
|
||||
if (pendingRequestId > 0) {
|
||||
continue;
|
||||
} else if (pendingRequestId < 0) {
|
||||
if (pendingRequestId == -1) {
|
||||
pendingRequestId = requestId;
|
||||
} else {
|
||||
|
@ -2248,9 +2274,8 @@ void ApiWrap::resolveWebPages() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m < INT_MAX) {
|
||||
_webPagesTimer.callOnce(m * 1000);
|
||||
_webPagesTimer.callOnce(std::min(m, 86400) * crl::time(1000));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2441,10 +2466,10 @@ void ApiWrap::refreshFileReference(
|
|||
void ApiWrap::gotWebPages(ChannelData *channel, const MTPmessages_Messages &result, mtpRequestId req) {
|
||||
WebPageData::ApplyChanges(_session, channel, result);
|
||||
for (auto i = _webPagesPending.begin(); i != _webPagesPending.cend();) {
|
||||
if (i.value() == req) {
|
||||
if (i.key()->pendingTill > 0) {
|
||||
i.key()->pendingTill = -1;
|
||||
_session->data().notifyWebPageUpdateDelayed(i.key());
|
||||
if (i->second == req) {
|
||||
if (i->first->pendingTill > 0) {
|
||||
i->first->pendingTill = -1;
|
||||
_session->data().notifyWebPageUpdateDelayed(i->first);
|
||||
}
|
||||
i = _webPagesPending.erase(i);
|
||||
} else {
|
||||
|
|
|
@ -32,6 +32,7 @@ class WallPaper;
|
|||
struct ResolvedForwardDraft;
|
||||
enum class DefaultNotify;
|
||||
enum class StickersType : uchar;
|
||||
class ForumTopic;
|
||||
} // namespace Data
|
||||
|
||||
namespace InlineBots {
|
||||
|
@ -219,8 +220,8 @@ public:
|
|||
not_null<ChannelData*> channel,
|
||||
not_null<PeerData*> from);
|
||||
|
||||
void requestWebPageDelayed(WebPageData *page);
|
||||
void clearWebPageRequest(WebPageData *page);
|
||||
void requestWebPageDelayed(not_null<WebPageData*> page);
|
||||
void clearWebPageRequest(not_null<WebPageData*> page);
|
||||
void clearWebPageRequests();
|
||||
|
||||
void scheduleStickerSetRequest(uint64 setId, uint64 access);
|
||||
|
@ -244,8 +245,10 @@ public:
|
|||
void leaveChannel(not_null<ChannelData*> channel);
|
||||
|
||||
void requestNotifySettings(const MTPInputNotifyPeer &peer);
|
||||
void updateNotifySettingsDelayed(
|
||||
not_null<const Data::ForumTopic*> topic);
|
||||
void updateNotifySettingsDelayed(not_null<const PeerData*> peer);
|
||||
void updateDefaultNotifySettingsDelayed(Data::DefaultNotify type);
|
||||
void updateNotifySettingsDelayed(Data::DefaultNotify type);
|
||||
void saveDraftToCloudDelayed(not_null<History*> history);
|
||||
|
||||
static int OnlineTillFromStatus(
|
||||
|
@ -523,7 +526,7 @@ private:
|
|||
not_null<ChannelData*> channel);
|
||||
void migrateFail(not_null<PeerData*> peer, const QString &error);
|
||||
|
||||
not_null<Main::Session*> _session;
|
||||
const not_null<Main::Session*> _session;
|
||||
|
||||
base::flat_map<QString, int> _modifyRequests;
|
||||
|
||||
|
@ -541,13 +544,29 @@ private:
|
|||
not_null<History*>,
|
||||
std::pair<mtpRequestId,Fn<void()>>> _historyArchivedRequests;
|
||||
|
||||
QMap<WebPageData*, mtpRequestId> _webPagesPending;
|
||||
base::flat_map<not_null<WebPageData*>, mtpRequestId> _webPagesPending;
|
||||
base::Timer _webPagesTimer;
|
||||
|
||||
QMap<uint64, QPair<uint64, mtpRequestId> > _stickerSetRequests;
|
||||
struct StickerSetRequest {
|
||||
uint64 accessHash = 0;
|
||||
mtpRequestId id = 0;
|
||||
};
|
||||
base::flat_map<uint64, StickerSetRequest> _stickerSetRequests;
|
||||
|
||||
base::flat_map<
|
||||
not_null<ChannelData*>,
|
||||
mtpRequestId> _channelAmInRequests;
|
||||
|
||||
struct NotifySettingsKey {
|
||||
PeerId peerId = 0;
|
||||
MsgId topicRootId = 0;
|
||||
|
||||
friend inline constexpr auto operator<=>(
|
||||
NotifySettingsKey,
|
||||
NotifySettingsKey) = default;
|
||||
};
|
||||
base::flat_map<NotifySettingsKey, mtpRequestId> _notifySettingRequests;
|
||||
|
||||
QMap<ChannelData*, mtpRequestId> _channelAmInRequests;
|
||||
base::flat_map<PeerId, mtpRequestId> _notifySettingRequests;
|
||||
base::flat_map<not_null<History*>, mtpRequestId> _draftsSaveRequestIds;
|
||||
base::Timer _draftsSaveTimer;
|
||||
|
||||
|
@ -610,9 +629,11 @@ private:
|
|||
TimeId _topPromotionNextRequestTime = TimeId(0);
|
||||
base::Timer _topPromotionTimer;
|
||||
|
||||
base::flat_set<not_null<const PeerData*>> _updateNotifySettingsPeers;
|
||||
base::flat_set<Data::DefaultNotify> _updateNotifySettingsDefaults;
|
||||
base::Timer _updateNotifySettingsTimer;
|
||||
base::flat_set<not_null<const Data::ForumTopic*>> _updateNotifyTopics;
|
||||
base::flat_set<not_null<const PeerData*>> _updateNotifyPeers;
|
||||
base::flat_set<Data::DefaultNotify> _updateNotifyDefaults;
|
||||
base::Timer _updateNotifyTimer;
|
||||
rpl::lifetime _updateNotifyQueueLifetime;
|
||||
|
||||
std::map<
|
||||
Data::FileOrigin,
|
||||
|
|
|
@ -148,8 +148,9 @@ struct TopicUpdate {
|
|||
UnreadView = (1U << 1),
|
||||
UnreadMentions = (1U << 2),
|
||||
UnreadReactions = (1U << 3),
|
||||
Notifications = (1U << 4),
|
||||
|
||||
LastUsedBit = (1U << 3),
|
||||
LastUsedBit = (1U << 4),
|
||||
};
|
||||
using Flags = base::flags<Flag>;
|
||||
friend inline constexpr auto is_flag_type(Flag) { return true; }
|
||||
|
|
|
@ -207,7 +207,7 @@ bool ChatFilter::contains(not_null<History*> history) const {
|
|||
return false
|
||||
|| ((_flags & flag)
|
||||
&& (!(_flags & Flag::NoMuted)
|
||||
|| !history->mute()
|
||||
|| !history->muted()
|
||||
|| (history->unreadMentions().has()
|
||||
&& history->folderKnown()
|
||||
&& !history->folder()))
|
||||
|
|
|
@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_forum.h"
|
||||
#include "data/data_histories.h"
|
||||
#include "data/data_replies_list.h"
|
||||
#include "data/notify/data_notify_settings.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/stickers/data_custom_emoji.h"
|
||||
#include "dialogs/dialogs_main_list.h"
|
||||
|
@ -141,7 +142,8 @@ ForumTopic::ForumTopic(not_null<History*> history, MsgId rootId)
|
|||
, _forum(history->peer->forum())
|
||||
, _list(_forum->topicsList())
|
||||
, _replies(std::make_shared<RepliesList>(history, rootId))
|
||||
, _rootId(rootId) {
|
||||
, _rootId(rootId)
|
||||
, _flags(owner().notifySettings().isMuted(this) ? Flag::Muted : Flag(0)) {
|
||||
_replies->unreadCountValue(
|
||||
) | rpl::combine_previous(
|
||||
) | rpl::filter([=] {
|
||||
|
@ -487,6 +489,32 @@ int ForumTopic::unreadCountForBadge() const {
|
|||
return (!result && unreadMark()) ? 1 : result;
|
||||
}
|
||||
|
||||
bool ForumTopic::muted() const {
|
||||
return (_flags & Flag::Muted);
|
||||
}
|
||||
|
||||
bool ForumTopic::changeMuted(bool muted) {
|
||||
if (this->muted() == muted) {
|
||||
return false;
|
||||
}
|
||||
const auto refresher = gsl::finally([&] {
|
||||
if (inChatList()) {
|
||||
updateChatListEntry();
|
||||
}
|
||||
session().changes().topicUpdated(
|
||||
this,
|
||||
Data::TopicUpdate::Flag::Notifications);
|
||||
});
|
||||
const auto notify = (unreadCountForBadge() > 0);
|
||||
const auto notifier = unreadStateChangeNotifier(notify);
|
||||
if (muted) {
|
||||
_flags |= Flag::Muted;
|
||||
} else {
|
||||
_flags &= ~Flag::Muted;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ForumTopic::unreadCountKnown() const {
|
||||
return _replies->unreadCountKnown();
|
||||
}
|
||||
|
@ -531,7 +559,7 @@ Dialogs::UnreadState ForumTopic::unreadStateFor(
|
|||
bool known) const {
|
||||
auto result = Dialogs::UnreadState();
|
||||
const auto mark = !count && unreadMark();
|
||||
const auto muted = history()->mute();
|
||||
const auto muted = this->muted();
|
||||
result.messages = count;
|
||||
result.messagesMuted = muted ? count : 0;
|
||||
result.chats = count ? 1 : 0;
|
||||
|
@ -547,7 +575,7 @@ bool ForumTopic::chatListUnreadMark() const {
|
|||
}
|
||||
|
||||
bool ForumTopic::chatListMutedBadge() const {
|
||||
return history()->mute();
|
||||
return muted();
|
||||
}
|
||||
|
||||
HistoryItem *ForumTopic::chatListMessage() const {
|
||||
|
|
|
@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
#include "dialogs/dialogs_entry.h"
|
||||
#include "dialogs/ui/dialogs_message_view.h"
|
||||
#include "data/notify/data_peer_notify_settings.h"
|
||||
#include "base/flags.h"
|
||||
|
||||
class ChannelData;
|
||||
|
@ -95,6 +96,13 @@ public:
|
|||
void applyItemAdded(not_null<HistoryItem*> item);
|
||||
void applyItemRemoved(MsgId id);
|
||||
|
||||
[[nodiscard]] Data::PeerNotifySettings ¬ify() {
|
||||
return _notify;
|
||||
}
|
||||
[[nodiscard]] const Data::PeerNotifySettings ¬ify() const {
|
||||
return _notify;
|
||||
}
|
||||
|
||||
void loadUserpic() override;
|
||||
void paintUserpic(
|
||||
Painter &p,
|
||||
|
@ -105,6 +113,8 @@ public:
|
|||
[[nodiscard]] bool unreadCountKnown() const;
|
||||
|
||||
[[nodiscard]] int unreadCountForBadge() const; // unreadCount || unreadMark ? 1 : 0.
|
||||
[[nodiscard]] bool muted() const;
|
||||
bool changeMuted(bool muted);
|
||||
|
||||
void setUnreadMark(bool unread);
|
||||
[[nodiscard]] bool unreadMark() const;
|
||||
|
@ -114,7 +124,8 @@ public:
|
|||
|
||||
private:
|
||||
enum class Flag : uchar {
|
||||
UnreadMark = 0x01,
|
||||
UnreadMark = (1 << 0),
|
||||
Muted = (1 << 1),
|
||||
};
|
||||
friend inline constexpr bool is_flag_type(Flag) { return true; }
|
||||
|
||||
|
@ -137,6 +148,8 @@ private:
|
|||
std::shared_ptr<RepliesList> _replies;
|
||||
MsgId _rootId = 0;
|
||||
|
||||
Data::PeerNotifySettings _notify;
|
||||
|
||||
QString _title;
|
||||
DocumentId _iconId = 0;
|
||||
base::flat_set<QString> _titleWords;
|
||||
|
@ -151,7 +164,7 @@ private:
|
|||
std::optional<HistoryItem*> _lastServerMessage;
|
||||
std::optional<HistoryItem*> _chatListMessage;
|
||||
base::flat_set<FullMsgId> _requestedGroups;
|
||||
base::flags<Flag> _flags;
|
||||
base::flags<Flag> _flags; // Initializer accesses _notify, be careful.
|
||||
|
||||
rpl::lifetime _lifetime;
|
||||
|
||||
|
|
|
@ -202,29 +202,11 @@ public:
|
|||
not_null<const HistoryItem*> item) const;
|
||||
[[nodiscard]] Data::ForumTopic *forumTopicFor(MsgId rootId) const;
|
||||
|
||||
[[nodiscard]] std::optional<TimeId> notifyMuteUntil() const {
|
||||
return _notify.muteUntil();
|
||||
[[nodiscard]] Data::PeerNotifySettings ¬ify() {
|
||||
return _notify;
|
||||
}
|
||||
bool notifyChange(const MTPPeerNotifySettings &settings) {
|
||||
return _notify.change(settings);
|
||||
}
|
||||
bool notifyChange(
|
||||
Data::MuteValue muteForSeconds,
|
||||
std::optional<bool> silentPosts,
|
||||
std::optional<Data::NotifySound> sound) {
|
||||
return _notify.change(muteForSeconds, silentPosts, sound);
|
||||
}
|
||||
[[nodiscard]] bool notifySettingsUnknown() const {
|
||||
return _notify.settingsUnknown();
|
||||
}
|
||||
[[nodiscard]] std::optional<bool> notifySilentPosts() const {
|
||||
return _notify.silentPosts();
|
||||
}
|
||||
[[nodiscard]] std::optional<Data::NotifySound> notifySound() const {
|
||||
return _notify.sound();
|
||||
}
|
||||
[[nodiscard]] MTPinputPeerNotifySettings notifySerialize() const {
|
||||
return _notify.serialize();
|
||||
[[nodiscard]] const Data::PeerNotifySettings ¬ify() const {
|
||||
return _notify;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool canWrite() const;
|
||||
|
|
|
@ -3892,7 +3892,9 @@ void Session::removeChatListEntry(Dialogs::Key key) {
|
|||
_contactsNoChatsList.addByName(key);
|
||||
}
|
||||
}
|
||||
if (const auto history = key.history()) {
|
||||
if (const auto topic = key.topic()) {
|
||||
Core::App().notifications().clearFromTopic(topic);
|
||||
} else if (const auto history = key.history()) {
|
||||
Core::App().notifications().clearFromHistory(history);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_document.h"
|
||||
#include "data/data_file_origin.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "data/data_forum_topic.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_user.h"
|
||||
#include "main/main_session.h"
|
||||
|
@ -25,11 +26,21 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "window/notifications_manager.h"
|
||||
|
||||
namespace Data {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr auto kMaxNotifyCheckDelay = 24 * 3600 * crl::time(1000);
|
||||
|
||||
[[nodiscard]] bool MutedFromUntil(TimeId until, crl::time *changesIn) {
|
||||
const auto now = base::unixtime::now();
|
||||
const auto result = (until > now) ? (until - now) : 0;
|
||||
if (changesIn) {
|
||||
*changesIn = (result > 0)
|
||||
? std::min(result * crl::time(1000), kMaxNotifyCheckDelay)
|
||||
: kMaxNotifyCheckDelay;
|
||||
}
|
||||
return (result > 0);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
NotifySettings::NotifySettings(not_null<Session*> owner)
|
||||
|
@ -38,7 +49,7 @@ NotifySettings::NotifySettings(not_null<Session*> owner)
|
|||
}
|
||||
|
||||
void NotifySettings::request(not_null<PeerData*> peer) {
|
||||
if (peer->notifySettingsUnknown()) {
|
||||
if (peer->notify().settingsUnknown()) {
|
||||
peer->session().api().requestNotifySettings(
|
||||
MTP_inputNotifyPeer(peer->input));
|
||||
}
|
||||
|
@ -51,6 +62,16 @@ void NotifySettings::request(not_null<PeerData*> peer) {
|
|||
}
|
||||
}
|
||||
|
||||
void NotifySettings::request(not_null<Data::ForumTopic*> topic) {
|
||||
if (topic->notify().settingsUnknown()) {
|
||||
topic->session().api().requestNotifySettings(
|
||||
MTP_inputNotifyForumTopic(
|
||||
topic->channel()->input,
|
||||
MTP_int(topic->rootId())));
|
||||
}
|
||||
request(topic->channel());
|
||||
}
|
||||
|
||||
void NotifySettings::apply(
|
||||
const MTPNotifyPeer ¬ifyPeer,
|
||||
const MTPPeerNotifySettings &settings) {
|
||||
|
@ -66,7 +87,7 @@ void NotifySettings::apply(
|
|||
case mtpc_notifyPeer: {
|
||||
const auto &data = notifyPeer.c_notifyPeer();
|
||||
if (const auto peer = _owner->peerLoaded(peerFromMTP(data.vpeer()))) {
|
||||
if (peer->notifyChange(settings)) {
|
||||
if (peer->notify().change(settings)) {
|
||||
updateLocal(peer);
|
||||
}
|
||||
}
|
||||
|
@ -74,12 +95,37 @@ void NotifySettings::apply(
|
|||
}
|
||||
}
|
||||
|
||||
void NotifySettings::update(
|
||||
not_null<Data::ForumTopic*> topic,
|
||||
Data::MuteValue muteForSeconds,
|
||||
std::optional<NotifySound> sound) {
|
||||
if (topic->notify().change(muteForSeconds, std::nullopt, sound)) {
|
||||
updateLocal(topic);
|
||||
topic->session().api().updateNotifySettingsDelayed(topic);
|
||||
}
|
||||
}
|
||||
|
||||
void NotifySettings::resetToDefault(not_null<Data::ForumTopic*> topic) {
|
||||
const auto empty = MTP_peerNotifySettings(
|
||||
MTP_flags(0),
|
||||
MTPBool(),
|
||||
MTPBool(),
|
||||
MTPint(),
|
||||
MTPNotificationSound(),
|
||||
MTPNotificationSound(),
|
||||
MTPNotificationSound());
|
||||
if (topic->notify().change(empty)) {
|
||||
updateLocal(topic);
|
||||
topic->session().api().updateNotifySettingsDelayed(topic);
|
||||
}
|
||||
}
|
||||
|
||||
void NotifySettings::update(
|
||||
not_null<PeerData*> peer,
|
||||
Data::MuteValue muteForSeconds,
|
||||
std::optional<bool> silentPosts,
|
||||
std::optional<NotifySound> sound) {
|
||||
if (peer->notifyChange(muteForSeconds, silentPosts, sound)) {
|
||||
if (peer->notify().change(muteForSeconds, silentPosts, sound)) {
|
||||
updateLocal(peer);
|
||||
peer->session().api().updateNotifySettingsDelayed(peer);
|
||||
}
|
||||
|
@ -94,7 +140,7 @@ void NotifySettings::resetToDefault(not_null<PeerData*> peer) {
|
|||
MTPNotificationSound(),
|
||||
MTPNotificationSound(),
|
||||
MTPNotificationSound());
|
||||
if (peer->notifyChange(empty)) {
|
||||
if (peer->notify().change(empty)) {
|
||||
updateLocal(peer);
|
||||
peer->session().api().updateNotifySettingsDelayed(peer);
|
||||
}
|
||||
|
@ -136,15 +182,34 @@ void NotifySettings::defaultUpdate(
|
|||
auto &settings = defaultValue(type).settings;
|
||||
if (settings.change(muteForSeconds, silentPosts, sound)) {
|
||||
updateLocal(type);
|
||||
_owner->session().api().updateDefaultNotifySettingsDelayed(type);
|
||||
_owner->session().api().updateNotifySettingsDelayed(type);
|
||||
}
|
||||
}
|
||||
|
||||
void NotifySettings::updateLocal(not_null<Data::ForumTopic*> topic) {
|
||||
auto changesIn = crl::time(0);
|
||||
const auto muted = isMuted(topic, &changesIn);
|
||||
topic->changeMuted(muted);
|
||||
if (muted) {
|
||||
auto &lifetime = _mutedTopics.emplace(
|
||||
topic,
|
||||
rpl::lifetime()).first->second;
|
||||
topic->destroyed() | rpl::start_with_next([=] {
|
||||
_mutedTopics.erase(topic);
|
||||
}, lifetime);
|
||||
unmuteByFinishedDelayed(changesIn);
|
||||
Core::App().notifications().clearIncomingFromTopic(topic);
|
||||
} else {
|
||||
_mutedTopics.erase(topic);
|
||||
}
|
||||
cacheSound(topic->notify().sound());
|
||||
}
|
||||
|
||||
void NotifySettings::updateLocal(not_null<PeerData*> peer) {
|
||||
const auto history = _owner->historyLoaded(peer->id);
|
||||
auto changesIn = crl::time(0);
|
||||
const auto muted = isMuted(peer, &changesIn);
|
||||
if (history && history->changeMute(muted)) {
|
||||
if (history && history->changeMuted(muted)) {
|
||||
// Notification already sent.
|
||||
} else {
|
||||
peer->session().changes().peerUpdated(
|
||||
|
@ -161,7 +226,7 @@ void NotifySettings::updateLocal(not_null<PeerData*> peer) {
|
|||
} else {
|
||||
_mutedPeers.erase(peer);
|
||||
}
|
||||
cacheSound(peer->notifySound());
|
||||
cacheSound(peer->notify().sound());
|
||||
}
|
||||
|
||||
void NotifySettings::cacheSound(DocumentId id) {
|
||||
|
@ -206,10 +271,11 @@ void NotifySettings::updateLocal(DefaultNotify type) {
|
|||
const auto goodForUpdate = [&](
|
||||
not_null<const PeerData*> peer,
|
||||
const PeerNotifySettings &settings) {
|
||||
return !peer->notifySettingsUnknown()
|
||||
&& ((!peer->notifyMuteUntil() && settings.muteUntil())
|
||||
|| (!peer->notifySilentPosts() && settings.silentPosts())
|
||||
|| (!peer->notifySound() && settings.sound()));
|
||||
auto &peers = peer->notify();
|
||||
return !peers.settingsUnknown()
|
||||
&& ((!peers.muteUntil() && settings.muteUntil())
|
||||
|| (!peers.silentPosts() && settings.silentPosts())
|
||||
|| (!peers.sound() && settings.sound()));
|
||||
};
|
||||
|
||||
const auto callback = [&](not_null<PeerData*> peer) {
|
||||
|
@ -252,7 +318,7 @@ void NotifySettings::unmuteByFinished() {
|
|||
const auto muted = isMuted(*i, &changesIn);
|
||||
if (muted) {
|
||||
if (history) {
|
||||
history->changeMute(true);
|
||||
history->changeMuted(true);
|
||||
}
|
||||
if (!changesInMin || changesInMin > changesIn) {
|
||||
changesInMin = changesIn;
|
||||
|
@ -260,35 +326,71 @@ void NotifySettings::unmuteByFinished() {
|
|||
++i;
|
||||
} else {
|
||||
if (history) {
|
||||
history->changeMute(false);
|
||||
history->changeMuted(false);
|
||||
}
|
||||
i = _mutedPeers.erase(i);
|
||||
}
|
||||
}
|
||||
for (auto i = begin(_mutedTopics); i != end(_mutedTopics);) {
|
||||
auto changesIn = crl::time(0);
|
||||
const auto topic = i->first;
|
||||
const auto muted = isMuted(topic, &changesIn);
|
||||
if (muted) {
|
||||
topic->changeMuted(true);
|
||||
if (!changesInMin || changesInMin > changesIn) {
|
||||
changesInMin = changesIn;
|
||||
}
|
||||
++i;
|
||||
} else {
|
||||
topic->changeMuted(false);
|
||||
i = _mutedTopics.erase(i);
|
||||
}
|
||||
}
|
||||
if (changesInMin) {
|
||||
unmuteByFinishedDelayed(changesInMin);
|
||||
}
|
||||
}
|
||||
|
||||
bool NotifySettings::isMuted(
|
||||
not_null<const Data::ForumTopic*> topic,
|
||||
crl::time *changesIn) const {
|
||||
const auto until = topic->notify().muteUntil();
|
||||
return until
|
||||
? MutedFromUntil(*until, changesIn)
|
||||
: isMuted(topic->channel(), changesIn);
|
||||
}
|
||||
|
||||
bool NotifySettings::isMuted(not_null<const Data::ForumTopic*> topic) const {
|
||||
return isMuted(topic, nullptr);
|
||||
}
|
||||
|
||||
NotifySound NotifySettings::sound(
|
||||
not_null<const Data::ForumTopic*> topic) const {
|
||||
const auto sound = topic->notify().sound();
|
||||
return sound ? *sound : this->sound(topic->channel());
|
||||
}
|
||||
|
||||
bool NotifySettings::muteUnknown(
|
||||
not_null<const Data::ForumTopic*> topic) const {
|
||||
return topic->notify().settingsUnknown()
|
||||
|| (!topic->notify().muteUntil().has_value()
|
||||
&& muteUnknown(topic->channel()));
|
||||
}
|
||||
|
||||
bool NotifySettings::soundUnknown(
|
||||
not_null<const Data::ForumTopic*> topic) const {
|
||||
return topic->notify().settingsUnknown()
|
||||
|| (!topic->notify().sound().has_value()
|
||||
&& soundUnknown(topic->channel()));
|
||||
}
|
||||
|
||||
bool NotifySettings::isMuted(
|
||||
not_null<const PeerData*> peer,
|
||||
crl::time *changesIn) const {
|
||||
const auto resultFromUntil = [&](TimeId until) {
|
||||
const auto now = base::unixtime::now();
|
||||
const auto result = (until > now) ? (until - now) : 0;
|
||||
if (changesIn) {
|
||||
*changesIn = (result > 0)
|
||||
? std::min(result * crl::time(1000), kMaxNotifyCheckDelay)
|
||||
: kMaxNotifyCheckDelay;
|
||||
}
|
||||
return (result > 0);
|
||||
};
|
||||
if (const auto until = peer->notifyMuteUntil()) {
|
||||
return resultFromUntil(*until);
|
||||
}
|
||||
const auto &settings = defaultSettings(peer);
|
||||
if (const auto until = settings.muteUntil()) {
|
||||
return resultFromUntil(*until);
|
||||
if (const auto until = peer->notify().muteUntil()) {
|
||||
return MutedFromUntil(*until, changesIn);
|
||||
} else if (const auto until = defaultSettings(peer).muteUntil()) {
|
||||
return MutedFromUntil(*until, changesIn);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -298,54 +400,41 @@ bool NotifySettings::isMuted(not_null<const PeerData*> peer) const {
|
|||
}
|
||||
|
||||
bool NotifySettings::silentPosts(not_null<const PeerData*> peer) const {
|
||||
if (const auto silent = peer->notifySilentPosts()) {
|
||||
if (const auto silent = peer->notify().silentPosts()) {
|
||||
return *silent;
|
||||
}
|
||||
const auto &settings = defaultSettings(peer);
|
||||
if (const auto silent = settings.silentPosts()) {
|
||||
} else if (const auto silent = defaultSettings(peer).silentPosts()) {
|
||||
return *silent;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
NotifySound NotifySettings::sound(not_null<const PeerData*> peer) const {
|
||||
if (const auto sound = peer->notifySound()) {
|
||||
if (const auto sound = peer->notify().sound()) {
|
||||
return *sound;
|
||||
}
|
||||
const auto &settings = defaultSettings(peer);
|
||||
if (const auto sound = settings.sound()) {
|
||||
} else if (const auto sound = defaultSettings(peer).sound()) {
|
||||
return *sound;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
bool NotifySettings::muteUnknown(not_null<const PeerData*> peer) const {
|
||||
if (peer->notifySettingsUnknown()) {
|
||||
return true;
|
||||
} else if (const auto nonDefault = peer->notifyMuteUntil()) {
|
||||
return false;
|
||||
}
|
||||
return defaultSettings(peer).settingsUnknown();
|
||||
return peer->notify().settingsUnknown()
|
||||
|| (!peer->notify().muteUntil().has_value()
|
||||
&& defaultSettings(peer).settingsUnknown());
|
||||
}
|
||||
|
||||
bool NotifySettings::silentPostsUnknown(
|
||||
not_null<const PeerData*> peer) const {
|
||||
if (peer->notifySettingsUnknown()) {
|
||||
return true;
|
||||
} else if (const auto nonDefault = peer->notifySilentPosts()) {
|
||||
return false;
|
||||
}
|
||||
return defaultSettings(peer).settingsUnknown();
|
||||
return peer->notify().settingsUnknown()
|
||||
|| (!peer->notify().silentPosts().has_value()
|
||||
&& defaultSettings(peer).settingsUnknown());
|
||||
}
|
||||
|
||||
bool NotifySettings::soundUnknown(
|
||||
not_null<const PeerData*> peer) const {
|
||||
if (peer->notifySettingsUnknown()) {
|
||||
return true;
|
||||
} else if (const auto nonDefault = peer->notifySound()) {
|
||||
return false;
|
||||
}
|
||||
return defaultSettings(peer).settingsUnknown();
|
||||
return peer->notify().settingsUnknown()
|
||||
|| (!peer->notify().sound().has_value()
|
||||
&& defaultSettings(peer).settingsUnknown());
|
||||
}
|
||||
|
||||
bool NotifySettings::settingsUnknown(not_null<const PeerData*> peer) const {
|
||||
|
@ -354,6 +443,11 @@ bool NotifySettings::settingsUnknown(not_null<const PeerData*> peer) const {
|
|||
|| soundUnknown(peer);
|
||||
}
|
||||
|
||||
bool NotifySettings::settingsUnknown(
|
||||
not_null<const Data::ForumTopic*> topic) const {
|
||||
return muteUnknown(topic) || soundUnknown(topic);
|
||||
}
|
||||
|
||||
rpl::producer<> NotifySettings::defaultUpdates(DefaultNotify type) const {
|
||||
return defaultValue(type).updates.events();
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ namespace Data {
|
|||
|
||||
class DocumentMedia;
|
||||
class Session;
|
||||
class ForumTopic;
|
||||
|
||||
enum class DefaultNotify {
|
||||
User,
|
||||
|
@ -29,9 +30,15 @@ public:
|
|||
NotifySettings(not_null<Session*> owner);
|
||||
|
||||
void request(not_null<PeerData*> peer);
|
||||
void request(not_null<Data::ForumTopic*> topic);
|
||||
void apply(
|
||||
const MTPNotifyPeer ¬ifyPeer,
|
||||
const MTPPeerNotifySettings &settings);
|
||||
void update(
|
||||
not_null<Data::ForumTopic*> topic,
|
||||
Data::MuteValue muteForSeconds,
|
||||
std::optional<NotifySound> sound = std::nullopt);
|
||||
void resetToDefault(not_null<Data::ForumTopic*> topic);
|
||||
void update(
|
||||
not_null<PeerData*> peer,
|
||||
Data::MuteValue muteForSeconds,
|
||||
|
@ -57,6 +64,15 @@ public:
|
|||
std::optional<bool> silentPosts = std::nullopt,
|
||||
std::optional<NotifySound> sound = std::nullopt);
|
||||
|
||||
[[nodiscard]] bool isMuted(
|
||||
not_null<const Data::ForumTopic*> topic) const;
|
||||
[[nodiscard]] NotifySound sound(
|
||||
not_null<const Data::ForumTopic*> topic) const;
|
||||
[[nodiscard]] bool muteUnknown(
|
||||
not_null<const Data::ForumTopic*> topic) const;
|
||||
[[nodiscard]] bool soundUnknown(
|
||||
not_null<const Data::ForumTopic*> topic) const;
|
||||
|
||||
[[nodiscard]] bool isMuted(not_null<const PeerData*> peer) const;
|
||||
[[nodiscard]] bool silentPosts(not_null<const PeerData*> peer) const;
|
||||
[[nodiscard]] NotifySound sound(not_null<const PeerData*> peer) const;
|
||||
|
@ -73,6 +89,9 @@ private:
|
|||
|
||||
void cacheSound(const std::optional<NotifySound> &sound);
|
||||
|
||||
[[nodiscard]] bool isMuted(
|
||||
not_null<const Data::ForumTopic*> peer,
|
||||
crl::time *changesIn) const;
|
||||
[[nodiscard]] bool isMuted(
|
||||
not_null<const PeerData*> peer,
|
||||
crl::time *changesIn) const;
|
||||
|
@ -82,9 +101,12 @@ private:
|
|||
[[nodiscard]] const PeerNotifySettings &defaultSettings(
|
||||
not_null<const PeerData*> peer) const;
|
||||
[[nodiscard]] bool settingsUnknown(not_null<const PeerData*> peer) const;
|
||||
[[nodiscard]] bool settingsUnknown(
|
||||
not_null<const Data::ForumTopic*> topic) const;
|
||||
|
||||
void unmuteByFinished();
|
||||
void unmuteByFinishedDelayed(crl::time delay);
|
||||
void updateLocal(not_null<Data::ForumTopic*> topic);
|
||||
void updateLocal(not_null<PeerData*> peer);
|
||||
void updateLocal(DefaultNotify type);
|
||||
|
||||
|
@ -92,6 +114,9 @@ private:
|
|||
|
||||
DefaultValue _defaultValues[3];
|
||||
std::unordered_set<not_null<const PeerData*>> _mutedPeers;
|
||||
std::unordered_map<
|
||||
not_null<Data::ForumTopic*>,
|
||||
rpl::lifetime> _mutedTopics;
|
||||
base::Timer _unmuteByFinishedTimer;
|
||||
|
||||
struct {
|
||||
|
|
|
@ -74,7 +74,7 @@ History::History(not_null<Data::Session*> owner, PeerId peerId)
|
|||
, peer(owner->peer(peerId))
|
||||
, cloudDraftTextCache(st::dialogsTextWidthMin)
|
||||
, _delegateMixin(HistoryInner::DelegateMixin())
|
||||
, _mute(owner->notifySettings().isMuted(peer))
|
||||
, _flags(owner->notifySettings().isMuted(peer) ? Flag::Muted : Flag(0))
|
||||
, _chatListNameSortKey(owner->nameSortKey(peer->name()))
|
||||
, _sendActionPainter(this) {
|
||||
if (const auto user = peer->asUser()) {
|
||||
|
@ -1768,12 +1768,12 @@ void History::setFakeUnreadWhileOpened(bool enabled) {
|
|||
return _fakeUnreadWhileOpened;
|
||||
}
|
||||
|
||||
bool History::mute() const {
|
||||
return _mute;
|
||||
bool History::muted() const {
|
||||
return (_flags & Flag::Muted);
|
||||
}
|
||||
|
||||
bool History::changeMute(bool newMute) {
|
||||
if (_mute == newMute) {
|
||||
bool History::changeMuted(bool muted) {
|
||||
if (this->muted() == muted) {
|
||||
return false;
|
||||
}
|
||||
const auto refresher = gsl::finally([&] {
|
||||
|
@ -1787,7 +1787,11 @@ bool History::changeMute(bool newMute) {
|
|||
});
|
||||
const auto notify = (unreadCountForBadge() > 0);
|
||||
const auto notifier = unreadStateChangeNotifier(notify);
|
||||
_mute = newMute;
|
||||
if (muted) {
|
||||
_flags |= Flag::Muted;
|
||||
} else {
|
||||
_flags &= ~Flag::Muted;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2072,14 +2076,14 @@ bool History::chatListUnreadMark() const {
|
|||
}
|
||||
|
||||
bool History::chatListMutedBadge() const {
|
||||
return mute();
|
||||
return muted();
|
||||
}
|
||||
|
||||
Dialogs::UnreadState History::chatListUnreadState() const {
|
||||
auto result = Dialogs::UnreadState();
|
||||
const auto count = _unreadCount.value_or(0);
|
||||
const auto mark = !count && _unreadMark;
|
||||
const auto muted = mute();
|
||||
const auto muted = this->muted();
|
||||
result.messages = count;
|
||||
result.messagesMuted = muted ? count : 0;
|
||||
result.chats = count ? 1 : 0;
|
||||
|
|
|
@ -262,8 +262,8 @@ public:
|
|||
void setFakeUnreadWhileOpened(bool enabled);
|
||||
[[nodiscard]] bool fakeUnreadWhileOpened() const;
|
||||
[[nodiscard]] int unreadCountForBadge() const; // unreadCount || unreadMark ? 1 : 0.
|
||||
[[nodiscard]] bool mute() const;
|
||||
bool changeMute(bool newMute);
|
||||
[[nodiscard]] bool muted() const;
|
||||
bool changeMuted(bool muted);
|
||||
void addUnreadBar();
|
||||
void destroyUnreadBar();
|
||||
[[nodiscard]] Element *unreadBar() const;
|
||||
|
@ -472,6 +472,7 @@ private:
|
|||
|
||||
enum class Flag : uchar {
|
||||
HasPendingResizedItems = (1 << 0),
|
||||
Muted = (1 << 1),
|
||||
};
|
||||
using Flags = base::flags<Flag>;
|
||||
friend inline constexpr auto is_flag_type(Flag) {
|
||||
|
@ -588,7 +589,6 @@ private:
|
|||
const std::unique_ptr<HistoryMainElementDelegateMixin> _delegateMixin;
|
||||
|
||||
Flags _flags = 0;
|
||||
bool _mute = false;
|
||||
int _width = 0;
|
||||
int _height = 0;
|
||||
Element *_unreadBarView = nullptr;
|
||||
|
|
|
@ -2448,7 +2448,7 @@ void HistoryWidget::updateNotifyControls() {
|
|||
return;
|
||||
}
|
||||
|
||||
_muteUnmute->setText((_history->mute()
|
||||
_muteUnmute->setText((_history->muted()
|
||||
? tr::lng_channel_unmute(tr::now)
|
||||
: tr::lng_channel_mute(tr::now)).toUpper());
|
||||
if (!session().data().notifySettings().silentPostsUnknown(_peer)) {
|
||||
|
@ -3797,7 +3797,7 @@ void HistoryWidget::joinChannel() {
|
|||
}
|
||||
|
||||
void HistoryWidget::toggleMuteUnmute() {
|
||||
const auto wasMuted = !!_history->mute();
|
||||
const auto wasMuted = _history->muted();
|
||||
const auto muteForSeconds = Data::MuteValue{
|
||||
.unmute = wasMuted,
|
||||
.forever = !wasMuted,
|
||||
|
|
|
@ -53,6 +53,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "base/call_delayed.h"
|
||||
#include "base/qt/qt_key_modifiers.h"
|
||||
#include "core/file_utilities.h"
|
||||
#include "core/application.h"
|
||||
#include "main/main_session.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_user.h"
|
||||
|
@ -69,6 +70,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "inline_bots/inline_bot_result.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "facades.h"
|
||||
#include "window/notifications_manager.h"
|
||||
#include "styles/style_chat.h"
|
||||
#include "styles/style_window.h"
|
||||
#include "styles/style_info.h"
|
||||
|
@ -1954,6 +1956,9 @@ void RepliesWidget::readTill(not_null<HistoryItem*> item) {
|
|||
_readRequestTimer.callOnce(0);
|
||||
}
|
||||
}
|
||||
if (_topic) {
|
||||
Core::App().notifications().clearIncomingFromTopic(_topic);
|
||||
}
|
||||
}
|
||||
|
||||
void RepliesWidget::listMarkReadTill(not_null<HistoryItem*> item) {
|
||||
|
|
|
@ -320,7 +320,7 @@ private:
|
|||
};
|
||||
|
||||
|
||||
class RepliesMemento : public Window::SectionMemento {
|
||||
class RepliesMemento final : public Window::SectionMemento {
|
||||
public:
|
||||
RepliesMemento(
|
||||
not_null<History*> history,
|
||||
|
|
|
@ -180,6 +180,23 @@ rpl::producer<const ChannelLocation*> LocationValue(
|
|||
});
|
||||
}
|
||||
|
||||
rpl::producer<bool> NotificationsEnabledValue(
|
||||
not_null<Data::ForumTopic*> topic) {
|
||||
return rpl::merge(
|
||||
topic->session().changes().topicFlagsValue(
|
||||
topic,
|
||||
Data::TopicUpdate::Flag::Notifications
|
||||
) | rpl::to_empty,
|
||||
topic->session().changes().peerUpdates(
|
||||
topic->channel(),
|
||||
UpdateFlag::Notifications
|
||||
) | rpl::to_empty,
|
||||
topic->owner().notifySettings().defaultUpdates(topic->channel())
|
||||
) | rpl::map([=] {
|
||||
return !topic->owner().notifySettings().isMuted(topic);
|
||||
}) | rpl::distinct_until_changed();
|
||||
}
|
||||
|
||||
rpl::producer<bool> NotificationsEnabledValue(not_null<PeerData*> peer) {
|
||||
return rpl::merge(
|
||||
peer->session().changes().peerFlagsValue(
|
||||
|
|
|
@ -62,6 +62,8 @@ rpl::producer<not_null<PeerData*>> MigratedOrMeValue(
|
|||
not_null<ChannelData*> channel);
|
||||
[[nodiscard]] rpl::producer<bool> NotificationsEnabledValue(
|
||||
not_null<PeerData*> peer);
|
||||
[[nodiscard]] rpl::producer<bool> NotificationsEnabledValue(
|
||||
not_null<Data::ForumTopic*> topic);
|
||||
[[nodiscard]] rpl::producer<bool> IsContactValue(not_null<UserData*> user);
|
||||
[[nodiscard]] rpl::producer<QString> InviteToChatButton(
|
||||
not_null<UserData*> user);
|
||||
|
|
|
@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "base/platform/linux/base_linux_dbus_utilities.h"
|
||||
#include "core/application.h"
|
||||
#include "core/core_settings.h"
|
||||
#include "data/data_forum_topic.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_item.h"
|
||||
#include "main/main_session.h"
|
||||
|
@ -794,11 +795,12 @@ public:
|
|||
DisplayOptions options);
|
||||
void clearAll();
|
||||
void clearFromItem(not_null<HistoryItem*> item);
|
||||
void clearFromTopic(not_null<Data::ForumTopic*> topic);
|
||||
void clearFromHistory(not_null<History*> history);
|
||||
void clearFromSession(not_null<Main::Session*> session);
|
||||
void clearNotification(NotificationId id);
|
||||
|
||||
bool inhibited() {
|
||||
[[nodiscard]] bool inhibited() const {
|
||||
return _inhibited;
|
||||
}
|
||||
|
||||
|
@ -808,7 +810,7 @@ private:
|
|||
const not_null<Manager*> _manager;
|
||||
|
||||
base::flat_map<
|
||||
FullPeer,
|
||||
ContextId,
|
||||
base::flat_map<MsgId, Notification>> _notifications;
|
||||
|
||||
Window::Notifications::CachedUserpics _cachedUserpics;
|
||||
|
@ -892,17 +894,22 @@ Manager::Private::Private(not_null<Manager*> manager, Type type)
|
|||
|
||||
void Manager::Private::showNotification(
|
||||
not_null<PeerData*> peer,
|
||||
MsgId topicRootId,
|
||||
std::shared_ptr<Data::CloudImageView> &userpicView,
|
||||
MsgId msgId,
|
||||
const QString &title,
|
||||
const QString &subtitle,
|
||||
const QString &msg,
|
||||
DisplayOptions options) {
|
||||
const auto key = FullPeer{
|
||||
const auto key = ContextId{
|
||||
.sessionId = peer->session().uniqueId(),
|
||||
.peerId = peer->id
|
||||
.peerId = peer->id,
|
||||
.topicRootId = topicRootId,
|
||||
};
|
||||
const auto notificationId = NotificationId{
|
||||
.contextId = key,
|
||||
.msgId = msgId,
|
||||
};
|
||||
const auto notificationId = NotificationId{ .full = key, .msgId = msgId };
|
||||
auto notification = std::make_unique<NotificationData>(
|
||||
_manager,
|
||||
notificationId);
|
||||
|
@ -951,9 +958,10 @@ void Manager::Private::clearAll() {
|
|||
}
|
||||
|
||||
void Manager::Private::clearFromItem(not_null<HistoryItem*> item) {
|
||||
const auto key = FullPeer{
|
||||
const auto key = ContextId{
|
||||
.sessionId = item->history()->session().uniqueId(),
|
||||
.peerId = item->history()->peer->id
|
||||
.peerId = item->history()->peer->id,
|
||||
.topicRootId = item->topicRootId(),
|
||||
};
|
||||
const auto i = _notifications.find(key);
|
||||
if (i == _notifications.cend()) {
|
||||
|
@ -971,10 +979,10 @@ void Manager::Private::clearFromItem(not_null<HistoryItem*> item) {
|
|||
taken->close();
|
||||
}
|
||||
|
||||
void Manager::Private::clearFromHistory(not_null<History*> history) {
|
||||
const auto key = FullPeer{
|
||||
.sessionId = history->session().uniqueId(),
|
||||
.peerId = history->peer->id
|
||||
void Manager::Private::clearFromTopic(not_null<Data::ForumTopic*> topic) {
|
||||
const auto key = ContextId{
|
||||
.sessionId = topic->session().uniqueId(),
|
||||
.peerId = topic->history()->peer->id
|
||||
};
|
||||
const auto i = _notifications.find(key);
|
||||
if (i != _notifications.cend()) {
|
||||
|
@ -987,13 +995,31 @@ void Manager::Private::clearFromHistory(not_null<History*> history) {
|
|||
}
|
||||
}
|
||||
|
||||
void Manager::Private::clearFromHistory(not_null<History*> history) {
|
||||
const auto sessionId = history->session().uniqueId();
|
||||
const auto peerId = history->peer->id;
|
||||
auto i = _notifications.lower_bound(ContextId{
|
||||
.sessionId = sessionId,
|
||||
.peerId = peerId,
|
||||
});
|
||||
while (i != _notifications.cend()
|
||||
&& i->first.sessionId == sessionId
|
||||
&& i->first.peerId == peerId) {
|
||||
const auto temp = base::take(i->second);
|
||||
i = _notifications.erase(i);
|
||||
|
||||
for (const auto &[msgId, notification] : temp) {
|
||||
notification->close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Manager::Private::clearFromSession(not_null<Main::Session*> session) {
|
||||
const auto sessionId = session->uniqueId();
|
||||
for (auto i = _notifications.begin(); i != _notifications.end();) {
|
||||
if (i->first.sessionId != sessionId) {
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
auto i = _notifications.lower_bound(ContextId{
|
||||
.sessionId = sessionId,
|
||||
});
|
||||
while (i != _notifications.cend() && i->first.sessionId == sessionId) {
|
||||
const auto temp = base::take(i->second);
|
||||
i = _notifications.erase(i);
|
||||
|
||||
|
@ -1004,7 +1030,7 @@ void Manager::Private::clearFromSession(not_null<Main::Session*> session) {
|
|||
}
|
||||
|
||||
void Manager::Private::clearNotification(NotificationId id) {
|
||||
auto i = _notifications.find(id.full);
|
||||
auto i = _notifications.find(id.contextId);
|
||||
if (i != _notifications.cend()) {
|
||||
if (i->second.remove(id.msgId) && i->second.empty()) {
|
||||
_notifications.erase(i);
|
||||
|
@ -1059,6 +1085,10 @@ void Manager::doClearFromItem(not_null<HistoryItem*> item) {
|
|||
_private->clearFromItem(item);
|
||||
}
|
||||
|
||||
void Manager::doClearFromTopic(not_null<Data::ForumTopic*> topic) {
|
||||
_private->clearFromTopic(topic);
|
||||
}
|
||||
|
||||
void Manager::doClearFromHistory(not_null<History*> history) {
|
||||
_private->clearFromHistory(history);
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ protected:
|
|||
DisplayOptions options) override;
|
||||
void doClearAllFast() override;
|
||||
void doClearFromItem(not_null<HistoryItem*> item) override;
|
||||
void doClearFromTopic(not_null<Data::ForumTopic*> topic) override;
|
||||
void doClearFromHistory(not_null<History*> history) override;
|
||||
void doClearFromSession(not_null<Main::Session*> session) override;
|
||||
bool doSkipAudio() const override;
|
||||
|
|
|
@ -21,6 +21,7 @@ public:
|
|||
protected:
|
||||
void doShowNativeNotification(
|
||||
not_null<PeerData*> peer,
|
||||
MsgId topicRootId,
|
||||
std::shared_ptr<Data::CloudImageView> &userpicView,
|
||||
MsgId msgId,
|
||||
const QString &title,
|
||||
|
@ -29,6 +30,7 @@ protected:
|
|||
DisplayOptions options) override;
|
||||
void doClearAllFast() override;
|
||||
void doClearFromItem(not_null<HistoryItem*> item) override;
|
||||
void doClearFromTopic(not_null<Data::ForumTopic*> topic) override;
|
||||
void doClearFromHistory(not_null<History*> history) override;
|
||||
void doClearFromSession(not_null<Main::Session*> session) override;
|
||||
QString accountNameSeparator() override;
|
||||
|
|
|
@ -106,16 +106,23 @@ using Manager = Platform::Notifications::Manager;
|
|||
LOG(("App Error: A notification with unknown peer was received"));
|
||||
return;
|
||||
}
|
||||
NSNumber *topicObject = [notificationUserInfo objectForKey:@"topic"];
|
||||
if (!topicObject) {
|
||||
LOG(("App Error: A notification with unknown topic was received"));
|
||||
return;
|
||||
}
|
||||
const auto notificationTopicRootId = [topicObject longlongValue];
|
||||
|
||||
NSNumber *msgObject = [notificationUserInfo objectForKey:@"msgid"];
|
||||
const auto notificationMsgId = msgObject ? [msgObject longLongValue] : 0LL;
|
||||
|
||||
const auto my = Window::Notifications::Manager::NotificationId{
|
||||
.full = Manager::FullPeer{
|
||||
.contextId = Manager::ContextId{
|
||||
.sessionId = notificationSessionId,
|
||||
.peerId = PeerId(notificationPeerId)
|
||||
.peerId = PeerId(notificationPeerId),
|
||||
.topicRootId = MsgId(notificationTopicRootId),
|
||||
},
|
||||
.msgId = notificationMsgId
|
||||
.msgId = notificationMsgId,
|
||||
};
|
||||
if (notification.activationType == NSUserNotificationActivationTypeReplied) {
|
||||
const auto notificationReply = QString::fromUtf8([[[notification response] string] UTF8String]);
|
||||
|
@ -180,6 +187,7 @@ public:
|
|||
|
||||
void showNotification(
|
||||
not_null<PeerData*> peer,
|
||||
MsgId topicRootId,
|
||||
std::shared_ptr<Data::CloudImageView> &userpicView,
|
||||
MsgId msgId,
|
||||
const QString &title,
|
||||
|
@ -188,6 +196,7 @@ public:
|
|||
DisplayOptions options);
|
||||
void clearAll();
|
||||
void clearFromItem(not_null<HistoryItem*> item);
|
||||
void clearFromTopic(not_null<Data::ForumTopic*> topic);
|
||||
void clearFromHistory(not_null<History*> history);
|
||||
void clearFromSession(not_null<Main::Session*> session);
|
||||
void updateDelegate();
|
||||
|
@ -212,8 +221,11 @@ private:
|
|||
struct ClearFromItem {
|
||||
NotificationId id;
|
||||
};
|
||||
struct ClearFromTopic {
|
||||
ContextId contextId;
|
||||
}
|
||||
struct ClearFromHistory {
|
||||
FullPeer fullPeer;
|
||||
ContextId partialContextId;
|
||||
};
|
||||
struct ClearFromSession {
|
||||
uint64 sessionId = 0;
|
||||
|
@ -224,6 +236,7 @@ private:
|
|||
};
|
||||
using ClearTask = std::variant<
|
||||
ClearFromItem,
|
||||
ClearFromTopic,
|
||||
ClearFromHistory,
|
||||
ClearFromSession,
|
||||
ClearAll,
|
||||
|
@ -250,6 +263,7 @@ Manager::Private::Private(Manager *manager)
|
|||
|
||||
void Manager::Private::showNotification(
|
||||
not_null<PeerData*> peer,
|
||||
MsgId topicRootId,
|
||||
std::shared_ptr<Data::CloudImageView> &userpicView,
|
||||
MsgId msgId,
|
||||
const QString &title,
|
||||
|
@ -274,6 +288,8 @@ void Manager::Private::showNotification(
|
|||
@"session",
|
||||
[NSNumber numberWithUnsignedLongLong:peer->id.value],
|
||||
@"peer",
|
||||
[NSNumber numberWithLongLong:topicRootId.bare],
|
||||
@"topic",
|
||||
[NSNumber numberWithLongLong:msgId.bare],
|
||||
@"msgid",
|
||||
[NSNumber numberWithUnsignedLongLong:_managerId],
|
||||
|
@ -312,7 +328,8 @@ void Manager::Private::clearingThreadLoop() {
|
|||
while (!finished) {
|
||||
auto clearAll = false;
|
||||
auto clearFromItems = base::flat_set<NotificationId>();
|
||||
auto clearFromPeers = base::flat_set<FullPeer>();
|
||||
auto clearFromTopics = base::flat_set<ContextId>();
|
||||
auto clearFromHistories = base::flat_set<ContextId>();
|
||||
auto clearFromSessions = base::flat_set<uint64>();
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(_clearingMutex);
|
||||
|
@ -327,8 +344,10 @@ void Manager::Private::clearingThreadLoop() {
|
|||
clearAll = true;
|
||||
}, [&](const ClearFromItem &value) {
|
||||
clearFromItems.emplace(value.id);
|
||||
}, [&](Const ClearFromTopic &value) {
|
||||
clearFromTopics.emplace(value.contextId);
|
||||
}, [&](const ClearFromHistory &value) {
|
||||
clearFromPeers.emplace(value.fullPeer);
|
||||
clearFromHistories.emplace(value.partialContextId);
|
||||
}, [&](const ClearFromSession &value) {
|
||||
clearFromSessions.emplace(value.sessionId);
|
||||
});
|
||||
|
@ -349,15 +368,26 @@ void Manager::Private::clearingThreadLoop() {
|
|||
if (!notificationPeerId) {
|
||||
return true;
|
||||
}
|
||||
NSNumber *topicObject = [notificationUserInfo objectForKey:@"topic"];
|
||||
if (!topicObject) {
|
||||
return true;
|
||||
}
|
||||
const auto notificationTopicRootId = [topicObject longLongValue];
|
||||
NSNumber *msgObject = [notificationUserInfo objectForKey:@"msgid"];
|
||||
const auto msgId = msgObject ? [msgObject longLongValue] : 0LL;
|
||||
const auto full = FullPeer{
|
||||
const auto partialContextId = ContextId{
|
||||
.sessionId = notificationSessionId,
|
||||
.peerId = PeerId(notificationPeerId)
|
||||
.peerId = PeerId(notificationPeerId),
|
||||
};
|
||||
const auto id = NotificationId{ full, MsgId(msgId) };
|
||||
const auto contextId = ContextId{
|
||||
.sessionId = notificationSessionId,
|
||||
.peerId = PeerId(notificationPeerId),
|
||||
.topicRootId = MsgId(notificationTopicRootId),
|
||||
};
|
||||
const auto id = NotificationId{ contextId, MsgId(msgId) };
|
||||
return clearFromSessions.contains(notificationSessionId)
|
||||
|| clearFromPeers.contains(full)
|
||||
|| clearFromHistories.contains(partialContextId)
|
||||
|| clearFromTopics.contains(contextId)
|
||||
|| (msgId && clearFromItems.contains(id));
|
||||
};
|
||||
|
||||
|
@ -394,21 +424,30 @@ void Manager::Private::clearAll() {
|
|||
}
|
||||
|
||||
void Manager::Private::clearFromItem(not_null<HistoryItem*> item) {
|
||||
putClearTask(ClearFromItem { FullPeer{
|
||||
putClearTask(ClearFromItem{ ContextId{
|
||||
.sessionId = item->history()->session().uniqueId(),
|
||||
.peerId = item->history()->peer->id
|
||||
.peerId = item->history()->peer->id,
|
||||
.topicRootId = item->topicRootId(),
|
||||
}, item->id });
|
||||
}
|
||||
|
||||
void Manager::Private::clearFromTopic(not_null<Data::ForumTopic*> topic) {
|
||||
putClearTask(ClearFromTopic{ ContextId{
|
||||
.sessionId = topic->session().uniqueId(),
|
||||
.peerId = topic->history()->peer->id,
|
||||
.topicRootId = topic->rootId(),
|
||||
} });
|
||||
}
|
||||
|
||||
void Manager::Private::clearFromHistory(not_null<History*> history) {
|
||||
putClearTask(ClearFromHistory { FullPeer{
|
||||
putClearTask(ClearFromHistory{ ContextId{
|
||||
.sessionId = history->session().uniqueId(),
|
||||
.peerId = history->peer->id
|
||||
.peerId = history->peer->id,
|
||||
} });
|
||||
}
|
||||
|
||||
void Manager::Private::clearFromSession(not_null<Main::Session*> session) {
|
||||
putClearTask(ClearFromSession { session->uniqueId() });
|
||||
putClearTask(ClearFromSession{ session->uniqueId() });
|
||||
}
|
||||
|
||||
void Manager::Private::updateDelegate() {
|
||||
|
@ -434,6 +473,7 @@ Manager::~Manager() = default;
|
|||
|
||||
void Manager::doShowNativeNotification(
|
||||
not_null<PeerData*> peer,
|
||||
MsgId topicRootId,
|
||||
std::shared_ptr<Data::CloudImageView> &userpicView,
|
||||
MsgId msgId,
|
||||
const QString &title,
|
||||
|
@ -442,6 +482,7 @@ void Manager::doShowNativeNotification(
|
|||
DisplayOptions options) {
|
||||
_private->showNotification(
|
||||
peer,
|
||||
topicRootId,
|
||||
userpicView,
|
||||
msgId,
|
||||
title,
|
||||
|
@ -458,6 +499,10 @@ void Manager::doClearFromItem(not_null<HistoryItem*> item) {
|
|||
_private->clearFromItem(item);
|
||||
}
|
||||
|
||||
void Manager::doClearFromTopic(not_null<Data::ForumTopic*> topic) {
|
||||
_private->clearFromTopic(topic);
|
||||
}
|
||||
|
||||
void Manager::doClearFromHistory(not_null<History*> history) {
|
||||
_private->clearFromHistory(history);
|
||||
}
|
||||
|
|
|
@ -100,7 +100,7 @@ QImage UnreadBadge(not_null<PeerData*> peer) {
|
|||
: QString::number(count);
|
||||
Dialogs::Ui::UnreadBadgeStyle unreadSt;
|
||||
unreadSt.sizeId = Dialogs::Ui::UnreadBadgeSize::TouchBar;
|
||||
unreadSt.muted = history->mute();
|
||||
unreadSt.muted = history->muted();
|
||||
// Use constant values to draw badge regardless of cConfigScale().
|
||||
unreadSt.size = kUnreadBadgeSize * cRetinaFactor();
|
||||
unreadSt.padding = 4 * cRetinaFactor();
|
||||
|
|
|
@ -18,6 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "platform/win/windows_toast_activator.h"
|
||||
#include "platform/win/windows_dlls.h"
|
||||
#include "platform/win/specific_win.h"
|
||||
#include "data/data_forum_topic.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_item.h"
|
||||
#include "core/application.h"
|
||||
|
@ -411,6 +412,7 @@ public:
|
|||
|
||||
bool showNotification(
|
||||
not_null<PeerData*> peer,
|
||||
MsgId topicRootId,
|
||||
std::shared_ptr<Data::CloudImageView> &userpicView,
|
||||
MsgId msgId,
|
||||
const QString &title,
|
||||
|
@ -419,6 +421,7 @@ public:
|
|||
DisplayOptions options);
|
||||
void clearAll();
|
||||
void clearFromItem(not_null<HistoryItem*> item);
|
||||
void clearFromTopic(not_null<Data::ForumTopic*> topic);
|
||||
void clearFromHistory(not_null<History*> history);
|
||||
void clearFromSession(not_null<Main::Session*> session);
|
||||
void beforeNotificationActivated(NotificationId id);
|
||||
|
@ -434,6 +437,7 @@ public:
|
|||
private:
|
||||
bool showNotificationInTryCatch(
|
||||
not_null<PeerData*> peer,
|
||||
MsgId topicRootId,
|
||||
std::shared_ptr<Data::CloudImageView> &userpicView,
|
||||
MsgId msgId,
|
||||
const QString &title,
|
||||
|
@ -450,7 +454,7 @@ private:
|
|||
ToastNotifier _notifier = nullptr;
|
||||
|
||||
base::flat_map<
|
||||
FullPeer,
|
||||
ContextId,
|
||||
base::flat_map<MsgId, ToastNotification>> _notifications;
|
||||
rpl::lifetime _lifetime;
|
||||
|
||||
|
@ -496,9 +500,10 @@ void Manager::Private::clearFromItem(not_null<HistoryItem*> item) {
|
|||
return;
|
||||
}
|
||||
|
||||
auto i = _notifications.find(FullPeer{
|
||||
auto i = _notifications.find(ContextId{
|
||||
.sessionId = item->history()->session().uniqueId(),
|
||||
.peerId = item->history()->peer->id
|
||||
.peerId = item->history()->peer->id,
|
||||
.topicRootId = item->topicRootId(),
|
||||
});
|
||||
if (i == _notifications.cend()) {
|
||||
return;
|
||||
|
@ -515,18 +520,42 @@ void Manager::Private::clearFromItem(not_null<HistoryItem*> item) {
|
|||
tryHide(taken);
|
||||
}
|
||||
|
||||
void Manager::Private::clearFromTopic(not_null<Data::ForumTopic*> topic) {
|
||||
if (!_notifier) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto i = _notifications.find(ContextId{
|
||||
.sessionId = topic->session().uniqueId(),
|
||||
.peerId = topic->history()->peer->id,
|
||||
.topicRootId = topic->rootId(),
|
||||
});
|
||||
if (i != _notifications.cend()) {
|
||||
const auto temp = base::take(i->second);
|
||||
_notifications.erase(i);
|
||||
|
||||
for (const auto &[msgId, notification] : temp) {
|
||||
tryHide(notification);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Manager::Private::clearFromHistory(not_null<History*> history) {
|
||||
if (!_notifier) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto i = _notifications.find(FullPeer{
|
||||
.sessionId = history->session().uniqueId(),
|
||||
.peerId = history->peer->id
|
||||
const auto sessionId = history->session().uniqueId();
|
||||
const auto peerId = history->peer->id;
|
||||
auto i = _notifications.lower_bound(ContextId{
|
||||
.sessionId = sessionId,
|
||||
.peerId = peerId,
|
||||
});
|
||||
if (i != _notifications.cend()) {
|
||||
while (i != _notifications.cend()
|
||||
&& i->first.sessionId == sessionId
|
||||
&& i->first.peerId == peerId) {
|
||||
const auto temp = base::take(i->second);
|
||||
_notifications.erase(i);
|
||||
i = _notifications.erase(i);
|
||||
|
||||
for (const auto &[msgId, notification] : temp) {
|
||||
tryHide(notification);
|
||||
|
@ -540,13 +569,12 @@ void Manager::Private::clearFromSession(not_null<Main::Session*> session) {
|
|||
}
|
||||
|
||||
const auto sessionId = session->uniqueId();
|
||||
for (auto i = _notifications.begin(); i != _notifications.end();) {
|
||||
if (i->first.sessionId != sessionId) {
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
auto i = _notifications.lower_bound(ContextId{
|
||||
.sessionId = sessionId,
|
||||
});
|
||||
while (i != _notifications.cend() && i->first.sessionId == sessionId) {
|
||||
const auto temp = base::take(i->second);
|
||||
_notifications.erase(i);
|
||||
i = _notifications.erase(i);
|
||||
|
||||
for (const auto &[msgId, notification] : temp) {
|
||||
tryHide(notification);
|
||||
|
@ -565,7 +593,7 @@ void Manager::Private::afterNotificationActivated(
|
|||
}
|
||||
|
||||
void Manager::Private::clearNotification(NotificationId id) {
|
||||
auto i = _notifications.find(id.full);
|
||||
auto i = _notifications.find(id.contextId);
|
||||
if (i != _notifications.cend()) {
|
||||
i->second.remove(id.msgId);
|
||||
if (i->second.empty()) {
|
||||
|
@ -589,13 +617,14 @@ void Manager::Private::handleActivation(const ToastActivation &activation) {
|
|||
}
|
||||
const auto action = parsed.value("action");
|
||||
const auto id = NotificationId{
|
||||
.full = FullPeer{
|
||||
.contextId = ContextId{
|
||||
.sessionId = parsed.value("session").toULongLong(),
|
||||
.peerId = PeerId(parsed.value("peer").toULongLong()),
|
||||
.topicRootId = MsgId(parsed.value("topic").toLongLong())
|
||||
},
|
||||
.msgId = MsgId(parsed.value("msg").toLongLong()),
|
||||
};
|
||||
if (!id.full.sessionId || !id.full.peerId || !id.msgId) {
|
||||
if (!id.contextId.sessionId || !id.contextId.peerId || !id.msgId) {
|
||||
DEBUG_LOG(("Toast Info: Got activation \"%1\", my %1, skipping."
|
||||
).arg(activation.args
|
||||
).arg(pid));
|
||||
|
@ -610,7 +639,7 @@ void Manager::Private::handleActivation(const ToastActivation &activation) {
|
|||
text.text = entry.value;
|
||||
}
|
||||
}
|
||||
const auto i = _notifications.find(id.full);
|
||||
const auto i = _notifications.find(id.contextId);
|
||||
if (i == _notifications.cend() || !i->second.contains(id.msgId)) {
|
||||
return;
|
||||
}
|
||||
|
@ -627,6 +656,7 @@ void Manager::Private::handleActivation(const ToastActivation &activation) {
|
|||
|
||||
bool Manager::Private::showNotification(
|
||||
not_null<PeerData*> peer,
|
||||
MsgId topicRootId,
|
||||
std::shared_ptr<Data::CloudImageView> &userpicView,
|
||||
MsgId msgId,
|
||||
const QString &title,
|
||||
|
@ -640,6 +670,7 @@ bool Manager::Private::showNotification(
|
|||
return base::WinRT::Try([&] {
|
||||
return showNotificationInTryCatch(
|
||||
peer,
|
||||
topicRootId,
|
||||
userpicView,
|
||||
msgId,
|
||||
title,
|
||||
|
@ -660,6 +691,7 @@ std::wstring Manager::Private::ensureSendButtonIcon() {
|
|||
|
||||
bool Manager::Private::showNotificationInTryCatch(
|
||||
not_null<PeerData*> peer,
|
||||
MsgId topicRootId,
|
||||
std::shared_ptr<Data::CloudImageView> &userpicView,
|
||||
MsgId msgId,
|
||||
const QString &title,
|
||||
|
@ -669,18 +701,20 @@ bool Manager::Private::showNotificationInTryCatch(
|
|||
const auto withSubtitle = !subtitle.isEmpty();
|
||||
auto toastXml = XmlDocument();
|
||||
|
||||
const auto key = FullPeer{
|
||||
const auto key = ContextId{
|
||||
.sessionId = peer->session().uniqueId(),
|
||||
.peerId = peer->id,
|
||||
.topicRootId = topicRootId,
|
||||
};
|
||||
const auto notificationId = NotificationId{
|
||||
.full = key,
|
||||
.contextId = key,
|
||||
.msgId = msgId
|
||||
};
|
||||
const auto idString = u"pid=%1&session=%2&peer=%3&msg=%4"_q
|
||||
const auto idString = u"pid=%1&session=%2&peer=%3&topic=%4&msg=%5"_q
|
||||
.arg(GetCurrentProcessId())
|
||||
.arg(key.sessionId)
|
||||
.arg(key.peerId.value)
|
||||
.arg(topicRootId.bare)
|
||||
.arg(msgId.bare);
|
||||
|
||||
const auto modern = Platform::IsWindows10OrGreater();
|
||||
|
@ -855,6 +889,7 @@ Manager::~Manager() = default;
|
|||
|
||||
void Manager::doShowNativeNotification(
|
||||
not_null<PeerData*> peer,
|
||||
MsgId topicRootId,
|
||||
std::shared_ptr<Data::CloudImageView> &userpicView,
|
||||
MsgId msgId,
|
||||
const QString &title,
|
||||
|
@ -863,6 +898,7 @@ void Manager::doShowNativeNotification(
|
|||
DisplayOptions options) {
|
||||
_private->showNotification(
|
||||
peer,
|
||||
topicRootId,
|
||||
userpicView,
|
||||
msgId,
|
||||
title,
|
||||
|
@ -879,6 +915,10 @@ void Manager::doClearFromItem(not_null<HistoryItem*> item) {
|
|||
_private->clearFromItem(item);
|
||||
}
|
||||
|
||||
void Manager::doClearFromTopic(not_null<Data::ForumTopic*> topic) {
|
||||
_private->clearFromTopic(topic);
|
||||
}
|
||||
|
||||
void Manager::doClearFromHistory(not_null<History*> history) {
|
||||
_private->clearFromHistory(history);
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ public:
|
|||
protected:
|
||||
void doShowNativeNotification(
|
||||
not_null<PeerData*> peer,
|
||||
MsgId topicRootId,
|
||||
std::shared_ptr<Data::CloudImageView> &userpicView,
|
||||
MsgId msgId,
|
||||
const QString &title,
|
||||
|
@ -37,6 +38,7 @@ protected:
|
|||
DisplayOptions options) override;
|
||||
void doClearAllFast() override;
|
||||
void doClearFromItem(not_null<HistoryItem*> item) override;
|
||||
void doClearFromTopic(not_null<Data::ForumTopic*> topic) override;
|
||||
void doClearFromHistory(not_null<History*> history) override;
|
||||
void doClearFromSession(not_null<Main::Session*> session) override;
|
||||
void onBeforeNotificationActivated(NotificationId id) override;
|
||||
|
|
|
@ -71,7 +71,7 @@ void SharedMedia::add(SharedMediaAddSlice &&query) {
|
|||
}
|
||||
|
||||
void SharedMedia::remove(SharedMediaRemoveOne &&query) {
|
||||
auto peerIt = _lists.find({ query.peerId, MsgId(0) });
|
||||
auto peerIt = _lists.lower_bound({ query.peerId, MsgId(0) });
|
||||
while (peerIt != end(_lists) && peerIt->first.peerId == query.peerId) {
|
||||
for (auto index = 0; index != kSharedMediaTypeCount; ++index) {
|
||||
auto type = static_cast<SharedMediaType>(index);
|
||||
|
@ -85,7 +85,7 @@ void SharedMedia::remove(SharedMediaRemoveOne &&query) {
|
|||
}
|
||||
|
||||
void SharedMedia::remove(SharedMediaRemoveAll &&query) {
|
||||
auto peerIt = _lists.find({ query.peerId, MsgId(0) });
|
||||
auto peerIt = _lists.lower_bound({ query.peerId, MsgId(0) });
|
||||
while (peerIt != end(_lists) && peerIt->first.peerId == query.peerId) {
|
||||
for (auto index = 0; index != kSharedMediaTypeCount; ++index) {
|
||||
auto type = static_cast<SharedMediaType>(index);
|
||||
|
@ -99,7 +99,7 @@ void SharedMedia::remove(SharedMediaRemoveAll &&query) {
|
|||
}
|
||||
|
||||
void SharedMedia::invalidate(SharedMediaInvalidateBottom &&query) {
|
||||
auto peerIt = _lists.find({ query.peerId, MsgId(0) });
|
||||
auto peerIt = _lists.lower_bound({ query.peerId, MsgId(0) });
|
||||
while (peerIt != end(_lists) && peerIt->first.peerId == query.peerId) {
|
||||
for (auto index = 0; index != kSharedMediaTypeCount; ++index) {
|
||||
peerIt->second[index].invalidateBottom();
|
||||
|
|
|
@ -14,12 +14,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "mtproto/mtproto_config.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_item_components.h"
|
||||
#include "history/view/history_view_replies_section.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "data/notify/data_notify_settings.h"
|
||||
#include "data/stickers/data_custom_emoji.h"
|
||||
#include "data/data_document_media.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_forum_topic.h"
|
||||
#include "data/data_user.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_poll.h"
|
||||
|
@ -327,6 +329,22 @@ void System::clearAll() {
|
|||
_settingWaiters.clear();
|
||||
}
|
||||
|
||||
void System::clearFromTopic(not_null<Data::ForumTopic*> topic) {
|
||||
if (_manager) {
|
||||
_manager->clearFromTopic(topic);
|
||||
}
|
||||
|
||||
// #TODO forum notifications
|
||||
//topic->clearNotifications();
|
||||
//_whenMaps.remove(topic);
|
||||
//_whenAlerts.remove(topic);
|
||||
//_waiters.remove(topic);
|
||||
//_settingWaiters.remove(topic);
|
||||
|
||||
_waitTimer.cancel();
|
||||
showNext();
|
||||
}
|
||||
|
||||
void System::clearFromHistory(not_null<History*> history) {
|
||||
if (_manager) {
|
||||
_manager->clearFromHistory(history);
|
||||
|
@ -381,6 +399,15 @@ void System::clearIncomingFromHistory(not_null<History*> history) {
|
|||
_whenAlerts.remove(history);
|
||||
}
|
||||
|
||||
void System::clearIncomingFromTopic(not_null<Data::ForumTopic*> topic) {
|
||||
if (_manager) {
|
||||
_manager->clearFromTopic(topic);
|
||||
}
|
||||
// #TODO forum notifications
|
||||
//topic->clearIncomingNotifications();
|
||||
//_whenAlerts.remove(topic);
|
||||
}
|
||||
|
||||
void System::clearFromItem(not_null<HistoryItem*> item) {
|
||||
if (_manager) {
|
||||
_manager->clearFromItem(item);
|
||||
|
@ -922,14 +949,16 @@ void Manager::notificationActivated(
|
|||
NotificationId id,
|
||||
const TextWithTags &reply) {
|
||||
onBeforeNotificationActivated(id);
|
||||
if (const auto session = system()->findSession(id.full.sessionId)) {
|
||||
if (const auto session = system()->findSession(id.contextId.sessionId)) {
|
||||
if (session->windows().empty()) {
|
||||
Core::App().domain().activate(&session->account());
|
||||
}
|
||||
if (!session->windows().empty()) {
|
||||
const auto window = session->windows().front();
|
||||
const auto history = session->data().history(id.full.peerId);
|
||||
const auto history = session->data().history(
|
||||
id.contextId.peerId);
|
||||
if (!reply.text.isEmpty()) {
|
||||
// #TODO forum notifications
|
||||
const auto replyToId = (id.msgId > 0
|
||||
&& !history->peer->isUser())
|
||||
? id.msgId
|
||||
|
@ -961,45 +990,57 @@ void Manager::notificationActivated(
|
|||
void Manager::openNotificationMessage(
|
||||
not_null<History*> history,
|
||||
MsgId messageId) {
|
||||
const auto openExactlyMessage = [&] {
|
||||
const auto peer = history->peer;
|
||||
if (peer->isBroadcast()) {
|
||||
return false;
|
||||
const auto item = history->owner().message(history->peer, messageId);
|
||||
const auto openExactlyMessage = !history->peer->isBroadcast()
|
||||
&& item
|
||||
&& item->isRegular()
|
||||
&& (item->out() || (item->mentionsMe() && !history->peer->isUser()));
|
||||
const auto topic = item ? history->peer->forumTopicFor(item) : nullptr;
|
||||
const auto separate = Core::App().separateWindowForPeer(history->peer);
|
||||
const auto window = separate
|
||||
? separate->sessionController()
|
||||
: history->session().tryResolveWindow();
|
||||
const auto itemId = openExactlyMessage ? messageId : ShowAtUnreadMsgId;
|
||||
if (window) {
|
||||
if (topic) {
|
||||
window->showSection(
|
||||
std::make_shared<HistoryView::RepliesMemento>(
|
||||
history,
|
||||
topic->rootId(),
|
||||
itemId),
|
||||
SectionShow::Way::Forward);
|
||||
} else {
|
||||
window->showPeerHistory(
|
||||
history->peer->id,
|
||||
SectionShow::Way::Forward,
|
||||
itemId);
|
||||
}
|
||||
const auto item = history->owner().message(history->peer, messageId);
|
||||
if (!item
|
||||
|| !item->isRegular()
|
||||
|| (!item->out() && (!item->mentionsMe() || peer->isUser()))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}();
|
||||
if (openExactlyMessage) {
|
||||
Ui::showPeerHistory(history, messageId);
|
||||
} else {
|
||||
Ui::showPeerHistory(history, ShowAtUnreadMsgId);
|
||||
}
|
||||
system()->clearFromHistory(history);
|
||||
if (topic) {
|
||||
system()->clearFromTopic(topic);
|
||||
} else {
|
||||
system()->clearFromHistory(history);
|
||||
}
|
||||
}
|
||||
|
||||
void Manager::notificationReplied(
|
||||
NotificationId id,
|
||||
const TextWithTags &reply) {
|
||||
if (!id.full.sessionId || !id.full.peerId) {
|
||||
if (!id.contextId.sessionId || !id.contextId.peerId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto session = system()->findSession(id.full.sessionId);
|
||||
const auto session = system()->findSession(id.contextId.sessionId);
|
||||
if (!session) {
|
||||
return;
|
||||
}
|
||||
const auto history = session->data().history(id.full.peerId);
|
||||
const auto history = session->data().history(id.contextId.peerId);
|
||||
|
||||
auto message = Api::MessageToSend(Api::SendAction(history));
|
||||
message.textWithTags = reply;
|
||||
message.action.replyTo = (id.msgId > 0 && !history->peer->isUser())
|
||||
? id.msgId
|
||||
: 0;
|
||||
: id.contextId.topicRootId;
|
||||
message.action.clearDraft = false;
|
||||
history->session().api().sendMessage(std::move(message));
|
||||
|
||||
|
@ -1053,6 +1094,7 @@ void NativeManager::doShowNotification(NotificationFields &&fields) {
|
|||
auto userpicView = item->history()->peer->createUserpicView();
|
||||
doShowNativeNotification(
|
||||
item->history()->peer,
|
||||
item->topicRootId(),
|
||||
userpicView,
|
||||
item->id,
|
||||
scheduled ? WrapFromScheduled(fullTitle) : fullTitle,
|
||||
|
|
|
@ -18,6 +18,7 @@ enum class ItemNotificationType;
|
|||
namespace Data {
|
||||
class Session;
|
||||
class CloudImageView;
|
||||
class ForumTopic;
|
||||
} // namespace Data
|
||||
|
||||
namespace Main {
|
||||
|
@ -90,7 +91,9 @@ public:
|
|||
|
||||
void checkDelayed();
|
||||
void schedule(ItemNotification notification);
|
||||
void clearFromTopic(not_null<Data::ForumTopic*> topic);
|
||||
void clearFromHistory(not_null<History*> history);
|
||||
void clearIncomingFromTopic(not_null<Data::ForumTopic*> topic);
|
||||
void clearIncomingFromHistory(not_null<History*> history);
|
||||
void clearFromSession(not_null<Main::Session*> session);
|
||||
void clearFromItem(not_null<HistoryItem*> item);
|
||||
|
@ -202,24 +205,22 @@ private:
|
|||
|
||||
class Manager {
|
||||
public:
|
||||
struct FullPeer {
|
||||
struct ContextId {
|
||||
uint64 sessionId = 0;
|
||||
PeerId peerId = 0;
|
||||
MsgId topicRootId = 0;
|
||||
|
||||
friend inline bool operator<(const FullPeer &a, const FullPeer &b) {
|
||||
return std::tie(a.sessionId, a.peerId)
|
||||
< std::tie(b.sessionId, b.peerId);
|
||||
}
|
||||
friend inline auto operator<=>(
|
||||
const ContextId&,
|
||||
const ContextId&) = default;
|
||||
};
|
||||
struct NotificationId {
|
||||
FullPeer full;
|
||||
ContextId contextId;
|
||||
MsgId msgId = 0;
|
||||
|
||||
friend inline bool operator<(
|
||||
const NotificationId &a,
|
||||
const NotificationId &b) {
|
||||
return std::tie(a.full, a.msgId) < std::tie(b.full, b.msgId);
|
||||
}
|
||||
friend inline auto operator<=>(
|
||||
const NotificationId&,
|
||||
const NotificationId&) = default;
|
||||
};
|
||||
struct NotificationFields {
|
||||
not_null<HistoryItem*> item;
|
||||
|
@ -246,6 +247,9 @@ public:
|
|||
void clearFromItem(not_null<HistoryItem*> item) {
|
||||
doClearFromItem(item);
|
||||
}
|
||||
void clearFromTopic(not_null<Data::ForumTopic*> topic) {
|
||||
doClearFromTopic(topic);
|
||||
}
|
||||
void clearFromHistory(not_null<History*> history) {
|
||||
doClearFromHistory(history);
|
||||
}
|
||||
|
@ -294,7 +298,7 @@ public:
|
|||
virtual ~Manager() = default;
|
||||
|
||||
protected:
|
||||
not_null<System*> system() const {
|
||||
[[nodiscard]] not_null<System*> system() const {
|
||||
return _system;
|
||||
}
|
||||
|
||||
|
@ -303,6 +307,7 @@ protected:
|
|||
virtual void doClearAll() = 0;
|
||||
virtual void doClearAllFast() = 0;
|
||||
virtual void doClearFromItem(not_null<HistoryItem*> item) = 0;
|
||||
virtual void doClearFromTopic(not_null<Data::ForumTopic*> topic) = 0;
|
||||
virtual void doClearFromHistory(not_null<History*> history) = 0;
|
||||
virtual void doClearFromSession(not_null<Main::Session*> session) = 0;
|
||||
virtual bool doSkipAudio() const = 0;
|
||||
|
@ -349,6 +354,7 @@ protected:
|
|||
|
||||
virtual void doShowNativeNotification(
|
||||
not_null<PeerData*> peer,
|
||||
MsgId topicRootId,
|
||||
std::shared_ptr<Data::CloudImageView> &userpicView,
|
||||
MsgId msgId,
|
||||
const QString &title,
|
||||
|
@ -369,6 +375,7 @@ public:
|
|||
protected:
|
||||
void doShowNativeNotification(
|
||||
not_null<PeerData*> peer,
|
||||
MsgId topicRootId,
|
||||
std::shared_ptr<Data::CloudImageView> &userpicView,
|
||||
MsgId msgId,
|
||||
const QString &title,
|
||||
|
@ -380,6 +387,8 @@ protected:
|
|||
}
|
||||
void doClearFromItem(not_null<HistoryItem*> item) override {
|
||||
}
|
||||
void doClearFromTopic(not_null<Data::ForumTopic*> topic) override {
|
||||
}
|
||||
void doClearFromHistory(not_null<History*> history) override {
|
||||
}
|
||||
void doClearFromSession(not_null<Main::Session*> session) override {
|
||||
|
|
|
@ -23,6 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/painter.h"
|
||||
#include "ui/ui_utility.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_forum_topic.h"
|
||||
#include "data/stickers/data_custom_emoji.h"
|
||||
#include "dialogs/ui/dialogs_layout.h"
|
||||
#include "window/window_controller.h"
|
||||
|
@ -82,6 +83,7 @@ Manager::Manager(System *system)
|
|||
|
||||
Manager::QueuedNotification::QueuedNotification(NotificationFields &&fields)
|
||||
: history(fields.item->history())
|
||||
, topicRootId(fields.item->topicRootId())
|
||||
, peer(history->peer)
|
||||
, reaction(fields.reactionId)
|
||||
, author(!fields.reactionFrom
|
||||
|
@ -236,6 +238,7 @@ void Manager::showNextFromQueue() {
|
|||
_notifications.push_back(std::make_unique<Notification>(
|
||||
this,
|
||||
queued.history,
|
||||
queued.topicRootId,
|
||||
queued.peer,
|
||||
queued.author,
|
||||
queued.item,
|
||||
|
@ -372,6 +375,24 @@ void Manager::doClearAllFast() {
|
|||
base::take(_hideAll);
|
||||
}
|
||||
|
||||
void Manager::doClearFromTopic(not_null<Data::ForumTopic*> topic) {
|
||||
const auto history = topic->history();
|
||||
const auto topicRootId = topic->rootId();
|
||||
for (auto i = _queuedNotifications.begin(); i != _queuedNotifications.cend();) {
|
||||
if (i->history == history && i->topicRootId == topicRootId) {
|
||||
i = _queuedNotifications.erase(i);
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
for (const auto ¬ification : _notifications) {
|
||||
if (notification->unlinkHistory(history, topicRootId)) {
|
||||
_positionsOutdated = true;
|
||||
}
|
||||
}
|
||||
showNextFromQueue();
|
||||
}
|
||||
|
||||
void Manager::doClearFromHistory(not_null<History*> history) {
|
||||
for (auto i = _queuedNotifications.begin(); i != _queuedNotifications.cend();) {
|
||||
if (i->history == history) {
|
||||
|
@ -601,6 +622,7 @@ void Background::paintEvent(QPaintEvent *e) {
|
|||
Notification::Notification(
|
||||
not_null<Manager*> manager,
|
||||
not_null<History*> history,
|
||||
MsgId topicRootId,
|
||||
not_null<PeerData*> peer,
|
||||
const QString &author,
|
||||
HistoryItem *item,
|
||||
|
@ -614,6 +636,7 @@ Notification::Notification(
|
|||
, _peer(peer)
|
||||
, _started(crl::now())
|
||||
, _history(history)
|
||||
, _topicRootId(topicRootId)
|
||||
, _userpicView(_peer->createUserpicView())
|
||||
, _author(author)
|
||||
, _reaction(reaction)
|
||||
|
@ -1061,9 +1084,10 @@ Notifications::Manager::NotificationId Notification::myId() const {
|
|||
if (!_history) {
|
||||
return {};
|
||||
}
|
||||
return { .full = {
|
||||
return { .contextId = {
|
||||
.sessionId = _history->session().uniqueId(),
|
||||
.peerId = _history->peer->id
|
||||
.peerId = _history->peer->id,
|
||||
.topicRootId = _topicRootId,
|
||||
}, .msgId = _item ? _item->id : ShowAtUnreadMsgId };
|
||||
}
|
||||
|
||||
|
@ -1071,8 +1095,10 @@ void Notification::changeHeight(int newHeight) {
|
|||
manager()->changeNotificationHeight(this, newHeight);
|
||||
}
|
||||
|
||||
bool Notification::unlinkHistory(History *history) {
|
||||
const auto unlink = _history && (history == _history || !history);
|
||||
bool Notification::unlinkHistory(History *history, MsgId topicRootId) {
|
||||
const auto unlink = _history
|
||||
&& (history == _history || !history)
|
||||
&& (topicRootId == _topicRootId || !topicRootId);
|
||||
if (unlink) {
|
||||
hideFast();
|
||||
_history = nullptr;
|
||||
|
|
|
@ -72,6 +72,7 @@ private:
|
|||
void doShowNotification(NotificationFields &&fields) override;
|
||||
void doClearAll() override;
|
||||
void doClearAllFast() override;
|
||||
void doClearFromTopic(not_null<Data::ForumTopic*> topic) override;
|
||||
void doClearFromHistory(not_null<History*> history) override;
|
||||
void doClearFromSession(not_null<Main::Session*> session) override;
|
||||
void doClearFromItem(not_null<HistoryItem*> item) override;
|
||||
|
@ -112,6 +113,7 @@ private:
|
|||
QueuedNotification(NotificationFields &&fields);
|
||||
|
||||
not_null<History*> history;
|
||||
MsgId topicRootId = 0;
|
||||
not_null<PeerData*> peer;
|
||||
Data::ReactionId reaction;
|
||||
QString author;
|
||||
|
@ -205,6 +207,7 @@ public:
|
|||
Notification(
|
||||
not_null<Manager*> manager,
|
||||
not_null<History*> history,
|
||||
MsgId topicRootId,
|
||||
not_null<PeerData*> peer,
|
||||
const QString &author,
|
||||
HistoryItem *item,
|
||||
|
@ -233,7 +236,7 @@ public:
|
|||
|
||||
// Called only by Manager.
|
||||
bool unlinkItem(HistoryItem *del);
|
||||
bool unlinkHistory(History *history = nullptr);
|
||||
bool unlinkHistory(History *history = nullptr, MsgId topicRootId = 0);
|
||||
bool unlinkSession(not_null<Main::Session*> session);
|
||||
bool checkLastInput(
|
||||
bool hasReplyingNotifications,
|
||||
|
@ -282,6 +285,7 @@ private:
|
|||
crl::time _started;
|
||||
|
||||
History *_history = nullptr;
|
||||
MsgId _topicRootId = 0;
|
||||
std::shared_ptr<Data::CloudImageView> _userpicView;
|
||||
QString _author;
|
||||
Data::ReactionId _reaction;
|
||||
|
|
|
@ -141,7 +141,7 @@ void PeerMenuAddMuteSubmenuAction(
|
|||
if (isMuted) {
|
||||
const auto text = tr::lng_context_unmute(tr::now)
|
||||
+ '\t'
|
||||
+ Ui::FormatMuteForTiny(peer->notifyMuteUntil().value_or(0)
|
||||
+ Ui::FormatMuteForTiny(peer->notify().muteUntil().value_or(0)
|
||||
- base::unixtime::now());
|
||||
addAction(text, [=] {
|
||||
peer->owner().notifySettings().update(peer, { .unmute = true });
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 8d9d8e86b9abea58ed5a218e60d9f79b47085c63
|
||||
Subproject commit 2a94813b6aa1f8645fd9de88a78981356259fab7
|
Loading…
Add table
Reference in a new issue