mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-22 17:17:15 +02:00
One Window::Notifications system for all sessions.
This commit is contained in:
parent
83538675ce
commit
997913be25
28 changed files with 578 additions and 297 deletions
|
@ -2601,7 +2601,7 @@ void ApiWrap::applyNotifySettings(
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
_session->notifications().checkDelayed();
|
Core::App().notifications().checkDelayed();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApiWrap::gotStickerSet(uint64 setId, const MTPmessages_StickerSet &result) {
|
void ApiWrap::gotStickerSet(uint64 setId, const MTPmessages_StickerSet &result) {
|
||||||
|
|
|
@ -99,6 +99,7 @@ Application::Application(not_null<Launcher*> launcher)
|
||||||
, _fallbackProductionConfig(
|
, _fallbackProductionConfig(
|
||||||
std::make_unique<MTP::Config>(MTP::Environment::Production))
|
std::make_unique<MTP::Config>(MTP::Environment::Production))
|
||||||
, _domain(std::make_unique<Main::Domain>(cDataFile()))
|
, _domain(std::make_unique<Main::Domain>(cDataFile()))
|
||||||
|
, _notifications(std::make_unique<Window::Notifications::System>())
|
||||||
, _langpack(std::make_unique<Lang::Instance>())
|
, _langpack(std::make_unique<Lang::Instance>())
|
||||||
, _langCloudManager(std::make_unique<Lang::CloudManager>(langpack()))
|
, _langCloudManager(std::make_unique<Lang::CloudManager>(langpack()))
|
||||||
, _emojiKeywords(std::make_unique<ChatHelpers::EmojiKeywords>())
|
, _emojiKeywords(std::make_unique<ChatHelpers::EmojiKeywords>())
|
||||||
|
@ -116,6 +117,11 @@ Application::Application(not_null<Launcher*> launcher)
|
||||||
_shouldLockAt = 0;
|
_shouldLockAt = 0;
|
||||||
}, _lifetime);
|
}, _lifetime);
|
||||||
|
|
||||||
|
passcodeLockChanges(
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
_notifications->updateAll();
|
||||||
|
}, _lifetime);
|
||||||
|
|
||||||
_domain->activeSessionChanges(
|
_domain->activeSessionChanges(
|
||||||
) | rpl::start_with_next([=](Main::Session *session) {
|
) | rpl::start_with_next([=](Main::Session *session) {
|
||||||
if (session && !UpdaterDisabled()) { // #TODO multi someSessionValue
|
if (session && !UpdaterDisabled()) { // #TODO multi someSessionValue
|
||||||
|
|
|
@ -27,6 +27,12 @@ struct TermsLock;
|
||||||
class Controller;
|
class Controller;
|
||||||
} // namespace Window
|
} // namespace Window
|
||||||
|
|
||||||
|
namespace Window {
|
||||||
|
namespace Notifications {
|
||||||
|
class System;
|
||||||
|
} // namespace Notifications
|
||||||
|
} // namespace Window
|
||||||
|
|
||||||
namespace ChatHelpers {
|
namespace ChatHelpers {
|
||||||
class EmojiKeywords;
|
class EmojiKeywords;
|
||||||
} // namespace ChatHelpers
|
} // namespace ChatHelpers
|
||||||
|
@ -101,6 +107,9 @@ public:
|
||||||
[[nodiscard]] Ui::Animations::Manager &animationManager() const {
|
[[nodiscard]] Ui::Animations::Manager &animationManager() const {
|
||||||
return *_animationsManager;
|
return *_animationsManager;
|
||||||
}
|
}
|
||||||
|
[[nodiscard]] Window::Notifications::System ¬ifications() const {
|
||||||
|
return *_notifications;
|
||||||
|
}
|
||||||
|
|
||||||
// Windows interface.
|
// Windows interface.
|
||||||
bool hasActiveWindow(not_null<Main::Session*> session) const;
|
bool hasActiveWindow(not_null<Main::Session*> session) const;
|
||||||
|
@ -294,6 +303,10 @@ private:
|
||||||
QPointer<Ui::BoxContent> _badProxyDisableBox;
|
QPointer<Ui::BoxContent> _badProxyDisableBox;
|
||||||
|
|
||||||
const std::unique_ptr<Media::Audio::Instance> _audio;
|
const std::unique_ptr<Media::Audio::Instance> _audio;
|
||||||
|
|
||||||
|
// Notifications should be destroyed before _audio.
|
||||||
|
const std::unique_ptr<Window::Notifications::System> _notifications;
|
||||||
|
|
||||||
const QImage _logo;
|
const QImage _logo;
|
||||||
const QImage _logoNoMargin;
|
const QImage _logoNoMargin;
|
||||||
|
|
||||||
|
|
|
@ -165,7 +165,7 @@ void Histories::readInboxTill(
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
history->session().notifications().clearIncomingFromHistory(history);
|
Core::App().notifications().clearIncomingFromHistory(history);
|
||||||
|
|
||||||
const auto needsRequest = history->readInboxTillNeedsRequest(tillId);
|
const auto needsRequest = history->readInboxTillNeedsRequest(tillId);
|
||||||
if (!needsRequest && !force) {
|
if (!needsRequest && !force) {
|
||||||
|
|
|
@ -1110,7 +1110,7 @@ void Session::setupUserIsContactViewer() {
|
||||||
|
|
||||||
Session::~Session() {
|
Session::~Session() {
|
||||||
// Optimization: clear notifications before destroying items.
|
// Optimization: clear notifications before destroying items.
|
||||||
_session->notifications().clearAllFast();
|
Core::App().notifications().clearFromSession(_session);
|
||||||
clearLocalStorage();
|
clearLocalStorage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1980,7 +1980,7 @@ void Session::updateNotifySettingsLocal(not_null<PeerData*> peer) {
|
||||||
_mutedPeers.emplace(peer);
|
_mutedPeers.emplace(peer);
|
||||||
unmuteByFinishedDelayed(changesIn);
|
unmuteByFinishedDelayed(changesIn);
|
||||||
if (history) {
|
if (history) {
|
||||||
_session->notifications().clearIncomingFromHistory(history);
|
Core::App().notifications().clearIncomingFromHistory(history);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_mutedPeers.erase(peer);
|
_mutedPeers.erase(peer);
|
||||||
|
@ -3488,7 +3488,7 @@ void Session::removeChatListEntry(Dialogs::Key key) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (const auto history = key.history()) {
|
if (const auto history = key.history()) {
|
||||||
session().notifications().clearFromHistory(history);
|
Core::App().notifications().clearFromHistory(history);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "history/history.h"
|
#include "history/history.h"
|
||||||
#include "history/history_item.h"
|
#include "history/history_item.h"
|
||||||
#include "core/shortcuts.h"
|
#include "core/shortcuts.h"
|
||||||
|
#include "core/application.h"
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
#include "ui/widgets/popup_menu.h"
|
#include "ui/widgets/popup_menu.h"
|
||||||
#include "ui/text/text_utilities.h"
|
#include "ui/text/text_utilities.h"
|
||||||
|
@ -133,7 +134,7 @@ InnerWidget::InnerWidget(
|
||||||
|
|
||||||
subscribe(session().downloaderTaskFinished(), [=] { update(); });
|
subscribe(session().downloaderTaskFinished(), [=] { update(); });
|
||||||
|
|
||||||
subscribe(session().notifications().settingsChanged(), [=](
|
subscribe(Core::App().notifications().settingsChanged(), [=](
|
||||||
Window::Notifications::ChangeType change) {
|
Window::Notifications::ChangeType change) {
|
||||||
if (change == Window::Notifications::ChangeType::CountMessages) {
|
if (change == Window::Notifications::ChangeType::CountMessages) {
|
||||||
// Folder rows change their unread badge with this setting.
|
// Folder rows change their unread badge with this setting.
|
||||||
|
|
|
@ -43,6 +43,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/image/image.h"
|
#include "ui/image/image.h"
|
||||||
#include "ui/text_options.h"
|
#include "ui/text_options.h"
|
||||||
#include "core/crash_reports.h"
|
#include "core/crash_reports.h"
|
||||||
|
#include "core/application.h"
|
||||||
#include "base/unixtime.h"
|
#include "base/unixtime.h"
|
||||||
#include "styles/style_dialogs.h"
|
#include "styles/style_dialogs.h"
|
||||||
|
|
||||||
|
@ -671,7 +672,7 @@ void History::destroyMessage(not_null<HistoryItem*> item) {
|
||||||
}
|
}
|
||||||
|
|
||||||
owner().unregisterMessage(item);
|
owner().unregisterMessage(item);
|
||||||
session().notifications().clearFromItem(item);
|
Core::App().notifications().clearFromItem(item);
|
||||||
|
|
||||||
auto hack = std::unique_ptr<HistoryItem>(item.get());
|
auto hack = std::unique_ptr<HistoryItem>(item.get());
|
||||||
const auto i = _messages.find(hack);
|
const auto i = _messages.find(hack);
|
||||||
|
@ -1290,7 +1291,7 @@ void History::newItemAdded(not_null<HistoryItem*> item) {
|
||||||
owner().notifyUnreadItemAdded(item);
|
owner().notifyUnreadItemAdded(item);
|
||||||
const auto stillShow = item->showNotification();
|
const auto stillShow = item->showNotification();
|
||||||
if (stillShow) {
|
if (stillShow) {
|
||||||
session().notifications().schedule(item);
|
Core::App().notifications().schedule(item);
|
||||||
if (!item->out() && item->unread()) {
|
if (!item->out() && item->unread()) {
|
||||||
if (unreadCountKnown()) {
|
if (unreadCountKnown()) {
|
||||||
setUnreadCount(unreadCount() + 1);
|
setUnreadCount(unreadCount() + 1);
|
||||||
|
@ -1741,7 +1742,7 @@ void History::inboxRead(MsgId upTo, std::optional<int> stillUnread) {
|
||||||
}
|
}
|
||||||
|
|
||||||
_firstUnreadView = nullptr;
|
_firstUnreadView = nullptr;
|
||||||
session().notifications().clearIncomingFromHistory(this);
|
Core::App().notifications().clearIncomingFromHistory(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void History::inboxRead(not_null<const HistoryItem*> wasRead) {
|
void History::inboxRead(not_null<const HistoryItem*> wasRead) {
|
||||||
|
|
|
@ -2057,7 +2057,7 @@ void HistoryInner::checkHistoryActivation() {
|
||||||
adjustCurrent(_visibleAreaBottom);
|
adjustCurrent(_visibleAreaBottom);
|
||||||
if (_history->loadedAtBottom() && _visibleAreaBottom >= height()) {
|
if (_history->loadedAtBottom() && _visibleAreaBottom >= height()) {
|
||||||
// Clear possible scheduled messages notifications.
|
// Clear possible scheduled messages notifications.
|
||||||
session().notifications().clearFromHistory(_history);
|
Core::App().notifications().clearFromHistory(_history);
|
||||||
}
|
}
|
||||||
if (_curHistory != _history || _history->isEmpty()) {
|
if (_curHistory != _history || _history->isEmpty()) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -24,6 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_channel.h"
|
#include "data/data_channel.h"
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
#include "data/data_changes.h"
|
#include "data/data_changes.h"
|
||||||
|
#include "core/application.h"
|
||||||
#include "window/notifications_manager.h"
|
#include "window/notifications_manager.h"
|
||||||
#include "window/window_session_controller.h"
|
#include "window/window_session_controller.h"
|
||||||
#include "storage/storage_shared_media.h"
|
#include "storage/storage_shared_media.h"
|
||||||
|
@ -355,7 +356,7 @@ bool HistoryService::updateDependent(bool force) {
|
||||||
updateDependentText();
|
updateDependentText();
|
||||||
}
|
}
|
||||||
if (force && gotDependencyItem) {
|
if (force && gotDependencyItem) {
|
||||||
history()->session().notifications().checkDelayed();
|
Core::App().notifications().checkDelayed();
|
||||||
}
|
}
|
||||||
return (dependent->msg || !dependent->msgId);
|
return (dependent->msg || !dependent->msgId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2423,7 +2423,7 @@ void HistoryWidget::unreadMessageAdded(not_null<HistoryItem*> item) {
|
||||||
session().data().histories().readInboxOnNewMessage(item);
|
session().data().histories().readInboxOnNewMessage(item);
|
||||||
|
|
||||||
// Also clear possible scheduled messages notifications.
|
// Also clear possible scheduled messages notifications.
|
||||||
session().notifications().clearFromHistory(_history);
|
Core::App().notifications().clearFromHistory(_history);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::unreadCountUpdated() {
|
void HistoryWidget::unreadCountUpdated() {
|
||||||
|
|
|
@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "mtproto/mtproto_dc_options.h"
|
#include "mtproto/mtproto_dc_options.h"
|
||||||
#include "storage/storage_domain.h"
|
#include "storage/storage_domain.h"
|
||||||
#include "storage/localstorage.h"
|
#include "storage/localstorage.h"
|
||||||
|
#include "window/notifications_manager.h"
|
||||||
#include "facades.h"
|
#include "facades.h"
|
||||||
|
|
||||||
namespace Main {
|
namespace Main {
|
||||||
|
@ -47,22 +48,25 @@ Storage::StartResult Domain::start(const QByteArray &passcode) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Domain::finish() {
|
void Domain::finish() {
|
||||||
_activeIndex = -1;
|
_accountToActivate = -1;
|
||||||
_active = nullptr;
|
_active = nullptr;
|
||||||
base::take(_accounts);
|
base::take(_accounts);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Domain::accountAddedInStorage(
|
void Domain::accountAddedInStorage(AccountWithIndex accountWithIndex) {
|
||||||
int index,
|
Expects(accountWithIndex.account != nullptr);
|
||||||
std::unique_ptr<Account> account) {
|
|
||||||
Expects(account != nullptr);
|
|
||||||
Expects(!_accounts.contains(index));
|
|
||||||
|
|
||||||
if (_accounts.empty()) {
|
for (const auto &[index, _] : _accounts) {
|
||||||
_activeIndex = index;
|
if (index == accountWithIndex.index) {
|
||||||
|
Unexpected("Repeated account index.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_accounts.push_back(std::move(accountWithIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Domain::activateFromStorage(int index) {
|
||||||
|
_accountToActivate = index;
|
||||||
}
|
}
|
||||||
_accounts.emplace(index, std::move(account));
|
|
||||||
};
|
|
||||||
|
|
||||||
void Domain::resetWithForgottenPasscode() {
|
void Domain::resetWithForgottenPasscode() {
|
||||||
if (_accounts.empty()) {
|
if (_accounts.empty()) {
|
||||||
|
@ -78,15 +82,19 @@ void Domain::resetWithForgottenPasscode() {
|
||||||
void Domain::activateAfterStarting() {
|
void Domain::activateAfterStarting() {
|
||||||
Expects(started());
|
Expects(started());
|
||||||
|
|
||||||
|
auto toActivate = _accounts.front().account.get();
|
||||||
for (const auto &[index, account] : _accounts) {
|
for (const auto &[index, account] : _accounts) {
|
||||||
|
if (index == _accountToActivate) {
|
||||||
|
toActivate = account.get();
|
||||||
|
}
|
||||||
watchSession(account.get());
|
watchSession(account.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
activate(_activeIndex);
|
activate(toActivate);
|
||||||
removePasscodeIfEmpty();
|
removePasscodeIfEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
const base::flat_map<int, std::unique_ptr<Account>> &Domain::accounts() const {
|
const std::vector<Domain::AccountWithIndex> &Domain::accounts() const {
|
||||||
return _accounts;
|
return _accounts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,12 +102,6 @@ rpl::producer<Account*> Domain::activeValue() const {
|
||||||
return _active.value();
|
return _active.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
int Domain::activeIndex() const {
|
|
||||||
Expects(_accounts.contains(_activeIndex));
|
|
||||||
|
|
||||||
return _activeIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
Account &Domain::active() const {
|
Account &Domain::active() const {
|
||||||
Expects(!_accounts.empty());
|
Expects(!_accounts.empty());
|
||||||
|
|
||||||
|
@ -170,8 +172,8 @@ void Domain::scheduleUpdateUnreadBadge() {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
int Domain::add(MTP::Environment environment) {
|
not_null<Main::Account*> Domain::add(MTP::Environment environment) {
|
||||||
Expects(_active.current() != nullptr);
|
Expects(started());
|
||||||
|
|
||||||
static const auto cloneConfig = [](const MTP::Config &config) {
|
static const auto cloneConfig = [](const MTP::Config &config) {
|
||||||
return std::make_unique<MTP::Config>(config);
|
return std::make_unique<MTP::Config>(config);
|
||||||
|
@ -193,16 +195,17 @@ int Domain::add(MTP::Environment environment) {
|
||||||
: std::make_unique<MTP::Config>(environment);
|
: std::make_unique<MTP::Config>(environment);
|
||||||
}();
|
}();
|
||||||
auto index = 0;
|
auto index = 0;
|
||||||
while (_accounts.contains(index)) {
|
while (ranges::contains(_accounts, index, &AccountWithIndex::index)) {
|
||||||
++index;
|
++index;
|
||||||
}
|
}
|
||||||
const auto account = _accounts.emplace(
|
_accounts.push_back(AccountWithIndex{
|
||||||
index,
|
.index = index,
|
||||||
std::make_unique<Account>(this, _dataName, index)
|
.account = std::make_unique<Account>(this, _dataName, index)
|
||||||
).first->second.get();
|
});
|
||||||
|
const auto account = _accounts.back().account.get();
|
||||||
_local->startAdded(account, std::move(config));
|
_local->startAdded(account, std::move(config));
|
||||||
watchSession(account);
|
watchSession(account);
|
||||||
return index;
|
return account;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Domain::watchSession(not_null<Account*> account) {
|
void Domain::watchSession(not_null<Account*> account) {
|
||||||
|
@ -237,8 +240,8 @@ void Domain::activateAuthedAccount() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (auto i = _accounts.begin(); i != _accounts.end(); ++i) {
|
for (auto i = _accounts.begin(); i != _accounts.end(); ++i) {
|
||||||
if (i->second->sessionExists()) {
|
if (i->account->sessionExists()) {
|
||||||
activate(i->first);
|
activate(i->account.get());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -264,12 +267,12 @@ void Domain::removeRedundantAccounts() {
|
||||||
const auto was = _accounts.size();
|
const auto was = _accounts.size();
|
||||||
activateAuthedAccount();
|
activateAuthedAccount();
|
||||||
for (auto i = _accounts.begin(); i != _accounts.end();) {
|
for (auto i = _accounts.begin(); i != _accounts.end();) {
|
||||||
if (i->second.get() == _active.current()
|
if (i->account.get() == _active.current()
|
||||||
|| i->second->sessionExists()) {
|
|| i->account->sessionExists()) {
|
||||||
++i;
|
++i;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
checkForLastProductionConfig(i->second.get());
|
checkForLastProductionConfig(i->account.get());
|
||||||
i = _accounts.erase(i);
|
i = _accounts.erase(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -293,13 +296,20 @@ void Domain::checkForLastProductionConfig(
|
||||||
Core::App().refreshFallbackProductionConfig(mtp->config());
|
Core::App().refreshFallbackProductionConfig(mtp->config());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Domain::activate(int index) {
|
void Domain::activate(not_null<Main::Account*> account) {
|
||||||
Expects(_accounts.contains(index));
|
if (_active.current() == account.get()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto i = ranges::find(_accounts, account.get(), [](
|
||||||
|
const AccountWithIndex &value) {
|
||||||
|
return value.account.get();
|
||||||
|
});
|
||||||
|
Assert(i != end(_accounts));
|
||||||
|
const auto changed = (_accountToActivate != i->index);
|
||||||
|
|
||||||
const auto changed = (_activeIndex != index);
|
|
||||||
_activeLifetime.destroy();
|
_activeLifetime.destroy();
|
||||||
_activeIndex = index;
|
_accountToActivate = i->index;
|
||||||
_active = _accounts.find(index)->second.get();
|
_active = account.get();
|
||||||
_active.current()->sessionValue(
|
_active.current()->sessionValue(
|
||||||
) | rpl::start_to_stream(_activeSessions, _activeLifetime);
|
) | rpl::start_to_stream(_activeSessions, _activeLifetime);
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,11 @@ class Session;
|
||||||
|
|
||||||
class Domain final {
|
class Domain final {
|
||||||
public:
|
public:
|
||||||
|
struct AccountWithIndex {
|
||||||
|
int index = 0;
|
||||||
|
std::unique_ptr<Account> account;
|
||||||
|
};
|
||||||
|
|
||||||
static constexpr auto kMaxAccounts = 3;
|
static constexpr auto kMaxAccounts = 3;
|
||||||
|
|
||||||
explicit Domain(const QString &dataName);
|
explicit Domain(const QString &dataName);
|
||||||
|
@ -40,11 +45,10 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto accounts() const
|
[[nodiscard]] auto accounts() const
|
||||||
-> const base::flat_map<int, std::unique_ptr<Account>> &;
|
-> const std::vector<AccountWithIndex> &;
|
||||||
[[nodiscard]] rpl::producer<Account*> activeValue() const;
|
[[nodiscard]] rpl::producer<Account*> activeValue() const;
|
||||||
|
|
||||||
// Expects(started());
|
// Expects(started());
|
||||||
[[nodiscard]] int activeIndex() const;
|
|
||||||
[[nodiscard]] Account &active() const;
|
[[nodiscard]] Account &active() const;
|
||||||
[[nodiscard]] rpl::producer<not_null<Account*>> activeChanges() const;
|
[[nodiscard]] rpl::producer<not_null<Account*>> activeChanges() const;
|
||||||
|
|
||||||
|
@ -56,11 +60,12 @@ public:
|
||||||
[[nodiscard]] rpl::producer<> unreadBadgeChanges() const;
|
[[nodiscard]] rpl::producer<> unreadBadgeChanges() const;
|
||||||
void notifyUnreadBadgeChanged();
|
void notifyUnreadBadgeChanged();
|
||||||
|
|
||||||
[[nodiscard]] int add(MTP::Environment environment);
|
[[nodiscard]] not_null<Main::Account*> add(MTP::Environment environment);
|
||||||
void activate(int index);
|
void activate(not_null<Main::Account*> account);
|
||||||
|
|
||||||
// Interface for Storage::Domain.
|
// Interface for Storage::Domain.
|
||||||
void accountAddedInStorage(int index, std::unique_ptr<Account> account);
|
void accountAddedInStorage(AccountWithIndex accountWithIndex);
|
||||||
|
void activateFromStorage(int index);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void activateAfterStarting();
|
void activateAfterStarting();
|
||||||
|
@ -76,9 +81,9 @@ private:
|
||||||
const QString _dataName;
|
const QString _dataName;
|
||||||
const std::unique_ptr<Storage::Domain> _local;
|
const std::unique_ptr<Storage::Domain> _local;
|
||||||
|
|
||||||
base::flat_map<int, std::unique_ptr<Account>> _accounts;
|
std::vector<AccountWithIndex> _accounts;
|
||||||
rpl::variable<Account*> _active = nullptr;
|
rpl::variable<Account*> _active = nullptr;
|
||||||
int _activeIndex = 0;
|
int _accountToActivate = -1;
|
||||||
bool _writeAccountsScheduled = false;
|
bool _writeAccountsScheduled = false;
|
||||||
|
|
||||||
rpl::event_stream<Session*> _activeSessions;
|
rpl::event_stream<Session*> _activeSessions;
|
||||||
|
|
|
@ -25,7 +25,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_changes.h"
|
#include "data/data_changes.h"
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
#include "window/notifications_manager.h"
|
|
||||||
#include "window/window_session_controller.h"
|
#include "window/window_session_controller.h"
|
||||||
#include "window/themes/window_theme.h"
|
#include "window/themes/window_theme.h"
|
||||||
//#include "platform/platform_specific.h"
|
//#include "platform/platform_specific.h"
|
||||||
|
@ -75,7 +74,6 @@ Session::Session(
|
||||||
, _downloader(std::make_unique<Storage::DownloadManagerMtproto>(_api.get()))
|
, _downloader(std::make_unique<Storage::DownloadManagerMtproto>(_api.get()))
|
||||||
, _uploader(std::make_unique<Storage::Uploader>(_api.get()))
|
, _uploader(std::make_unique<Storage::Uploader>(_api.get()))
|
||||||
, _storage(std::make_unique<Storage::Facade>())
|
, _storage(std::make_unique<Storage::Facade>())
|
||||||
, _notifications(std::make_unique<Window::Notifications::System>(this))
|
|
||||||
, _changes(std::make_unique<Data::Changes>(this))
|
, _changes(std::make_unique<Data::Changes>(this))
|
||||||
, _data(std::make_unique<Data::Session>(this))
|
, _data(std::make_unique<Data::Session>(this))
|
||||||
, _user(_data->processUser(user))
|
, _user(_data->processUser(user))
|
||||||
|
@ -85,11 +83,6 @@ Session::Session(
|
||||||
, _saveSettingsTimer([=] { saveSettings(); }) {
|
, _saveSettingsTimer([=] { saveSettings(); }) {
|
||||||
Expects(_settings != nullptr);
|
Expects(_settings != nullptr);
|
||||||
|
|
||||||
Core::App().lockChanges(
|
|
||||||
) | rpl::start_with_next([=] {
|
|
||||||
notifications().updateAll();
|
|
||||||
}, _lifetime);
|
|
||||||
|
|
||||||
subscribe(Global::RefConnectionTypeChanged(), [=] {
|
subscribe(Global::RefConnectionTypeChanged(), [=] {
|
||||||
_api->refreshTopPromotion();
|
_api->refreshTopPromotion();
|
||||||
});
|
});
|
||||||
|
|
|
@ -42,9 +42,6 @@ class Domain;
|
||||||
} // namespace Storage
|
} // namespace Storage
|
||||||
|
|
||||||
namespace Window {
|
namespace Window {
|
||||||
namespace Notifications {
|
|
||||||
class System;
|
|
||||||
} // namespace Notifications
|
|
||||||
class SessionController;
|
class SessionController;
|
||||||
} // namespace Window
|
} // namespace Window
|
||||||
|
|
||||||
|
@ -106,9 +103,6 @@ public:
|
||||||
[[nodiscard]] Stickers::DicePacks &diceStickersPacks() const {
|
[[nodiscard]] Stickers::DicePacks &diceStickersPacks() const {
|
||||||
return *_diceStickersPacks;
|
return *_diceStickersPacks;
|
||||||
}
|
}
|
||||||
[[nodiscard]] Window::Notifications::System ¬ifications() const {
|
|
||||||
return *_notifications;
|
|
||||||
}
|
|
||||||
[[nodiscard]] Data::Changes &changes() const {
|
[[nodiscard]] Data::Changes &changes() const {
|
||||||
return *_changes;
|
return *_changes;
|
||||||
}
|
}
|
||||||
|
@ -168,9 +162,8 @@ private:
|
||||||
const std::unique_ptr<Storage::DownloadManagerMtproto> _downloader;
|
const std::unique_ptr<Storage::DownloadManagerMtproto> _downloader;
|
||||||
const std::unique_ptr<Storage::Uploader> _uploader;
|
const std::unique_ptr<Storage::Uploader> _uploader;
|
||||||
const std::unique_ptr<Storage::Facade> _storage;
|
const std::unique_ptr<Storage::Facade> _storage;
|
||||||
const std::unique_ptr<Window::Notifications::System> _notifications;
|
|
||||||
|
|
||||||
// _data depends on _downloader / _uploader / _notifications.
|
// _data depends on _downloader / _uploader.
|
||||||
const std::unique_ptr<Data::Changes> _changes;
|
const std::unique_ptr<Data::Changes> _changes;
|
||||||
const std::unique_ptr<Data::Session> _data;
|
const std::unique_ptr<Data::Session> _data;
|
||||||
const not_null<UserData*> _user;
|
const not_null<UserData*> _user;
|
||||||
|
|
|
@ -814,7 +814,7 @@ void MainWindow::toggleDisplayNotifyFromTray() {
|
||||||
}
|
}
|
||||||
account().session().saveSettings();
|
account().session().saveSettings();
|
||||||
using Change = Window::Notifications::ChangeType;
|
using Change = Window::Notifications::ChangeType;
|
||||||
auto &changes = account().session().notifications().settingsChanged();
|
auto &changes = Core::App().notifications().settingsChanged();
|
||||||
changes.notify(Change::DesktopEnabled);
|
changes.notify(Change::DesktopEnabled);
|
||||||
if (soundNotifyChanged) {
|
if (soundNotifyChanged) {
|
||||||
changes.notify(Change::SoundEnabled);
|
changes.notify(Change::SoundEnabled);
|
||||||
|
|
|
@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "core/application.h"
|
#include "core/application.h"
|
||||||
#include "core/core_settings.h"
|
#include "core/core_settings.h"
|
||||||
#include "history/history.h"
|
#include "history/history.h"
|
||||||
|
#include "main/main_session.h"
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
|
|
||||||
#include <QtCore/QVersionNumber>
|
#include <QtCore/QVersionNumber>
|
||||||
|
@ -201,7 +202,7 @@ QString GetImageKey(const QVersionNumber &specificationVersion) {
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace
|
||||||
|
|
||||||
NotificationData::NotificationData(
|
NotificationData::NotificationData(
|
||||||
const base::weak_ptr<Manager> &manager,
|
const base::weak_ptr<Manager> &manager,
|
||||||
|
@ -210,6 +211,7 @@ NotificationData::NotificationData(
|
||||||
const QString &msg,
|
const QString &msg,
|
||||||
PeerId peerId,
|
PeerId peerId,
|
||||||
MsgId msgId,
|
MsgId msgId,
|
||||||
|
UserId selfId,
|
||||||
bool hideReplyButton)
|
bool hideReplyButton)
|
||||||
: _dbusConnection(QDBusConnection::sessionBus())
|
: _dbusConnection(QDBusConnection::sessionBus())
|
||||||
, _manager(manager)
|
, _manager(manager)
|
||||||
|
@ -217,7 +219,8 @@ NotificationData::NotificationData(
|
||||||
, _imageKey(GetImageKey(ParseSpecificationVersion(
|
, _imageKey(GetImageKey(ParseSpecificationVersion(
|
||||||
GetServerInformation())))
|
GetServerInformation())))
|
||||||
, _peerId(peerId)
|
, _peerId(peerId)
|
||||||
, _msgId(msgId) {
|
, _msgId(msgId)
|
||||||
|
, _selfId(selfId) {
|
||||||
const auto capabilities = GetCapabilities();
|
const auto capabilities = GetCapabilities();
|
||||||
|
|
||||||
if (capabilities.contains(qsl("body-markup"))) {
|
if (capabilities.contains(qsl("body-markup"))) {
|
||||||
|
@ -374,11 +377,16 @@ void NotificationData::setImage(const QString &imagePath) {
|
||||||
_hints[_imageKey] = QVariant::fromValue(imageData);
|
_hints[_imageKey] = QVariant::fromValue(imageData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NotificationData::NotificationId NotificationData::myId() const {
|
||||||
|
return { .peerId = _peerId, .msgId = _msgId, .selfId = _selfId };
|
||||||
|
}
|
||||||
|
|
||||||
void NotificationData::notificationClosed(uint id) {
|
void NotificationData::notificationClosed(uint id) {
|
||||||
if (id == _notificationId) {
|
if (id == _notificationId) {
|
||||||
const auto manager = _manager;
|
const auto manager = _manager;
|
||||||
|
const auto my = myId();
|
||||||
crl::on_main(manager, [=] {
|
crl::on_main(manager, [=] {
|
||||||
manager->clearNotification(_peerId, _msgId);
|
manager->clearNotification(my);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -391,13 +399,15 @@ void NotificationData::actionInvoked(uint id, const QString &actionName) {
|
||||||
if (actionName == qsl("default")
|
if (actionName == qsl("default")
|
||||||
|| actionName == qsl("mail-reply-sender")) {
|
|| actionName == qsl("mail-reply-sender")) {
|
||||||
const auto manager = _manager;
|
const auto manager = _manager;
|
||||||
|
const auto my = myId();
|
||||||
crl::on_main(manager, [=] {
|
crl::on_main(manager, [=] {
|
||||||
manager->notificationActivated(_peerId, _msgId);
|
manager->notificationActivated(my);
|
||||||
});
|
});
|
||||||
} else if (actionName == qsl("mail-mark-read")) {
|
} else if (actionName == qsl("mail-mark-read")) {
|
||||||
const auto manager = _manager;
|
const auto manager = _manager;
|
||||||
|
const auto my = myId();
|
||||||
crl::on_main(manager, [=] {
|
crl::on_main(manager, [=] {
|
||||||
manager->notificationReplied(_peerId, _msgId, {});
|
manager->notificationReplied(my, {});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -405,8 +415,9 @@ void NotificationData::actionInvoked(uint id, const QString &actionName) {
|
||||||
void NotificationData::notificationReplied(uint id, const QString &text) {
|
void NotificationData::notificationReplied(uint id, const QString &text) {
|
||||||
if (id == _notificationId) {
|
if (id == _notificationId) {
|
||||||
const auto manager = _manager;
|
const auto manager = _manager;
|
||||||
|
const auto my = myId();
|
||||||
crl::on_main(manager, [=] {
|
crl::on_main(manager, [=] {
|
||||||
manager->notificationReplied(_peerId, _msgId, { text, {} });
|
manager->notificationReplied(my, { text, {} });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -530,6 +541,9 @@ void Manager::Private::showNotification(
|
||||||
bool hideReplyButton) {
|
bool hideReplyButton) {
|
||||||
if (!Supported()) return;
|
if (!Supported()) return;
|
||||||
|
|
||||||
|
const auto peerId = peer->id;
|
||||||
|
const auto selfId = peer->session().userId();
|
||||||
|
const auto key = FullPeer{ peerId, selfId };
|
||||||
auto notification = std::make_shared<NotificationData>(
|
auto notification = std::make_shared<NotificationData>(
|
||||||
_manager,
|
_manager,
|
||||||
title,
|
title,
|
||||||
|
@ -537,32 +551,38 @@ void Manager::Private::showNotification(
|
||||||
msg,
|
msg,
|
||||||
peer->id,
|
peer->id,
|
||||||
msgId,
|
msgId,
|
||||||
|
peer->session().userId(),
|
||||||
hideReplyButton);
|
hideReplyButton);
|
||||||
|
|
||||||
if (!hideNameAndPhoto) {
|
if (!hideNameAndPhoto) {
|
||||||
const auto key = peer->userpicUniqueKey(userpicView);
|
const auto userpicKey = peer->userpicUniqueKey(userpicView);
|
||||||
notification->setImage(_cachedUserpics.get(key, peer, userpicView));
|
notification->setImage(
|
||||||
|
_cachedUserpics.get(userpicKey, peer, userpicView));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto i = _notifications.find(peer->id);
|
auto i = _notifications.find(key);
|
||||||
if (i != _notifications.cend()) {
|
if (i != _notifications.cend()) {
|
||||||
auto j = i->find(msgId);
|
auto j = i->second.find(msgId);
|
||||||
if (j != i->cend()) {
|
if (j != i->second.end()) {
|
||||||
auto oldNotification = j.value();
|
auto oldNotification = j->second;
|
||||||
i->erase(j);
|
i->second.erase(j);
|
||||||
oldNotification->close();
|
oldNotification->close();
|
||||||
i = _notifications.find(peer->id);
|
i = _notifications.find(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (i == _notifications.cend()) {
|
if (i == _notifications.cend()) {
|
||||||
i = _notifications.insert(peer->id, QMap<MsgId, Notification>());
|
i = _notifications.emplace(
|
||||||
|
key,
|
||||||
|
base::flat_map<MsgId, Notification>()).first;
|
||||||
}
|
}
|
||||||
_notifications[peer->id].insert(msgId, notification);
|
i->second.emplace(msgId, notification);
|
||||||
if (!notification->show()) {
|
if (!notification->show()) {
|
||||||
i = _notifications.find(peer->id);
|
i = _notifications.find(key);
|
||||||
if (i != _notifications.cend()) {
|
if (i != _notifications.cend()) {
|
||||||
i->remove(msgId);
|
i->second.remove(msgId);
|
||||||
if (i->isEmpty()) _notifications.erase(i);
|
if (i->empty()) {
|
||||||
|
_notifications.erase(i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -570,9 +590,8 @@ void Manager::Private::showNotification(
|
||||||
void Manager::Private::clearAll() {
|
void Manager::Private::clearAll() {
|
||||||
if (!Supported()) return;
|
if (!Supported()) return;
|
||||||
|
|
||||||
auto temp = base::take(_notifications);
|
for (const auto &[key, notifications] : base::take(_notifications)) {
|
||||||
for_const (auto ¬ifications, temp) {
|
for (const auto &[msgId, notification] : notifications) {
|
||||||
for_const (auto notification, notifications) {
|
|
||||||
notification->close();
|
notification->close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -581,24 +600,43 @@ void Manager::Private::clearAll() {
|
||||||
void Manager::Private::clearFromHistory(not_null<History*> history) {
|
void Manager::Private::clearFromHistory(not_null<History*> history) {
|
||||||
if (!Supported()) return;
|
if (!Supported()) return;
|
||||||
|
|
||||||
auto i = _notifications.find(history->peer->id);
|
const auto key = FullPeer{
|
||||||
|
history->peer->id,
|
||||||
|
history->session().userId()
|
||||||
|
};
|
||||||
|
auto i = _notifications.find(key);
|
||||||
if (i != _notifications.cend()) {
|
if (i != _notifications.cend()) {
|
||||||
auto temp = base::take(i.value());
|
const auto temp = base::take(i->second);
|
||||||
_notifications.erase(i);
|
_notifications.erase(i);
|
||||||
|
|
||||||
for_const (auto notification, temp) {
|
for (const auto &[msgId, notification] : temp) {
|
||||||
notification->close();
|
notification->close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::Private::clearNotification(PeerId peerId, MsgId msgId) {
|
void Manager::Private::clearFromSession(not_null<Main::Session*> session) {
|
||||||
if (!Supported()) return;
|
if (!Supported()) return;
|
||||||
|
|
||||||
auto i = _notifications.find(peerId);
|
const auto selfId = session->userId();
|
||||||
|
for (auto i = _notifications.begin(); i != _notifications.end();) {
|
||||||
|
if (i->first.second == selfId) {
|
||||||
|
const auto temp = base::take(i->second);
|
||||||
|
i = _notifications.erase(i);
|
||||||
|
|
||||||
|
for (const auto &[msgId, notification] : temp) {
|
||||||
|
notification->close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Manager::Private::clearNotification(NotificationId id) {
|
||||||
|
if (!Supported()) return;
|
||||||
|
|
||||||
|
auto i = _notifications.find(FullPeer{ id.peerId, id.selfId });
|
||||||
if (i != _notifications.cend()) {
|
if (i != _notifications.cend()) {
|
||||||
i.value().remove(msgId);
|
if (i->second.remove(id.msgId) && i->second.empty()) {
|
||||||
if (i.value().isEmpty()) {
|
|
||||||
_notifications.erase(i);
|
_notifications.erase(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -613,8 +651,8 @@ Manager::Manager(not_null<Window::Notifications::System*> system)
|
||||||
, _private(std::make_unique<Private>(this, Private::Type::Rounded)) {
|
, _private(std::make_unique<Private>(this, Private::Type::Rounded)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::clearNotification(PeerId peerId, MsgId msgId) {
|
void Manager::clearNotification(NotificationId id) {
|
||||||
_private->clearNotification(peerId, msgId);
|
_private->clearNotification(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
Manager::~Manager() = default;
|
Manager::~Manager() = default;
|
||||||
|
@ -646,6 +684,10 @@ void Manager::doClearAllFast() {
|
||||||
void Manager::doClearFromHistory(not_null<History*> history) {
|
void Manager::doClearFromHistory(not_null<History*> history) {
|
||||||
_private->clearFromHistory(history);
|
_private->clearFromHistory(history);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Manager::doClearFromSession(not_null<Main::Session*> session) {
|
||||||
|
_private->clearFromSession(session);
|
||||||
|
}
|
||||||
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
|
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
|
||||||
|
|
||||||
} // namespace Notifications
|
} // namespace Notifications
|
||||||
|
|
|
@ -24,6 +24,8 @@ class NotificationData : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
using NotificationId = Window::Notifications::Manager::NotificationId;
|
||||||
|
|
||||||
NotificationData(
|
NotificationData(
|
||||||
const base::weak_ptr<Manager> &manager,
|
const base::weak_ptr<Manager> &manager,
|
||||||
const QString &title,
|
const QString &title,
|
||||||
|
@ -31,6 +33,7 @@ public:
|
||||||
const QString &msg,
|
const QString &msg,
|
||||||
PeerId peerId,
|
PeerId peerId,
|
||||||
MsgId msgId,
|
MsgId msgId,
|
||||||
|
UserId selfId,
|
||||||
bool hideReplyButton);
|
bool hideReplyButton);
|
||||||
|
|
||||||
NotificationData(const NotificationData &other) = delete;
|
NotificationData(const NotificationData &other) = delete;
|
||||||
|
@ -50,6 +53,8 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
[[nodiscard]] NotificationId myId() const;
|
||||||
|
|
||||||
QDBusConnection _dbusConnection;
|
QDBusConnection _dbusConnection;
|
||||||
base::weak_ptr<Manager> _manager;
|
base::weak_ptr<Manager> _manager;
|
||||||
|
|
||||||
|
@ -59,9 +64,10 @@ private:
|
||||||
QVariantMap _hints;
|
QVariantMap _hints;
|
||||||
QString _imageKey;
|
QString _imageKey;
|
||||||
|
|
||||||
uint _notificationId;
|
uint _notificationId = 0;
|
||||||
PeerId _peerId;
|
PeerId _peerId = 0;
|
||||||
MsgId _msgId;
|
MsgId _msgId = 0;
|
||||||
|
UserId _selfId = 0;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void notificationClosed(uint id);
|
void notificationClosed(uint id);
|
||||||
|
@ -84,7 +90,7 @@ class Manager
|
||||||
, public base::has_weak_ptr {
|
, public base::has_weak_ptr {
|
||||||
public:
|
public:
|
||||||
Manager(not_null<Window::Notifications::System*> system);
|
Manager(not_null<Window::Notifications::System*> system);
|
||||||
void clearNotification(PeerId peerId, MsgId msgId);
|
void clearNotification(NotificationId id);
|
||||||
~Manager();
|
~Manager();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -99,6 +105,7 @@ protected:
|
||||||
bool hideReplyButton) override;
|
bool hideReplyButton) override;
|
||||||
void doClearAllFast() override;
|
void doClearAllFast() override;
|
||||||
void doClearFromHistory(not_null<History*> history) override;
|
void doClearFromHistory(not_null<History*> history) override;
|
||||||
|
void doClearFromSession(not_null<Main::Session*> session) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class Private;
|
class Private;
|
||||||
|
@ -122,13 +129,15 @@ public:
|
||||||
bool hideReplyButton);
|
bool hideReplyButton);
|
||||||
void clearAll();
|
void clearAll();
|
||||||
void clearFromHistory(not_null<History*> history);
|
void clearFromHistory(not_null<History*> history);
|
||||||
void clearNotification(PeerId peerId, MsgId msgId);
|
void clearFromSession(not_null<Main::Session*> session);
|
||||||
|
void clearNotification(NotificationId id);
|
||||||
|
|
||||||
~Private();
|
~Private();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using Notifications = QMap<PeerId, QMap<MsgId, Notification>>;
|
base::flat_map<
|
||||||
Notifications _notifications;
|
FullPeer,
|
||||||
|
base::flat_map<MsgId, Notification>> _notifications;
|
||||||
|
|
||||||
Window::Notifications::CachedUserpics _cachedUserpics;
|
Window::Notifications::CachedUserpics _cachedUserpics;
|
||||||
base::weak_ptr<Manager> _manager;
|
base::weak_ptr<Manager> _manager;
|
||||||
|
|
|
@ -30,6 +30,7 @@ protected:
|
||||||
bool hideReplyButton) override;
|
bool hideReplyButton) override;
|
||||||
void doClearAllFast() override;
|
void doClearAllFast() override;
|
||||||
void doClearFromHistory(not_null<History*> history) override;
|
void doClearFromHistory(not_null<History*> history) override;
|
||||||
|
void doClearFromSession(not_null<Main::Session*> session) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class Private;
|
class Private;
|
||||||
|
|
|
@ -173,6 +173,7 @@ public:
|
||||||
bool hideReplyButton);
|
bool hideReplyButton);
|
||||||
void clearAll();
|
void clearAll();
|
||||||
void clearFromHistory(not_null<History*> history);
|
void clearFromHistory(not_null<History*> history);
|
||||||
|
void clearFromSession(not_null<Main::Session*> session);
|
||||||
void updateDelegate();
|
void updateDelegate();
|
||||||
|
|
||||||
~Private();
|
~Private();
|
||||||
|
@ -328,6 +329,10 @@ void Manager::Private::clearFromHistory(not_null<History*> history) {
|
||||||
putClearTask(ClearFromHistory { history->peer->id });
|
putClearTask(ClearFromHistory { history->peer->id });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Manager::Private::clearFromSession(not_null<Main::Session*> session) {
|
||||||
|
putClearTask(); // #TODO multi
|
||||||
|
}
|
||||||
|
|
||||||
void Manager::Private::updateDelegate() {
|
void Manager::Private::updateDelegate() {
|
||||||
NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter];
|
NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter];
|
||||||
[center setDelegate:_delegate];
|
[center setDelegate:_delegate];
|
||||||
|
@ -377,5 +382,9 @@ void Manager::doClearFromHistory(not_null<History*> history) {
|
||||||
_private->clearFromHistory(history);
|
_private->clearFromHistory(history);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Manager::doClearFromSession(not_null<Main::Session*> session) {
|
||||||
|
_private->clearFromSession(session);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Notifications
|
} // namespace Notifications
|
||||||
} // namespace Platform
|
} // namespace Platform
|
||||||
|
|
|
@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "history/history.h"
|
#include "history/history.h"
|
||||||
#include "core/application.h"
|
#include "core/application.h"
|
||||||
#include "core/core_settings.h"
|
#include "core/core_settings.h"
|
||||||
|
#include "main/main_session.h"
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
|
|
||||||
#include <Shobjidl.h>
|
#include <Shobjidl.h>
|
||||||
|
@ -208,13 +209,17 @@ class ToastEventHandler final : public Implements<
|
||||||
DesktopToastDismissedEventHandler,
|
DesktopToastDismissedEventHandler,
|
||||||
DesktopToastFailedEventHandler> {
|
DesktopToastFailedEventHandler> {
|
||||||
public:
|
public:
|
||||||
|
using NotificationId = Manager::NotificationId;
|
||||||
|
|
||||||
// We keep a weak pointer to a member field of native notifications manager.
|
// We keep a weak pointer to a member field of native notifications manager.
|
||||||
ToastEventHandler(
|
ToastEventHandler(
|
||||||
const std::shared_ptr<Manager*> &guarded,
|
const std::shared_ptr<Manager*> &guarded,
|
||||||
const PeerId &peer,
|
PeerId peer,
|
||||||
MsgId msg)
|
MsgId msg,
|
||||||
|
UserId selfId)
|
||||||
: _peerId(peer)
|
: _peerId(peer)
|
||||||
, _msgId(msg)
|
, _msgId(msg)
|
||||||
|
, _selfId(selfId)
|
||||||
, _weak(guarded) {
|
, _weak(guarded) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,8 +232,9 @@ public:
|
||||||
|
|
||||||
// DesktopToastActivatedEventHandler
|
// DesktopToastActivatedEventHandler
|
||||||
IFACEMETHODIMP Invoke(_In_ IToastNotification *sender, _In_ IInspectable* args) {
|
IFACEMETHODIMP Invoke(_In_ IToastNotification *sender, _In_ IInspectable* args) {
|
||||||
performOnMainQueue([peerId = _peerId, msgId = _msgId](Manager *manager) {
|
const auto my = myId();
|
||||||
manager->notificationActivated(peerId, msgId);
|
performOnMainQueue([my](Manager *manager) {
|
||||||
|
manager->notificationActivated(my);
|
||||||
});
|
});
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
@ -243,8 +249,9 @@ public:
|
||||||
case ToastDismissalReason_UserCanceled:
|
case ToastDismissalReason_UserCanceled:
|
||||||
case ToastDismissalReason_TimedOut:
|
case ToastDismissalReason_TimedOut:
|
||||||
default:
|
default:
|
||||||
performOnMainQueue([peerId = _peerId, msgId = _msgId](Manager *manager) {
|
const auto my = myId();
|
||||||
manager->clearNotification(peerId, msgId);
|
performOnMainQueue([my](Manager *manager) {
|
||||||
|
manager->clearNotification(my);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -254,8 +261,9 @@ public:
|
||||||
|
|
||||||
// DesktopToastFailedEventHandler
|
// DesktopToastFailedEventHandler
|
||||||
IFACEMETHODIMP Invoke(_In_ IToastNotification *sender, _In_ IToastFailedEventArgs *e) {
|
IFACEMETHODIMP Invoke(_In_ IToastNotification *sender, _In_ IToastFailedEventArgs *e) {
|
||||||
performOnMainQueue([peerId = _peerId, msgId = _msgId](Manager *manager) {
|
const auto my = myId();
|
||||||
manager->clearNotification(peerId, msgId);
|
performOnMainQueue([my](Manager *manager) {
|
||||||
|
manager->clearNotification(my);
|
||||||
});
|
});
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
@ -293,9 +301,14 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
[[nodiscard]] NotificationId myId() const {
|
||||||
|
return { .peerId = _peerId, .msgId = _msgId, .selfId = _selfId };
|
||||||
|
}
|
||||||
|
|
||||||
ULONG _refCount = 0;
|
ULONG _refCount = 0;
|
||||||
PeerId _peerId = 0;
|
PeerId _peerId = 0;
|
||||||
MsgId _msgId = 0;
|
MsgId _msgId = 0;
|
||||||
|
UserId _selfId = 0;
|
||||||
std::weak_ptr<Manager*> _weak;
|
std::weak_ptr<Manager*> _weak;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -353,9 +366,10 @@ public:
|
||||||
bool hideReplyButton);
|
bool hideReplyButton);
|
||||||
void clearAll();
|
void clearAll();
|
||||||
void clearFromHistory(not_null<History*> history);
|
void clearFromHistory(not_null<History*> history);
|
||||||
void beforeNotificationActivated(PeerId peerId, MsgId msgId);
|
void clearFromSession(not_null<Main::Session*> session);
|
||||||
void afterNotificationActivated(PeerId peerId, MsgId msgId);
|
void beforeNotificationActivated(NotificationId id);
|
||||||
void clearNotification(PeerId peerId, MsgId msgId);
|
void afterNotificationActivated(NotificationId id);
|
||||||
|
void clearNotification(NotificationId id);
|
||||||
|
|
||||||
~Private();
|
~Private();
|
||||||
|
|
||||||
|
@ -376,7 +390,7 @@ private:
|
||||||
|
|
||||||
ComPtr<IToastNotification> p;
|
ComPtr<IToastNotification> p;
|
||||||
};
|
};
|
||||||
QMap<PeerId, QMap<MsgId, NotificationPtr>> _notifications;
|
base::flat_map<FullPeer, base::flat_map<MsgId, NotificationPtr>> _notifications;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -414,8 +428,8 @@ void Manager::Private::clearAll() {
|
||||||
if (!_notifier) return;
|
if (!_notifier) return;
|
||||||
|
|
||||||
auto temp = base::take(_notifications);
|
auto temp = base::take(_notifications);
|
||||||
for_const (auto ¬ifications, temp) {
|
for (const auto &[key, notifications] : base::take(_notifications)) {
|
||||||
for_const (auto ¬ification, notifications) {
|
for (const auto &[msgId, notification] : notifications) {
|
||||||
_notifier->Hide(notification.p.Get());
|
_notifier->Hide(notification.p.Get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -424,32 +438,51 @@ void Manager::Private::clearAll() {
|
||||||
void Manager::Private::clearFromHistory(not_null<History*> history) {
|
void Manager::Private::clearFromHistory(not_null<History*> history) {
|
||||||
if (!_notifier) return;
|
if (!_notifier) return;
|
||||||
|
|
||||||
auto i = _notifications.find(history->peer->id);
|
auto i = _notifications.find(FullPeer{
|
||||||
|
history->peer->id,
|
||||||
|
history->session().userId()
|
||||||
|
});
|
||||||
if (i != _notifications.cend()) {
|
if (i != _notifications.cend()) {
|
||||||
auto temp = base::take(i.value());
|
auto temp = base::take(i->second);
|
||||||
_notifications.erase(i);
|
_notifications.erase(i);
|
||||||
|
|
||||||
for_const (auto ¬ification, temp) {
|
for (const auto &[msgId, notification] : temp) {
|
||||||
_notifier->Hide(notification.p.Get());
|
_notifier->Hide(notification.p.Get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::Private::beforeNotificationActivated(PeerId peerId, MsgId msgId) {
|
void Manager::Private::clearFromSession(not_null<Main::Session*> session) {
|
||||||
clearNotification(peerId, msgId);
|
if (!_notifier) return;
|
||||||
|
|
||||||
|
const auto selfId = session->userId();
|
||||||
|
for (auto i = _notifications.begin(); i != _notifications.end();) {
|
||||||
|
if (i->first.selfId == selfId) {
|
||||||
|
const auto temp = base::take(i->second);
|
||||||
|
_notifications.erase(i);
|
||||||
|
|
||||||
|
for (const auto &[msgId, notification] : temp) {
|
||||||
|
_notifier->Hide(notification.p.Get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::Private::afterNotificationActivated(PeerId peerId, MsgId msgId) {
|
void Manager::Private::beforeNotificationActivated(NotificationId id) {
|
||||||
|
clearNotification(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Manager::Private::afterNotificationActivated(NotificationId id) {
|
||||||
if (auto window = App::wnd()) {
|
if (auto window = App::wnd()) {
|
||||||
SetForegroundWindow(window->psHwnd());
|
SetForegroundWindow(window->psHwnd());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::Private::clearNotification(PeerId peerId, MsgId msgId) {
|
void Manager::Private::clearNotification(NotificationId id) {
|
||||||
auto i = _notifications.find(peerId);
|
auto i = _notifications.find(FullPeer{ id.peerId, id.selfId });
|
||||||
if (i != _notifications.cend()) {
|
if (i != _notifications.cend()) {
|
||||||
i.value().remove(msgId);
|
i->second.remove(id.msgId);
|
||||||
if (i.value().isEmpty()) {
|
if (i->second.empty()) {
|
||||||
_notifications.erase(i);
|
_notifications.erase(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -481,10 +514,10 @@ bool Manager::Private::showNotification(
|
||||||
hr = SetAudioSilent(toastXml.Get());
|
hr = SetAudioSilent(toastXml.Get());
|
||||||
if (!SUCCEEDED(hr)) return false;
|
if (!SUCCEEDED(hr)) return false;
|
||||||
|
|
||||||
const auto key = hideNameAndPhoto
|
const auto userpicKey = hideNameAndPhoto
|
||||||
? InMemoryKey()
|
? InMemoryKey()
|
||||||
: peer->userpicUniqueKey(userpicView);
|
: peer->userpicUniqueKey(userpicView);
|
||||||
const auto userpicPath = _cachedUserpics.get(key, peer, userpicView);
|
const auto userpicPath = _cachedUserpics.get(userpicKey, peer, userpicView);
|
||||||
const auto userpicPathWide = QDir::toNativeSeparators(userpicPath).toStdWString();
|
const auto userpicPathWide = QDir::toNativeSeparators(userpicPath).toStdWString();
|
||||||
|
|
||||||
hr = SetImageSrc(userpicPathWide.c_str(), toastXml.Get());
|
hr = SetImageSrc(userpicPathWide.c_str(), toastXml.Get());
|
||||||
|
@ -533,7 +566,11 @@ bool Manager::Private::showNotification(
|
||||||
if (!SUCCEEDED(hr)) return false;
|
if (!SUCCEEDED(hr)) return false;
|
||||||
|
|
||||||
EventRegistrationToken activatedToken, dismissedToken, failedToken;
|
EventRegistrationToken activatedToken, dismissedToken, failedToken;
|
||||||
ComPtr<ToastEventHandler> eventHandler(new ToastEventHandler(_guarded, peer->id, msgId));
|
ComPtr<ToastEventHandler> eventHandler(new ToastEventHandler(
|
||||||
|
_guarded,
|
||||||
|
peer->id,
|
||||||
|
msgId,
|
||||||
|
peer->session().userId()));
|
||||||
|
|
||||||
hr = toast->add_Activated(eventHandler.Get(), &activatedToken);
|
hr = toast->add_Activated(eventHandler.Get(), &activatedToken);
|
||||||
if (!SUCCEEDED(hr)) return false;
|
if (!SUCCEEDED(hr)) return false;
|
||||||
|
@ -544,26 +581,34 @@ bool Manager::Private::showNotification(
|
||||||
hr = toast->add_Failed(eventHandler.Get(), &failedToken);
|
hr = toast->add_Failed(eventHandler.Get(), &failedToken);
|
||||||
if (!SUCCEEDED(hr)) return false;
|
if (!SUCCEEDED(hr)) return false;
|
||||||
|
|
||||||
auto i = _notifications.find(peer->id);
|
const auto key = FullPeer{
|
||||||
|
peer->id,
|
||||||
|
peer->session().userId()
|
||||||
|
};
|
||||||
|
auto i = _notifications.find(key);
|
||||||
if (i != _notifications.cend()) {
|
if (i != _notifications.cend()) {
|
||||||
auto j = i->find(msgId);
|
auto j = i->second.find(msgId);
|
||||||
if (j != i->cend()) {
|
if (j != i->second.end()) {
|
||||||
ComPtr<IToastNotification> notify = j->p;
|
ComPtr<IToastNotification> notify = j->second.p;
|
||||||
i->erase(j);
|
i->second.erase(j);
|
||||||
_notifier->Hide(notify.Get());
|
_notifier->Hide(notify.Get());
|
||||||
i = _notifications.find(peer->id);
|
i = _notifications.find(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (i == _notifications.cend()) {
|
if (i == _notifications.cend()) {
|
||||||
i = _notifications.insert(peer->id, QMap<MsgId, NotificationPtr>());
|
i = _notifications.emplace(
|
||||||
|
key,
|
||||||
|
base::flat_map<MsgId, NotificationPtr>()).first;
|
||||||
}
|
}
|
||||||
hr = _notifier->Show(toast.Get());
|
hr = _notifier->Show(toast.Get());
|
||||||
if (!SUCCEEDED(hr)) {
|
if (!SUCCEEDED(hr)) {
|
||||||
i = _notifications.find(peer->id);
|
i = _notifications.find(key);
|
||||||
if (i != _notifications.cend() && i->isEmpty()) _notifications.erase(i);
|
if (i != _notifications.cend() && i->second.empty()) {
|
||||||
|
_notifications.erase(i);
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
_notifications[peer->id].insert(msgId, toast);
|
i->second.emplace(msgId, toast);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -576,8 +621,8 @@ bool Manager::init() {
|
||||||
return _private->init();
|
return _private->init();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::clearNotification(PeerId peerId, MsgId msgId) {
|
void Manager::clearNotification(NotificationId id) {
|
||||||
_private->clearNotification(peerId, msgId);
|
_private->clearNotification(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
Manager::~Manager() = default;
|
Manager::~Manager() = default;
|
||||||
|
@ -610,12 +655,16 @@ void Manager::doClearFromHistory(not_null<History*> history) {
|
||||||
_private->clearFromHistory(history);
|
_private->clearFromHistory(history);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::onBeforeNotificationActivated(PeerId peerId, MsgId msgId) {
|
void Manager::doClearFromSession(not_null<Main::Session*> session) {
|
||||||
_private->beforeNotificationActivated(peerId, msgId);
|
_private->clearFromSession(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::onAfterNotificationActivated(PeerId peerId, MsgId msgId) {
|
void Manager::onBeforeNotificationActivated(NotificationId id) {
|
||||||
_private->afterNotificationActivated(peerId, msgId);
|
_private->beforeNotificationActivated(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Manager::onAfterNotificationActivated(NotificationId id) {
|
||||||
|
_private->afterNotificationActivated(id);
|
||||||
}
|
}
|
||||||
#endif // !__MINGW32__
|
#endif // !__MINGW32__
|
||||||
|
|
||||||
|
|
|
@ -13,15 +13,14 @@ namespace Platform {
|
||||||
namespace Notifications {
|
namespace Notifications {
|
||||||
|
|
||||||
#ifndef __MINGW32__
|
#ifndef __MINGW32__
|
||||||
|
|
||||||
class Manager : public Window::Notifications::NativeManager {
|
class Manager : public Window::Notifications::NativeManager {
|
||||||
public:
|
public:
|
||||||
Manager(Window::Notifications::System *system);
|
Manager(Window::Notifications::System *system);
|
||||||
|
~Manager();
|
||||||
|
|
||||||
bool init();
|
bool init();
|
||||||
|
void clearNotification(NotificationId id);
|
||||||
void clearNotification(PeerId peerId, MsgId msgId);
|
|
||||||
|
|
||||||
~Manager();
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void doShowNativeNotification(
|
void doShowNativeNotification(
|
||||||
|
@ -35,8 +34,9 @@ protected:
|
||||||
bool hideReplyButton) override;
|
bool hideReplyButton) override;
|
||||||
void doClearAllFast() override;
|
void doClearAllFast() override;
|
||||||
void doClearFromHistory(not_null<History*> history) override;
|
void doClearFromHistory(not_null<History*> history) override;
|
||||||
void onBeforeNotificationActivated(PeerId peerId, MsgId msgId) override;
|
void doClearFromSession(not_null<Main::Session*> session) override;
|
||||||
void onAfterNotificationActivated(PeerId peerId, MsgId msgId) override;
|
void onBeforeNotificationActivated(NotificationId id) override;
|
||||||
|
void onAfterNotificationActivated(NotificationId id) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class Private;
|
class Private;
|
||||||
|
|
|
@ -150,11 +150,8 @@ auto GenerateCodes() {
|
||||||
SessionController *window) {
|
SessionController *window) {
|
||||||
crl::on_main(&Core::App(), [=] {
|
crl::on_main(&Core::App(), [=] {
|
||||||
const auto &list = Core::App().domain().accounts();
|
const auto &list = Core::App().domain().accounts();
|
||||||
const auto j = list.find(i);
|
if (i < list.size()) {
|
||||||
if (j != list.end() && !Core::App().locked()) {
|
Core::App().domain().activate(list[i].account.get());
|
||||||
if (&Core::App().activeAccount() != j->second.get()) {
|
|
||||||
Core::App().domain().activate(i);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -191,7 +191,7 @@ void NotificationsCount::setCount(int count) {
|
||||||
if (count != Core::App().settings().notificationsCount()) {
|
if (count != Core::App().settings().notificationsCount()) {
|
||||||
Core::App().settings().setNotificationsCount(count);
|
Core::App().settings().setNotificationsCount(count);
|
||||||
Core::App().saveSettingsDelayed();
|
Core::App().saveSettingsDelayed();
|
||||||
_controller->session().notifications().settingsChanged().notify(
|
Core::App().notifications().settingsChanged().notify(
|
||||||
ChangeType::MaxCount);
|
ChangeType::MaxCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -355,7 +355,7 @@ void NotificationsCount::setOverCorner(ScreenCorner corner) {
|
||||||
_isOverCorner = true;
|
_isOverCorner = true;
|
||||||
setCursor(style::cur_pointer);
|
setCursor(style::cur_pointer);
|
||||||
Global::SetNotificationsDemoIsShown(true);
|
Global::SetNotificationsDemoIsShown(true);
|
||||||
_controller->session().notifications().settingsChanged().notify(
|
Core::App().notifications().settingsChanged().notify(
|
||||||
ChangeType::DemoIsShown);
|
ChangeType::DemoIsShown);
|
||||||
}
|
}
|
||||||
_overCorner = corner;
|
_overCorner = corner;
|
||||||
|
@ -391,7 +391,7 @@ void NotificationsCount::clearOverCorner() {
|
||||||
_isOverCorner = false;
|
_isOverCorner = false;
|
||||||
setCursor(style::cur_default);
|
setCursor(style::cur_default);
|
||||||
Global::SetNotificationsDemoIsShown(false);
|
Global::SetNotificationsDemoIsShown(false);
|
||||||
_controller->session().notifications().settingsChanged().notify(ChangeType::DemoIsShown);
|
Core::App().notifications().settingsChanged().notify(ChangeType::DemoIsShown);
|
||||||
|
|
||||||
for_const (const auto &samples, _cornerSamples) {
|
for_const (const auto &samples, _cornerSamples) {
|
||||||
for_const (const auto widget, samples) {
|
for_const (const auto widget, samples) {
|
||||||
|
@ -418,7 +418,7 @@ void NotificationsCount::mouseReleaseEvent(QMouseEvent *e) {
|
||||||
if (_chosenCorner != Core::App().settings().notificationsCorner()) {
|
if (_chosenCorner != Core::App().settings().notificationsCorner()) {
|
||||||
Core::App().settings().setNotificationsCorner(_chosenCorner);
|
Core::App().settings().setNotificationsCorner(_chosenCorner);
|
||||||
Core::App().saveSettingsDelayed();
|
Core::App().saveSettingsDelayed();
|
||||||
_controller->session().notifications().settingsChanged().notify(
|
Core::App().notifications().settingsChanged().notify(
|
||||||
ChangeType::Corner);
|
ChangeType::Corner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -685,7 +685,7 @@ void SetupNotificationsContent(
|
||||||
using Change = Window::Notifications::ChangeType;
|
using Change = Window::Notifications::ChangeType;
|
||||||
const auto changed = [=](Change change) {
|
const auto changed = [=](Change change) {
|
||||||
Core::App().saveSettingsDelayed();
|
Core::App().saveSettingsDelayed();
|
||||||
session->notifications().settingsChanged().notify(change);
|
Core::App().notifications().settingsChanged().notify(change);
|
||||||
};
|
};
|
||||||
desktop->checkedChanges(
|
desktop->checkedChanges(
|
||||||
) | rpl::filter([](bool checked) {
|
) | rpl::filter([](bool checked) {
|
||||||
|
@ -758,7 +758,7 @@ void SetupNotificationsContent(
|
||||||
}, count->lifetime());
|
}, count->lifetime());
|
||||||
|
|
||||||
base::ObservableViewer(
|
base::ObservableViewer(
|
||||||
session->notifications().settingsChanged()
|
Core::App().notifications().settingsChanged()
|
||||||
) | rpl::start_with_next([=](Change change) {
|
) | rpl::start_with_next([=](Change change) {
|
||||||
if (change == Change::DesktopEnabled) {
|
if (change == Change::DesktopEnabled) {
|
||||||
desktop->setChecked(Core::App().settings().desktopNotify());
|
desktop->setChecked(Core::App().settings().desktopNotify());
|
||||||
|
@ -785,7 +785,7 @@ void SetupNotificationsContent(
|
||||||
}) | rpl::start_with_next([=](bool checked) {
|
}) | rpl::start_with_next([=](bool checked) {
|
||||||
Core::App().settings().setNativeNotifications(checked);
|
Core::App().settings().setNativeNotifications(checked);
|
||||||
Core::App().saveSettingsDelayed();
|
Core::App().saveSettingsDelayed();
|
||||||
session->notifications().createManager();
|
Core::App().notifications().createManager();
|
||||||
|
|
||||||
if (advancedSlide) {
|
if (advancedSlide) {
|
||||||
advancedSlide->toggle(
|
advancedSlide->toggle(
|
||||||
|
|
|
@ -87,7 +87,7 @@ void Domain::startWithSingleAccount(
|
||||||
generateLocalKey();
|
generateLocalKey();
|
||||||
account->start(account->prepareToStart(_localKey));
|
account->start(account->prepareToStart(_localKey));
|
||||||
}
|
}
|
||||||
_owner->accountAddedInStorage(0, std::move(account));
|
_owner->accountAddedInStorage({ .account = std::move(account) });
|
||||||
writeAccounts();
|
writeAccounts();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,6 +170,7 @@ Domain::StartModernResult Domain::startModern(
|
||||||
|
|
||||||
auto tried = base::flat_set<int>();
|
auto tried = base::flat_set<int>();
|
||||||
auto users = base::flat_set<UserId>();
|
auto users = base::flat_set<UserId>();
|
||||||
|
auto active = 0;
|
||||||
for (auto i = 0; i != count; ++i) {
|
for (auto i = 0; i != count; ++i) {
|
||||||
auto index = qint32();
|
auto index = qint32();
|
||||||
info.stream >> index;
|
info.stream >> index;
|
||||||
|
@ -184,12 +185,22 @@ Domain::StartModernResult Domain::startModern(
|
||||||
const auto userId = account->willHaveUserId();
|
const auto userId = account->willHaveUserId();
|
||||||
if (!users.contains(userId)
|
if (!users.contains(userId)
|
||||||
&& (userId != 0 || (users.empty() && i + 1 == count))) {
|
&& (userId != 0 || (users.empty() && i + 1 == count))) {
|
||||||
|
if (users.empty()) {
|
||||||
|
active = index;
|
||||||
|
}
|
||||||
account->start(std::move(config));
|
account->start(std::move(config));
|
||||||
_owner->accountAddedInStorage(index, std::move(account));
|
_owner->accountAddedInStorage({
|
||||||
|
.index = index,
|
||||||
|
.account = std::move(account)
|
||||||
|
});
|
||||||
users.emplace(userId);
|
users.emplace(userId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!info.stream.atEnd()) {
|
||||||
|
info.stream >> active;
|
||||||
|
}
|
||||||
|
_owner->activateFromStorage(active);
|
||||||
|
|
||||||
Ensures(!users.empty());
|
Ensures(!users.empty());
|
||||||
return StartModernResult::Success;
|
return StartModernResult::Success;
|
||||||
|
@ -208,18 +219,21 @@ void Domain::writeAccounts() {
|
||||||
key.writeData(_passcodeKeyEncrypted);
|
key.writeData(_passcodeKeyEncrypted);
|
||||||
|
|
||||||
const auto &list = _owner->accounts();
|
const auto &list = _owner->accounts();
|
||||||
const auto active = _owner->activeIndex();
|
|
||||||
|
|
||||||
auto keySize = sizeof(qint32) + sizeof(qint32) * list.size();
|
auto keySize = sizeof(qint32) + sizeof(qint32) * list.size();
|
||||||
|
|
||||||
|
const auto active = &_owner->active();
|
||||||
|
auto activeIndex = -1;
|
||||||
|
|
||||||
EncryptedDescriptor keyData(keySize);
|
EncryptedDescriptor keyData(keySize);
|
||||||
keyData.stream << qint32(list.size());
|
keyData.stream << qint32(list.size());
|
||||||
keyData.stream << qint32(active);
|
|
||||||
for (const auto &[index, account] : list) {
|
for (const auto &[index, account] : list) {
|
||||||
if (index != active) {
|
if (active == account.get()) {
|
||||||
|
activeIndex = index;
|
||||||
|
}
|
||||||
keyData.stream << qint32(index);
|
keyData.stream << qint32(index);
|
||||||
}
|
}
|
||||||
}
|
keyData.stream << qint32(activeIndex);
|
||||||
key.writeEncrypted(keyData, _localKey);
|
key.writeEncrypted(keyData, _localKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "api/api_updates.h"
|
#include "api/api_updates.h"
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
|
#include "main/main_account.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "main/main_domain.h"
|
#include "main/main_domain.h"
|
||||||
#include "facades.h"
|
#include "facades.h"
|
||||||
|
@ -47,9 +48,8 @@ constexpr auto kSystemAlertDuration = crl::time(0);
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
System::System(not_null<Main::Session*> session)
|
System::System()
|
||||||
: _session(session)
|
: _waitTimer([=] { showNext(); })
|
||||||
, _waitTimer([=] { showNext(); })
|
|
||||||
, _waitForAllGroupedTimer([=] { showGrouped(); }) {
|
, _waitForAllGroupedTimer([=] { showGrouped(); }) {
|
||||||
createManager();
|
createManager();
|
||||||
|
|
||||||
|
@ -73,6 +73,16 @@ void System::createManager() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Main::Session *System::findSession(UserId selfId) const {
|
||||||
|
for (const auto &[index, account] : Core::App().domain().accounts()) {
|
||||||
|
if (account->sessionExists()
|
||||||
|
&& account->session().userId() == selfId) {
|
||||||
|
return &account->session();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
System::SkipState System::skipNotification(
|
System::SkipState System::skipNotification(
|
||||||
not_null<HistoryItem*> item) const {
|
not_null<HistoryItem*> item) const {
|
||||||
const auto history = item->history();
|
const auto history = item->history();
|
||||||
|
@ -135,19 +145,23 @@ void System::schedule(not_null<HistoryItem*> item) {
|
||||||
|
|
||||||
auto when = ms + delay;
|
auto when = ms + delay;
|
||||||
if (!skip.silent) {
|
if (!skip.silent) {
|
||||||
_whenAlerts[history].insert(when, notifyBy);
|
_whenAlerts[history].emplace(when, notifyBy);
|
||||||
}
|
}
|
||||||
if (Core::App().settings().desktopNotify()
|
if (Core::App().settings().desktopNotify()
|
||||||
&& !Platform::Notifications::SkipToast()) {
|
&& !Platform::Notifications::SkipToast()) {
|
||||||
auto &whenMap = _whenMaps[history];
|
auto &whenMap = _whenMaps[history];
|
||||||
if (whenMap.constFind(item->id) == whenMap.cend()) {
|
if (whenMap.find(item->id) == whenMap.end()) {
|
||||||
whenMap.insert(item->id, when);
|
whenMap.emplace(item->id, when);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto &addTo = ready ? _waiters : _settingWaiters;
|
auto &addTo = ready ? _waiters : _settingWaiters;
|
||||||
const auto it = addTo.constFind(history);
|
const auto it = addTo.find(history);
|
||||||
if (it == addTo.cend() || it->when > when) {
|
if (it == addTo.end() || it->second.when > when) {
|
||||||
addTo.insert(history, Waiter(item->id, when, notifyBy));
|
addTo.emplace(history, Waiter{
|
||||||
|
.msg = item->id,
|
||||||
|
.when = when,
|
||||||
|
.notifyBy = notifyBy
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ready) {
|
if (ready) {
|
||||||
|
@ -161,7 +175,7 @@ void System::clearAll() {
|
||||||
_manager->clearAll();
|
_manager->clearAll();
|
||||||
|
|
||||||
for (auto i = _whenMaps.cbegin(), e = _whenMaps.cend(); i != e; ++i) {
|
for (auto i = _whenMaps.cbegin(), e = _whenMaps.cend(); i != e; ++i) {
|
||||||
i.key()->clearNotifications();
|
i->first->clearNotifications();
|
||||||
}
|
}
|
||||||
_whenMaps.clear();
|
_whenMaps.clear();
|
||||||
_whenAlerts.clear();
|
_whenAlerts.clear();
|
||||||
|
@ -182,6 +196,35 @@ void System::clearFromHistory(not_null<History*> history) {
|
||||||
showNext();
|
showNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void System::clearFromSession(not_null<Main::Session*> session) {
|
||||||
|
_manager->clearFromSession(session);
|
||||||
|
|
||||||
|
for (auto i = _whenMaps.begin(), e = _whenMaps.end(); i != e;) {
|
||||||
|
const auto history = i->first;
|
||||||
|
if (&history->session() == session) {
|
||||||
|
history->clearNotifications();
|
||||||
|
i = _whenMaps.erase(i);
|
||||||
|
_whenAlerts.remove(history);
|
||||||
|
_waiters.remove(history);
|
||||||
|
_settingWaiters.remove(history);
|
||||||
|
} else {
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const auto clearFrom = [&](auto &map) {
|
||||||
|
for (auto i = map.begin(); i != map.end();) {
|
||||||
|
if (&i->first->session() == session) {
|
||||||
|
i = map.erase(i);
|
||||||
|
} else {
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
clearFrom(_whenAlerts);
|
||||||
|
clearFrom(_waiters);
|
||||||
|
clearFrom(_settingWaiters);
|
||||||
|
}
|
||||||
|
|
||||||
void System::clearIncomingFromHistory(not_null<History*> history) {
|
void System::clearIncomingFromHistory(not_null<History*> history) {
|
||||||
_manager->clearFromHistory(history);
|
_manager->clearFromHistory(history);
|
||||||
history->clearIncomingNotifications();
|
history->clearIncomingNotifications();
|
||||||
|
@ -203,14 +246,14 @@ void System::clearAllFast() {
|
||||||
|
|
||||||
void System::checkDelayed() {
|
void System::checkDelayed() {
|
||||||
for (auto i = _settingWaiters.begin(); i != _settingWaiters.end();) {
|
for (auto i = _settingWaiters.begin(); i != _settingWaiters.end();) {
|
||||||
const auto history = i.key();
|
const auto history = i->first;
|
||||||
const auto peer = history->peer;
|
const auto peer = history->peer;
|
||||||
auto loaded = false;
|
auto loaded = false;
|
||||||
auto muted = false;
|
auto muted = false;
|
||||||
if (!peer->owner().notifyMuteUnknown(peer)) {
|
if (!peer->owner().notifyMuteUnknown(peer)) {
|
||||||
if (!peer->owner().notifyIsMuted(peer)) {
|
if (!peer->owner().notifyIsMuted(peer)) {
|
||||||
loaded = true;
|
loaded = true;
|
||||||
} else if (const auto from = i.value().notifyBy) {
|
} else if (const auto from = i->second.notifyBy) {
|
||||||
if (!peer->owner().notifyMuteUnknown(from)) {
|
if (!peer->owner().notifyMuteUnknown(from)) {
|
||||||
if (!peer->owner().notifyIsMuted(from)) {
|
if (!peer->owner().notifyIsMuted(from)) {
|
||||||
loaded = true;
|
loaded = true;
|
||||||
|
@ -225,7 +268,7 @@ void System::checkDelayed() {
|
||||||
if (loaded) {
|
if (loaded) {
|
||||||
const auto fullId = FullMsgId(
|
const auto fullId = FullMsgId(
|
||||||
history->channelId(),
|
history->channelId(),
|
||||||
i.value().msg);
|
i->second.msg);
|
||||||
if (const auto item = peer->owner().message(fullId)) {
|
if (const auto item = peer->owner().message(fullId)) {
|
||||||
if (!item->notificationReady()) {
|
if (!item->notificationReady()) {
|
||||||
loaded = false;
|
loaded = false;
|
||||||
|
@ -236,7 +279,7 @@ void System::checkDelayed() {
|
||||||
}
|
}
|
||||||
if (loaded) {
|
if (loaded) {
|
||||||
if (!muted) {
|
if (!muted) {
|
||||||
_waiters.insert(i.key(), i.value());
|
_waiters.emplace(i->first, i->second);
|
||||||
}
|
}
|
||||||
i = _settingWaiters.erase(i);
|
i = _settingWaiters.erase(i);
|
||||||
} else {
|
} else {
|
||||||
|
@ -248,13 +291,15 @@ void System::checkDelayed() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::showGrouped() {
|
void System::showGrouped() {
|
||||||
if (const auto lastItem = session().data().message(_lastHistoryItemId)) {
|
if (const auto session = findSession(_lastHistorySelfId)) {
|
||||||
|
if (const auto lastItem = session->data().message(_lastHistoryItemId)) {
|
||||||
_waitForAllGroupedTimer.cancel();
|
_waitForAllGroupedTimer.cancel();
|
||||||
_manager->showNotification(lastItem, _lastForwardedCount);
|
_manager->showNotification(lastItem, _lastForwardedCount);
|
||||||
_lastForwardedCount = 0;
|
_lastForwardedCount = 0;
|
||||||
_lastHistoryItemId = FullMsgId();
|
_lastHistoryItemId = FullMsgId();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void System::showNext() {
|
void System::showNext() {
|
||||||
if (App::quitting()) return;
|
if (App::quitting()) return;
|
||||||
|
@ -275,12 +320,12 @@ void System::showNext() {
|
||||||
bool alert = false;
|
bool alert = false;
|
||||||
int32 now = base::unixtime::now();
|
int32 now = base::unixtime::now();
|
||||||
for (auto i = _whenAlerts.begin(); i != _whenAlerts.end();) {
|
for (auto i = _whenAlerts.begin(); i != _whenAlerts.end();) {
|
||||||
while (!i.value().isEmpty() && i.value().begin().key() <= ms) {
|
while (!i->second.empty() && i->second.begin()->first <= ms) {
|
||||||
const auto peer = i.key()->peer;
|
const auto peer = i->first->peer;
|
||||||
const auto peerUnknown = peer->owner().notifyMuteUnknown(peer);
|
const auto peerUnknown = peer->owner().notifyMuteUnknown(peer);
|
||||||
const auto peerAlert = !peerUnknown
|
const auto peerAlert = !peerUnknown
|
||||||
&& !peer->owner().notifyIsMuted(peer);
|
&& !peer->owner().notifyIsMuted(peer);
|
||||||
const auto from = i.value().begin().value();
|
const auto from = i->second.begin()->second;
|
||||||
const auto fromUnknown = (!from
|
const auto fromUnknown = (!from
|
||||||
|| peer->owner().notifyMuteUnknown(from));
|
|| peer->owner().notifyMuteUnknown(from));
|
||||||
const auto fromAlert = !fromUnknown
|
const auto fromAlert = !fromUnknown
|
||||||
|
@ -288,16 +333,16 @@ void System::showNext() {
|
||||||
if (peerAlert || fromAlert) {
|
if (peerAlert || fromAlert) {
|
||||||
alert = true;
|
alert = true;
|
||||||
}
|
}
|
||||||
while (!i.value().isEmpty()
|
while (!i->second.empty()
|
||||||
&& i.value().begin().key() <= ms + kMinimalAlertDelay) {
|
&& i->second.begin()->first <= ms + kMinimalAlertDelay) {
|
||||||
i.value().erase(i.value().begin());
|
i->second.erase(i->second.begin());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (i.value().isEmpty()) {
|
if (i->second.empty()) {
|
||||||
i = _whenAlerts.erase(i);
|
i = _whenAlerts.erase(i);
|
||||||
} else {
|
} else {
|
||||||
if (!nextAlert || nextAlert > i.value().begin().key()) {
|
if (!nextAlert || nextAlert > i->second.begin()->first) {
|
||||||
nextAlert = i.value().begin().key();
|
nextAlert = i->second.begin()->first;
|
||||||
}
|
}
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
|
@ -320,7 +365,7 @@ void System::showNext() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_waiters.isEmpty() || !settings.desktopNotify() || Platform::Notifications::SkipToast()) {
|
if (_waiters.empty() || !settings.desktopNotify() || Platform::Notifications::SkipToast()) {
|
||||||
if (nextAlert) {
|
if (nextAlert) {
|
||||||
_waitTimer.callOnce(nextAlert - ms);
|
_waitTimer.callOnce(nextAlert - ms);
|
||||||
}
|
}
|
||||||
|
@ -332,8 +377,8 @@ void System::showNext() {
|
||||||
HistoryItem *notifyItem = nullptr;
|
HistoryItem *notifyItem = nullptr;
|
||||||
History *notifyHistory = nullptr;
|
History *notifyHistory = nullptr;
|
||||||
for (auto i = _waiters.begin(); i != _waiters.end();) {
|
for (auto i = _waiters.begin(); i != _waiters.end();) {
|
||||||
History *history = i.key();
|
const auto history = i->first;
|
||||||
if (history->currentNotification() && history->currentNotification()->id != i.value().msg) {
|
if (history->currentNotification() && history->currentNotification()->id != i->second.msg) {
|
||||||
auto j = _whenMaps.find(history);
|
auto j = _whenMaps.find(history);
|
||||||
if (j == _whenMaps.end()) {
|
if (j == _whenMaps.end()) {
|
||||||
history->clearNotifications();
|
history->clearNotifications();
|
||||||
|
@ -341,10 +386,10 @@ void System::showNext() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
do {
|
do {
|
||||||
auto k = j.value().constFind(history->currentNotification()->id);
|
auto k = j->second.find(history->currentNotification()->id);
|
||||||
if (k != j.value().cend()) {
|
if (k != j->second.cend()) {
|
||||||
i.value().msg = k.key();
|
i->second.msg = k->first;
|
||||||
i.value().when = k.value();
|
i->second.when = k->second;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
history->skipNotification();
|
history->skipNotification();
|
||||||
|
@ -355,7 +400,7 @@ void System::showNext() {
|
||||||
i = _waiters.erase(i);
|
i = _waiters.erase(i);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
auto when = i.value().when;
|
auto when = i->second.when;
|
||||||
if (!notifyItem || next > when) {
|
if (!notifyItem || next > when) {
|
||||||
next = when;
|
next = when;
|
||||||
notifyItem = history->currentNotification();
|
notifyItem = history->currentNotification();
|
||||||
|
@ -390,12 +435,15 @@ void System::showNext() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
j.value().remove((groupedItem ? groupedItem : notifyItem)->id);
|
j->second.remove((groupedItem ? groupedItem : notifyItem)->id);
|
||||||
do {
|
do {
|
||||||
const auto k = j.value().constFind(history->currentNotification()->id);
|
const auto k = j->second.find(history->currentNotification()->id);
|
||||||
if (k != j.value().cend()) {
|
if (k != j->second.cend()) {
|
||||||
nextNotify = history->currentNotification();
|
nextNotify = history->currentNotification();
|
||||||
_waiters.insert(notifyHistory, Waiter(k.key(), k.value(), 0));
|
_waiters.emplace(notifyHistory, Waiter{
|
||||||
|
.msg = k->first,
|
||||||
|
.when = k->second
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
history->skipNotification();
|
history->skipNotification();
|
||||||
|
@ -482,8 +530,8 @@ void System::updateAll() {
|
||||||
_manager->updateAll();
|
_manager->updateAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
Manager::DisplayOptions Manager::getNotificationOptions(HistoryItem *item) {
|
Manager::DisplayOptions Manager::GetNotificationOptions(HistoryItem *item) {
|
||||||
const auto hideEverything = Core::App().locked()
|
const auto hideEverything = Core::App().passcodeLocked()
|
||||||
|| Global::ScreenIsLocked();
|
|| Global::ScreenIsLocked();
|
||||||
|
|
||||||
const auto view = Core::App().settings().notifyView();
|
const auto view = Core::App().settings().notifyView();
|
||||||
|
@ -499,20 +547,26 @@ Manager::DisplayOptions Manager::getNotificationOptions(HistoryItem *item) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::notificationActivated(PeerId peerId, MsgId msgId) {
|
void Manager::notificationActivated(NotificationId id) {
|
||||||
onBeforeNotificationActivated(peerId, msgId);
|
onBeforeNotificationActivated(id);
|
||||||
if (auto window = App::wnd()) {
|
if (const auto session = system()->findSession(id.selfId)) {
|
||||||
auto history = system()->session().data().history(peerId);
|
if (session->windows().empty()) {
|
||||||
window->showFromTray();
|
Core::App().domain().activate(&session->account());
|
||||||
window->reActivateWindow();
|
}
|
||||||
if (Core::App().locked()) {
|
if (!session->windows().empty()) {
|
||||||
window->setInnerFocus();
|
const auto window = session->windows().front();
|
||||||
|
const auto history = session->data().history(id.peerId);
|
||||||
|
window->widget()->showFromTray();
|
||||||
|
window->widget()->reActivateWindow();
|
||||||
|
if (Core::App().passcodeLocked()) {
|
||||||
|
window->widget()->setInnerFocus();
|
||||||
system()->clearAll();
|
system()->clearAll();
|
||||||
} else {
|
} else {
|
||||||
openNotificationMessage(history, msgId);
|
openNotificationMessage(history, id.msgId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onAfterNotificationActivated(peerId, msgId);
|
}
|
||||||
|
onAfterNotificationActivated(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::openNotificationMessage(
|
void Manager::openNotificationMessage(
|
||||||
|
@ -548,20 +602,29 @@ void Manager::openNotificationMessage(
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::notificationReplied(
|
void Manager::notificationReplied(
|
||||||
PeerId peerId,
|
NotificationId id,
|
||||||
MsgId msgId,
|
|
||||||
const TextWithTags &reply) {
|
const TextWithTags &reply) {
|
||||||
if (!peerId) return;
|
if (!id.selfId || !id.peerId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const auto history = system()->session().data().history(peerId);
|
const auto session = system()->findSession(id.selfId);
|
||||||
|
if (!session) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto history = session->data().history(id.peerId);
|
||||||
|
|
||||||
auto message = Api::MessageToSend(history);
|
auto message = Api::MessageToSend(history);
|
||||||
message.textWithTags = reply;
|
message.textWithTags = reply;
|
||||||
message.action.replyTo = (msgId > 0 && !history->peer->isUser()) ? msgId : 0;
|
message.action.replyTo = (id.msgId > 0 && !history->peer->isUser())
|
||||||
|
? id.msgId
|
||||||
|
: 0;
|
||||||
message.action.clearDraft = false;
|
message.action.clearDraft = false;
|
||||||
history->session().api().sendMessage(std::move(message));
|
history->session().api().sendMessage(std::move(message));
|
||||||
|
|
||||||
const auto item = history->owner().message(history->channelId(), msgId);
|
const auto item = history->owner().message(
|
||||||
|
history->channelId(),
|
||||||
|
id.msgId);
|
||||||
if (item && item->isUnreadMention() && !item->isUnreadMedia()) {
|
if (item && item->isUnreadMention() && !item->isUnreadMedia()) {
|
||||||
history->session().api().markMediaRead(item);
|
history->session().api().markMediaRead(item);
|
||||||
}
|
}
|
||||||
|
@ -570,7 +633,7 @@ void Manager::notificationReplied(
|
||||||
void NativeManager::doShowNotification(
|
void NativeManager::doShowNotification(
|
||||||
not_null<HistoryItem*> item,
|
not_null<HistoryItem*> item,
|
||||||
int forwardedCount) {
|
int forwardedCount) {
|
||||||
const auto options = getNotificationOptions(item);
|
const auto options = GetNotificationOptions(item);
|
||||||
|
|
||||||
const auto peer = item->history()->peer;
|
const auto peer = item->history()->peer;
|
||||||
const auto scheduled = !options.hideNameAndPhoto
|
const auto scheduled = !options.hideNameAndPhoto
|
||||||
|
|
|
@ -64,7 +64,10 @@ class Manager;
|
||||||
|
|
||||||
class System final : private base::Subscriber {
|
class System final : private base::Subscriber {
|
||||||
public:
|
public:
|
||||||
explicit System(not_null<Main::Session*> session);
|
System();
|
||||||
|
~System();
|
||||||
|
|
||||||
|
[[nodiscard]] Main::Session *findSession(UserId selfId) const;
|
||||||
|
|
||||||
void createManager();
|
void createManager();
|
||||||
|
|
||||||
|
@ -72,6 +75,7 @@ public:
|
||||||
void schedule(not_null<HistoryItem*> item);
|
void schedule(not_null<HistoryItem*> item);
|
||||||
void clearFromHistory(not_null<History*> history);
|
void clearFromHistory(not_null<History*> history);
|
||||||
void clearIncomingFromHistory(not_null<History*> history);
|
void clearIncomingFromHistory(not_null<History*> history);
|
||||||
|
void clearFromSession(not_null<Main::Session*> session);
|
||||||
void clearFromItem(not_null<HistoryItem*> item);
|
void clearFromItem(not_null<HistoryItem*> item);
|
||||||
void clearAll();
|
void clearAll();
|
||||||
void clearAllFast();
|
void clearAllFast();
|
||||||
|
@ -81,12 +85,6 @@ public:
|
||||||
return _settingsChanged;
|
return _settingsChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
Main::Session &session() const {
|
|
||||||
return *_session;
|
|
||||||
}
|
|
||||||
|
|
||||||
~System();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct SkipState {
|
struct SkipState {
|
||||||
enum Value {
|
enum Value {
|
||||||
|
@ -97,34 +95,29 @@ private:
|
||||||
Value value = Value::Unknown;
|
Value value = Value::Unknown;
|
||||||
bool silent = false;
|
bool silent = false;
|
||||||
};
|
};
|
||||||
|
struct Waiter {
|
||||||
|
MsgId msg;
|
||||||
|
crl::time when;
|
||||||
|
PeerData *notifyBy = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
SkipState skipNotification(not_null<HistoryItem*> item) const;
|
[[nodiscard]] SkipState skipNotification(
|
||||||
|
not_null<HistoryItem*> item) const;
|
||||||
|
|
||||||
void showNext();
|
void showNext();
|
||||||
void showGrouped();
|
void showGrouped();
|
||||||
void ensureSoundCreated();
|
void ensureSoundCreated();
|
||||||
|
|
||||||
not_null<Main::Session*> _session;
|
base::flat_map<
|
||||||
|
not_null<History*>,
|
||||||
|
base::flat_map<MsgId, crl::time>> _whenMaps;
|
||||||
|
|
||||||
QMap<History*, QMap<MsgId, crl::time>> _whenMaps;
|
base::flat_map<not_null<History*>, Waiter> _waiters;
|
||||||
|
base::flat_map<not_null<History*>, Waiter> _settingWaiters;
|
||||||
struct Waiter {
|
|
||||||
Waiter(MsgId msg, crl::time when, PeerData *notifyBy)
|
|
||||||
: msg(msg)
|
|
||||||
, when(when)
|
|
||||||
, notifyBy(notifyBy) {
|
|
||||||
}
|
|
||||||
MsgId msg;
|
|
||||||
crl::time when;
|
|
||||||
PeerData *notifyBy;
|
|
||||||
};
|
|
||||||
using Waiters = QMap<History*, Waiter>;
|
|
||||||
Waiters _waiters;
|
|
||||||
Waiters _settingWaiters;
|
|
||||||
base::Timer _waitTimer;
|
base::Timer _waitTimer;
|
||||||
base::Timer _waitForAllGroupedTimer;
|
base::Timer _waitForAllGroupedTimer;
|
||||||
|
|
||||||
QMap<History*, QMap<crl::time, PeerData*>> _whenAlerts;
|
base::flat_map<not_null<History*>, base::flat_map<crl::time, PeerData*>> _whenAlerts;
|
||||||
|
|
||||||
std::unique_ptr<Manager> _manager;
|
std::unique_ptr<Manager> _manager;
|
||||||
|
|
||||||
|
@ -133,12 +126,28 @@ private:
|
||||||
std::unique_ptr<Media::Audio::Track> _soundTrack;
|
std::unique_ptr<Media::Audio::Track> _soundTrack;
|
||||||
|
|
||||||
int _lastForwardedCount = 0;
|
int _lastForwardedCount = 0;
|
||||||
|
UserId _lastHistorySelfId = 0;
|
||||||
FullMsgId _lastHistoryItemId;
|
FullMsgId _lastHistoryItemId;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Manager {
|
class Manager {
|
||||||
public:
|
public:
|
||||||
|
struct NotificationId {
|
||||||
|
PeerId peerId = 0;
|
||||||
|
MsgId msgId = 0;
|
||||||
|
UserId selfId = 0;
|
||||||
|
};
|
||||||
|
struct FullPeer {
|
||||||
|
PeerId peerId = 0;
|
||||||
|
UserId selfId = 0;
|
||||||
|
|
||||||
|
friend inline bool operator<(const FullPeer &a, const FullPeer &b) {
|
||||||
|
return std::tie(a.peerId, a.selfId)
|
||||||
|
< std::tie(b.peerId, b.selfId);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
explicit Manager(not_null<System*> system) : _system(system) {
|
explicit Manager(not_null<System*> system) : _system(system) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,19 +171,20 @@ public:
|
||||||
void clearFromHistory(not_null<History*> history) {
|
void clearFromHistory(not_null<History*> history) {
|
||||||
doClearFromHistory(history);
|
doClearFromHistory(history);
|
||||||
}
|
}
|
||||||
|
void clearFromSession(not_null<Main::Session*> session) {
|
||||||
|
doClearFromSession(session);
|
||||||
|
}
|
||||||
|
|
||||||
void notificationActivated(PeerId peerId, MsgId msgId);
|
void notificationActivated(NotificationId id);
|
||||||
void notificationReplied(
|
void notificationReplied(NotificationId id, const TextWithTags &reply);
|
||||||
PeerId peerId,
|
|
||||||
MsgId msgId,
|
|
||||||
const TextWithTags &reply);
|
|
||||||
|
|
||||||
struct DisplayOptions {
|
struct DisplayOptions {
|
||||||
bool hideNameAndPhoto;
|
bool hideNameAndPhoto = false;
|
||||||
bool hideMessageText;
|
bool hideMessageText = false;
|
||||||
bool hideReplyButton;
|
bool hideReplyButton = false;
|
||||||
};
|
};
|
||||||
static DisplayOptions getNotificationOptions(HistoryItem *item);
|
[[nodiscard]] static DisplayOptions GetNotificationOptions(
|
||||||
|
HistoryItem *item);
|
||||||
|
|
||||||
virtual ~Manager() = default;
|
virtual ~Manager() = default;
|
||||||
|
|
||||||
|
@ -191,9 +201,10 @@ protected:
|
||||||
virtual void doClearAllFast() = 0;
|
virtual void doClearAllFast() = 0;
|
||||||
virtual void doClearFromItem(not_null<HistoryItem*> item) = 0;
|
virtual void doClearFromItem(not_null<HistoryItem*> item) = 0;
|
||||||
virtual void doClearFromHistory(not_null<History*> history) = 0;
|
virtual void doClearFromHistory(not_null<History*> history) = 0;
|
||||||
virtual void onBeforeNotificationActivated(PeerId peerId, MsgId msgId) {
|
virtual void doClearFromSession(not_null<Main::Session*> session) = 0;
|
||||||
|
virtual void onBeforeNotificationActivated(NotificationId id) {
|
||||||
}
|
}
|
||||||
virtual void onAfterNotificationActivated(PeerId peerId, MsgId msgId) {
|
virtual void onAfterNotificationActivated(NotificationId id) {
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -67,11 +67,6 @@ std::unique_ptr<Manager> Create(System *system) {
|
||||||
Manager::Manager(System *system)
|
Manager::Manager(System *system)
|
||||||
: Notifications::Manager(system)
|
: Notifications::Manager(system)
|
||||||
, _inputCheckTimer([=] { checkLastInput(); }) {
|
, _inputCheckTimer([=] { checkLastInput(); }) {
|
||||||
subscribe(system->session().downloaderTaskFinished(), [this] {
|
|
||||||
for (const auto ¬ification : _notifications) {
|
|
||||||
notification->updatePeerPhoto();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
subscribe(system->settingsChanged(), [this](ChangeType change) {
|
subscribe(system->settingsChanged(), [this](ChangeType change) {
|
||||||
settingsChanged(change);
|
settingsChanged(change);
|
||||||
});
|
});
|
||||||
|
@ -212,7 +207,8 @@ void Manager::showNextFromQueue() {
|
||||||
auto queued = _queuedNotifications.front();
|
auto queued = _queuedNotifications.front();
|
||||||
_queuedNotifications.pop_front();
|
_queuedNotifications.pop_front();
|
||||||
|
|
||||||
auto notification = std::make_unique<Notification>(
|
subscribeToSession(&queued.history->session());
|
||||||
|
_notifications.push_back(std::make_unique<Notification>(
|
||||||
this,
|
this,
|
||||||
queued.history,
|
queued.history,
|
||||||
queued.peer,
|
queued.peer,
|
||||||
|
@ -222,8 +218,7 @@ void Manager::showNextFromQueue() {
|
||||||
queued.fromScheduled,
|
queued.fromScheduled,
|
||||||
startPosition,
|
startPosition,
|
||||||
startShift,
|
startShift,
|
||||||
shiftDirection);
|
shiftDirection));
|
||||||
_notifications.push_back(std::move(notification));
|
|
||||||
--count;
|
--count;
|
||||||
} while (count > 0 && !_queuedNotifications.empty());
|
} while (count > 0 && !_queuedNotifications.empty());
|
||||||
|
|
||||||
|
@ -231,6 +226,32 @@ void Manager::showNextFromQueue() {
|
||||||
checkLastInput();
|
checkLastInput();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Manager::subscribeToSession(not_null<Main::Session*> session) {
|
||||||
|
auto i = _subscriptions.find(session);
|
||||||
|
if (i == _subscriptions.end()) {
|
||||||
|
i = _subscriptions.emplace(session, base::Subscription()).first;
|
||||||
|
session->lifetime().add([=] {
|
||||||
|
_subscriptions.remove(session);
|
||||||
|
});
|
||||||
|
} else if (i->second) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
i->second = session->downloaderTaskFinished().add_subscription([=] {
|
||||||
|
auto found = false;
|
||||||
|
for (const auto ¬ification : _notifications) {
|
||||||
|
if (const auto history = notification->maybeHistory()) {
|
||||||
|
if (&history->session() == session) {
|
||||||
|
notification->updatePeerPhoto();
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
_subscriptions[session].destroy();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void Manager::moveWidgets() {
|
void Manager::moveWidgets() {
|
||||||
auto shift = st::notifyDeltaY;
|
auto shift = st::notifyDeltaY;
|
||||||
int lastShift = 0, lastShiftCurrent = 0, count = 0;
|
int lastShift = 0, lastShiftCurrent = 0, count = 0;
|
||||||
|
@ -334,7 +355,7 @@ void Manager::doClearFromHistory(not_null<History*> history) {
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for_const (auto ¬ification, _notifications) {
|
for (const auto ¬ification : _notifications) {
|
||||||
if (notification->unlinkHistory(history)) {
|
if (notification->unlinkHistory(history)) {
|
||||||
_positionsOutdated = true;
|
_positionsOutdated = true;
|
||||||
}
|
}
|
||||||
|
@ -342,6 +363,22 @@ void Manager::doClearFromHistory(not_null<History*> history) {
|
||||||
showNextFromQueue();
|
showNextFromQueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Manager::doClearFromSession(not_null<Main::Session*> session) {
|
||||||
|
for (auto i = _queuedNotifications.begin(); i != _queuedNotifications.cend();) {
|
||||||
|
if (&i->history->session() == session) {
|
||||||
|
i = _queuedNotifications.erase(i);
|
||||||
|
} else {
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const auto ¬ification : _notifications) {
|
||||||
|
if (notification->unlinkSession(session)) {
|
||||||
|
_positionsOutdated = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
showNextFromQueue();
|
||||||
|
}
|
||||||
|
|
||||||
void Manager::doClearFromItem(not_null<HistoryItem*> item) {
|
void Manager::doClearFromItem(not_null<HistoryItem*> item) {
|
||||||
_queuedNotifications.erase(std::remove_if(_queuedNotifications.begin(), _queuedNotifications.end(), [&](auto &queued) {
|
_queuedNotifications.erase(std::remove_if(_queuedNotifications.begin(), _queuedNotifications.end(), [&](auto &queued) {
|
||||||
return (queued.item == item);
|
return (queued.item == item);
|
||||||
|
@ -678,7 +715,7 @@ void Notification::actionsOpacityCallback() {
|
||||||
void Notification::updateNotifyDisplay() {
|
void Notification::updateNotifyDisplay() {
|
||||||
if (!_history || (!_item && _forwardedCount < 2)) return;
|
if (!_history || (!_item && _forwardedCount < 2)) return;
|
||||||
|
|
||||||
const auto options = Manager::getNotificationOptions(_item);
|
const auto options = Manager::GetNotificationOptions(_item);
|
||||||
_hideReplyButton = options.hideReplyButton;
|
_hideReplyButton = options.hideReplyButton;
|
||||||
|
|
||||||
int32 w = width(), h = height();
|
int32 w = width(), h = height();
|
||||||
|
@ -832,7 +869,7 @@ bool Notification::unlinkItem(HistoryItem *deleted) {
|
||||||
bool Notification::canReply() const {
|
bool Notification::canReply() const {
|
||||||
return !_hideReplyButton
|
return !_hideReplyButton
|
||||||
&& (_item != nullptr)
|
&& (_item != nullptr)
|
||||||
&& !Core::App().locked()
|
&& !Core::App().passcodeLocked()
|
||||||
&& (Core::App().settings().notifyView() <= dbinvShowPreview);
|
&& (Core::App().settings().notifyView() <= dbinvShowPreview);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -901,16 +938,23 @@ void Notification::showReplyField() {
|
||||||
void Notification::sendReply() {
|
void Notification::sendReply() {
|
||||||
if (!_history) return;
|
if (!_history) return;
|
||||||
|
|
||||||
auto peerId = _history->peer->id;
|
|
||||||
auto msgId = _item ? _item->id : ShowAtUnreadMsgId;
|
|
||||||
manager()->notificationReplied(
|
manager()->notificationReplied(
|
||||||
peerId,
|
myId(),
|
||||||
msgId,
|
|
||||||
_replyArea->getTextWithAppliedMarkdown());
|
_replyArea->getTextWithAppliedMarkdown());
|
||||||
|
|
||||||
manager()->startAllHiding();
|
manager()->startAllHiding();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Notifications::Manager::NotificationId Notification::myId() const {
|
||||||
|
if (!_history) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
const auto selfId = _history->session().userId();
|
||||||
|
const auto peerId = _history->peer->id;
|
||||||
|
const auto msgId = _item ? _item->id : ShowAtUnreadMsgId;
|
||||||
|
return { .peerId = peerId, .msgId = msgId, .selfId = selfId };
|
||||||
|
}
|
||||||
|
|
||||||
void Notification::changeHeight(int newHeight) {
|
void Notification::changeHeight(int newHeight) {
|
||||||
manager()->changeNotificationHeight(this, newHeight);
|
manager()->changeNotificationHeight(this, newHeight);
|
||||||
}
|
}
|
||||||
|
@ -925,6 +969,16 @@ bool Notification::unlinkHistory(History *history) {
|
||||||
return unlink;
|
return unlink;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Notification::unlinkSession(not_null<Main::Session*> session) {
|
||||||
|
const auto unlink = _history && (&_history->session() == session);
|
||||||
|
if (unlink) {
|
||||||
|
hideFast();
|
||||||
|
_history = nullptr;
|
||||||
|
_item = nullptr;
|
||||||
|
}
|
||||||
|
return unlink;
|
||||||
|
}
|
||||||
|
|
||||||
void Notification::enterEventHook(QEvent *e) {
|
void Notification::enterEventHook(QEvent *e) {
|
||||||
if (!_history) return;
|
if (!_history) return;
|
||||||
manager()->stopAllHiding();
|
manager()->stopAllHiding();
|
||||||
|
@ -951,9 +1005,7 @@ void Notification::mousePressEvent(QMouseEvent *e) {
|
||||||
unlinkHistoryInManager();
|
unlinkHistoryInManager();
|
||||||
} else {
|
} else {
|
||||||
e->ignore();
|
e->ignore();
|
||||||
auto peerId = _history->peer->id;
|
manager()->notificationActivated(myId());
|
||||||
auto msgId = _item ? _item->id : ShowAtUnreadMsgId;
|
|
||||||
manager()->notificationActivated(peerId, msgId);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,19 +38,18 @@ class HideAllButton;
|
||||||
class Manager;
|
class Manager;
|
||||||
std::unique_ptr<Manager> Create(System *system);
|
std::unique_ptr<Manager> Create(System *system);
|
||||||
|
|
||||||
class Manager : public Notifications::Manager, private base::Subscriber {
|
class Manager final : public Notifications::Manager, private base::Subscriber {
|
||||||
public:
|
public:
|
||||||
Manager(System *system);
|
Manager(System *system);
|
||||||
|
~Manager();
|
||||||
|
|
||||||
template <typename Method>
|
template <typename Method>
|
||||||
void enumerateNotifications(Method method) {
|
void enumerateNotifications(Method method) {
|
||||||
for_const (auto ¬ification, _notifications) {
|
for (const auto ¬ification : _notifications) {
|
||||||
method(notification);
|
method(notification);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
~Manager();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class internal::Notification;
|
friend class internal::Notification;
|
||||||
friend class internal::HideAllButton;
|
friend class internal::HideAllButton;
|
||||||
|
@ -58,7 +57,7 @@ private:
|
||||||
using Notification = internal::Notification;
|
using Notification = internal::Notification;
|
||||||
using HideAllButton = internal::HideAllButton;
|
using HideAllButton = internal::HideAllButton;
|
||||||
|
|
||||||
QPixmap hiddenUserpicPlaceholder() const;
|
[[nodiscard]] QPixmap hiddenUserpicPlaceholder() const;
|
||||||
|
|
||||||
void doUpdateAll() override;
|
void doUpdateAll() override;
|
||||||
void doShowNotification(
|
void doShowNotification(
|
||||||
|
@ -67,6 +66,7 @@ private:
|
||||||
void doClearAll() override;
|
void doClearAll() override;
|
||||||
void doClearAllFast() override;
|
void doClearAllFast() override;
|
||||||
void doClearFromHistory(not_null<History*> history) override;
|
void doClearFromHistory(not_null<History*> history) override;
|
||||||
|
void doClearFromSession(not_null<Main::Session*> session) override;
|
||||||
void doClearFromItem(not_null<HistoryItem*> item) override;
|
void doClearFromItem(not_null<HistoryItem*> item) override;
|
||||||
|
|
||||||
void showNextFromQueue();
|
void showNextFromQueue();
|
||||||
|
@ -86,7 +86,12 @@ private:
|
||||||
|
|
||||||
bool hasReplyingNotification() const;
|
bool hasReplyingNotification() const;
|
||||||
|
|
||||||
|
void subscribeToSession(not_null<Main::Session*> session);
|
||||||
|
|
||||||
std::vector<std::unique_ptr<Notification>> _notifications;
|
std::vector<std::unique_ptr<Notification>> _notifications;
|
||||||
|
base::flat_map<
|
||||||
|
not_null<Main::Session*>,
|
||||||
|
base::Subscription> _subscriptions;
|
||||||
|
|
||||||
std::unique_ptr<HideAllButton> _hideAll;
|
std::unique_ptr<HideAllButton> _hideAll;
|
||||||
|
|
||||||
|
@ -181,7 +186,7 @@ protected:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Notification : public Widget {
|
class Notification final : public Widget {
|
||||||
public:
|
public:
|
||||||
Notification(
|
Notification(
|
||||||
not_null<Manager*> manager,
|
not_null<Manager*> manager,
|
||||||
|
@ -207,10 +212,14 @@ public:
|
||||||
bool isReplying() const {
|
bool isReplying() const {
|
||||||
return _replyArea && !isUnlinked();
|
return _replyArea && !isUnlinked();
|
||||||
}
|
}
|
||||||
|
[[nodiscard]] History *maybeHistory() const {
|
||||||
|
return _history;
|
||||||
|
}
|
||||||
|
|
||||||
// Called only by Manager.
|
// Called only by Manager.
|
||||||
bool unlinkItem(HistoryItem *del);
|
bool unlinkItem(HistoryItem *del);
|
||||||
bool unlinkHistory(History *history = nullptr);
|
bool unlinkHistory(History *history = nullptr);
|
||||||
|
bool unlinkSession(not_null<Main::Session*> session);
|
||||||
bool checkLastInput(bool hasReplyingNotifications);
|
bool checkLastInput(bool hasReplyingNotifications);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -236,6 +245,8 @@ private:
|
||||||
void updateGeometry(int x, int y, int width, int height) override;
|
void updateGeometry(int x, int y, int width, int height) override;
|
||||||
void actionsOpacityCallback();
|
void actionsOpacityCallback();
|
||||||
|
|
||||||
|
[[nodiscard]] Notifications::Manager::NotificationId myId() const;
|
||||||
|
|
||||||
const not_null<PeerData*> _peer;
|
const not_null<PeerData*> _peer;
|
||||||
|
|
||||||
QPixmap _cache;
|
QPixmap _cache;
|
||||||
|
|
Loading…
Add table
Reference in a new issue