diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index b1e8b1ff74..15295e8b57 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -249,6 +249,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org "lng_settings_include_muted" = "Include muted chats in unread count"; "lng_notification_preview" = "You have a new message"; +"lng_notification_reply" = "Reply"; +"lng_notification_hide_all" = "Hide all"; "lng_settings_section_general" = "General"; "lng_settings_change_lang" = "Change language"; @@ -872,8 +874,6 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org "lng_send_image_too_large" = "Could not send a file, because it is larger than 1.5 GB :("; "lng_send_folder" = "Could not send «{name}» because it is a directory :("; -"lng_notification_reply" = "Reply"; - "lng_forward_choose" = "Choose recipient..."; "lng_forward_cant" = "Sorry, no way to forward here :("; "lng_forward_confirm" = "Forward to {recipient}?"; diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h index 524f195c6b..23e453beec 100644 --- a/Telegram/SourceFiles/apiwrap.h +++ b/Telegram/SourceFiles/apiwrap.h @@ -20,6 +20,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org */ #pragma once +#include "core/single_timer.h" + class ApiWrap : public QObject, public RPCSender { Q_OBJECT diff --git a/Telegram/SourceFiles/application.h b/Telegram/SourceFiles/application.h index 60c2d520ba..27347b9800 100644 --- a/Telegram/SourceFiles/application.h +++ b/Telegram/SourceFiles/application.h @@ -22,6 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "mainwindow.h" #include "pspecific.h" +#include "core/single_timer.h" class UpdateChecker; class Application : public QApplication { diff --git a/Telegram/SourceFiles/boxes/contactsbox.h b/Telegram/SourceFiles/boxes/contactsbox.h index 1d3976e6d7..646421224f 100644 --- a/Telegram/SourceFiles/boxes/contactsbox.h +++ b/Telegram/SourceFiles/boxes/contactsbox.h @@ -21,6 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #pragma once #include "abstractbox.h" +#include "core/single_timer.h" namespace Dialogs { class Row; diff --git a/Telegram/SourceFiles/boxes/sessionsbox.h b/Telegram/SourceFiles/boxes/sessionsbox.h index 51f84d0214..851bfa8fba 100644 --- a/Telegram/SourceFiles/boxes/sessionsbox.h +++ b/Telegram/SourceFiles/boxes/sessionsbox.h @@ -21,6 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #pragma once #include "abstractbox.h" +#include "core/single_timer.h" class ConfirmBox; diff --git a/Telegram/SourceFiles/config.h b/Telegram/SourceFiles/config.h index 6a0d52540b..85eb99476c 100644 --- a/Telegram/SourceFiles/config.h +++ b/Telegram/SourceFiles/config.h @@ -97,9 +97,6 @@ enum { MediaOverviewStartPerPage = 5, MediaOverviewPreloadCount = 4, - // a new message from the same sender is attached to previous within 15 minutes - AttachMessageToPreviousSecondsDelta = 900, - AudioSimultaneousLimit = 4, AudioCheckPositionTimeout = 100, // 100ms per check audio pos AudioCheckPositionDelta = 2400, // update position called each 2400 samples diff --git a/Telegram/SourceFiles/core/lambda_wrap.h b/Telegram/SourceFiles/core/lambda_wrap.h index b8c6c8e531..22e1ed4381 100644 --- a/Telegram/SourceFiles/core/lambda_wrap.h +++ b/Telegram/SourceFiles/core/lambda_wrap.h @@ -20,9 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org */ #pragma once -#ifndef OS_MAC_OLD -#include -#endif // OS_MAC_OLD +#include "core/stl_subset.h" namespace base { namespace internal { @@ -392,191 +390,3 @@ public: }; } // namespace base - -// While we still use rpcDone() and rpcFail() - -#include "mtproto/rpc_sender.h" - -template -struct LambdaUniqueHelper; - -template -struct LambdaUniqueHelper { - using UniqueType = base::lambda_unique; -}; - -template -using LambdaGetUnique = typename LambdaUniqueHelper::UniqueType; - -template -class RPCHandlerImplementation : public Base { -protected: - using Lambda = base::lambda_unique; - using Parent = RPCHandlerImplementation; - -public: - RPCHandlerImplementation(Lambda &&handler) : _handler(std_::move(handler)) { - } - -protected: - Lambda _handler; - -}; - -template -using RPCDoneHandlerImplementation = RPCHandlerImplementation; - -template -class RPCDoneHandlerImplementationBare : public RPCDoneHandlerImplementation { // done(from, end) -public: - using RPCDoneHandlerImplementation::Parent::Parent; - void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const override { - return this->_handler ? this->_handler(from, end) : void(0); - } - -}; - -template -class RPCDoneHandlerImplementationBareReq : public RPCDoneHandlerImplementation { // done(from, end, req_id) -public: - using RPCDoneHandlerImplementation::Parent::Parent; - void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const override { - return this->_handler ? this->_handler(from, end, requestId) : void(0); - } - -}; - -template -class RPCDoneHandlerImplementationPlain : public RPCDoneHandlerImplementation { // done(result) -public: - using RPCDoneHandlerImplementation::Parent::Parent; - void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const override { - return this->_handler ? this->_handler(T(from, end)) : void(0); - } - -}; - -template -class RPCDoneHandlerImplementationReq : public RPCDoneHandlerImplementation { // done(result, req_id) -public: - using RPCDoneHandlerImplementation::Parent::Parent; - void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const override { - return this->_handler ? this->_handler(T(from, end), requestId) : void(0); - } - -}; - -template -class RPCDoneHandlerImplementationNo : public RPCDoneHandlerImplementation { // done() -public: - using RPCDoneHandlerImplementation::Parent::Parent; - void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const override { - return this->_handler ? this->_handler() : void(0); - } - -}; - -template -class RPCDoneHandlerImplementationNoReq : public RPCDoneHandlerImplementation { // done(req_id) -public: - using RPCDoneHandlerImplementation::Parent::Parent; - void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const override { - return this->_handler ? this->_handler(requestId) : void(0); - } - -}; - -template -inline RPCDoneHandlerPtr rpcDone_lambda_wrap_helper(base::lambda_unique &&lambda) { - return RPCDoneHandlerPtr(new RPCDoneHandlerImplementationBare(std_::move(lambda))); -} - -template -inline RPCDoneHandlerPtr rpcDone_lambda_wrap_helper(base::lambda_unique &&lambda) { - return RPCDoneHandlerPtr(new RPCDoneHandlerImplementationBareReq(std_::move(lambda))); -} - -template -inline RPCDoneHandlerPtr rpcDone_lambda_wrap_helper(base::lambda_unique &&lambda) { - return RPCDoneHandlerPtr(new RPCDoneHandlerImplementationPlain(std_::move(lambda))); -} - -template -inline RPCDoneHandlerPtr rpcDone_lambda_wrap_helper(base::lambda_unique &&lambda) { - return RPCDoneHandlerPtr(new RPCDoneHandlerImplementationReq(std_::move(lambda))); -} - -template -inline RPCDoneHandlerPtr rpcDone_lambda_wrap_helper(base::lambda_unique &&lambda) { - return RPCDoneHandlerPtr(new RPCDoneHandlerImplementationNo(std_::move(lambda))); -} - -template -inline RPCDoneHandlerPtr rpcDone_lambda_wrap_helper(base::lambda_unique &&lambda) { - return RPCDoneHandlerPtr(new RPCDoneHandlerImplementationNoReq(std_::move(lambda))); -} - -template ::value>> -RPCDoneHandlerPtr rpcDone(Lambda &&lambda) { - return rpcDone_lambda_wrap_helper(LambdaGetUnique(std_::move(lambda))); -} - -template -using RPCFailHandlerImplementation = RPCHandlerImplementation; - -class RPCFailHandlerImplementationPlain : public RPCFailHandlerImplementation { // fail(error) -public: - using Parent::Parent; - bool operator()(mtpRequestId requestId, const RPCError &error) const override { - return _handler ? _handler(error) : true; - } - -}; - -class RPCFailHandlerImplementationReq : public RPCFailHandlerImplementation { // fail(error, req_id) -public: - using Parent::Parent; - bool operator()(mtpRequestId requestId, const RPCError &error) const override { - return this->_handler ? this->_handler(error, requestId) : true; - } - -}; - -class RPCFailHandlerImplementationNo : public RPCFailHandlerImplementation { // fail() -public: - using Parent::Parent; - bool operator()(mtpRequestId requestId, const RPCError &error) const override { - return this->_handler ? this->_handler() : true; - } - -}; - -class RPCFailHandlerImplementationNoReq : public RPCFailHandlerImplementation { // fail(req_id) -public: - using Parent::Parent; - bool operator()(mtpRequestId requestId, const RPCError &error) const override { - return this->_handler ? this->_handler(requestId) : true; - } - -}; - -inline RPCFailHandlerPtr rpcFail_lambda_wrap_helper(base::lambda_unique &&lambda) { - return RPCFailHandlerPtr(new RPCFailHandlerImplementationPlain(std_::move(lambda))); -} - -inline RPCFailHandlerPtr rpcFail_lambda_wrap_helper(base::lambda_unique &&lambda) { - return RPCFailHandlerPtr(new RPCFailHandlerImplementationReq(std_::move(lambda))); -} - -inline RPCFailHandlerPtr rpcFail_lambda_wrap_helper(base::lambda_unique &&lambda) { - return RPCFailHandlerPtr(new RPCFailHandlerImplementationNo(std_::move(lambda))); -} - -inline RPCFailHandlerPtr rpcFail_lambda_wrap_helper(base::lambda_unique &&lambda) { - return RPCFailHandlerPtr(new RPCFailHandlerImplementationNoReq(std_::move(lambda))); -} - -template ::value>> -RPCFailHandlerPtr rpcFail(Lambda &&lambda) { - return rpcFail_lambda_wrap_helper(LambdaGetUnique(std_::move(lambda))); -} diff --git a/Telegram/SourceFiles/core/single_timer.cpp b/Telegram/SourceFiles/core/single_timer.cpp new file mode 100644 index 0000000000..7507a8f14b --- /dev/null +++ b/Telegram/SourceFiles/core/single_timer.cpp @@ -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 +*/ +#include "stdafx.h" +#include "core/single_timer.h" + +#include "application.h" + +SingleTimer::SingleTimer() { + QTimer::setSingleShot(true); + if (App::app()) { + connect(App::app(), SIGNAL(adjustSingleTimers()), this, SLOT(adjust())); + _inited = true; + } +} + +void SingleTimer::setTimeoutHandler(base::lambda_unique &&handler) { + if (_handler && !handler) { + disconnect(this, SIGNAL(timeout()), this, SLOT(onTimeout())); + } else if (handler && !_handler) { + connect(this, SIGNAL(timeout()), this, SLOT(onTimeout())); + } + _handler = std_::move(handler); +} + +void SingleTimer::adjust() { + uint64 n = getms(true); + if (isActive()) { + if (n >= _finishing) { + start(0); + } else { + start(_finishing - n); + } + } +} + +void SingleTimer::onTimeout() { + if (_handler) { + _handler(); + } +} + +void SingleTimer::start(int msec) { + _finishing = getms(true) + (msec < 0 ? 0 : uint64(msec)); + if (!_inited && App::app()) { + connect(App::app(), SIGNAL(adjustSingleTimers()), this, SLOT(adjust())); + _inited = true; + } + QTimer::start(msec); +} + +void SingleTimer::startIfNotActive(int msec) { + if (isActive()) { + int remains = remainingTime(); + if (remains > msec) { + start(msec); + } else if (!remains) { + start(1); + } + } else { + start(msec); + } +} diff --git a/Telegram/SourceFiles/core/single_timer.h b/Telegram/SourceFiles/core/single_timer.h new file mode 100644 index 0000000000..3aa89647a9 --- /dev/null +++ b/Telegram/SourceFiles/core/single_timer.h @@ -0,0 +1,50 @@ +/* +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 + +#include "core/basic_types.h" +#include "core/lambda_wrap.h" + +class SingleTimer : public QTimer { // single shot timer with check + Q_OBJECT + +public: + SingleTimer(); + + void setSingleShot(bool); // is not available + void start(); // is not available + + void setTimeoutHandler(base::lambda_unique &&handler); + +public slots: + void start(int msec); + void startIfNotActive(int msec); + +private slots: + void adjust(); + void onTimeout(); + +private: + uint64 _finishing = 0; + bool _inited = false; + base::lambda_unique _handler; + +}; diff --git a/Telegram/SourceFiles/core/utils.cpp b/Telegram/SourceFiles/core/utils.cpp index 4ad8140abd..63959c2720 100644 --- a/Telegram/SourceFiles/core/utils.cpp +++ b/Telegram/SourceFiles/core/utils.cpp @@ -345,36 +345,6 @@ uint64 getms(bool checked) { #endif } -SingleTimer::SingleTimer() : _finishing(0), _inited(false) { - QTimer::setSingleShot(true); - if (App::app()) { - connect(App::app(), SIGNAL(adjustSingleTimers()), this, SLOT(adjust())); - _inited = true; - } -} - -void SingleTimer::start(int msec) { - _finishing = getms(true) + (msec < 0 ? 0 : uint64(msec)); - if (!_inited && App::app()) { - connect(App::app(), SIGNAL(adjustSingleTimers()), this, SLOT(adjust())); - _inited = true; - } - QTimer::start(msec); -} - -void SingleTimer::startIfNotActive(int msec) { - if (isActive()) { - int remains = remainingTime(); - if (remains > msec) { - start(msec); - } else if (!remains) { - start(1); - } - } else { - start(msec); - } -} - uint64 msgid() { #ifdef Q_OS_WIN LARGE_INTEGER li; diff --git a/Telegram/SourceFiles/core/utils.h b/Telegram/SourceFiles/core/utils.h index df4c23af37..7fb79b1c02 100644 --- a/Telegram/SourceFiles/core/utils.h +++ b/Telegram/SourceFiles/core/utils.h @@ -172,37 +172,6 @@ void finish(); bool checkms(); // returns true if time has changed uint64 getms(bool checked = false); -class SingleTimer : public QTimer { // single shot timer with check - Q_OBJECT - -public: - - SingleTimer(); - - void setSingleShot(bool); // is not available - void start(); // is not available - - public slots: - - void start(int msec); - void startIfNotActive(int msec); - void adjust() { - uint64 n = getms(true); - if (isActive()) { - if (n >= _finishing) { - start(0); - } else { - start(_finishing - n); - } - } - } - -private: - uint64 _finishing; - bool _inited; - -}; - const static uint32 _md5_block_size = 64; class HashMd5 { public: diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index 15c8562489..f792eafd6f 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -28,6 +28,13 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "styles/style_dialogs.h" #include "fileuploader.h" +namespace { + +// a new message from the same sender is attached to previous within 15 minutes +constexpr int kAttachMessageToPreviousSecondsDelta = 900; + +} // namespace + ReplyMarkupClickHandler::ReplyMarkupClickHandler(const HistoryItem *item, int row, int col) : _itemId(item->fullId()) , _row(row) @@ -629,7 +636,7 @@ void HistoryItem::recountAttachToPrevious() { && !previos->serviceMsg() && !previos->isEmpty() && previos->from() == from() - && (qAbs(previos->date.secsTo(date)) < AttachMessageToPreviousSecondsDelta); + && (qAbs(previos->date.secsTo(date)) < kAttachMessageToPreviousSecondsDelta); } } if (attach && !(_flags & MTPDmessage_ClientFlag::f_attach_to_previous)) { diff --git a/Telegram/SourceFiles/historywidget.h b/Telegram/SourceFiles/historywidget.h index cf6c62bca8..af7d4e4d58 100644 --- a/Telegram/SourceFiles/historywidget.h +++ b/Telegram/SourceFiles/historywidget.h @@ -26,6 +26,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "history/history_common.h" #include "history/field_autocomplete.h" #include "window/section_widget.h" +#include "core/single_timer.h" namespace InlineBots { namespace Layout { diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index a6d3547ee6..9b4027b1a6 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -22,6 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "localimageloader.h" #include "history/history_common.h" +#include "core/single_timer.h" namespace Dialogs { class Row; diff --git a/Telegram/SourceFiles/mainwindow.h b/Telegram/SourceFiles/mainwindow.h index 9ace9c51dd..7df6e021ed 100644 --- a/Telegram/SourceFiles/mainwindow.h +++ b/Telegram/SourceFiles/mainwindow.h @@ -24,6 +24,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "pspecific.h" #include "ui/effects/rect_shadow.h" #include "platform/platform_main_window.h" +#include "core/single_timer.h" class MediaView; class TitleWidget; @@ -41,14 +42,6 @@ namespace Settings { class Widget; } // namespace Settings -namespace Window { -namespace Notifications { -namespace Default { -class Widget; -} // namespace Default -} // namespace Notifications -} // namespace Window - class ConnectingWidget : public QWidget { Q_OBJECT diff --git a/Telegram/SourceFiles/mtproto/connection.h b/Telegram/SourceFiles/mtproto/connection.h index 89c62fb4bf..ab21010858 100644 --- a/Telegram/SourceFiles/mtproto/connection.h +++ b/Telegram/SourceFiles/mtproto/connection.h @@ -23,6 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "mtproto/core_types.h" #include "mtproto/auth_key.h" #include "mtproto/connection_abstract.h" +#include "core/single_timer.h" namespace MTP { namespace internal { diff --git a/Telegram/SourceFiles/mtproto/dcenter.h b/Telegram/SourceFiles/mtproto/dcenter.h index 4f47c63d33..058ab61fdb 100644 --- a/Telegram/SourceFiles/mtproto/dcenter.h +++ b/Telegram/SourceFiles/mtproto/dcenter.h @@ -20,6 +20,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org */ #pragma once +#include "core/single_timer.h" + namespace MTP { namespace internal { @@ -27,7 +29,6 @@ class Dcenter : public QObject { Q_OBJECT public: - Dcenter(int32 id, const AuthKeyPtr &key); QReadWriteLock *keyMutex() const; @@ -46,21 +47,19 @@ public: } signals: - void authKeyCreated(); void layerWasInited(bool was); private slots: - void authKeyWrite(); private: - mutable QReadWriteLock keyLock; mutable QMutex initLock; int32 _id; AuthKeyPtr _key; bool _connectionInited; + }; typedef QSharedPointer DcenterPtr; @@ -70,21 +69,17 @@ class ConfigLoader : public QObject { Q_OBJECT public: - ConfigLoader(); void load(); void done(); public slots: - void enumDC(); signals: - void loaded(); private: - SingleTimer _enumDCTimer; int32 _enumCurrent; mtpRequestId _enumRequest; diff --git a/Telegram/SourceFiles/mtproto/facade.h b/Telegram/SourceFiles/mtproto/facade.h index 94f5e39c0e..568ecb5b71 100644 --- a/Telegram/SourceFiles/mtproto/facade.h +++ b/Telegram/SourceFiles/mtproto/facade.h @@ -22,6 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "mtproto/core_types.h" #include "mtproto/session.h" +#include "core/single_timer.h" namespace MTP { @@ -57,17 +58,15 @@ class GlobalSlotCarrier : public QObject { Q_OBJECT public: - GlobalSlotCarrier(); public slots: - void checkDelayed(); void connectionFinished(Connection *connection); private: - SingleTimer _timer; + }; GlobalSlotCarrier *globalSlotCarrier(); diff --git a/Telegram/SourceFiles/mtproto/rpc_sender.h b/Telegram/SourceFiles/mtproto/rpc_sender.h index fb5fd95eb9..76839e5a17 100644 --- a/Telegram/SourceFiles/mtproto/rpc_sender.h +++ b/Telegram/SourceFiles/mtproto/rpc_sender.h @@ -20,9 +20,10 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org */ #pragma once +#include "core/lambda_wrap.h" + class RPCError { public: - RPCError(const MTPrpcError &error) : _code(error.c_rpc_error().verror_code.v) { QString text = qs(error.c_rpc_error().verror_message); if (_code < 0 || _code >= 500) { @@ -827,3 +828,187 @@ protected: typedef void (*MTPStateChangedHandler)(int32 dcId, int32 state); typedef void(*MTPSessionResetHandler)(int32 dcId); + +template +struct LambdaUniqueHelper; + +template +struct LambdaUniqueHelper { + using UniqueType = base::lambda_unique; +}; + +template +using LambdaGetUnique = typename LambdaUniqueHelper::UniqueType; + +template +class RPCHandlerImplementation : public Base { +protected: + using Lambda = base::lambda_unique; + using Parent = RPCHandlerImplementation; + +public: + RPCHandlerImplementation(Lambda &&handler) : _handler(std_::move(handler)) { + } + +protected: + Lambda _handler; + +}; + +template +using RPCDoneHandlerImplementation = RPCHandlerImplementation; + +template +class RPCDoneHandlerImplementationBare : public RPCDoneHandlerImplementation { // done(from, end) +public: + using RPCDoneHandlerImplementation::Parent::Parent; + void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const override { + return this->_handler ? this->_handler(from, end) : void(0); + } + +}; + +template +class RPCDoneHandlerImplementationBareReq : public RPCDoneHandlerImplementation { // done(from, end, req_id) +public: + using RPCDoneHandlerImplementation::Parent::Parent; + void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const override { + return this->_handler ? this->_handler(from, end, requestId) : void(0); + } + +}; + +template +class RPCDoneHandlerImplementationPlain : public RPCDoneHandlerImplementation { // done(result) +public: + using RPCDoneHandlerImplementation::Parent::Parent; + void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const override { + return this->_handler ? this->_handler(T(from, end)) : void(0); + } + +}; + +template +class RPCDoneHandlerImplementationReq : public RPCDoneHandlerImplementation { // done(result, req_id) +public: + using RPCDoneHandlerImplementation::Parent::Parent; + void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const override { + return this->_handler ? this->_handler(T(from, end), requestId) : void(0); + } + +}; + +template +class RPCDoneHandlerImplementationNo : public RPCDoneHandlerImplementation { // done() +public: + using RPCDoneHandlerImplementation::Parent::Parent; + void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const override { + return this->_handler ? this->_handler() : void(0); + } + +}; + +template +class RPCDoneHandlerImplementationNoReq : public RPCDoneHandlerImplementation { // done(req_id) +public: + using RPCDoneHandlerImplementation::Parent::Parent; + void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const override { + return this->_handler ? this->_handler(requestId) : void(0); + } + +}; + +template +inline RPCDoneHandlerPtr rpcDone_lambda_wrap_helper(base::lambda_unique &&lambda) { + return RPCDoneHandlerPtr(new RPCDoneHandlerImplementationBare(std_::move(lambda))); +} + +template +inline RPCDoneHandlerPtr rpcDone_lambda_wrap_helper(base::lambda_unique &&lambda) { + return RPCDoneHandlerPtr(new RPCDoneHandlerImplementationBareReq(std_::move(lambda))); +} + +template +inline RPCDoneHandlerPtr rpcDone_lambda_wrap_helper(base::lambda_unique &&lambda) { + return RPCDoneHandlerPtr(new RPCDoneHandlerImplementationPlain(std_::move(lambda))); +} + +template +inline RPCDoneHandlerPtr rpcDone_lambda_wrap_helper(base::lambda_unique &&lambda) { + return RPCDoneHandlerPtr(new RPCDoneHandlerImplementationReq(std_::move(lambda))); +} + +template +inline RPCDoneHandlerPtr rpcDone_lambda_wrap_helper(base::lambda_unique &&lambda) { + return RPCDoneHandlerPtr(new RPCDoneHandlerImplementationNo(std_::move(lambda))); +} + +template +inline RPCDoneHandlerPtr rpcDone_lambda_wrap_helper(base::lambda_unique &&lambda) { + return RPCDoneHandlerPtr(new RPCDoneHandlerImplementationNoReq(std_::move(lambda))); +} + +template ::value>> +RPCDoneHandlerPtr rpcDone(Lambda &&lambda) { + return rpcDone_lambda_wrap_helper(LambdaGetUnique(std_::move(lambda))); +} + +template +using RPCFailHandlerImplementation = RPCHandlerImplementation; + +class RPCFailHandlerImplementationPlain : public RPCFailHandlerImplementation { // fail(error) +public: + using Parent::Parent; + bool operator()(mtpRequestId requestId, const RPCError &error) const override { + return _handler ? _handler(error) : true; + } + +}; + +class RPCFailHandlerImplementationReq : public RPCFailHandlerImplementation { // fail(error, req_id) +public: + using Parent::Parent; + bool operator()(mtpRequestId requestId, const RPCError &error) const override { + return this->_handler ? this->_handler(error, requestId) : true; + } + +}; + +class RPCFailHandlerImplementationNo : public RPCFailHandlerImplementation { // fail() +public: + using Parent::Parent; + bool operator()(mtpRequestId requestId, const RPCError &error) const override { + return this->_handler ? this->_handler() : true; + } + +}; + +class RPCFailHandlerImplementationNoReq : public RPCFailHandlerImplementation { // fail(req_id) +public: + using Parent::Parent; + bool operator()(mtpRequestId requestId, const RPCError &error) const override { + return this->_handler ? this->_handler(requestId) : true; + } + +}; + +inline RPCFailHandlerPtr rpcFail_lambda_wrap_helper(base::lambda_unique &&lambda) { + return RPCFailHandlerPtr(new RPCFailHandlerImplementationPlain(std_::move(lambda))); +} + +inline RPCFailHandlerPtr rpcFail_lambda_wrap_helper(base::lambda_unique &&lambda) { + return RPCFailHandlerPtr(new RPCFailHandlerImplementationReq(std_::move(lambda))); +} + +inline RPCFailHandlerPtr rpcFail_lambda_wrap_helper(base::lambda_unique &&lambda) { + return RPCFailHandlerPtr(new RPCFailHandlerImplementationNo(std_::move(lambda))); +} + +inline RPCFailHandlerPtr rpcFail_lambda_wrap_helper(base::lambda_unique &&lambda) { + return RPCFailHandlerPtr(new RPCFailHandlerImplementationNoReq(std_::move(lambda))); +} + +template ::value>> +RPCFailHandlerPtr rpcFail(Lambda &&lambda) { + return rpcFail_lambda_wrap_helper(LambdaGetUnique(std_::move(lambda))); +} diff --git a/Telegram/SourceFiles/mtproto/session.h b/Telegram/SourceFiles/mtproto/session.h index f46694e3a2..4c8b17c693 100644 --- a/Telegram/SourceFiles/mtproto/session.h +++ b/Telegram/SourceFiles/mtproto/session.h @@ -23,6 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "mtproto/connection.h" #include "mtproto/dcenter.h" #include "mtproto/rpc_sender.h" +#include "core/single_timer.h" namespace MTP { namespace internal { @@ -31,7 +32,6 @@ class Session; class SessionData { public: - SessionData(Session *creator) : _session(0) , _salt(0) @@ -227,7 +227,6 @@ class Session : public QObject { Q_OBJECT public: - Session(int32 dcenter); void restart(); @@ -237,7 +236,6 @@ public: void unpaused(); int32 getDcWithShift() const; - ~Session(); QReadWriteLock *keyMutex() const; void notifyKeyCreated(const AuthKeyPtr &key); @@ -255,15 +253,15 @@ public: void sendPrepared(const mtpRequest &request, uint64 msCanWait = 0, bool newRequest = true); // nulls msgId and seqNo in request, if newRequest = true -signals: + ~Session(); +signals: void authKeyCreated(); void needToSend(); void needToPing(); void needToRestart(); public slots: - void needToResumeAndSend(); mtpRequestId resend(quint64 msgId, quint64 msCanWait = 0, bool forceContainer = false, bool sendMsgStateInfo = false); @@ -283,7 +281,6 @@ public slots: void sendMsgsStateInfo(quint64 msgId, QByteArray data); private: - Connection *_connection; bool _killed; diff --git a/Telegram/SourceFiles/platform/mac/main_window_mac.mm b/Telegram/SourceFiles/platform/mac/main_window_mac.mm index ddf50c9066..6dd1d6edb1 100644 --- a/Telegram/SourceFiles/platform/mac/main_window_mac.mm +++ b/Telegram/SourceFiles/platform/mac/main_window_mac.mm @@ -39,7 +39,7 @@ namespace Platform { void MacPrivate::activeSpaceChanged() { if (auto manager = Window::Notifications::Default::manager()) { - manager->enumerateWidgets([](QWidget *widget) { + manager->enumerateNotifications([](QWidget *widget) { objc_activateWnd(widget->winId()); }); } diff --git a/Telegram/SourceFiles/ui/animation.h b/Telegram/SourceFiles/ui/animation.h index 6842c55a7f..eaa496fb86 100644 --- a/Telegram/SourceFiles/ui/animation.h +++ b/Telegram/SourceFiles/ui/animation.h @@ -106,13 +106,12 @@ namespace anim { public: using ValueType = float64; - fvalue() { + fvalue() = default; + fvalue(float64 from) : _cur(from), _from(from) { } - fvalue(const float64 &from) : _cur(from), _from(from), _delta(0) { + fvalue(float64 from, float64 to) : _cur(from), _from(from), _delta(to - from) { } - fvalue(const float64 &from, const float64 &to) : _cur(from), _from(from), _delta(to - from) { - } - void start(const float64 &to) { + void start(float64 to) { _from = _cur; _delta = to - _from; } @@ -120,13 +119,21 @@ namespace anim { _delta = _from + _delta - _cur; _from = _cur; } - const float64 ¤t() const { + + float64 from() const { + return _from; + } + float64 current() const { return _cur; } float64 to() const { return _from + _delta; } - fvalue &update(const float64 &dt, transition func) { + void add(float64 delta) { + _from += delta; + _cur += delta; + } + fvalue &update(float64 dt, transition func) { _cur = _from + (*func)(_delta, dt); return *this; } @@ -137,19 +144,20 @@ namespace anim { } private: - float64 _cur, _from, _delta; + float64 _cur = 0.; + float64 _from = 0.; + float64 _delta = 0.; }; class ivalue { // int animated value public: - using ValueType = int32; + using ValueType = int; - ivalue() { + ivalue() = default; + ivalue(int from) : _cur(from), _from(float64(from)) { } - ivalue(int32 from) : _cur(from), _from(float64(from)), _delta(0) { - } - ivalue(int32 from, int32 to) : _cur(from), _from(float64(from)), _delta(float64(to - from)) { + ivalue(int from, int to) : _cur(from), _from(float64(from)), _delta(float64(to - from)) { } void start(int32 to) { _from = float64(_cur); @@ -159,13 +167,21 @@ namespace anim { _delta = _from + _delta - float64(_cur); _from = float64(_cur); } - int32 current() const { + + int from() const { + return _from; + } + int current() const { return _cur; } - int32 to() const { - return _from + _delta; + int to() const { + return qRound(_from + _delta); } - ivalue &update(const float64 &dt, transition func) { + void add(int delta) { + _from += delta; + _cur += delta; + } + ivalue &update(float64 dt, transition func) { _cur = qRound(_from + (*func)(_delta, dt)); return *this; } @@ -176,8 +192,9 @@ namespace anim { } private: - int32 _cur; - float64 _from, _delta; + int _cur = 0; + float64 _from = 0.; + float64 _delta = 0.; }; @@ -185,15 +202,24 @@ namespace anim { public: using ValueType = QColor; - cvalue() { - } - cvalue(const QColor &from) : _cur(from), _from_r(from.redF()), _from_g(from.greenF()), _from_b(from.blueF()), _from_a(from.alphaF()), _delta_r(0), _delta_g(0), _delta_b(0), _delta_a(0) { + cvalue() = default; + cvalue(const QColor &from) + : _cur(from) + , _from_r(from.redF()) + , _from_g(from.greenF()) + , _from_b(from.blueF()) + , _from_a(from.alphaF()) { } cvalue(const QColor &from, const QColor &to) : _cur(from) - , _from_r(from.redF()), _from_g(from.greenF()), _from_b(from.blueF()), _from_a(from.alphaF()) - , _delta_r(to.redF() - from.redF()), _delta_g(to.greenF() - from.greenF()), _delta_b(to.blueF() - from.blueF()), _delta_a(to.alphaF() - from.alphaF()) - { + , _from_r(from.redF()) + , _from_g(from.greenF()) + , _from_b(from.blueF()) + , _from_a(from.alphaF()) + , _delta_r(to.redF() - from.redF()) + , _delta_g(to.greenF() - from.greenF()) + , _delta_b(to.blueF() - from.blueF()) + , _delta_a(to.alphaF() - from.alphaF()) { } void start(const QColor &to) { _from_r = _cur.redF(); @@ -215,6 +241,14 @@ namespace anim { _from_b = _cur.blueF(); _from_a = _cur.alphaF(); } + QColor from() const { + QColor result; + result.setRedF(_from_r); + result.setGreenF(_from_g); + result.setBlueF(_from_b); + result.setAlphaF(_from_a); + return result; + } const QColor ¤t() const { return _cur; } @@ -247,7 +281,14 @@ namespace anim { private: QColor _cur; - float64 _from_r, _from_g, _from_b, _from_a, _delta_r, _delta_g, _delta_b, _delta_a; + float64 _from_r = 0.; + float64 _from_g = 0.; + float64 _from_b = 0.; + float64 _from_a = 0.; + float64 _delta_r = 0.; + float64 _delta_g = 0.; + float64 _delta_b = 0.; + float64 _delta_a = 0.; }; diff --git a/Telegram/SourceFiles/ui/flatinput.cpp b/Telegram/SourceFiles/ui/flatinput.cpp index 6385060a27..de441e418e 100644 --- a/Telegram/SourceFiles/ui/flatinput.cpp +++ b/Telegram/SourceFiles/ui/flatinput.cpp @@ -735,7 +735,7 @@ void InputArea::paintEvent(QPaintEvent *e) { Painter p(this); QRect r(rect().intersected(e->rect())); - p.fillRect(r, st::white->b); + p.fillRect(r, st::white); if (_st.border) { p.fillRect(0, height() - _st.border, width(), _st.border, _st.borderFg->b); } diff --git a/Telegram/SourceFiles/ui/toast/toast_manager.h b/Telegram/SourceFiles/ui/toast/toast_manager.h index 28419cf720..e8e42f9f8a 100644 --- a/Telegram/SourceFiles/ui/toast/toast_manager.h +++ b/Telegram/SourceFiles/ui/toast/toast_manager.h @@ -21,6 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #pragma once #include "ui/toast/toast.h" +#include "core/single_timer.h" namespace Ui { namespace Toast { diff --git a/Telegram/SourceFiles/window/notifications_manager_default.cpp b/Telegram/SourceFiles/window/notifications_manager_default.cpp index f0b57d975e..e63719950b 100644 --- a/Telegram/SourceFiles/window/notifications_manager_default.cpp +++ b/Telegram/SourceFiles/window/notifications_manager_default.cpp @@ -49,6 +49,10 @@ int notificationWidth() { return result; } +int notificationMaxHeight() { + return st::notifyMinHeight + st::notifyReplyArea.heightMax + st::notifyBorderWidth; +} + } // namespace void start() { @@ -65,69 +69,173 @@ void finish() { Manager::Manager() { subscribe(FileDownload::ImageLoaded(), [this] { - for_const (auto widget, _widgets) { - widget->updatePeerPhoto(); + for_const (auto notification, _notifications) { + notification->updatePeerPhoto(); } }); + _inputCheckTimer.setTimeoutHandler([this] { checkLastInput(); }); +} + +void Manager::checkLastInput() { + auto waiting = false; + for_const (auto notification, _notifications) { + if (!notification->checkLastInput()) { + waiting = true; + } + } + if (waiting) { + _inputCheckTimer.start(300); + } } void Manager::startAllHiding() { - for_const (auto widget, _widgets) { - widget->startHiding(); + auto hasReplyingNotification = false; + for_const (auto notification, _notifications) { + if (notification->isReplying()) { + hasReplyingNotification = true; + break; + } + } + if (!hasReplyingNotification) { + int notHidingCount = 0; + for_const (auto notification, _notifications) { + if (notification->isShowing()) { + ++notHidingCount; + } else { + notification->startHiding(); + } + } + notHidingCount += _queuedNotifications.size(); + if (_hideAll && notHidingCount < 2) { + _hideAll->startHiding(); + } } } void Manager::stopAllHiding() { - for_const (auto widget, _widgets) { - widget->stopHiding(); + for_const (auto notification, _notifications) { + notification->stopHiding(); + } + if (_hideAll) { + _hideAll->stopHiding(); } } void Manager::showNextFromQueue() { - if (_queuedNotifications.isEmpty()) { - return; + if (!_queuedNotifications.isEmpty()) { + int count = kNotifyWindowsCount; + for_const (auto notification, _notifications) { + if (notification->isUnlinked()) continue; + --count; + } + if (count > 0) { + auto position = notificationStartPosition(); + do { + auto queued = _queuedNotifications.front(); + _queuedNotifications.pop_front(); + + auto notification = std_::make_unique( + queued.history, + queued.peer, + queued.author, + queued.item, + queued.forwardedCount, + position); + Platform::Notifications::defaultNotificationShown(notification.get()); + _notifications.push_back(notification.release()); + --count; + } while (count > 0 && !_queuedNotifications.isEmpty()); + + _positionsOutdated = true; + checkLastInput(); + } } - - int count = kNotifyWindowsCount; - for_const (auto widget, _widgets) { - if (widget->isUnlinked()) continue; - --count; - } - if (count <= 0) { - return; - } - - auto r = psDesktopRect(); - auto x = r.x() + r.width() - notificationWidth() - st::notifyDeltaX; - auto y = r.y() + r.height(); - do { - auto queued = _queuedNotifications.front(); - _queuedNotifications.pop_front(); - - auto widget = std_::make_unique(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 bottom = y - st::notifyDeltaY; - for_const (auto widget, _widgets) { - if (widget->isUnlinked() < 0) continue; - widget->moveTop(y - widget->height(), y); - y -= widget->height() + st::notifyDeltaY; + if (_positionsOutdated) { + moveWidgets(); } } -void Manager::removeFromShown(Widget *remove) { +QPoint Manager::notificationStartPosition() const { + auto r = psDesktopRect(); + auto x = r.x() + r.width() - notificationWidth() - st::notifyDeltaX; + auto y = r.y() + r.height(); + return QPoint(x, y); +} + +void Manager::moveWidgets() { + auto startPosition = notificationStartPosition(); + auto top = startPosition.y(); + int firstLeft = 0, firstTopCurrent = 0, firstTop = 0, count = 0; + for (int i = _notifications.size(); i != 0;) { + auto notification = _notifications[--i]; + if (notification->isUnlinked()) continue; + + top -= notification->height() + st::notifyDeltaY; + notification->moveTop(top); + + firstLeft = notification->x(); + firstTopCurrent = notification->y(); + firstTop = top; + + ++count; + } + + if (count > 1 || !_queuedNotifications.isEmpty()) { + auto deltaY = st::notifyHideAll.height + st::notifyDeltaY; + if (!_hideAll) { + _hideAll = new HideAllButton(QPoint(firstLeft, firstTopCurrent - deltaY)); + } + _hideAll->moveTop(firstTop - deltaY); + _hideAll->stopHiding(); + } else if (_hideAll) { + _hideAll->startHidingFast(); + } +} + +void Manager::changeNotificationHeight(Notification *notification, int newHeight) { + auto deltaHeight = newHeight - notification->height(); + if (!deltaHeight) return; + + notification->addToHeight(deltaHeight, Notification::AddToHeight::Above); + auto index = _notifications.indexOf(notification); + if (index > 0) { + for (int i = 0; i != index; ++i) { + auto notification = _notifications[i]; + if (notification->isUnlinked()) continue; + + notification->addToTop(-deltaHeight); + } + } + if (_hideAll) { + _hideAll->addToTop(-deltaHeight); + } +} + +void Manager::unlinkFromShown(Notification *remove) { if (remove) { - auto index = _widgets.indexOf(remove); - if (index >= 0) { - _widgets.removeAt(index); + if (remove->unlinkHistory()) { + _positionsOutdated = true; } } showNextFromQueue(); } +void Manager::removeFromShown(Notification *remove) { + if (remove) { + auto index = _notifications.indexOf(remove); + if (index >= 0) { + _notifications.removeAt(index); + _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(); @@ -135,18 +243,19 @@ void Manager::doShowNotification(HistoryItem *item, int forwardedCount) { void Manager::doClearAll() { _queuedNotifications.clear(); - for_const (auto widget, _widgets) { - widget->unlinkHistory(); + for_const (auto notification, _notifications) { + notification->unlinkHistory(); } + showNextFromQueue(); } void Manager::doClearAllFast() { _queuedNotifications.clear(); - - auto widgets = createAndSwap(_widgets); - for_const (auto widget, widgets) { - widget->deleteLater(); + auto notifications = createAndSwap(_notifications); + for_const (auto notification, notifications) { + notification->deleteLater(); } + showNextFromQueue(); } void Manager::doClearFromHistory(History *history) { @@ -157,21 +266,24 @@ void Manager::doClearFromHistory(History *history) { ++i; } } - for_const (auto widget, _widgets) { - widget->unlinkHistory(history); + for_const (auto notification, _notifications) { + if (notification->unlinkHistory(history)) { + _positionsOutdated = true; + } } showNextFromQueue(); } void Manager::doClearFromItem(HistoryItem *item) { - for_const (auto widget, _widgets) { - widget->itemRemoved(item); + for_const (auto notification, _notifications) { + // Calls unlinkFromShown() -> showNextFromQueue() + notification->itemRemoved(item); } } void Manager::doUpdateAll() { - for_const (auto widget, _widgets) { - widget->updateNotifyDisplay(); + for_const (auto notification, _notifications) { + notification->updateNotifyDisplay(); } } @@ -179,7 +291,116 @@ Manager::~Manager() { clearAllFast(); } -Widget::Widget(History *history, PeerData *peer, PeerData *author, HistoryItem *msg, int forwardedCount, int x, int y) : TWidget(nullptr) +namespace internal { + +Widget::Widget(QPoint position) : TWidget(nullptr) +, _opacityDuration(st::notifyFastAnim) +, a_opacity(0, 1) +, a_func(anim::linear) +, _a_appearance(animation(this, &Widget::step_appearance)) +, a_top(position.y()) +, _a_movement(animation(this, &Notification::step_movement)) { + setWindowOpacity(0.); + + setAttribute(Qt::WA_OpaquePaintEvent); + + setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::BypassWindowManagerHint | Qt::NoDropShadowWindowHint); + setAttribute(Qt::WA_MacAlwaysShowToolWindow); + setAttribute(Qt::WA_NoSystemBackground, true); + setAttribute(Qt::WA_TranslucentBackground, true); + + _a_appearance.start(); +} + +void Widget::step_appearance(float64 ms, bool timer) { + float64 dt = ms / float64(_opacityDuration); + if (dt >= 1) { + a_opacity.finish(); + _a_appearance.stop(); + if (_hiding) { + deleteLater(); + } + } else { + a_opacity.update(dt, a_func); + } + setWindowOpacity(a_opacity.current()); + update(); +} + +void Widget::step_movement(float64 ms, bool timer) { + float64 dt = ms / float64(st::notifyFastAnim); + if (dt >= 1) { + a_top.finish(); + } else { + a_top.update(dt, anim::linear); + } + move(x(), a_top.current()); + update(); +} + +void Widget::hideSlow() { + animHide(st::notifySlowHide, st::notifySlowHideFunc); +} + +void Widget::hideFast() { + animHide(st::notifyFastAnim, anim::linear); +} + +void Widget::hideStop() { + if (_hiding) { + _opacityDuration = st::notifyFastAnim; + a_func = anim::linear; + a_opacity.start(1); + _hiding = false; + _a_appearance.start(); + } +} + +void Widget::animHide(float64 duration, anim::transition func) { + _opacityDuration = duration; + a_func = func; + a_opacity.start(0); + _hiding = true; + _a_appearance.start(); +} + +void Widget::moveTop(int top) { + a_top.start(top); + _a_movement.start(); +} + +void Widget::addToHeight(int add, AddToHeight aboveOrBelow) { + int newHeight = height() + add; + if (aboveOrBelow == AddToHeight::Above) { + a_top.add(-add); + } + updateGeometry(x(), a_top.current(), width(), newHeight); +} + +void Widget::updateGeometry(int x, int y, int width, int height) { + setGeometry(x, y, width, height); + update(); +} + +void Widget::addToTop(int add) { + a_top.add(add); + move(x(), a_top.current()); +} + +Background::Background(QWidget *parent) : TWidget(parent) { + setAttribute(Qt::WA_OpaquePaintEvent); +} + +void Background::paintEvent(QPaintEvent *e) { + Painter p(this); + + p.fillRect(rect(), st::notifyBg); + p.fillRect(0, 0, st::notifyBorderWidth, height(), st::notifyBorder); + p.fillRect(width() - st::notifyBorderWidth, 0, st::notifyBorderWidth, height(), st::notifyBorder); + 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 position) : Widget(position) , _history(history) , _peer(peer) , _author(author) @@ -189,26 +410,17 @@ Widget::Widget(History *history, PeerData *peer, PeerData *author, HistoryItem * , _started(GetTickCount()) #endif // Q_OS_WIN && !Q_OS_WINRT , _close(this, st::notifyClose) -, _reply(this, lang(lng_notification_reply), st::defaultBoxButton) -, _alphaDuration(st::notifyFastAnim) -, a_opacity(0) -, a_func(anim::linear) -, a_top(y) -, a_bottom(y + st::notifyMinHeight) -, _a_movement(animation(this, &Widget::step_movement)) -, _a_appearance(animation(this, &Widget::step_appearance)) { - setGeometry(x, a_top.current(), notificationWidth(), a_bottom.current() - a_top.current()); +, _reply(this, lang(lng_notification_reply), st::defaultBoxButton) { + updateGeometry(position.x(), position.y(), notificationWidth(), st::notifyMinHeight); + _userpicLoaded = _peer ? _peer->userpicLoaded() : true; updateNotifyDisplay(); _hideTimer.setSingleShot(true); - connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(hideByTimer())); - - _inputTimer.setSingleShot(true); - connect(&_inputTimer, SIGNAL(timeout()), this, SLOT(checkLastInput())); + connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(onHideByTimer())); _close->setClickedCallback([this] { - unlinkHistoryAndNotify(); + unlinkHistoryInManager(); }); _close->setAcceptBoth(true); _close->moveToRight(st::notifyClosePos.x(), st::notifyClosePos.y()); @@ -223,21 +435,15 @@ Widget::Widget(History *history, PeerData *peer, PeerData *author, HistoryItem * prepareActionsCache(); - a_opacity.start(1); - setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint); + setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::BypassWindowManagerHint | Qt::NoDropShadowWindowHint); setAttribute(Qt::WA_MacAlwaysShowToolWindow); + setAttribute(Qt::WA_NoSystemBackground, true); + setAttribute(Qt::WA_TranslucentBackground, true); show(); - - setWindowOpacity(a_opacity.current()); - - _alphaDuration = st::notifyFastAnim; - _a_appearance.start(); - - checkLastInput(); } -void Widget::prepareActionsCache() { +void Notification::prepareActionsCache() { auto replyCache = myGrab(_reply); auto fadeWidth = st::notifyFadeRight.width(); auto actionsTop = st::notifyTextTop + st::msgNameFont->height; @@ -254,53 +460,73 @@ void Widget::prepareActionsCache() { _buttonsCache = App::pixmapFromImageInPlace(std_::move(actionsCacheImg)); } -void Widget::checkLastInput() { +bool Notification::checkLastInput() { + if (!_waitingForInput) return true; + + auto wasUserInput = true; // TODO #if defined Q_OS_WIN && !defined Q_OS_WINRT LASTINPUTINFO lii; lii.cbSize = sizeof(LASTINPUTINFO); BOOL res = GetLastInputInfo(&lii); - if (!res || lii.dwTime >= _started) { - _hideTimer.start(st::notifyWaitLongHide); - } else { - _inputTimer.start(300); + wasUserInput = (!res || lii.dwTime >= _started); +#endif // Q_OS_WIN && !Q_OS_WINRT + if (wasUserInput) { + _waitingForInput = false; + if (!isReplying()) { + _hideTimer.start(st::notifyWaitLongHide); + } + return true; } -#else // Q_OS_WIN && !Q_OS_WINRT - // TODO - if (true) { - _hideTimer.start(st::notifyWaitLongHide); - } else { - _inputTimer.start(300); - } -#endif // else for Q_OS_WIN && !Q_OS_WINRT + return false; } -void Widget::onReplyResize() { - _a_movement.stop(); - auto newHeight = st::notifyMinHeight + _replyArea->height() + st::notifyBorderWidth; - auto delta = height() - newHeight; - if (delta != 0) { - auto top = a_top.current() + delta; - a_top = anim::ivalue(top, top); - setGeometry(x(), top, width(), a_bottom.current() - top); - update(); - } +void Notification::onReplyResize() { + changeHeight(st::notifyMinHeight + _replyArea->height() + st::notifyBorderWidth); } -void Widget::onReplySubmit(bool ctrlShiftEnter) { +void Notification::onReplySubmit(bool ctrlShiftEnter) { sendReply(); } -void Widget::onReplyCancel() { - unlinkHistoryAndNotify(); +void Notification::onReplyCancel() { + unlinkHistoryInManager(); } -void Widget::moveTop(int top, int bottom) { - a_top.start(top); - a_bottom.start(bottom); - _a_movement.start(); +void Notification::updateGeometry(int x, int y, int width, int height) { + if (height > st::notifyMinHeight) { + if (!_background) { + _background = new Background(this); + } + _background->setGeometry(0, st::notifyMinHeight, width, height - st::notifyMinHeight); + } else if (_background) { + _background.destroy(); + } + Widget::updateGeometry(x, y, width, height); } -void Widget::updateNotifyDisplay() { +void Notification::paintEvent(QPaintEvent *e) { + Painter p(this); + p.setClipRect(e->rect()); + p.drawPixmap(0, 0, _cache); + + auto buttonsLeft = st::notifyPhotoPos.x() + st::notifyPhotoSize + st::notifyTextLeft; + auto buttonsTop = st::notifyTextTop + st::msgNameFont->height; + if (a_actionsOpacity.animating(getms())) { + p.setOpacity(a_actionsOpacity.current()); + p.drawPixmapRight(0, buttonsTop, width(), _buttonsCache); + } else if (_actionsVisible) { + p.drawPixmapRight(0, buttonsTop, width(), _buttonsCache); + } +} + +void Notification::actionsOpacityCallback() { + update(); + if (!a_actionsOpacity.animating() && _actionsVisible) { + _reply->show(); + } +} + +void Notification::updateNotifyDisplay() { if (!_history || !_peer || (!_item && _forwardedCount < 2)) return; int32 w = width(), h = height(); @@ -372,50 +598,48 @@ void Widget::updateNotifyDisplay() { update(); } -void Widget::updatePeerPhoto() { - if (!peerPhoto->isNull() && peerPhoto->loaded()) { - auto img = _cache.toImage(); - { - Painter p(&img); - p.drawPixmap(st::notifyPhotoPos.x(), st::notifyPhotoPos.y(), peerPhoto->pix(st::notifyPhotoSize)); - } - peerPhoto = ImagePtr(); - _cache = App::pixmapFromImageInPlace(std_::move(img)); - update(); +void Notification::updatePeerPhoto() { + if (_userpicLoaded || !_peer || !_peer->userpicLoaded()) { + return; } + _userpicLoaded = true; + + auto img = _cache.toImage(); + { + Painter p(&img); + _peer->paintUserpicLeft(p, st::notifyPhotoSize, st::notifyPhotoPos.x(), st::notifyPhotoPos.y(), width()); + } + _cache = App::pixmapFromImageInPlace(std_::move(img)); } -void Widget::itemRemoved(HistoryItem *deleted) { +void Notification::itemRemoved(HistoryItem *deleted) { if (_item && _item == deleted) { _item = nullptr; - unlinkHistoryAndNotify(); + unlinkHistoryInManager(); } } -void Widget::unlinkHistoryAndNotify() { - unlinkHistory(); +void Notification::unlinkHistoryInManager() { if (auto manager = ManagerInstance.data()) { - manager->showNextFromQueue(); + manager->unlinkFromShown(this); } } -void Widget::toggleActionButtons(bool visible) { +void Notification::toggleActionButtons(bool visible) { if (_actionsVisible != visible) { _actionsVisible = visible; - _reply->hide(); a_actionsOpacity.start([this] { actionsOpacityCallback(); }, _actionsVisible ? 0. : 1., _actionsVisible ? 1. : 0., st::notifyActionsDuration); + _reply->hide(); } } -void Widget::actionsOpacityCallback() { - update(); - if (!a_actionsOpacity.animating() && _actionsVisible) { - _reply->show(); - } -} - -void Widget::showReplyField() { +void Notification::showReplyField() { if (_replyArea) return; + stopHiding(); + + _background = new Background(this); + _background->setGeometry(0, st::notifyMinHeight, width(), st::notifySendReply.height + st::notifyBorderWidth); + _background->show(); _replyArea = new InputArea(this, st::notifyReplyArea, lang(lng_message_ph), QString()); _replyArea->resize(width() - st::notifySendReply.width - 2 * st::notifyBorderWidth, st::notifySendReply.height); @@ -435,37 +659,42 @@ void Widget::showReplyField() { toggleActionButtons(false); - a_top.finish(); - a_bottom.finish(); - - _a_movement.stop(); - auto top = a_top.current() - _replyArea->height() - st::notifyBorderWidth; - auto bottom = a_top.current() + st::notifyMinHeight; - a_top = anim::ivalue(top, top); - a_bottom = anim::ivalue(bottom, bottom); - setGeometry(x(), top, width(), bottom - top); + onReplyResize(); update(); } -void Widget::sendReply() { +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()); + + manager->startAllHiding(); } } -void Widget::unlinkHistory(History *history) { - if (!history || history == _history) { - animHide(st::notifyFastAnim, anim::linear); +void Notification::changeHeight(int newHeight) { + if (auto manager = ManagerInstance.data()) { + manager->changeNotificationHeight(this, newHeight); + } +} + +bool Notification::unlinkHistory(History *history) { + auto unlink = _history && (history == _history || !history); + if (unlink) { + if (_history->peer->id != 4456802837) { + int a = 0; + } + hideFast(); _history = nullptr; _item = nullptr; } + return unlink; } -void Widget::enterEvent(QEvent *e) { +void Notification::enterEvent(QEvent *e) { if (!_history) return; if (auto manager = ManagerInstance.data()) { manager->stopAllHiding(); @@ -475,7 +704,7 @@ void Widget::enterEvent(QEvent *e) { } } -void Widget::leaveEvent(QEvent *e) { +void Notification::leaveEvent(QEvent *e) { if (!_history) return; if (auto manager = ManagerInstance.data()) { manager->startAllHiding(); @@ -483,15 +712,16 @@ void Widget::leaveEvent(QEvent *e) { toggleActionButtons(false); } -void Widget::startHiding() { - _hideTimer.start(st::notifyWaitShortHide); +void Notification::startHiding() { + if (!_history) return; + hideSlow(); } -void Widget::mousePressEvent(QMouseEvent *e) { +void Notification::mousePressEvent(QMouseEvent *e) { if (!_history) return; if (e->button() == Qt::RightButton) { - unlinkHistoryAndNotify(); + unlinkHistoryInManager(); } else { e->ignore(); if (auto manager = ManagerInstance.data()) { @@ -502,88 +732,89 @@ void Widget::mousePressEvent(QMouseEvent *e) { } } -void Widget::paintEvent(QPaintEvent *e) { - Painter p(this); - p.drawPixmap(0, 0, _cache); - - auto buttonsLeft = st::notifyPhotoPos.x() + st::notifyPhotoSize + st::notifyTextLeft; - auto buttonsTop = st::notifyTextTop + st::msgNameFont->height; - if (a_actionsOpacity.animating(getms())) { - p.setOpacity(a_actionsOpacity.current()); - p.drawPixmapRight(0, buttonsTop, width(), _buttonsCache); - } else if (_actionsVisible) { - p.drawPixmapRight(0, buttonsTop, width(), _buttonsCache); - } - - if (height() > st::notifyMinHeight) { - auto replyAreaHeight = height() - st::notifyMinHeight - st::notifyBorderWidth; - if (replyAreaHeight > 0) { - p.fillRect(st::notifyBorderWidth, st::notifyMinHeight, width() - 2 * st::notifyBorderWidth, replyAreaHeight, st::notifyBg); - } - p.fillRect(0, st::notifyMinHeight, st::notifyBorderWidth, height() - st::notifyMinHeight, st::notifyBorder); - p.fillRect(width() - st::notifyBorderWidth, st::notifyMinHeight, st::notifyBorderWidth, height() - st::notifyMinHeight, st::notifyBorder); - p.fillRect(st::notifyBorderWidth, height() - st::notifyBorderWidth, width() - 2 * st::notifyBorderWidth, st::notifyBorderWidth, st::notifyBorder); - } -} - -void Widget::animHide(float64 duration, anim::transition func) { +void Notification::stopHiding() { if (!_history) return; - _alphaDuration = duration; - a_func = func; - a_opacity.start(0); - _hiding = true; - _a_appearance.start(); -} - -void Widget::stopHiding() { - if (!_history) return; - _alphaDuration = st::notifyFastAnim; - a_func = anim::linear; - a_opacity.start(1); - _hiding = false; _hideTimer.stop(); - _a_appearance.start(); + Widget::hideStop(); } -void Widget::hideByTimer() { - if (!_history) return; - animHide(st::notifySlowHide, st::notifySlowHideFunc); +void Notification::onHideByTimer() { + startHiding(); } -void Widget::step_appearance(float64 ms, bool timer) { - float64 dt = ms / float64(_alphaDuration); - if (dt >= 1) { - a_opacity.finish(); - _a_appearance.stop(); - if (_hiding) { - deleteLater(); - } - } else { - a_opacity.update(dt, a_func); - } - setWindowOpacity(a_opacity.current()); - update(); -} - -void Widget::step_movement(float64 ms, bool timer) { - float64 dt = ms / float64(st::notifyFastAnim); - if (dt >= 1) { - a_top.finish(); - a_bottom.finish(); - } else { - a_top.update(dt, anim::linear); - a_bottom.update(dt, anim::linear); - } - setGeometry(x(), a_top.current(), width(), a_bottom.current() - a_top.current()); - update(); -} - -Widget::~Widget() { +Notification::~Notification() { if (auto manager = ManagerInstance.data()) { manager->removeFromShown(this); } } +HideAllButton::HideAllButton(QPoint position) : Widget(position) { + setCursor(style::cur_pointer); + + updateGeometry(position.x(), position.y(), notificationWidth(), st::notifyHideAll.height); + hide(); + createWinId(); + + show(); +} + +void HideAllButton::startHiding() { + hideSlow(); +} + +void HideAllButton::startHidingFast() { + hideFast(); +} + +void HideAllButton::stopHiding() { + hideStop(); +} + +HideAllButton::~HideAllButton() { + if (auto manager = ManagerInstance.data()) { + manager->removeHideAll(this); + } +} + +void HideAllButton::enterEvent(QEvent *e) { + _mouseOver = true; + update(); +} + +void HideAllButton::leaveEvent(QEvent *e) { + _mouseOver = false; + update(); +} + +void HideAllButton::mousePressEvent(QMouseEvent *e) { + _mouseDown = true; +} + +void HideAllButton::mouseReleaseEvent(QMouseEvent *e) { + auto mouseDown = createAndSwap(_mouseDown); + if (mouseDown && _mouseOver) { + if (auto manager = ManagerInstance.data()) { + manager->clearAll(); + } + } +} + +void HideAllButton::paintEvent(QPaintEvent *e) { + Painter p(this); + p.setClipRect(e->rect()); + + p.fillRect(rect(), _mouseOver ? st::notifyHideAll.textBgOver : st::notifyHideAll.textBg); + p.fillRect(0, 0, width(), st::notifyBorderWidth, st::notifyBorder); + p.fillRect(0, height() - st::notifyBorderWidth, width(), st::notifyBorderWidth, st::notifyBorder); + p.fillRect(0, st::notifyBorderWidth, st::notifyBorderWidth, height() - 2 * st::notifyBorderWidth, st::notifyBorder); + p.fillRect(width() - st::notifyBorderWidth, st::notifyBorderWidth, st::notifyBorderWidth, height() - 2 * st::notifyBorderWidth, st::notifyBorder); + + p.setFont(st::btnDefLink.font); + p.setPen(st::btnDefLink.color); + p.drawText(rect(), lang(lng_notification_hide_all), style::al_center); +} + +} // namespace internal } // namespace Default } // namespace Notifications } // namespace Window diff --git a/Telegram/SourceFiles/window/notifications_manager_default.h b/Telegram/SourceFiles/window/notifications_manager_default.h index 2d2c1cfa54..6094b8037e 100644 --- a/Telegram/SourceFiles/window/notifications_manager_default.h +++ b/Telegram/SourceFiles/window/notifications_manager_default.h @@ -21,6 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #pragma once #include "window/notifications_manager.h" +#include "core/single_timer.h" namespace Ui { class IconButton; @@ -29,9 +30,12 @@ class IconButton; namespace Window { namespace Notifications { namespace Default { +namespace internal { +class Notification; +class HideAllButton; +} // namespace internal class Manager; -class Widget; void start(); Manager *manager(); @@ -41,21 +45,21 @@ class Manager : public Notifications::Manager, private base::Subscriber { public: Manager(); - void showNextFromQueue(); - void removeFromShown(Widget *remove); - void startAllHiding(); - void stopAllHiding(); - template - void enumerateWidgets(Method method) { - for_const (auto widget, _widgets) { - method(widget); + void enumerateNotifications(Method method) { + for_const (auto notification, _notifications) { + method(notification); } } ~Manager(); private: + using Notification = internal::Notification; + friend class Notification; + using HideAllButton = internal::HideAllButton; + friend class HideAllButton; + void doUpdateAll() override; void doShowNotification(HistoryItem *item, int forwardedCount) override; void doClearAll() override; @@ -63,8 +67,25 @@ private: void doClearFromHistory(History *history) override; void doClearFromItem(HistoryItem *item) override; - using Widgets = QList; - Widgets _widgets; + void showNextFromQueue(); + void unlinkFromShown(Notification *remove); + void removeFromShown(Notification *remove); + void removeHideAll(HideAllButton *remove); + void startAllHiding(); + void stopAllHiding(); + void checkLastInput(); + + QPoint notificationStartPosition() const; + void moveWidgets(); + void changeNotificationHeight(Notification *widget, int newHeight); + + using Notifications = QList; + Notifications _notifications; + + HideAllButton *_hideAll = nullptr; + + bool _positionsOutdated = false; + SingleTimer _inputCheckTimer; struct QueuedNotification { QueuedNotification(HistoryItem *item, int forwardedCount) @@ -86,52 +107,109 @@ private: }; +namespace internal { + class Widget : public TWidget { - Q_OBJECT - public: - Widget(History *history, PeerData *peer, PeerData *author, HistoryItem *item, int forwardedCount, int x, int y); + Widget(QPoint position); - void startHiding(); - void stopHiding(); - void moveTop(int top, int bottom); - - void updateNotifyDisplay(); - void updatePeerPhoto(); - - void itemRemoved(HistoryItem *del); - - int isUnlinked() const { - return !_history; + bool isShowing() const { + return _a_appearance.animating() && !_hiding; } + void moveTop(int top); - void unlinkHistory(History *history = nullptr); - - ~Widget(); + enum class AddToHeight { + Above, + Below, + }; + void addToHeight(int add, AddToHeight aboveOrBelow); + void addToTop(int add); protected: - void enterEvent(QEvent *e) override; - void leaveEvent(QEvent *e) override; - void mousePressEvent(QMouseEvent *e) override; - void paintEvent(QPaintEvent *e) override; + void hideSlow(); + void hideFast(); + void hideStop(); -private slots: - void hideByTimer(); - void checkLastInput(); - void onReplyResize(); - void onReplySubmit(bool ctrlShiftEnter); - void onReplyCancel(); + virtual void updateGeometry(int x, int y, int width, int height); private: void animHide(float64 duration, anim::transition func); void step_appearance(float64 ms, bool timer); void step_movement(float64 ms, bool timer); - void unlinkHistoryAndNotify(); + + bool _hiding = false; + float64 _opacityDuration; + anim::fvalue a_opacity; + anim::transition a_func; + Animation _a_appearance; + + anim::ivalue a_top; + Animation _a_movement; + +}; + +class Background : public TWidget { +public: + Background(QWidget *parent); + +protected: + void paintEvent(QPaintEvent *e) override; + +}; + +class Notification : public Widget { + Q_OBJECT + +public: + Notification(History *history, PeerData *peer, PeerData *author, HistoryItem *item, int forwardedCount, QPoint position); + + void startHiding(); + void stopHiding(); + + void updateNotifyDisplay(); + void updatePeerPhoto(); + + bool isUnlinked() const { + return !_history; + } + bool isReplying() const { + return (_replyArea != nullptr) && !isUnlinked(); + } + + // Called only by Manager. + void itemRemoved(HistoryItem *del); + bool unlinkHistory(History *history = nullptr); + bool checkLastInput(); + + ~Notification(); + +protected: + void enterEvent(QEvent *e) override; + void leaveEvent(QEvent *e) override; + void paintEvent(QPaintEvent *e) override; + void mousePressEvent(QMouseEvent *e) override; + +private slots: + void onHideByTimer(); + void onReplyResize(); + void onReplySubmit(bool ctrlShiftEnter); + void onReplyCancel(); + +private: + void unlinkHistoryInManager(); void toggleActionButtons(bool visible); void prepareActionsCache(); - void actionsOpacityCallback(); void showReplyField(); void sendReply(); + void changeHeight(int newHeight); + void updateGeometry(int x, int y, int width, int height) override; + void actionsOpacityCallback(); + + QPixmap _cache; + + bool _actionsVisible = false; + FloatAnimation a_actionsOpacity; + QPixmap _buttonsCache; #if defined Q_OS_WIN && !defined Q_OS_WINRT uint64 _started; @@ -144,29 +222,43 @@ private: int _forwardedCount; ChildWidget _close; ChildWidget _reply; + ChildWidget _background = { nullptr }; ChildWidget _replyArea = { nullptr }; ChildWidget _replySend = { nullptr }; - QPixmap _cache; - float64 _alphaDuration; - QTimer _hideTimer, _inputTimer; - bool _hiding = false; + bool _waitingForInput = true; - anim::ivalue a_top, a_bottom; - Animation _a_movement; - - anim::fvalue a_opacity; - anim::transition a_func; - Animation _a_appearance; + QTimer _hideTimer; int _replyPadding = 0; - bool _actionsVisible = false; - FloatAnimation a_actionsOpacity; - QPixmap _buttonsCache; - ImagePtr peerPhoto; + bool _userpicLoaded = false; }; +class HideAllButton : public Widget { +public: + HideAllButton(QPoint position); + + void startHiding(); + void startHidingFast(); + void stopHiding(); + + ~HideAllButton(); + +protected: + void enterEvent(QEvent *e) override; + void leaveEvent(QEvent *e) override; + void mousePressEvent(QMouseEvent *e) override; + void mouseReleaseEvent(QMouseEvent *e) override; + void paintEvent(QPaintEvent *e) override; + +private: + bool _mouseOver = false; + bool _mouseDown = false; + +}; + +} // namespace internal } // namespace Default } // namespace Notifications } // namespace Window diff --git a/Telegram/SourceFiles/window/notifications_utilities.h b/Telegram/SourceFiles/window/notifications_utilities.h index 384690d300..f5609210b2 100644 --- a/Telegram/SourceFiles/window/notifications_utilities.h +++ b/Telegram/SourceFiles/window/notifications_utilities.h @@ -21,6 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #pragma once #include "window/notifications_manager.h" +#include "core/single_timer.h" namespace Window { namespace Notifications { diff --git a/Telegram/SourceFiles/window/window.style b/Telegram/SourceFiles/window/window.style index 2c8e3da713..c2b4a20d24 100644 --- a/Telegram/SourceFiles/window/window.style +++ b/Telegram/SourceFiles/window/window.style @@ -35,8 +35,7 @@ notifyItemTop: 12px; notifyTextLeft: 12px; notifyTextTop: 7px; notifySlowHideFunc: transition(easeInCirc); -notifyWaitShortHide: 0; -notifyWaitLongHide: 20000; +notifyWaitLongHide: 3000; notifyFastAnim: 150; notifyMinWidth: 316px; notifyMinHeight: 80px; @@ -44,6 +43,9 @@ notifyDeltaX: 6px; notifyDeltaY: 7px; notifyActionsDuration: 200; +notifyHideAll: RoundButton(defaultBoxButton) { +} + notifyFadeRight: icon {{ "fade_horizontal_right", notifyBg }}; notifyReplyArea: InputArea(defaultInputArea) { font: normalFont; diff --git a/Telegram/gyp/Telegram.gyp b/Telegram/gyp/Telegram.gyp index 7598ad52ca..8f096ee360 100644 --- a/Telegram/gyp/Telegram.gyp +++ b/Telegram/gyp/Telegram.gyp @@ -205,6 +205,8 @@ '<(src_loc)/core/qthelp_url.h', '<(src_loc)/core/runtime_composer.cpp', '<(src_loc)/core/runtime_composer.h', + '<(src_loc)/core/single_timer.cpp', + '<(src_loc)/core/single_timer.h', '<(src_loc)/core/stl_subset.h', '<(src_loc)/core/utils.cpp', '<(src_loc)/core/utils.h',