mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-16 14:17:12 +02:00
Notifications management moved to AuthSession.
Also implemented Global::WorkMode() as an base::Variable.
This commit is contained in:
parent
b14ba398e6
commit
81790b2271
80 changed files with 1299 additions and 1152 deletions
|
@ -31,6 +31,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
#include "auth_session.h"
|
||||
#include "boxes/confirmbox.h"
|
||||
#include "window/themes/window_theme.h"
|
||||
#include "window/notifications_manager.h"
|
||||
|
||||
ApiWrap::ApiWrap(QObject *parent) : QObject(parent)
|
||||
, _messageDataResolveDelayed(new SingleDelayedCall(this, "resolveMessageDatas")) {
|
||||
|
@ -1016,7 +1017,7 @@ PeerData *ApiWrap::notifySettingReceived(MTPInputNotifyPeer notifyPeer, const MT
|
|||
}
|
||||
} break;
|
||||
}
|
||||
App::wnd()->notifySettingGot();
|
||||
AuthSession::Current().notifications()->checkDelayed();
|
||||
return requestedPeer;
|
||||
}
|
||||
|
||||
|
|
|
@ -203,15 +203,14 @@ namespace {
|
|||
Media::Player::mixer()->stopAndClear();
|
||||
if (auto w = wnd()) {
|
||||
w->tempDirDelete(Local::ClearManagerAll);
|
||||
w->notifyClearFast();
|
||||
w->setupIntro();
|
||||
}
|
||||
histories().clear();
|
||||
Messenger::Instance().authSessionDestroy();
|
||||
Local::reset();
|
||||
Window::Theme::Background()->reset();
|
||||
|
||||
cSetOtherOnline(0);
|
||||
histories().clear();
|
||||
globalNotifyAllPtr = UnknownNotifySettings;
|
||||
globalNotifyUsersPtr = UnknownNotifySettings;
|
||||
globalNotifyChatsPtr = UnknownNotifySettings;
|
||||
|
@ -2014,9 +2013,7 @@ namespace {
|
|||
dependent->dependencyItemRemoved(item);
|
||||
}
|
||||
}
|
||||
if (auto manager = Window::Notifications::GetManager()) {
|
||||
manager->clearFromItem(item);
|
||||
}
|
||||
AuthSession::Current().notifications()->clearFromItem(item);
|
||||
if (Global::started() && !App::quitting()) {
|
||||
Global::RefItemRemoved().notify(item, true);
|
||||
}
|
||||
|
@ -2038,13 +2035,13 @@ namespace {
|
|||
::dependentItems.clear();
|
||||
|
||||
QVector<HistoryItem*> toDelete;
|
||||
for_const (HistoryItem *item, msgsData) {
|
||||
for_const (auto item, msgsData) {
|
||||
if (item->detached()) {
|
||||
toDelete.push_back(item);
|
||||
}
|
||||
}
|
||||
for_const (const MsgsData &chMsgsData, channelMsgsData) {
|
||||
for_const (HistoryItem *item, chMsgsData) {
|
||||
for_const (auto &chMsgsData, channelMsgsData) {
|
||||
for_const (auto item, chMsgsData) {
|
||||
if (item->detached()) {
|
||||
toDelete.push_back(item);
|
||||
}
|
||||
|
@ -2052,8 +2049,8 @@ namespace {
|
|||
}
|
||||
msgsData.clear();
|
||||
channelMsgsData.clear();
|
||||
for (int32 i = 0, l = toDelete.size(); i < l; ++i) {
|
||||
delete toDelete[i];
|
||||
for_const (auto item, toDelete) {
|
||||
delete item;
|
||||
}
|
||||
|
||||
clearMousedItems();
|
||||
|
|
|
@ -319,10 +319,6 @@ void Application::closeApplication() {
|
|||
if (App::launchState() == App::QuitProcessed) return;
|
||||
App::setLaunchState(App::QuitProcessed);
|
||||
|
||||
if (auto manager = Window::Notifications::GetManager()) {
|
||||
manager->clearAllFast();
|
||||
}
|
||||
|
||||
if (_messengerInstance) {
|
||||
Messenger::Instance().prepareToDestroy();
|
||||
_messengerInstance.reset();
|
||||
|
|
|
@ -21,18 +21,41 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
#include "auth_session.h"
|
||||
|
||||
#include "messenger.h"
|
||||
#include "storage/file_download.h"
|
||||
#include "window/notifications_manager.h"
|
||||
|
||||
AuthSession::AuthSession(UserId userId) : _userId(userId) {
|
||||
AuthSession::AuthSession(UserId userId)
|
||||
: _userId(userId)
|
||||
, _downloader(std::make_unique<Storage::Downloader>())
|
||||
, _notifications(std::make_unique<Window::Notifications::System>(this)) {
|
||||
t_assert(_userId != 0);
|
||||
}
|
||||
|
||||
AuthSession *AuthSession::Current() {
|
||||
return Messenger::Instance().authSession();
|
||||
bool AuthSession::Exists() {
|
||||
return (Messenger::Instance().authSession() != nullptr);
|
||||
}
|
||||
|
||||
AuthSession &AuthSession::Current() {
|
||||
auto result = Messenger::Instance().authSession();
|
||||
t_assert(result != nullptr);
|
||||
return *result;
|
||||
}
|
||||
|
||||
UserData *AuthSession::CurrentUser() {
|
||||
if (auto userId = CurrentUserId()) {
|
||||
return App::user(userId);
|
||||
}
|
||||
return nullptr;
|
||||
return App::user(CurrentUserId());
|
||||
}
|
||||
|
||||
base::Observable<void> &AuthSession::CurrentDownloaderTaskFinished() {
|
||||
return Current().downloader()->taskFinished();
|
||||
}
|
||||
|
||||
bool AuthSession::validateSelf(const MTPUser &user) {
|
||||
if (user.type() != mtpc_user || !user.c_user().is_self() || user.c_user().vid.v != userId()) {
|
||||
LOG(("Auth Error: wrong self user received."));
|
||||
App::logOutDelayed();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
AuthSession::~AuthSession() = default;
|
||||
|
|
|
@ -20,29 +20,55 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
class AuthSession {
|
||||
namespace Storage {
|
||||
class Downloader;
|
||||
} // namespace Storage
|
||||
|
||||
namespace Window {
|
||||
namespace Notifications {
|
||||
class System;
|
||||
} // namespace Notifications
|
||||
} // namespace Window
|
||||
|
||||
class AuthSession final {
|
||||
public:
|
||||
AuthSession(UserId userId);
|
||||
|
||||
AuthSession(const AuthSession &other) = delete;
|
||||
AuthSession &operator=(const AuthSession &other) = delete;
|
||||
|
||||
static AuthSession *Current();
|
||||
static bool Exists();
|
||||
|
||||
static AuthSession &Current();
|
||||
static UserId CurrentUserId() {
|
||||
auto current = Current();
|
||||
return current ? current->userId() : 0;
|
||||
return Current().userId();
|
||||
}
|
||||
static PeerId CurrentUserPeerId() {
|
||||
auto userId = CurrentUserId();
|
||||
return userId ? peerFromUser(userId) : 0;
|
||||
return peerFromUser(CurrentUserId());
|
||||
}
|
||||
static UserData *CurrentUser();
|
||||
|
||||
UserId userId() const {
|
||||
return _userId;
|
||||
}
|
||||
bool validateSelf(const MTPUser &user);
|
||||
|
||||
Storage::Downloader *downloader() {
|
||||
return _downloader.get();
|
||||
}
|
||||
|
||||
static base::Observable<void> &CurrentDownloaderTaskFinished();
|
||||
|
||||
Window::Notifications::System *notifications() {
|
||||
return _notifications.get();
|
||||
}
|
||||
|
||||
~AuthSession();
|
||||
|
||||
private:
|
||||
UserId _userId = 0;
|
||||
|
||||
const std::unique_ptr<Storage::Downloader> _downloader;
|
||||
const std::unique_ptr<Window::Notifications::System> _notifications;
|
||||
|
||||
};
|
||||
|
|
|
@ -38,6 +38,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
#include "mainwindow.h"
|
||||
#include "apiwrap.h"
|
||||
#include "observer_peer.h"
|
||||
#include "auth_session.h"
|
||||
|
||||
AddContactBox::AddContactBox(QWidget*, QString fname, QString lname, QString phone)
|
||||
: _first(this, st::defaultInputField, lang(lng_signup_firstname), fname)
|
||||
|
@ -1119,7 +1120,7 @@ void RevokePublicLinkBox::prepare() {
|
|||
|
||||
addButton(lang(lng_cancel), [this] { closeBox(); });
|
||||
|
||||
subscribe(FileDownload::ImageLoaded(), [this] { update(); });
|
||||
subscribe(AuthSession::CurrentDownloaderTaskFinished(), [this] { update(); });
|
||||
|
||||
updateMaxHeight();
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
#include "styles/style_overview.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "ui/effects/round_checkbox.h"
|
||||
#include "auth_session.h"
|
||||
|
||||
BackgroundBox::BackgroundBox(QWidget*) {
|
||||
}
|
||||
|
@ -63,7 +64,7 @@ BackgroundBox::Inner::Inner(QWidget *parent) : TWidget(parent)
|
|||
updateWallpapers();
|
||||
}
|
||||
|
||||
subscribe(FileDownload::ImageLoaded(), [this] { update(); });
|
||||
subscribe(AuthSession::CurrentDownloaderTaskFinished(), [this] { update(); });
|
||||
subscribe(Window::Theme::Background(), [this](const Window::Theme::BackgroundUpdate &update) {
|
||||
if (update.paletteChanged()) {
|
||||
_check->invalidateCache();
|
||||
|
|
|
@ -32,6 +32,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
#include "ui/toast/toast.h"
|
||||
#include "core/click_handler_types.h"
|
||||
#include "storage/localstorage.h"
|
||||
#include "auth_session.h"
|
||||
|
||||
TextParseOptions _confirmBoxTextOptions = {
|
||||
TextParseLinks | TextParseMultiline | TextParseRichText, // flags
|
||||
|
@ -569,7 +570,7 @@ ConfirmInviteBox::ConfirmInviteBox(QWidget*, const QString &title, const MTPChat
|
|||
if (!location.isNull()) {
|
||||
_photo = ImagePtr(location);
|
||||
if (!_photo->loaded()) {
|
||||
subscribe(FileDownload::ImageLoaded(), [this] { update(); });
|
||||
subscribe(AuthSession::CurrentDownloaderTaskFinished(), [this] { update(); });
|
||||
_photo->load();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
#include "observer_peer.h"
|
||||
#include "apiwrap.h"
|
||||
#include "auth_session.h"
|
||||
#include "storage/file_download.h"
|
||||
|
||||
QString PeerFloodErrorText(PeerFloodType type) {
|
||||
auto link = textcmdLink(CreateInternalLinkHttps(qsl("spambot")), lang(lng_cant_more_info));
|
||||
|
@ -623,7 +624,7 @@ ContactsBox::Inner::Inner(QWidget *parent, UserData *bot) : TWidget(parent)
|
|||
}
|
||||
|
||||
void ContactsBox::Inner::init() {
|
||||
subscribe(FileDownload::ImageLoaded(), [this] { update(); });
|
||||
subscribe(AuthSession::CurrentDownloaderTaskFinished(), [this] { update(); });
|
||||
connect(_addContactLnk, SIGNAL(clicked()), App::wnd(), SLOT(onShowAddContact()));
|
||||
connect(_allAdmins, SIGNAL(changed()), this, SLOT(onAllAdminsChanged()));
|
||||
|
||||
|
@ -848,7 +849,7 @@ void ContactsBox::Inner::loadProfilePhotos() {
|
|||
|
||||
auto yFrom = _visibleTop - _rowsTop;
|
||||
auto yTo = yFrom + (_visibleBottom - _visibleTop) * 5;
|
||||
MTP::clearLoaderPriorities();
|
||||
AuthSession::Current().downloader()->clearPriorities();
|
||||
|
||||
if (yTo < 0) return;
|
||||
if (yFrom < 0) yFrom = 0;
|
||||
|
|
|
@ -25,6 +25,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
#include "storage/localstorage.h"
|
||||
#include "lang.h"
|
||||
#include "mainwindow.h"
|
||||
#include "auth_session.h"
|
||||
|
||||
LocalStorageBox::LocalStorageBox(QWidget *parent)
|
||||
: _clear(this, lang(lng_local_storage_clear), st::boxLinkButton) {
|
||||
|
@ -40,7 +41,7 @@ void LocalStorageBox::prepare() {
|
|||
connect(App::wnd(), SIGNAL(tempDirCleared(int)), this, SLOT(onTempDirCleared(int)));
|
||||
connect(App::wnd(), SIGNAL(tempDirClearFailed(int)), this, SLOT(onTempDirClearFailed(int)));
|
||||
|
||||
subscribe(FileDownload::ImageLoaded(), [this] { update(); });
|
||||
subscribe(AuthSession::CurrentDownloaderTaskFinished(), [this] { update(); });
|
||||
|
||||
updateControls();
|
||||
|
||||
|
|
|
@ -31,7 +31,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
#include "ui/widgets/scroll_area.h"
|
||||
#include "ui/effects/ripple_animation.h"
|
||||
#include "observer_peer.h"
|
||||
|
||||
#include "auth_session.h"
|
||||
#include "storage/file_download.h"
|
||||
|
||||
MembersAddButton::MembersAddButton(QWidget *parent, const style::TwoIconButton &st) : RippleButton(parent, st.ripple)
|
||||
, _st(st) {
|
||||
|
@ -132,7 +133,7 @@ MembersBox::Inner::Inner(QWidget *parent, ChannelData *channel, MembersFilter fi
|
|||
, _kickWidth(st::normalFont->width(_kickText))
|
||||
, _aboutWidth(st::boxWideWidth - st::contactsPadding.left() - st::contactsPadding.right())
|
||||
, _about(_aboutWidth) {
|
||||
subscribe(FileDownload::ImageLoaded(), [this] { update(); });
|
||||
subscribe(AuthSession::CurrentDownloaderTaskFinished(), [this] { update(); });
|
||||
|
||||
connect(App::main(), SIGNAL(peerNameChanged(PeerData*,const PeerData::Names&,const PeerData::NameFirstChars&)), this, SLOT(onPeerNameChanged(PeerData*, const PeerData::Names&, const PeerData::NameFirstChars&)));
|
||||
connect(App::main(), SIGNAL(peerPhotoChanged(PeerData*)), this, SLOT(peerUpdated(PeerData*)));
|
||||
|
@ -341,7 +342,7 @@ void MembersBox::Inner::loadProfilePhotos() {
|
|||
|
||||
auto yFrom = _visibleTop;
|
||||
auto yTo = yFrom + (_visibleBottom - _visibleTop) * 5;
|
||||
MTP::clearLoaderPriorities();
|
||||
AuthSession::Current().downloader()->clearPriorities();
|
||||
|
||||
if (yTo < 0) return;
|
||||
if (yFrom < 0) yFrom = 0;
|
||||
|
|
|
@ -28,11 +28,15 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
#include "styles/style_window.h"
|
||||
#include "mainwindow.h"
|
||||
#include "storage/localstorage.h"
|
||||
#include "auth_session.h"
|
||||
#include "window/notifications_manager.h"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr int kMaxNotificationsCount = 5;
|
||||
|
||||
using ChangeType = Window::Notifications::ChangeType;
|
||||
|
||||
} // namespace
|
||||
|
||||
class NotificationsBox::SampleWidget : public QWidget {
|
||||
|
@ -190,7 +194,7 @@ void NotificationsBox::countChanged() {
|
|||
|
||||
if (currentCount() != Global::NotificationsCount()) {
|
||||
Global::SetNotificationsCount(currentCount());
|
||||
Global::RefNotifySettingsChanged().notify(Notify::ChangeType::MaxCount);
|
||||
AuthSession::Current().notifications()->settingsChanged().notify(ChangeType::MaxCount);
|
||||
Local::writeUserSettings();
|
||||
}
|
||||
}
|
||||
|
@ -347,7 +351,7 @@ void NotificationsBox::setOverCorner(Notify::ScreenCorner corner) {
|
|||
_isOverCorner = true;
|
||||
setCursor(style::cur_pointer);
|
||||
Global::SetNotificationsDemoIsShown(true);
|
||||
Global::RefNotifySettingsChanged().notify(Notify::ChangeType::DemoIsShown);
|
||||
AuthSession::Current().notifications()->settingsChanged().notify(ChangeType::DemoIsShown);
|
||||
}
|
||||
_overCorner = corner;
|
||||
|
||||
|
@ -382,7 +386,7 @@ void NotificationsBox::clearOverCorner() {
|
|||
_isOverCorner = false;
|
||||
setCursor(style::cur_default);
|
||||
Global::SetNotificationsDemoIsShown(false);
|
||||
Global::RefNotifySettingsChanged().notify(Notify::ChangeType::DemoIsShown);
|
||||
AuthSession::Current().notifications()->settingsChanged().notify(ChangeType::DemoIsShown);
|
||||
|
||||
for_const (auto &samples, _cornerSamples) {
|
||||
for_const (auto widget, samples) {
|
||||
|
@ -409,7 +413,7 @@ void NotificationsBox::mouseReleaseEvent(QMouseEvent *e) {
|
|||
|
||||
if (_chosenCorner != Global::NotificationsCorner()) {
|
||||
Global::SetNotificationsCorner(_chosenCorner);
|
||||
Global::RefNotifySettingsChanged().notify(Notify::ChangeType::Corner);
|
||||
AuthSession::Current().notifications()->settingsChanged().notify(ChangeType::Corner);
|
||||
Local::writeUserSettings();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -294,7 +294,7 @@ ShareBox::Inner::Inner(QWidget *parent, ShareBox::FilterCallback &&filterCallbac
|
|||
subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) {
|
||||
notifyPeerUpdated(update);
|
||||
}));
|
||||
subscribe(FileDownload::ImageLoaded(), [this] { update(); });
|
||||
subscribe(AuthSession::CurrentDownloaderTaskFinished(), [this] { update(); });
|
||||
|
||||
subscribe(Window::Theme::Background(), [this](const Window::Theme::BackgroundUpdate &update) {
|
||||
if (update.paletteChanged()) {
|
||||
|
@ -435,7 +435,7 @@ void ShareBox::Inner::loadProfilePhotos(int yFrom) {
|
|||
yFrom *= _columnCount;
|
||||
yTo *= _columnCount;
|
||||
|
||||
MTP::clearLoaderPriorities();
|
||||
AuthSession::Current().downloader()->clearPriorities();
|
||||
if (_filter.isEmpty()) {
|
||||
if (!_chatsIndexed->isEmpty()) {
|
||||
auto i = _chatsIndexed->cfind(yFrom, _rowHeight);
|
||||
|
@ -953,7 +953,7 @@ void shareGameScoreByHash(const QString &hash) {
|
|||
}
|
||||
|
||||
auto hashDataInts = reinterpret_cast<int32*>(hashData.data());
|
||||
if (hashDataInts[0] != AuthSession::CurrentUserId()) {
|
||||
if (!AuthSession::Exists() || hashDataInts[0] != AuthSession::CurrentUserId()) {
|
||||
Ui::show(Box<InformBox>(lang(lng_share_wrong_user)));
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
#include "ui/effects/ripple_animation.h"
|
||||
#include "ui/effects/slide_animation.h"
|
||||
#include "ui/widgets/discrete_sliders.h"
|
||||
#include "auth_session.h"
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -576,7 +577,7 @@ StickersBox::Inner::Inner(QWidget *parent, const Stickers::Order &archivedIds) :
|
|||
}
|
||||
|
||||
void StickersBox::Inner::setup() {
|
||||
subscribe(FileDownload::ImageLoaded(), [this] {
|
||||
subscribe(AuthSession::CurrentDownloaderTaskFinished(), [this] {
|
||||
update();
|
||||
readVisibleSets();
|
||||
});
|
||||
|
|
|
@ -32,6 +32,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
#include "styles/style_stickers.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/scroll_area.h"
|
||||
#include "auth_session.h"
|
||||
|
||||
StickerSetBox::StickerSetBox(QWidget*, const MTPInputStickerSet &set)
|
||||
: _set(set) {
|
||||
|
@ -109,7 +110,7 @@ StickerSetBox::Inner::Inner(QWidget *parent, const MTPInputStickerSet &set) : TW
|
|||
MTP::send(MTPmessages_GetStickerSet(_input), rpcDone(&Inner::gotSet), rpcFail(&Inner::failedSet));
|
||||
App::main()->updateStickers();
|
||||
|
||||
subscribe(FileDownload::ImageLoaded(), [this] { update(); });
|
||||
subscribe(AuthSession::CurrentDownloaderTaskFinished(), [this] { update(); });
|
||||
|
||||
setMouseTracking(true);
|
||||
|
||||
|
|
|
@ -176,7 +176,7 @@ struct vtable_once_impl<Lambda, false, Return, Args...> : public vtable_base<Ret
|
|||
vtable_once_impl() : Parent(
|
||||
&bad_construct_copy,
|
||||
&vtable_once_impl::construct_move_other_method,
|
||||
&bad_const_call<Args...>,
|
||||
&bad_const_call<Return, Args...>,
|
||||
&vtable_once_impl::call_method,
|
||||
&vtable_once_impl::destruct_method) {
|
||||
}
|
||||
|
|
|
@ -376,7 +376,7 @@ public:
|
|||
|
||||
void setForced(parameter_type<Type> newValue, bool sync = false) {
|
||||
_value = newValue;
|
||||
_observable.notify(_value, sync);
|
||||
changed().notify(_value, sync);
|
||||
}
|
||||
|
||||
void set(parameter_type<Type> newValue, bool sync = false) {
|
||||
|
@ -388,16 +388,16 @@ public:
|
|||
template <typename Callback>
|
||||
void process(Callback callback, bool sync = false) {
|
||||
callback(_value);
|
||||
_observable.notify(_value, sync);
|
||||
changed().notify(_value, sync);
|
||||
}
|
||||
|
||||
Observable<Type> &observable() {
|
||||
return _observable;
|
||||
Observable<Type> &changed() {
|
||||
return _changed;
|
||||
}
|
||||
|
||||
private:
|
||||
Type _value;
|
||||
Observable<Type> _observable;
|
||||
Observable<Type> _changed;
|
||||
|
||||
};
|
||||
|
||||
|
@ -416,12 +416,12 @@ protected:
|
|||
|
||||
template <typename Type, typename Lambda>
|
||||
int subscribe(base::Variable<Type> &variable, Lambda &&handler) {
|
||||
return subscribe(variable.observable(), std::forward<Lambda>(handler));
|
||||
return subscribe(variable.changed(), std::forward<Lambda>(handler));
|
||||
}
|
||||
|
||||
template <typename Type, typename Lambda>
|
||||
int subscribe(base::Variable<Type> *variable, Lambda &&handler) {
|
||||
return subscribe(variable->observable(), std::forward<Lambda>(handler));
|
||||
return subscribe(variable->changed(), std::forward<Lambda>(handler));
|
||||
}
|
||||
|
||||
void unsubscribe(int index) {
|
||||
|
|
|
@ -20,30 +20,14 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
*/
|
||||
#include "core/task_queue.h"
|
||||
|
||||
#include <thread>
|
||||
#include <condition_variable>
|
||||
|
||||
namespace base {
|
||||
namespace {
|
||||
|
||||
auto MainThreadId = QThread::currentThreadId();
|
||||
const auto MaxThreadsCount = qMax(QThread::idealThreadCount(), 2);
|
||||
|
||||
template <typename Lambda>
|
||||
class Thread : public QThread {
|
||||
public:
|
||||
Thread(Lambda code) : _code(std::move(code)) {
|
||||
}
|
||||
void run() override {
|
||||
_code();
|
||||
}
|
||||
|
||||
private:
|
||||
Lambda _code;
|
||||
|
||||
};
|
||||
|
||||
template <typename Lambda>
|
||||
object_ptr<Thread<Lambda>> MakeThread(Lambda code) {
|
||||
return object_ptr<Thread<Lambda>>(std::move(code));
|
||||
}
|
||||
auto MainThreadId = std::this_thread::get_id();
|
||||
const auto MaxThreadsCount = qMax(std::thread::hardware_concurrency(), 2U);
|
||||
|
||||
} // namespace
|
||||
|
||||
|
@ -76,7 +60,7 @@ class TaskQueue::TaskThreadPool {
|
|||
|
||||
public:
|
||||
TaskThreadPool(const Private &) { }
|
||||
static const QSharedPointer<TaskThreadPool> &Instance();
|
||||
static const std::shared_ptr<TaskThreadPool> &Instance();
|
||||
|
||||
void AddQueueTask(TaskQueue *queue, Task &&task);
|
||||
void RemoveQueue(TaskQueue *queue);
|
||||
|
@ -84,16 +68,15 @@ public:
|
|||
~TaskThreadPool();
|
||||
|
||||
private:
|
||||
|
||||
void ThreadFunction();
|
||||
|
||||
std::vector<object_ptr<QThread>> threads_;
|
||||
QMutex queues_mutex_;
|
||||
std::vector<std::thread> threads_;
|
||||
std::mutex queues_mutex_;
|
||||
|
||||
// queues_mutex_ must be locked when working with the list.
|
||||
TaskQueueList queue_list_;
|
||||
|
||||
QWaitCondition thread_condition_;
|
||||
std::condition_variable thread_condition_;
|
||||
bool stopped_ = false;
|
||||
int tasks_in_process_ = 0;
|
||||
int background_tasks_in_process_ = 0;
|
||||
|
@ -192,7 +175,7 @@ TaskQueue *TaskQueue::TaskQueueList::TakeFirst(int list_index_) {
|
|||
}
|
||||
|
||||
void TaskQueue::TaskThreadPool::AddQueueTask(TaskQueue *queue, Task &&task) {
|
||||
QMutexLocker lock(&queues_mutex_);
|
||||
std::unique_lock<std::mutex> lock(queues_mutex_);
|
||||
|
||||
queue->tasks_.push_back(std::move(task));
|
||||
auto list_was_empty = queue_list_.Empty(kAllQueuesList);
|
||||
|
@ -207,18 +190,17 @@ void TaskQueue::TaskThreadPool::AddQueueTask(TaskQueue *queue, Task &&task) {
|
|||
}
|
||||
}
|
||||
if (will_create_thread) {
|
||||
threads_.push_back(MakeThread([this]() {
|
||||
threads_.emplace_back([this]() {
|
||||
ThreadFunction();
|
||||
}));
|
||||
threads_.back()->start();
|
||||
});
|
||||
} else if (some_threads_are_vacant) {
|
||||
t_assert(threads_count > tasks_in_process_);
|
||||
thread_condition_.wakeOne();
|
||||
thread_condition_.notify_one();
|
||||
}
|
||||
}
|
||||
|
||||
void TaskQueue::TaskThreadPool::RemoveQueue(TaskQueue *queue) {
|
||||
QMutexLocker lock(&queues_mutex_);
|
||||
std::unique_lock<std::mutex> lock(queues_mutex_);
|
||||
if (queue_list_.IsInList(queue)) {
|
||||
queue_list_.Unregister(queue);
|
||||
}
|
||||
|
@ -229,18 +211,18 @@ void TaskQueue::TaskThreadPool::RemoveQueue(TaskQueue *queue) {
|
|||
|
||||
TaskQueue::TaskThreadPool::~TaskThreadPool() {
|
||||
{
|
||||
QMutexLocker lock(&queues_mutex_);
|
||||
std::unique_lock<std::mutex> lock(queues_mutex_);
|
||||
queue_list_.Clear();
|
||||
stopped_ = true;
|
||||
}
|
||||
thread_condition_.wakeAll();
|
||||
thread_condition_.notify_all();
|
||||
for (auto &thread : threads_) {
|
||||
thread->wait();
|
||||
thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
const QSharedPointer<TaskQueue::TaskThreadPool> &TaskQueue::TaskThreadPool::Instance() { // static
|
||||
static auto Pool = MakeShared<TaskThreadPool>(Private());
|
||||
const std::shared_ptr<TaskQueue::TaskThreadPool> &TaskQueue::TaskThreadPool::Instance() { // static
|
||||
static auto Pool = std::make_shared<TaskThreadPool>(Private());
|
||||
return Pool;
|
||||
}
|
||||
|
||||
|
@ -259,7 +241,7 @@ void TaskQueue::TaskThreadPool::ThreadFunction() {
|
|||
while (true) {
|
||||
Task task;
|
||||
{
|
||||
QMutexLocker lock(&queues_mutex_);
|
||||
std::unique_lock<std::mutex> lock(queues_mutex_);
|
||||
|
||||
// Finish the previous task processing.
|
||||
if (task_was_processed) {
|
||||
|
@ -285,7 +267,7 @@ void TaskQueue::TaskThreadPool::ThreadFunction() {
|
|||
if (stopped_) {
|
||||
return;
|
||||
}
|
||||
thread_condition_.wait(&queues_mutex_);
|
||||
thread_condition_.wait(lock);
|
||||
}
|
||||
|
||||
// Select a task we will be processing.
|
||||
|
@ -331,7 +313,7 @@ TaskQueue::TaskQueue(Type type, Priority priority)
|
|||
|
||||
TaskQueue::~TaskQueue() {
|
||||
if (type_ != Type::Main && type_ != Type::Special) {
|
||||
if (auto thread_pool = weak_thread_pool_.toStrongRef()) {
|
||||
if (auto thread_pool = weak_thread_pool_.lock()) {
|
||||
thread_pool->RemoveQueue(this);
|
||||
}
|
||||
}
|
||||
|
@ -339,7 +321,7 @@ TaskQueue::~TaskQueue() {
|
|||
|
||||
void TaskQueue::Put(Task &&task) {
|
||||
if (type_ == Type::Main) {
|
||||
QMutexLocker lock(&tasks_mutex_);
|
||||
std::unique_lock<std::mutex> lock(tasks_mutex_);
|
||||
tasks_.push_back(std::move(task));
|
||||
|
||||
Sandbox::MainThreadTaskAdded();
|
||||
|
@ -350,14 +332,14 @@ void TaskQueue::Put(Task &&task) {
|
|||
}
|
||||
|
||||
void TaskQueue::ProcessMainTasks() { // static
|
||||
t_assert(QThread::currentThreadId() == MainThreadId);
|
||||
t_assert(std::this_thread::get_id() == MainThreadId);
|
||||
|
||||
while (ProcessOneMainTask()) {
|
||||
}
|
||||
}
|
||||
|
||||
void TaskQueue::ProcessMainTasks(TimeMs max_time_spent) { // static
|
||||
t_assert(QThread::currentThreadId() == MainThreadId);
|
||||
t_assert(std::this_thread::get_id() == MainThreadId);
|
||||
|
||||
auto start_time = getms();
|
||||
while (ProcessOneMainTask()) {
|
||||
|
@ -370,7 +352,7 @@ void TaskQueue::ProcessMainTasks(TimeMs max_time_spent) { // static
|
|||
bool TaskQueue::ProcessOneMainTask() { // static
|
||||
Task task;
|
||||
{
|
||||
QMutexLocker lock(&Main().tasks_mutex_);
|
||||
std::unique_lock<std::mutex> lock(Main().tasks_mutex_);
|
||||
auto &tasks = Main().tasks_;
|
||||
if (tasks.empty()) {
|
||||
return false;
|
||||
|
@ -386,7 +368,7 @@ bool TaskQueue::ProcessOneMainTask() { // static
|
|||
|
||||
bool TaskQueue::IsMyThread() const {
|
||||
if (type_ == Type::Main) {
|
||||
return (QThread::currentThreadId() == MainThreadId);
|
||||
return (std::this_thread::get_id() == MainThreadId);
|
||||
}
|
||||
t_assert(type_ != Type::Special);
|
||||
return false;
|
||||
|
|
|
@ -20,6 +20,9 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <memory>
|
||||
|
||||
namespace base {
|
||||
|
||||
using Task = lambda_once<void()>;
|
||||
|
@ -70,11 +73,11 @@ private:
|
|||
const Priority priority_;
|
||||
|
||||
std::deque<Task> tasks_;
|
||||
QMutex tasks_mutex_; // Only for the main queue.
|
||||
std::mutex tasks_mutex_; // Only for the main queue.
|
||||
|
||||
// Only for the other queues, not main.
|
||||
class TaskThreadPool;
|
||||
QWeakPointer<TaskThreadPool> weak_thread_pool_;
|
||||
std::weak_ptr<TaskThreadPool> weak_thread_pool_;
|
||||
|
||||
class TaskQueueList;
|
||||
|
||||
|
|
|
@ -45,6 +45,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
#include "autoupdater.h"
|
||||
#include "observer_peer.h"
|
||||
#include "auth_session.h"
|
||||
#include "window/notifications_manager.h"
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -95,7 +96,7 @@ DialogsInner::DialogsInner(QWidget *parent, QWidget *main) : SplittedWidget(pare
|
|||
connect(_cancelSearchInPeer, SIGNAL(clicked()), this, SIGNAL(cancelSearchInPeer()));
|
||||
_cancelSearchInPeer->hide();
|
||||
|
||||
subscribe(FileDownload::ImageLoaded(), [this] { update(); });
|
||||
subscribe(AuthSession::CurrentDownloaderTaskFinished(), [this] { update(); });
|
||||
subscribe(Global::RefItemRemoved(), [this](HistoryItem *item) {
|
||||
itemRemoved(item);
|
||||
});
|
||||
|
@ -999,7 +1000,7 @@ void DialogsInner::removeDialog(History *history) {
|
|||
if (_dialogsImportant) {
|
||||
history->removeFromChatList(Dialogs::Mode::Important, _dialogsImportant.get());
|
||||
}
|
||||
if (App::wnd()) App::wnd()->notifyClear(history);
|
||||
AuthSession::Current().notifications()->clearFromHistory(history);
|
||||
if (_contacts->contains(history->peer->id)) {
|
||||
if (!_contactsNoDialogs->contains(history->peer->id)) {
|
||||
_contactsNoDialogs->addByName(history);
|
||||
|
@ -1889,7 +1890,7 @@ void DialogsInner::loadPeerPhotos() {
|
|||
|
||||
auto yFrom = _visibleTop;
|
||||
auto yTo = _visibleTop + (_visibleBottom - _visibleTop) * (PreloadHeightsCount + 1);
|
||||
MTP::clearLoaderPriorities();
|
||||
AuthSession::Current().downloader()->clearPriorities();
|
||||
if (_state == DefaultState) {
|
||||
auto otherStart = shownDialogs()->size() * st::dialogsRowHeight;
|
||||
if (yFrom < otherStart) {
|
||||
|
|
|
@ -686,7 +686,6 @@ struct Data {
|
|||
int NotificationsCount = 3;
|
||||
Notify::ScreenCorner NotificationsCorner = Notify::ScreenCorner::BottomRight;
|
||||
bool NotificationsDemoIsShown = false;
|
||||
base::Observable<Notify::ChangeType> NotifySettingsChanged;
|
||||
|
||||
DBIConnectionType ConnectionType = dbictAuto;
|
||||
bool TryIPv6 = (cPlatform() == dbipWindows) ? false : true;
|
||||
|
@ -699,6 +698,8 @@ struct Data {
|
|||
bool LocalPasscode = false;
|
||||
base::Observable<void> LocalPasscodeChanged;
|
||||
|
||||
base::Variable<DBIWorkMode> WorkMode = { dbiwmWindowAndTray };
|
||||
|
||||
base::Observable<HistoryItem*> ItemRemoved;
|
||||
base::Observable<void> UnreadCounterUpdate;
|
||||
base::Observable<void> PeerChooseCancel;
|
||||
|
@ -807,7 +808,6 @@ DefineVar(Global, bool, NativeNotifications);
|
|||
DefineVar(Global, int, NotificationsCount);
|
||||
DefineVar(Global, Notify::ScreenCorner, NotificationsCorner);
|
||||
DefineVar(Global, bool, NotificationsDemoIsShown);
|
||||
DefineRefVar(Global, base::Observable<Notify::ChangeType>, NotifySettingsChanged);
|
||||
|
||||
DefineVar(Global, DBIConnectionType, ConnectionType);
|
||||
DefineVar(Global, bool, TryIPv6);
|
||||
|
@ -820,6 +820,8 @@ DefineVar(Global, int, AutoLock);
|
|||
DefineVar(Global, bool, LocalPasscode);
|
||||
DefineRefVar(Global, base::Observable<void>, LocalPasscodeChanged);
|
||||
|
||||
DefineRefVar(Global, base::Variable<DBIWorkMode>, WorkMode);
|
||||
|
||||
DefineRefVar(Global, base::Observable<HistoryItem*>, ItemRemoved);
|
||||
DefineRefVar(Global, base::Observable<void>, UnreadCounterUpdate);
|
||||
DefineRefVar(Global, base::Observable<void>, PeerChooseCancel);
|
||||
|
|
|
@ -187,15 +187,6 @@ void historyMuteUpdated(History *history);
|
|||
void handlePendingHistoryUpdate();
|
||||
void unreadCounterUpdated();
|
||||
|
||||
enum class ChangeType {
|
||||
SoundEnabled,
|
||||
IncludeMuted,
|
||||
DesktopEnabled,
|
||||
ViewParams,
|
||||
MaxCount,
|
||||
Corner,
|
||||
DemoIsShown,
|
||||
};
|
||||
|
||||
enum class ScreenCorner {
|
||||
TopLeft = 0,
|
||||
|
@ -214,14 +205,6 @@ inline bool IsTopCorner(ScreenCorner corner) {
|
|||
|
||||
} // namespace Notify
|
||||
|
||||
namespace base {
|
||||
|
||||
template <>
|
||||
struct custom_is_fast_copy_type<Notify::ChangeType> : public std::true_type {
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
#define DeclareReadOnlyVar(Type, Name) const Type &Name();
|
||||
#define DeclareRefVar(Type, Name) DeclareReadOnlyVar(Type, Name) \
|
||||
Type &Ref##Name();
|
||||
|
@ -395,7 +378,6 @@ DeclareVar(bool, NativeNotifications);
|
|||
DeclareVar(int, NotificationsCount);
|
||||
DeclareVar(Notify::ScreenCorner, NotificationsCorner);
|
||||
DeclareVar(bool, NotificationsDemoIsShown);
|
||||
DeclareRefVar(base::Observable<Notify::ChangeType>, NotifySettingsChanged);
|
||||
|
||||
DeclareVar(DBIConnectionType, ConnectionType);
|
||||
DeclareVar(bool, TryIPv6);
|
||||
|
@ -408,6 +390,8 @@ DeclareVar(int, AutoLock);
|
|||
DeclareVar(bool, LocalPasscode);
|
||||
DeclareRefVar(base::Observable<void>, LocalPasscodeChanged);
|
||||
|
||||
DeclareRefVar(base::Variable<DBIWorkMode>, WorkMode);
|
||||
|
||||
DeclareRefVar(base::Observable<HistoryItem*>, ItemRemoved);
|
||||
DeclareRefVar(base::Observable<void>, UnreadCounterUpdate);
|
||||
DeclareRefVar(base::Observable<void>, PeerChooseCancel);
|
||||
|
|
|
@ -32,6 +32,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
#include "window/top_bar_widget.h"
|
||||
#include "observer_peer.h"
|
||||
#include "auth_session.h"
|
||||
#include "window/notifications_manager.h"
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -1503,7 +1504,7 @@ MsgId History::inboxRead(MsgId upTo) {
|
|||
}
|
||||
|
||||
showFrom = nullptr;
|
||||
App::wnd()->notifyClear(this);
|
||||
AuthSession::Current().notifications()->clearFromHistory(this);
|
||||
|
||||
return upTo;
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
#include "structs.h"
|
||||
#include "dialogs/dialogs_common.h"
|
||||
#include "ui/effects/send_action_animations.h"
|
||||
#include "core/observer.h"
|
||||
|
||||
void historyInit();
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
#include "styles/style_history.h"
|
||||
#include "styles/style_widgets.h"
|
||||
#include "styles/style_stickers.h"
|
||||
#include "auth_session.h"
|
||||
|
||||
FieldAutocomplete::FieldAutocomplete(QWidget *parent) : TWidget(parent)
|
||||
, _scroll(this, st::mentionScroll) {
|
||||
|
@ -533,7 +534,7 @@ FieldAutocompleteInner::FieldAutocompleteInner(FieldAutocomplete *parent, Mentio
|
|||
, _previewShown(false) {
|
||||
_previewTimer.setSingleShot(true);
|
||||
connect(&_previewTimer, SIGNAL(timeout()), this, SLOT(onPreview()));
|
||||
subscribe(FileDownload::ImageLoaded(), [this] { update(); });
|
||||
subscribe(AuthSession::CurrentDownloaderTaskFinished(), [this] { update(); });
|
||||
}
|
||||
|
||||
void FieldAutocompleteInner::paintEvent(QPaintEvent *e) {
|
||||
|
|
|
@ -31,6 +31,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
#include "styles/style_dialogs.h"
|
||||
#include "styles/style_widgets.h"
|
||||
#include "styles/style_history.h"
|
||||
#include "window/notifications_manager.h"
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -2032,10 +2033,8 @@ bool HistoryService::updateDependent(bool force) {
|
|||
}
|
||||
updateDependentText();
|
||||
}
|
||||
if (force) {
|
||||
if (gotDependencyItem && App::wnd()) {
|
||||
App::wnd()->notifySettingGot();
|
||||
}
|
||||
if (force && gotDependencyItem) {
|
||||
AuthSession::Current().notifications()->checkDelayed();
|
||||
}
|
||||
return (dependent->msg || !dependent->msgId);
|
||||
}
|
||||
|
|
|
@ -61,6 +61,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
#include "ui/widgets/popup_menu.h"
|
||||
#include "platform/platform_file_utilities.h"
|
||||
#include "auth_session.h"
|
||||
#include "window/notifications_manager.h"
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -3130,7 +3131,7 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent)
|
|||
, _topShadow(this, st::shadowFg) {
|
||||
setAcceptDrops(true);
|
||||
|
||||
subscribe(FileDownload::ImageLoaded(), [this] { update(); });
|
||||
subscribe(AuthSession::CurrentDownloaderTaskFinished(), [this] { update(); });
|
||||
connect(_scroll, SIGNAL(scrolled()), this, SLOT(onScroll()));
|
||||
connect(_reportSpamPanel, SIGNAL(reportClicked()), this, SLOT(onReportSpamClicked()));
|
||||
connect(_reportSpamPanel, SIGNAL(hideClicked()), this, SLOT(onReportSpamHide()));
|
||||
|
@ -4341,7 +4342,7 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re
|
|||
if (_peer) {
|
||||
App::forgetMedia();
|
||||
_serviceImageCacheSize = imageCacheSize();
|
||||
MTP::clearLoaderPriorities();
|
||||
AuthSession::Current().downloader()->clearPriorities();
|
||||
|
||||
_history = App::history(_peer->id);
|
||||
_migrated = _peer->migrateFrom() ? App::history(_peer->migrateFrom()->id) : 0;
|
||||
|
@ -4797,7 +4798,7 @@ void HistoryWidget::newUnreadMsg(History *history, HistoryItem *item) {
|
|||
return;
|
||||
}
|
||||
}
|
||||
App::wnd()->notifySchedule(history, item);
|
||||
AuthSession::Current().notifications()->schedule(history, item);
|
||||
history->setUnreadCount(history->unreadCount() + 1);
|
||||
}
|
||||
|
||||
|
@ -6803,8 +6804,6 @@ void HistoryWidget::sendFileConfirmed(const FileLoadResultPtr &file) {
|
|||
}
|
||||
|
||||
void HistoryWidget::onPhotoUploaded(const FullMsgId &newId, bool silent, const MTPInputFile &file) {
|
||||
if (!AuthSession::Current()) return;
|
||||
|
||||
if (auto item = App::histItemById(newId)) {
|
||||
uint64 randomId = rand_value<uint64>();
|
||||
App::historyRegRandom(randomId, newId);
|
||||
|
@ -6853,8 +6852,6 @@ namespace {
|
|||
}
|
||||
|
||||
void HistoryWidget::onDocumentUploaded(const FullMsgId &newId, bool silent, const MTPInputFile &file) {
|
||||
if (!AuthSession::Current()) return;
|
||||
|
||||
if (auto item = dynamic_cast<HistoryMessage*>(App::histItemById(newId))) {
|
||||
auto media = item->getMedia();
|
||||
if (auto document = media ? media->getDocument() : nullptr) {
|
||||
|
@ -6881,8 +6878,6 @@ void HistoryWidget::onDocumentUploaded(const FullMsgId &newId, bool silent, cons
|
|||
}
|
||||
|
||||
void HistoryWidget::onThumbDocumentUploaded(const FullMsgId &newId, bool silent, const MTPInputFile &file, const MTPInputFile &thumb) {
|
||||
if (!AuthSession::Current()) return;
|
||||
|
||||
if (auto item = dynamic_cast<HistoryMessage*>(App::histItemById(newId))) {
|
||||
auto media = item->getMedia();
|
||||
if (auto document = media ? media->getDocument() : nullptr) {
|
||||
|
@ -6909,8 +6904,6 @@ void HistoryWidget::onThumbDocumentUploaded(const FullMsgId &newId, bool silent,
|
|||
}
|
||||
|
||||
void HistoryWidget::onPhotoProgress(const FullMsgId &newId) {
|
||||
if (!AuthSession::Current()) return;
|
||||
|
||||
if (auto item = App::histItemById(newId)) {
|
||||
auto photo = (item->getMedia() && item->getMedia()->type() == MediaTypePhoto) ? static_cast<HistoryPhoto*>(item->getMedia())->photo() : nullptr;
|
||||
if (!item->isPost()) {
|
||||
|
@ -6921,8 +6914,6 @@ void HistoryWidget::onPhotoProgress(const FullMsgId &newId) {
|
|||
}
|
||||
|
||||
void HistoryWidget::onDocumentProgress(const FullMsgId &newId) {
|
||||
if (!AuthSession::Current()) return;
|
||||
|
||||
if (auto item = App::histItemById(newId)) {
|
||||
auto media = item->getMedia();
|
||||
auto document = media ? media->getDocument() : nullptr;
|
||||
|
@ -6934,8 +6925,6 @@ void HistoryWidget::onDocumentProgress(const FullMsgId &newId) {
|
|||
}
|
||||
|
||||
void HistoryWidget::onPhotoFailed(const FullMsgId &newId) {
|
||||
if (!AuthSession::Current()) return;
|
||||
|
||||
HistoryItem *item = App::histItemById(newId);
|
||||
if (item) {
|
||||
if (!item->isPost()) {
|
||||
|
@ -6946,8 +6935,6 @@ void HistoryWidget::onPhotoFailed(const FullMsgId &newId) {
|
|||
}
|
||||
|
||||
void HistoryWidget::onDocumentFailed(const FullMsgId &newId) {
|
||||
if (!AuthSession::Current()) return;
|
||||
|
||||
if (auto item = App::histItemById(newId)) {
|
||||
auto media = item->getMedia();
|
||||
auto document = media ? media->getDocument() : nullptr;
|
||||
|
|
|
@ -425,6 +425,15 @@ QString Widget::Step::nextButtonText() const {
|
|||
}
|
||||
|
||||
void Widget::Step::finish(const MTPUser &user, QImage photo) {
|
||||
if (user.type() != mtpc_user || !user.c_user().is_self()) {
|
||||
// No idea what to do here.
|
||||
// We could've reset intro and MTP, but this really should not happen.
|
||||
Ui::show(Box<InformBox>("Internal error: bad user.is_self() after sign in."));
|
||||
return;
|
||||
}
|
||||
|
||||
Messenger::Instance().authSessionCreate(user.c_user().vid.v);
|
||||
|
||||
App::wnd()->setupMain(&user);
|
||||
|
||||
// "this" is already deleted here by creating the main widget.
|
||||
|
|
|
@ -32,6 +32,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
#include "styles/style_stickers.h"
|
||||
#include "ui/widgets/shadow.h"
|
||||
#include "window/window_main_menu.h"
|
||||
#include "auth_session.h"
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -720,7 +721,7 @@ LayerStackWidget::~LayerStackWidget() {
|
|||
MediaPreviewWidget::MediaPreviewWidget(QWidget *parent) : TWidget(parent)
|
||||
, _emojiSize(Ui::Emoji::Size(Ui::Emoji::Index() + 1) / cIntRetinaFactor()) {
|
||||
setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
subscribe(FileDownload::ImageLoaded(), [this] { update(); });
|
||||
subscribe(AuthSession::CurrentDownloaderTaskFinished(), [this] { update(); });
|
||||
}
|
||||
|
||||
void MediaPreviewWidget::paintEvent(QPaintEvent *e) {
|
||||
|
|
|
@ -63,6 +63,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
#include "mtproto/dc_options.h"
|
||||
#include "core/file_utilities.h"
|
||||
#include "auth_session.h"
|
||||
#include "window/notifications_manager.h"
|
||||
|
||||
StackItemSection::StackItemSection(std::unique_ptr<Window::SectionMemento> &&memento) : StackItem(nullptr)
|
||||
, _memento(std::move(memento)) {
|
||||
|
@ -810,7 +811,6 @@ void MainWidget::deleteHistoryPart(DeleteHistoryRequest request, const MTPmessag
|
|||
}
|
||||
|
||||
int32 offset = d.voffset.v;
|
||||
if (!AuthSession::Current()) return;
|
||||
if (offset <= 0) {
|
||||
cRefReportSpamStatuses().remove(peer->id);
|
||||
Local::writeReportSpamStatuses();
|
||||
|
@ -909,7 +909,6 @@ void MainWidget::deleteAllFromUserPart(DeleteAllFromUserParams params, const MTP
|
|||
}
|
||||
|
||||
int32 offset = d.voffset.v;
|
||||
if (!AuthSession::Current()) return;
|
||||
if (offset > 0) {
|
||||
MTP::send(MTPchannels_DeleteUserHistory(params.channel->inputChannel, params.from->inputUser), rpcDone(&MainWidget::deleteAllFromUserPart, params));
|
||||
} else if (History *h = App::historyLoaded(params.channel)) {
|
||||
|
@ -1504,7 +1503,6 @@ void MainWidget::overviewLoaded(History *history, const MTPmessages_Messages &re
|
|||
}
|
||||
|
||||
void MainWidget::sendReadRequest(PeerData *peer, MsgId upTo) {
|
||||
if (!AuthSession::Current()) return;
|
||||
if (peer->isChannel()) {
|
||||
_readRequests.insert(peer, qMakePair(MTP::send(MTPchannels_ReadHistory(peer->asChannel()->inputChannel, MTP_int(upTo)), rpcDone(&MainWidget::channelReadDone, peer), rpcFail(&MainWidget::readRequestFail, peer)), upTo));
|
||||
} else {
|
||||
|
@ -2106,8 +2104,6 @@ void MainWidget::fillPeerMenu(PeerData *peer, base::lambda<QAction*(const QStrin
|
|||
}
|
||||
|
||||
void MainWidget::onViewsIncrement() {
|
||||
if (!App::main() || !AuthSession::Current()) return;
|
||||
|
||||
for (ViewsIncrement::iterator i = _viewsToIncrement.begin(); i != _viewsToIncrement.cend();) {
|
||||
if (_viewsIncrementRequests.contains(i.key())) {
|
||||
++i;
|
||||
|
@ -3628,8 +3624,6 @@ bool MainWidget::failDifference(const RPCError &error) {
|
|||
}
|
||||
|
||||
void MainWidget::onGetDifferenceTimeByPts() {
|
||||
if (!AuthSession::Current()) return;
|
||||
|
||||
auto now = getms(true), wait = 0LL;
|
||||
if (_getDifferenceTimeByPts) {
|
||||
if (_getDifferenceTimeByPts > now) {
|
||||
|
@ -3655,8 +3649,6 @@ void MainWidget::onGetDifferenceTimeByPts() {
|
|||
}
|
||||
|
||||
void MainWidget::onGetDifferenceTimeAfterFail() {
|
||||
if (!AuthSession::Current()) return;
|
||||
|
||||
auto now = getms(true), wait = 0LL;
|
||||
if (_getDifferenceTimeAfterFail) {
|
||||
if (_getDifferenceTimeAfterFail > now) {
|
||||
|
@ -3731,24 +3723,21 @@ void MainWidget::mtpPing() {
|
|||
MTP::ping();
|
||||
}
|
||||
|
||||
void MainWidget::start(const MTPUser &user) {
|
||||
int32 uid = user.c_user().vid.v;
|
||||
if (!uid) {
|
||||
LOG(("MTP Error: incorrect user received"));
|
||||
App::logOut();
|
||||
void MainWidget::start(const MTPUser *self) {
|
||||
if (!self) {
|
||||
MTP::send(MTPusers_GetUsers(MTP_vector<MTPInputUser>(1, MTP_inputUserSelf())), rpcDone(&MainWidget::startWithSelf));
|
||||
return;
|
||||
}
|
||||
if (AuthSession::CurrentUserId() != uid) {
|
||||
Messenger::Instance().authSessionCreate(uid);
|
||||
Local::writeMtpData();
|
||||
if (!AuthSession::Current().validateSelf(*self)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Local::readSavedPeers();
|
||||
|
||||
cSetOtherOnline(0);
|
||||
if (auto self = App::feedUsers(MTP_vector<MTPUser>(1, user))) {
|
||||
self->loadUserpic();
|
||||
if (auto user = App::feedUsers(MTP_vector<MTPUser>(1, *self))) {
|
||||
user->loadUserpic();
|
||||
}
|
||||
|
||||
MTP::send(MTPupdates_GetState(), rpcDone(&MainWidget::gotState));
|
||||
update();
|
||||
|
||||
|
@ -4039,12 +4028,13 @@ bool MainWidget::inviteImportFail(const RPCError &error) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void MainWidget::startFull(const MTPVector<MTPUser> &users) {
|
||||
const auto &v(users.c_vector().v);
|
||||
if (v.isEmpty() || v[0].type() != mtpc_user || !v[0].c_user().is_self()) { // wtf?..
|
||||
void MainWidget::startWithSelf(const MTPVector<MTPUser> &users) {
|
||||
auto &v = users.c_vector().v;
|
||||
if (v.isEmpty()) {
|
||||
LOG(("Auth Error: self user not received."));
|
||||
return App::logOutDelayed();
|
||||
}
|
||||
start(v[0]);
|
||||
start(&v[0]);
|
||||
}
|
||||
|
||||
void MainWidget::applyNotifySetting(const MTPNotifyPeer &peer, const MTPPeerNotifySettings &settings, History *h) {
|
||||
|
@ -4100,7 +4090,7 @@ void MainWidget::applyNotifySetting(const MTPNotifyPeer &peer, const MTPPeerNoti
|
|||
if (!h) h = App::history(updatePeer->id);
|
||||
int32 changeIn = 0;
|
||||
if (isNotifyMuted(setTo, &changeIn)) {
|
||||
App::wnd()->notifyClear(h);
|
||||
AuthSession::Current().notifications()->clearFromHistory(h);
|
||||
h->setMute(true);
|
||||
App::regMuted(updatePeer, changeIn);
|
||||
} else {
|
||||
|
@ -4379,7 +4369,7 @@ void MainWidget::checkIdleFinish() {
|
|||
}
|
||||
|
||||
void MainWidget::updateReceived(const mtpPrime *from, const mtpPrime *end) {
|
||||
if (end <= from || !AuthSession::Current()) return;
|
||||
if (end <= from) return;
|
||||
|
||||
App::wnd()->checkAutoLock();
|
||||
|
||||
|
@ -4638,8 +4628,6 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) {
|
|||
}
|
||||
|
||||
void MainWidget::feedUpdate(const MTPUpdate &update) {
|
||||
if (!AuthSession::Current()) return;
|
||||
|
||||
switch (update.type()) {
|
||||
case mtpc_updateNewMessage: {
|
||||
auto &d = update.c_updateNewMessage();
|
||||
|
|
|
@ -158,7 +158,7 @@ public:
|
|||
|
||||
void showAnimated(const QPixmap &bgAnimCache, bool back = false);
|
||||
|
||||
void start(const MTPUser &user);
|
||||
void start(const MTPUser *self = nullptr);
|
||||
|
||||
void checkStartUrl();
|
||||
void openLocalUrl(const QString &str);
|
||||
|
@ -166,7 +166,6 @@ public:
|
|||
void joinGroupByHash(const QString &hash);
|
||||
void stickersBox(const MTPInputStickerSet &set);
|
||||
|
||||
void startFull(const MTPVector<MTPUser> &users);
|
||||
bool started();
|
||||
void applyNotifySetting(const MTPNotifyPeer &peer, const MTPPeerNotifySettings &settings, History *history = 0);
|
||||
|
||||
|
@ -518,6 +517,8 @@ private:
|
|||
Window::SectionSlideParams prepareOverviewAnimation();
|
||||
Window::SectionSlideParams prepareDialogsAnimation();
|
||||
|
||||
void startWithSelf(const MTPVector<MTPUser> &users);
|
||||
|
||||
void saveSectionInStack();
|
||||
|
||||
bool _started = false;
|
||||
|
|
|
@ -100,17 +100,6 @@ MainWindow::MainWindow() {
|
|||
iconbig32 = iconbig256.scaledToWidth(32, Qt::SmoothTransformation);
|
||||
iconbig64 = iconbig256.scaledToWidth(64, Qt::SmoothTransformation);
|
||||
|
||||
subscribe(Global::RefNotifySettingsChanged(), [this](Notify::ChangeType type) {
|
||||
if (type == Notify::ChangeType::DesktopEnabled) {
|
||||
updateTrayMenu();
|
||||
notifyClear();
|
||||
} else if (type == Notify::ChangeType::ViewParams) {
|
||||
notifyUpdateAll();
|
||||
} else if (type == Notify::ChangeType::IncludeMuted) {
|
||||
Notify::unreadCounterUpdated();
|
||||
}
|
||||
});
|
||||
|
||||
resize(st::windowDefaultWidth, st::windowDefaultHeight);
|
||||
|
||||
setLocale(QLocale(QLocale::English, QLocale::UnitedStates));
|
||||
|
@ -118,8 +107,6 @@ MainWindow::MainWindow() {
|
|||
_inactiveTimer.setSingleShot(true);
|
||||
connect(&_inactiveTimer, SIGNAL(timeout()), this, SLOT(onInactiveTimer()));
|
||||
|
||||
connect(&_notifyWaitTimer, SIGNAL(timeout()), this, SLOT(notifyShowNext()));
|
||||
|
||||
connect(&_autoLockTimer, SIGNAL(timeout()), this, SLOT(checkAutoLock()));
|
||||
|
||||
subscribe(Global::RefSelfChanged(), [this]() { updateGlobalMenu(); });
|
||||
|
@ -156,7 +143,7 @@ void MainWindow::onStateChanged(Qt::WindowState state) {
|
|||
updateIsActive((state == Qt::WindowMinimized) ? Global::OfflineBlurTimeout() : Global::OnlineFocusTimeout());
|
||||
|
||||
psUpdateSysMenu(state);
|
||||
if (state == Qt::WindowMinimized && cWorkMode() == dbiwmTrayOnly) {
|
||||
if (state == Qt::WindowMinimized && Global::WorkMode().value() == dbiwmTrayOnly) {
|
||||
App::wnd()->minimizeToTray();
|
||||
}
|
||||
savePosition(state);
|
||||
|
@ -200,7 +187,7 @@ void MainWindow::firstShow() {
|
|||
trayIconMenu->addAction(notificationActionText, this, SLOT(toggleDisplayNotifyFromTray()))->setEnabled(true);
|
||||
trayIconMenu->addAction(lang(lng_quit_from_tray), this, SLOT(quitFromTray()))->setEnabled(true);
|
||||
}
|
||||
psUpdateWorkmode();
|
||||
workmodeUpdated(Global::WorkMode().value());
|
||||
|
||||
psFirstShow();
|
||||
updateTrayMenu();
|
||||
|
@ -241,7 +228,7 @@ void MainWindow::clearPasscode() {
|
|||
} else {
|
||||
_main->showAnimated(bg, true);
|
||||
}
|
||||
notifyUpdateAll();
|
||||
AuthSession::Current().notifications()->updateAll();
|
||||
updateGlobalMenu();
|
||||
|
||||
if (_main) {
|
||||
|
@ -265,7 +252,9 @@ void MainWindow::setupPasscode() {
|
|||
setInnerFocus();
|
||||
}
|
||||
_shouldLockAt = 0;
|
||||
notifyUpdateAll();
|
||||
if (AuthSession::Exists()) {
|
||||
AuthSession::Current().notifications()->updateAll();
|
||||
}
|
||||
updateGlobalMenu();
|
||||
}
|
||||
|
||||
|
@ -360,6 +349,9 @@ void MainWindow::setupMain(const MTPUser *self) {
|
|||
auto bg = animated ? grabInner() : QPixmap();
|
||||
|
||||
clearWidgets();
|
||||
|
||||
t_assert(AuthSession::Exists());
|
||||
|
||||
_main.create(bodyWidget());
|
||||
_main->show();
|
||||
updateControlsGeometry();
|
||||
|
@ -369,11 +361,7 @@ void MainWindow::setupMain(const MTPUser *self) {
|
|||
} else {
|
||||
_main->activate();
|
||||
}
|
||||
if (self) {
|
||||
_main->start(*self);
|
||||
} else {
|
||||
MTP::send(MTPusers_GetUsers(MTP_vector<MTPInputUser>(1, MTP_inputUserSelf())), _main->rpcDone(&MainWidget::startFull));
|
||||
}
|
||||
_main->start(self);
|
||||
|
||||
fixOrder();
|
||||
|
||||
|
@ -573,7 +561,7 @@ bool MainWindow::doWeReadServerHistory() {
|
|||
}
|
||||
|
||||
void MainWindow::checkHistoryActivation() {
|
||||
if (_main && AuthSession::Current() && doWeReadServerHistory()) {
|
||||
if (_main && doWeReadServerHistory()) {
|
||||
_main->markActiveHistoryAsRead();
|
||||
}
|
||||
}
|
||||
|
@ -842,9 +830,9 @@ void MainWindow::toggleDisplayNotifyFromTray() {
|
|||
}
|
||||
}
|
||||
Local::writeUserSettings();
|
||||
Global::RefNotifySettingsChanged().notify(Notify::ChangeType::DesktopEnabled);
|
||||
AuthSession::Current().notifications()->settingsChanged().notify(Window::Notifications::ChangeType::DesktopEnabled);
|
||||
if (soundNotifyChanged) {
|
||||
Global::RefNotifySettingsChanged().notify(Notify::ChangeType::SoundEnabled);
|
||||
AuthSession::Current().notifications()->settingsChanged().notify(Window::Notifications::ChangeType::SoundEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -854,7 +842,7 @@ void MainWindow::closeEvent(QCloseEvent *e) {
|
|||
App::quit();
|
||||
} else {
|
||||
e->ignore();
|
||||
if (!AuthSession::Current() || !Ui::hideWindowNoQuit()) {
|
||||
if (!AuthSession::Exists() || !Ui::hideWindowNoQuit()) {
|
||||
App::quit();
|
||||
}
|
||||
}
|
||||
|
@ -919,305 +907,10 @@ void MainWindow::onClearFailed(int task, void *manager) {
|
|||
emit tempDirClearFailed(task);
|
||||
}
|
||||
|
||||
void MainWindow::notifySchedule(History *history, HistoryItem *item) {
|
||||
if (App::quitting() || !history->currentNotification() || !App::api()) return;
|
||||
|
||||
PeerData *notifyByFrom = (!history->peer->isUser() && item->mentionsMe()) ? item->from() : 0;
|
||||
|
||||
if (item->isSilent()) {
|
||||
history->popNotification(item);
|
||||
return;
|
||||
}
|
||||
|
||||
bool haveSetting = (history->peer->notify != UnknownNotifySettings);
|
||||
if (haveSetting) {
|
||||
if (history->peer->notify != EmptyNotifySettings && history->peer->notify->mute > unixtime()) {
|
||||
if (notifyByFrom) {
|
||||
haveSetting = (item->from()->notify != UnknownNotifySettings);
|
||||
if (haveSetting) {
|
||||
if (notifyByFrom->notify != EmptyNotifySettings && notifyByFrom->notify->mute > unixtime()) {
|
||||
history->popNotification(item);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
App::api()->requestNotifySetting(notifyByFrom);
|
||||
}
|
||||
} else {
|
||||
history->popNotification(item);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (notifyByFrom && notifyByFrom->notify == UnknownNotifySettings) {
|
||||
App::api()->requestNotifySetting(notifyByFrom);
|
||||
}
|
||||
App::api()->requestNotifySetting(history->peer);
|
||||
}
|
||||
if (!item->notificationReady()) {
|
||||
haveSetting = false;
|
||||
}
|
||||
|
||||
int delay = item->Has<HistoryMessageForwarded>() ? 500 : 100, t = unixtime();
|
||||
auto ms = getms(true);
|
||||
bool isOnline = _main->lastWasOnline(), otherNotOld = ((cOtherOnline() * 1000LL) + Global::OnlineCloudTimeout() > t * 1000LL);
|
||||
bool otherLaterThanMe = (cOtherOnline() * 1000LL + (ms - _main->lastSetOnline()) > t * 1000LL);
|
||||
if (!isOnline && otherNotOld && otherLaterThanMe) {
|
||||
delay = Global::NotifyCloudDelay();
|
||||
} else if (cOtherOnline() >= t) {
|
||||
delay = Global::NotifyDefaultDelay();
|
||||
}
|
||||
|
||||
auto when = ms + delay;
|
||||
_notifyWhenAlerts[history].insert(when, notifyByFrom);
|
||||
if (Global::DesktopNotify() && !Platform::Notifications::SkipToast()) {
|
||||
NotifyWhenMaps::iterator i = _notifyWhenMaps.find(history);
|
||||
if (i == _notifyWhenMaps.end()) {
|
||||
i = _notifyWhenMaps.insert(history, NotifyWhenMap());
|
||||
}
|
||||
if (i.value().constFind(item->id) == i.value().cend()) {
|
||||
i.value().insert(item->id, when);
|
||||
}
|
||||
NotifyWaiters *addTo = haveSetting ? &_notifyWaiters : &_notifySettingWaiters;
|
||||
NotifyWaiters::const_iterator it = addTo->constFind(history);
|
||||
if (it == addTo->cend() || it->when > when) {
|
||||
addTo->insert(history, NotifyWaiter(item->id, when, notifyByFrom));
|
||||
}
|
||||
}
|
||||
if (haveSetting) {
|
||||
if (!_notifyWaitTimer.isActive() || _notifyWaitTimer.remainingTime() > delay) {
|
||||
_notifyWaitTimer.start(delay);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::notifyClear(History *history) {
|
||||
if (!history) {
|
||||
Window::Notifications::GetManager()->clearAll();
|
||||
|
||||
for (auto i = _notifyWhenMaps.cbegin(), e = _notifyWhenMaps.cend(); i != e; ++i) {
|
||||
i.key()->clearNotifications();
|
||||
}
|
||||
_notifyWhenMaps.clear();
|
||||
_notifyWhenAlerts.clear();
|
||||
_notifyWaiters.clear();
|
||||
_notifySettingWaiters.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
Window::Notifications::GetManager()->clearFromHistory(history);
|
||||
|
||||
history->clearNotifications();
|
||||
_notifyWhenMaps.remove(history);
|
||||
_notifyWhenAlerts.remove(history);
|
||||
_notifyWaiters.remove(history);
|
||||
_notifySettingWaiters.remove(history);
|
||||
|
||||
_notifyWaitTimer.stop();
|
||||
notifyShowNext();
|
||||
}
|
||||
|
||||
void MainWindow::notifyClearFast() {
|
||||
Window::Notifications::GetManager()->clearAllFast();
|
||||
|
||||
_notifyWhenMaps.clear();
|
||||
_notifyWhenAlerts.clear();
|
||||
_notifyWaiters.clear();
|
||||
_notifySettingWaiters.clear();
|
||||
}
|
||||
|
||||
void MainWindow::notifySettingGot() {
|
||||
int32 t = unixtime();
|
||||
for (NotifyWaiters::iterator i = _notifySettingWaiters.begin(); i != _notifySettingWaiters.end();) {
|
||||
History *history = i.key();
|
||||
bool loaded = false, muted = false;
|
||||
if (history->peer->notify != UnknownNotifySettings) {
|
||||
if (history->peer->notify == EmptyNotifySettings || history->peer->notify->mute <= t) {
|
||||
loaded = true;
|
||||
} else if (PeerData *from = i.value().notifyByFrom) {
|
||||
if (from->notify != UnknownNotifySettings) {
|
||||
if (from->notify == EmptyNotifySettings || from->notify->mute <= t) {
|
||||
loaded = true;
|
||||
} else {
|
||||
loaded = muted = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
loaded = muted = true;
|
||||
}
|
||||
}
|
||||
if (loaded) {
|
||||
if (HistoryItem *item = App::histItemById(history->channelId(), i.value().msg)) {
|
||||
if (!item->notificationReady()) {
|
||||
loaded = false;
|
||||
}
|
||||
} else {
|
||||
muted = true;
|
||||
}
|
||||
}
|
||||
if (loaded) {
|
||||
if (!muted) {
|
||||
_notifyWaiters.insert(i.key(), i.value());
|
||||
}
|
||||
i = _notifySettingWaiters.erase(i);
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
_notifyWaitTimer.stop();
|
||||
notifyShowNext();
|
||||
}
|
||||
|
||||
void MainWindow::notifyShowNext() {
|
||||
if (App::quitting()) return;
|
||||
|
||||
auto ms = getms(true), nextAlert = 0LL;
|
||||
bool alert = false;
|
||||
int32 now = unixtime();
|
||||
for (NotifyWhenAlerts::iterator i = _notifyWhenAlerts.begin(); i != _notifyWhenAlerts.end();) {
|
||||
while (!i.value().isEmpty() && i.value().begin().key() <= ms) {
|
||||
NotifySettingsPtr n = i.key()->peer->notify, f = i.value().begin().value() ? i.value().begin().value()->notify : UnknownNotifySettings;
|
||||
while (!i.value().isEmpty() && i.value().begin().key() <= ms + 500) { // not more than one sound in 500ms from one peer - grouping
|
||||
i.value().erase(i.value().begin());
|
||||
}
|
||||
if (n == EmptyNotifySettings || (n != UnknownNotifySettings && n->mute <= now)) {
|
||||
alert = true;
|
||||
} else if (f == EmptyNotifySettings || (f != UnknownNotifySettings && f->mute <= now)) { // notify by from()
|
||||
alert = true;
|
||||
}
|
||||
}
|
||||
if (i.value().isEmpty()) {
|
||||
i = _notifyWhenAlerts.erase(i);
|
||||
} else {
|
||||
if (!nextAlert || nextAlert > i.value().begin().key()) {
|
||||
nextAlert = i.value().begin().key();
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
if (alert) {
|
||||
psFlash();
|
||||
App::playSound();
|
||||
}
|
||||
|
||||
if (_notifyWaiters.isEmpty() || !Global::DesktopNotify() || Platform::Notifications::SkipToast()) {
|
||||
if (nextAlert) {
|
||||
_notifyWaitTimer.start(nextAlert - ms);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
auto next = 0LL;
|
||||
HistoryItem *notifyItem = 0;
|
||||
History *notifyHistory = 0;
|
||||
for (NotifyWaiters::iterator i = _notifyWaiters.begin(); i != _notifyWaiters.end();) {
|
||||
History *history = i.key();
|
||||
if (history->currentNotification() && history->currentNotification()->id != i.value().msg) {
|
||||
NotifyWhenMaps::iterator j = _notifyWhenMaps.find(history);
|
||||
if (j == _notifyWhenMaps.end()) {
|
||||
history->clearNotifications();
|
||||
i = _notifyWaiters.erase(i);
|
||||
continue;
|
||||
}
|
||||
do {
|
||||
NotifyWhenMap::const_iterator k = j.value().constFind(history->currentNotification()->id);
|
||||
if (k != j.value().cend()) {
|
||||
i.value().msg = k.key();
|
||||
i.value().when = k.value();
|
||||
break;
|
||||
}
|
||||
history->skipNotification();
|
||||
} while (history->currentNotification());
|
||||
}
|
||||
if (!history->currentNotification()) {
|
||||
_notifyWhenMaps.remove(history);
|
||||
i = _notifyWaiters.erase(i);
|
||||
continue;
|
||||
}
|
||||
auto when = i.value().when;
|
||||
if (!notifyItem || next > when) {
|
||||
next = when;
|
||||
notifyItem = history->currentNotification();
|
||||
notifyHistory = history;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
if (notifyItem) {
|
||||
if (next > ms) {
|
||||
if (nextAlert && nextAlert < next) {
|
||||
next = nextAlert;
|
||||
nextAlert = 0;
|
||||
}
|
||||
_notifyWaitTimer.start(next - ms);
|
||||
break;
|
||||
} else {
|
||||
HistoryItem *fwd = notifyItem->Has<HistoryMessageForwarded>() ? notifyItem : nullptr; // forwarded notify grouping
|
||||
int32 fwdCount = 1;
|
||||
|
||||
auto ms = getms(true);
|
||||
History *history = notifyItem->history();
|
||||
NotifyWhenMaps::iterator j = _notifyWhenMaps.find(history);
|
||||
if (j == _notifyWhenMaps.cend()) {
|
||||
history->clearNotifications();
|
||||
} else {
|
||||
HistoryItem *nextNotify = 0;
|
||||
do {
|
||||
history->skipNotification();
|
||||
if (!history->hasNotification()) {
|
||||
break;
|
||||
}
|
||||
|
||||
j.value().remove((fwd ? fwd : notifyItem)->id);
|
||||
do {
|
||||
NotifyWhenMap::const_iterator k = j.value().constFind(history->currentNotification()->id);
|
||||
if (k != j.value().cend()) {
|
||||
nextNotify = history->currentNotification();
|
||||
_notifyWaiters.insert(notifyHistory, NotifyWaiter(k.key(), k.value(), 0));
|
||||
break;
|
||||
}
|
||||
history->skipNotification();
|
||||
} while (history->hasNotification());
|
||||
if (nextNotify) {
|
||||
if (fwd) {
|
||||
HistoryItem *nextFwd = nextNotify->Has<HistoryMessageForwarded>() ? nextNotify : nullptr;
|
||||
if (nextFwd && fwd->author() == nextFwd->author() && qAbs(int64(nextFwd->date.toTime_t()) - int64(fwd->date.toTime_t())) < 2) {
|
||||
fwd = nextFwd;
|
||||
++fwdCount;
|
||||
} else {
|
||||
nextNotify = 0;
|
||||
}
|
||||
} else {
|
||||
nextNotify = 0;
|
||||
}
|
||||
}
|
||||
} while (nextNotify);
|
||||
}
|
||||
|
||||
Window::Notifications::GetManager()->showNotification(notifyItem, fwdCount);
|
||||
|
||||
if (!history->hasNotification()) {
|
||||
_notifyWaiters.remove(history);
|
||||
_notifyWhenMaps.remove(history);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (nextAlert) {
|
||||
_notifyWaitTimer.start(nextAlert - ms);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::app_activateClickHandler(ClickHandlerPtr handler, Qt::MouseButton button) {
|
||||
handler->onClick(button);
|
||||
}
|
||||
|
||||
void MainWindow::notifyUpdateAll() {
|
||||
Window::Notifications::GetManager()->updateAll();
|
||||
}
|
||||
|
||||
QImage MainWindow::iconLarge() const {
|
||||
return iconbig256;
|
||||
}
|
||||
|
@ -1346,7 +1039,6 @@ void MainWindow::updateIsActiveHook() {
|
|||
}
|
||||
|
||||
MainWindow::~MainWindow() {
|
||||
notifyClearFast();
|
||||
if (_clearManager) {
|
||||
_clearManager->stop();
|
||||
_clearManager = nullptr;
|
||||
|
|
|
@ -87,7 +87,7 @@ public:
|
|||
void clearPasscode();
|
||||
void checkAutoLockIn(int msec);
|
||||
void setupIntro();
|
||||
void setupMain(const MTPUser *user = 0);
|
||||
void setupMain(const MTPUser *user = nullptr);
|
||||
void serviceNotification(const TextWithEntities &message, const MTPMessageMedia &media = MTP_messageMediaEmpty(), int32 date = 0, bool force = false);
|
||||
void serviceNotificationLocal(QString text);
|
||||
void sendServiceHistoryRequest();
|
||||
|
@ -120,12 +120,6 @@ public:
|
|||
TempDirState localStorageState();
|
||||
void tempDirDelete(int task);
|
||||
|
||||
void notifySettingGot();
|
||||
void notifySchedule(History *history, HistoryItem *item);
|
||||
void notifyClear(History *history = 0);
|
||||
void notifyClearFast();
|
||||
void notifyUpdateAll();
|
||||
|
||||
QImage iconLarge() const;
|
||||
|
||||
void sendPaths();
|
||||
|
@ -183,8 +177,6 @@ public slots:
|
|||
void onClearFinished(int task, void *manager);
|
||||
void onClearFailed(int task, void *manager);
|
||||
|
||||
void notifyShowNext();
|
||||
|
||||
void onShowAddContact();
|
||||
void onShowNewGroup();
|
||||
void onShowNewChannel();
|
||||
|
@ -240,28 +232,6 @@ private:
|
|||
SingleTimer _autoLockTimer;
|
||||
TimeMs _shouldLockAt = 0;
|
||||
|
||||
using NotifyWhenMap = QMap<MsgId, TimeMs>;
|
||||
using NotifyWhenMaps = QMap<History*, NotifyWhenMap>;
|
||||
NotifyWhenMaps _notifyWhenMaps;
|
||||
struct NotifyWaiter {
|
||||
NotifyWaiter(MsgId msg, TimeMs when, PeerData *notifyByFrom)
|
||||
: msg(msg)
|
||||
, when(when)
|
||||
, notifyByFrom(notifyByFrom) {
|
||||
}
|
||||
MsgId msg;
|
||||
TimeMs when;
|
||||
PeerData *notifyByFrom;
|
||||
};
|
||||
using NotifyWaiters = QMap<History*, NotifyWaiter>;
|
||||
NotifyWaiters _notifyWaiters;
|
||||
NotifyWaiters _notifySettingWaiters;
|
||||
SingleTimer _notifyWaitTimer;
|
||||
|
||||
using NotifyWhenAlert = QMap<TimeMs, PeerData*>;
|
||||
using NotifyWhenAlerts = QMap<History*, NotifyWhenAlert>;
|
||||
NotifyWhenAlerts _notifyWhenAlerts;
|
||||
|
||||
};
|
||||
|
||||
class PreLaunchWindow : public TWidget {
|
||||
|
|
|
@ -36,6 +36,9 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
#include "window/themes/window_theme_preview.h"
|
||||
#include "core/task_queue.h"
|
||||
#include "observer_peer.h"
|
||||
#include "auth_session.h"
|
||||
#include "messenger.h"
|
||||
#include "storage/file_download.h"
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -86,10 +89,15 @@ MediaView::MediaView(QWidget*) : TWidget(nullptr)
|
|||
|
||||
connect(QApplication::desktop(), SIGNAL(resized(int)), this, SLOT(onScreenResized(int)));
|
||||
|
||||
subscribe(FileDownload::ImageLoaded(), [this] {
|
||||
if (!isHidden()) {
|
||||
updateControls();
|
||||
}
|
||||
// While we have one mediaview for all authsessions we have to do this.
|
||||
subscribe(Messenger::Instance().authSessionChanged(), [this] {
|
||||
if (!AuthSession::Exists()) return;
|
||||
|
||||
subscribe(AuthSession::CurrentDownloaderTaskFinished(), [this] {
|
||||
if (!isHidden()) {
|
||||
updateControls();
|
||||
}
|
||||
});
|
||||
});
|
||||
auto observeEvents = Notify::PeerUpdate::Flag::SharedMediaChanged;
|
||||
subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) {
|
||||
|
@ -1155,7 +1163,7 @@ void MediaView::displayPhoto(PhotoData *photo, HistoryItem *item) {
|
|||
}
|
||||
|
||||
_zoomToScreen = 0;
|
||||
MTP::clearLoaderPriorities();
|
||||
AuthSession::Current().downloader()->clearPriorities();
|
||||
_full = -1;
|
||||
_current = QPixmap();
|
||||
_down = OverNone;
|
||||
|
|
|
@ -86,7 +86,6 @@ Messenger::Messenger() : QObject()
|
|||
anim::startManager();
|
||||
historyInit();
|
||||
Media::Player::start();
|
||||
Window::Notifications::Start();
|
||||
|
||||
DEBUG_LOG(("Application Info: inited..."));
|
||||
|
||||
|
@ -130,7 +129,7 @@ Messenger::Messenger() : QObject()
|
|||
if (state == Local::ReadMapPassNeeded) {
|
||||
_window->setupPasscode();
|
||||
} else {
|
||||
if (AuthSession::Current()) {
|
||||
if (AuthSession::Exists()) {
|
||||
_window->setupMain();
|
||||
} else {
|
||||
_window->setupIntro();
|
||||
|
@ -196,7 +195,7 @@ QByteArray Messenger::serializeMtpAuthorization() const {
|
|||
QDataStream stream(&buffer);
|
||||
stream.setVersion(QDataStream::Qt_5_1);
|
||||
|
||||
stream << qint32(AuthSession::CurrentUserId()) << qint32(mainDcId);
|
||||
stream << qint32(AuthSession::Exists() ? AuthSession::CurrentUserId() : 0) << qint32(mainDcId);
|
||||
writeKeys(stream, keys);
|
||||
writeKeys(stream, keysToDestroy);
|
||||
}
|
||||
|
@ -433,7 +432,7 @@ bool Messenger::peerPhotoFail(PeerId peer, const RPCError &error) {
|
|||
}
|
||||
|
||||
void Messenger::peerClearPhoto(PeerId id) {
|
||||
if (!AuthSession::Current()) return;
|
||||
if (!AuthSession::Exists()) return;
|
||||
|
||||
if (id == AuthSession::CurrentUserPeerId()) {
|
||||
MTP::send(MTPphotos_UpdateProfilePhoto(MTP_inputPhotoEmpty()), rpcDone(&Messenger::selfPhotoCleared), rpcFail(&Messenger::peerPhotoFail, id));
|
||||
|
@ -525,7 +524,7 @@ void Messenger::killDownloadSessions() {
|
|||
}
|
||||
|
||||
void Messenger::photoUpdated(const FullMsgId &msgId, bool silent, const MTPInputFile &file) {
|
||||
if (!AuthSession::Current()) return;
|
||||
if (!AuthSession::Exists()) return;
|
||||
|
||||
auto i = photoUpdates.find(msgId);
|
||||
if (i != photoUpdates.end()) {
|
||||
|
@ -583,10 +582,12 @@ void Messenger::onSwitchTestMode() {
|
|||
|
||||
void Messenger::authSessionCreate(UserId userId) {
|
||||
_authSession = std::make_unique<AuthSession>(userId);
|
||||
authSessionChanged().notify();
|
||||
}
|
||||
|
||||
void Messenger::authSessionDestroy() {
|
||||
_authSession.reset();
|
||||
authSessionChanged().notify();
|
||||
}
|
||||
|
||||
FileUploader *Messenger::uploader() {
|
||||
|
@ -656,6 +657,7 @@ void Messenger::prepareToDestroy() {
|
|||
|
||||
// Some MTP requests can be cancelled from data clearing.
|
||||
App::clearHistories();
|
||||
authSessionDestroy();
|
||||
_delayedDestroyedLoaders.clear();
|
||||
|
||||
_mtproto.reset();
|
||||
|
@ -668,8 +670,6 @@ Messenger::~Messenger() {
|
|||
|
||||
Shortcuts::finish();
|
||||
|
||||
Window::Notifications::Finish();
|
||||
|
||||
anim::stopManager();
|
||||
|
||||
stopWebLoadManager();
|
||||
|
|
|
@ -32,7 +32,7 @@ class MainWidget;
|
|||
class FileUploader;
|
||||
class Translator;
|
||||
|
||||
class Messenger : public QObject, public RPCSender, private base::Subscriber {
|
||||
class Messenger final : public QObject, public RPCSender, private base::Subscriber {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
@ -73,6 +73,9 @@ public:
|
|||
}
|
||||
void authSessionCreate(UserId userId);
|
||||
void authSessionDestroy();
|
||||
base::Observable<void> &authSessionChanged() {
|
||||
return _authSessionChanged;
|
||||
}
|
||||
|
||||
FileUploader *uploader();
|
||||
void uploadProfilePhoto(const QImage &tosend, const PeerId &peerId);
|
||||
|
@ -145,6 +148,7 @@ private:
|
|||
std::unique_ptr<MTP::Instance> _mtproto;
|
||||
std::unique_ptr<MTP::Instance> _mtprotoForKeysDestroy;
|
||||
std::unique_ptr<AuthSession> _authSession;
|
||||
base::Observable<void> _authSessionChanged;
|
||||
|
||||
SingleDelayedCall _delayedLoadersDestroyer;
|
||||
std::vector<std::unique_ptr<FileLoader>> _delayedDestroyedLoaders;
|
||||
|
|
|
@ -796,7 +796,7 @@ bool Instance::Private::rpcErrorOccured(mtpRequestId requestId, const RPCFailHan
|
|||
}
|
||||
|
||||
bool Instance::Private::hasAuthorization() {
|
||||
return (AuthSession::Current() != nullptr);
|
||||
return AuthSession::Exists();
|
||||
}
|
||||
|
||||
void Instance::Private::importDone(const MTPauth_Authorization &result, mtpRequestId requestId) {
|
||||
|
|
|
@ -42,6 +42,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
#include "history/history_service_layout.h"
|
||||
#include "media/media_audio.h"
|
||||
#include "observer_peer.h"
|
||||
#include "auth_session.h"
|
||||
#include "storage/file_download.h"
|
||||
|
||||
// flick scroll taken from http://qt-project.org/doc/qt-4.8/demos-embedded-anomaly-src-flickcharm-cpp.html
|
||||
|
||||
|
@ -59,7 +61,7 @@ OverviewInner::OverviewInner(OverviewWidget *overview, Ui::ScrollArea *scroll, P
|
|||
, _cancelSearch(this, st::dialogsCancelSearch)
|
||||
, _itemsToBeLoaded(LinksOverviewPerPage * 2)
|
||||
, _width(st::windowMinWidth) {
|
||||
subscribe(FileDownload::ImageLoaded(), [this] { update(); });
|
||||
subscribe(AuthSession::Current().downloader()->taskFinished(), [this] { update(); });
|
||||
subscribe(Global::RefItemRemoved(), [this](HistoryItem *item) {
|
||||
itemRemoved(item);
|
||||
});
|
||||
|
@ -1917,7 +1919,7 @@ void OverviewWidget::clear() {
|
|||
}
|
||||
|
||||
void OverviewWidget::onScroll() {
|
||||
MTP::clearLoaderPriorities();
|
||||
AuthSession::Current().downloader()->clearPriorities();
|
||||
int32 preloadThreshold = _scroll->height() * 5;
|
||||
bool needToPreload = false;
|
||||
do {
|
||||
|
|
|
@ -72,7 +72,7 @@ void PasscodeWidget::onSubmit() {
|
|||
cSetPasscodeBadTries(0);
|
||||
|
||||
Messenger::Instance().startMtp();
|
||||
if (AuthSession::Current()) {
|
||||
if (AuthSession::Exists()) {
|
||||
App::wnd()->setupMain();
|
||||
} else {
|
||||
App::wnd()->setupIntro();
|
||||
|
|
|
@ -164,8 +164,10 @@ static gboolean _trayIconCheck(gpointer/* pIn*/) {
|
|||
if (Libs::gtk_status_icon_is_embedded(_trayIcon)) {
|
||||
trayIconChecked = true;
|
||||
cSetSupportTray(true);
|
||||
if (Global::started()) {
|
||||
Global::RefWorkMode().setForced(Global::WorkMode().value(), true);
|
||||
}
|
||||
if (App::wnd()) {
|
||||
App::wnd()->psUpdateWorkmode();
|
||||
Notify::unreadCounterUpdated();
|
||||
App::wnd()->updateTrayMenu();
|
||||
}
|
||||
|
@ -196,7 +198,7 @@ void MainWindow::initHook() {
|
|||
}
|
||||
|
||||
bool MainWindow::hasTrayIcon() const {
|
||||
return trayIcon || ((useAppIndicator || (useStatusIcon && trayIconChecked)) && (cWorkMode() != dbiwmWindowOnly));
|
||||
return trayIcon || ((useAppIndicator || (useStatusIcon && trayIconChecked)) && (Global::WorkMode().value() != dbiwmWindowOnly));
|
||||
}
|
||||
|
||||
void MainWindow::psStatusIconCheck() {
|
||||
|
@ -272,10 +274,10 @@ void MainWindow::psSetupTrayIcon() {
|
|||
}
|
||||
}
|
||||
|
||||
void MainWindow::psUpdateWorkmode() {
|
||||
void MainWindow::workmodeUpdated(DBIWorkMode mode) {
|
||||
if (!cSupportTray()) return;
|
||||
|
||||
if (cWorkMode() == dbiwmWindowOnly) {
|
||||
if (mode == dbiwmWindowOnly) {
|
||||
if (noQtTrayIcon) {
|
||||
if (useAppIndicator) {
|
||||
Libs::app_indicator_set_status(_trayIndicator, APP_INDICATOR_STATUS_PASSIVE);
|
||||
|
@ -372,10 +374,6 @@ void MainWindow::updateIconCounters() {
|
|||
}
|
||||
}
|
||||
|
||||
bool MainWindow::psHasNativeNotifications() {
|
||||
return Notifications::Supported();
|
||||
}
|
||||
|
||||
void MainWindow::LibsLoaded() {
|
||||
noQtTrayIcon = !DesktopEnvironment::TryQtTrayIcon();
|
||||
tryAppIndicator = !DesktopEnvironment::PreferAppIndicatorTrayIcon();
|
||||
|
@ -518,7 +516,7 @@ void MainWindow::psCreateTrayIcon() {
|
|||
Libs::g_idle_add((GSourceFunc)_trayIconCheck, 0);
|
||||
_psCheckStatusIconTimer.start(100);
|
||||
} else {
|
||||
psUpdateWorkmode();
|
||||
workmodeUpdated(Global::WorkMode().value());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -555,7 +553,7 @@ void MainWindow::psFirstShow() {
|
|||
|
||||
if ((cLaunchMode() == LaunchModeAutoStart && cStartMinimized()) || cStartInTray()) {
|
||||
setWindowState(Qt::WindowMinimized);
|
||||
if (cWorkMode() == dbiwmTrayOnly || cWorkMode() == dbiwmWindowAndTray) {
|
||||
if (Global::WorkMode().value() == dbiwmTrayOnly || Global::WorkMode().value() == dbiwmWindowAndTray) {
|
||||
hide();
|
||||
} else {
|
||||
show();
|
||||
|
@ -577,9 +575,6 @@ void MainWindow::psUpdateSysMenu(Qt::WindowState state) {
|
|||
void MainWindow::psUpdateMargins() {
|
||||
}
|
||||
|
||||
void MainWindow::psFlash() {
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow() {
|
||||
if (_trayIcon) {
|
||||
Libs::g_object_unref(_trayIcon);
|
||||
|
|
|
@ -35,16 +35,9 @@ public:
|
|||
void psUpdateSysMenu(Qt::WindowState state);
|
||||
void psUpdateMargins();
|
||||
|
||||
void psFlash();
|
||||
void psNotifySettingGot();
|
||||
|
||||
void psUpdateWorkmode();
|
||||
|
||||
void psRefreshTaskbarIcon() {
|
||||
}
|
||||
|
||||
bool psHasNativeNotifications();
|
||||
|
||||
virtual QImage iconWithCounter(int size, int count, style::color bg, style::color fg, bool smallIcon) = 0;
|
||||
|
||||
static void LibsLoaded();
|
||||
|
@ -63,6 +56,8 @@ protected:
|
|||
|
||||
bool hasTrayIcon() const override;
|
||||
|
||||
void workmodeUpdated(DBIWorkMode mode) override;
|
||||
|
||||
QSystemTrayIcon *trayIcon = nullptr;
|
||||
QMenu *trayIconMenu = nullptr;
|
||||
QImage icon256, iconbig256;
|
||||
|
|
|
@ -24,13 +24,12 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
#include "platform/linux/linux_libnotify.h"
|
||||
#include "platform/linux/linux_libs.h"
|
||||
#include "lang.h"
|
||||
#include "core/task_queue.h"
|
||||
|
||||
namespace Platform {
|
||||
namespace Notifications {
|
||||
namespace {
|
||||
|
||||
NeverFreedPointer<Manager> ManagerInstance;
|
||||
|
||||
bool LibNotifyLoaded() {
|
||||
return (Libs::notify_init != nullptr)
|
||||
&& (Libs::notify_uninit != nullptr)
|
||||
|
@ -100,10 +99,10 @@ QString escapeHtml(const QString &text) {
|
|||
|
||||
class NotificationData {
|
||||
public:
|
||||
NotificationData(const QString &title, const QString &body, const QStringList &capabilities, PeerId peerId, MsgId msgId)
|
||||
NotificationData(const std::shared_ptr<Manager*> &guarded, const QString &title, const QString &body, const QStringList &capabilities, PeerId peerId, MsgId msgId)
|
||||
: _data(Libs::notify_notification_new(title.toUtf8().constData(), body.toUtf8().constData(), nullptr)) {
|
||||
if (valid()) {
|
||||
init(capabilities, peerId, msgId);
|
||||
init(guarded, capabilities, peerId, msgId);
|
||||
}
|
||||
}
|
||||
bool valid() const {
|
||||
|
@ -158,7 +157,7 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
void init(const QStringList &capabilities, PeerId peerId, MsgId msgId) {
|
||||
void init(const std::shared_ptr<Manager*> &guarded, const QStringList &capabilities, PeerId peerId, MsgId msgId) {
|
||||
if (capabilities.contains(qsl("append"))) {
|
||||
Libs::notify_notification_set_hint_string(_data, "append", "true");
|
||||
} else if (capabilities.contains(qsl("x-canonical-append"))) {
|
||||
|
@ -169,22 +168,20 @@ private:
|
|||
auto signalHandler = G_CALLBACK(NotificationData::notificationClosed);
|
||||
auto signalName = "closed";
|
||||
auto signalDataFreeMethod = &NotificationData::notificationDataFreeClosure;
|
||||
auto signalData = new NotificationDataStruct(peerId, msgId);
|
||||
auto signalData = new NotificationDataStruct(guarded, peerId, msgId);
|
||||
_handlerId = Libs::g_signal_connect_helper(signalReceiver, signalName, signalHandler, signalData, signalDataFreeMethod);
|
||||
|
||||
Libs::notify_notification_set_timeout(_data, Libs::NOTIFY_EXPIRES_DEFAULT);
|
||||
|
||||
if (auto manager = ManagerInstance.data()) {
|
||||
if (manager->hasActionsSupport()) {
|
||||
auto label = lang(lng_notification_reply).toUtf8();
|
||||
auto actionReceiver = _data;
|
||||
auto actionHandler = &NotificationData::notificationClicked;
|
||||
auto actionLabel = label.constData();
|
||||
auto actionName = "default";
|
||||
auto actionDataFreeMethod = &NotificationData::notificationDataFree;
|
||||
auto actionData = new NotificationDataStruct(peerId, msgId);
|
||||
Libs::notify_notification_add_action(actionReceiver, actionName, actionLabel, actionHandler, actionData, actionDataFreeMethod);
|
||||
}
|
||||
if ((*guarded)->hasActionsSupport()) {
|
||||
auto label = lang(lng_notification_reply).toUtf8();
|
||||
auto actionReceiver = _data;
|
||||
auto actionHandler = &NotificationData::notificationClicked;
|
||||
auto actionLabel = label.constData();
|
||||
auto actionName = "default";
|
||||
auto actionDataFreeMethod = &NotificationData::notificationDataFree;
|
||||
auto actionData = new NotificationDataStruct(guarded, peerId, msgId);
|
||||
Libs::notify_notification_add_action(actionReceiver, actionName, actionLabel, actionHandler, actionData, actionDataFreeMethod);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -194,12 +191,23 @@ private:
|
|||
}
|
||||
|
||||
struct NotificationDataStruct {
|
||||
NotificationDataStruct(PeerId peerId, MsgId msgId) : peerId(peerId), msgId(msgId) {
|
||||
NotificationDataStruct(const std::shared_ptr<Manager*> &guarded, PeerId peerId, MsgId msgId)
|
||||
: weak(guarded)
|
||||
, peerId(peerId)
|
||||
, msgId(msgId) {
|
||||
}
|
||||
|
||||
std::weak_ptr<Manager*> weak;
|
||||
PeerId peerId = 0;
|
||||
MsgId msgId = 0;
|
||||
};
|
||||
static void performOnMainQueue(NotificationDataStruct *data, base::lambda_once<void(Manager *manager)> task) {
|
||||
base::TaskQueue::Main().Put([weak = data->weak, task = std::move(task)]() mutable {
|
||||
if (auto strong = weak.lock()) {
|
||||
task(*strong);
|
||||
}
|
||||
});
|
||||
}
|
||||
static void notificationDataFree(gpointer data) {
|
||||
auto notificationData = static_cast<NotificationDataStruct*>(data);
|
||||
delete notificationData;
|
||||
|
@ -211,15 +219,15 @@ private:
|
|||
static void notificationClosed(Libs::NotifyNotification *notification, gpointer data) {
|
||||
auto closedReason = Libs::notify_notification_get_closed_reason(notification);
|
||||
auto notificationData = static_cast<NotificationDataStruct*>(data);
|
||||
if (auto manager = ManagerInstance.data()) {
|
||||
manager->clearNotification(notificationData->peerId, notificationData->msgId);
|
||||
}
|
||||
performOnMainQueue(notificationData, [peerId = notificationData->peerId, msgId = notificationData->msgId](Manager *manager) {
|
||||
manager->clearNotification(peerId, msgId);
|
||||
});
|
||||
}
|
||||
static void notificationClicked(Libs::NotifyNotification *notification, char *action, gpointer data) {
|
||||
auto notificationData = static_cast<NotificationDataStruct*>(data);
|
||||
if (auto manager = ManagerInstance.data()) {
|
||||
manager->notificationActivated(notificationData->peerId, notificationData->msgId);
|
||||
}
|
||||
performOnMainQueue(notificationData, [peerId = notificationData->peerId, msgId = notificationData->msgId](Manager *manager) {
|
||||
manager->notificationActivated(peerId, msgId);
|
||||
});
|
||||
}
|
||||
|
||||
Libs::NotifyNotification *_data = nullptr;
|
||||
|
@ -229,47 +237,72 @@ private:
|
|||
|
||||
using Notification = QSharedPointer<NotificationData>;
|
||||
|
||||
} // namespace
|
||||
|
||||
void Start() {
|
||||
if (LibNotifyLoaded()) {
|
||||
if (Libs::notify_is_initted() || Libs::notify_init("Telegram Desktop")) {
|
||||
ManagerInstance.createIfNull();
|
||||
if (!ManagerInstance->init()) {
|
||||
ManagerInstance.clear();
|
||||
LOG(("LibNotify Error: manager failed to init!"));
|
||||
}
|
||||
} else {
|
||||
LOG(("LibNotify Error: failed to init!"));
|
||||
}
|
||||
QString GetServerName() {
|
||||
if (!LibNotifyLoaded()) {
|
||||
return QString();
|
||||
}
|
||||
if (!Libs::notify_is_initted() && !Libs::notify_init("Telegram Desktop")) {
|
||||
LOG(("LibNotify Error: failed to init!"));
|
||||
return QString();
|
||||
}
|
||||
|
||||
gchar *name = nullptr;
|
||||
auto guard = base::scope_guard([&name] {
|
||||
if (name) Libs::g_free(name);
|
||||
});
|
||||
|
||||
if (!Libs::notify_get_server_info(&name, nullptr, nullptr, nullptr)) {
|
||||
LOG(("LibNotify Error: could not get server name!"));
|
||||
return QString();
|
||||
}
|
||||
if (!name) {
|
||||
LOG(("LibNotify Error: successfully got empty server name!"));
|
||||
return QString();
|
||||
}
|
||||
|
||||
auto result = QString::fromUtf8(static_cast<const char*>(name));
|
||||
LOG(("Notifications Server: %1").arg(result));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Window::Notifications::Manager *GetManager() {
|
||||
if (Global::started() && Global::NativeNotifications()) {
|
||||
return ManagerInstance.data();
|
||||
auto LibNotifyServerName = QString();
|
||||
|
||||
} // namespace
|
||||
|
||||
bool Supported() {
|
||||
static auto Checked = false;
|
||||
if (!Checked) {
|
||||
Checked = true;
|
||||
LibNotifyServerName = GetServerName();
|
||||
}
|
||||
|
||||
return !LibNotifyServerName.isEmpty();
|
||||
}
|
||||
|
||||
std::unique_ptr<Window::Notifications::Manager> Create(Window::Notifications::System *system) {
|
||||
if (Global::NativeNotifications() && Supported()) {
|
||||
return std::make_unique<Manager>(system);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool Supported() {
|
||||
return ManagerInstance.data() != nullptr;
|
||||
}
|
||||
|
||||
void Finish() {
|
||||
if (GetManager()) {
|
||||
ManagerInstance.reset();
|
||||
Libs::notify_uninit();
|
||||
if (Libs::notify_is_initted && Libs::notify_uninit) {
|
||||
if (Libs::notify_is_initted()) {
|
||||
Libs::notify_uninit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Manager::Impl {
|
||||
class Manager::Private {
|
||||
public:
|
||||
using Type = Window::Notifications::CachedUserpics::Type;
|
||||
Impl(Type type) : _cachedUserpics(type) {
|
||||
explicit Private(Type type)
|
||||
: _cachedUserpics(type) {
|
||||
}
|
||||
|
||||
bool init();
|
||||
void init(Manager *manager);
|
||||
|
||||
void showNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, const QString &msg, bool hideNameAndPhoto, bool hideReplyButton);
|
||||
void clearAll();
|
||||
|
@ -283,6 +316,8 @@ public:
|
|||
return _actionsSupported;
|
||||
}
|
||||
|
||||
~Private();
|
||||
|
||||
private:
|
||||
QString escapeNotificationText(const QString &text) const;
|
||||
void showNextNotification();
|
||||
|
@ -309,9 +344,13 @@ private:
|
|||
bool _markupSupported = false;
|
||||
bool _poorSupported = false;
|
||||
|
||||
std::shared_ptr<Manager*> _guarded;
|
||||
|
||||
};
|
||||
|
||||
bool Manager::Impl::init() {
|
||||
void Manager::Private::init(Manager *manager) {
|
||||
_guarded = std::make_shared<Manager*>(manager);
|
||||
|
||||
if (auto capabilities = Libs::notify_get_server_caps()) {
|
||||
for (auto capability = capabilities; capability; capability = capability->next) {
|
||||
auto capabilityText = QString::fromUtf8(static_cast<const char*>(capability->data));
|
||||
|
@ -331,32 +370,19 @@ bool Manager::Impl::init() {
|
|||
|
||||
// Unity and other Notify OSD users handle desktop notifications
|
||||
// extremely poor, even without the ability to close() them.
|
||||
gchar *name = nullptr;
|
||||
if (Libs::notify_get_server_info(&name, nullptr, nullptr, nullptr)) {
|
||||
if (name) {
|
||||
_serverName = QString::fromUtf8(static_cast<const char*>(name));
|
||||
Libs::g_free(name);
|
||||
|
||||
LOG(("Notifications Server: %1").arg(_serverName));
|
||||
if (_serverName == qstr("notify-osd")) {
|
||||
// _poorSupported = true;
|
||||
_actionsSupported = false;
|
||||
}
|
||||
} else {
|
||||
LOG(("LibNotify Error: successfully got empty server name!"));
|
||||
}
|
||||
} else {
|
||||
LOG(("LibNotify Error: could not get server name!"));
|
||||
_serverName = LibNotifyServerName;
|
||||
t_assert(!_serverName.isEmpty());
|
||||
if (_serverName == qstr("notify-osd")) {
|
||||
// _poorSupported = true;
|
||||
_actionsSupported = false;
|
||||
}
|
||||
|
||||
return !_serverName.isEmpty();
|
||||
}
|
||||
|
||||
QString Manager::Impl::escapeNotificationText(const QString &text) const {
|
||||
QString Manager::Private::escapeNotificationText(const QString &text) const {
|
||||
return _markupSupported ? escapeHtml(text) : text;
|
||||
}
|
||||
|
||||
void Manager::Impl::showNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, const QString &msg, bool hideNameAndPhoto, bool hideReplyButton) {
|
||||
void Manager::Private::showNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, const QString &msg, bool hideNameAndPhoto, bool hideReplyButton) {
|
||||
auto titleText = escapeNotificationText(title);
|
||||
auto subtitleText = escapeNotificationText(subtitle);
|
||||
auto msgText = escapeNotificationText(msg);
|
||||
|
@ -376,7 +402,7 @@ void Manager::Impl::showNotification(PeerData *peer, MsgId msgId, const QString
|
|||
showNextNotification();
|
||||
}
|
||||
|
||||
void Manager::Impl::showNextNotification() {
|
||||
void Manager::Private::showNextNotification() {
|
||||
// Show only one notification at a time in Unity / Notify OSD.
|
||||
if (_poorSupported) {
|
||||
for (auto b = _notifications.begin(); !_notifications.isEmpty() && b->isEmpty();) {
|
||||
|
@ -401,7 +427,7 @@ void Manager::Impl::showNextNotification() {
|
|||
|
||||
auto peerId = data.peer->id;
|
||||
auto msgId = data.msgId;
|
||||
auto notification = MakeShared<NotificationData>(data.title, data.body, _capabilities, peerId, msgId);
|
||||
auto notification = MakeShared<NotificationData>(_guarded, data.title, data.body, _capabilities, peerId, msgId);
|
||||
if (!notification->valid()) {
|
||||
return;
|
||||
}
|
||||
|
@ -438,7 +464,7 @@ void Manager::Impl::showNextNotification() {
|
|||
}
|
||||
}
|
||||
|
||||
void Manager::Impl::clearAll() {
|
||||
void Manager::Private::clearAll() {
|
||||
_queuedNotifications.clear();
|
||||
|
||||
auto temp = base::take(_notifications);
|
||||
|
@ -449,7 +475,7 @@ void Manager::Impl::clearAll() {
|
|||
}
|
||||
}
|
||||
|
||||
void Manager::Impl::clearFromHistory(History *history) {
|
||||
void Manager::Private::clearFromHistory(History *history) {
|
||||
for (auto i = _queuedNotifications.begin(); i != _queuedNotifications.end();) {
|
||||
if (i->peer == history->peer) {
|
||||
i = _queuedNotifications.erase(i);
|
||||
|
@ -471,7 +497,7 @@ void Manager::Impl::clearFromHistory(History *history) {
|
|||
showNextNotification();
|
||||
}
|
||||
|
||||
void Manager::Impl::clearNotification(PeerId peerId, MsgId msgId) {
|
||||
void Manager::Private::clearNotification(PeerId peerId, MsgId msgId) {
|
||||
auto i = _notifications.find(peerId);
|
||||
if (i != _notifications.cend()) {
|
||||
i.value().remove(msgId);
|
||||
|
@ -483,37 +509,39 @@ void Manager::Impl::clearNotification(PeerId peerId, MsgId msgId) {
|
|||
showNextNotification();
|
||||
}
|
||||
|
||||
Manager::Manager() : _impl(std::make_unique<Impl>(Impl::Type::Rounded)) {
|
||||
Manager::Private::~Private() {
|
||||
clearAll();
|
||||
}
|
||||
|
||||
bool Manager::init() {
|
||||
return _impl->init();
|
||||
Manager::Manager(Window::Notifications::System *system) : NativeManager(system)
|
||||
, _private(std::make_unique<Private>(Private::Type::Rounded)) {
|
||||
_private->init(this);
|
||||
}
|
||||
|
||||
void Manager::clearNotification(PeerId peerId, MsgId msgId) {
|
||||
_impl->clearNotification(peerId, msgId);
|
||||
_private->clearNotification(peerId, msgId);
|
||||
}
|
||||
|
||||
bool Manager::hasPoorSupport() const {
|
||||
return _impl->hasPoorSupport();
|
||||
return _private->hasPoorSupport();
|
||||
}
|
||||
|
||||
bool Manager::hasActionsSupport() const {
|
||||
return _impl->hasActionsSupport();
|
||||
return _private->hasActionsSupport();
|
||||
}
|
||||
|
||||
Manager::~Manager() = default;
|
||||
|
||||
void Manager::doShowNativeNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, const QString &msg, bool hideNameAndPhoto, bool hideReplyButton) {
|
||||
_impl->showNotification(peer, msgId, title, subtitle, msg, hideNameAndPhoto, hideReplyButton);
|
||||
_private->showNotification(peer, msgId, title, subtitle, msg, hideNameAndPhoto, hideReplyButton);
|
||||
}
|
||||
|
||||
void Manager::doClearAllFast() {
|
||||
_impl->clearAll();
|
||||
_private->clearAll();
|
||||
}
|
||||
|
||||
void Manager::doClearFromHistory(History *history) {
|
||||
_impl->clearFromHistory(history);
|
||||
_private->clearFromHistory(history);
|
||||
}
|
||||
|
||||
} // namespace Notifications
|
||||
|
|
|
@ -36,11 +36,14 @@ inline bool SkipToast() {
|
|||
return false;
|
||||
}
|
||||
|
||||
inline void FlashBounce() {
|
||||
}
|
||||
|
||||
void Finish();
|
||||
|
||||
class Manager : public Window::Notifications::NativeManager {
|
||||
public:
|
||||
Manager();
|
||||
|
||||
bool init();
|
||||
Manager(Window::Notifications::System *system);
|
||||
|
||||
void clearNotification(PeerId peerId, MsgId msgId);
|
||||
bool hasPoorSupport() const;
|
||||
|
@ -54,9 +57,8 @@ protected:
|
|||
void doClearFromHistory(History *history) override;
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
friend class Impl;
|
||||
std::unique_ptr<Impl> _impl;
|
||||
class Private;
|
||||
const std::unique_ptr<Private> _private;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
#include "mainwidget.h"
|
||||
#include "mainwindow.h"
|
||||
#include "platform/linux/file_utilities_linux.h"
|
||||
#include "platform/platform_notifications_manager.h"
|
||||
#include "storage/localstorage.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
@ -370,6 +371,8 @@ void start() {
|
|||
}
|
||||
|
||||
void finish() {
|
||||
Notifications::Finish();
|
||||
|
||||
delete _psEventFilter;
|
||||
_psEventFilter = nullptr;
|
||||
}
|
||||
|
|
|
@ -36,25 +36,20 @@ public:
|
|||
void psUpdateSysMenu(Qt::WindowState state);
|
||||
void psUpdateMargins();
|
||||
|
||||
void psFlash();
|
||||
|
||||
void psUpdateWorkmode();
|
||||
|
||||
void psRefreshTaskbarIcon() {
|
||||
}
|
||||
|
||||
bool psFilterNativeEvent(void *event);
|
||||
|
||||
bool psHasNativeNotifications() {
|
||||
return !(QSysInfo::macVersion() < QSysInfo::MV_10_8);
|
||||
}
|
||||
|
||||
virtual QImage iconWithCounter(int size, int count, style::color bg, style::color fg, bool smallIcon) = 0;
|
||||
|
||||
int getCustomTitleHeight() const {
|
||||
return _customTitleHeight;
|
||||
}
|
||||
|
||||
// It is placed here while the window handles activeSpaceDidChange event.
|
||||
void customNotificationCreated(QWidget *notification);
|
||||
|
||||
~MainWindow();
|
||||
|
||||
class Private;
|
||||
|
@ -88,6 +83,8 @@ protected:
|
|||
|
||||
void updateGlobalMenuHook() override;
|
||||
|
||||
void workmodeUpdated(DBIWorkMode mode) override;
|
||||
|
||||
QSystemTrayIcon *trayIcon = nullptr;
|
||||
QMenu *trayIconMenu = nullptr;
|
||||
QImage icon256, iconbig256;
|
||||
|
@ -109,9 +106,16 @@ private:
|
|||
void updateTitleCounter();
|
||||
void updateIconCounters();
|
||||
|
||||
class CustomNotificationHandle;
|
||||
friend class CustomNotificationHandle;
|
||||
void customNotificationDestroyed(CustomNotificationHandle *handle);
|
||||
void activateCustomNotifications();
|
||||
|
||||
friend class Private;
|
||||
std::unique_ptr<Private> _private;
|
||||
|
||||
std::set<CustomNotificationHandle*> _customNotifications;
|
||||
|
||||
mutable bool psIdle;
|
||||
mutable QTimer psIdleTimer;
|
||||
|
||||
|
|
|
@ -56,7 +56,6 @@ public:
|
|||
Private(MainWindow *window);
|
||||
|
||||
void setWindowBadge(const QString &str);
|
||||
void startBounce();
|
||||
|
||||
void enableShadow(WId winId);
|
||||
|
||||
|
@ -64,6 +63,7 @@ public:
|
|||
|
||||
void willEnterFullScreen();
|
||||
void willExitFullScreen();
|
||||
void activateCustomNotifications();
|
||||
|
||||
void initCustomTitle(NSWindow *window, NSView *view);
|
||||
|
||||
|
@ -82,6 +82,25 @@ private:
|
|||
|
||||
};
|
||||
|
||||
class MainWindow::CustomNotificationHandle : public QObject {
|
||||
public:
|
||||
CustomNotificationHandle(QWidget *parent) : QObject(parent) {
|
||||
}
|
||||
|
||||
void activate() {
|
||||
auto widget = static_cast<QWidget*>(parent());
|
||||
NSWindow *wnd = [reinterpret_cast<NSView *>(widget->winId()) window];
|
||||
[wnd orderFront:wnd];
|
||||
}
|
||||
|
||||
~CustomNotificationHandle() {
|
||||
if (auto window = App::wnd()) {
|
||||
window->customNotificationDestroyed(this);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace Platform
|
||||
|
||||
@implementation MainWindowObserver {
|
||||
|
@ -98,11 +117,7 @@ MainWindow::Private *_private;
|
|||
}
|
||||
|
||||
- (void) activeSpaceDidChange:(NSNotification *)aNotification {
|
||||
if (auto manager = Window::Notifications::Default::GetManager()) {
|
||||
manager->enumerateNotifications([](QWidget *widget) {
|
||||
objc_activateWnd(widget->winId());
|
||||
});
|
||||
}
|
||||
_private->activateCustomNotifications();
|
||||
}
|
||||
|
||||
- (void) darkModeChanged:(NSNotification *)aNotification {
|
||||
|
@ -157,10 +172,6 @@ void MainWindow::Private::setWindowBadge(const QString &str) {
|
|||
}
|
||||
}
|
||||
|
||||
void MainWindow::Private::startBounce() {
|
||||
[NSApp requestUserAttention:NSInformationalRequest];
|
||||
}
|
||||
|
||||
void MainWindow::Private::initCustomTitle(NSWindow *window, NSView *view) {
|
||||
[window setStyleMask:[window styleMask] | NSFullSizeContentViewWindowMask];
|
||||
[window setTitlebarAppearsTransparent:YES];
|
||||
|
@ -191,6 +202,10 @@ void MainWindow::Private::willExitFullScreen() {
|
|||
_public->setTitleVisible(true);
|
||||
}
|
||||
|
||||
void MainWindow::Private::activateCustomNotifications() {
|
||||
_public->activateCustomNotifications();
|
||||
}
|
||||
|
||||
void MainWindow::Private::enableShadow(WId winId) {
|
||||
// [[(NSView*)winId window] setStyleMask:NSBorderlessWindowMask];
|
||||
// [[(NSView*)winId window] setHasShadow:YES];
|
||||
|
@ -299,18 +314,15 @@ void MainWindow::psSetupTrayIcon() {
|
|||
trayIcon->show();
|
||||
}
|
||||
|
||||
void MainWindow::psUpdateWorkmode() {
|
||||
void MainWindow::workmodeUpdated(DBIWorkMode mode) {
|
||||
psSetupTrayIcon();
|
||||
if (cWorkMode() == dbiwmWindowOnly) {
|
||||
if (mode == dbiwmWindowOnly) {
|
||||
if (trayIcon) {
|
||||
trayIcon->setContextMenu(0);
|
||||
delete trayIcon;
|
||||
trayIcon = nullptr;
|
||||
}
|
||||
}
|
||||
if (auto manager = Platform::Notifications::GetNativeManager()) {
|
||||
manager->updateDelegate();
|
||||
}
|
||||
}
|
||||
|
||||
void _placeCounter(QImage &img, int size, int count, style::color bg, style::color color) {
|
||||
|
@ -400,7 +412,7 @@ void MainWindow::psFirstShow() {
|
|||
|
||||
if ((cLaunchMode() == LaunchModeAutoStart && cStartMinimized()) || cStartInTray()) {
|
||||
setWindowState(Qt::WindowMinimized);
|
||||
if (cWorkMode() == dbiwmTrayOnly || cWorkMode() == dbiwmWindowAndTray) {
|
||||
if (Global::WorkMode().value() == dbiwmTrayOnly || Global::WorkMode().value() == dbiwmWindowAndTray) {
|
||||
hide();
|
||||
} else {
|
||||
show();
|
||||
|
@ -514,6 +526,20 @@ void MainWindow::psUpdateSysMenu(Qt::WindowState state) {
|
|||
void MainWindow::psUpdateMargins() {
|
||||
}
|
||||
|
||||
void MainWindow::customNotificationCreated(QWidget *notification) {
|
||||
_customNotifications.insert(object_ptr<CustomNotificationHandle>(notification));
|
||||
}
|
||||
|
||||
void MainWindow::customNotificationDestroyed(CustomNotificationHandle *handle) {
|
||||
_customNotifications.erase(handle);
|
||||
}
|
||||
|
||||
void MainWindow::activateCustomNotifications() {
|
||||
for (auto handle : _customNotifications) {
|
||||
handle->activate();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::updateGlobalMenuHook() {
|
||||
if (!App::wnd() || !positionInited()) return;
|
||||
|
||||
|
@ -552,10 +578,6 @@ void MainWindow::updateGlobalMenuHook() {
|
|||
_forceDisabled(psShowTelegram, App::wnd()->isActive());
|
||||
}
|
||||
|
||||
void MainWindow::psFlash() {
|
||||
return _private->startBounce();
|
||||
}
|
||||
|
||||
bool MainWindow::psFilterNativeEvent(void *event) {
|
||||
return _private->filterNativeEvent(event);
|
||||
}
|
||||
|
|
|
@ -25,9 +25,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
namespace Platform {
|
||||
namespace Notifications {
|
||||
|
||||
class Manager;
|
||||
Manager *GetNativeManager();
|
||||
|
||||
inline bool SkipAudio() {
|
||||
return false;
|
||||
}
|
||||
|
@ -38,10 +35,7 @@ inline bool SkipToast() {
|
|||
|
||||
class Manager : public Window::Notifications::NativeManager {
|
||||
public:
|
||||
Manager();
|
||||
|
||||
void updateDelegate();
|
||||
|
||||
Manager(Window::Notifications::System *system);
|
||||
~Manager();
|
||||
|
||||
protected:
|
||||
|
@ -50,14 +44,10 @@ protected:
|
|||
void doClearFromHistory(History *history) override;
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> _impl;
|
||||
class Private;
|
||||
const std::unique_ptr<Private> _private;
|
||||
|
||||
};
|
||||
|
||||
inline Window::Notifications::Manager *GetManager() {
|
||||
return GetNativeManager();
|
||||
}
|
||||
|
||||
} // namespace Notifications
|
||||
} // namespace Platform
|
||||
|
|
|
@ -23,6 +23,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
#include "platform/platform_specific.h"
|
||||
#include "platform/mac/mac_utilities.h"
|
||||
#include "styles/style_window.h"
|
||||
#include "mainwindow.h"
|
||||
#include "core/task_queue.h"
|
||||
|
||||
#include <Cocoa/Cocoa.h>
|
||||
|
||||
|
@ -93,22 +95,19 @@ NSImage *qt_mac_create_nsimage(const QPixmap &pm);
|
|||
namespace Platform {
|
||||
namespace Notifications {
|
||||
|
||||
void Start() {
|
||||
if (cPlatform() != dbipMacOld) {
|
||||
ManagerInstance.createIfNull();
|
||||
}
|
||||
}
|
||||
|
||||
Manager *GetNativeManager() {
|
||||
return ManagerInstance.data();
|
||||
}
|
||||
|
||||
bool Supported() {
|
||||
return ManagerInstance.data() != nullptr;
|
||||
return (cPlatform() != dbipMacOld);
|
||||
}
|
||||
|
||||
void Finish() {
|
||||
ManagerInstance.clear();
|
||||
std::unique_ptr<Window::Notifications::Manager> Create(Window::Notifications::System *system) {
|
||||
if (Supported()) {
|
||||
return std::make_unique<Manager>(system);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void FlashBounce() {
|
||||
[NSApp requestUserAttention:NSInformationalRequest];
|
||||
}
|
||||
|
||||
void CustomNotificationShownHook(QWidget *widget) {
|
||||
|
@ -116,27 +115,38 @@ void CustomNotificationShownHook(QWidget *widget) {
|
|||
objc_holdOnTop(widget->winId());
|
||||
widget->show();
|
||||
psShowOverAll(widget, false);
|
||||
if (auto window = App::wnd()) {
|
||||
window->customNotificationCreated(widget);
|
||||
}
|
||||
}
|
||||
|
||||
class Manager::Impl {
|
||||
class Manager::Private : public QObject, private base::Subscriber {
|
||||
public:
|
||||
Impl();
|
||||
Private();
|
||||
void showNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, const QString &msg, bool hideNameAndPhoto, bool hideReplyButton);
|
||||
void clearAll();
|
||||
void clearFromHistory(History *history);
|
||||
void updateDelegate();
|
||||
|
||||
~Impl();
|
||||
~Private();
|
||||
|
||||
private:
|
||||
NotificationDelegate *_delegate;
|
||||
|
||||
};
|
||||
|
||||
Manager::Impl::Impl() : _delegate([[NotificationDelegate alloc] init]) {
|
||||
Manager::Private::Private() : _delegate([[NotificationDelegate alloc] init]) {
|
||||
updateDelegate();
|
||||
subscribe(Global::RefWorkMode(), [this](DBIWorkMode mode) {
|
||||
// We need to update the delegate _after_ the tray icon change was done in Qt.
|
||||
// Because Qt resets the delegate.
|
||||
base::TaskQueue::Main().Put(base::lambda_guarded(this, [this] {
|
||||
updateDelegate();
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
void Manager::Impl::showNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, const QString &msg, bool hideNameAndPhoto, bool hideReplyButton) {
|
||||
void Manager::Private::showNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, const QString &msg, bool hideNameAndPhoto, bool hideReplyButton) {
|
||||
@autoreleasepool {
|
||||
|
||||
NSUserNotification *notification = [[[NSUserNotification alloc] init] autorelease];
|
||||
|
@ -168,7 +178,7 @@ void Manager::Impl::showNotification(PeerData *peer, MsgId msgId, const QString
|
|||
}
|
||||
}
|
||||
|
||||
void Manager::Impl::clearAll() {
|
||||
void Manager::Private::clearAll() {
|
||||
NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter];
|
||||
NSArray *notificationsList = [center deliveredNotifications];
|
||||
for (id notification in notificationsList) {
|
||||
|
@ -182,7 +192,7 @@ void Manager::Impl::clearAll() {
|
|||
[center removeAllDeliveredNotifications];
|
||||
}
|
||||
|
||||
void Manager::Impl::clearFromHistory(History *history) {
|
||||
void Manager::Private::clearFromHistory(History *history) {
|
||||
unsigned long long peerId = history->peer->id;
|
||||
|
||||
NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter];
|
||||
|
@ -199,34 +209,32 @@ void Manager::Impl::clearFromHistory(History *history) {
|
|||
}
|
||||
}
|
||||
|
||||
void Manager::Impl::updateDelegate() {
|
||||
void Manager::Private::updateDelegate() {
|
||||
NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter];
|
||||
[center setDelegate:_delegate];
|
||||
}
|
||||
|
||||
Manager::Impl::~Impl() {
|
||||
Manager::Private::~Private() {
|
||||
clearAll();
|
||||
[_delegate release];
|
||||
}
|
||||
|
||||
Manager::Manager() : _impl(std::make_unique<Impl>()) {
|
||||
}
|
||||
|
||||
void Manager::updateDelegate() {
|
||||
_impl->updateDelegate();
|
||||
Manager::Manager(Window::Notifications::System *system) : NativeManager(system)
|
||||
, _private(std::make_unique<Private>()) {
|
||||
}
|
||||
|
||||
Manager::~Manager() = default;
|
||||
|
||||
void Manager::doShowNativeNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, const QString &msg, bool hideNameAndPhoto, bool hideReplyButton) {
|
||||
_impl->showNotification(peer, msgId, title, subtitle, msg, hideNameAndPhoto, hideReplyButton);
|
||||
_private->showNotification(peer, msgId, title, subtitle, msg, hideNameAndPhoto, hideReplyButton);
|
||||
}
|
||||
|
||||
void Manager::doClearAllFast() {
|
||||
_impl->clearAll();
|
||||
_private->clearAll();
|
||||
}
|
||||
|
||||
void Manager::doClearFromHistory(History *history) {
|
||||
_impl->clearFromHistory(history);
|
||||
_private->clearFromHistory(history);
|
||||
}
|
||||
|
||||
} // namespace Notifications
|
||||
|
|
|
@ -24,7 +24,6 @@ void objc_holdOnTop(WId winId);
|
|||
bool objc_darkMode();
|
||||
void objc_showOverAll(WId winId, bool canFocus = true);
|
||||
void objc_bringToBack(WId winId);
|
||||
void objc_activateWnd(WId winId);
|
||||
|
||||
void objc_debugShowAlert(const QString &str);
|
||||
void objc_outputDebugString(const QString &str);
|
||||
|
|
|
@ -208,11 +208,6 @@ void objc_bringToBack(WId winId) {
|
|||
[wnd setLevel:NSModalPanelWindowLevel];
|
||||
}
|
||||
|
||||
void objc_activateWnd(WId winId) {
|
||||
NSWindow *wnd = [reinterpret_cast<NSView *>(winId) window];
|
||||
[wnd orderFront:wnd];
|
||||
}
|
||||
|
||||
bool objc_handleMediaKeyEvent(void *ev) {
|
||||
auto e = reinterpret_cast<NSEvent*>(ev);
|
||||
|
||||
|
|
|
@ -29,10 +29,9 @@ void CustomNotificationShownHook(QWidget *widget);
|
|||
bool SkipAudio();
|
||||
bool SkipToast();
|
||||
|
||||
void Start();
|
||||
Window::Notifications::Manager *GetManager();
|
||||
bool Supported();
|
||||
void Finish();
|
||||
std::unique_ptr<Window::Notifications::Manager> Create(Window::Notifications::System *system);
|
||||
void FlashBounce();
|
||||
|
||||
} // namespace Notifications
|
||||
} // namespace Platform
|
||||
|
|
|
@ -703,8 +703,8 @@ void MainWindow::showTrayTooltip() {
|
|||
}
|
||||
}
|
||||
|
||||
void MainWindow::psUpdateWorkmode() {
|
||||
switch (cWorkMode()) {
|
||||
void MainWindow::workmodeUpdated(DBIWorkMode mode) {
|
||||
switch (mode) {
|
||||
case dbiwmWindowAndTray: {
|
||||
psSetupTrayIcon();
|
||||
HWND psOwner = (HWND)GetWindowLong(ps_hWnd, GWL_HWNDPARENT);
|
||||
|
@ -800,10 +800,6 @@ void MainWindow::initHook() {
|
|||
setWindowIcon(wndIcon);
|
||||
}
|
||||
|
||||
bool MainWindow::psHasNativeNotifications() {
|
||||
return Notifications::Supported();
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(QMargins);
|
||||
void MainWindow::psFirstShow() {
|
||||
_psShadowWindows.init(st::windowShadowFg->c);
|
||||
|
@ -821,7 +817,7 @@ void MainWindow::psFirstShow() {
|
|||
|
||||
if ((cLaunchMode() == LaunchModeAutoStart && cStartMinimized() && !App::passcoded()) || cStartInTray()) {
|
||||
setWindowState(Qt::WindowMinimized);
|
||||
if (cWorkMode() == dbiwmTrayOnly || cWorkMode() == dbiwmWindowAndTray) {
|
||||
if (Global::WorkMode().value() == dbiwmTrayOnly || Global::WorkMode().value() == dbiwmWindowAndTray) {
|
||||
hide();
|
||||
} else {
|
||||
show();
|
||||
|
@ -934,18 +930,6 @@ void MainWindow::psUpdateMargins() {
|
|||
}
|
||||
}
|
||||
|
||||
void MainWindow::psFlash() {
|
||||
if (GetForegroundWindow() == ps_hWnd) return;
|
||||
|
||||
FLASHWINFO info;
|
||||
info.cbSize = sizeof(info);
|
||||
info.hwnd = ps_hWnd;
|
||||
info.dwFlags = FLASHW_ALL;
|
||||
info.dwTimeout = 0;
|
||||
info.uCount = 1;
|
||||
FlashWindowEx(&info);
|
||||
}
|
||||
|
||||
HWND MainWindow::psHwnd() const {
|
||||
return ps_hWnd;
|
||||
}
|
||||
|
|
|
@ -43,15 +43,8 @@ public:
|
|||
void psUpdateSysMenu(Qt::WindowState state);
|
||||
void psUpdateMargins();
|
||||
|
||||
void psFlash();
|
||||
void psNotifySettingGot();
|
||||
|
||||
void psUpdateWorkmode();
|
||||
|
||||
void psRefreshTaskbarIcon();
|
||||
|
||||
bool psHasNativeNotifications();
|
||||
|
||||
virtual QImage iconWithCounter(int size, int count, style::color bg, style::color fg, bool smallIcon) = 0;
|
||||
|
||||
static UINT TaskbarCreatedMsgId() {
|
||||
|
@ -108,6 +101,8 @@ protected:
|
|||
|
||||
void showTrayTooltip() override;
|
||||
|
||||
void workmodeUpdated(DBIWorkMode mode) override;
|
||||
|
||||
QTimer psUpdatedPositionTimer;
|
||||
|
||||
private:
|
||||
|
|
|
@ -25,6 +25,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
#include "platform/win/windows_event_filter.h"
|
||||
#include "platform/win/windows_dlls.h"
|
||||
#include "mainwindow.h"
|
||||
#include "core/task_queue.h"
|
||||
|
||||
#include <Shobjidl.h>
|
||||
#include <shellapi.h>
|
||||
|
@ -48,22 +49,6 @@ namespace Platform {
|
|||
namespace Notifications {
|
||||
namespace {
|
||||
|
||||
NeverFreedPointer<Manager> ManagerInstance;
|
||||
|
||||
ComPtr<IToastNotificationManagerStatics> _notificationManager;
|
||||
ComPtr<IToastNotifier> _notifier;
|
||||
ComPtr<IToastNotificationFactory> _notificationFactory;
|
||||
|
||||
struct NotificationPtr {
|
||||
NotificationPtr() {
|
||||
}
|
||||
NotificationPtr(const ComPtr<IToastNotification> &ptr) : p(ptr) {
|
||||
}
|
||||
ComPtr<IToastNotification> p;
|
||||
};
|
||||
using Notifications = QMap<PeerId, QMap<MsgId, NotificationPtr>>;
|
||||
Notifications _notifications;
|
||||
|
||||
class StringReferenceWrapper {
|
||||
public:
|
||||
StringReferenceWrapper(_In_reads_(length) PCWSTR stringRef, _In_ UINT32 length) throw() {
|
||||
|
@ -137,15 +122,6 @@ bool init() {
|
|||
if (!SUCCEEDED(Dlls::SetCurrentProcessExplicitAppUserModelID(appUserModelId))) {
|
||||
return false;
|
||||
}
|
||||
if (!SUCCEEDED(wrap_GetActivationFactory(StringReferenceWrapper(RuntimeClass_Windows_UI_Notifications_ToastNotificationManager).Get(), &_notificationManager))) {
|
||||
return false;
|
||||
}
|
||||
if (!SUCCEEDED(_notificationManager->CreateToastNotifierWithId(StringReferenceWrapper(appUserModelId, wcslen(appUserModelId)).Get(), &_notifier))) {
|
||||
return false;
|
||||
}
|
||||
if (!SUCCEEDED(wrap_GetActivationFactory(StringReferenceWrapper(RuntimeClass_Windows_UI_Notifications_ToastNotification).Get(), &_notificationFactory))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -235,16 +211,27 @@ typedef ABI::Windows::Foundation::ITypedEventHandler<ToastNotification*, ToastFa
|
|||
|
||||
class ToastEventHandler : public Implements<DesktopToastActivatedEventHandler, DesktopToastDismissedEventHandler, DesktopToastFailedEventHandler> {
|
||||
public:
|
||||
ToastEventHandler::ToastEventHandler(const PeerId &peer, MsgId msg) : _ref(1), _peerId(peer), _msgId(msg) {
|
||||
// We keep a weak pointer to a member field of native notifications manager.
|
||||
ToastEventHandler::ToastEventHandler(const std::shared_ptr<Manager*> &guarded, const PeerId &peer, MsgId msg)
|
||||
: _peerId(peer)
|
||||
, _msgId(msg)
|
||||
, _weak(guarded) {
|
||||
}
|
||||
~ToastEventHandler() {
|
||||
~ToastEventHandler() = default;
|
||||
|
||||
void performOnMainQueue(base::lambda_once<void(Manager *manager)> task) {
|
||||
base::TaskQueue::Main().Put([weak = _weak, task = std::move(task)]() mutable {
|
||||
if (auto strong = weak.lock()) {
|
||||
task(*strong);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// DesktopToastActivatedEventHandler
|
||||
IFACEMETHODIMP Invoke(_In_ IToastNotification *sender, _In_ IInspectable* args) {
|
||||
if (auto manager = ManagerInstance.data()) {
|
||||
manager->notificationActivated(_peerId, _msgId);
|
||||
}
|
||||
performOnMainQueue([peerId = _peerId, msgId = _msgId](Manager *manager) {
|
||||
manager->notificationActivated(peerId, msgId);
|
||||
});
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
@ -258,9 +245,9 @@ public:
|
|||
case ToastDismissalReason_UserCanceled:
|
||||
case ToastDismissalReason_TimedOut:
|
||||
default:
|
||||
if (auto manager = ManagerInstance.data()) {
|
||||
manager->clearNotification(_peerId, _msgId);
|
||||
}
|
||||
performOnMainQueue([peerId = _peerId, msgId = _msgId](Manager *manager) {
|
||||
manager->clearNotification(peerId, msgId);
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -269,21 +256,23 @@ public:
|
|||
|
||||
// DesktopToastFailedEventHandler
|
||||
IFACEMETHODIMP Invoke(_In_ IToastNotification *sender, _In_ IToastFailedEventArgs *e) {
|
||||
if (auto manager = ManagerInstance.data()) {
|
||||
manager->clearNotification(_peerId, _msgId);
|
||||
}
|
||||
performOnMainQueue([peerId = _peerId, msgId = _msgId](Manager *manager) {
|
||||
manager->clearNotification(peerId, msgId);
|
||||
});
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// IUnknown
|
||||
IFACEMETHODIMP_(ULONG) AddRef() {
|
||||
return InterlockedIncrement(&_ref);
|
||||
return InterlockedIncrement(&_refCount);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(ULONG) Release() {
|
||||
ULONG l = InterlockedDecrement(&_ref);
|
||||
if (l == 0) delete this;
|
||||
return l;
|
||||
auto refCount = InterlockedDecrement(&_refCount);
|
||||
if (refCount == 0) {
|
||||
delete this;
|
||||
}
|
||||
return refCount;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP QueryInterface(_In_ REFIID riid, _COM_Outptr_ void **ppv) {
|
||||
|
@ -306,41 +295,61 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
ULONG _ref;
|
||||
PeerId _peerId;
|
||||
MsgId _msgId;
|
||||
ULONG _refCount = 0;
|
||||
PeerId _peerId = 0;
|
||||
MsgId _msgId = 0;
|
||||
std::weak_ptr<Manager*> _weak;
|
||||
|
||||
};
|
||||
|
||||
} // namespace
|
||||
auto Checked = false;
|
||||
auto InitSucceeded = false;
|
||||
|
||||
void Start() {
|
||||
if (init()) {
|
||||
ManagerInstance.createIfNull();
|
||||
}
|
||||
void Check() {
|
||||
InitSucceeded = init();
|
||||
}
|
||||
|
||||
Window::Notifications::Manager *GetManager() {
|
||||
if (Global::started() && Global::NativeNotifications()) {
|
||||
return ManagerInstance.data();
|
||||
} // namespace
|
||||
|
||||
bool Supported() {
|
||||
if (!Checked) {
|
||||
Checked = true;
|
||||
Check();
|
||||
}
|
||||
return InitSucceeded;
|
||||
}
|
||||
|
||||
std::unique_ptr<Window::Notifications::Manager> Create(Window::Notifications::System *system) {
|
||||
if (Global::NativeNotifications() && Supported()) {
|
||||
auto result = std::make_unique<Manager>(system);
|
||||
if (result->init()) {
|
||||
return std::move(result);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool Supported() {
|
||||
return ManagerInstance.data() != nullptr;
|
||||
void FlashBounce() {
|
||||
auto window = App::wnd();
|
||||
if (!window || GetForegroundWindow() == window->psHwnd()) {
|
||||
return;
|
||||
}
|
||||
|
||||
FLASHWINFO info;
|
||||
info.cbSize = sizeof(info);
|
||||
info.hwnd = window->psHwnd();
|
||||
info.dwFlags = FLASHW_ALL;
|
||||
info.dwTimeout = 0;
|
||||
info.uCount = 1;
|
||||
FlashWindowEx(&info);
|
||||
}
|
||||
|
||||
void Finish() {
|
||||
ManagerInstance.clear();
|
||||
}
|
||||
|
||||
class Manager::Impl {
|
||||
class Manager::Private {
|
||||
public:
|
||||
using Type = Window::Notifications::CachedUserpics::Type;
|
||||
|
||||
Impl(Type type) : _cachedUserpics(type) {
|
||||
}
|
||||
explicit Private(Manager *instance, Type type);
|
||||
bool init();
|
||||
|
||||
bool showNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, const QString &msg, bool hideNameAndPhoto, bool hideReplyButton);
|
||||
void clearAll();
|
||||
|
@ -349,21 +358,60 @@ public:
|
|||
void afterNotificationActivated(PeerId peerId, MsgId msgId);
|
||||
void clearNotification(PeerId peerId, MsgId msgId);
|
||||
|
||||
~Impl();
|
||||
~Private();
|
||||
|
||||
private:
|
||||
Window::Notifications::CachedUserpics _cachedUserpics;
|
||||
|
||||
std::shared_ptr<Manager*> _guarded;
|
||||
|
||||
ComPtr<IToastNotificationManagerStatics> _notificationManager;
|
||||
ComPtr<IToastNotifier> _notifier;
|
||||
ComPtr<IToastNotificationFactory> _notificationFactory;
|
||||
|
||||
struct NotificationPtr {
|
||||
NotificationPtr() {
|
||||
}
|
||||
NotificationPtr(const ComPtr<IToastNotification> &ptr) : p(ptr) {
|
||||
}
|
||||
|
||||
ComPtr<IToastNotification> p;
|
||||
};
|
||||
QMap<PeerId, QMap<MsgId, NotificationPtr>> _notifications;
|
||||
|
||||
};
|
||||
|
||||
Manager::Impl::~Impl() {
|
||||
Manager::Private::Private(Manager *instance, Type type)
|
||||
: _guarded(std::make_shared<Manager*>(instance))
|
||||
, _cachedUserpics(type) {
|
||||
}
|
||||
|
||||
bool Manager::Private::init() {
|
||||
if (!SUCCEEDED(wrap_GetActivationFactory(StringReferenceWrapper(RuntimeClass_Windows_UI_Notifications_ToastNotificationManager).Get(), &_notificationManager))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto appUserModelId = AppUserModelId::getId();
|
||||
if (!SUCCEEDED(_notificationManager->CreateToastNotifierWithId(StringReferenceWrapper(appUserModelId, wcslen(appUserModelId)).Get(), &_notifier))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SUCCEEDED(wrap_GetActivationFactory(StringReferenceWrapper(RuntimeClass_Windows_UI_Notifications_ToastNotification).Get(), &_notificationFactory))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Manager::Private::~Private() {
|
||||
clearAll();
|
||||
|
||||
_notifications.clear();
|
||||
if (_notificationManager) _notificationManager.Reset();
|
||||
if (_notifier) _notifier.Reset();
|
||||
if (_notificationFactory) _notificationFactory.Reset();
|
||||
}
|
||||
|
||||
void Manager::Impl::clearAll() {
|
||||
void Manager::Private::clearAll() {
|
||||
if (!_notifier) return;
|
||||
|
||||
auto temp = base::take(_notifications);
|
||||
|
@ -374,7 +422,7 @@ void Manager::Impl::clearAll() {
|
|||
}
|
||||
}
|
||||
|
||||
void Manager::Impl::clearFromHistory(History *history) {
|
||||
void Manager::Private::clearFromHistory(History *history) {
|
||||
if (!_notifier) return;
|
||||
|
||||
auto i = _notifications.find(history->peer->id);
|
||||
|
@ -388,17 +436,17 @@ void Manager::Impl::clearFromHistory(History *history) {
|
|||
}
|
||||
}
|
||||
|
||||
void Manager::Impl::beforeNotificationActivated(PeerId peerId, MsgId msgId) {
|
||||
void Manager::Private::beforeNotificationActivated(PeerId peerId, MsgId msgId) {
|
||||
clearNotification(peerId, msgId);
|
||||
}
|
||||
|
||||
void Manager::Impl::afterNotificationActivated(PeerId peerId, MsgId msgId) {
|
||||
void Manager::Private::afterNotificationActivated(PeerId peerId, MsgId msgId) {
|
||||
if (auto window = App::wnd()) {
|
||||
SetForegroundWindow(window->psHwnd());
|
||||
}
|
||||
}
|
||||
|
||||
void Manager::Impl::clearNotification(PeerId peerId, MsgId msgId) {
|
||||
void Manager::Private::clearNotification(PeerId peerId, MsgId msgId) {
|
||||
auto i = _notifications.find(peerId);
|
||||
if (i != _notifications.cend()) {
|
||||
i.value().remove(msgId);
|
||||
|
@ -408,7 +456,7 @@ void Manager::Impl::clearNotification(PeerId peerId, MsgId msgId) {
|
|||
}
|
||||
}
|
||||
|
||||
bool Manager::Impl::showNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, const QString &msg, bool hideNameAndPhoto, bool hideReplyButton) {
|
||||
bool Manager::Private::showNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, const QString &msg, bool hideNameAndPhoto, bool hideReplyButton) {
|
||||
if (!_notificationManager || !_notifier || !_notificationFactory) return false;
|
||||
|
||||
ComPtr<IXmlDocument> toastXml;
|
||||
|
@ -475,7 +523,7 @@ bool Manager::Impl::showNotification(PeerData *peer, MsgId msgId, const QString
|
|||
if (!SUCCEEDED(hr)) return false;
|
||||
|
||||
EventRegistrationToken activatedToken, dismissedToken, failedToken;
|
||||
ComPtr<ToastEventHandler> eventHandler(new ToastEventHandler(peer->id, msgId));
|
||||
ComPtr<ToastEventHandler> eventHandler(new ToastEventHandler(_guarded, peer->id, msgId));
|
||||
|
||||
hr = toast->add_Activated(eventHandler.Get(), &activatedToken);
|
||||
if (!SUCCEEDED(hr)) return false;
|
||||
|
@ -510,33 +558,38 @@ bool Manager::Impl::showNotification(PeerData *peer, MsgId msgId, const QString
|
|||
return true;
|
||||
}
|
||||
|
||||
Manager::Manager() : _impl(std::make_unique<Impl>(Impl::Type::Rounded)) {
|
||||
Manager::Manager(Window::Notifications::System *system) : NativeManager(system)
|
||||
, _private(std::make_unique<Private>(this, Private::Type::Rounded)) {
|
||||
}
|
||||
|
||||
bool Manager::init() {
|
||||
return _private->init();
|
||||
}
|
||||
|
||||
void Manager::clearNotification(PeerId peerId, MsgId msgId) {
|
||||
_impl->clearNotification(peerId, msgId);
|
||||
_private->clearNotification(peerId, msgId);
|
||||
}
|
||||
|
||||
Manager::~Manager() = default;
|
||||
|
||||
void Manager::doShowNativeNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, const QString &msg, bool hideNameAndPhoto, bool hideReplyButton) {
|
||||
_impl->showNotification(peer, msgId, title, subtitle, msg, hideNameAndPhoto, hideReplyButton);
|
||||
_private->showNotification(peer, msgId, title, subtitle, msg, hideNameAndPhoto, hideReplyButton);
|
||||
}
|
||||
|
||||
void Manager::doClearAllFast() {
|
||||
_impl->clearAll();
|
||||
_private->clearAll();
|
||||
}
|
||||
|
||||
void Manager::doClearFromHistory(History *history) {
|
||||
_impl->clearFromHistory(history);
|
||||
_private->clearFromHistory(history);
|
||||
}
|
||||
|
||||
void Manager::onBeforeNotificationActivated(PeerId peerId, MsgId msgId) {
|
||||
_impl->beforeNotificationActivated(peerId, msgId);
|
||||
_private->beforeNotificationActivated(peerId, msgId);
|
||||
}
|
||||
|
||||
void Manager::onAfterNotificationActivated(PeerId peerId, MsgId msgId) {
|
||||
_impl->afterNotificationActivated(peerId, msgId);
|
||||
_private->afterNotificationActivated(peerId, msgId);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
|
|
@ -30,7 +30,9 @@ inline void CustomNotificationShownHook(QWidget *widget) {
|
|||
|
||||
class Manager : public Window::Notifications::NativeManager {
|
||||
public:
|
||||
Manager();
|
||||
Manager(Window::Notifications::System *system);
|
||||
|
||||
bool init();
|
||||
|
||||
void clearNotification(PeerId peerId, MsgId msgId);
|
||||
|
||||
|
@ -44,8 +46,8 @@ protected:
|
|||
void onAfterNotificationActivated(PeerId peerId, MsgId msgId) override;
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> _impl;
|
||||
class Private;
|
||||
const std::unique_ptr<Private> _private;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
#include "ui/widgets/popup_menu.h"
|
||||
#include "styles/style_profile.h"
|
||||
#include "styles/style_widgets.h"
|
||||
#include "auth_session.h"
|
||||
|
||||
namespace Profile {
|
||||
|
||||
|
@ -38,7 +39,7 @@ PeerListWidget::PeerListWidget(QWidget *parent, PeerData *peer, const QString &t
|
|||
, _removeText(removeText)
|
||||
, _removeWidth(st::normalFont->width(_removeText)) {
|
||||
setMouseTracking(true);
|
||||
subscribe(FileDownload::ImageLoaded(), [this] { update(); });
|
||||
subscribe(AuthSession::CurrentDownloaderTaskFinished(), [this] { update(); });
|
||||
}
|
||||
|
||||
int PeerListWidget::resizeGetHeight(int newWidth) {
|
||||
|
|
|
@ -22,7 +22,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
|
||||
#include "styles/style_profile.h"
|
||||
#include "observer_peer.h"
|
||||
#include "storage/file_download.h"
|
||||
#include "auth_session.h"
|
||||
|
||||
namespace Profile {
|
||||
|
||||
|
@ -41,7 +41,7 @@ UserpicButton::UserpicButton(QWidget *parent, PeerData *peer, int size) : Abstra
|
|||
subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) {
|
||||
notifyPeerUpdated(update);
|
||||
}));
|
||||
subscribe(FileDownload::ImageLoaded(), [this] {
|
||||
subscribe(AuthSession::CurrentDownloaderTaskFinished(), [this] {
|
||||
if (_waiting && _peer->userpicLoaded()) {
|
||||
_waiting = false;
|
||||
startNewPhotoShowing();
|
||||
|
|
|
@ -55,7 +55,6 @@ bool gAutoUpdate = true;
|
|||
TWindowPos gWindowPos;
|
||||
LaunchMode gLaunchMode = LaunchModeNormal;
|
||||
bool gSupportTray = true;
|
||||
DBIWorkMode gWorkMode = dbiwmWindowAndTray;
|
||||
bool gSeenTrayTooltip = false;
|
||||
bool gRestartingUpdate = false, gRestarting = false, gRestartingToSettings = false, gWriteProtected = false;
|
||||
int32 gLastUpdateCheck = 0;
|
||||
|
|
|
@ -101,7 +101,6 @@ struct TWindowPos {
|
|||
};
|
||||
DeclareSetting(TWindowPos, WindowPos);
|
||||
DeclareSetting(bool, SupportTray);
|
||||
DeclareSetting(DBIWorkMode, WorkMode);
|
||||
DeclareSetting(bool, SeenTrayTooltip);
|
||||
DeclareSetting(bool, RestartingUpdate);
|
||||
DeclareSetting(bool, Restarting);
|
||||
|
|
|
@ -184,9 +184,10 @@ void GeneralWidget::refreshControls() {
|
|||
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
|
||||
|
||||
if (cPlatform() == dbipWindows || cSupportTray()) {
|
||||
addChildRow(_enableTrayIcon, marginSmall, lang(lng_settings_workmode_tray), SLOT(onEnableTrayIcon()), (cWorkMode() == dbiwmTrayOnly || cWorkMode() == dbiwmWindowAndTray));
|
||||
auto workMode = Global::WorkMode().value();
|
||||
addChildRow(_enableTrayIcon, marginSmall, lang(lng_settings_workmode_tray), SLOT(onEnableTrayIcon()), (workMode == dbiwmTrayOnly || workMode == dbiwmWindowAndTray));
|
||||
if (cPlatform() == dbipWindows) {
|
||||
addChildRow(_enableTaskbarIcon, marginLarge, lang(lng_settings_workmode_window), SLOT(onEnableTaskbarIcon()), (cWorkMode() == dbiwmWindowOnly || cWorkMode() == dbiwmWindowAndTray));
|
||||
addChildRow(_enableTaskbarIcon, marginLarge, lang(lng_settings_workmode_window), SLOT(onEnableTaskbarIcon()), (workMode == dbiwmWindowOnly || workMode == dbiwmWindowAndTray));
|
||||
|
||||
#ifndef OS_WIN_STORE
|
||||
addChildRow(_autoStart, marginSmall, lang(lng_settings_auto_start), SLOT(onAutoStart()), cAutoStart());
|
||||
|
@ -276,12 +277,11 @@ void GeneralWidget::onEnableTaskbarIcon() {
|
|||
}
|
||||
|
||||
void GeneralWidget::updateWorkmode() {
|
||||
DBIWorkMode newMode = (_enableTrayIcon->checked() && (!_enableTaskbarIcon || _enableTaskbarIcon->checked())) ? dbiwmWindowAndTray : (_enableTrayIcon->checked() ? dbiwmTrayOnly : dbiwmWindowOnly);
|
||||
if (cWorkMode() != newMode && (newMode == dbiwmWindowAndTray || newMode == dbiwmTrayOnly)) {
|
||||
auto newMode = (_enableTrayIcon->checked() && (!_enableTaskbarIcon || _enableTaskbarIcon->checked())) ? dbiwmWindowAndTray : (_enableTrayIcon->checked() ? dbiwmTrayOnly : dbiwmWindowOnly);
|
||||
if (Global::WorkMode().value() != newMode && (newMode == dbiwmWindowAndTray || newMode == dbiwmTrayOnly)) {
|
||||
cSetSeenTrayTooltip(false);
|
||||
}
|
||||
cSetWorkMode(newMode);
|
||||
App::wnd()->psUpdateWorkmode();
|
||||
Global::RefWorkMode().set(newMode);
|
||||
Local::writeSettings();
|
||||
}
|
||||
|
||||
|
|
|
@ -30,18 +30,24 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
#include "window/notifications_manager.h"
|
||||
#include "boxes/notifications_box.h"
|
||||
#include "platform/platform_notifications_manager.h"
|
||||
#include "auth_session.h"
|
||||
|
||||
namespace Settings {
|
||||
namespace {
|
||||
|
||||
using ChangeType = Window::Notifications::ChangeType;
|
||||
|
||||
} // namespace
|
||||
|
||||
NotificationsWidget::NotificationsWidget(QWidget *parent, UserData *self) : BlockWidget(parent, self, lang(lng_settings_section_notify)) {
|
||||
createControls();
|
||||
|
||||
subscribe(Global::RefNotifySettingsChanged(), [this](Notify::ChangeType type) {
|
||||
if (type == Notify::ChangeType::DesktopEnabled) {
|
||||
subscribe(AuthSession::Current().notifications()->settingsChanged(), [this](ChangeType type) {
|
||||
if (type == ChangeType::DesktopEnabled) {
|
||||
desktopEnabledUpdated();
|
||||
} else if (type == Notify::ChangeType::ViewParams) {
|
||||
} else if (type == ChangeType::ViewParams) {
|
||||
viewParamUpdated();
|
||||
} else if (type == Notify::ChangeType::SoundEnabled) {
|
||||
} else if (type == ChangeType::SoundEnabled) {
|
||||
_playSound->setChecked(Global::SoundNotify());
|
||||
}
|
||||
});
|
||||
|
@ -95,7 +101,7 @@ void NotificationsWidget::onDesktopNotifications() {
|
|||
}
|
||||
Global::SetDesktopNotify(_desktopNotifications->checked());
|
||||
Local::writeUserSettings();
|
||||
Global::RefNotifySettingsChanged().notify(Notify::ChangeType::DesktopEnabled);
|
||||
AuthSession::Current().notifications()->settingsChanged().notify(ChangeType::DesktopEnabled);
|
||||
}
|
||||
|
||||
void NotificationsWidget::desktopEnabledUpdated() {
|
||||
|
@ -125,7 +131,7 @@ void NotificationsWidget::onShowSenderName() {
|
|||
}
|
||||
Global::SetNotifyView(viewParam);
|
||||
Local::writeUserSettings();
|
||||
Global::RefNotifySettingsChanged().notify(Notify::ChangeType::ViewParams);
|
||||
AuthSession::Current().notifications()->settingsChanged().notify(ChangeType::ViewParams);
|
||||
}
|
||||
|
||||
void NotificationsWidget::onShowMessagePreview() {
|
||||
|
@ -143,7 +149,7 @@ void NotificationsWidget::onShowMessagePreview() {
|
|||
|
||||
Global::SetNotifyView(viewParam);
|
||||
Local::writeUserSettings();
|
||||
Global::RefNotifySettingsChanged().notify(Notify::ChangeType::ViewParams);
|
||||
AuthSession::Current().notifications()->settingsChanged().notify(ChangeType::ViewParams);
|
||||
}
|
||||
|
||||
void NotificationsWidget::viewParamUpdated() {
|
||||
|
@ -159,10 +165,11 @@ void NotificationsWidget::onNativeNotifications() {
|
|||
return;
|
||||
}
|
||||
|
||||
Window::Notifications::GetManager()->clearAllFast();
|
||||
Global::SetNativeNotifications(_nativeNotifications->checked());
|
||||
Local::writeUserSettings();
|
||||
|
||||
AuthSession::Current().notifications()->createManager();
|
||||
|
||||
if (Global::NativeNotifications()) {
|
||||
_advanced->slideUp();
|
||||
} else {
|
||||
|
@ -181,13 +188,13 @@ void NotificationsWidget::onPlaySound() {
|
|||
|
||||
Global::SetSoundNotify(_playSound->checked());
|
||||
Local::writeUserSettings();
|
||||
Global::RefNotifySettingsChanged().notify(Notify::ChangeType::SoundEnabled);
|
||||
AuthSession::Current().notifications()->settingsChanged().notify(ChangeType::SoundEnabled);
|
||||
}
|
||||
|
||||
void NotificationsWidget::onIncludeMuted() {
|
||||
Global::SetIncludeMuted(_includeMuted->checked());
|
||||
Local::writeUserSettings();
|
||||
Global::RefNotifySettingsChanged().notify(Notify::ChangeType::IncludeMuted);
|
||||
AuthSession::Current().notifications()->settingsChanged().notify(ChangeType::IncludeMuted);
|
||||
}
|
||||
|
||||
} // namespace Settings
|
||||
|
|
|
@ -46,7 +46,7 @@ bool lock_telegram() {
|
|||
|
||||
bool minimize_telegram() {
|
||||
if (auto w = App::wnd()) {
|
||||
if (cWorkMode() == dbiwmTrayOnly) {
|
||||
if (Global::WorkMode().value() == dbiwmTrayOnly) {
|
||||
w->minimizeToTray();
|
||||
} else {
|
||||
w->setWindowState(Qt::WindowMinimized);
|
||||
|
|
|
@ -37,6 +37,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
#include "mainwindow.h"
|
||||
#include "apiwrap.h"
|
||||
#include "mainwidget.h"
|
||||
#include "auth_session.h"
|
||||
|
||||
namespace internal {
|
||||
namespace {
|
||||
|
@ -719,7 +720,7 @@ StickerPanInner::StickerPanInner(QWidget *parent) : TWidget(parent)
|
|||
_updateInlineItems.setSingleShot(true);
|
||||
connect(&_updateInlineItems, SIGNAL(timeout()), this, SLOT(onUpdateInlineItems()));
|
||||
|
||||
subscribe(FileDownload::ImageLoaded(), [this] {
|
||||
subscribe(AuthSession::CurrentDownloaderTaskFinished(), [this] {
|
||||
update();
|
||||
readVisibleSets();
|
||||
});
|
||||
|
|
|
@ -25,10 +25,18 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
#include "messenger.h"
|
||||
#include "storage/localstorage.h"
|
||||
#include "platform/platform_file_utilities.h"
|
||||
#include "auth_session.h"
|
||||
|
||||
namespace Storage {
|
||||
|
||||
void Downloader::clearPriorities() {
|
||||
++_priority;
|
||||
}
|
||||
|
||||
} // namespace Storage
|
||||
|
||||
namespace {
|
||||
|
||||
int32 GlobalPriority = 1;
|
||||
struct DataRequested {
|
||||
DataRequested() {
|
||||
memset(v, 0, sizeof(v));
|
||||
|
@ -37,16 +45,15 @@ struct DataRequested {
|
|||
};
|
||||
QMap<int32, DataRequested> DataRequestedMap;
|
||||
|
||||
// Debug flag to find out how we end up crashing.
|
||||
std::set<FileLoader*> MustNotDestroy;
|
||||
|
||||
}
|
||||
} // namespace
|
||||
|
||||
struct FileLoaderQueue {
|
||||
FileLoaderQueue(int32 limit) : queries(0), limit(limit), start(0), end(0) {
|
||||
FileLoaderQueue(int32 limit) : limit(limit) {
|
||||
}
|
||||
int32 queries, limit;
|
||||
FileLoader *start, *end;
|
||||
int queries = 0;
|
||||
int limit = 0;
|
||||
FileLoader *start = nullptr;
|
||||
FileLoader *end = nullptr;
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
@ -64,7 +71,8 @@ namespace {
|
|||
}
|
||||
|
||||
FileLoader::FileLoader(const QString &toFile, int32 size, LocationType locationType, LoadToCacheSetting toCache, LoadFromCloudSetting fromCloud, bool autoLoading)
|
||||
: _autoLoading(autoLoading)
|
||||
: _downloader(AuthSession::Current().downloader())
|
||||
, _autoLoading(autoLoading)
|
||||
, _file(toFile)
|
||||
, _fname(toFile)
|
||||
, _toCache(toCache)
|
||||
|
@ -158,8 +166,6 @@ void FileLoader::pause() {
|
|||
}
|
||||
|
||||
FileLoader::~FileLoader() {
|
||||
t_assert(MustNotDestroy.find(this) == MustNotDestroy.cend());
|
||||
|
||||
if (_localTaskId) {
|
||||
Local::cancelTask(_localTaskId);
|
||||
}
|
||||
|
@ -197,11 +203,9 @@ void FileLoader::localLoaded(const StorageImageSaved &result, const QByteArray &
|
|||
_fileIsOpen = false;
|
||||
Platform::File::PostprocessDownloaded(QFileInfo(_file).absoluteFilePath());
|
||||
}
|
||||
FileDownload::ImageLoaded().notify();
|
||||
_downloader->taskFinished().notify();
|
||||
|
||||
MustNotDestroy.insert(this);
|
||||
emit progress(this);
|
||||
MustNotDestroy.erase(this);
|
||||
|
||||
loadNext();
|
||||
}
|
||||
|
@ -224,45 +228,46 @@ void FileLoader::start(bool loadFirst, bool prior) {
|
|||
}
|
||||
}
|
||||
|
||||
auto currentPriority = _downloader->currentPriority();
|
||||
FileLoader *before = 0, *after = 0;
|
||||
if (prior) {
|
||||
if (_inQueue && _priority == GlobalPriority) {
|
||||
if (_inQueue && _priority == currentPriority) {
|
||||
if (loadFirst) {
|
||||
if (!_prev) return startLoading(loadFirst, prior);
|
||||
before = _queue->start;
|
||||
} else {
|
||||
if (!_next || _next->_priority < GlobalPriority) return startLoading(loadFirst, prior);
|
||||
if (!_next || _next->_priority < currentPriority) return startLoading(loadFirst, prior);
|
||||
after = _next;
|
||||
while (after->_next && after->_next->_priority == GlobalPriority) {
|
||||
while (after->_next && after->_next->_priority == currentPriority) {
|
||||
after = after->_next;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_priority = GlobalPriority;
|
||||
_priority = currentPriority;
|
||||
if (loadFirst) {
|
||||
if (_inQueue && !_prev) return startLoading(loadFirst, prior);
|
||||
before = _queue->start;
|
||||
} else {
|
||||
if (_inQueue) {
|
||||
if (_next && _next->_priority == GlobalPriority) {
|
||||
if (_next && _next->_priority == currentPriority) {
|
||||
after = _next;
|
||||
} else if (_prev && _prev->_priority < GlobalPriority) {
|
||||
} else if (_prev && _prev->_priority < currentPriority) {
|
||||
before = _prev;
|
||||
while (before->_prev && before->_prev->_priority < GlobalPriority) {
|
||||
while (before->_prev && before->_prev->_priority < currentPriority) {
|
||||
before = before->_prev;
|
||||
}
|
||||
} else {
|
||||
return startLoading(loadFirst, prior);
|
||||
}
|
||||
} else {
|
||||
if (_queue->start && _queue->start->_priority == GlobalPriority) {
|
||||
if (_queue->start && _queue->start->_priority == currentPriority) {
|
||||
after = _queue->start;
|
||||
} else {
|
||||
before = _queue->start;
|
||||
}
|
||||
}
|
||||
if (after) {
|
||||
while (after->_next && after->_next->_priority == GlobalPriority) {
|
||||
while (after->_next && after->_next->_priority == currentPriority) {
|
||||
after = after->_next;
|
||||
}
|
||||
}
|
||||
|
@ -270,9 +275,9 @@ void FileLoader::start(bool loadFirst, bool prior) {
|
|||
}
|
||||
} else {
|
||||
if (loadFirst) {
|
||||
if (_inQueue && (!_prev || _prev->_priority == GlobalPriority)) return startLoading(loadFirst, prior);
|
||||
if (_inQueue && (!_prev || _prev->_priority == currentPriority)) return startLoading(loadFirst, prior);
|
||||
before = _prev;
|
||||
while (before->_prev && before->_prev->_priority != GlobalPriority) {
|
||||
while (before->_prev && before->_prev->_priority != currentPriority) {
|
||||
before = before->_prev;
|
||||
}
|
||||
} else {
|
||||
|
@ -330,13 +335,11 @@ void FileLoader::cancel(bool fail) {
|
|||
_fname = QString();
|
||||
_file.setFileName(_fname);
|
||||
|
||||
MustNotDestroy.insert(this);
|
||||
if (fail) {
|
||||
emit failed(this, started);
|
||||
} else {
|
||||
emit progress(this);
|
||||
}
|
||||
MustNotDestroy.erase(this);
|
||||
|
||||
loadNext();
|
||||
}
|
||||
|
@ -553,12 +556,10 @@ void mtpFileLoader::partLoaded(int32 offset, const MTPupload_File &result, mtpRe
|
|||
}
|
||||
}
|
||||
if (_finished) {
|
||||
FileDownload::ImageLoaded().notify();
|
||||
_downloader->taskFinished().notify();
|
||||
}
|
||||
|
||||
MustNotDestroy.insert(this);
|
||||
emit progress(this);
|
||||
MustNotDestroy.erase(this);
|
||||
|
||||
loadNext();
|
||||
}
|
||||
|
@ -609,9 +610,7 @@ bool mtpFileLoader::tryLoadLocal() {
|
|||
}
|
||||
}
|
||||
|
||||
MustNotDestroy.insert(this);
|
||||
emit progress(this);
|
||||
MustNotDestroy.erase(this);
|
||||
|
||||
if (_localStatus != LocalNotTried) {
|
||||
return _finished;
|
||||
|
@ -690,11 +689,9 @@ void webFileLoader::onFinished(const QByteArray &data) {
|
|||
if (_localStatus == LocalNotFound || _localStatus == LocalFailed) {
|
||||
Local::writeWebFile(_url, _data);
|
||||
}
|
||||
FileDownload::ImageLoaded().notify();
|
||||
_downloader->taskFinished().notify();
|
||||
|
||||
MustNotDestroy.insert(this);
|
||||
emit progress(this);
|
||||
MustNotDestroy.erase(this);
|
||||
|
||||
loadNext();
|
||||
}
|
||||
|
@ -1103,22 +1100,3 @@ void WebLoadMainManager::error(webFileLoader *loader) {
|
|||
loader->onError();
|
||||
}
|
||||
}
|
||||
|
||||
namespace MTP {
|
||||
void clearLoaderPriorities() {
|
||||
++GlobalPriority;
|
||||
}
|
||||
}
|
||||
|
||||
namespace FileDownload {
|
||||
namespace {
|
||||
|
||||
base::Observable<void> ImageLoadedObservable;
|
||||
|
||||
} // namespace
|
||||
|
||||
base::Observable<void> &ImageLoaded() {
|
||||
return ImageLoadedObservable;
|
||||
}
|
||||
|
||||
} // namespace FileDownload
|
||||
|
|
|
@ -21,20 +21,29 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
#pragma once
|
||||
|
||||
#include "core/observer.h"
|
||||
#include "storage/localimageloader.h" // for TaskId
|
||||
|
||||
namespace MTP {
|
||||
void clearLoaderPriorities();
|
||||
}
|
||||
namespace Storage {
|
||||
|
||||
enum LocationType {
|
||||
UnknownFileLocation = 0,
|
||||
// 1, 2, etc are used as "version" value in mediaKey() method.
|
||||
class Downloader final {
|
||||
public:
|
||||
int currentPriority() const {
|
||||
return _priority;
|
||||
}
|
||||
void clearPriorities();
|
||||
|
||||
base::Observable<void> &taskFinished() {
|
||||
return _taskFinishedObservable;
|
||||
}
|
||||
|
||||
private:
|
||||
base::Observable<void> _taskFinishedObservable;
|
||||
int _priority = 1;
|
||||
|
||||
DocumentFileLocation = 0x4e45abe9, // mtpc_inputDocumentFileLocation
|
||||
AudioFileLocation = 0x74dc404d, // mtpc_inputAudioFileLocation
|
||||
VideoFileLocation = 0x3d0364ec, // mtpc_inputVideoFileLocation
|
||||
};
|
||||
|
||||
} // namespace Storage
|
||||
|
||||
struct StorageImageSaved {
|
||||
StorageImageSaved() = default;
|
||||
explicit StorageImageSaved(const QByteArray &data) : data(data) {
|
||||
|
@ -52,17 +61,6 @@ enum LocalLoadStatus {
|
|||
LocalFailed,
|
||||
};
|
||||
|
||||
using TaskId = void*; // no interface, just id
|
||||
|
||||
enum LoadFromCloudSetting {
|
||||
LoadFromCloudOrLocal,
|
||||
LoadFromLocalOnly,
|
||||
};
|
||||
enum LoadToCacheSetting {
|
||||
LoadToFileOnly,
|
||||
LoadToCacheAsWell,
|
||||
};
|
||||
|
||||
class mtpFileLoader;
|
||||
class webFileLoader;
|
||||
|
||||
|
@ -129,6 +127,7 @@ signals:
|
|||
protected:
|
||||
void readImage(const QSize &shrinkBox) const;
|
||||
|
||||
Storage::Downloader *_downloader = nullptr;
|
||||
FileLoader *_prev = nullptr;
|
||||
FileLoader *_next = nullptr;
|
||||
int _priority = 0;
|
||||
|
@ -338,9 +337,3 @@ static WebLoadManager * const FinishedWebLoadManager = SharedMemoryLocation<WebL
|
|||
|
||||
void reinitWebLoadManager();
|
||||
void stopWebLoadManager();
|
||||
|
||||
namespace FileDownload {
|
||||
|
||||
base::Observable<void> &ImageLoaded();
|
||||
|
||||
} // namespace FileDownload
|
||||
|
|
|
@ -99,6 +99,8 @@ struct SendMediaReady {
|
|||
|
||||
};
|
||||
|
||||
using TaskId = void*; // no interface, just id
|
||||
|
||||
class Task {
|
||||
public:
|
||||
virtual void process() = 0; // is executed in a separate thread
|
||||
|
|
|
@ -1088,11 +1088,14 @@ bool _readSetting(quint32 blockId, QDataStream &stream, int version, ReadSetting
|
|||
stream >> v;
|
||||
if (!_checkStreamStatus(stream)) return false;
|
||||
|
||||
switch (v) {
|
||||
case dbiwmTrayOnly: cSetWorkMode(dbiwmTrayOnly); break;
|
||||
case dbiwmWindowOnly: cSetWorkMode(dbiwmWindowOnly); break;
|
||||
default: cSetWorkMode(dbiwmWindowAndTray); break;
|
||||
auto newMode = [v] {
|
||||
switch (v) {
|
||||
case dbiwmTrayOnly: return dbiwmTrayOnly;
|
||||
case dbiwmWindowOnly: return dbiwmWindowOnly;
|
||||
};
|
||||
return dbiwmWindowAndTray;
|
||||
};
|
||||
Global::RefWorkMode().set(newMode());
|
||||
} break;
|
||||
|
||||
case dbiConnectionType: {
|
||||
|
@ -2269,7 +2272,7 @@ void writeSettings() {
|
|||
data.stream << quint32(dbiAutoStart) << qint32(cAutoStart());
|
||||
data.stream << quint32(dbiStartMinimized) << qint32(cStartMinimized());
|
||||
data.stream << quint32(dbiSendToMenu) << qint32(cSendToMenu());
|
||||
data.stream << quint32(dbiWorkMode) << qint32(cWorkMode());
|
||||
data.stream << quint32(dbiWorkMode) << qint32(Global::WorkMode().value());
|
||||
data.stream << quint32(dbiSeenTrayTooltip) << qint32(cSeenTrayTooltip());
|
||||
data.stream << quint32(dbiAutoUpdate) << qint32(cAutoUpdate());
|
||||
data.stream << quint32(dbiLastUpdateCheck) << qint32(cLastUpdateCheck());
|
||||
|
@ -2731,7 +2734,7 @@ public:
|
|||
qint32 legacyTypeField = 0;
|
||||
stream >> first >> second >> legacyTypeField >> data;
|
||||
}
|
||||
void clearInMap() {
|
||||
void clearInMap() override {
|
||||
StorageMap::iterator j = _imagesMap.find(_location);
|
||||
if (j != _imagesMap.cend() && j->first == _key) {
|
||||
clearKey(_key, FileOption::User);
|
||||
|
|
|
@ -21,6 +21,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
#pragma once
|
||||
|
||||
#include "core/basic_types.h"
|
||||
#include "storage/file_download.h"
|
||||
|
||||
namespace Window {
|
||||
namespace Theme {
|
||||
|
|
|
@ -37,6 +37,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
#include "window/themes/window_theme.h"
|
||||
#include "auth_session.h"
|
||||
#include "messenger.h"
|
||||
#include "storage/file_download.h"
|
||||
|
||||
namespace {
|
||||
|
||||
|
|
|
@ -20,6 +20,34 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
using MediaKey = QPair<uint64, uint64>;
|
||||
|
||||
inline uint64 mediaMix32To64(int32 a, int32 b) {
|
||||
return (uint64(*reinterpret_cast<uint32*>(&a)) << 32) | uint64(*reinterpret_cast<uint32*>(&b));
|
||||
}
|
||||
|
||||
enum LocationType {
|
||||
UnknownFileLocation = 0,
|
||||
// 1, 2, etc are used as "version" value in mediaKey() method.
|
||||
|
||||
DocumentFileLocation = 0x4e45abe9, // mtpc_inputDocumentFileLocation
|
||||
AudioFileLocation = 0x74dc404d, // mtpc_inputAudioFileLocation
|
||||
VideoFileLocation = 0x3d0364ec, // mtpc_inputVideoFileLocation
|
||||
};
|
||||
|
||||
// Old method, should not be used anymore.
|
||||
//inline MediaKey mediaKey(LocationType type, int32 dc, const uint64 &id) {
|
||||
// return MediaKey(mediaMix32To64(type, dc), id);
|
||||
//}
|
||||
// New method when version was introduced, type is not relevant anymore (all files are Documents).
|
||||
inline MediaKey mediaKey(LocationType type, int32 dc, const uint64 &id, int32 version) {
|
||||
return (version > 0) ? MediaKey(mediaMix32To64(version, dc), id) : MediaKey(mediaMix32To64(type, dc), id);
|
||||
}
|
||||
|
||||
inline StorageKey mediaKey(const MTPDfileLocation &location) {
|
||||
return storageKey(location.vdc_id.v, location.vvolume_id.v, location.vlocal_id.v);
|
||||
}
|
||||
|
||||
typedef int32 UserId;
|
||||
typedef int32 ChatId;
|
||||
typedef int32 ChannelId;
|
||||
|
|
|
@ -883,6 +883,10 @@ void RemoteImage::setData(QByteArray &bytes, const QByteArray &bytesFormat) {
|
|||
_forgot = false;
|
||||
}
|
||||
|
||||
bool RemoteImage::amLoading() const {
|
||||
return _loader && _loader != CancelledFileLoader;
|
||||
}
|
||||
|
||||
void RemoteImage::automaticLoad(const HistoryItem *item) {
|
||||
if (loaded()) return;
|
||||
|
||||
|
|
|
@ -20,7 +20,18 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#include "storage/file_download.h"
|
||||
class FileLoader;
|
||||
class mtpFileLoader;
|
||||
|
||||
enum LoadFromCloudSetting {
|
||||
LoadFromCloudOrLocal,
|
||||
LoadFromLocalOnly,
|
||||
};
|
||||
|
||||
enum LoadToCacheSetting {
|
||||
LoadToFileOnly,
|
||||
LoadToCacheAsWell,
|
||||
};
|
||||
|
||||
enum class ImageRoundRadius {
|
||||
None,
|
||||
|
@ -317,9 +328,7 @@ protected:
|
|||
|
||||
private:
|
||||
mutable FileLoader *_loader = nullptr;
|
||||
bool amLoading() const {
|
||||
return _loader && _loader != CancelledFileLoader;
|
||||
}
|
||||
bool amLoading() const;
|
||||
void doCheckload() const;
|
||||
|
||||
void destroyLoaderDelayed(FileLoader *newValue = nullptr) const;
|
||||
|
@ -328,7 +337,6 @@ private:
|
|||
|
||||
class StorageImage : public RemoteImage {
|
||||
public:
|
||||
|
||||
StorageImage(const StorageImageLocation &location, int32 size = 0);
|
||||
StorageImage(const StorageImageLocation &location, QByteArray &bytes);
|
||||
|
||||
|
@ -511,19 +519,3 @@ inline bool operator==(const FileLocation &a, const FileLocation &b) {
|
|||
inline bool operator!=(const FileLocation &a, const FileLocation &b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
typedef QPair<uint64, uint64> MediaKey;
|
||||
inline uint64 mediaMix32To64(int32 a, int32 b) {
|
||||
return (uint64(*reinterpret_cast<uint32*>(&a)) << 32) | uint64(*reinterpret_cast<uint32*>(&b));
|
||||
}
|
||||
// Old method, should not be used anymore.
|
||||
//inline MediaKey mediaKey(LocationType type, int32 dc, const uint64 &id) {
|
||||
// return MediaKey(mediaMix32To64(type, dc), id);
|
||||
//}
|
||||
// New method when version was introduced, type is not relevant anymore (all files are Documents).
|
||||
inline MediaKey mediaKey(LocationType type, int32 dc, const uint64 &id, int32 version) {
|
||||
return (version > 0) ? MediaKey(mediaMix32To64(version, dc), id) : MediaKey(mediaMix32To64(type, dc), id);
|
||||
}
|
||||
inline StorageKey mediaKey(const MTPDfileLocation &location) {
|
||||
return storageKey(location.vdc_id.v, location.vvolume_id.v, location.vlocal_id.v);
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ MainWindow::MainWindow() : QWidget()
|
|||
}
|
||||
});
|
||||
subscribe(Global::RefUnreadCounterUpdate(), [this] { updateUnreadCounter(); });
|
||||
subscribe(Global::RefWorkMode(), [this](DBIWorkMode mode) { workmodeUpdated(mode); });
|
||||
|
||||
_isActiveTimer->setSingleShot(true);
|
||||
connect(_isActiveTimer, SIGNAL(timeout()), this, SLOT(updateIsActiveByTimer()));
|
||||
|
@ -53,7 +54,7 @@ bool MainWindow::hideNoQuit() {
|
|||
hideMediaview();
|
||||
return true;
|
||||
}
|
||||
if (cWorkMode() == dbiwmTrayOnly || cWorkMode() == dbiwmWindowAndTray) {
|
||||
if (Global::WorkMode().value() == dbiwmTrayOnly || Global::WorkMode().value() == dbiwmWindowAndTray) {
|
||||
if (minimizeToTray()) {
|
||||
Ui::showChatsList();
|
||||
return true;
|
||||
|
|
|
@ -127,6 +127,9 @@ protected:
|
|||
virtual void showTrayTooltip() {
|
||||
}
|
||||
|
||||
virtual void workmodeUpdated(DBIWorkMode mode) {
|
||||
}
|
||||
|
||||
virtual void updateControlsGeometry();
|
||||
|
||||
// This one is overriden in Windows for historical reasons.
|
||||
|
|
|
@ -25,25 +25,332 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
#include "lang.h"
|
||||
#include "mainwindow.h"
|
||||
#include "mainwidget.h"
|
||||
#include "apiwrap.h"
|
||||
#include "auth_session.h"
|
||||
|
||||
namespace Window {
|
||||
namespace Notifications {
|
||||
|
||||
void Start() {
|
||||
Default::Start();
|
||||
Platform::Notifications::Start();
|
||||
System::System(AuthSession *session) : _authSession(session) {
|
||||
createManager();
|
||||
|
||||
_waitTimer.setTimeoutHandler([this] {
|
||||
showNext();
|
||||
});
|
||||
|
||||
subscribe(settingsChanged(), [this](ChangeType type) {
|
||||
if (type == ChangeType::DesktopEnabled) {
|
||||
App::wnd()->updateTrayMenu();
|
||||
clearAll();
|
||||
} else if (type == ChangeType::ViewParams) {
|
||||
updateAll();
|
||||
} else if (type == ChangeType::IncludeMuted) {
|
||||
Notify::unreadCounterUpdated();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Manager *GetManager() {
|
||||
if (auto result = Platform::Notifications::GetManager()) {
|
||||
return result;
|
||||
void System::createManager() {
|
||||
_manager = Platform::Notifications::Create(this);
|
||||
if (!_manager) {
|
||||
_manager = std::make_unique<Default::Manager>(this);
|
||||
}
|
||||
return Default::GetManager();
|
||||
}
|
||||
|
||||
void Finish() {
|
||||
Platform::Notifications::Finish();
|
||||
Default::Finish();
|
||||
void System::schedule(History *history, HistoryItem *item) {
|
||||
if (App::quitting() || !history->currentNotification() || !App::api()) return;
|
||||
|
||||
PeerData *notifyByFrom = (!history->peer->isUser() && item->mentionsMe()) ? item->from() : 0;
|
||||
|
||||
if (item->isSilent()) {
|
||||
history->popNotification(item);
|
||||
return;
|
||||
}
|
||||
|
||||
bool haveSetting = (history->peer->notify != UnknownNotifySettings);
|
||||
if (haveSetting) {
|
||||
if (history->peer->notify != EmptyNotifySettings && history->peer->notify->mute > unixtime()) {
|
||||
if (notifyByFrom) {
|
||||
haveSetting = (item->from()->notify != UnknownNotifySettings);
|
||||
if (haveSetting) {
|
||||
if (notifyByFrom->notify != EmptyNotifySettings && notifyByFrom->notify->mute > unixtime()) {
|
||||
history->popNotification(item);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
App::api()->requestNotifySetting(notifyByFrom);
|
||||
}
|
||||
} else {
|
||||
history->popNotification(item);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (notifyByFrom && notifyByFrom->notify == UnknownNotifySettings) {
|
||||
App::api()->requestNotifySetting(notifyByFrom);
|
||||
}
|
||||
App::api()->requestNotifySetting(history->peer);
|
||||
}
|
||||
if (!item->notificationReady()) {
|
||||
haveSetting = false;
|
||||
}
|
||||
|
||||
int delay = item->Has<HistoryMessageForwarded>() ? 500 : 100, t = unixtime();
|
||||
auto ms = getms(true);
|
||||
bool isOnline = App::main()->lastWasOnline(), otherNotOld = ((cOtherOnline() * 1000LL) + Global::OnlineCloudTimeout() > t * 1000LL);
|
||||
bool otherLaterThanMe = (cOtherOnline() * 1000LL + (ms - App::main()->lastSetOnline()) > t * 1000LL);
|
||||
if (!isOnline && otherNotOld && otherLaterThanMe) {
|
||||
delay = Global::NotifyCloudDelay();
|
||||
} else if (cOtherOnline() >= t) {
|
||||
delay = Global::NotifyDefaultDelay();
|
||||
}
|
||||
|
||||
auto when = ms + delay;
|
||||
_whenAlerts[history].insert(when, notifyByFrom);
|
||||
if (Global::DesktopNotify() && !Platform::Notifications::SkipToast()) {
|
||||
auto &whenMap = _whenMaps[history];
|
||||
if (whenMap.constFind(item->id) == whenMap.cend()) {
|
||||
whenMap.insert(item->id, when);
|
||||
}
|
||||
|
||||
auto &addTo = haveSetting ? _waiters : _settingWaiters;
|
||||
auto it = addTo.constFind(history);
|
||||
if (it == addTo.cend() || it->when > when) {
|
||||
addTo.insert(history, Waiter(item->id, when, notifyByFrom));
|
||||
}
|
||||
}
|
||||
if (haveSetting) {
|
||||
if (!_waitTimer.isActive() || _waitTimer.remainingTime() > delay) {
|
||||
_waitTimer.start(delay);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void System::clearAll() {
|
||||
_manager->clearAll();
|
||||
|
||||
for (auto i = _whenMaps.cbegin(), e = _whenMaps.cend(); i != e; ++i) {
|
||||
i.key()->clearNotifications();
|
||||
}
|
||||
_whenMaps.clear();
|
||||
_whenAlerts.clear();
|
||||
_waiters.clear();
|
||||
_settingWaiters.clear();
|
||||
}
|
||||
|
||||
void System::clearFromHistory(History *history) {
|
||||
_manager->clearFromHistory(history);
|
||||
|
||||
history->clearNotifications();
|
||||
_whenMaps.remove(history);
|
||||
_whenAlerts.remove(history);
|
||||
_waiters.remove(history);
|
||||
_settingWaiters.remove(history);
|
||||
|
||||
_waitTimer.stop();
|
||||
showNext();
|
||||
}
|
||||
|
||||
void System::clearFromItem(HistoryItem *item) {
|
||||
_manager->clearFromItem(item);
|
||||
}
|
||||
|
||||
void System::clearAllFast() {
|
||||
_manager->clearAllFast();
|
||||
|
||||
_whenMaps.clear();
|
||||
_whenAlerts.clear();
|
||||
_waiters.clear();
|
||||
_settingWaiters.clear();
|
||||
}
|
||||
|
||||
void System::checkDelayed() {
|
||||
int32 t = unixtime();
|
||||
for (auto i = _settingWaiters.begin(); i != _settingWaiters.end();) {
|
||||
auto history = i.key();
|
||||
bool loaded = false, muted = false;
|
||||
if (history->peer->notify != UnknownNotifySettings) {
|
||||
if (history->peer->notify == EmptyNotifySettings || history->peer->notify->mute <= t) {
|
||||
loaded = true;
|
||||
} else if (PeerData *from = i.value().notifyByFrom) {
|
||||
if (from->notify != UnknownNotifySettings) {
|
||||
if (from->notify == EmptyNotifySettings || from->notify->mute <= t) {
|
||||
loaded = true;
|
||||
} else {
|
||||
loaded = muted = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
loaded = muted = true;
|
||||
}
|
||||
}
|
||||
if (loaded) {
|
||||
if (HistoryItem *item = App::histItemById(history->channelId(), i.value().msg)) {
|
||||
if (!item->notificationReady()) {
|
||||
loaded = false;
|
||||
}
|
||||
} else {
|
||||
muted = true;
|
||||
}
|
||||
}
|
||||
if (loaded) {
|
||||
if (!muted) {
|
||||
_waiters.insert(i.key(), i.value());
|
||||
}
|
||||
i = _settingWaiters.erase(i);
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
_waitTimer.stop();
|
||||
showNext();
|
||||
}
|
||||
|
||||
void System::showNext() {
|
||||
if (App::quitting()) return;
|
||||
|
||||
auto ms = getms(true), nextAlert = 0LL;
|
||||
bool alert = false;
|
||||
int32 now = unixtime();
|
||||
for (auto i = _whenAlerts.begin(); i != _whenAlerts.end();) {
|
||||
while (!i.value().isEmpty() && i.value().begin().key() <= ms) {
|
||||
NotifySettingsPtr n = i.key()->peer->notify, f = i.value().begin().value() ? i.value().begin().value()->notify : UnknownNotifySettings;
|
||||
while (!i.value().isEmpty() && i.value().begin().key() <= ms + 500) { // not more than one sound in 500ms from one peer - grouping
|
||||
i.value().erase(i.value().begin());
|
||||
}
|
||||
if (n == EmptyNotifySettings || (n != UnknownNotifySettings && n->mute <= now)) {
|
||||
alert = true;
|
||||
} else if (f == EmptyNotifySettings || (f != UnknownNotifySettings && f->mute <= now)) { // notify by from()
|
||||
alert = true;
|
||||
}
|
||||
}
|
||||
if (i.value().isEmpty()) {
|
||||
i = _whenAlerts.erase(i);
|
||||
} else {
|
||||
if (!nextAlert || nextAlert > i.value().begin().key()) {
|
||||
nextAlert = i.value().begin().key();
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
if (alert) {
|
||||
Platform::Notifications::FlashBounce();
|
||||
App::playSound();
|
||||
}
|
||||
|
||||
if (_waiters.isEmpty() || !Global::DesktopNotify() || Platform::Notifications::SkipToast()) {
|
||||
if (nextAlert) {
|
||||
_waitTimer.start(nextAlert - ms);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
auto next = 0LL;
|
||||
HistoryItem *notifyItem = nullptr;
|
||||
History *notifyHistory = nullptr;
|
||||
for (auto i = _waiters.begin(); i != _waiters.end();) {
|
||||
History *history = i.key();
|
||||
if (history->currentNotification() && history->currentNotification()->id != i.value().msg) {
|
||||
auto j = _whenMaps.find(history);
|
||||
if (j == _whenMaps.end()) {
|
||||
history->clearNotifications();
|
||||
i = _waiters.erase(i);
|
||||
continue;
|
||||
}
|
||||
do {
|
||||
auto k = j.value().constFind(history->currentNotification()->id);
|
||||
if (k != j.value().cend()) {
|
||||
i.value().msg = k.key();
|
||||
i.value().when = k.value();
|
||||
break;
|
||||
}
|
||||
history->skipNotification();
|
||||
} while (history->currentNotification());
|
||||
}
|
||||
if (!history->currentNotification()) {
|
||||
_whenMaps.remove(history);
|
||||
i = _waiters.erase(i);
|
||||
continue;
|
||||
}
|
||||
auto when = i.value().when;
|
||||
if (!notifyItem || next > when) {
|
||||
next = when;
|
||||
notifyItem = history->currentNotification();
|
||||
notifyHistory = history;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
if (notifyItem) {
|
||||
if (next > ms) {
|
||||
if (nextAlert && nextAlert < next) {
|
||||
next = nextAlert;
|
||||
nextAlert = 0;
|
||||
}
|
||||
_waitTimer.start(next - ms);
|
||||
break;
|
||||
} else {
|
||||
HistoryItem *fwd = notifyItem->Has<HistoryMessageForwarded>() ? notifyItem : nullptr; // forwarded notify grouping
|
||||
int32 fwdCount = 1;
|
||||
|
||||
auto ms = getms(true);
|
||||
History *history = notifyItem->history();
|
||||
auto j = _whenMaps.find(history);
|
||||
if (j == _whenMaps.cend()) {
|
||||
history->clearNotifications();
|
||||
} else {
|
||||
HistoryItem *nextNotify = 0;
|
||||
do {
|
||||
history->skipNotification();
|
||||
if (!history->hasNotification()) {
|
||||
break;
|
||||
}
|
||||
|
||||
j.value().remove((fwd ? fwd : notifyItem)->id);
|
||||
do {
|
||||
auto k = j.value().constFind(history->currentNotification()->id);
|
||||
if (k != j.value().cend()) {
|
||||
nextNotify = history->currentNotification();
|
||||
_waiters.insert(notifyHistory, Waiter(k.key(), k.value(), 0));
|
||||
break;
|
||||
}
|
||||
history->skipNotification();
|
||||
} while (history->hasNotification());
|
||||
if (nextNotify) {
|
||||
if (fwd) {
|
||||
HistoryItem *nextFwd = nextNotify->Has<HistoryMessageForwarded>() ? nextNotify : nullptr;
|
||||
if (nextFwd && fwd->author() == nextFwd->author() && qAbs(int64(nextFwd->date.toTime_t()) - int64(fwd->date.toTime_t())) < 2) {
|
||||
fwd = nextFwd;
|
||||
++fwdCount;
|
||||
} else {
|
||||
nextNotify = nullptr;
|
||||
}
|
||||
} else {
|
||||
nextNotify = nullptr;
|
||||
}
|
||||
}
|
||||
} while (nextNotify);
|
||||
}
|
||||
|
||||
_manager->showNotification(notifyItem, fwdCount);
|
||||
|
||||
if (!history->hasNotification()) {
|
||||
_waiters.remove(history);
|
||||
_whenMaps.remove(history);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (nextAlert) {
|
||||
_waitTimer.start(nextAlert - ms);
|
||||
}
|
||||
}
|
||||
|
||||
void System::updateAll() {
|
||||
_manager->updateAll();
|
||||
}
|
||||
|
||||
Manager::DisplayOptions Manager::getNotificationOptions(HistoryItem *item) {
|
||||
|
@ -66,7 +373,7 @@ void Manager::notificationActivated(PeerId peerId, MsgId msgId) {
|
|||
#endif
|
||||
if (App::passcoded()) {
|
||||
window->setInnerFocus();
|
||||
window->notifyClear();
|
||||
system()->clearAll();
|
||||
} else {
|
||||
auto tomsg = !history->peer->isUser() && (msgId > 0);
|
||||
if (tomsg) {
|
||||
|
@ -76,7 +383,7 @@ void Manager::notificationActivated(PeerId peerId, MsgId msgId) {
|
|||
}
|
||||
}
|
||||
Ui::showPeerHistory(history, tomsg ? msgId : ShowAtUnreadMsgId);
|
||||
window->notifyClear(history);
|
||||
system()->clearFromHistory(history);
|
||||
}
|
||||
}
|
||||
onAfterNotificationActivated(peerId, msgId);
|
||||
|
|
|
@ -20,17 +20,100 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
class AuthSession;
|
||||
|
||||
namespace Platform {
|
||||
namespace Notifications {
|
||||
class Manager;
|
||||
} // namespace Notifications
|
||||
} // namespace Platform
|
||||
|
||||
namespace Window {
|
||||
namespace Notifications {
|
||||
|
||||
enum class ChangeType {
|
||||
SoundEnabled,
|
||||
IncludeMuted,
|
||||
DesktopEnabled,
|
||||
ViewParams,
|
||||
MaxCount,
|
||||
Corner,
|
||||
DemoIsShown,
|
||||
};
|
||||
|
||||
} // namespace Notifications
|
||||
} // namespace Window
|
||||
|
||||
namespace base {
|
||||
|
||||
template <>
|
||||
struct custom_is_fast_copy_type<Window::Notifications::ChangeType> : public std::true_type {
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
namespace Window {
|
||||
namespace Notifications {
|
||||
|
||||
class Manager;
|
||||
|
||||
void Start();
|
||||
Manager *GetManager();
|
||||
void Finish();
|
||||
class System final : private base::Subscriber {
|
||||
public:
|
||||
System(AuthSession *session);
|
||||
|
||||
void createManager();
|
||||
|
||||
void checkDelayed();
|
||||
void schedule(History *history, HistoryItem *item);
|
||||
void clearFromHistory(History *history);
|
||||
void clearFromItem(HistoryItem *item);
|
||||
void clearAll();
|
||||
void clearAllFast();
|
||||
void updateAll();
|
||||
|
||||
base::Observable<ChangeType> &settingsChanged() {
|
||||
return _settingsChanged;
|
||||
}
|
||||
|
||||
AuthSession *authSession() {
|
||||
return _authSession;
|
||||
}
|
||||
|
||||
private:
|
||||
void showNext();
|
||||
|
||||
AuthSession *_authSession = nullptr;
|
||||
|
||||
QMap<History*, QMap<MsgId, TimeMs>> _whenMaps;
|
||||
|
||||
struct Waiter {
|
||||
Waiter(MsgId msg, TimeMs when, PeerData *notifyByFrom)
|
||||
: msg(msg)
|
||||
, when(when)
|
||||
, notifyByFrom(notifyByFrom) {
|
||||
}
|
||||
MsgId msg;
|
||||
TimeMs when;
|
||||
PeerData *notifyByFrom;
|
||||
};
|
||||
using Waiters = QMap<History*, Waiter>;
|
||||
Waiters _waiters;
|
||||
Waiters _settingWaiters;
|
||||
SingleTimer _waitTimer;
|
||||
|
||||
QMap<History*, QMap<TimeMs, PeerData*>> _whenAlerts;
|
||||
|
||||
std::unique_ptr<Manager> _manager;
|
||||
|
||||
base::Observable<ChangeType> _settingsChanged;
|
||||
|
||||
};
|
||||
|
||||
class Manager {
|
||||
public:
|
||||
Manager(System *system) : _system(system) {
|
||||
}
|
||||
|
||||
void showNotification(HistoryItem *item, int forwardedCount) {
|
||||
doShowNotification(item, forwardedCount);
|
||||
}
|
||||
|
@ -63,6 +146,10 @@ public:
|
|||
virtual ~Manager() = default;
|
||||
|
||||
protected:
|
||||
System *system() const {
|
||||
return _system;
|
||||
}
|
||||
|
||||
virtual void doUpdateAll() = 0;
|
||||
virtual void doShowNotification(HistoryItem *item, int forwardedCount) = 0;
|
||||
virtual void doClearAll() = 0;
|
||||
|
@ -74,10 +161,15 @@ protected:
|
|||
virtual void onAfterNotificationActivated(PeerId peerId, MsgId msgId) {
|
||||
}
|
||||
|
||||
private:
|
||||
System *_system = nullptr;
|
||||
|
||||
};
|
||||
|
||||
class NativeManager : public Manager {
|
||||
protected:
|
||||
using Manager::Manager;
|
||||
|
||||
void doUpdateAll() override {
|
||||
doClearAllFast();
|
||||
}
|
||||
|
|
|
@ -31,14 +31,14 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
#include "styles/style_dialogs.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_window.h"
|
||||
#include "storage/file_download.h"
|
||||
#include "auth_session.h"
|
||||
|
||||
namespace Window {
|
||||
namespace Notifications {
|
||||
namespace Default {
|
||||
namespace {
|
||||
|
||||
NeverFreedPointer<Manager> ManagerInstance;
|
||||
|
||||
int notificationMaxHeight() {
|
||||
return st::notifyMinHeight + st::notifyReplyArea.heightMax + st::notifyBorderWidth;
|
||||
}
|
||||
|
@ -59,32 +59,24 @@ internal::Widget::Direction notificationShiftDirection() {
|
|||
|
||||
} // namespace
|
||||
|
||||
void Start() {
|
||||
ManagerInstance.createIfNull();
|
||||
std::unique_ptr<Manager> Create(System *system) {
|
||||
return std::make_unique<Manager>(system);
|
||||
}
|
||||
|
||||
Manager *GetManager() {
|
||||
return ManagerInstance.data();
|
||||
}
|
||||
|
||||
void Finish() {
|
||||
ManagerInstance.clear();
|
||||
}
|
||||
|
||||
Manager::Manager() {
|
||||
subscribe(FileDownload::ImageLoaded(), [this] {
|
||||
for_const (auto notification, _notifications) {
|
||||
Manager::Manager(System *system) : Notifications::Manager(system) {
|
||||
subscribe(system->authSession()->downloader()->taskFinished(), [this] {
|
||||
for_const (auto ¬ification, _notifications) {
|
||||
notification->updatePeerPhoto();
|
||||
}
|
||||
});
|
||||
subscribe(Global::RefNotifySettingsChanged(), [this](Notify::ChangeType change) {
|
||||
subscribe(system->settingsChanged(), [this](ChangeType change) {
|
||||
settingsChanged(change);
|
||||
});
|
||||
_inputCheckTimer.setTimeoutHandler([this] { checkLastInput(); });
|
||||
}
|
||||
|
||||
bool Manager::hasReplyingNotification() const {
|
||||
for_const (auto notification, _notifications) {
|
||||
for_const (auto ¬ification, _notifications) {
|
||||
if (notification->isReplying()) {
|
||||
return true;
|
||||
}
|
||||
|
@ -92,20 +84,20 @@ bool Manager::hasReplyingNotification() const {
|
|||
return false;
|
||||
}
|
||||
|
||||
void Manager::settingsChanged(Notify::ChangeType change) {
|
||||
if (change == Notify::ChangeType::Corner) {
|
||||
void Manager::settingsChanged(ChangeType change) {
|
||||
if (change == ChangeType::Corner) {
|
||||
auto startPosition = notificationStartPosition();
|
||||
auto shiftDirection = notificationShiftDirection();
|
||||
for_const (auto notification, _notifications) {
|
||||
for_const (auto ¬ification, _notifications) {
|
||||
notification->updatePosition(startPosition, shiftDirection);
|
||||
}
|
||||
if (_hideAll) {
|
||||
_hideAll->updatePosition(startPosition, shiftDirection);
|
||||
}
|
||||
} else if (change == Notify::ChangeType::MaxCount) {
|
||||
} else if (change == ChangeType::MaxCount) {
|
||||
int allow = Global::NotificationsCount();
|
||||
for (int i = _notifications.size(); i != 0;) {
|
||||
auto notification = _notifications[--i];
|
||||
auto ¬ification = _notifications[--i];
|
||||
if (notification->isUnlinked()) continue;
|
||||
if (--allow < 0) {
|
||||
notification->unlinkHistory();
|
||||
|
@ -116,14 +108,14 @@ void Manager::settingsChanged(Notify::ChangeType change) {
|
|||
showNextFromQueue();
|
||||
}
|
||||
}
|
||||
} else if (change == Notify::ChangeType::DemoIsShown) {
|
||||
} else if (change == ChangeType::DemoIsShown) {
|
||||
auto demoIsShown = Global::NotificationsDemoIsShown();
|
||||
_demoMasterOpacity.start([this] { demoMasterOpacityCallback(); }, demoIsShown ? 1. : 0., demoIsShown ? 0. : 1., st::notifyFastAnim);
|
||||
}
|
||||
}
|
||||
|
||||
void Manager::demoMasterOpacityCallback() {
|
||||
for_const (auto notification, _notifications) {
|
||||
for_const (auto ¬ification, _notifications) {
|
||||
notification->updateOpacity();
|
||||
}
|
||||
if (_hideAll) {
|
||||
|
@ -138,7 +130,7 @@ float64 Manager::demoMasterOpacity() const {
|
|||
void Manager::checkLastInput() {
|
||||
auto replying = hasReplyingNotification();
|
||||
auto waiting = false;
|
||||
for_const (auto notification, _notifications) {
|
||||
for_const (auto ¬ification, _notifications) {
|
||||
if (!notification->checkLastInput(replying)) {
|
||||
waiting = true;
|
||||
}
|
||||
|
@ -151,7 +143,7 @@ void Manager::checkLastInput() {
|
|||
void Manager::startAllHiding() {
|
||||
if (!hasReplyingNotification()) {
|
||||
int notHidingCount = 0;
|
||||
for_const (auto notification, _notifications) {
|
||||
for_const (auto ¬ification, _notifications) {
|
||||
if (notification->isShowing()) {
|
||||
++notHidingCount;
|
||||
} else {
|
||||
|
@ -166,7 +158,7 @@ void Manager::startAllHiding() {
|
|||
}
|
||||
|
||||
void Manager::stopAllHiding() {
|
||||
for_const (auto notification, _notifications) {
|
||||
for_const (auto ¬ification, _notifications) {
|
||||
notification->stopHiding();
|
||||
}
|
||||
if (_hideAll) {
|
||||
|
@ -175,46 +167,52 @@ void Manager::stopAllHiding() {
|
|||
}
|
||||
|
||||
void Manager::showNextFromQueue() {
|
||||
if (!_queuedNotifications.isEmpty()) {
|
||||
int count = Global::NotificationsCount();
|
||||
for_const (auto notification, _notifications) {
|
||||
if (notification->isUnlinked()) continue;
|
||||
--count;
|
||||
}
|
||||
if (count > 0) {
|
||||
auto startPosition = notificationStartPosition();
|
||||
auto startShift = 0;
|
||||
auto shiftDirection = notificationShiftDirection();
|
||||
do {
|
||||
auto queued = _queuedNotifications.front();
|
||||
_queuedNotifications.pop_front();
|
||||
|
||||
auto notification = std::make_unique<Notification>(
|
||||
queued.history,
|
||||
queued.peer,
|
||||
queued.author,
|
||||
queued.item,
|
||||
queued.forwardedCount,
|
||||
startPosition, startShift, shiftDirection);
|
||||
Platform::Notifications::CustomNotificationShownHook(notification.get());
|
||||
_notifications.push_back(notification.release());
|
||||
--count;
|
||||
} while (count > 0 && !_queuedNotifications.isEmpty());
|
||||
|
||||
_positionsOutdated = true;
|
||||
checkLastInput();
|
||||
auto guard = base::scope_guard([this] {
|
||||
if (_positionsOutdated) {
|
||||
moveWidgets();
|
||||
}
|
||||
});
|
||||
if (_queuedNotifications.empty()) {
|
||||
return;
|
||||
}
|
||||
if (_positionsOutdated) {
|
||||
moveWidgets();
|
||||
int count = Global::NotificationsCount();
|
||||
for_const (auto ¬ification, _notifications) {
|
||||
if (notification->isUnlinked()) continue;
|
||||
--count;
|
||||
}
|
||||
if (count <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto startPosition = notificationStartPosition();
|
||||
auto startShift = 0;
|
||||
auto shiftDirection = notificationShiftDirection();
|
||||
do {
|
||||
auto queued = _queuedNotifications.front();
|
||||
_queuedNotifications.pop_front();
|
||||
|
||||
auto notification = std::make_unique<Notification>(
|
||||
this,
|
||||
queued.history,
|
||||
queued.peer,
|
||||
queued.author,
|
||||
queued.item,
|
||||
queued.forwardedCount,
|
||||
startPosition, startShift, shiftDirection);
|
||||
Platform::Notifications::CustomNotificationShownHook(notification.get());
|
||||
_notifications.push_back(std::move(notification));
|
||||
--count;
|
||||
} while (count > 0 && !_queuedNotifications.empty());
|
||||
|
||||
_positionsOutdated = true;
|
||||
checkLastInput();
|
||||
}
|
||||
|
||||
void Manager::moveWidgets() {
|
||||
auto shift = st::notifyDeltaY;
|
||||
int lastShift = 0, lastShiftCurrent = 0, count = 0;
|
||||
for (int i = _notifications.size(); i != 0;) {
|
||||
auto notification = _notifications[--i];
|
||||
auto ¬ification = _notifications[--i];
|
||||
if (notification->isUnlinked()) continue;
|
||||
|
||||
notification->changeShift(shift);
|
||||
|
@ -226,10 +224,10 @@ void Manager::moveWidgets() {
|
|||
++count;
|
||||
}
|
||||
|
||||
if (count > 1 || !_queuedNotifications.isEmpty()) {
|
||||
if (count > 1 || !_queuedNotifications.empty()) {
|
||||
auto deltaY = st::notifyHideAllHeight + st::notifyDeltaY;
|
||||
if (!_hideAll) {
|
||||
_hideAll = new HideAllButton(notificationStartPosition(), lastShiftCurrent, notificationShiftDirection());
|
||||
_hideAll = std::make_unique<HideAllButton>(this, notificationStartPosition(), lastShiftCurrent, notificationShiftDirection());
|
||||
}
|
||||
_hideAll->changeShift(lastShift);
|
||||
_hideAll->stopHiding();
|
||||
|
@ -243,10 +241,12 @@ void Manager::changeNotificationHeight(Notification *notification, int newHeight
|
|||
if (!deltaHeight) return;
|
||||
|
||||
notification->addToHeight(deltaHeight);
|
||||
auto index = _notifications.indexOf(notification);
|
||||
if (index > 0) {
|
||||
for (int i = 0; i != index; ++i) {
|
||||
auto notification = _notifications[i];
|
||||
auto it = std::find_if(_notifications.cbegin(), _notifications.cend(), [notification](auto &item) {
|
||||
return (item.get() == notification);
|
||||
});
|
||||
if (it != _notifications.cend()) {
|
||||
for (auto i = _notifications.cbegin(); i != it; ++i) {
|
||||
auto ¬ification = *i;
|
||||
if (notification->isUnlinked()) continue;
|
||||
|
||||
notification->addToShift(deltaHeight);
|
||||
|
@ -266,22 +266,21 @@ void Manager::unlinkFromShown(Notification *remove) {
|
|||
showNextFromQueue();
|
||||
}
|
||||
|
||||
void Manager::removeFromShown(Notification *remove) {
|
||||
if (remove) {
|
||||
auto index = _notifications.indexOf(remove);
|
||||
if (index >= 0) {
|
||||
_notifications.removeAt(index);
|
||||
void Manager::removeWidget(internal::Widget *remove) {
|
||||
if (remove == _hideAll.get()) {
|
||||
_hideAll.reset();
|
||||
} else if (remove) {
|
||||
auto it = std::find_if(_notifications.cbegin(), _notifications.cend(), [remove](auto &item) {
|
||||
return item.get() == remove;
|
||||
});
|
||||
if (it != _notifications.cend()) {
|
||||
_notifications.erase(it);
|
||||
_positionsOutdated = true;
|
||||
}
|
||||
}
|
||||
showNextFromQueue();
|
||||
}
|
||||
|
||||
void Manager::removeHideAll(HideAllButton *remove) {
|
||||
if (remove == _hideAll) {
|
||||
_hideAll = nullptr;
|
||||
}
|
||||
}
|
||||
void Manager::doShowNotification(HistoryItem *item, int forwardedCount) {
|
||||
_queuedNotifications.push_back(QueuedNotification(item, forwardedCount));
|
||||
showNextFromQueue();
|
||||
|
@ -289,7 +288,7 @@ void Manager::doShowNotification(HistoryItem *item, int forwardedCount) {
|
|||
|
||||
void Manager::doClearAll() {
|
||||
_queuedNotifications.clear();
|
||||
for_const (auto notification, _notifications) {
|
||||
for_const (auto ¬ification, _notifications) {
|
||||
notification->unlinkHistory();
|
||||
}
|
||||
showNextFromQueue();
|
||||
|
@ -297,11 +296,8 @@ void Manager::doClearAll() {
|
|||
|
||||
void Manager::doClearAllFast() {
|
||||
_queuedNotifications.clear();
|
||||
auto notifications = base::take(_notifications);
|
||||
for_const (auto notification, notifications) {
|
||||
delete notification;
|
||||
}
|
||||
delete base::take(_hideAll);
|
||||
base::take(_notifications);
|
||||
base::take(_hideAll);
|
||||
}
|
||||
|
||||
void Manager::doClearFromHistory(History *history) {
|
||||
|
@ -312,7 +308,7 @@ void Manager::doClearFromHistory(History *history) {
|
|||
++i;
|
||||
}
|
||||
}
|
||||
for_const (auto notification, _notifications) {
|
||||
for_const (auto ¬ification, _notifications) {
|
||||
if (notification->unlinkHistory(history)) {
|
||||
_positionsOutdated = true;
|
||||
}
|
||||
|
@ -321,20 +317,18 @@ void Manager::doClearFromHistory(History *history) {
|
|||
}
|
||||
|
||||
void Manager::doClearFromItem(HistoryItem *item) {
|
||||
for (auto i = 0, queuedCount = _queuedNotifications.size(); i != queuedCount; ++i) {
|
||||
if (_queuedNotifications[i].item == item) {
|
||||
_queuedNotifications.removeAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
for_const (auto notification, _notifications) {
|
||||
_queuedNotifications.erase(std::remove_if(_queuedNotifications.begin(), _queuedNotifications.end(), [item](auto &queued) {
|
||||
return (queued.item == item);
|
||||
}), _queuedNotifications.cend());
|
||||
|
||||
for_const (auto ¬ification, _notifications) {
|
||||
// Calls unlinkFromShown() -> showNextFromQueue()
|
||||
notification->itemRemoved(item);
|
||||
}
|
||||
}
|
||||
|
||||
void Manager::doUpdateAll() {
|
||||
for_const (auto notification, _notifications) {
|
||||
for_const (auto ¬ification, _notifications) {
|
||||
notification->updateNotifyDisplay();
|
||||
}
|
||||
}
|
||||
|
@ -345,7 +339,8 @@ Manager::~Manager() {
|
|||
|
||||
namespace internal {
|
||||
|
||||
Widget::Widget(QPoint startPosition, int shift, Direction shiftDirection) : TWidget(nullptr)
|
||||
Widget::Widget(Manager *manager, QPoint startPosition, int shift, Direction shiftDirection) : TWidget(nullptr)
|
||||
, _manager(manager)
|
||||
, _startPosition(startPosition)
|
||||
, _direction(shiftDirection)
|
||||
, a_shift(shift)
|
||||
|
@ -364,12 +359,10 @@ void Widget::destroyDelayed() {
|
|||
if (_deleted) return;
|
||||
_deleted = true;
|
||||
|
||||
// Ubuntu has a lag if deleteLater() called immediately.
|
||||
#if defined Q_OS_LINUX32 || defined Q_OS_LINUX64
|
||||
QTimer::singleShot(1000, [this] { delete this; });
|
||||
#else // Q_OS_LINUX32 || Q_OS_LINUX64
|
||||
deleteLater();
|
||||
#endif // Q_OS_LINUX32 || Q_OS_LINUX64
|
||||
// Ubuntu has a lag if a fully transparent widget is destroyed immediately.
|
||||
App::CallDelayed(1000, this, [this] {
|
||||
manager()->removeWidget(this);
|
||||
});
|
||||
}
|
||||
|
||||
void Widget::opacityAnimationCallback() {
|
||||
|
@ -411,9 +404,7 @@ void Widget::hideAnimated(float64 duration, const anim::transition &func) {
|
|||
}
|
||||
|
||||
void Widget::updateOpacity() {
|
||||
if (auto manager = ManagerInstance.data()) {
|
||||
setWindowOpacity(_a_opacity.current(_hiding ? 0. : 1.) * manager->demoMasterOpacity());
|
||||
}
|
||||
setWindowOpacity(_a_opacity.current(_hiding ? 0. : 1.) * _manager->demoMasterOpacity());
|
||||
}
|
||||
|
||||
void Widget::changeShift(int top) {
|
||||
|
@ -469,7 +460,7 @@ void Background::paintEvent(QPaintEvent *e) {
|
|||
p.fillRect(st::notifyBorderWidth, height() - st::notifyBorderWidth, width() - 2 * st::notifyBorderWidth, st::notifyBorderWidth, st::notifyBorder);
|
||||
}
|
||||
|
||||
Notification::Notification(History *history, PeerData *peer, PeerData *author, HistoryItem *msg, int forwardedCount, QPoint startPosition, int shift, Direction shiftDirection) : Widget(startPosition, shift, shiftDirection)
|
||||
Notification::Notification(Manager *manager, History *history, PeerData *peer, PeerData *author, HistoryItem *msg, int forwardedCount, QPoint startPosition, int shift, Direction shiftDirection) : Widget(manager, startPosition, shift, shiftDirection)
|
||||
, _history(history)
|
||||
, _peer(peer)
|
||||
, _author(author)
|
||||
|
@ -711,9 +702,7 @@ bool Notification::canReply() const {
|
|||
}
|
||||
|
||||
void Notification::unlinkHistoryInManager() {
|
||||
if (auto manager = ManagerInstance.data()) {
|
||||
manager->unlinkFromShown(this);
|
||||
}
|
||||
manager()->unlinkFromShown(this);
|
||||
}
|
||||
|
||||
void Notification::toggleActionButtons(bool visible) {
|
||||
|
@ -766,19 +755,15 @@ void Notification::showReplyField() {
|
|||
void Notification::sendReply() {
|
||||
if (!_history) return;
|
||||
|
||||
if (auto manager = ManagerInstance.data()) {
|
||||
auto peerId = _history->peer->id;
|
||||
auto msgId = _item ? _item->id : ShowAtUnreadMsgId;
|
||||
manager->notificationReplied(peerId, msgId, _replyArea->getLastText());
|
||||
auto peerId = _history->peer->id;
|
||||
auto msgId = _item ? _item->id : ShowAtUnreadMsgId;
|
||||
manager()->notificationReplied(peerId, msgId, _replyArea->getLastText());
|
||||
|
||||
manager->startAllHiding();
|
||||
}
|
||||
manager()->startAllHiding();
|
||||
}
|
||||
|
||||
void Notification::changeHeight(int newHeight) {
|
||||
if (auto manager = ManagerInstance.data()) {
|
||||
manager->changeNotificationHeight(this, newHeight);
|
||||
}
|
||||
manager()->changeNotificationHeight(this, newHeight);
|
||||
}
|
||||
|
||||
bool Notification::unlinkHistory(History *history) {
|
||||
|
@ -793,9 +778,7 @@ bool Notification::unlinkHistory(History *history) {
|
|||
|
||||
void Notification::enterEventHook(QEvent *e) {
|
||||
if (!_history) return;
|
||||
if (auto manager = ManagerInstance.data()) {
|
||||
manager->stopAllHiding();
|
||||
}
|
||||
manager()->stopAllHiding();
|
||||
if (!_replyArea && canReply()) {
|
||||
toggleActionButtons(true);
|
||||
}
|
||||
|
@ -803,9 +786,7 @@ void Notification::enterEventHook(QEvent *e) {
|
|||
|
||||
void Notification::leaveEventHook(QEvent *e) {
|
||||
if (!_history) return;
|
||||
if (auto manager = ManagerInstance.data()) {
|
||||
manager->startAllHiding();
|
||||
}
|
||||
manager()->startAllHiding();
|
||||
toggleActionButtons(false);
|
||||
}
|
||||
|
||||
|
@ -821,11 +802,9 @@ void Notification::mousePressEvent(QMouseEvent *e) {
|
|||
unlinkHistoryInManager();
|
||||
} else {
|
||||
e->ignore();
|
||||
if (auto manager = ManagerInstance.data()) {
|
||||
auto peerId = _history->peer->id;
|
||||
auto msgId = _item ? _item->id : ShowAtUnreadMsgId;
|
||||
manager->notificationActivated(peerId, msgId);
|
||||
}
|
||||
auto peerId = _history->peer->id;
|
||||
auto msgId = _item ? _item->id : ShowAtUnreadMsgId;
|
||||
manager()->notificationActivated(peerId, msgId);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -850,13 +829,7 @@ void Notification::onHideByTimer() {
|
|||
startHiding();
|
||||
}
|
||||
|
||||
Notification::~Notification() {
|
||||
if (auto manager = ManagerInstance.data()) {
|
||||
manager->removeFromShown(this);
|
||||
}
|
||||
}
|
||||
|
||||
HideAllButton::HideAllButton(QPoint startPosition, int shift, Direction shiftDirection) : Widget(startPosition, shift, shiftDirection) {
|
||||
HideAllButton::HideAllButton(Manager *manager, QPoint startPosition, int shift, Direction shiftDirection) : Widget(manager, startPosition, shift, shiftDirection) {
|
||||
setCursor(style::cur_pointer);
|
||||
|
||||
auto position = computePosition(st::notifyHideAllHeight);
|
||||
|
@ -885,12 +858,6 @@ void HideAllButton::stopHiding() {
|
|||
hideStop();
|
||||
}
|
||||
|
||||
HideAllButton::~HideAllButton() {
|
||||
if (auto manager = ManagerInstance.data()) {
|
||||
manager->removeHideAll(this);
|
||||
}
|
||||
}
|
||||
|
||||
void HideAllButton::enterEventHook(QEvent *e) {
|
||||
_mouseOver = true;
|
||||
update();
|
||||
|
@ -908,9 +875,7 @@ void HideAllButton::mousePressEvent(QMouseEvent *e) {
|
|||
void HideAllButton::mouseReleaseEvent(QMouseEvent *e) {
|
||||
auto mouseDown = base::take(_mouseDown);
|
||||
if (mouseDown && _mouseOver) {
|
||||
if (auto manager = ManagerInstance.data()) {
|
||||
manager->clearAll();
|
||||
}
|
||||
manager()->clearAll();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -39,18 +39,15 @@ class HideAllButton;
|
|||
} // namespace internal
|
||||
|
||||
class Manager;
|
||||
|
||||
void Start();
|
||||
Manager *GetManager();
|
||||
void Finish();
|
||||
std::unique_ptr<Manager> Create(System *system);
|
||||
|
||||
class Manager : public Notifications::Manager, private base::Subscriber {
|
||||
public:
|
||||
Manager();
|
||||
Manager(System *system);
|
||||
|
||||
template <typename Method>
|
||||
void enumerateNotifications(Method method) {
|
||||
for_const (auto notification, _notifications) {
|
||||
for_const (auto ¬ification, _notifications) {
|
||||
method(notification);
|
||||
}
|
||||
}
|
||||
|
@ -73,25 +70,24 @@ private:
|
|||
|
||||
void showNextFromQueue();
|
||||
void unlinkFromShown(Notification *remove);
|
||||
void removeFromShown(Notification *remove);
|
||||
void removeHideAll(HideAllButton *remove);
|
||||
void startAllHiding();
|
||||
void stopAllHiding();
|
||||
void checkLastInput();
|
||||
|
||||
void removeWidget(internal::Widget *remove);
|
||||
|
||||
float64 demoMasterOpacity() const;
|
||||
void demoMasterOpacityCallback();
|
||||
|
||||
void moveWidgets();
|
||||
void changeNotificationHeight(Notification *widget, int newHeight);
|
||||
void settingsChanged(Notify::ChangeType change);
|
||||
void settingsChanged(ChangeType change);
|
||||
|
||||
bool hasReplyingNotification() const;
|
||||
|
||||
using Notifications = QList<Notification*>;
|
||||
Notifications _notifications;
|
||||
std::vector<std::unique_ptr<Notification>> _notifications;
|
||||
|
||||
HideAllButton *_hideAll = nullptr;
|
||||
std::unique_ptr<HideAllButton> _hideAll;
|
||||
|
||||
bool _positionsOutdated = false;
|
||||
SingleTimer _inputCheckTimer;
|
||||
|
@ -111,8 +107,7 @@ private:
|
|||
HistoryItem *item;
|
||||
int forwardedCount;
|
||||
};
|
||||
using QueuedNotifications = QList<QueuedNotification>;
|
||||
QueuedNotifications _queuedNotifications;
|
||||
std::deque<QueuedNotification> _queuedNotifications;
|
||||
|
||||
Animation _demoMasterOpacity;
|
||||
|
||||
|
@ -126,7 +121,7 @@ public:
|
|||
Up,
|
||||
Down,
|
||||
};
|
||||
Widget(QPoint startPosition, int shift, Direction shiftDirection);
|
||||
Widget(Manager *manager, QPoint startPosition, int shift, Direction shiftDirection);
|
||||
|
||||
bool isShowing() const {
|
||||
return _a_opacity.animating() && !_hiding;
|
||||
|
@ -149,6 +144,11 @@ protected:
|
|||
|
||||
virtual void updateGeometry(int x, int y, int width, int height);
|
||||
|
||||
protected:
|
||||
Manager *manager() const {
|
||||
return _manager;
|
||||
}
|
||||
|
||||
private:
|
||||
void opacityAnimationCallback();
|
||||
void destroyDelayed();
|
||||
|
@ -156,6 +156,8 @@ private:
|
|||
void hideAnimated(float64 duration, const anim::transition &func);
|
||||
void step_shift(float64 ms, bool timer);
|
||||
|
||||
Manager *_manager = nullptr;
|
||||
|
||||
bool _hiding = false;
|
||||
bool _deleted = false;
|
||||
Animation _a_opacity;
|
||||
|
@ -180,7 +182,7 @@ class Notification : public Widget {
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Notification(History *history, PeerData *peer, PeerData *author, HistoryItem *item, int forwardedCount, QPoint startPosition, int shift, Direction shiftDirection);
|
||||
Notification(Manager *manager, History *history, PeerData *peer, PeerData *author, HistoryItem *item, int forwardedCount, QPoint startPosition, int shift, Direction shiftDirection);
|
||||
|
||||
void startHiding();
|
||||
void stopHiding();
|
||||
|
@ -200,8 +202,6 @@ public:
|
|||
bool unlinkHistory(History *history = nullptr);
|
||||
bool checkLastInput(bool hasReplyingNotifications);
|
||||
|
||||
~Notification();
|
||||
|
||||
protected:
|
||||
void enterEventHook(QEvent *e) override;
|
||||
void leaveEventHook(QEvent *e) override;
|
||||
|
@ -260,14 +260,12 @@ private:
|
|||
|
||||
class HideAllButton : public Widget {
|
||||
public:
|
||||
HideAllButton(QPoint startPosition, int shift, Direction shiftDirection);
|
||||
HideAllButton(Manager *manager, QPoint startPosition, int shift, Direction shiftDirection);
|
||||
|
||||
void startHiding();
|
||||
void startHidingFast();
|
||||
void stopHiding();
|
||||
|
||||
~HideAllButton();
|
||||
|
||||
protected:
|
||||
void enterEventHook(QEvent *e) override;
|
||||
void leaveEventHook(QEvent *e) override;
|
||||
|
|
|
@ -112,7 +112,13 @@ void CachedUserpics::onClear() {
|
|||
|
||||
CachedUserpics::~CachedUserpics() {
|
||||
if (_someSavedFlag) {
|
||||
psDeleteDir(cWorkingDir() + qsl("tdata/temp"));
|
||||
TimeMs result = 0;
|
||||
for_const (auto &item, _images) {
|
||||
QFile(item.path).remove();
|
||||
}
|
||||
|
||||
// This works about 1200ms on Windows for a folder with one image O_o
|
||||
// psDeleteDir(cWorkingDir() + qsl("tdata/temp"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
#include "boxes/aboutbox.h"
|
||||
#include "lang.h"
|
||||
#include "core/click_handler_types.h"
|
||||
#include "auth_session.h"
|
||||
|
||||
namespace Window {
|
||||
|
||||
|
@ -70,7 +71,7 @@ MainMenu::MainMenu(QWidget *parent) : TWidget(parent)
|
|||
_version->setLink(1, MakeShared<UrlClickHandler>(qsl("https://desktop.telegram.org/changelog")));
|
||||
_version->setLink(2, MakeShared<LambdaClickHandler>([] { Ui::show(Box<AboutBox>()); }));
|
||||
|
||||
subscribe(FileDownload::ImageLoaded(), [this] { update(); });
|
||||
subscribe(AuthSession::CurrentDownloaderTaskFinished(), [this] { update(); });
|
||||
subscribe(Global::RefConnectionTypeChanged(), [this] { updateConnectionState(); });
|
||||
updateConnectionState();
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue