mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-15 21:57:10 +02:00
Update API scheme on layer 148: Notifications.
Support editing / respect notification settings for topics.
This commit is contained in:
parent
b8bdca8921
commit
d92580b8fc
47 changed files with 631 additions and 528 deletions
|
@ -249,8 +249,6 @@ PRIVATE
|
|||
boxes/local_storage_box.h
|
||||
boxes/max_invite_box.cpp
|
||||
boxes/max_invite_box.h
|
||||
boxes/mute_settings_box.cpp
|
||||
boxes/mute_settings_box.h
|
||||
boxes/peer_list_box.cpp
|
||||
boxes/peer_list_box.h
|
||||
boxes/peer_list_controllers.cpp
|
||||
|
@ -539,6 +537,8 @@ PRIVATE
|
|||
data/data_sponsored_messages.h
|
||||
data/data_streaming.cpp
|
||||
data/data_streaming.h
|
||||
data/data_thread.cpp
|
||||
data/data_thread.h
|
||||
data/data_types.cpp
|
||||
data/data_types.h
|
||||
data/data_user.cpp
|
||||
|
|
|
@ -474,6 +474,7 @@ notifyPeer#9fd40bd8 peer:Peer = NotifyPeer;
|
|||
notifyUsers#b4c83b4c = NotifyPeer;
|
||||
notifyChats#c007cec3 = NotifyPeer;
|
||||
notifyBroadcasts#d612e8ef = NotifyPeer;
|
||||
notifyForumTopic#226e6308 peer:Peer top_msg_id:int = NotifyPeer;
|
||||
|
||||
sendMessageTypingAction#16bf744e = SendMessageAction;
|
||||
sendMessageCancelAction#fd5ec8f5 = SendMessageAction;
|
||||
|
@ -1456,6 +1457,7 @@ stickerKeyword#fcfeb29c document_id:long keyword:Vector<string> = StickerKeyword
|
|||
|
||||
username#b4073647 flags:# editable:flags.0?true active:flags.1?true username:string = Username;
|
||||
|
||||
forumTopicDeleted#23f109b id:int = ForumTopic;
|
||||
forumTopic#5920d6dc flags:# my:flags.1?true closed:flags.2?true pinned:flags.3?true id:int date:int title:string icon_color:int icon_emoji_id:flags.0?long top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int from_id:Peer notify_settings:PeerNotifySettings = ForumTopic;
|
||||
|
||||
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;
|
||||
|
|
|
@ -30,12 +30,12 @@ UnreadThings::UnreadThings(not_null<ApiWrap*> api) : _api(api) {
|
|||
}
|
||||
|
||||
bool UnreadThings::trackMentions(Data::Thread *thread) const {
|
||||
const auto peer = thread ? thread->owningHistory()->peer.get() : nullptr;
|
||||
const auto peer = thread ? thread->peer().get() : nullptr;
|
||||
return peer && (peer->isChat() || peer->isMegagroup());
|
||||
}
|
||||
|
||||
bool UnreadThings::trackReactions(Data::Thread *thread) const {
|
||||
const auto peer = thread ? thread->owningHistory()->peer.get() : nullptr;
|
||||
const auto peer = thread ? thread->peer().get() : nullptr;
|
||||
return peer && (peer->isChat() || peer->isMegagroup());
|
||||
}
|
||||
|
||||
|
|
|
@ -1729,10 +1729,10 @@ void ApiWrap::requestNotifySettings(const MTPInputNotifyPeer &peer) {
|
|||
const auto requestId = request(MTPaccount_GetNotifySettings(
|
||||
peer
|
||||
)).done([=](const MTPPeerNotifySettings &result) {
|
||||
applyNotifySettings(peer, result);
|
||||
_session->data().notifySettings().apply(peer, result);
|
||||
_notifySettingRequests.remove(key);
|
||||
}).fail([=] {
|
||||
applyNotifySettings(
|
||||
_session->data().notifySettings().apply(
|
||||
peer,
|
||||
MTP_peerNotifySettings(
|
||||
MTP_flags(0),
|
||||
|
@ -1748,7 +1748,11 @@ void ApiWrap::requestNotifySettings(const MTPInputNotifyPeer &peer) {
|
|||
}
|
||||
|
||||
void ApiWrap::updateNotifySettingsDelayed(
|
||||
not_null<const Data::ForumTopic*> topic) {
|
||||
not_null<const Data::Thread*> thread) {
|
||||
const auto topic = thread->asTopic();
|
||||
if (!topic) {
|
||||
return updateNotifySettingsDelayed(thread->peer());
|
||||
}
|
||||
if (_updateNotifyTopics.emplace(topic).second) {
|
||||
topic->destroyed(
|
||||
) | rpl::start_with_next([=] {
|
||||
|
@ -2122,51 +2126,6 @@ void ApiWrap::clearModifyRequest(const QString &key) {
|
|||
_modifyRequests.remove(key);
|
||||
}
|
||||
|
||||
void ApiWrap::applyNotifySettings(
|
||||
MTPInputNotifyPeer notifyPeer,
|
||||
const MTPPeerNotifySettings &settings) {
|
||||
auto ¬ifySettings = _session->data().notifySettings();
|
||||
switch (notifyPeer.type()) {
|
||||
case mtpc_inputNotifyUsers:
|
||||
notifySettings.apply(MTP_notifyUsers(), settings);
|
||||
break;
|
||||
case mtpc_inputNotifyChats:
|
||||
notifySettings.apply(MTP_notifyChats(), settings);
|
||||
break;
|
||||
case mtpc_inputNotifyBroadcasts:
|
||||
notifySettings.apply(
|
||||
MTP_notifyBroadcasts(),
|
||||
settings);
|
||||
break;
|
||||
case mtpc_inputNotifyPeer: {
|
||||
auto &peer = notifyPeer.c_inputNotifyPeer().vpeer();
|
||||
const auto apply = [&](PeerId peerId) {
|
||||
notifySettings.apply(
|
||||
MTP_notifyPeer(peerToMTP(peerId)),
|
||||
settings);
|
||||
};
|
||||
switch (peer.type()) {
|
||||
case mtpc_inputPeerEmpty:
|
||||
apply(0);
|
||||
break;
|
||||
case mtpc_inputPeerSelf:
|
||||
apply(_session->userPeerId());
|
||||
break;
|
||||
case mtpc_inputPeerUser:
|
||||
apply(peerFromUser(peer.c_inputPeerUser().vuser_id()));
|
||||
break;
|
||||
case mtpc_inputPeerChat:
|
||||
apply(peerFromChat(peer.c_inputPeerChat().vchat_id()));
|
||||
break;
|
||||
case mtpc_inputPeerChannel:
|
||||
apply(peerFromChannel(peer.c_inputPeerChannel().vchannel_id()));
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
Core::App().notifications().checkDelayed();
|
||||
}
|
||||
|
||||
void ApiWrap::gotStickerSet(
|
||||
uint64 setId,
|
||||
const MTPmessages_StickerSet &result) {
|
||||
|
|
|
@ -33,6 +33,7 @@ struct ResolvedForwardDraft;
|
|||
enum class DefaultNotify;
|
||||
enum class StickersType : uchar;
|
||||
class ForumTopic;
|
||||
class Thread;
|
||||
} // namespace Data
|
||||
|
||||
namespace InlineBots {
|
||||
|
@ -144,10 +145,6 @@ public:
|
|||
void registerModifyRequest(const QString &key, mtpRequestId requestId);
|
||||
void clearModifyRequest(const QString &key);
|
||||
|
||||
void applyNotifySettings(
|
||||
MTPInputNotifyPeer peer,
|
||||
const MTPPeerNotifySettings &settings);
|
||||
|
||||
void saveCurrentDraftToCloud();
|
||||
|
||||
void savePinnedOrder(Data::Folder *folder);
|
||||
|
@ -245,8 +242,7 @@ 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 Data::Thread*> thread);
|
||||
void updateNotifySettingsDelayed(not_null<const PeerData*> peer);
|
||||
void updateNotifySettingsDelayed(Data::DefaultNotify type);
|
||||
void saveDraftToCloudDelayed(not_null<History*> history);
|
||||
|
|
|
@ -1,98 +0,0 @@
|
|||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
This code is in Public Domain, see license terms in .github/CONTRIBUTING.md
|
||||
Copyright (C) 2017, Nicholas Guriev <guriev-ns@ya.ru>
|
||||
*/
|
||||
#include "boxes/mute_settings_box.h"
|
||||
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_session.h"
|
||||
#include "data/notify/data_notify_settings.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "ui/special_buttons.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_boxes.h"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr auto kForeverHours = 24 * 365;
|
||||
|
||||
} // namespace
|
||||
|
||||
MuteSettingsBox::MuteSettingsBox(QWidget *parent, not_null<PeerData*> peer)
|
||||
: _peer(peer) {
|
||||
}
|
||||
|
||||
void MuteSettingsBox::prepare() {
|
||||
setTitle(tr::lng_disable_notifications_from_tray());
|
||||
auto y = 0;
|
||||
|
||||
object_ptr<Ui::FlatLabel> info(this, st::boxLabel);
|
||||
info->setText(tr::lng_mute_box_tip(tr::now));
|
||||
info->moveToLeft(st::boxPadding.left(), y);
|
||||
y += info->height() + st::boxLittleSkip;
|
||||
|
||||
const auto icon = object_ptr<Ui::UserpicButton>(
|
||||
this,
|
||||
_peer,
|
||||
Ui::UserpicButton::Role::Custom,
|
||||
st::mutePhotoButton);
|
||||
icon->setPointerCursor(false);
|
||||
icon->moveToLeft(st::boxPadding.left(), y);
|
||||
|
||||
object_ptr<Ui::FlatLabel> title(this, st::muteChatTitle);
|
||||
title->setText(_peer->name());
|
||||
title->moveToLeft(
|
||||
st::boxPadding.left() + st::muteChatTitleLeft,
|
||||
y + (icon->height() / 2) - (title->height() / 2));
|
||||
// the icon is always higher than this chat title
|
||||
y += icon->height() + st::boxMediumSkip;
|
||||
|
||||
// in fact, this is mute only for 1 year
|
||||
const auto group = std::make_shared<Ui::RadiobuttonGroup>(kForeverHours);
|
||||
y += st::boxOptionListPadding.top();
|
||||
for (const auto hours : { 1, 4, 18, 72, kForeverHours }) {
|
||||
const auto text = [&] {
|
||||
if (hours < 24) {
|
||||
return tr::lng_mute_duration_hours(tr::now, lt_count, hours);
|
||||
} else if (hours < kForeverHours) {
|
||||
return tr::lng_mute_duration_days(tr::now, lt_count, hours / 24);
|
||||
} else {
|
||||
return tr::lng_mute_duration_forever(tr::now);
|
||||
}
|
||||
}();
|
||||
object_ptr<Ui::Radiobutton> option(this, group, hours, text);
|
||||
option->moveToLeft(st::boxPadding.left(), y);
|
||||
y += option->heightNoMargins() + st::boxOptionListSkip;
|
||||
}
|
||||
y += st::boxOptionListPadding.bottom()
|
||||
- st::boxOptionListSkip
|
||||
+ st::defaultCheckbox.margin.bottom();
|
||||
|
||||
_save = [=] {
|
||||
const auto muteForSeconds = group->value() * 3600;
|
||||
_peer->owner().notifySettings().update(
|
||||
_peer,
|
||||
{ .period = muteForSeconds });
|
||||
closeBox();
|
||||
};
|
||||
addButton(tr::lng_box_ok(), _save);
|
||||
addButton(tr::lng_cancel(), [this] { closeBox(); });
|
||||
|
||||
setDimensions(st::boxWidth, y);
|
||||
}
|
||||
|
||||
void MuteSettingsBox::keyPressEvent(QKeyEvent *e) {
|
||||
if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) {
|
||||
if (_save) {
|
||||
_save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// vi: ts=4 tw=80
|
|
@ -1,29 +0,0 @@
|
|||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
This code is in Public Domain, see license terms in .github/CONTRIBUTING.md
|
||||
Copyright (C) 2017, Nicholas Guriev <guriev-ns@ya.ru>
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "boxes/abstract_box.h"
|
||||
|
||||
/* This class implements a dialog-box with radio-buttons for pick duration of
|
||||
* turning off notifications from a chat. The widget is opened by a context menu
|
||||
* in the left list of dialogues. */
|
||||
class MuteSettingsBox : public Ui::BoxContent {
|
||||
public:
|
||||
MuteSettingsBox(QWidget *parent, not_null<PeerData*> peer);
|
||||
|
||||
protected:
|
||||
void prepare() override;
|
||||
|
||||
void keyPressEvent(QKeyEvent *e) override;
|
||||
|
||||
private:
|
||||
not_null<PeerData*> _peer;
|
||||
Fn<void()> _save;
|
||||
|
||||
};
|
||||
// vi: ts=4 tw=80
|
|
@ -21,7 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_document.h"
|
||||
#include "data/data_document_media.h"
|
||||
#include "data/data_document_resolver.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "data/data_thread.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/notify/data_notify_settings.h"
|
||||
#include "lang/lang_keys.h"
|
||||
|
@ -342,11 +342,11 @@ void RingtonesBox(
|
|||
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
|
||||
}
|
||||
|
||||
void PeerRingtonesBox(
|
||||
void ThreadRingtonesBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
not_null<PeerData*> peer) {
|
||||
const auto now = peer->owner().notifySettings().sound(peer);
|
||||
RingtonesBox(box, &peer->session(), now, [=](Data::NotifySound sound) {
|
||||
peer->owner().notifySettings().update(peer, {}, {}, sound);
|
||||
not_null<Data::Thread*> thread) {
|
||||
const auto now = thread->owner().notifySettings().sound(thread);
|
||||
RingtonesBox(box, &thread->session(), now, [=](Data::NotifySound sound) {
|
||||
thread->owner().notifySettings().update(thread, {}, {}, sound);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -9,10 +9,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
#include "ui/layers/generic_box.h"
|
||||
|
||||
class PeerData;
|
||||
|
||||
namespace Data {
|
||||
struct NotifySound;
|
||||
class Thread;
|
||||
} // namespace Data
|
||||
|
||||
namespace Main {
|
||||
|
@ -31,6 +30,6 @@ void RingtonesBox(
|
|||
Data::NotifySound selected,
|
||||
Fn<void(Data::NotifySound)> save);
|
||||
|
||||
void PeerRingtonesBox(
|
||||
void ThreadRingtonesBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
not_null<PeerData*> peer);
|
||||
not_null<Data::Thread*> thread);
|
||||
|
|
|
@ -20,14 +20,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_group_call.h"
|
||||
#include "data/data_message_reactions.h"
|
||||
#include "data/data_peer_bot_command.h"
|
||||
#include "data/notify/data_notify_settings.h"
|
||||
#include "main/main_session.h"
|
||||
#include "main/session/send_as_peers.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "core/application.h"
|
||||
#include "history/history.h"
|
||||
#include "main/main_session.h"
|
||||
#include "api/api_chat_invite.h"
|
||||
#include "api/api_invite_links.h"
|
||||
#include "apiwrap.h"
|
||||
#include "window/notifications_manager.h"
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -131,9 +134,14 @@ void ChannelData::setFlags(ChannelDataFlags which) {
|
|||
session().changes().peerUpdated(this, UpdateFlag::Migration);
|
||||
}
|
||||
}
|
||||
if (diff & Flag::CallNotEmpty) {
|
||||
if (diff & (Flag::Forum | Flag::CallNotEmpty)) {
|
||||
if (const auto history = this->owner().historyLoaded(this)) {
|
||||
history->updateChatListEntry();
|
||||
if (diff & Flag::CallNotEmpty) {
|
||||
history->updateChatListEntry();
|
||||
}
|
||||
if (diff & Flag::Forum) {
|
||||
Core::App().notifications().clearFromHistory(history);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -986,8 +994,8 @@ void ApplyChannelUpdate(
|
|||
session->changes().peerUpdated(channel, UpdateFlag::Rights);
|
||||
}
|
||||
|
||||
session->api().applyNotifySettings(
|
||||
MTP_inputNotifyPeer(channel->input),
|
||||
channel->owner().notifySettings().apply(
|
||||
channel,
|
||||
update.vnotify_settings());
|
||||
|
||||
if (const auto sendAs = update.vdefault_send_as()) {
|
||||
|
|
|
@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_changes.h"
|
||||
#include "data/data_group_call.h"
|
||||
#include "data/data_message_reactions.h"
|
||||
#include "data/notify/data_notify_settings.h"
|
||||
#include "history/history.h"
|
||||
#include "main/main_session.h"
|
||||
#include "apiwrap.h"
|
||||
|
@ -489,9 +490,7 @@ void ApplyChatUpdate(not_null<ChatData*> chat, const MTPDchatFull &update) {
|
|||
update.vrequests_pending().value_or_empty(),
|
||||
update.vrecent_requesters().value_or_empty());
|
||||
|
||||
chat->session().api().applyNotifySettings(
|
||||
MTP_inputNotifyPeer(chat->input),
|
||||
update.vnotify_settings());
|
||||
chat->owner().notifySettings().apply(chat, update.vnotify_settings());
|
||||
}
|
||||
|
||||
void ApplyChatUpdate(
|
||||
|
|
|
@ -18,9 +18,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "base/random.h"
|
||||
#include "apiwrap.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "core/application.h"
|
||||
#include "ui/layers/generic_box.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "window/notifications_manager.h"
|
||||
#include "styles/style_boxes.h"
|
||||
|
||||
namespace Data {
|
||||
|
@ -114,6 +116,16 @@ void Forum::applyReceivedTopics(const MTPmessages_ForumTopics &result) {
|
|||
applyReceivedTopics(result, false);
|
||||
}
|
||||
|
||||
void Forum::applyTopicDeleted(MsgId rootId) {
|
||||
const auto i = _topics.find(rootId);
|
||||
if (i != end(_topics)) {
|
||||
Core::App().notifications().clearFromTopic(i->second.get());
|
||||
_topicDestroyed.fire(i->second.get());
|
||||
_history->destroyMessagesByTopic(rootId);
|
||||
_topics.erase(i);
|
||||
}
|
||||
}
|
||||
|
||||
void Forum::applyReceivedTopics(
|
||||
const MTPmessages_ForumTopics &topics,
|
||||
bool updateOffset) {
|
||||
|
@ -124,23 +136,32 @@ void Forum::applyReceivedTopics(
|
|||
channel()->ptsReceived(data.vpts().v);
|
||||
const auto &list = data.vtopics().v;
|
||||
for (const auto &topic : list) {
|
||||
const auto rootId = MsgId(topic.data().vid().v);
|
||||
const auto i = _topics.find(rootId);
|
||||
const auto creating = (i == end(_topics));
|
||||
const auto raw = creating
|
||||
? _topics.emplace(
|
||||
rootId,
|
||||
std::make_unique<ForumTopic>(this, rootId)
|
||||
).first->second.get()
|
||||
: i->second.get();
|
||||
raw->applyTopic(topic);
|
||||
if (updateOffset) {
|
||||
if (const auto last = raw->lastServerMessage()) {
|
||||
_offsetDate = last->date();
|
||||
_offsetId = last->id;
|
||||
const auto rootId = topic.match([&](const auto &data) {
|
||||
return data.vid().v;
|
||||
});
|
||||
topic.match([&](const MTPDforumTopicDeleted &data) {
|
||||
if (updateOffset) {
|
||||
LOG(("API Error: Got a deleted topic in getForumTopics."));
|
||||
}
|
||||
_offsetTopicId = rootId;
|
||||
}
|
||||
applyTopicDeleted(rootId);
|
||||
}, [&](const MTPDforumTopic &data) {
|
||||
const auto i = _topics.find(rootId);
|
||||
const auto creating = (i == end(_topics));
|
||||
const auto raw = creating
|
||||
? _topics.emplace(
|
||||
rootId,
|
||||
std::make_unique<ForumTopic>(this, rootId)
|
||||
).first->second.get()
|
||||
: i->second.get();
|
||||
raw->applyTopic(data);
|
||||
if (updateOffset) {
|
||||
if (const auto last = raw->lastServerMessage()) {
|
||||
_offsetDate = last->date();
|
||||
_offsetId = last->id;
|
||||
}
|
||||
_offsetTopicId = rootId;
|
||||
}
|
||||
});
|
||||
}
|
||||
if (updateOffset
|
||||
&& (list.isEmpty() || list.size() == data.vcount().v)) {
|
||||
|
@ -184,11 +205,13 @@ void Forum::requestTopic(MsgId rootId, Fn<void()> done) {
|
|||
});
|
||||
}
|
||||
|
||||
void Forum::applyTopicAdded(
|
||||
ForumTopic *Forum::applyTopicAdded(
|
||||
MsgId rootId,
|
||||
const QString &title,
|
||||
int32 colorId,
|
||||
DocumentId iconId) {
|
||||
Expects(rootId != 0);
|
||||
|
||||
const auto i = _topics.find(rootId);
|
||||
const auto raw = (i != end(_topics))
|
||||
? i->second.get()
|
||||
|
@ -203,6 +226,7 @@ void Forum::applyTopicAdded(
|
|||
raw->addToChatList(FilterId(), topicsList());
|
||||
_chatsListChanges.fire({});
|
||||
}
|
||||
return raw;
|
||||
}
|
||||
|
||||
MsgId Forum::reserveCreatingId(
|
||||
|
@ -261,10 +285,6 @@ void Forum::clearAllUnreadReactions() {
|
|||
}
|
||||
}
|
||||
|
||||
ForumTopic *Forum::topicFor(not_null<const HistoryItem*> item) {
|
||||
return topicFor(item->topicRootId());
|
||||
}
|
||||
|
||||
ForumTopic *Forum::topicFor(MsgId rootId) {
|
||||
if (!rootId) {
|
||||
return nullptr;
|
||||
|
@ -273,6 +293,18 @@ ForumTopic *Forum::topicFor(MsgId rootId) {
|
|||
return (i != end(_topics)) ? i->second.get() : nullptr;
|
||||
}
|
||||
|
||||
ForumTopic *Forum::enforceTopicFor(MsgId rootId) {
|
||||
Expects(rootId != 0);
|
||||
|
||||
const auto i = _topics.find(rootId);
|
||||
if (i != end(_topics)) {
|
||||
return i->second.get();
|
||||
}
|
||||
const auto result = applyTopicAdded(rootId, {}, {}, {});
|
||||
requestTopic(rootId);
|
||||
return result;
|
||||
}
|
||||
|
||||
rpl::producer<> Forum::chatsListChanges() const {
|
||||
return _chatsListChanges.events();
|
||||
}
|
||||
|
|
|
@ -43,14 +43,15 @@ public:
|
|||
[[nodiscard]] rpl::producer<> chatsListLoadedEvents() const;
|
||||
|
||||
void requestTopic(MsgId rootId, Fn<void()> done = nullptr);
|
||||
void applyTopicAdded(
|
||||
ForumTopic *applyTopicAdded(
|
||||
MsgId rootId,
|
||||
const QString &title,
|
||||
int32 colorId,
|
||||
DocumentId iconId);
|
||||
void applyTopicCreated(MsgId rootId, MsgId realId);
|
||||
[[nodiscard]] ForumTopic *topicFor(not_null<const HistoryItem*> item);
|
||||
void applyTopicDeleted(MsgId rootId);
|
||||
[[nodiscard]] ForumTopic *topicFor(MsgId rootId);
|
||||
[[nodiscard]] ForumTopic *enforceTopicFor(MsgId rootId);
|
||||
|
||||
void applyReceivedTopics(const MTPmessages_ForumTopics &topics);
|
||||
|
||||
|
|
|
@ -197,10 +197,9 @@ void ForumTopic::setRealRootId(MsgId realId) {
|
|||
}
|
||||
}
|
||||
|
||||
void ForumTopic::applyTopic(const MTPForumTopic &topic) {
|
||||
Expects(_rootId == topic.data().vid().v);
|
||||
void ForumTopic::applyTopic(const MTPDforumTopic &data) {
|
||||
Expects(_rootId == data.vid().v);
|
||||
|
||||
const auto &data = topic.data();
|
||||
applyTitle(qs(data.vtitle()));
|
||||
if (const auto iconId = data.vicon_emoji_id()) {
|
||||
applyIconId(iconId->v);
|
||||
|
@ -218,6 +217,8 @@ void ForumTopic::applyTopic(const MTPForumTopic &topic) {
|
|||
}
|
||||
#endif
|
||||
|
||||
owner().notifySettings().apply(this, data.vnotify_settings());
|
||||
|
||||
_replies->setInboxReadTill(
|
||||
data.vread_inbox_max_id().v,
|
||||
data.vunread_count().v);
|
||||
|
|
|
@ -41,7 +41,7 @@ class Forum;
|
|||
const QString &title,
|
||||
const style::ForumTopicIcon &st);
|
||||
|
||||
class ForumTopic final : public Data::Thread {
|
||||
class ForumTopic final : public Thread {
|
||||
public:
|
||||
ForumTopic(not_null<Forum*> forum, MsgId rootId);
|
||||
~ForumTopic();
|
||||
|
@ -59,7 +59,7 @@ public:
|
|||
|
||||
void setRealRootId(MsgId realId);
|
||||
|
||||
void applyTopic(const MTPForumTopic &topic);
|
||||
void applyTopic(const MTPDforumTopic &data);
|
||||
|
||||
TimeId adjustedChatListTimeId() const override;
|
||||
|
||||
|
@ -91,17 +91,17 @@ public:
|
|||
void applyItemAdded(not_null<HistoryItem*> item);
|
||||
void applyItemRemoved(MsgId id);
|
||||
|
||||
[[nodiscard]] Data::PeerNotifySettings ¬ify() {
|
||||
[[nodiscard]] PeerNotifySettings ¬ify() {
|
||||
return _notify;
|
||||
}
|
||||
[[nodiscard]] const Data::PeerNotifySettings ¬ify() const {
|
||||
[[nodiscard]] const PeerNotifySettings ¬ify() const {
|
||||
return _notify;
|
||||
}
|
||||
|
||||
void loadUserpic() override;
|
||||
void paintUserpic(
|
||||
Painter &p,
|
||||
std::shared_ptr<Data::CloudImageView> &view,
|
||||
std::shared_ptr<CloudImageView> &view,
|
||||
const Dialogs::Ui::PaintContext &context) const override;
|
||||
|
||||
[[nodiscard]] int unreadCount() const;
|
||||
|
@ -127,12 +127,12 @@ private:
|
|||
int count,
|
||||
bool known) const;
|
||||
|
||||
const not_null<Data::Forum*> _forum;
|
||||
const not_null<Forum*> _forum;
|
||||
const not_null<Dialogs::MainList*> _list;
|
||||
std::shared_ptr<RepliesList> _replies;
|
||||
MsgId _rootId = 0;
|
||||
|
||||
Data::PeerNotifySettings _notify;
|
||||
PeerNotifySettings _notify;
|
||||
|
||||
QString _title;
|
||||
DocumentId _iconId = 0;
|
||||
|
|
|
@ -899,16 +899,6 @@ Data::Forum *PeerData::forum() const {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
Data::ForumTopic *PeerData::forumTopicFor(
|
||||
not_null<const HistoryItem*> item) const {
|
||||
if (const auto rootId = item->topicRootId()) {
|
||||
if (const auto forum = this->forum()) {
|
||||
return forum->topicFor(rootId);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Data::ForumTopic *PeerData::forumTopicFor(MsgId rootId) const {
|
||||
if (!rootId) {
|
||||
return nullptr;
|
||||
|
|
|
@ -198,8 +198,6 @@ public:
|
|||
}
|
||||
|
||||
[[nodiscard]] Data::Forum *forum() const;
|
||||
[[nodiscard]] Data::ForumTopic *forumTopicFor(
|
||||
not_null<const HistoryItem*> item) const;
|
||||
[[nodiscard]] Data::ForumTopic *forumTopicFor(MsgId rootId) const;
|
||||
|
||||
[[nodiscard]] Data::PeerNotifySettings ¬ify() {
|
||||
|
|
|
@ -7,6 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#include "data/data_thread.h"
|
||||
|
||||
#include "data/data_forum_topic.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_item.h"
|
||||
#include "history/history_unread_things.h"
|
||||
|
@ -15,6 +17,19 @@ namespace Data {
|
|||
|
||||
Thread::~Thread() = default;
|
||||
|
||||
not_null<PeerData*> Thread::peer() const {
|
||||
return owningHistory()->peer;
|
||||
}
|
||||
|
||||
PeerNotifySettings &Thread::notify() {
|
||||
const auto topic = asTopic();
|
||||
return topic ? topic->notify() : peer()->notify();
|
||||
}
|
||||
|
||||
const PeerNotifySettings &Thread::notify() const {
|
||||
return const_cast<Thread*>(this)->notify();
|
||||
}
|
||||
|
||||
void Thread::setUnreadThingsKnown() {
|
||||
_flags |= Flag::UnreadThingsKnown;
|
||||
}
|
||||
|
@ -72,7 +87,7 @@ void Thread::clearNotifications() {
|
|||
}
|
||||
|
||||
void Thread::clearIncomingNotifications() {
|
||||
if (!owningHistory()->peer->isSelf()) {
|
||||
if (!peer()->isSelf()) {
|
||||
const auto proj = [](ItemNotification notification) {
|
||||
return notification.item->out();
|
||||
};
|
||||
|
|
|
@ -30,6 +30,8 @@ extern const int &dialogsTextWidthMin;
|
|||
|
||||
namespace Data {
|
||||
|
||||
class PeerNotifySettings;
|
||||
|
||||
enum class ItemNotificationType {
|
||||
Message,
|
||||
Reaction,
|
||||
|
@ -55,6 +57,9 @@ public:
|
|||
[[nodiscard]] not_null<const History*> owningHistory() const {
|
||||
return const_cast<Thread*>(this)->owningHistory();
|
||||
}
|
||||
[[nodiscard]] not_null<PeerData*> peer() const;
|
||||
[[nodiscard]] PeerNotifySettings ¬ify();
|
||||
[[nodiscard]] const PeerNotifySettings ¬ify() const;
|
||||
|
||||
void setUnreadThingsKnown();
|
||||
[[nodiscard]] HistoryUnreadThings::Proxy unreadMentions();
|
||||
|
|
|
@ -13,8 +13,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_changes.h"
|
||||
#include "data/data_peer_bot_command.h"
|
||||
#include "data/data_emoji_statuses.h"
|
||||
#include "data/notify/data_notify_settings.h"
|
||||
#include "ui/text/text_options.h"
|
||||
#include "apiwrap.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "styles/style_chat.h"
|
||||
|
||||
|
@ -320,9 +320,7 @@ void ApplyUserUpdate(not_null<UserData*> user, const MTPDuserFull &update) {
|
|||
user->owner().processPhoto(*photo);
|
||||
}
|
||||
user->setSettings(update.vsettings());
|
||||
user->session().api().applyNotifySettings(
|
||||
MTP_inputNotifyPeer(user->input),
|
||||
update.vnotify_settings());
|
||||
user->owner().notifySettings().apply(user, update.vnotify_settings());
|
||||
|
||||
user->setMessagesTTL(update.vttl_period().value_or_empty());
|
||||
if (const auto info = update.vbot_info()) {
|
||||
|
|
|
@ -62,50 +62,125 @@ 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())));
|
||||
void NotifySettings::request(not_null<Data::Thread*> thread) {
|
||||
if (const auto topic = thread->asTopic()) {
|
||||
if (topic->notify().settingsUnknown()) {
|
||||
topic->session().api().requestNotifySettings(
|
||||
MTP_inputNotifyForumTopic(
|
||||
topic->channel()->input,
|
||||
MTP_int(topic->rootId())));
|
||||
}
|
||||
}
|
||||
request(topic->channel());
|
||||
request(thread->peer());
|
||||
}
|
||||
|
||||
void NotifySettings::apply(
|
||||
const MTPNotifyPeer ¬ifyPeer,
|
||||
const MTPPeerNotifySettings &settings) {
|
||||
const auto set = [&](DefaultNotify type) {
|
||||
if (defaultValue(type).settings.change(settings)) {
|
||||
updateLocal(type);
|
||||
}
|
||||
notifyPeer.match([&](const MTPDnotifyUsers &) {
|
||||
apply(DefaultNotify::User, settings);
|
||||
}, [&](const MTPDnotifyChats &) {
|
||||
apply(DefaultNotify::Group, settings);
|
||||
}, [&](const MTPDnotifyBroadcasts &) {
|
||||
apply(DefaultNotify::Broadcast, settings);
|
||||
}, [&](const MTPDnotifyPeer &data) {
|
||||
apply(peerFromMTP(data.vpeer()), settings);
|
||||
}, [&](const MTPDnotifyForumTopic &data) {
|
||||
apply(peerFromMTP(data.vpeer()), data.vtop_msg_id().v, settings);
|
||||
});
|
||||
}
|
||||
|
||||
void NotifySettings::apply(
|
||||
const MTPInputNotifyPeer ¬ifyPeer,
|
||||
const MTPPeerNotifySettings &settings) {
|
||||
const auto peerFromInput = [&](const MTPInputPeer &peer) {
|
||||
return peer.match([&](const MTPDinputPeerSelf &) {
|
||||
return _owner->session().userPeerId();
|
||||
}, [](const MTPDinputPeerUser &data) {
|
||||
return peerFromUser(data.vuser_id());
|
||||
}, [](const MTPDinputPeerChat &data) {
|
||||
return peerFromChat(data.vchat_id());
|
||||
}, [](const MTPDinputPeerChannel &data) {
|
||||
return peerFromChannel(data.vchannel_id());
|
||||
}, [](const MTPDinputPeerUserFromMessage &data) -> PeerId {
|
||||
Unexpected("From message peer in NotifySettings::apply.");
|
||||
}, [](const MTPDinputPeerChannelFromMessage &data) -> PeerId {
|
||||
Unexpected("From message peer in NotifySettings::apply.");
|
||||
}, [](const MTPDinputPeerEmpty &) -> PeerId {
|
||||
Unexpected("Empty peer in NotifySettings::apply.");
|
||||
});
|
||||
};
|
||||
switch (notifyPeer.type()) {
|
||||
case mtpc_notifyUsers: set(DefaultNotify::User); break;
|
||||
case mtpc_notifyChats: set(DefaultNotify::Group); break;
|
||||
case mtpc_notifyBroadcasts: set(DefaultNotify::Broadcast); break;
|
||||
case mtpc_notifyPeer: {
|
||||
const auto &data = notifyPeer.c_notifyPeer();
|
||||
if (const auto peer = _owner->peerLoaded(peerFromMTP(data.vpeer()))) {
|
||||
if (peer->notify().change(settings)) {
|
||||
updateLocal(peer);
|
||||
}
|
||||
notifyPeer.match([&](const MTPDinputNotifyUsers &) {
|
||||
apply(DefaultNotify::User, settings);
|
||||
}, [&](const MTPDinputNotifyChats &) {
|
||||
apply(DefaultNotify::Group, settings);
|
||||
}, [&](const MTPDinputNotifyBroadcasts &) {
|
||||
apply(DefaultNotify::Broadcast, settings);
|
||||
}, [&](const MTPDinputNotifyPeer &data) {
|
||||
apply(peerFromInput(data.vpeer()), settings);
|
||||
}, [&](const MTPDinputNotifyForumTopic &data) {
|
||||
apply(peerFromInput(data.vpeer()), data.vtop_msg_id().v, settings);
|
||||
});
|
||||
}
|
||||
|
||||
void NotifySettings::apply(
|
||||
DefaultNotify type,
|
||||
const MTPPeerNotifySettings &settings) {
|
||||
if (defaultValue(type).settings.change(settings)) {
|
||||
updateLocal(type);
|
||||
Core::App().notifications().checkDelayed();
|
||||
}
|
||||
}
|
||||
|
||||
void NotifySettings::apply(
|
||||
PeerId peerId,
|
||||
const MTPPeerNotifySettings &settings) {
|
||||
if (const auto peer = _owner->peerLoaded(peerId)) {
|
||||
apply(peer, settings);
|
||||
}
|
||||
}
|
||||
|
||||
void NotifySettings::apply(
|
||||
not_null<PeerData*> peer,
|
||||
const MTPPeerNotifySettings &settings) {
|
||||
if (peer->notify().change(settings)) {
|
||||
updateLocal(peer);
|
||||
Core::App().notifications().checkDelayed();
|
||||
}
|
||||
}
|
||||
|
||||
void NotifySettings::apply(
|
||||
PeerId peerId,
|
||||
MsgId topicRootId,
|
||||
const MTPPeerNotifySettings &settings) {
|
||||
if (const auto peer = _owner->peerLoaded(peerId)) {
|
||||
if (const auto topic = peer->forumTopicFor(topicRootId)) {
|
||||
apply(topic, settings);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void NotifySettings::apply(
|
||||
not_null<Data::ForumTopic*> topic,
|
||||
const MTPPeerNotifySettings &settings) {
|
||||
if (topic->notify().change(settings)) {
|
||||
updateLocal(topic);
|
||||
Core::App().notifications().checkDelayed();
|
||||
}
|
||||
}
|
||||
|
||||
void NotifySettings::update(
|
||||
not_null<Data::ForumTopic*> topic,
|
||||
not_null<Data::Thread*> thread,
|
||||
Data::MuteValue muteForSeconds,
|
||||
std::optional<bool> silentPosts,
|
||||
std::optional<NotifySound> sound) {
|
||||
if (topic->notify().change(muteForSeconds, std::nullopt, sound)) {
|
||||
updateLocal(topic);
|
||||
topic->session().api().updateNotifySettingsDelayed(topic);
|
||||
if (thread->notify().change(muteForSeconds, silentPosts, sound)) {
|
||||
updateLocal(thread);
|
||||
thread->session().api().updateNotifySettingsDelayed(thread);
|
||||
}
|
||||
}
|
||||
|
||||
void NotifySettings::resetToDefault(not_null<Data::ForumTopic*> topic) {
|
||||
void NotifySettings::resetToDefault(not_null<Data::Thread*> thread) {
|
||||
const auto empty = MTP_peerNotifySettings(
|
||||
MTP_flags(0),
|
||||
MTPBool(),
|
||||
|
@ -114,9 +189,9 @@ void NotifySettings::resetToDefault(not_null<Data::ForumTopic*> topic) {
|
|||
MTPNotificationSound(),
|
||||
MTPNotificationSound(),
|
||||
MTPNotificationSound());
|
||||
if (topic->notify().change(empty)) {
|
||||
updateLocal(topic);
|
||||
topic->session().api().updateNotifySettingsDelayed(topic);
|
||||
if (thread->notify().change(empty)) {
|
||||
updateLocal(thread);
|
||||
thread->session().api().updateNotifySettingsDelayed(thread);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -186,7 +261,11 @@ void NotifySettings::defaultUpdate(
|
|||
}
|
||||
}
|
||||
|
||||
void NotifySettings::updateLocal(not_null<Data::ForumTopic*> topic) {
|
||||
void NotifySettings::updateLocal(not_null<Data::Thread*> thread) {
|
||||
const auto topic = thread->asTopic();
|
||||
if (!topic) {
|
||||
return updateLocal(thread->peer());
|
||||
}
|
||||
auto changesIn = crl::time(0);
|
||||
const auto muted = isMuted(topic, &changesIn);
|
||||
topic->setMuted(muted);
|
||||
|
@ -350,35 +429,39 @@ void NotifySettings::unmuteByFinished() {
|
|||
}
|
||||
|
||||
bool NotifySettings::isMuted(
|
||||
not_null<const Data::ForumTopic*> topic,
|
||||
not_null<const Data::Thread*> thread,
|
||||
crl::time *changesIn) const {
|
||||
const auto until = topic->notify().muteUntil();
|
||||
const auto topic = thread->asTopic();
|
||||
const auto until = topic ? topic->notify().muteUntil() : std::nullopt;
|
||||
return until
|
||||
? MutedFromUntil(*until, changesIn)
|
||||
: isMuted(topic->channel(), changesIn);
|
||||
: isMuted(thread->peer(), changesIn);
|
||||
}
|
||||
|
||||
bool NotifySettings::isMuted(not_null<const Data::ForumTopic*> topic) const {
|
||||
return isMuted(topic, nullptr);
|
||||
bool NotifySettings::isMuted(not_null<const Data::Thread*> thread) const {
|
||||
return isMuted(thread, nullptr);
|
||||
}
|
||||
|
||||
NotifySound NotifySettings::sound(
|
||||
not_null<const Data::ForumTopic*> topic) const {
|
||||
const auto sound = topic->notify().sound();
|
||||
return sound ? *sound : this->sound(topic->channel());
|
||||
not_null<const Data::Thread*> thread) const {
|
||||
const auto topic = thread->asTopic();
|
||||
const auto sound = topic ? topic->notify().sound() : std::nullopt;
|
||||
return sound ? *sound : this->sound(thread->peer());
|
||||
}
|
||||
|
||||
bool NotifySettings::muteUnknown(
|
||||
not_null<const Data::ForumTopic*> topic) const {
|
||||
return topic->notify().settingsUnknown()
|
||||
|| (!topic->notify().muteUntil().has_value()
|
||||
&& muteUnknown(topic->channel()));
|
||||
not_null<const Data::Thread*> thread) const {
|
||||
const auto topic = thread->asTopic();
|
||||
return (topic && topic->notify().settingsUnknown())
|
||||
|| ((!topic || !topic->notify().muteUntil().has_value())
|
||||
&& muteUnknown(thread->peer()));
|
||||
}
|
||||
|
||||
bool NotifySettings::soundUnknown(
|
||||
not_null<const Data::ForumTopic*> topic) const {
|
||||
return topic->notify().settingsUnknown()
|
||||
|| (!topic->notify().sound().has_value()
|
||||
not_null<const Data::Thread*> thread) const {
|
||||
const auto topic = thread->asTopic();
|
||||
return (topic && topic->notify().settingsUnknown())
|
||||
|| ((!topic || !topic->notify().sound().has_value())
|
||||
&& soundUnknown(topic->channel()));
|
||||
}
|
||||
|
||||
|
@ -442,8 +525,11 @@ bool NotifySettings::settingsUnknown(not_null<const PeerData*> peer) const {
|
|||
}
|
||||
|
||||
bool NotifySettings::settingsUnknown(
|
||||
not_null<const Data::ForumTopic*> topic) const {
|
||||
return muteUnknown(topic) || soundUnknown(topic);
|
||||
not_null<const Data::Thread*> thread) const {
|
||||
const auto topic = thread->asTopic();
|
||||
return muteUnknown(thread)
|
||||
|| soundUnknown(thread)
|
||||
|| (!topic && silentPostsUnknown(thread->peer()));
|
||||
}
|
||||
|
||||
rpl::producer<> NotifySettings::defaultUpdates(DefaultNotify type) const {
|
||||
|
|
|
@ -17,6 +17,7 @@ namespace Data {
|
|||
|
||||
class DocumentMedia;
|
||||
class Session;
|
||||
class Thread;
|
||||
class ForumTopic;
|
||||
|
||||
enum class DefaultNotify {
|
||||
|
@ -30,15 +31,33 @@ public:
|
|||
NotifySettings(not_null<Session*> owner);
|
||||
|
||||
void request(not_null<PeerData*> peer);
|
||||
void request(not_null<Data::ForumTopic*> topic);
|
||||
void request(not_null<Data::Thread*> thread);
|
||||
|
||||
void apply(
|
||||
const MTPNotifyPeer ¬ifyPeer,
|
||||
const MTPPeerNotifySettings &settings);
|
||||
void update(
|
||||
void apply(
|
||||
const MTPInputNotifyPeer ¬ifyPeer,
|
||||
const MTPPeerNotifySettings &settings);
|
||||
void apply(DefaultNotify type, const MTPPeerNotifySettings &settings);
|
||||
void apply(PeerId peerId, const MTPPeerNotifySettings &settings);
|
||||
void apply(
|
||||
not_null<PeerData*> peer,
|
||||
const MTPPeerNotifySettings &settings);
|
||||
void apply(
|
||||
PeerId peerId,
|
||||
MsgId topicRootId,
|
||||
const MTPPeerNotifySettings &settings);
|
||||
void apply(
|
||||
not_null<Data::ForumTopic*> topic,
|
||||
const MTPPeerNotifySettings &settings);
|
||||
|
||||
void update(
|
||||
not_null<Data::Thread*> thread,
|
||||
Data::MuteValue muteForSeconds,
|
||||
std::optional<bool> silentPosts = std::nullopt,
|
||||
std::optional<NotifySound> sound = std::nullopt);
|
||||
void resetToDefault(not_null<Data::ForumTopic*> topic);
|
||||
void resetToDefault(not_null<Data::Thread*> thread);
|
||||
void update(
|
||||
not_null<PeerData*> peer,
|
||||
Data::MuteValue muteForSeconds,
|
||||
|
@ -64,14 +83,13 @@ public:
|
|||
std::optional<bool> silentPosts = std::nullopt,
|
||||
std::optional<NotifySound> sound = std::nullopt);
|
||||
|
||||
[[nodiscard]] bool isMuted(
|
||||
not_null<const Data::ForumTopic*> topic) const;
|
||||
[[nodiscard]] bool isMuted(not_null<const Data::Thread*> thread) const;
|
||||
[[nodiscard]] NotifySound sound(
|
||||
not_null<const Data::ForumTopic*> topic) const;
|
||||
not_null<const Data::Thread*> thread) const;
|
||||
[[nodiscard]] bool muteUnknown(
|
||||
not_null<const Data::ForumTopic*> topic) const;
|
||||
not_null<const Data::Thread*> thread) const;
|
||||
[[nodiscard]] bool soundUnknown(
|
||||
not_null<const Data::ForumTopic*> topic) const;
|
||||
not_null<const Data::Thread*> thread) const;
|
||||
|
||||
[[nodiscard]] bool isMuted(not_null<const PeerData*> peer) const;
|
||||
[[nodiscard]] bool silentPosts(not_null<const PeerData*> peer) const;
|
||||
|
@ -90,7 +108,7 @@ private:
|
|||
void cacheSound(const std::optional<NotifySound> &sound);
|
||||
|
||||
[[nodiscard]] bool isMuted(
|
||||
not_null<const Data::ForumTopic*> peer,
|
||||
not_null<const Data::Thread*> thread,
|
||||
crl::time *changesIn) const;
|
||||
[[nodiscard]] bool isMuted(
|
||||
not_null<const PeerData*> peer,
|
||||
|
@ -102,11 +120,11 @@ private:
|
|||
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;
|
||||
not_null<const Data::Thread*> thread) const;
|
||||
|
||||
void unmuteByFinished();
|
||||
void unmuteByFinishedDelayed(crl::time delay);
|
||||
void updateLocal(not_null<Data::ForumTopic*> topic);
|
||||
void updateLocal(not_null<Data::Thread*> thread);
|
||||
void updateLocal(not_null<PeerData*> peer);
|
||||
void updateLocal(DefaultNotify type);
|
||||
|
||||
|
|
|
@ -180,9 +180,7 @@ MTPinputPeerNotifySettings NotifyPeerSettingsValue::serialize() const {
|
|||
PeerNotifySettings::PeerNotifySettings() = default;
|
||||
|
||||
bool PeerNotifySettings::change(const MTPPeerNotifySettings &settings) {
|
||||
Expects(settings.type() == mtpc_peerNotifySettings);
|
||||
|
||||
auto &data = settings.c_peerNotifySettings();
|
||||
auto &data = settings.data();
|
||||
const auto empty = !data.vflags().v;
|
||||
if (empty) {
|
||||
if (!_known || _value) {
|
||||
|
|
|
@ -81,6 +81,22 @@ Data::ForumTopic *Entry::asTopic() {
|
|||
: nullptr;
|
||||
}
|
||||
|
||||
const History *Entry::asHistory() const {
|
||||
return const_cast<Entry*>(this)->asHistory();
|
||||
}
|
||||
|
||||
const Data::Folder *Entry::asFolder() const {
|
||||
return const_cast<Entry*>(this)->asFolder();
|
||||
}
|
||||
|
||||
const Data::Thread *Entry::asThread() const {
|
||||
return const_cast<Entry*>(this)->asThread();
|
||||
}
|
||||
|
||||
const Data::ForumTopic *Entry::asTopic() const {
|
||||
return const_cast<Entry*>(this)->asTopic();
|
||||
}
|
||||
|
||||
void Entry::pinnedIndexChanged(FilterId filterId, int was, int now) {
|
||||
if (!filterId && session().supportMode()) {
|
||||
// Force reorder in support mode.
|
||||
|
|
|
@ -119,6 +119,11 @@ public:
|
|||
Data::Thread *asThread();
|
||||
Data::ForumTopic *asTopic();
|
||||
|
||||
const History *asHistory() const;
|
||||
const Data::Folder *asFolder() const;
|
||||
const Data::Thread *asThread() const;
|
||||
const Data::ForumTopic *asTopic() const;
|
||||
|
||||
PositionChange adjustByPosInChatList(
|
||||
FilterId filterId,
|
||||
not_null<MainList*> list);
|
||||
|
|
|
@ -53,17 +53,15 @@ Data::Thread *Key::thread() const {
|
|||
return _value ? _value->asThread() : nullptr;
|
||||
}
|
||||
|
||||
History *Key::parentHistory() const {
|
||||
if (const auto result = history()) {
|
||||
return result;
|
||||
} else if (const auto child = topic()) {
|
||||
return child->history();
|
||||
History *Key::owningHistory() const {
|
||||
if (const auto thread = this->thread()) {
|
||||
return thread->owningHistory();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PeerData *Key::peer() const {
|
||||
if (const auto history = parentHistory()) {
|
||||
if (const auto history = owningHistory()) {
|
||||
return history->peer;
|
||||
}
|
||||
return nullptr;
|
||||
|
|
|
@ -42,7 +42,7 @@ public:
|
|||
Data::Folder *folder() const;
|
||||
Data::ForumTopic *topic() const;
|
||||
Data::Thread *thread() const;
|
||||
History *parentHistory() const;
|
||||
History *owningHistory() const;
|
||||
PeerData *peer() const;
|
||||
|
||||
friend inline constexpr auto operator<=>(Key, Key) noexcept = default;
|
||||
|
|
|
@ -152,7 +152,7 @@ void History::checkChatListMessageRemoved(not_null<HistoryItem*> item) {
|
|||
}
|
||||
|
||||
void History::itemVanished(not_null<HistoryItem*> item) {
|
||||
item->thread()->removeNotification(item);
|
||||
item->notificationThread()->removeNotification(item);
|
||||
if (lastKeyboardId == item->id) {
|
||||
clearLastKeyboard();
|
||||
}
|
||||
|
@ -450,6 +450,7 @@ void History::destroyMessage(not_null<HistoryItem*> item) {
|
|||
|
||||
void History::destroyMessagesByDates(TimeId minDate, TimeId maxDate) {
|
||||
auto toDestroy = std::vector<not_null<HistoryItem*>>();
|
||||
toDestroy.reserve(_messages.size());
|
||||
for (const auto &message : _messages) {
|
||||
if (message->isRegular()
|
||||
&& message->date() > minDate
|
||||
|
@ -462,6 +463,19 @@ void History::destroyMessagesByDates(TimeId minDate, TimeId maxDate) {
|
|||
}
|
||||
}
|
||||
|
||||
void History::destroyMessagesByTopic(MsgId topicRootId) {
|
||||
auto toDestroy = std::vector<not_null<HistoryItem*>>();
|
||||
toDestroy.reserve(_messages.size());
|
||||
for (const auto &message : _messages) {
|
||||
if (message->topicRootId() == topicRootId) {
|
||||
toDestroy.push_back(message.get());
|
||||
}
|
||||
}
|
||||
for (const auto item : toDestroy) {
|
||||
item->destroy();
|
||||
}
|
||||
}
|
||||
|
||||
void History::unpinAllMessages() {
|
||||
session().storage().remove(
|
||||
Storage::SharedMediaRemoveAll(
|
||||
|
@ -1123,7 +1137,7 @@ void History::newItemAdded(not_null<HistoryItem*> item) {
|
|||
.type = Data::ItemNotificationType::Message,
|
||||
};
|
||||
if (item->showNotification()) {
|
||||
item->thread()->pushNotification(notification);
|
||||
item->notificationThread()->pushNotification(notification);
|
||||
}
|
||||
owner().notifyNewItemAdded(item);
|
||||
const auto stillShow = item->showNotification(); // Could be read already.
|
||||
|
|
|
@ -134,6 +134,7 @@ public:
|
|||
}
|
||||
void destroyMessage(not_null<HistoryItem*> item);
|
||||
void destroyMessagesByDates(TimeId minDate, TimeId maxDate);
|
||||
void destroyMessagesByTopic(MsgId topicRootId);
|
||||
|
||||
void unpinAllMessages();
|
||||
|
||||
|
|
|
@ -232,7 +232,7 @@ void CheckReactionNotificationSchedule(
|
|||
.reactionSender = user,
|
||||
.type = Data::ItemNotificationType::Reaction,
|
||||
};
|
||||
item->thread()->pushNotification(notification);
|
||||
item->notificationThread()->pushNotification(notification);
|
||||
Core::App().notifications().schedule(notification);
|
||||
return;
|
||||
}
|
||||
|
@ -620,9 +620,11 @@ void HistoryItem::destroy() {
|
|||
_history->destroyMessage(this);
|
||||
}
|
||||
|
||||
not_null<Data::Thread*> HistoryItem::thread() const {
|
||||
if (const auto topic = this->topic()) {
|
||||
return topic;
|
||||
not_null<Data::Thread*> HistoryItem::notificationThread() const {
|
||||
if (const auto rootId = topicRootId()) {
|
||||
if (const auto forum = _history->peer->forum()) {
|
||||
return forum->enforceTopicFor(rootId);
|
||||
}
|
||||
}
|
||||
return _history;
|
||||
}
|
||||
|
|
|
@ -123,7 +123,7 @@ public:
|
|||
const QString &label,
|
||||
const TextWithEntities &content);
|
||||
|
||||
[[nodiscard]] not_null<Data::Thread*> thread() const;
|
||||
[[nodiscard]] not_null<Data::Thread*> notificationThread() const;
|
||||
[[nodiscard]] not_null<History*> history() const {
|
||||
return _history;
|
||||
}
|
||||
|
|
|
@ -743,12 +743,12 @@ void TopBarWidget::setActiveChat(
|
|||
_titleNameVersion = 0;
|
||||
_emojiInteractionSeen = nullptr;
|
||||
_activeChatLifetime.destroy();
|
||||
if (const auto history = _activeChat.key.parentHistory()) {
|
||||
if (const auto peer = _activeChat.key.peer()) {
|
||||
session().changes().peerFlagsValue(
|
||||
history->peer,
|
||||
peer,
|
||||
Data::PeerUpdate::Flag::GroupCall
|
||||
) | rpl::map([=] {
|
||||
return history->peer->groupCall();
|
||||
return peer->groupCall();
|
||||
}) | rpl::distinct_until_changed(
|
||||
) | rpl::map([](Data::GroupCall *call) {
|
||||
return call ? call->fullCountValue() : rpl::single(-1);
|
||||
|
|
|
@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_peer_values.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_folder.h"
|
||||
#include "data/data_forum_topic.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_changes.h"
|
||||
#include "data/data_user.h"
|
||||
|
@ -22,13 +23,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/box_content_divider.h"
|
||||
#include "ui/boxes/report_box.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "ui/layers/generic_box.h"
|
||||
#include "ui/toast/toast.h"
|
||||
#include "ui/text/text_utilities.h" // Ui::Text::ToUpper
|
||||
#include "history/history_location_manager.h" // LocationClickHandler.
|
||||
#include "history/view/history_view_context_menu.h" // HistoryView::ShowReportPeerBox
|
||||
#include "boxes/abstract_box.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "boxes/peer_list_box.h"
|
||||
#include "boxes/peer_list_controllers.h"
|
||||
#include "boxes/add_contact_box.h"
|
||||
|
@ -37,6 +38,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "boxes/report_messages_box.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "menu/menu_mute.h"
|
||||
#include "history/history.h"
|
||||
#include "info/info_controller.h"
|
||||
#include "info/info_memento.h"
|
||||
#include "info/profile/info_profile_icon.h"
|
||||
|
@ -132,6 +134,10 @@ public:
|
|||
not_null<Controller*> controller,
|
||||
not_null<Ui::RpWidget*> parent,
|
||||
not_null<PeerData*> peer);
|
||||
DetailsFiller(
|
||||
not_null<Controller*> controller,
|
||||
not_null<Ui::RpWidget*> parent,
|
||||
not_null<Data::ForumTopic*> topic);
|
||||
|
||||
object_ptr<Ui::RpWidget> fill();
|
||||
|
||||
|
@ -159,6 +165,7 @@ private:
|
|||
not_null<Controller*> _controller;
|
||||
not_null<Ui::RpWidget*> _parent;
|
||||
not_null<PeerData*> _peer;
|
||||
Data::ForumTopic *_topic = nullptr;
|
||||
object_ptr<Ui::VerticalLayout> _wrap;
|
||||
|
||||
};
|
||||
|
@ -202,6 +209,17 @@ DetailsFiller::DetailsFiller(
|
|||
, _wrap(_parent) {
|
||||
}
|
||||
|
||||
DetailsFiller::DetailsFiller(
|
||||
not_null<Controller*> controller,
|
||||
not_null<Ui::RpWidget*> parent,
|
||||
not_null<Data::ForumTopic*> topic)
|
||||
: _controller(controller)
|
||||
, _parent(parent)
|
||||
, _peer(topic->peer())
|
||||
, _topic(topic)
|
||||
, _wrap(_parent) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool SetClickContext(
|
||||
const ClickHandlerPtr &handler,
|
||||
|
@ -338,16 +356,20 @@ object_ptr<Ui::RpWidget> DetailsFiller::setupInfo() {
|
|||
[=] { controller->window().show(Box(EditContactBox, controller, user)); },
|
||||
tracker);
|
||||
} else {
|
||||
const auto topicRootId = _topic ? _topic->rootId() : 0;
|
||||
const auto addToLink = topicRootId
|
||||
? "?topic=" + QString::number(topicRootId.bare)
|
||||
: QString();
|
||||
auto linkText = LinkValue(
|
||||
_peer
|
||||
) | rpl::map([](const QString &link) {
|
||||
) | rpl::map([=](const QString &link) {
|
||||
return link.isEmpty()
|
||||
? TextWithEntities()
|
||||
: Ui::Text::Link(
|
||||
(link.startsWith(qstr("https://"))
|
||||
? link.mid(qstr("https://").size())
|
||||
: link),
|
||||
link);
|
||||
: link) + addToLink,
|
||||
link + addToLink);
|
||||
});
|
||||
auto link = addInfoOneLine(
|
||||
tr::lng_info_link_label(),
|
||||
|
@ -358,14 +380,14 @@ object_ptr<Ui::RpWidget> DetailsFiller::setupInfo() {
|
|||
const auto link = peer->session().createInternalLinkFull(
|
||||
peer->userName());
|
||||
if (!link.isEmpty()) {
|
||||
QGuiApplication::clipboard()->setText(link);
|
||||
QGuiApplication::clipboard()->setText(link + addToLink);
|
||||
Ui::Toast::Show(
|
||||
Window::Show(controller).toastParent(),
|
||||
tr::lng_username_copied(tr::now));
|
||||
}
|
||||
});
|
||||
|
||||
if (const auto channel = _peer->asChannel()) {
|
||||
if (const auto channel = _topic ? nullptr : _peer->asChannel()) {
|
||||
auto locationText = LocationValue(
|
||||
channel
|
||||
) | rpl::map([](const ChannelLocation *location) {
|
||||
|
@ -382,7 +404,9 @@ object_ptr<Ui::RpWidget> DetailsFiller::setupInfo() {
|
|||
)->setLinksTrusted();
|
||||
}
|
||||
|
||||
addInfoLine(tr::lng_info_about_label(), AboutValue(_peer));
|
||||
addInfoLine(
|
||||
tr::lng_info_about_label(),
|
||||
_topic ? rpl::single(TextWithEntities()) : AboutValue(_peer));
|
||||
}
|
||||
if (!_peer->isSelf()) {
|
||||
// No notifications toggle for Self => no separator.
|
||||
|
@ -400,17 +424,27 @@ object_ptr<Ui::RpWidget> DetailsFiller::setupInfo() {
|
|||
result,
|
||||
st::infoIconInformation,
|
||||
st::infoInformationIconPosition);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
object_ptr<Ui::RpWidget> DetailsFiller::setupMuteToggle() {
|
||||
const auto peer = _peer;
|
||||
const auto topicRootId = _topic ? _topic->rootId() : MsgId();
|
||||
const auto makeThread = [=] {
|
||||
return topicRootId
|
||||
? static_cast<Data::Thread*>(peer->forumTopicFor(topicRootId))
|
||||
: peer->owner().history(peer).get();
|
||||
};
|
||||
auto result = object_ptr<Ui::SettingsButton>(
|
||||
_wrap,
|
||||
tr::lng_profile_enable_notifications(),
|
||||
st::infoNotificationsButton);
|
||||
result->toggleOn(NotificationsEnabledValue(peer), true);
|
||||
result->toggleOn(_topic
|
||||
? NotificationsEnabledValue(_topic)
|
||||
: NotificationsEnabledValue(peer), true);
|
||||
result->setAcceptBoth();
|
||||
const auto notifySettings = &peer->owner().notifySettings();
|
||||
MuteMenu::SetupMuteMenu(
|
||||
result.data(),
|
||||
result->clicks(
|
||||
|
@ -418,16 +452,15 @@ object_ptr<Ui::RpWidget> DetailsFiller::setupMuteToggle() {
|
|||
if (button == Qt::RightButton) {
|
||||
return true;
|
||||
}
|
||||
if (peer->owner().notifySettings().isMuted(peer)) {
|
||||
peer->owner().notifySettings().update(
|
||||
peer,
|
||||
{ .unmute = true });
|
||||
if (notifySettings->isMuted(peer)) {
|
||||
notifySettings->update(peer, { .unmute = true });
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}) | rpl::to_empty,
|
||||
{ peer, std::make_shared<Window::Show>(_controller) });
|
||||
makeThread,
|
||||
std::make_shared<Window::Show>(_controller));
|
||||
object_ptr<FloatingIcon>(
|
||||
result,
|
||||
st::infoIconNotifications,
|
||||
|
@ -834,6 +867,14 @@ object_ptr<Ui::RpWidget> SetupDetails(
|
|||
return filler.fill();
|
||||
}
|
||||
|
||||
object_ptr<Ui::RpWidget> SetupDetails(
|
||||
not_null<Controller*> controller,
|
||||
not_null<Ui::RpWidget*> parent,
|
||||
not_null<Data::ForumTopic*> topic) {
|
||||
DetailsFiller filler(controller, parent, topic);
|
||||
return filler.fill();
|
||||
}
|
||||
|
||||
object_ptr<Ui::RpWidget> SetupActions(
|
||||
not_null<Controller*> controller,
|
||||
not_null<Ui::RpWidget*> parent,
|
||||
|
|
|
@ -13,17 +13,26 @@ namespace Ui {
|
|||
class RpWidget;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Data {
|
||||
class ForumTopic;
|
||||
} // namespace Data
|
||||
|
||||
namespace Info {
|
||||
|
||||
class Controller;
|
||||
} // namespace Info
|
||||
|
||||
namespace Profile {
|
||||
namespace Info::Profile {
|
||||
|
||||
object_ptr<Ui::RpWidget> SetupDetails(
|
||||
not_null<Controller*> controller,
|
||||
not_null<Ui::RpWidget*> parent,
|
||||
not_null<PeerData*> peer);
|
||||
|
||||
object_ptr<Ui::RpWidget> SetupDetails(
|
||||
not_null<Controller*> controller,
|
||||
not_null<Ui::RpWidget*> parent,
|
||||
not_null<Data::ForumTopic*> topic);
|
||||
|
||||
object_ptr<Ui::RpWidget> SetupActions(
|
||||
not_null<Controller*> controller,
|
||||
not_null<Ui::RpWidget*> parent,
|
||||
|
@ -34,5 +43,4 @@ object_ptr<Ui::RpWidget> SetupChannelMembers(
|
|||
not_null<Ui::RpWidget*> parent,
|
||||
not_null<PeerData*> peer);
|
||||
|
||||
} // namespace Profile
|
||||
} // namespace Info
|
||||
} // namespace Info::Profile
|
||||
|
|
|
@ -79,12 +79,14 @@ object_ptr<Ui::RpWidget> InnerWidget::setupContent(
|
|||
}, _cover->lifetime());
|
||||
_cover->setOnlineCount(rpl::single(0));
|
||||
if (_topic) {
|
||||
result->add(setupSharedMedia(result.data()));
|
||||
result->add(SetupDetails(_controller, parent, _topic));
|
||||
} else {
|
||||
result->add(SetupDetails(_controller, parent, _peer));
|
||||
}
|
||||
result->add(setupSharedMedia(result.data()));
|
||||
if (_topic) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result->add(SetupDetails(_controller, parent, _peer));
|
||||
result->add(setupSharedMedia(result.data()));
|
||||
if (auto members = SetupChannelMembers(_controller, result.data(), _peer)) {
|
||||
result->add(std::move(members));
|
||||
}
|
||||
|
|
|
@ -181,7 +181,11 @@ rpl::producer<const ChannelLocation*> LocationValue(
|
|||
}
|
||||
|
||||
rpl::producer<bool> NotificationsEnabledValue(
|
||||
not_null<Data::ForumTopic*> topic) {
|
||||
not_null<Data::Thread*> thread) {
|
||||
const auto topic = thread->asTopic();
|
||||
if (!topic) {
|
||||
return NotificationsEnabledValue(thread->peer());
|
||||
}
|
||||
return rpl::merge(
|
||||
topic->session().changes().topicFlagsValue(
|
||||
topic,
|
||||
|
|
|
@ -16,6 +16,7 @@ struct ChannelLocation;
|
|||
|
||||
namespace Data {
|
||||
class ForumTopic;
|
||||
class Thread;
|
||||
} // namespace Data
|
||||
|
||||
namespace Main {
|
||||
|
@ -63,7 +64,7 @@ rpl::producer<not_null<PeerData*>> MigratedOrMeValue(
|
|||
[[nodiscard]] rpl::producer<bool> NotificationsEnabledValue(
|
||||
not_null<PeerData*> peer);
|
||||
[[nodiscard]] rpl::producer<bool> NotificationsEnabledValue(
|
||||
not_null<Data::ForumTopic*> topic);
|
||||
not_null<Data::Thread*> thread);
|
||||
[[nodiscard]] rpl::producer<bool> IsContactValue(not_null<UserData*> user);
|
||||
[[nodiscard]] rpl::producer<QString> InviteToChatButton(
|
||||
not_null<UserData*> user);
|
||||
|
|
|
@ -72,7 +72,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "inline_bots/inline_bot_layout_item.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "boxes/sticker_set_box.h"
|
||||
#include "boxes/mute_settings_box.h"
|
||||
#include "boxes/peer_list_controllers.h"
|
||||
#include "boxes/download_path_box.h"
|
||||
#include "boxes/connection_box.h"
|
||||
|
|
|
@ -8,8 +8,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "menu/menu_mute.h"
|
||||
|
||||
#include "boxes/ringtones_box.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_thread.h"
|
||||
#include "data/notify/data_notify_settings.h"
|
||||
#include "info/profile/info_profile_values.h"
|
||||
#include "lang/lang_keys.h"
|
||||
|
@ -70,7 +70,7 @@ public:
|
|||
MuteItem(
|
||||
not_null<RpWidget*> parent,
|
||||
const style::Menu &st,
|
||||
not_null<PeerData*> peer);
|
||||
not_null<Data::Thread*> thread);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
@ -85,7 +85,7 @@ private:
|
|||
MuteItem::MuteItem(
|
||||
not_null<RpWidget*> parent,
|
||||
const style::Menu &st,
|
||||
not_null<PeerData*> peer)
|
||||
not_null<Data::Thread*> thread)
|
||||
: Ui::Menu::Action(
|
||||
parent,
|
||||
st,
|
||||
|
@ -93,10 +93,9 @@ MuteItem::MuteItem(
|
|||
nullptr,
|
||||
nullptr)
|
||||
, _itemIconPosition(st.itemIconPosition)
|
||||
, _isMuted(peer->owner().notifySettings().isMuted(peer)) {
|
||||
|
||||
, _isMuted(thread->owner().notifySettings().isMuted(thread)) {
|
||||
Info::Profile::NotificationsEnabledValue(
|
||||
peer
|
||||
thread
|
||||
) | rpl::start_with_next([=](bool isUnmuted) {
|
||||
const auto isMuted = !isUnmuted;
|
||||
action()->setText(isMuted
|
||||
|
@ -113,10 +112,13 @@ MuteItem::MuteItem(
|
|||
st::defaultPopupMenu.showDuration);
|
||||
}, lifetime());
|
||||
|
||||
const auto weak = base::make_weak(thread.get());
|
||||
setClickedCallback([=] {
|
||||
peer->owner().notifySettings().update(
|
||||
peer,
|
||||
{ .unmute = _isMuted, .forever = !_isMuted });
|
||||
if (const auto strong = weak.get()) {
|
||||
strong->owner().notifySettings().update(
|
||||
strong,
|
||||
{ .unmute = _isMuted, .forever = !_isMuted });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -138,7 +140,7 @@ void MuteItem::paintEvent(QPaintEvent *e) {
|
|||
icon.paint(p, _itemIconPosition, width(), color);
|
||||
}
|
||||
|
||||
void MuteBox(not_null<Ui::GenericBox*> box, not_null<PeerData*> peer) {
|
||||
void MuteBox(not_null<Ui::GenericBox*> box, not_null<Data::Thread*> thread) {
|
||||
struct State {
|
||||
int lastSeconds = 0;
|
||||
};
|
||||
|
@ -158,11 +160,15 @@ void MuteBox(not_null<Ui::GenericBox*> box, not_null<PeerData*> peer) {
|
|||
? tr::lng_mute_menu_unmute()
|
||||
: tr::lng_mute_menu_mute();
|
||||
}) | rpl::flatten_latest();
|
||||
|
||||
const auto weak = base::make_weak(thread.get());
|
||||
Ui::ConfirmBox(box, {
|
||||
.confirmed = [=] {
|
||||
peer->owner().notifySettings().update(
|
||||
peer,
|
||||
{ .period = state->lastSeconds });
|
||||
if (const auto strong = weak.get()) {
|
||||
strong->owner().notifySettings().update(
|
||||
strong,
|
||||
{ .period = state->lastSeconds });
|
||||
}
|
||||
box->getDelegate()->hideLayer();
|
||||
},
|
||||
.confirmText = std::move(confirmText),
|
||||
|
@ -170,7 +176,9 @@ void MuteBox(not_null<Ui::GenericBox*> box, not_null<PeerData*> peer) {
|
|||
});
|
||||
}
|
||||
|
||||
void PickMuteBox(not_null<Ui::GenericBox*> box, not_null<PeerData*> peer) {
|
||||
void PickMuteBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
not_null<Data::Thread*> thread) {
|
||||
struct State {
|
||||
base::unique_qptr<Ui::PopupMenu> menu;
|
||||
};
|
||||
|
@ -183,14 +191,17 @@ void PickMuteBox(not_null<Ui::GenericBox*> box, not_null<PeerData*> peer) {
|
|||
|
||||
const auto pickerCallback = TimePickerBox(box, seconds, phrases, 0);
|
||||
|
||||
const auto weak = base::make_weak(thread.get());
|
||||
Ui::ConfirmBox(box, {
|
||||
.confirmed = [=] {
|
||||
const auto muteFor = pickerCallback();
|
||||
peer->owner().notifySettings().update(
|
||||
peer,
|
||||
{ .period = muteFor });
|
||||
peer->session().settings().addMutePeriod(muteFor);
|
||||
peer->session().saveSettings();
|
||||
if (const auto strong = weak.get()) {
|
||||
strong->owner().notifySettings().update(
|
||||
strong,
|
||||
{ .period = muteFor });
|
||||
strong->session().settings().addMutePeriod(muteFor);
|
||||
strong->session().saveSettings();
|
||||
}
|
||||
box->closeBox();
|
||||
},
|
||||
.confirmText = tr::lng_mute_menu_mute(),
|
||||
|
@ -209,7 +220,11 @@ void PickMuteBox(not_null<Ui::GenericBox*> box, not_null<PeerData*> peer) {
|
|||
st::popupMenuWithIcons);
|
||||
state->menu->addAction(
|
||||
tr::lng_manage_messages_ttl_after_custom(tr::now),
|
||||
[=] { box->getDelegate()->show(Box(MuteBox, peer)); },
|
||||
[=] {
|
||||
if (const auto strong = weak.get()) {
|
||||
box->getDelegate()->show(Box(MuteBox, strong));
|
||||
}
|
||||
},
|
||||
&st::menuIconCustomize);
|
||||
state->menu->setDestroyedCallback(crl::guard(top, [=] {
|
||||
top->setForceRippled(false);
|
||||
|
@ -223,38 +238,44 @@ void PickMuteBox(not_null<Ui::GenericBox*> box, not_null<PeerData*> peer) {
|
|||
|
||||
void FillMuteMenu(
|
||||
not_null<Ui::PopupMenu*> menu,
|
||||
Args args) {
|
||||
const auto peer = args.peer;
|
||||
not_null<Data::Thread*> thread,
|
||||
std::shared_ptr<Ui::Show> show) {
|
||||
const auto weak = base::make_weak(thread.get());
|
||||
const auto with = [=](Fn<void(not_null<Data::Thread*> thread)> handler) {
|
||||
return [=] {
|
||||
if (const auto strong = weak.get()) {
|
||||
handler(strong);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
menu->addAction(
|
||||
tr::lng_mute_menu_sound_select(tr::now),
|
||||
[=, show = args.show] {
|
||||
show->showBox(Box(PeerRingtonesBox, peer));
|
||||
},
|
||||
with([=](not_null<Data::Thread*> thread) {
|
||||
show->showBox(Box(ThreadRingtonesBox, thread));
|
||||
}),
|
||||
&st::menuIconSoundSelect);
|
||||
|
||||
const auto soundIsNone = peer->owner().notifySettings().sound(peer).none;
|
||||
const auto notifySettings = &thread->owner().notifySettings();
|
||||
const auto soundIsNone = notifySettings->sound(thread).none;
|
||||
menu->addAction(
|
||||
soundIsNone
|
||||
? tr::lng_mute_menu_sound_on(tr::now)
|
||||
: tr::lng_mute_menu_sound_off(tr::now),
|
||||
[=] {
|
||||
auto ¬ifySettings = peer->owner().notifySettings();
|
||||
auto sound = notifySettings.sound(peer);
|
||||
with([=](not_null<Data::Thread*> thread) {
|
||||
auto sound = notifySettings->sound(thread);
|
||||
sound.none = !sound.none;
|
||||
notifySettings.update(peer, {}, {}, sound);
|
||||
},
|
||||
notifySettings->update(thread, {}, {}, sound);
|
||||
}),
|
||||
soundIsNone ? &st::menuIconSoundOn : &st::menuIconSoundOff);
|
||||
|
||||
const auto &st = menu->st().menu;
|
||||
const auto iconTextPosition = st.itemIconPosition
|
||||
+ st::menuIconMuteForAnyTextPosition;
|
||||
for (const auto &muteFor : peer->session().settings().mutePeriods()) {
|
||||
const auto callback = [=] {
|
||||
peer->owner().notifySettings().update(
|
||||
peer,
|
||||
{ .period = muteFor });
|
||||
};
|
||||
for (const auto muteFor : thread->session().settings().mutePeriods()) {
|
||||
const auto callback = with([=](not_null<Data::Thread*> thread) {
|
||||
notifySettings->update(thread, { .period = muteFor });
|
||||
});
|
||||
|
||||
auto item = base::make_unique_q<IconWithText>(
|
||||
menu,
|
||||
|
@ -272,23 +293,23 @@ void FillMuteMenu(
|
|||
menu->addAction(std::move(item));
|
||||
}
|
||||
|
||||
const auto callback = [=, show = args.show] {
|
||||
DEBUG_LOG(("Mute Info: PickMuteBox called."));
|
||||
show->showBox(Box(PickMuteBox, peer));
|
||||
};
|
||||
menu->addAction(
|
||||
tr::lng_mute_menu_duration(tr::now),
|
||||
callback,
|
||||
with([=](not_null<Data::Thread*> thread) {
|
||||
DEBUG_LOG(("Mute Info: PickMuteBox called."));
|
||||
show->showBox(Box(PickMuteBox, thread));
|
||||
}),
|
||||
&st::menuIconMuteFor);
|
||||
|
||||
menu->addAction(
|
||||
base::make_unique_q<MuteItem>(menu, menu->st().menu, peer));
|
||||
base::make_unique_q<MuteItem>(menu, menu->st().menu, thread));
|
||||
}
|
||||
|
||||
void SetupMuteMenu(
|
||||
not_null<Ui::RpWidget*> parent,
|
||||
rpl::producer<> triggers,
|
||||
Args args) {
|
||||
Fn<Data::Thread*()> makeThread,
|
||||
std::shared_ptr<Ui::Show> show) {
|
||||
struct State {
|
||||
base::unique_qptr<Ui::PopupMenu> menu;
|
||||
};
|
||||
|
@ -298,12 +319,13 @@ void SetupMuteMenu(
|
|||
) | rpl::start_with_next([=] {
|
||||
if (state->menu) {
|
||||
return;
|
||||
} else if (const auto thread = makeThread()) {
|
||||
state->menu = base::make_unique_q<Ui::PopupMenu>(
|
||||
parent,
|
||||
st::popupMenuWithIcons);
|
||||
FillMuteMenu(state->menu.get(), thread, show);
|
||||
state->menu->popup(QCursor::pos());
|
||||
}
|
||||
state->menu = base::make_unique_q<Ui::PopupMenu>(
|
||||
parent,
|
||||
st::popupMenuWithIcons);
|
||||
FillMuteMenu(state->menu.get(), args);
|
||||
state->menu->popup(QCursor::pos());
|
||||
}, parent->lifetime());
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
class PeerData;
|
||||
namespace Data {
|
||||
class Thread;
|
||||
} // namespace Data
|
||||
|
||||
namespace Ui {
|
||||
class PopupMenu;
|
||||
|
@ -17,18 +19,15 @@ class Show;
|
|||
|
||||
namespace MuteMenu {
|
||||
|
||||
struct Args {
|
||||
not_null<PeerData*> peer;
|
||||
std::shared_ptr<Ui::Show> show;
|
||||
};
|
||||
|
||||
void FillMuteMenu(
|
||||
not_null<Ui::PopupMenu*> menu,
|
||||
Args args);
|
||||
not_null<Data::Thread*> thread,
|
||||
std::shared_ptr<Ui::Show> show);
|
||||
|
||||
void SetupMuteMenu(
|
||||
not_null<Ui::RpWidget*> parent,
|
||||
rpl::producer<> triggers,
|
||||
Args args);
|
||||
Fn<Data::Thread*()> makeThread,
|
||||
std::shared_ptr<Ui::Show> show);
|
||||
|
||||
} // namespace MuteMenu
|
||||
|
|
|
@ -202,7 +202,7 @@ void SetupUnreadMentionsMenu(
|
|||
done();
|
||||
return;
|
||||
}
|
||||
const auto peer = thread->owningHistory()->peer;
|
||||
const auto peer = thread->peer();
|
||||
const auto topic = thread->asTopic();
|
||||
const auto rootId = topic ? topic->rootId() : 0;
|
||||
using Flag = MTPmessages_ReadMentions::Flag;
|
||||
|
@ -244,7 +244,7 @@ void SetupUnreadReactionsMenu(
|
|||
return;
|
||||
}
|
||||
const auto topic = thread->asTopic();
|
||||
const auto peer = thread->owningHistory()->peer;
|
||||
const auto peer = thread->peer();
|
||||
const auto rootId = topic ? topic->rootId() : 0;
|
||||
using Flag = MTPmessages_ReadReactions::Flag;
|
||||
peer->session().api().request(MTPmessages_ReadReactions(
|
||||
|
|
|
@ -165,7 +165,7 @@ System::SkipState System::skipNotification(
|
|||
const auto item = notification.item;
|
||||
const auto type = notification.type;
|
||||
const auto messageType = (type == Data::ItemNotificationType::Message);
|
||||
if (!item->thread()->currentNotification()
|
||||
if (!item->notificationThread()->currentNotification()
|
||||
|| (messageType && item->skipNotification())
|
||||
|| (type == Data::ItemNotificationType::Reaction
|
||||
&& skipReactionNotification(item))) {
|
||||
|
@ -178,7 +178,8 @@ System::SkipState System::computeSkipState(
|
|||
Data::ItemNotification notification) const {
|
||||
const auto type = notification.type;
|
||||
const auto item = notification.item;
|
||||
const auto history = item->history();
|
||||
const auto thread = item->notificationThread();
|
||||
const auto notifySettings = &thread->owner().notifySettings();
|
||||
const auto messageType = (type == Data::ItemNotificationType::Message);
|
||||
const auto withSilent = [&](
|
||||
SkipState::Value value,
|
||||
|
@ -188,8 +189,7 @@ System::SkipState System::computeSkipState(
|
|||
.silent = (forceSilent
|
||||
|| !messageType
|
||||
|| item->isSilent()
|
||||
|| history->owner().notifySettings().sound(
|
||||
history->peer).none),
|
||||
|| notifySettings->sound(thread).none),
|
||||
};
|
||||
};
|
||||
const auto showForMuted = messageType
|
||||
|
@ -201,35 +201,32 @@ System::SkipState System::computeSkipState(
|
|||
if (Core::Quitting()) {
|
||||
return { SkipState::Skip };
|
||||
} else if (!Core::App().settings().notifyFromAll()
|
||||
&& &history->session().account() != &Core::App().domain().active()) {
|
||||
&& &thread->session().account() != &Core::App().domain().active()) {
|
||||
return { SkipState::Skip };
|
||||
}
|
||||
|
||||
if (messageType) {
|
||||
history->owner().notifySettings().request(
|
||||
history->peer);
|
||||
notifySettings->request(thread);
|
||||
} else if (notifyBy->blockStatus() == PeerData::BlockStatus::Unknown) {
|
||||
notifyBy->updateFull();
|
||||
}
|
||||
if (notifyBy) {
|
||||
history->owner().notifySettings().request(notifyBy);
|
||||
notifySettings->request(notifyBy);
|
||||
}
|
||||
|
||||
if (messageType
|
||||
&& history->owner().notifySettings().muteUnknown(history->peer)) {
|
||||
if (messageType && notifySettings->muteUnknown(thread)) {
|
||||
return { SkipState::Unknown };
|
||||
} else if (messageType
|
||||
&& !history->owner().notifySettings().isMuted(history->peer)) {
|
||||
} else if (messageType && !notifySettings->isMuted(thread)) {
|
||||
return withSilent(SkipState::DontSkip);
|
||||
} else if (!notifyBy) {
|
||||
return withSilent(
|
||||
showForMuted ? SkipState::DontSkip : SkipState::Skip,
|
||||
showForMuted);
|
||||
} else if (history->owner().notifySettings().muteUnknown(notifyBy)
|
||||
} else if (notifySettings->muteUnknown(notifyBy)
|
||||
|| (!messageType
|
||||
&& notifyBy->blockStatus() == PeerData::BlockStatus::Unknown)) {
|
||||
return withSilent(SkipState::Unknown);
|
||||
} else if (!history->owner().notifySettings().isMuted(notifyBy)
|
||||
} else if (!notifySettings->isMuted(notifyBy)
|
||||
&& (messageType || !notifyBy->isBlocked())) {
|
||||
return withSilent(SkipState::DontSkip);
|
||||
} else {
|
||||
|
@ -240,13 +237,13 @@ System::SkipState System::computeSkipState(
|
|||
}
|
||||
|
||||
System::Timing System::countTiming(
|
||||
not_null<History*> history,
|
||||
not_null<Data::Thread*> thread,
|
||||
crl::time minimalDelay) const {
|
||||
auto delay = minimalDelay;
|
||||
const auto t = base::unixtime::now();
|
||||
const auto ms = crl::now();
|
||||
const auto &updates = history->session().updates();
|
||||
const auto &config = history->session().serverConfig();
|
||||
const auto &updates = thread->session().updates();
|
||||
const auto &config = thread->session().serverConfig();
|
||||
const bool isOnline = updates.lastWasOnline();
|
||||
const auto otherNotOld = ((cOtherOnline() * 1000LL) + config.onlineCloudTimeout > t * 1000LL);
|
||||
const bool otherLaterThanMe = (cOtherOnline() * 1000LL + (ms - updates.lastSetOnline()) > t * 1000LL);
|
||||
|
@ -261,15 +258,26 @@ System::Timing System::countTiming(
|
|||
};
|
||||
}
|
||||
|
||||
void System::registerThread(not_null<Data::Thread*> thread) {
|
||||
if (const auto topic = thread->asTopic()) {
|
||||
const auto [i, ok] = _watchedTopics.emplace(topic, rpl::lifetime());
|
||||
if (ok) {
|
||||
topic->destroyed() | rpl::start_with_next([=] {
|
||||
clearFromTopic(topic);
|
||||
}, i->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void System::schedule(Data::ItemNotification notification) {
|
||||
Expects(_manager != nullptr);
|
||||
|
||||
const auto item = notification.item;
|
||||
const auto type = notification.type;
|
||||
const auto history = item->history();
|
||||
const auto thread = item->notificationThread();
|
||||
const auto skip = skipNotification(notification);
|
||||
if (skip.value == SkipState::Skip) {
|
||||
history->popNotification(notification);
|
||||
thread->popNotification(notification);
|
||||
return;
|
||||
}
|
||||
const auto ready = (skip.value != SkipState::Unknown)
|
||||
|
@ -280,25 +288,27 @@ void System::schedule(Data::ItemNotification notification) {
|
|||
: item->Has<HistoryMessageForwarded>()
|
||||
? kMinimalForwardDelay
|
||||
: kMinimalDelay;
|
||||
const auto timing = countTiming(history, minimalDelay);
|
||||
const auto timing = countTiming(thread, minimalDelay);
|
||||
const auto notifyBy = (type == Data::ItemNotificationType::Message)
|
||||
? item->specialNotificationPeer()
|
||||
: notification.reactionSender;
|
||||
if (!skip.silent) {
|
||||
_whenAlerts[history].emplace(timing.when, notifyBy);
|
||||
registerThread(thread);
|
||||
_whenAlerts[thread].emplace(timing.when, notifyBy);
|
||||
}
|
||||
if (Core::App().settings().desktopNotify()
|
||||
&& !_manager->skipToast()) {
|
||||
registerThread(thread);
|
||||
const auto key = NotificationInHistoryKey(notification);
|
||||
auto &whenMap = _whenMaps[history];
|
||||
auto &whenMap = _whenMaps[thread];
|
||||
if (whenMap.find(key) == whenMap.end()) {
|
||||
whenMap.emplace(key, timing.when);
|
||||
}
|
||||
|
||||
auto &addTo = ready ? _waiters : _settingWaiters;
|
||||
const auto it = addTo.find(history);
|
||||
const auto it = addTo.find(thread);
|
||||
if (it == addTo.end() || it->second.when > timing.when) {
|
||||
addTo.emplace(history, Waiter{
|
||||
addTo.emplace(thread, Waiter{
|
||||
.key = key,
|
||||
.reactionSender = notification.reactionSender,
|
||||
.type = notification.type,
|
||||
|
@ -312,7 +322,6 @@ void System::schedule(Data::ItemNotification notification) {
|
|||
_waitTimer.callOnce(timing.delay);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void System::clearAll() {
|
||||
|
@ -327,6 +336,7 @@ void System::clearAll() {
|
|||
_whenAlerts.clear();
|
||||
_waiters.clear();
|
||||
_settingWaiters.clear();
|
||||
_watchedTopics.clear();
|
||||
}
|
||||
|
||||
void System::clearFromTopic(not_null<Data::ForumTopic*> topic) {
|
||||
|
@ -340,6 +350,8 @@ void System::clearFromTopic(not_null<Data::ForumTopic*> topic) {
|
|||
_waiters.remove(topic);
|
||||
_settingWaiters.remove(topic);
|
||||
|
||||
_watchedTopics.remove(topic);
|
||||
|
||||
_waitTimer.cancel();
|
||||
showNext();
|
||||
}
|
||||
|
@ -357,10 +369,17 @@ void System::clearForThreadIf(Fn<bool(not_null<Data::Thread*>)> predicate) {
|
|||
_whenAlerts.remove(thread);
|
||||
_waiters.remove(thread);
|
||||
_settingWaiters.remove(thread);
|
||||
if (const auto topic = thread->asTopic()) {
|
||||
_watchedTopics.remove(topic);
|
||||
}
|
||||
}
|
||||
const auto clearFrom = [&](auto &map) {
|
||||
for (auto i = map.begin(); i != map.end();) {
|
||||
if (predicate(i->first)) {
|
||||
const auto thread = i->first;
|
||||
if (predicate(thread)) {
|
||||
if (const auto topic = thread->asTopic()) {
|
||||
_watchedTopics.remove(topic);
|
||||
}
|
||||
i = map.erase(i);
|
||||
} else {
|
||||
++i;
|
||||
|
@ -424,13 +443,14 @@ void System::clearAllFast() {
|
|||
_whenAlerts.clear();
|
||||
_waiters.clear();
|
||||
_settingWaiters.clear();
|
||||
_watchedTopics.clear();
|
||||
}
|
||||
|
||||
void System::checkDelayed() {
|
||||
for (auto i = _settingWaiters.begin(); i != _settingWaiters.end();) {
|
||||
const auto remove = [&] {
|
||||
const auto thread = i->first;
|
||||
const auto peer = thread->owningHistory()->peer;
|
||||
const auto peer = thread->peer();
|
||||
const auto fullId = FullMsgId(peer->id, i->second.key.messageId);
|
||||
const auto item = thread->owner().message(fullId);
|
||||
if (!item) {
|
||||
|
@ -501,21 +521,21 @@ void System::showNext() {
|
|||
};
|
||||
|
||||
auto ms = crl::now(), nextAlert = crl::time(0);
|
||||
auto alertPeer = (PeerData*)nullptr;
|
||||
auto alertThread = (Data::Thread*)nullptr;
|
||||
for (auto i = _whenAlerts.begin(); i != _whenAlerts.end();) {
|
||||
while (!i->second.empty() && i->second.begin()->first <= ms) {
|
||||
const auto peer = i->first->owningHistory()->peer;
|
||||
const auto ¬ifySettings = peer->owner().notifySettings();
|
||||
const auto peerUnknown = notifySettings.muteUnknown(peer);
|
||||
const auto peerAlert = !peerUnknown
|
||||
&& !notifySettings.isMuted(peer);
|
||||
const auto thread = i->first;
|
||||
const auto notifySettings = &thread->owner().notifySettings();
|
||||
const auto threadUnknown = notifySettings->muteUnknown(thread);
|
||||
const auto threadAlert = !threadUnknown
|
||||
&& !notifySettings->isMuted(thread);
|
||||
const auto from = i->second.begin()->second;
|
||||
const auto fromUnknown = (!from
|
||||
|| notifySettings.muteUnknown(from));
|
||||
|| notifySettings->muteUnknown(from));
|
||||
const auto fromAlert = !fromUnknown
|
||||
&& !notifySettings.isMuted(from);
|
||||
if (peerAlert || fromAlert) {
|
||||
alertPeer = peer;
|
||||
&& !notifySettings->isMuted(from);
|
||||
if (threadAlert || fromAlert) {
|
||||
alertThread = thread;
|
||||
}
|
||||
while (!i->second.empty()
|
||||
&& i->second.begin()->first <= ms + kMinimalAlertDelay) {
|
||||
|
@ -532,7 +552,7 @@ void System::showNext() {
|
|||
}
|
||||
}
|
||||
const auto &settings = Core::App().settings();
|
||||
if (alertPeer) {
|
||||
if (alertThread) {
|
||||
if (settings.flashBounceNotify() && !_manager->skipFlashBounce()) {
|
||||
if (const auto window = Core::App().primaryWindow()) {
|
||||
if (const auto handle = window->widget()->windowHandle()) {
|
||||
|
@ -543,8 +563,8 @@ void System::showNext() {
|
|||
}
|
||||
if (settings.soundNotify() && !_manager->skipAudio()) {
|
||||
const auto track = lookupSound(
|
||||
&alertPeer->owner(),
|
||||
alertPeer->owner().notifySettings().sound(alertPeer).id);
|
||||
&alertThread->owner(),
|
||||
alertThread->owner().notifySettings().sound(alertThread).id);
|
||||
track->playOnce();
|
||||
Media::Player::mixer()->suppressAll(track->getLengthMs());
|
||||
Media::Player::mixer()->faderOnTimer();
|
||||
|
@ -620,7 +640,7 @@ void System::showNext() {
|
|||
: nullptr;
|
||||
auto forwardedCount = isForwarded ? 1 : 0;
|
||||
|
||||
const auto thread = notifyItem->thread();
|
||||
const auto thread = notifyItem->notificationThread();
|
||||
const auto j = _whenMaps.find(thread);
|
||||
if (j == _whenMaps.cend()) {
|
||||
thread->clearNotifications();
|
||||
|
@ -997,7 +1017,7 @@ void Manager::openNotificationMessage(
|
|||
&& item
|
||||
&& item->isRegular()
|
||||
&& (item->out() || (item->mentionsMe() && !history->peer->isUser()));
|
||||
const auto topic = item ? history->peer->forumTopicFor(item) : nullptr;
|
||||
const auto topic = item ? item->topic() : nullptr;
|
||||
const auto separate = Core::App().separateWindowForPeer(history->peer);
|
||||
const auto window = separate
|
||||
? separate->sessionController()
|
||||
|
|
|
@ -155,7 +155,7 @@ private:
|
|||
[[nodiscard]] SkipState computeSkipState(
|
||||
Data::ItemNotification notification) const;
|
||||
[[nodiscard]] Timing countTiming(
|
||||
not_null<History*> history,
|
||||
not_null<Data::Thread*> thread,
|
||||
crl::time minimalDelay) const;
|
||||
[[nodiscard]] bool skipReactionNotification(
|
||||
not_null<HistoryItem*> item) const;
|
||||
|
@ -167,6 +167,8 @@ private:
|
|||
not_null<Data::Session*> owner,
|
||||
DocumentId id);
|
||||
|
||||
void registerThread(not_null<Data::Thread*> thread);
|
||||
|
||||
base::flat_map<
|
||||
not_null<Data::Thread*>,
|
||||
base::flat_map<NotificationInHistoryKey, crl::time>> _whenMaps;
|
||||
|
@ -193,6 +195,10 @@ private:
|
|||
DocumentId,
|
||||
std::unique_ptr<Media::Audio::Track>> _customSoundTracks;
|
||||
|
||||
base::flat_map<
|
||||
not_null<Data::ForumTopic*>,
|
||||
rpl::lifetime> _watchedTopics;
|
||||
|
||||
int _lastForwardedCount = 0;
|
||||
uint64 _lastHistorySessionId = 0;
|
||||
FullMsgId _lastHistoryItemId;
|
||||
|
|
|
@ -14,7 +14,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "base/unixtime.h"
|
||||
#include "boxes/delete_messages_box.h"
|
||||
#include "boxes/max_invite_box.h"
|
||||
#include "boxes/mute_settings_box.h"
|
||||
#include "boxes/add_contact_box.h"
|
||||
#include "boxes/choose_filter_box.h"
|
||||
#include "boxes/create_poll_box.h"
|
||||
|
@ -134,28 +133,39 @@ void MarkAsReadChatList(not_null<Dialogs::MainList*> list) {
|
|||
|
||||
void PeerMenuAddMuteSubmenuAction(
|
||||
not_null<Window::SessionController*> controller,
|
||||
not_null<PeerData*> peer,
|
||||
not_null<Data::Thread*> thread,
|
||||
const PeerMenuCallback &addAction) {
|
||||
peer->owner().notifySettings().request(peer);
|
||||
const auto isMuted = peer->owner().notifySettings().isMuted(peer);
|
||||
const auto notifySettings = &thread->owner().notifySettings();
|
||||
notifySettings->request(thread);
|
||||
const auto weak = base::make_weak(thread.get());
|
||||
const auto with = [=](Fn<void(not_null<Data::Thread*>)> callback) {
|
||||
return [=] {
|
||||
if (const auto strong = weak.get()) {
|
||||
callback(strong);
|
||||
}
|
||||
};
|
||||
};
|
||||
const auto isMuted = notifySettings->isMuted(thread);
|
||||
if (isMuted) {
|
||||
const auto text = tr::lng_context_unmute(tr::now)
|
||||
+ '\t'
|
||||
+ Ui::FormatMuteForTiny(peer->notify().muteUntil().value_or(0)
|
||||
+ Ui::FormatMuteForTiny(thread->notify().muteUntil().value_or(0)
|
||||
- base::unixtime::now());
|
||||
addAction(text, [=] {
|
||||
peer->owner().notifySettings().update(peer, { .unmute = true });
|
||||
}, &st::menuIconUnmute);
|
||||
addAction(text, with([=](not_null<Data::Thread*> thread) {
|
||||
notifySettings->update(thread, { .unmute = true });
|
||||
}), &st::menuIconUnmute);
|
||||
} else {
|
||||
const auto show = std::make_shared<Window::Show>(controller);
|
||||
addAction(PeerMenuCallback::Args{
|
||||
.text = tr::lng_context_mute(tr::now),
|
||||
.handler = nullptr,
|
||||
.icon = peer->owner().notifySettings().sound(peer).none
|
||||
.icon = (notifySettings->sound(thread).none
|
||||
? &st::menuIconSilent
|
||||
: &st::menuIconMute,
|
||||
: &st::menuIconMute),
|
||||
.fillSubmenu = [=](not_null<Ui::PopupMenu*> menu) {
|
||||
MuteMenu::FillMuteMenu(menu, { peer, show });
|
||||
if (const auto strong = weak.get()) {
|
||||
MuteMenu::FillMuteMenu(menu, strong, show);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
@ -209,8 +219,8 @@ private:
|
|||
|
||||
not_null<SessionController*> _controller;
|
||||
Dialogs::EntryState _request;
|
||||
Data::Thread *_thread = nullptr;
|
||||
PeerData *_peer = nullptr;
|
||||
Data::ForumTopic *_topic = nullptr;
|
||||
Data::Folder *_folder = nullptr;
|
||||
const PeerMenuCallback &_addAction;
|
||||
|
||||
|
@ -329,8 +339,8 @@ Filler::Filler(
|
|||
const PeerMenuCallback &addAction)
|
||||
: _controller(controller)
|
||||
, _request(request)
|
||||
, _thread(request.key.thread())
|
||||
, _peer(request.key.peer())
|
||||
, _topic(request.key.topic())
|
||||
, _folder(request.key.folder())
|
||||
, _addAction(addAction) {
|
||||
}
|
||||
|
@ -385,10 +395,10 @@ void Filler::addTogglePin() {
|
|||
}
|
||||
|
||||
void Filler::addToggleMuteSubmenu(bool addSeparator) {
|
||||
if (_peer->isSelf()) {
|
||||
if (_thread->peer()->isSelf()) {
|
||||
return;
|
||||
}
|
||||
PeerMenuAddMuteSubmenuAction(_controller, _peer, _addAction);
|
||||
PeerMenuAddMuteSubmenuAction(_controller, _thread, _addAction);
|
||||
if (addSeparator) {
|
||||
_addAction(PeerMenuCallback::Args{ .isSeparator = true });
|
||||
}
|
||||
|
@ -412,26 +422,30 @@ void Filler::addInfo() {
|
|||
if (_peer && (_peer->isSelf() || _peer->isRepliesChat())) {
|
||||
return;
|
||||
} else if (_controller->adaptive().isThreeColumn()) {
|
||||
const auto peer = _controller->activeChatCurrent().peer();
|
||||
const auto topic = _controller->activeChatCurrent().topic();
|
||||
if ((peer && peer == _peer) || (topic && topic == _topic)) {
|
||||
const auto thread = _controller->activeChatCurrent().thread();
|
||||
if (thread && thread == _thread) {
|
||||
if (Core::App().settings().thirdSectionInfoEnabled()
|
||||
|| Core::App().settings().tabbedReplacedWithInfo()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if (!_thread) {
|
||||
return;
|
||||
}
|
||||
const auto controller = _controller;
|
||||
const auto id = _topic ? _topic->rootId() : 0;
|
||||
const auto peer = _peer;
|
||||
const auto text = (peer->isChat() || peer->isMegagroup())
|
||||
const auto weak = base::make_weak(_thread);
|
||||
const auto text = _thread->asTopic()
|
||||
? u"View Topic Info"_q // #TODO lang-forum
|
||||
: (_peer->isChat() || _peer->isMegagroup())
|
||||
? tr::lng_context_view_group(tr::now)
|
||||
: (peer->isUser()
|
||||
? tr::lng_context_view_profile(tr::now)
|
||||
: tr::lng_context_view_channel(tr::now));
|
||||
: _peer->isUser()
|
||||
? tr::lng_context_view_profile(tr::now)
|
||||
: tr::lng_context_view_channel(tr::now);
|
||||
_addAction(text, [=] {
|
||||
controller->showPeerInfo(peer);
|
||||
}, peer->isUser() ? &st::menuIconProfile : &st::menuIconInfo);
|
||||
if (const auto strong = weak.get()) {
|
||||
controller->showPeerInfo(strong);
|
||||
}
|
||||
}, _peer->isUser() ? &st::menuIconProfile : &st::menuIconInfo);
|
||||
}
|
||||
|
||||
void Filler::addToggleFolder() {
|
||||
|
@ -547,7 +561,7 @@ void Filler::addDeleteChat() {
|
|||
|
||||
void Filler::addLeaveChat() {
|
||||
const auto channel = _peer->asChannel();
|
||||
if (_topic || !channel || !channel->amIn()) {
|
||||
if (_thread->asTopic() || !channel || !channel->amIn()) {
|
||||
return;
|
||||
}
|
||||
_addAction({
|
||||
|
@ -632,7 +646,7 @@ void Filler::addViewDiscussion() {
|
|||
}
|
||||
|
||||
void Filler::addExportChat() {
|
||||
if (_topic || !_peer->canExportChatHistory()) {
|
||||
if (_thread->asTopic() || !_peer->canExportChatHistory()) {
|
||||
return;
|
||||
}
|
||||
const auto peer = _peer;
|
||||
|
@ -748,15 +762,17 @@ void Filler::addDeleteContact() {
|
|||
}
|
||||
|
||||
void Filler::addManageTopic() {
|
||||
if (!_topic) {
|
||||
const auto topic = _thread->asTopic();
|
||||
if (!topic) {
|
||||
return;
|
||||
}
|
||||
// #TODO lang-forum
|
||||
const auto history = _topic->history();
|
||||
const auto rootId = _topic->rootId();
|
||||
const auto history = topic->history();
|
||||
const auto rootId = topic->rootId();
|
||||
const auto navigation = _controller;
|
||||
_addAction(u"Edit topic"_q, [=] {
|
||||
navigation->show(Box(EditForumTopicBox, navigation, history, rootId));
|
||||
navigation->show(
|
||||
Box(EditForumTopicBox, navigation, history, rootId));
|
||||
}, &st::menuIconEdit);
|
||||
}
|
||||
|
||||
|
@ -821,7 +837,7 @@ void Filler::addThemeEdit() {
|
|||
}
|
||||
|
||||
void Filler::addTTLSubmenu(bool addSeparator) {
|
||||
if (_topic) {
|
||||
if (_thread->asTopic()) {
|
||||
return; // #TODO later forum
|
||||
}
|
||||
const auto validator = TTLMenu::TTLValidator(
|
||||
|
@ -928,7 +944,7 @@ void Filler::fillProfileActions() {
|
|||
}
|
||||
|
||||
void Filler::fillRepliesActions() {
|
||||
if (_topic) {
|
||||
if (_thread->asTopic()) {
|
||||
addInfo();
|
||||
addManageTopic();
|
||||
addManageChat();
|
||||
|
@ -1498,35 +1514,6 @@ void UnpinAllMessages(
|
|||
Ui::LayerOption::CloseOther);
|
||||
}
|
||||
|
||||
void PeerMenuAddMuteAction(
|
||||
not_null<Window::SessionController*> controller,
|
||||
not_null<PeerData*> peer,
|
||||
const PeerMenuCallback &addAction) {
|
||||
// There is no async to make weak from controller.
|
||||
peer->owner().notifySettings().request(peer);
|
||||
const auto muteText = [](bool isUnmuted) {
|
||||
return isUnmuted
|
||||
? tr::lng_context_mute(tr::now)
|
||||
: tr::lng_context_unmute(tr::now);
|
||||
};
|
||||
const auto muteAction = addAction(QString("-"), [=] {
|
||||
if (!peer->owner().notifySettings().isMuted(peer)) {
|
||||
controller->show(
|
||||
Box<MuteSettingsBox>(peer),
|
||||
Ui::LayerOption::CloseOther);
|
||||
} else {
|
||||
peer->owner().notifySettings().update(peer, { .unmute = true });
|
||||
}
|
||||
}, (peer->owner().notifySettings().isMuted(peer)
|
||||
? &st::menuIconUnmute
|
||||
: &st::menuIconMute));
|
||||
|
||||
auto actionText = Info::Profile::NotificationsEnabledValue(
|
||||
peer
|
||||
) | rpl::map(muteText);
|
||||
SetActionText(muteAction, std::move(actionText));
|
||||
}
|
||||
|
||||
void MenuAddMarkAsReadAllChatsAction(
|
||||
not_null<Window::SessionController*> controller,
|
||||
const PeerMenuCallback &addAction) {
|
||||
|
|
|
@ -46,11 +46,6 @@ void FillDialogsEntryMenu(
|
|||
Dialogs::EntryState request,
|
||||
const PeerMenuCallback &addAction);
|
||||
|
||||
void PeerMenuAddMuteAction(
|
||||
not_null<Window::SessionController*> controller,
|
||||
not_null<PeerData*> peer,
|
||||
const PeerMenuCallback &addAction);
|
||||
|
||||
void MenuAddMarkAsReadAllChatsAction(
|
||||
not_null<Window::SessionController*> controller,
|
||||
const PeerMenuCallback &addAction);
|
||||
|
|
|
@ -567,9 +567,13 @@ void SessionNavigation::showPeerInfo(
|
|||
}
|
||||
|
||||
void SessionNavigation::showPeerInfo(
|
||||
not_null<History*> history,
|
||||
not_null<Data::Thread*> thread,
|
||||
const SectionShow ¶ms) {
|
||||
showPeerInfo(history->peer->id, params);
|
||||
if (const auto topic = thread->asTopic()) {
|
||||
showSection(std::make_shared<Info::Memento>(topic), params);
|
||||
} else {
|
||||
showPeerInfo(thread->peer()->id, params);
|
||||
}
|
||||
}
|
||||
|
||||
void SessionNavigation::showPeerHistory(
|
||||
|
|
|
@ -69,6 +69,7 @@ class MessageSendingAnimationController;
|
|||
namespace Data {
|
||||
struct CloudTheme;
|
||||
enum class CloudThemeType;
|
||||
class Thread;
|
||||
} // namespace Data
|
||||
|
||||
namespace HistoryView::Reactions {
|
||||
|
@ -219,7 +220,7 @@ public:
|
|||
not_null<PeerData*> peer,
|
||||
const SectionShow ¶ms = SectionShow());
|
||||
void showPeerInfo(
|
||||
not_null<History*> history,
|
||||
not_null<Data::Thread*> thread,
|
||||
const SectionShow ¶ms = SectionShow());
|
||||
|
||||
virtual void showPeerHistory(
|
||||
|
|
Loading…
Add table
Reference in a new issue