NB Broken! Notifications refactored to Manager, only Windows working.

This commit is contained in:
John Preston 2016-10-02 16:54:27 +03:00
parent a41e0c4aa7
commit 0bf55835f5
39 changed files with 702 additions and 612 deletions

View File

@ -42,6 +42,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "numbers.h"
#include "observer_peer.h"
#include "window/chat_background.h"
#include "window/notifications_manager.h"
namespace {
App::LaunchState _launchState = App::Launched;
@ -1992,13 +1993,10 @@ namespace {
if (::mousedItem == item) {
mousedItem(nullptr);
}
if (App::wnd()) {
App::wnd()->notifyItemRemoved(item);
}
}
void historyUnregItem(HistoryItem *item) {
MsgsData *data = fetchMsgsData(item->channelId(), false);
auto data = fetchMsgsData(item->channelId(), false);
if (!data) return;
auto i = data->find(item->id);
@ -2014,10 +2012,13 @@ namespace {
std::swap(items, j.value());
::dependentItems.erase(j);
for_const (HistoryItem *dependent, items) {
for_const (auto dependent, items) {
dependent->dependencyItemRemoved(item);
}
}
if (auto manager = Window::Notifications::manager()) {
manager->clearFromItem(item);
}
if (App::main() && !App::quitting()) {
App::main()->itemRemoved(item);
}

View File

@ -35,7 +35,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "core/observer.h"
#include "observer_peer.h"
#include "window/chat_background.h"
#include "window/notifications_abstract_manager.h"
#include "window/notifications_manager.h"
#include "history/history_location_manager.h"
namespace {
@ -333,6 +333,10 @@ void Application::closeApplication() {
if (App::launchState() == App::QuitProcessed) return;
App::setLaunchState(App::QuitProcessed);
if (auto manager = Window::Notifications::manager()) {
manager->clearAllFast();
}
delete AppObject;
AppObject = 0;

View File

@ -375,9 +375,7 @@ enum {
WaitForChannelGetDifference = 1000, // 1s wait after show channel history before sending getChannelDifference
MemoryForImageCache = 64 * 1024 * 1024, // after 64mb of unpacked images we try to clear some memory
NotifyWindowsCount = 3, // 3 desktop notifies at the same time
NotifySettingSaveTimeout = 1000, // wait 1 second before saving notify setting to server
NotifyDeletePhotoAfter = 60000, // delete notify photo after 1 minute
UpdateChunk = 100 * 1024, // 100kb parts when downloading the update
IdleMsecs = 60 * 1000, // after 60secs without user input we think we are idle

View File

@ -479,7 +479,6 @@ void DialogsInner::removeDialog(History *history) {
if (importantDialogs) {
history->removeFromChatList(Dialogs::Mode::Important, importantDialogs.get());
}
history->clearNotifications();
if (App::wnd()) App::wnd()->notifyClear(history);
if (contacts->contains(history->peer->id)) {
if (!contactsNoDialogs->contains(history->peer->id)) {

View File

@ -635,7 +635,6 @@ struct Data {
bool IncludeMuted = true;
DBINotifyView NotifyView = dbinvShowPreview;
bool WindowsNotifications = true;
bool CustomNotifies = (cPlatform() == dbipMac) ? false : true;
base::Observable<Notify::ChangeType> NotifySettingsChanged;
DBIConnectionType ConnectionType = dbictAuto;
@ -743,7 +742,6 @@ DefineVar(Global, bool, RestoreSoundNotifyFromTray);
DefineVar(Global, bool, IncludeMuted);
DefineVar(Global, DBINotifyView, NotifyView);
DefineVar(Global, bool, WindowsNotifications);
DefineVar(Global, bool, CustomNotifies);
DefineRefVar(Global, base::Observable<Notify::ChangeType>, NotifySettingsChanged);
DefineVar(Global, DBIConnectionType, ConnectionType);

View File

@ -149,7 +149,6 @@ enum class ChangeType {
IncludeMuted,
DesktopEnabled,
ViewParams,
UseNative,
};
} // namespace Notify
@ -309,7 +308,6 @@ DeclareVar(bool, RestoreSoundNotifyFromTray);
DeclareVar(bool, IncludeMuted);
DeclareVar(DBINotifyView, NotifyView);
DeclareVar(bool, WindowsNotifications);
DeclareVar(bool, CustomNotifies);
DeclareRefVar(base::Observable<Notify::ChangeType>, NotifySettingsChanged);
DeclareVar(DBIConnectionType, ConnectionType);

View File

@ -1427,7 +1427,6 @@ MsgId History::inboxRead(MsgId upTo) {
showFrom = nullptr;
App::wnd()->notifyClear(this);
clearNotifications();
return upTo;
}

View File

@ -482,19 +482,19 @@ void HistoryMediaPtr::reset(HistoryMedia *p) {
namespace internal {
TextSelection unshiftSelection(TextSelection selection, const Text &byText) {
if (selection == FullSelection) {
return selection;
}
return ::unshiftSelection(selection, byText);
TextSelection unshiftSelection(TextSelection selection, const Text &byText) {
if (selection == FullSelection) {
return selection;
}
return ::unshiftSelection(selection, byText);
}
TextSelection shiftSelection(TextSelection selection, const Text &byText) {
if (selection == FullSelection) {
return selection;
}
return ::shiftSelection(selection, byText);
TextSelection shiftSelection(TextSelection selection, const Text &byText) {
if (selection == FullSelection) {
return selection;
}
return ::shiftSelection(selection, byText);
}
} // namespace internal

View File

@ -436,8 +436,8 @@ private:
namespace internal {
TextSelection unshiftSelection(TextSelection selection, const Text &byText);
TextSelection shiftSelection(TextSelection selection, const Text &byText);
TextSelection unshiftSelection(TextSelection selection, const Text &byText);
TextSelection shiftSelection(TextSelection selection, const Text &byText);
} // namespace internal
@ -837,7 +837,7 @@ public:
void clipCallback(Media::Clip::Notification notification);
virtual ~HistoryItem();
~HistoryItem();
protected:
HistoryItem(History *history, MsgId msgId, MTPDmessage::Flags flags, QDateTime msgDate, int32 from);

View File

@ -995,9 +995,6 @@ bool _readSetting(quint32 blockId, QDataStream &stream, int version) {
if (!_checkStreamStatus(stream)) return false;
Global::SetWindowsNotifications(v == 1);
if (cPlatform() == dbipWindows) {
Global::SetCustomNotifies((App::wnd() ? !App::wnd()->psHasNativeNotifications() : true) || !Global::WindowsNotifications());
}
} break;
case dbiWorkMode: {

View File

@ -43,7 +43,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "localstorage.h"
#include "apiwrap.h"
#include "settings/settings_widget.h"
#include "window/notifications_default_manager.h"
#include "window/notifications_manager.h"
ConnectingWidget::ConnectingWidget(QWidget *parent, const QString &text, const QString &reconnect) : QWidget(parent)
, _shadow(st::boxShadow)
@ -96,8 +96,6 @@ MainWindow::MainWindow() {
notifyClear();
} else if (type == Notify::ChangeType::ViewParams) {
notifyUpdateAll();
} else if (type == Notify::ChangeType::UseNative) {
notifyClearFast();
} else if (type == Notify::ChangeType::IncludeMuted) {
Notify::unreadCounterUpdated();
}
@ -118,14 +116,13 @@ MainWindow::MainWindow() {
_inactiveTimer.setSingleShot(true);
connect(&_inactiveTimer, SIGNAL(timeout()), this, SLOT(onInactiveTimer()));
connect(&notifyWaitTimer, SIGNAL(timeout()), this, SLOT(notifyFire()));
connect(&_notifyWaitTimer, SIGNAL(timeout()), this, SLOT(notifyShowNext()));
_isActiveTimer.setSingleShot(true);
connect(&_isActiveTimer, SIGNAL(timeout()), this, SLOT(updateIsActive()));
connect(&_autoLockTimer, SIGNAL(timeout()), this, SLOT(checkAutoLock()));
subscribe(FileDownload::ImageLoaded(), [this] { notifyUpdateAllPhotos(); });
subscribe(Global::RefSelfChanged(), [this]() { updateGlobalMenu(); });
setAttribute(Qt::WA_NoSystemBackground);
@ -1130,72 +1127,66 @@ void MainWindow::notifySchedule(History *history, HistoryItem *item) {
// LOG(("Is online: %1, otherOnline: %2, currentTime: %3, otherNotOld: %4, otherLaterThanMe: %5").arg(Logs::b(isOnline)).arg(cOtherOnline()).arg(t).arg(Logs::b(otherNotOld)).arg(Logs::b(otherLaterThanMe)));
uint64 when = ms + delay;
notifyWhenAlerts[history].insert(when, notifyByFrom);
_notifyWhenAlerts[history].insert(when, notifyByFrom);
if (Global::DesktopNotify() && !psSkipDesktopNotify()) {
NotifyWhenMaps::iterator i = notifyWhenMaps.find(history);
if (i == notifyWhenMaps.end()) {
i = notifyWhenMaps.insert(history, NotifyWhenMap());
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 *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);
if (!_notifyWaitTimer.isActive() || _notifyWaitTimer.remainingTime() > delay) {
_notifyWaitTimer.start(delay);
}
}
}
void MainWindow::notifyFire() {
notifyShowNext();
}
void MainWindow::notifyClear(History *history) {
if (!history) {
for_const (auto widget, notifyWidgets) {
widget->unlinkHistory();
}
psClearNotifies();
for (NotifyWhenMaps::const_iterator i = notifyWhenMaps.cbegin(), e = notifyWhenMaps.cend(); i != e; ++i) {
Window::Notifications::manager()->clearAll();
for (auto i = _notifyWhenMaps.cbegin(), e = _notifyWhenMaps.cend(); i != e; ++i) {
i.key()->clearNotifications();
}
notifyWaiters.clear();
notifySettingWaiters.clear();
notifyWhenMaps.clear();
_notifyWhenMaps.clear();
_notifyWhenAlerts.clear();
_notifyWaiters.clear();
_notifySettingWaiters.clear();
return;
}
notifyWaiters.remove(history);
notifySettingWaiters.remove(history);
for_const (auto widget, notifyWidgets) {
widget->unlinkHistory(history);
}
psClearNotifies(history);
notifyWhenMaps.remove(history);
notifyWhenAlerts.remove(history);
Window::Notifications::manager()->clearFromHistory(history);
history->clearNotifications();
_notifyWhenMaps.remove(history);
_notifyWhenAlerts.remove(history);
_notifyWaiters.remove(history);
_notifySettingWaiters.remove(history);
_notifyWaitTimer.stop();
notifyShowNext();
}
void MainWindow::notifyClearFast() {
notifyWaiters.clear();
notifySettingWaiters.clear();
for_const (auto widget, notifyWidgets) {
widget->deleteLater();
}
psClearNotifies();
notifyWidgets.clear();
notifyWhenMaps.clear();
notifyWhenAlerts.clear();
Window::Notifications::manager()->clearAllFast();
_notifyWhenMaps.clear();
_notifyWhenAlerts.clear();
_notifyWaiters.clear();
_notifySettingWaiters.clear();
}
void MainWindow::notifySettingGot() {
int32 t = unixtime();
for (NotifyWaiters::iterator i = notifySettingWaiters.begin(); i != notifySettingWaiters.end();) {
for (NotifyWaiters::iterator i = _notifySettingWaiters.begin(); i != _notifySettingWaiters.end();) {
History *history = i.key();
bool loaded = false, muted = false;
if (history->peer->notify != UnknownNotifySettings) {
@ -1224,34 +1215,24 @@ void MainWindow::notifySettingGot() {
}
if (loaded) {
if (!muted) {
notifyWaiters.insert(i.key(), i.value());
_notifyWaiters.insert(i.key(), i.value());
}
i = notifySettingWaiters.erase(i);
i = _notifySettingWaiters.erase(i);
} else {
++i;
}
}
notifyWaitTimer.stop();
_notifyWaitTimer.stop();
notifyShowNext();
}
void MainWindow::notifyShowNext(Window::Notifications::Widget *remove) {
void MainWindow::notifyShowNext() {
if (App::quitting()) return;
int32 count = NotifyWindowsCount;
if (remove) {
for (auto i = notifyWidgets.begin(), e = notifyWidgets.end(); i != e; ++i) {
if ((*i) == remove) {
notifyWidgets.erase(i);
break;
}
}
}
uint64 ms = getms(true), nextAlert = 0;
bool alert = false;
int32 now = unixtime();
for (NotifyWhenAlerts::iterator i = notifyWhenAlerts.begin(); i != notifyWhenAlerts.end();) {
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
@ -1264,7 +1245,7 @@ void MainWindow::notifyShowNext(Window::Notifications::Widget *remove) {
}
}
if (i.value().isEmpty()) {
i = notifyWhenAlerts.erase(i);
i = _notifyWhenAlerts.erase(i);
} else {
if (!nextAlert || nextAlert > i.value().begin().key()) {
nextAlert = i.value().begin().key();
@ -1277,32 +1258,24 @@ void MainWindow::notifyShowNext(Window::Notifications::Widget *remove) {
App::playSound();
}
if (Global::CustomNotifies()) {
for_const (auto widget, notifyWidgets) {
if (widget->index() < 0) continue;
--count;
}
}
if (count <= 0 || notifyWaiters.isEmpty() || !Global::DesktopNotify() || psSkipDesktopNotify()) {
if (_notifyWaiters.isEmpty() || !Global::DesktopNotify() || psSkipDesktopNotify()) {
if (nextAlert) {
notifyWaitTimer.start(nextAlert - ms);
_notifyWaitTimer.start(nextAlert - ms);
}
return;
}
QRect r = psDesktopRect();
int32 x = r.x() + r.width() - st::notifyWidth - st::notifyDeltaX, y = r.y() + r.height() - st::notifyHeight - st::notifyDeltaY;
while (count > 0) {
while (true) {
uint64 next = 0;
HistoryItem *notifyItem = 0;
History *notifyHistory = 0;
for (NotifyWaiters::iterator i = notifyWaiters.begin(); i != notifyWaiters.end();) {
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()) {
NotifyWhenMaps::iterator j = _notifyWhenMaps.find(history);
if (j == _notifyWhenMaps.end()) {
history->clearNotifications();
i = notifyWaiters.erase(i);
i = _notifyWaiters.erase(i);
continue;
}
do {
@ -1316,8 +1289,8 @@ void MainWindow::notifyShowNext(Window::Notifications::Widget *remove) {
} while (history->currentNotification());
}
if (!history->currentNotification()) {
notifyWhenMaps.remove(history);
i = notifyWaiters.erase(i);
_notifyWhenMaps.remove(history);
i = _notifyWaiters.erase(i);
continue;
}
uint64 when = i.value().when;
@ -1334,7 +1307,7 @@ void MainWindow::notifyShowNext(Window::Notifications::Widget *remove) {
next = nextAlert;
nextAlert = 0;
}
notifyWaitTimer.start(next - ms);
_notifyWaitTimer.start(next - ms);
break;
} else {
HistoryItem *fwd = notifyItem->Has<HistoryMessageForwarded>() ? notifyItem : nullptr; // forwarded notify grouping
@ -1342,8 +1315,8 @@ void MainWindow::notifyShowNext(Window::Notifications::Widget *remove) {
uint64 ms = getms(true);
History *history = notifyItem->history();
NotifyWhenMaps::iterator j = notifyWhenMaps.find(history);
if (j == notifyWhenMaps.cend()) {
NotifyWhenMaps::iterator j = _notifyWhenMaps.find(history);
if (j == _notifyWhenMaps.cend()) {
history->clearNotifications();
} else {
HistoryItem *nextNotify = 0;
@ -1358,7 +1331,7 @@ void MainWindow::notifyShowNext(Window::Notifications::Widget *remove) {
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));
_notifyWaiters.insert(notifyHistory, NotifyWaiter(k.key(), k.value(), 0));
break;
}
history->skipNotification();
@ -1379,18 +1352,11 @@ void MainWindow::notifyShowNext(Window::Notifications::Widget *remove) {
} while (nextNotify);
}
if (Global::CustomNotifies()) {
auto widget = new Window::Notifications::Widget(notifyItem, x, y, fwdCount);
notifyWidgets.push_back(widget);
psNotifyShown(widget);
--count;
} else {
psPlatformNotify(notifyItem, fwdCount);
}
Window::Notifications::manager()->showNotification(notifyItem, fwdCount);
if (!history->hasNotification()) {
notifyWaiters.remove(history);
notifyWhenMaps.remove(history);
_notifyWaiters.remove(history);
_notifyWhenMaps.remove(history);
continue;
}
}
@ -1399,48 +1365,8 @@ void MainWindow::notifyShowNext(Window::Notifications::Widget *remove) {
}
}
if (nextAlert) {
notifyWaitTimer.start(nextAlert - ms);
_notifyWaitTimer.start(nextAlert - ms);
}
count = NotifyWindowsCount - count;
for_const (auto widget, notifyWidgets) {
if (widget->index() < 0) continue;
--count;
widget->moveTo(x, y - count * (st::notifyHeight + st::notifyDeltaY));
}
}
void MainWindow::notifyItemRemoved(HistoryItem *item) {
if (Global::CustomNotifies()) {
for_const (auto widget, notifyWidgets) {
widget->itemRemoved(item);
}
}
}
void MainWindow::notifyStopHiding() {
if (Global::CustomNotifies()) {
for_const (auto widget, notifyWidgets) {
widget->stopHiding();
}
}
}
void MainWindow::notifyStartHiding() {
if (Global::CustomNotifies()) {
for_const (auto widget, notifyWidgets) {
widget->startHiding();
}
}
}
void MainWindow::notifyUpdateAllPhotos() {
if (Global::CustomNotifies()) {
for_const (auto widget, notifyWidgets) {
widget->updatePeerPhoto();
}
}
if (_mediaView && !_mediaView->isHidden()) _mediaView->updateControls();
}
void MainWindow::app_activateClickHandler(ClickHandlerPtr handler, Qt::MouseButton button) {
@ -1448,20 +1374,7 @@ void MainWindow::app_activateClickHandler(ClickHandlerPtr handler, Qt::MouseButt
}
void MainWindow::notifyUpdateAll() {
if (Global::CustomNotifies()) {
for_const (auto widget, notifyWidgets) {
widget->updateNotifyDisplay();
}
}
psClearNotifies();
}
void MainWindow::notifyActivateAll() {
if (Global::CustomNotifies()) {
for_const (auto widget, notifyWidgets) {
psActivateNotify(widget);
}
}
Window::Notifications::manager()->updateAll();
}
QImage MainWindow::iconLarge() const {

View File

@ -43,7 +43,9 @@ class Widget;
namespace Window {
namespace Notifications {
namespace Default {
class Widget;
} // namespace Default
} // namespace Notifications
} // namespace Window
@ -150,12 +152,7 @@ public:
void notifySchedule(History *history, HistoryItem *item);
void notifyClear(History *history = 0);
void notifyClearFast();
void notifyShowNext(Window::Notifications::Widget *remove = 0);
void notifyItemRemoved(HistoryItem *item);
void notifyStopHiding();
void notifyStartHiding();
void notifyUpdateAll();
void notifyActivateAll();
QImage iconLarge() const;
@ -212,7 +209,7 @@ public slots:
void onClearFinished(int task, void *manager);
void onClearFailed(int task, void *manager);
void notifyFire();
void notifyShowNext();
void updateTrayMenu(bool force = false);
void onShowAddContact();
@ -224,8 +221,6 @@ public slots:
void onReActivate();
void notifyUpdateAllPhotos();
void app_activateClickHandler(ClickHandlerPtr handler, Qt::MouseButton button);
signals:
@ -277,27 +272,27 @@ private:
SingleTimer _autoLockTimer;
uint64 _shouldLockAt = 0;
typedef QMap<MsgId, uint64> NotifyWhenMap;
typedef QMap<History*, NotifyWhenMap> NotifyWhenMaps;
NotifyWhenMaps notifyWhenMaps;
using NotifyWhenMap = QMap<MsgId, uint64>;
using NotifyWhenMaps = QMap<History*, NotifyWhenMap>;
NotifyWhenMaps _notifyWhenMaps;
struct NotifyWaiter {
NotifyWaiter(MsgId msg, uint64 when, PeerData *notifyByFrom) : msg(msg), when(when), notifyByFrom(notifyByFrom) {
NotifyWaiter(MsgId msg, uint64 when, PeerData *notifyByFrom)
: msg(msg)
, when(when)
, notifyByFrom(notifyByFrom) {
}
MsgId msg;
uint64 when;
PeerData *notifyByFrom;
};
typedef QMap<History*, NotifyWaiter> NotifyWaiters;
NotifyWaiters notifyWaiters;
NotifyWaiters notifySettingWaiters;
SingleTimer notifyWaitTimer;
using NotifyWaiters = QMap<History*, NotifyWaiter>;
NotifyWaiters _notifyWaiters;
NotifyWaiters _notifySettingWaiters;
SingleTimer _notifyWaitTimer;
typedef QMap<uint64, PeerData*> NotifyWhenAlert;
typedef QMap<History*, NotifyWhenAlert> NotifyWhenAlerts;
NotifyWhenAlerts notifyWhenAlerts;
using NotifyWidgets = QList<Window::Notifications::Widget*>;
NotifyWidgets notifyWidgets;
using NotifyWhenAlert = QMap<uint64, PeerData*>;
using NotifyWhenAlerts = QMap<History*, NotifyWhenAlert>;
NotifyWhenAlerts _notifyWhenAlerts;
MediaView *_mediaView = nullptr;

View File

@ -97,6 +97,12 @@ MediaView::MediaView() : TWidget(App::wnd())
connect(QApplication::desktop(), SIGNAL(resized(int)), this, SLOT(onScreenResized(int)));
subscribe(FileDownload::ImageLoaded(), [this] {
if (!isHidden()) {
updateControls();
}
});
_transparentBrush = QBrush(App::sprite().copy(st::mvTransparentBrush.rect()));
setWindowFlags(Qt::FramelessWindowHint | Qt::BypassWindowManagerHint | Qt::Tool | Qt::NoDropShadowWindowHint);

View File

@ -33,7 +33,7 @@ class PopupMenu;
struct AudioPlaybackState;
class MediaView : public TWidget, public RPCSender, public ClickHandlerHost {
class MediaView : public TWidget, private base::Subscriber, public RPCSender, public ClickHandlerHost {
Q_OBJECT
public:

View File

@ -663,18 +663,6 @@ void MainWindow::psUpdateMargins() {
void MainWindow::psFlash() {
}
void MainWindow::psActivateNotify(Window::Notifications::Widget *w) {
}
void MainWindow::psClearNotifies(PeerId peerId) {
}
void MainWindow::psNotifyShown(Window::Notifications::Widget *w) {
}
void MainWindow::psPlatformNotify(HistoryItem *item, int32 fwdCount) {
}
MainWindow::~MainWindow() {
if (_trayIcon) {
Libs::g_object_unref(_trayIcon);

View File

@ -22,12 +22,6 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "window/main_window.h"
namespace Window {
namespace Notifications {
class Widget;
} // namespace Notifications
} // namespace Window
namespace Platform {
class MainWindow : public Window::MainWindow {
@ -62,11 +56,6 @@ public:
return posInited;
}
void psActivateNotify(Window::Notifications::Widget *w);
void psClearNotifies(PeerId peerId = 0);
void psNotifyShown(Window::Notifications::Widget *w);
void psPlatformNotify(HistoryItem *item, int32 fwdCount);
void psUpdateCounter();
bool psHasNativeNotifications() {

View File

@ -27,7 +27,7 @@ namespace Notifications {
void start() {
}
Window::Notifications::AbstractManager *manager() {
Window::Notifications::Manager *manager() {
return nullptr;
}

View File

@ -20,14 +20,17 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
#include "window/notifications_abstract_manager.h"
#include "window/notifications_manager.h"
namespace Platform {
namespace Notifications {
void start();
Window::Notifications::AbstractManager *manager();
Window::Notifications::Manager *manager();
void finish();
inline void defaultNotificationShown(QWidget *widget) {
}
} // namespace Notifications
} // namespace Platform

View File

@ -23,12 +23,6 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "window/main_window.h"
#include "pspecific_mac_p.h"
namespace Window {
namespace Notifications {
class Widget;
} // namespace Notifications
} // namespace Window
namespace Platform {
class MacPrivate : public PsMacWindowPrivate {
@ -74,11 +68,6 @@ public:
bool psFilterNativeEvent(void *event);
void psActivateNotify(Window::Notifications::Widget *w);
void psClearNotifies(PeerId peerId = 0);
void psNotifyShown(Window::Notifications::Widget *w);
void psPlatformNotify(HistoryItem *item, int32 fwdCount);
bool eventFilter(QObject *obj, QEvent *evt) override;
void psUpdateCounter();

View File

@ -24,7 +24,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "playerwidget.h"
#include "historywidget.h"
#include "localstorage.h"
#include "window/notifications_default_manager.h"
#include "window/notifications_manager_default.h"
#include "lang.h"
@ -37,8 +37,10 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
namespace Platform {
void MacPrivate::activeSpaceChanged() {
if (App::wnd()) {
App::wnd()->notifyActivateAll();
if (auto manager = Window::Notifications::Default::manager()) {
manager->enumerateWidgets([](QWidget *widget) {
objc_activateWnd(widget->winId());
});
}
}
@ -464,36 +466,10 @@ void MainWindow::psFlash() {
_private.startBounce();
}
void MainWindow::psClearNotifies(PeerId peerId) {
_private.clearNotifies(peerId);
}
void MainWindow::psActivateNotify(Window::Notifications::Widget *w) {
objc_activateWnd(w->winId());
}
bool MainWindow::psFilterNativeEvent(void *event) {
return _private.filterNativeEvent(event);
}
void MainWindow::psNotifyShown(Window::Notifications::Widget *w) {
w->hide();
objc_holdOnTop(w->winId());
w->show();
psShowOverAll(w, false);
}
void MainWindow::psPlatformNotify(HistoryItem *item, int32 fwdCount) {
QString title = (!App::passcoded() && Global::NotifyView() <= dbinvShowName && !Global::ScreenIsLocked()) ? item->history()->peer->name : qsl("Telegram Desktop");
QString subtitle = (!App::passcoded() && Global::NotifyView() <= dbinvShowName && !Global::ScreenIsLocked()) ? item->notificationHeader() : QString();
QPixmap pix = (!App::passcoded() && Global::NotifyView() <= dbinvShowName && !Global::ScreenIsLocked()) ? item->history()->peer->genUserpic(st::notifyMacPhotoSize) : QPixmap();
QString msg = (!App::passcoded() && Global::NotifyView() <= dbinvShowPreview && !Global::ScreenIsLocked()) ? (fwdCount < 2 ? item->notificationText() : lng_forward_messages(lt_count, fwdCount)) : lang(lng_notification_preview);
bool withReply = !App::passcoded() && (Global::NotifyView() <= dbinvShowPreview && !Global::ScreenIsLocked()) && item->history()->peer->canWrite();
_private.showNotify(item->history()->peer->id, item->id, pix, title, subtitle, msg, withReply);
}
bool MainWindow::eventFilter(QObject *obj, QEvent *evt) {
QEvent::Type t = evt->type();
if (t == QEvent::FocusIn || t == QEvent::FocusOut) {

View File

@ -20,14 +20,31 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
#include "window/notifications_abstract_manager.h"
#include "window/notifications_manager.h"
namespace Platform {
namespace Notifications {
void start();
Window::Notifications::AbstractManager *manager();
Window::Notifications::Manager *manager();
void finish();
void defaultNotificationShown(QWidget *widget);
class Manager : public Window::Notifications::NativeManager {
public:
Manager();
~Manager();
private:
void doShowNativeNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, bool showUserpic, const QString &msg, bool showReplyButton) override;
void doClearAllFast() override;
void doClearFromHistory(History *history) override;
class Impl;
std_::unique_ptr<Impl> _impl;
};
} // namespace Notifications
} // namespace Platform

View File

@ -21,18 +21,103 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "stdafx.h"
#include "platform/mac/notifications_manager_mac.h"
#include "pspecific.h"
namespace Platform {
namespace Notifications {
void start() {
}
Window::Notifications::AbstractManager *manager() {
Window::Notifications::Manager *manager() {
return nullptr;
}
void finish() {
}
void defaultNotificationShown(QWidget *widget) {
widget->hide();
objc_holdOnTop(widget->winId());
widget->show();
psShowOverAll(w, false);
}
class Manager::Impl {
public:
void showNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, bool showUserpic, const QString &msg, bool showReplyButton);
void clearAll();
void clearFromHistory(History *history);
~Impl();
private:
};
void Manager::Impl::showNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, bool showUserpic, const QString &msg, bool showReplyButton) {
auto notification = [[NSUserNotification alloc] init];
[notification setUserInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithUnsignedLongLong:peer->id],@"peer",[NSNumber numberWithInt:msgId],@"msgid",[NSNumber numberWithUnsignedLongLong:Global::LaunchId()],@"launch",nil]];
[notification setTitle:QNSString(title).s()];
[notification setSubtitle:QNSString(subtitle).s()];
[notification setInformativeText:QNSString(msg).s()];
if (showUserpic && [notification respondsToSelector:@selector(setContentImage:)]) {
auto userpic = peer->genUserpic(st::notifyMacPhotoSize);
auto img = qt_mac_create_nsimage(userpic);
[notification setContentImage:img];
[img release];
}
if (showReplyButton && [notification respondsToSelector:@selector(setHasReplyButton:)]) {
[notification setHasReplyButton:YES];
}
[notification setSoundName:nil];
auto center = [NSUserNotificationCenter defaultUserNotificationCenter];
[center deliverNotification:notification];
[notification release];
}
void Manager::Impl::clearAll() {
auto center = [NSUserNotificationCenter defaultUserNotificationCenter];
[center removeAllDeliveredNotifications];
}
void Manager::Impl::clearFromHistory(History *history) {
unsigned long long peerId = history->peer->id;
auto center = [NSUserNotificationCenter defaultUserNotificationCenter];
auto notificationsList = [center deliveredNotifications];
for (id notify in notificationsList) {
auto notifyUserInfo = [notify userInfo];
auto notifyPeerId = [[notifyUserInfo objectForKey:@"peer"] unsignedLongLongValue];
auto notifyLaunchId = [[notifyUserInfo objectForKey:@"launch"] unsignedLongLongValue];
if (notifyPeerId == peerId && notifyLaunchId == Global::LaunchId()) {
[center removeDeliveredNotification:notify];
}
}
}
Manager::Manager() : _impl(std_::make_unique<Impl>()) {
}
Manager::~Manager() = default;
void Manager::doShowNativeNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, bool showUserpic, const QString &msg, bool showReplyButton) {
_impl->showNotification(peer, msgId, title, subtitle, showUserpic, msg, showReplyButton);
}
void Manager::doClearAllFast() {
_impl->clearAll();
}
void Manager::doClearFromHistory(History *history) {
_impl->clearFromHistory(history);
}
} // namespace Notifications
} // namespace Platform

View File

@ -24,7 +24,6 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#ifdef Q_OS_MAC
namespace Platform {
namespace FileDialog {
inline bool Supported() {
return false;

View File

@ -21,7 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#pragma once
#ifdef Q_OS_MAC
#include "platform/winrt/notifications_manager_mac.h"
#include "platform/mac/notifications_manager_mac.h"
#elif defined Q_OS_LINUX // Q_OS_MAC
#include "platform/linux/notifications_manager_linux.h"
#elif defined Q_OS_WINRT // Q_OS_MAC || Q_OS_LINUX

View File

@ -23,7 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "platform/win/windows_toasts.h"
#include "platform/win/windows_dlls.h"
#include "window/notifications_abstract_manager.h"
#include "window/notifications_manager.h"
#include "mainwindow.h"
#include "application.h"
#include "lang.h"
@ -617,7 +617,6 @@ MainWindow::MainWindow()
if (!_taskbarCreatedMsgId) {
_taskbarCreatedMsgId = RegisterWindowMessage(L"TaskbarButtonCreated");
}
connect(&ps_cleanNotifyPhotosTimer, SIGNAL(timeout()), this, SLOT(psCleanNotifyPhotos()));
}
void MainWindow::TaskbarCreated() {
@ -644,22 +643,6 @@ void MainWindow::psShowTrayMenu() {
trayIconMenu->popup(QCursor::pos());
}
void MainWindow::psCleanNotifyPhotosIn(int32 dt) {
if (dt < 0) {
if (ps_cleanNotifyPhotosTimer.isActive() && ps_cleanNotifyPhotosTimer.remainingTime() <= -dt) return;
dt = -dt;
}
ps_cleanNotifyPhotosTimer.start(dt);
}
void MainWindow::psCleanNotifyPhotos() {
auto ms = getms(true);
auto minuntil = Toasts::clearImages(ms);
if (minuntil) {
psCleanNotifyPhotosIn(int32(minuntil - ms));
}
}
void MainWindow::psRefreshTaskbarIcon() {
QWidget *w = new QWidget(this);
w->setWindowFlags(::operator|(Qt::Tool, Qt::FramelessWindowHint));
@ -879,17 +862,11 @@ void MainWindow::psUpdatedPosition() {
}
bool MainWindow::psHasNativeNotifications() {
return Toasts::supported();
return (Toasts::manager() != nullptr);
}
Q_DECLARE_METATYPE(QMargins);
void MainWindow::psFirstShow() {
if (Toasts::supported()) {
Global::SetCustomNotifies(!Global::WindowsNotifications());
} else {
Global::SetCustomNotifies(true);
}
_psShadowWindows.init(_shActive);
_shadowsWorking = true;
@ -1074,22 +1051,4 @@ MainWindow::~MainWindow() {
if (ps_tbHider_hWnd) DestroyWindow(ps_tbHider_hWnd);
}
void MainWindow::psActivateNotify(Window::Notifications::Widget *w) {
}
void MainWindow::psClearNotifies(History *history) {
if (history) {
Window::Notifications::manager()->clearFromHistory(history);
} else {
Window::Notifications::manager()->clearAllFast();
}
}
void MainWindow::psNotifyShown(Window::Notifications::Widget *w) {
}
void MainWindow::psPlatformNotify(HistoryItem *item, int32 fwdCount) {
Window::Notifications::manager()->showNotification(item, fwdCount);
}
} // namespace Platform

View File

@ -25,12 +25,6 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
class PopupMenu;
namespace Window {
namespace Notifications {
class Widget;
} // namespace Notifications
} // namespace Window
namespace Platform {
class MainWindow : public Window::MainWindow {
@ -67,15 +61,9 @@ public:
return posInited;
}
void psActivateNotify(Window::Notifications::Widget *w);
void psClearNotifies(History *history = nullptr);
void psNotifyShown(Window::Notifications::Widget *w);
void psPlatformNotify(HistoryItem *item, int32 fwdCount);
void psUpdateCounter();
bool psHasNativeNotifications();
void psCleanNotifyPhotosIn(int32 dt);
virtual QImage iconWithCounter(int size, int count, style::color bg, bool smallIcon) = 0;
@ -111,15 +99,11 @@ public:
~MainWindow();
public slots:
void psUpdateDelegate();
void psSavePosition(Qt::WindowState state = Qt::WindowActive);
void psShowTrayMenu();
void psCleanNotifyPhotos();
protected:
bool psHasTrayIcon() const {
return trayIcon;
}
@ -150,8 +134,6 @@ private:
HICON ps_iconSmall = nullptr;
HICON ps_iconOverlay = nullptr;
SingleTimer ps_cleanNotifyPhotosTimer;
int _deltaLeft = 0;
int _deltaTop = 0;

View File

@ -25,26 +25,20 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
namespace Platform {
namespace Notifications {
namespace {
NeverFreedPointer<Toasts::Manager> ToastsManager;
} // namespace
void start() {
Toasts::start();
}
Window::Notifications::AbstractManager *manager() {
if (Toasts::supported()) {
ToastsManager.makeIfNull();
return ToastsManager.data();
Window::Notifications::Manager *manager() {
if (Global::WindowsNotifications()) {
return Toasts::manager();
}
return nullptr;
}
void finish() {
ToastsManager.reset();
Toasts::finish();
}
} // namespace Notifications

View File

@ -20,14 +20,17 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
#include "window/notifications_abstract_manager.h"
#include "window/notifications_manager.h"
namespace Platform {
namespace Notifications {
void start();
Window::Notifications::AbstractManager *manager();
Window::Notifications::Manager *manager();
void finish();
inline void defaultNotificationShown(QWidget *widget) {
}
} // namespace Notifications
} // namespace Platform

View File

@ -47,7 +47,10 @@ namespace Platform {
namespace Toasts {
namespace {
bool _supported = false;
// Delete notify photo file after 1 minute of not using.
constexpr int kNotifyDeletePhotoAfterMs = 60000;
NeverFreedPointer<Manager> ToastsManager;
ComPtr<IToastNotificationManagerStatics> _notificationManager;
ComPtr<IToastNotifier> _notifier;
@ -357,14 +360,18 @@ QString getImage(const StorageKey &key, PeerData *peer) {
auto i = _images.find(key);
if (i != _images.cend()) {
if (i->until) {
i->until = ms + NotifyDeletePhotoAfter;
if (App::wnd()) App::wnd()->psCleanNotifyPhotosIn(-NotifyDeletePhotoAfter);
i->until = ms + kNotifyDeletePhotoAfterMs;
if (auto manager = ToastsManager.data()) {
manager->clearNotifyPhotosInMs(-kNotifyDeletePhotoAfterMs);
}
}
} else {
Image v;
if (key.first) {
v.until = ms + NotifyDeletePhotoAfter;
if (App::wnd()) App::wnd()->psCleanNotifyPhotosIn(-NotifyDeletePhotoAfter);
v.until = ms + kNotifyDeletePhotoAfterMs;
if (auto manager = ToastsManager.data()) {
manager->clearNotifyPhotosInMs(-kNotifyDeletePhotoAfterMs);
}
} else {
v.until = 0;
}
@ -383,14 +390,17 @@ QString getImage(const StorageKey &key, PeerData *peer) {
} // namespace
void start() {
_supported = init();
if (init()) {
ToastsManager.makeIfNull();
}
}
Manager *manager() {
return ToastsManager.data();
}
void finish() {
}
bool supported() {
return _supported;
ToastsManager.reset();
}
uint64 clearImages(uint64 ms) {
@ -417,12 +427,15 @@ uint64 clearImages(uint64 ms) {
class Manager::Impl {
public:
bool create(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, bool showUserpic, const QString &msg, bool showReplyButton);
void clear(History *history, bool fast);
bool showNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, bool showUserpic, const QString &msg, bool showReplyButton);
void clearAll();
void clearFromHistory(History *history);
~Impl();
private:
QTimer _clearNotifyPhotosTimer;
friend class Manager;
};
@ -437,31 +450,33 @@ Manager::Impl::~Impl() {
}
}
void Manager::Impl::clear(History *history, bool fast) {
void Manager::Impl::clearAll() {
if (!_notifier) return;
if (history) {
auto i = _notifications.find(history->peer->id);
if (i != _notifications.cend()) {
auto temp = createAndSwap(i.value());
_notifications.erase(i);
for (auto j = temp.cbegin(), e = temp.cend(); j != e; ++j) {
_notifier->Hide(j->p.Get());
}
}
} else {
auto temp = createAndSwap(_notifications);
for_const (auto &notifications, temp) {
for_const (auto &notification, notifications) {
_notifier->Hide(notification.p.Get());
}
auto temp = createAndSwap(_notifications);
for_const (auto &notifications, temp) {
for_const (auto &notification, notifications) {
_notifier->Hide(notification.p.Get());
}
}
}
bool Manager::Impl::create(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, bool showUserpic, const QString &msg, bool showReplyButton) {
if (!supported() || !_notificationManager || !_notifier || !_notificationFactory) return false;
void Manager::Impl::clearFromHistory(History *history) {
if (!_notifier) return;
auto i = _notifications.find(history->peer->id);
if (i != _notifications.cend()) {
auto temp = createAndSwap(i.value());
_notifications.erase(i);
for (auto j = temp.cbegin(), e = temp.cend(); j != e; ++j) {
_notifier->Hide(j->p.Get());
}
}
}
bool Manager::Impl::showNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, bool showUserpic, const QString &msg, bool showReplyButton) {
if (!_notificationManager || !_notifier || !_notificationFactory) return false;
ComPtr<IXmlDocument> toastXml;
bool withSubtitle = !subtitle.isEmpty();
@ -564,16 +579,39 @@ bool Manager::Impl::create(PeerData *peer, MsgId msgId, const QString &title, co
}
Manager::Manager() : _impl(std_::make_unique<Impl>()) {
connect(&_impl->_clearNotifyPhotosTimer, SIGNAL(timeout()), this, SLOT(onClearNotifyPhotos()));
}
void Manager::clearNotifyPhotosInMs(int ms) {
if (ms < 0) {
ms = -ms;
if (_impl->_clearNotifyPhotosTimer.isActive() && _impl->_clearNotifyPhotosTimer.remainingTime() <= ms) {
return;
}
}
_impl->_clearNotifyPhotosTimer.start(ms);
}
void Manager::onClearNotifyPhotos() {
auto ms = getms(true);
auto minuntil = Toasts::clearImages(ms);
if (minuntil) {
clearNotifyPhotosInMs(int32(minuntil - ms));
}
}
Manager::~Manager() = default;
void Manager::create(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, bool showUserpic, const QString &msg, bool showReplyButton) {
_impl->create(peer, msgId, title, subtitle, showUserpic, msg, showReplyButton);
void Manager::doShowNativeNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, bool showUserpic, const QString &msg, bool showReplyButton) {
_impl->showNotification(peer, msgId, title, subtitle, showUserpic, msg, showReplyButton);
}
void Manager::clear(History *history, bool fast) {
return _impl->clear(history, fast);
void Manager::doClearAllFast() {
_impl->clearAll();
}
void Manager::doClearFromHistory(History *history) {
_impl->clearFromHistory(history);
}
} // namespace Toasts

View File

@ -20,26 +20,37 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
#include "window/notifications_abstract_manager.h"
#include "window/notifications_manager.h"
namespace Platform {
namespace Toasts {
class Manager;
void start();
bool supported();
Manager *manager();
void finish();
// Returns the next ms when clearImages() should be called.
uint64 clearImages(uint64 ms);
class Manager : public Window::Notifications::AbstractManager {
class Manager : public QObject, public Window::Notifications::NativeManager {
Q_OBJECT
public:
Manager();
void clearNotifyPhotosInMs(int ms);
~Manager();
private slots:
void onClearNotifyPhotos();
private:
void create(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, bool showUserpic, const QString &msg, bool showReplyButton) override;
void clear(History *history, bool fast) override;
void doShowNativeNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, bool showUserpic, const QString &msg, bool showReplyButton) override;
void doClearAllFast() override;
void doClearFromHistory(History *history) override;
class Impl;
std_::unique_ptr<Impl> _impl;

View File

@ -1,17 +1,17 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
@ -29,9 +29,6 @@ public:
void updateDelegate();
void showNotify(uint64 peer, int32 msgId, const QPixmap &pix, const QString &title, const QString &subtitle, const QString &msg, bool withReply);
void clearNotifies(uint64 peer = 0);
void enableShadow(WId winId);
bool filterNativeEvent(void *event);

View File

@ -293,33 +293,6 @@ void objc_activateWnd(WId winId) {
NSImage *qt_mac_create_nsimage(const QPixmap &pm);
void PsMacWindowPrivate::showNotify(uint64 peer, int32 msgId, const QPixmap &pix, const QString &title, const QString &subtitle, const QString &msg, bool withReply) {
NSUserNotification *notification = [[NSUserNotification alloc] init];
NSImage *img = qt_mac_create_nsimage(pix);
DEBUG_LOG(("Sending notification with userinfo: peer %1, msgId %2 and instance %3").arg(peer).arg(msgId).arg(Global::LaunchId()));
[notification setUserInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithUnsignedLongLong:peer],@"peer",[NSNumber numberWithInt:msgId],@"msgid",[NSNumber numberWithUnsignedLongLong:Global::LaunchId()],@"launch",nil]];
[notification setTitle:QNSString(title).s()];
[notification setSubtitle:QNSString(subtitle).s()];
[notification setInformativeText:QNSString(msg).s()];
if ([notification respondsToSelector:@selector(setContentImage:)]) {
[notification setContentImage:img];
}
if (withReply && [notification respondsToSelector:@selector(setHasReplyButton:)]) {
[notification setHasReplyButton:YES];
}
[notification setSoundName:nil];
NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter];
[center deliverNotification:notification];
if (img) [img release];
[notification release];
}
void PsMacWindowPrivate::enableShadow(WId winId) {
// [[(NSView*)winId window] setStyleMask:NSBorderlessWindowMask];
// [[(NSView*)winId window] setHasShadow:YES];
@ -359,22 +332,6 @@ bool PsMacWindowPrivate::filterNativeEvent(void *event) {
return false;
}
void PsMacWindowPrivate::clearNotifies(unsigned long long peer) {
NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter];
if (peer) {
NSArray *notifies = [center deliveredNotifications];
for (id notify in notifies) {
NSDictionary *dict = [notify userInfo];
if ([[dict objectForKey:@"peer"] unsignedLongLongValue] == peer && [[dict objectForKey:@"launch"] unsignedLongLongValue] == Global::LaunchId()) {
[center removeDeliveredNotification:notify];
}
}
} else {
[center removeAllDeliveredNotifications];
}
}
void objc_debugShowAlert(const QString &str) {
[[NSAlert alertWithMessageText:@"Debug Message" defaultButton:@"OK" alternateButton:nil otherButton:nil informativeTextWithFormat:@"%@", QNSString(str).s()] runModal];
}

View File

@ -27,6 +27,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "ui/widgets/widget_slide_wrap.h"
#include "ui/flatcheckbox.h"
#include "mainwindow.h"
#include "window/notifications_manager.h"
namespace Settings {
@ -132,16 +133,13 @@ void NotificationsWidget::viewParamUpdated() {
}
void NotificationsWidget::onWindowsNative() {
#ifdef Q_OS_WIN
if (Global::WindowsNotifications() == _windowsNative->checked()) {
return;
}
Window::Notifications::manager()->clearAllFast();
Global::SetWindowsNotifications(_windowsNative->checked());
Global::SetCustomNotifies(!Global::WindowsNotifications());
Local::writeUserSettings();
Global::RefNotifySettingsChanged().notify(Notify::ChangeType::UseNative);
#endif // Q_OS_WIN
}
void NotificationsWidget::onPlaySound() {

View File

@ -1,46 +0,0 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
namespace Window {
namespace Notifications {
class AbstractManager;
void start();
AbstractManager *manager();
void finish();
class AbstractManager {
public:
void showNotification(HistoryItem *item, int forwardedCount);
void clearAllFast();
void clearAll();
void clearFromHistory(History *history);
private:
virtual void create(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, bool showUserpic, const QString &msg, bool showReplyButton) = 0;
virtual void clear(History *history, bool fast) = 0;
};
} // namespace Notifications
} // namespace Window

View File

@ -19,38 +19,33 @@ Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "window/notifications_abstract_manager.h"
#include "window/notifications_manager.h"
#include "platform/platform_notifications_manager.h"
#include "window/notifications_default_manager.h"
#include "window/notifications_manager_default.h"
#include "lang.h"
namespace Window {
namespace Notifications {
namespace {
NeverFreedPointer<DefaultManager> FallbackManager;
} // namespace
void start() {
Default::start();
Platform::Notifications::start();
}
AbstractManager *manager() {
Manager *manager() {
if (auto result = Platform::Notifications::manager()) {
return result;
}
FallbackManager.makeIfNull();
return FallbackManager.data();
return Default::manager();
}
void finish() {
Platform::Notifications::finish();
FallbackManager.reset();
Default::finish();
}
void AbstractManager::showNotification(HistoryItem *item, int forwardedCount) {
void NativeManager::doShowNotification(HistoryItem *item, int forwardedCount) {
auto hideEverything = (App::passcoded() || Global::ScreenIsLocked());
auto hideName = hideEverything || (Global::NotifyView() > dbinvShowName);
auto hidePreview = hideEverything || (Global::NotifyView() > dbinvShowPreview);
@ -62,19 +57,7 @@ void AbstractManager::showNotification(HistoryItem *item, int forwardedCount) {
QString msg = hidePreview ? lang(lng_notification_preview) : (forwardedCount < 2 ? item->notificationText() : lng_forward_messages(lt_count, forwardedCount));
bool showReplyButton = hidePreview ? false : item->history()->peer->canWrite();
create(item->history()->peer, item->id, title, subtitle, showUserpic, msg, showReplyButton);
}
void AbstractManager::clearAllFast() {
clear(nullptr, true);
}
void AbstractManager::clearAll() {
clear(nullptr, false);
}
void AbstractManager::clearFromHistory(History *history) {
clear(history, false);
doShowNativeNotification(item->history()->peer, item->id, title, subtitle, showUserpic, msg, showReplyButton);
}
} // namespace Notifications

View File

@ -0,0 +1,80 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
namespace Window {
namespace Notifications {
class Manager;
void start();
Manager *manager();
void finish();
class Manager {
public:
void showNotification(HistoryItem *item, int forwardedCount) {
doShowNotification(item, forwardedCount);
}
void updateAll() {
doUpdateAll();
}
void clearAll() {
doClearAll();
}
void clearAllFast() {
doClearAllFast();
}
void clearFromItem(HistoryItem *item) {
doClearFromItem(item);
}
void clearFromHistory(History *history) {
doClearFromHistory(history);
}
protected:
virtual void doUpdateAll() = 0;
virtual void doShowNotification(HistoryItem *item, int forwardedCount) = 0;
virtual void doClearAll() = 0;
virtual void doClearAllFast() = 0;
virtual void doClearFromItem(HistoryItem *item) = 0;
virtual void doClearFromHistory(History *history) = 0;
};
class NativeManager : public Manager {
protected:
void doUpdateAll() override {
doClearAllFast();
}
void doClearAll() override {
doClearAllFast();
}
void doClearFromItem(HistoryItem *item) override {
}
void doShowNotification(HistoryItem *item, int forwardedCount) override;
virtual void doShowNativeNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, bool showUserpic, const QString &msg, bool showReplyButton) = 0;
};
} // namespace Notifications
} // namespace Window

View File

@ -19,8 +19,9 @@ Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "window/notifications_default_manager.h"
#include "window/notifications_manager_default.h"
#include "platform/platform_notifications_manager.h"
#include "mainwindow.h"
#include "lang.h"
#include "dialogs/dialogs_layout.h"
@ -28,45 +29,174 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
namespace Window {
namespace Notifications {
namespace Default {
namespace {
void DefaultManager::create(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, bool showUserpic, const QString &msg, bool showReplyButton) {
// 3 desktop notifies at the same time.
constexpr int kNotifyWindowsCount = 3;
NeverFreedPointer<Manager> FallbackManager;
} // namespace
void start() {
FallbackManager.makeIfNull();
}
void DefaultManager::clear(History *history, bool fast) {
Manager *manager() {
return FallbackManager.data();
}
void finish() {
FallbackManager.reset();
}
Widget::Widget(HistoryItem *msg, int32 x, int32 y, int32 fwdCount) : TWidget(0)
, history(msg->history())
, item(msg)
, fwdCount(fwdCount)
Manager::Manager() {
subscribe(FileDownload::ImageLoaded(), [this] {
for_const (auto widget, _widgets) {
widget->updatePeerPhoto();
}
});
}
void Manager::startAllHiding() {
for_const (auto widget, _widgets) {
widget->startHiding();
}
}
void Manager::stopAllHiding() {
for_const (auto widget, _widgets) {
widget->stopHiding();
}
}
void Manager::showNextFromQueue() {
if (_queuedNotifications.isEmpty()) {
return;
}
int count = kNotifyWindowsCount;
for_const (auto widget, _widgets) {
if (widget->index() < 0) continue;
--count;
}
if (count <= 0) {
return;
}
auto r = psDesktopRect();
auto x = r.x() + r.width() - st::notifyWidth - st::notifyDeltaX;
auto y = r.y() + r.height() - st::notifyHeight - st::notifyDeltaY;
do {
auto queued = _queuedNotifications.front();
_queuedNotifications.pop_front();
auto widget = std_::make_unique<Widget>(queued.history, queued.peer, queued.author, queued.item, queued.forwardedCount, x, y);
Platform::Notifications::defaultNotificationShown(widget.get());
_widgets.push_back(widget.release());
--count;
} while (count > 0 && !_queuedNotifications.isEmpty());
auto shown = kNotifyWindowsCount - count;
for_const (auto widget, _widgets) {
if (widget->index() < 0) continue;
--shown;
widget->moveTo(x, y - shown * (st::notifyHeight + st::notifyDeltaY));
}
}
void Manager::removeFromShown(Widget *remove) {
if (remove) {
auto index = _widgets.indexOf(remove);
if (index >= 0) {
_widgets.removeAt(index);
}
}
showNextFromQueue();
}
void Manager::doShowNotification(HistoryItem *item, int forwardedCount) {
_queuedNotifications.push_back(QueuedNotification(item, forwardedCount));
showNextFromQueue();
}
void Manager::doClearAll() {
_queuedNotifications.clear();
for_const (auto widget, _widgets) {
widget->unlinkHistory();
}
}
void Manager::doClearAllFast() {
_queuedNotifications.clear();
auto widgets = createAndSwap(_widgets);
for_const (auto widget, widgets) {
widget->deleteLater();
}
}
void Manager::doClearFromHistory(History *history) {
for (auto i = _queuedNotifications.begin(); i != _queuedNotifications.cend();) {
if (i->history == history) {
i = _queuedNotifications.erase(i);
} else {
++i;
}
}
for_const (auto widget, _widgets) {
widget->unlinkHistory(history);
}
showNextFromQueue();
}
void Manager::doClearFromItem(HistoryItem *item) {
for_const (auto widget, _widgets) {
widget->itemRemoved(item);
}
}
void Manager::doUpdateAll() {
for_const (auto widget, _widgets) {
widget->updateNotifyDisplay();
}
}
Manager::~Manager() {
clearAllFast();
}
Widget::Widget(History *history, PeerData *peer, PeerData *author, HistoryItem *msg, int forwardedCount, int x, int y) : TWidget(nullptr)
, _history(history)
, _peer(peer)
, _author(author)
, _item(msg)
, _forwardedCount(forwardedCount)
#if defined Q_OS_WIN && !defined Q_OS_WINRT
, started(GetTickCount())
, _started(GetTickCount())
#endif // Q_OS_WIN && !Q_OS_WINRT
, close(this, st::notifyClose)
, alphaDuration(st::notifyFastAnim)
, posDuration(st::notifyFastAnim)
, hiding(false)
, _index(0)
, _close(this, st::notifyClose)
, _alphaDuration(st::notifyFastAnim)
, _posDuration(st::notifyFastAnim)
, a_opacity(0)
, a_func(anim::linear)
, a_y(y + st::notifyHeight + st::notifyDeltaY)
, _a_appearance(animation(this, &Widget::step_appearance)) {
updateNotifyDisplay();
hideTimer.setSingleShot(true);
connect(&hideTimer, SIGNAL(timeout()), this, SLOT(hideByTimer()));
_hideTimer.setSingleShot(true);
connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(hideByTimer()));
inputTimer.setSingleShot(true);
connect(&inputTimer, SIGNAL(timeout()), this, SLOT(checkLastInput()));
_inputTimer.setSingleShot(true);
connect(&_inputTimer, SIGNAL(timeout()), this, SLOT(checkLastInput()));
close.setClickedCallback([this] {
_close.setClickedCallback([this] {
unlinkHistoryAndNotify();
});
close.setAcceptBoth(true);
close.move(st::notifyWidth - st::notifyClose.width - st::notifyClosePos.x(), st::notifyClosePos.y());
close.show();
_close.setAcceptBoth(true);
_close.move(st::notifyWidth - st::notifyClose.width - st::notifyClosePos.x(), st::notifyClosePos.y());
_close.show();
a_y.start(y);
setGeometry(x, a_y.current(), st::notifyWidth, st::notifyHeight);
@ -79,7 +209,7 @@ Widget::Widget(HistoryItem *msg, int32 x, int32 y, int32 fwdCount) : TWidget(0)
setWindowOpacity(a_opacity.current());
alphaDuration = posDuration = st::notifyFastAnim;
_alphaDuration = _posDuration = st::notifyFastAnim;
_a_appearance.start();
checkLastInput();
@ -90,34 +220,34 @@ void Widget::checkLastInput() {
LASTINPUTINFO lii;
lii.cbSize = sizeof(LASTINPUTINFO);
BOOL res = GetLastInputInfo(&lii);
if (!res || lii.dwTime >= started) {
hideTimer.start(st::notifyWaitLongHide);
if (!res || lii.dwTime >= _started) {
_hideTimer.start(st::notifyWaitLongHide);
} else {
inputTimer.start(300);
_inputTimer.start(300);
}
#else // Q_OS_WIN && !Q_OS_WINRT
// TODO
if (true) {
hideTimer.start(st::notifyWaitLongHide);
_hideTimer.start(st::notifyWaitLongHide);
} else {
inputTimer.start(300);
_inputTimer.start(300);
}
#endif // else for Q_OS_WIN && !Q_OS_WINRT
}
void Widget::moveTo(int32 x, int32 y, int32 index) {
void Widget::moveTo(int x, int y, int index) {
if (index >= 0) {
_index = index;
}
move(x, a_y.current());
a_y.start(y);
a_opacity.restart();
posDuration = st::notifyFastAnim;
_posDuration = st::notifyFastAnim;
_a_appearance.start();
}
void Widget::updateNotifyDisplay() {
if (!item) return;
if (!_history || !_peer || (!_item && _forwardedCount < 2)) return;
int32 w = st::notifyWidth, h = st::notifyHeight;
QImage img(w * cIntRetinaFactor(), h * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
@ -132,8 +262,8 @@ void Widget::updateNotifyDisplay() {
p.fillRect(0, st::notifyBorderWidth, st::notifyBorderWidth, h - st::notifyBorderWidth, st::notifyBorder->b);
if (!App::passcoded() && Global::NotifyView() <= dbinvShowName) {
history->peer->loadUserpic(true, true);
history->peer->paintUserpicLeft(p, st::notifyPhotoSize, st::notifyPhotoPos.x(), st::notifyPhotoPos.y(), width());
_history->peer->loadUserpic(true, true);
_history->peer->paintUserpicLeft(p, st::notifyPhotoSize, st::notifyPhotoPos.x(), st::notifyPhotoPos.y(), width());
} else {
static QPixmap icon = App::pixmapFromImageInPlace(App::wnd()->iconLarge().scaled(st::notifyPhotoSize, st::notifyPhotoSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
p.drawPixmap(st::notifyPhotoPos.x(), st::notifyPhotoPos.y(), icon);
@ -143,113 +273,109 @@ void Widget::updateNotifyDisplay() {
QRect rectForName(st::notifyPhotoPos.x() + st::notifyPhotoSize + st::notifyTextLeft, st::notifyTextTop, itemWidth, st::msgNameFont->height);
if (!App::passcoded() && Global::NotifyView() <= dbinvShowName) {
if (auto chatTypeIcon = Dialogs::Layout::ChatTypeIcon(history->peer, false)) {
if (auto chatTypeIcon = Dialogs::Layout::ChatTypeIcon(_history->peer, false)) {
chatTypeIcon->paint(p, rectForName.topLeft(), w);
rectForName.setLeft(rectForName.left() + st::dialogsChatTypeSkip);
}
}
QDateTime now(QDateTime::currentDateTime()), lastTime(item->date);
QDate nowDate(now.date()), lastDate(lastTime.date());
QString dt = lastTime.toString(cTimeFormat());
int32 dtWidth = st::dialogsTextFont->width(dt);
rectForName.setWidth(rectForName.width() - dtWidth - st::dialogsDateSkip);
p.setFont(st::dialogsDateFont);
p.setPen(st::dialogsDateFg);
p.drawText(rectForName.left() + rectForName.width() + st::dialogsDateSkip, rectForName.top() + st::dialogsTextFont->ascent, dt);
if (!App::passcoded() && Global::NotifyView() <= dbinvShowPreview) {
const HistoryItem *textCachedFor = 0;
Text itemTextCache(itemWidth);
QRect r(st::notifyPhotoPos.x() + st::notifyPhotoSize + st::notifyTextLeft, st::notifyItemTop + st::msgNameFont->height, itemWidth, 2 * st::dialogsTextFont->height);
if (fwdCount < 2) {
if (_item) {
bool active = false;
item->drawInDialog(p, r, active, textCachedFor, itemTextCache);
} else {
_item->drawInDialog(p, r, active, textCachedFor, itemTextCache);
} else if (_forwardedCount > 1) {
p.setFont(st::dialogsTextFont);
if (item->hasFromName() && !item->isPost()) {
itemTextCache.setText(st::dialogsTextFont, item->author()->name);
if (_author) {
itemTextCache.setText(st::dialogsTextFont, _author->name);
p.setPen(st::dialogsTextFgService);
itemTextCache.drawElided(p, r.left(), r.top(), r.width(), st::dialogsTextFont->height);
r.setTop(r.top() + st::dialogsTextFont->height);
}
p.setPen(st::dialogsTextFg);
p.drawText(r.left(), r.top() + st::dialogsTextFont->ascent, lng_forward_messages(lt_count, fwdCount));
p.drawText(r.left(), r.top() + st::dialogsTextFont->ascent, lng_forward_messages(lt_count, _forwardedCount));
}
} else {
static QString notifyText = st::dialogsTextFont->elided(lang(lng_notification_preview), itemWidth);
p.setFont(st::dialogsTextFont);
p.setPen(st::dialogsTextFgService);
p.drawText(st::notifyPhotoPos.x() + st::notifyPhotoSize + st::notifyTextLeft, st::notifyItemTop + st::msgNameFont->height + st::dialogsTextFont->ascent, notifyText);
}
p.setPen(st::dialogsNameFg);
if (!App::passcoded() && Global::NotifyView() <= dbinvShowName) {
history->peer->dialogName().drawElided(p, rectForName.left(), rectForName.top(), rectForName.width());
_history->peer->dialogName().drawElided(p, rectForName.left(), rectForName.top(), rectForName.width());
} else {
p.setFont(st::msgNameFont->f);
p.setFont(st::msgNameFont);
static QString notifyTitle = st::msgNameFont->elided(qsl("Telegram Desktop"), rectForName.width());
p.drawText(rectForName.left(), rectForName.top() + st::msgNameFont->ascent, notifyTitle);
}
}
pm = App::pixmapFromImageInPlace(std_::move(img));
_cache = App::pixmapFromImageInPlace(std_::move(img));
update();
}
void Widget::updatePeerPhoto() {
if (!peerPhoto->isNull() && peerPhoto->loaded()) {
QImage img(pm.toImage());
auto img = _cache.toImage();
{
QPainter p(&img);
Painter p(&img);
p.drawPixmap(st::notifyPhotoPos.x(), st::notifyPhotoPos.y(), peerPhoto->pix(st::notifyPhotoSize));
}
peerPhoto = ImagePtr();
pm = App::pixmapFromImageInPlace(std_::move(img));
_cache = App::pixmapFromImageInPlace(std_::move(img));
update();
}
}
void Widget::itemRemoved(HistoryItem *del) {
if (item == del) {
item = 0;
void Widget::itemRemoved(HistoryItem *deleted) {
if (_item && _item == deleted) {
_item = nullptr;
unlinkHistoryAndNotify();
}
}
void Widget::unlinkHistoryAndNotify() {
unlinkHistory();
if (auto window = App::wnd()) {
window->notifyShowNext();
if (auto manager = FallbackManager.data()) {
manager->showNextFromQueue();
}
}
void Widget::unlinkHistory(History *hist) {
if (!hist || hist == history) {
void Widget::unlinkHistory(History *history) {
if (!history || history == _history) {
animHide(st::notifyFastAnim, anim::linear);
history = 0;
item = 0;
_history = nullptr;
_item = nullptr;
}
}
void Widget::enterEvent(QEvent *e) {
if (!history) return;
if (App::wnd()) App::wnd()->notifyStopHiding();
if (!_history) return;
if (auto manager = FallbackManager.data()) {
manager->stopAllHiding();
}
}
void Widget::leaveEvent(QEvent *e) {
if (!history) return;
App::wnd()->notifyStartHiding();
if (!_history) return;
if (auto manager = FallbackManager.data()) {
manager->startAllHiding();
}
}
void Widget::startHiding() {
hideTimer.start(st::notifyWaitShortHide);
_hideTimer.start(st::notifyWaitShortHide);
}
void Widget::mousePressEvent(QMouseEvent *e) {
if (!history) return;
if (!_history) return;
PeerId peer = history->peer->id;
MsgId msgId = (!history->peer->isUser() && item && item->mentionsMe() && item->id > 0) ? item->id : ShowAtUnreadMsgId;
auto peerId = _history->peer->id;
auto msgId = (!_history->peer->isUser() && _item && _item->mentionsMe() && _item->id > 0) ? _item->id : ShowAtUnreadMsgId;
if (e->button() == Qt::RightButton) {
unlinkHistoryAndNotify();
@ -259,7 +385,7 @@ void Widget::mousePressEvent(QMouseEvent *e) {
App::wnd()->setInnerFocus();
App::wnd()->notifyClear();
} else {
Ui::showPeerHistory(peer, msgId);
Ui::showPeerHistory(peerId, msgId);
}
e->ignore();
}
@ -267,40 +393,40 @@ void Widget::mousePressEvent(QMouseEvent *e) {
void Widget::paintEvent(QPaintEvent *e) {
QPainter p(this);
p.drawPixmap(0, 0, pm);
p.drawPixmap(0, 0, _cache);
}
void Widget::animHide(float64 duration, anim::transition func) {
if (!history) return;
alphaDuration = duration;
if (!_history) return;
_alphaDuration = duration;
a_func = func;
a_opacity.start(0);
a_y.restart();
hiding = true;
_hiding = true;
_a_appearance.start();
}
void Widget::stopHiding() {
if (!history) return;
alphaDuration = st::notifyFastAnim;
if (!_history) return;
_alphaDuration = st::notifyFastAnim;
a_func = anim::linear;
a_opacity.start(1);
a_y.restart();
hiding = false;
hideTimer.stop();
_hiding = false;
_hideTimer.stop();
_a_appearance.start();
}
void Widget::hideByTimer() {
if (!history) return;
if (!_history) return;
animHide(st::notifySlowHide, st::notifySlowHideFunc);
}
void Widget::step_appearance(float64 ms, bool timer) {
float64 dtAlpha = ms / alphaDuration, dtPos = ms / posDuration;
float64 dtAlpha = ms / _alphaDuration, dtPos = ms / _posDuration;
if (dtAlpha >= 1) {
a_opacity.finish();
if (hiding) {
if (_hiding) {
_a_appearance.stop();
deleteLater();
} else if (dtPos >= 1) {
@ -320,8 +446,11 @@ void Widget::step_appearance(float64 ms, bool timer) {
}
Widget::~Widget() {
if (App::wnd()) App::wnd()->notifyShowNext(this);
if (auto manager = FallbackManager.data()) {
manager->removeFromShown(this);
}
}
} // namespace Default
} // namespace Notifications
} // namespace Window

View File

@ -20,17 +20,65 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
#include "window/notifications_abstract_manager.h"
#include "window/notifications_manager.h"
namespace Window {
namespace Notifications {
namespace Default {
class DefaultManager : public AbstractManager {
class Manager;
class Widget;
void start();
Manager *manager();
void finish();
class Manager : public Notifications::Manager, private base::Subscriber {
public:
Manager();
void showNextFromQueue();
void removeFromShown(Widget *remove);
void startAllHiding();
void stopAllHiding();
template <typename Method>
void enumerateWidgets(Method method) {
for_const (auto widget, _widgets) {
method(widget);
}
}
~Manager();
private:
void create(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, bool showUserpic, const QString &msg, bool showReplyButton) override;
void clear(History *history, bool fast) override;
void doUpdateAll() override;
void doShowNotification(HistoryItem *item, int forwardedCount) override;
void doClearAll() override;
void doClearAllFast() override;
void doClearFromHistory(History *history) override;
void doClearFromItem(HistoryItem *item) override;
using Widgets = QList<Widget*>;
Widgets _widgets;
struct QueuedNotification {
QueuedNotification(HistoryItem *item, int forwardedCount)
: history(item->history())
, peer(history->peer)
, author((item->hasFromName() && !item->isPost()) ? item->author() : nullptr)
, item((forwardedCount > 1) ? nullptr : item)
, forwardedCount(forwardedCount) {
}
History *history;
PeerData *peer;
PeerData *author;
HistoryItem *item;
int forwardedCount;
};
using QueuedNotifications = QList<QueuedNotification>;
QueuedNotifications _queuedNotifications;
};
@ -38,21 +86,21 @@ class Widget : public TWidget {
Q_OBJECT
public:
Widget(HistoryItem *item, int32 x, int32 y, int32 fwdCount);
Widget(History *history, PeerData *peer, PeerData *author, HistoryItem *item, int forwardedCount, int x, int y);
void step_appearance(float64 ms, bool timer);
void animHide(float64 duration, anim::transition func);
void startHiding();
void stopHiding();
void moveTo(int32 x, int32 y, int32 index = -1);
void moveTo(int x, int y, int index = -1);
void updateNotifyDisplay();
void updatePeerPhoto();
void itemRemoved(HistoryItem *del);
int32 index() const {
return history ? _index : -1;
int index() const {
return _history ? _index : -1;
}
void unlinkHistory(History *hist = 0);
@ -73,18 +121,20 @@ private:
void unlinkHistoryAndNotify();
#if defined Q_OS_WIN && !defined Q_OS_WINRT
uint64 started;
uint64 _started;
#endif // Q_OS_WIN && !Q_OS_WINRT
History *history;
HistoryItem *item;
int32 fwdCount;
IconedButton close;
QPixmap pm;
float64 alphaDuration, posDuration;
QTimer hideTimer, inputTimer;
bool hiding;
int32 _index;
History *_history;
PeerData *_peer;
PeerData *_author;
HistoryItem *_item;
int _forwardedCount;
IconedButton _close;
QPixmap _cache;
float64 _alphaDuration, _posDuration;
QTimer _hideTimer, _inputTimer;
bool _hiding = false;
int _index = 0;
anim::fvalue a_opacity;
anim::transition a_func;
anim::ivalue a_y;
@ -94,5 +144,6 @@ private:
};
} // namespace Default
} // namespace Notifications
} // namespace Window

View File

@ -482,10 +482,10 @@
'<(src_loc)/window/chat_background.h',
'<(src_loc)/window/main_window.cpp',
'<(src_loc)/window/main_window.h',
'<(src_loc)/window/notifications_abstract_manager.cpp',
'<(src_loc)/window/notifications_abstract_manager.h',
'<(src_loc)/window/notifications_default_manager.cpp',
'<(src_loc)/window/notifications_default_manager.h',
'<(src_loc)/window/notifications_manager.cpp',
'<(src_loc)/window/notifications_manager.h',
'<(src_loc)/window/notifications_manager_default.cpp',
'<(src_loc)/window/notifications_manager_default.h',
'<(src_loc)/window/section_widget.cpp',
'<(src_loc)/window/section_widget.h',
'<(src_loc)/window/slide_animation.cpp',