From a70613d92925ad730f47760fa26abeb79da05503 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 27 Sep 2018 23:31:48 +0300 Subject: [PATCH 1/7] Fix client side generated changelogs display. Also use message date if available in MediaView. --- Telegram/Resources/langs/lang.strings | 4 +- Telegram/SourceFiles/apiwrap.cpp | 22 ++++-- Telegram/SourceFiles/apiwrap.h | 8 +- Telegram/SourceFiles/base/assertion.h | 4 + Telegram/SourceFiles/core/changelogs.cpp | 5 +- Telegram/SourceFiles/data/data_session.cpp | 73 ++++++++++++++++++- Telegram/SourceFiles/data/data_session.h | 9 +++ Telegram/SourceFiles/history/history.cpp | 26 ++++++- Telegram/SourceFiles/history/history.h | 1 + Telegram/SourceFiles/mainwidget.cpp | 68 +---------------- Telegram/SourceFiles/mainwidget.h | 4 - Telegram/SourceFiles/mainwindow.cpp | 65 ----------------- Telegram/SourceFiles/mainwindow.h | 12 --- Telegram/SourceFiles/mediaview.cpp | 10 +-- .../SourceFiles/settings/settings_chat.cpp | 25 ------- Telegram/SourceFiles/settings/settings_chat.h | 1 - .../SourceFiles/settings/settings_common.cpp | 2 +- 17 files changed, 141 insertions(+), 198 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 1bd0e33ed0106..f7e6ec51ddbcb 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -331,15 +331,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_settings_language" = "Language"; "lng_settings_default_scale" = "Default interface scale"; -"lng_settings_edit_info" = "Edit information"; "lng_settings_connection_type" = "Connection type"; "lng_settings_downloading_update" = "Downloading update {progress}..."; -"lng_settings_use_night_mode" = "Use night mode"; "lng_settings_privacy_title" = "Privacy"; "lng_settings_last_seen" = "Last seen"; "lng_settings_calls" = "Voice calls"; "lng_settings_groups_invite" = "Groups"; -"lng_settings_group_privacy_about" = "Change who can add you to groups and channel."; +"lng_settings_group_privacy_about" = "Change who can add you to groups and channels."; "lng_settings_sessions_about" = "Control your sessions on other devices."; "lng_settings_passcode_disable" = "Disable passcode"; "lng_settings_password_disable" = "Disable cloud password"; diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 9946d7dda4c1e..261fb909babed 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -610,11 +610,23 @@ void ApiWrap::requestDialogEntry(not_null feed) { // }).send(); //} -void ApiWrap::requestDialogEntry(not_null history) { - if (_dialogRequests.contains(history)) { +void ApiWrap::requestDialogEntry( + not_null history, + Fn callback) { + const auto[i, ok] = _dialogRequests.try_emplace(history); + if (callback) { + i->second.push_back(std::move(callback)); + } + if (!ok) { return; } - _dialogRequests.emplace(history); + const auto finalize = [=] { + if (const auto callbacks = _dialogRequests.take(history)) { + for (const auto callback : *callbacks) { + callback(); + } + } + }; auto peers = QVector( 1, MTP_inputDialogPeer(history->peer->input)); @@ -623,9 +635,9 @@ void ApiWrap::requestDialogEntry(not_null history) { )).done([=](const MTPmessages_PeerDialogs &result) { applyPeerDialogs(result); historyDialogEntryApplied(history); - _dialogRequests.remove(history); + finalize(); }).fail([=](const RPCError &error) { - _dialogRequests.remove(history); + finalize(); }).send(); } diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h index c37f3fbaab44a..7913a6672ddb1 100644 --- a/Telegram/SourceFiles/apiwrap.h +++ b/Telegram/SourceFiles/apiwrap.h @@ -84,7 +84,9 @@ class ApiWrap : private MTP::Sender, private base::Subscriber { void requestContacts(); void requestDialogEntry(not_null feed); //void requestFeedDialogsEntries(not_null feed); - void requestDialogEntry(not_null history); + void requestDialogEntry( + not_null history, + Fn callback = nullptr); //void applyFeedSources(const MTPDchannels_feedSources &data); // #feed //void setFeedChannels( // not_null feed, @@ -622,7 +624,9 @@ class ApiWrap : private MTP::Sender, private base::Subscriber { mtpRequestId _contactsRequestId = 0; mtpRequestId _contactsStatusesRequestId = 0; base::flat_set> _dialogFeedRequests; - base::flat_set> _dialogRequests; + base::flat_map< + not_null, + std::vector>> _dialogRequests; base::flat_map, mtpRequestId> _unreadMentionsRequests; diff --git a/Telegram/SourceFiles/base/assertion.h b/Telegram/SourceFiles/base/assertion.h index 39cb7a2965092..c67873f617d74 100644 --- a/Telegram/SourceFiles/base/assertion.h +++ b/Telegram/SourceFiles/base/assertion.h @@ -66,3 +66,7 @@ inline constexpr void validate(bool condition, const char *message, const char * #undef Unexpected #endif // Unexpected #define Unexpected(message) (::base::assertion::fail("Unexpected: " message, __FILE__, __LINE__)) + +#ifdef _DEBUG +#define AssertIsDebug(...) +#endif // _DEBUG diff --git a/Telegram/SourceFiles/core/changelogs.cpp b/Telegram/SourceFiles/core/changelogs.cpp index 70e4686a2bbf8..1564c17d485a0 100644 --- a/Telegram/SourceFiles/core/changelogs.cpp +++ b/Telegram/SourceFiles/core/changelogs.cpp @@ -146,10 +146,9 @@ void Changelogs::addLocalLogs() { void Changelogs::addLocalLog(const QString &text) { auto textWithEntities = TextWithEntities{ text }; TextUtilities::ParseEntities(textWithEntities, TextParseLinks); - App::wnd()->serviceNotification( + _session->data().serviceNotification( textWithEntities, - MTP_messageMediaEmpty(), - unixtime()); + MTP_messageMediaEmpty()); _addedSomeLocal = true; }; diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index 37536d510f3ff..10ba615234666 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -329,7 +329,7 @@ void Session::notifyItemIdChange(IdChange event) { view->refreshDataId(); }; enumerateItemViews(event.item, refreshViewDataId); - if (const auto group = Auth().data().groups().find(event.item)) { + if (const auto group = groups().find(event.item)) { const auto leader = group->items.back(); if (leader != event.item) { enumerateItemViews(leader, refreshViewDataId); @@ -1922,6 +1922,77 @@ rpl::producer<> Session::defaultNotifyUpdates( : defaultChatNotifyUpdates(); } +void Session::serviceNotification( + const TextWithEntities &message, + const MTPMessageMedia &media) { + const auto date = unixtime(); + if (!App::userLoaded(ServiceUserId)) { + App::feedUsers(MTP_vector(1, MTP_user( + MTP_flags( + MTPDuser::Flag::f_first_name + | MTPDuser::Flag::f_phone + | MTPDuser::Flag::f_status + | MTPDuser::Flag::f_verified), + MTP_int(ServiceUserId), + MTPlong(), + MTP_string("Telegram"), + MTPstring(), + MTPstring(), + MTP_string("42777"), + MTP_userProfilePhotoEmpty(), + MTP_userStatusRecently(), + MTPint(), + MTPstring(), + MTPstring(), + MTPstring()))); + } + const auto history = App::history(peerFromUser(ServiceUserId)); + if (!history->lastMessageKnown()) { + _session->api().requestDialogEntry(history, [=] { + insertCheckedServiceNotification(message, media, date); + }); + } else { + insertCheckedServiceNotification(message, media, date); + } +} + +void Session::insertCheckedServiceNotification( + const TextWithEntities &message, + const MTPMessageMedia &media, + TimeId date) { + const auto history = App::history(peerFromUser(ServiceUserId)); + if (!history->isReadyFor(ShowAtUnreadMsgId)) { + history->setUnreadCount(0); + history->getReadyFor(ShowAtTheEndMsgId); + } + const auto flags = MTPDmessage::Flag::f_entities + | MTPDmessage::Flag::f_from_id + | MTPDmessage_ClientFlag::f_clientside_unread; + auto sending = TextWithEntities(), left = message; + while (TextUtilities::CutPart(sending, left, MaxMessageSize)) { + App::histories().addNewMessage( + MTP_message( + MTP_flags(flags), + MTP_int(clientMsgId()), + MTP_int(ServiceUserId), + MTP_peerUser(MTP_int(_session->userId())), + MTPnullFwdHeader, + MTPint(), + MTPint(), + MTP_int(date), + MTP_string(sending.text), + media, + MTPnullMarkup, + TextUtilities::EntitiesToMTP(sending.entities), + MTPint(), + MTPint(), + MTPstring(), + MTPlong()), + NewMessageUnread); + } + sendHistoryChangeNotifications(); +} + void Session::forgetMedia() { for (const auto &[id, photo] : _photos) { photo->forget(); diff --git a/Telegram/SourceFiles/data/data_session.h b/Telegram/SourceFiles/data/data_session.h index c20db99dfecc8..81b75122ed320 100644 --- a/Telegram/SourceFiles/data/data_session.h +++ b/Telegram/SourceFiles/data/data_session.h @@ -410,6 +410,10 @@ class Session final { rpl::producer<> defaultNotifyUpdates( not_null peer) const; + void serviceNotification( + const TextWithEntities &message, + const MTPMessageMedia &media); + void forgetMedia(); void setMimeForwardIds(MessageIdsList &&list); @@ -521,6 +525,11 @@ class Session final { not_null item, Method method); + void insertCheckedServiceNotification( + const TextWithEntities &message, + const MTPMessageMedia &media, + TimeId date); + not_null _session; Storage::DatabasePointer _cache; diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp index 6fb0744b50c65..c61fbbd46066e 100644 --- a/Telegram/SourceFiles/history/history.cpp +++ b/Telegram/SourceFiles/history/history.cpp @@ -2176,8 +2176,13 @@ void History::markFullyLoaded() { void History::setLastMessage(HistoryItem *item) { if (item) { - if (_lastMessage && !*_lastMessage) { - Local::removeSavedPeer(peer); + if (_lastMessage) { + if (!*_lastMessage) { + Local::removeSavedPeer(peer); + } else if (!IsServerMsgId((*_lastMessage)->id) + && (*_lastMessage)->date() > item->date()) { + return; + } } _lastMessage = item; if (const auto feed = peer->feed()) { @@ -2280,12 +2285,25 @@ void History::applyDialog(const MTPDdialog &data) { } } +bool History::skipUnreadUpdateForClientSideUnread() const { + if (peer->id != peerFromUser(ServiceUserId)) { + return false; + } else if (!_unreadCount || !*_unreadCount) { + return false; + } else if (!_lastMessage || IsServerMsgId((*_lastMessage)->id)) { + return false; + } + return true; +} + void History::applyDialogFields( int unreadCount, MsgId maxInboxRead, MsgId maxOutboxRead) { - setUnreadCount(unreadCount); - setInboxReadTill(maxInboxRead); + if (!skipUnreadUpdateForClientSideUnread()) { + setUnreadCount(unreadCount); + setInboxReadTill(maxInboxRead); + } setOutboxReadTill(maxOutboxRead); } diff --git a/Telegram/SourceFiles/history/history.h b/Telegram/SourceFiles/history/history.h index e4822988f9e20..4b3c5ae73a025 100644 --- a/Telegram/SourceFiles/history/history.h +++ b/Telegram/SourceFiles/history/history.h @@ -471,6 +471,7 @@ class History : public Dialogs::Entry { void addItemsToLists(const std::vector> &items); void clearSendAction(not_null from); + bool skipUnreadUpdateForClientSideUnread() const; HistoryItem *lastAvailableMessage() const; void getNextFirstUnreadMessage(); diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 4f420e4657807..3d48ba73dab06 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -1690,71 +1690,6 @@ void MainWidget::dialogsCancelled() { _history->activate(); } -void MainWidget::insertCheckedServiceNotification(const TextWithEntities &message, const MTPMessageMedia &media, int32 date) { - auto flags = MTPDmessage::Flag::f_entities | MTPDmessage::Flag::f_from_id | MTPDmessage_ClientFlag::f_clientside_unread; - auto sending = TextWithEntities(), left = message; - HistoryItem *item = nullptr; - while (TextUtilities::CutPart(sending, left, MaxMessageSize)) { - auto localEntities = TextUtilities::EntitiesToMTP(sending.entities); - item = App::histories().addNewMessage( - MTP_message( - MTP_flags(flags), - MTP_int(clientMsgId()), - MTP_int(ServiceUserId), - MTP_peerUser(MTP_int(Auth().userId())), - MTPnullFwdHeader, - MTPint(), - MTPint(), - MTP_int(date), - MTP_string(sending.text), - media, - MTPnullMarkup, - localEntities, - MTPint(), - MTPint(), - MTPstring(), - MTPlong()), - NewMessageUnread); - } - Auth().data().sendHistoryChangeNotifications(); -} - -void MainWidget::serviceHistoryDone(const MTPmessages_Messages &msgs) { - auto handleResult = [&](auto &&result) { - App::feedUsers(result.vusers); - App::feedChats(result.vchats); - App::feedMsgs(result.vmessages, NewMessageLast); - }; - - switch (msgs.type()) { - case mtpc_messages_messages: - handleResult(msgs.c_messages_messages()); - break; - - case mtpc_messages_messagesSlice: - handleResult(msgs.c_messages_messagesSlice()); - break; - - case mtpc_messages_channelMessages: - LOG(("API Error: received messages.channelMessages! (MainWidget::serviceHistoryDone)")); - handleResult(msgs.c_messages_channelMessages()); - break; - - case mtpc_messages_messagesNotModified: - LOG(("API Error: received messages.messagesNotModified! (MainWidget::serviceHistoryDone)")); - break; - } - - App::wnd()->showDelayedServiceMsgs(); -} - -bool MainWidget::serviceHistoryFail(const RPCError &error) { - if (MTP::isDefaultHandledError(error)) return false; - - App::wnd()->showDelayedServiceMsgs(); - return false; -} - bool MainWidget::isIdle() const { return _isIdle; } @@ -3664,7 +3599,6 @@ void MainWidget::start() { update(); _started = true; - App::wnd()->sendServiceHistoryRequest(); Local::readInstalledStickers(); Local::readFeaturedStickers(); Local::readRecentStickers(); @@ -4905,7 +4839,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { } else if (d.is_popup()) { Ui::show(Box(text)); } else { - App::wnd()->serviceNotification(text, d.vmedia); + Auth().data().serviceNotification(text, d.vmedia); emit App::wnd()->checkNewAuthorization(); } } break; diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index 7372ff4a79b46..aacf3052f43dc 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -239,10 +239,6 @@ class MainWidget : public Ui::RpWidget, public RPCSender, private base::Subscrib void checkLastUpdate(bool afterSleep); - void insertCheckedServiceNotification(const TextWithEntities &message, const MTPMessageMedia &media, int32 date); - void serviceHistoryDone(const MTPmessages_Messages &msgs); - bool serviceHistoryFail(const RPCError &error); - bool isIdle() const; QPixmap cachedBackground(const QRect &forRect, int &x, int &y); diff --git a/Telegram/SourceFiles/mainwindow.cpp b/Telegram/SourceFiles/mainwindow.cpp index d77c09cc33a85..24ee85f139b04 100644 --- a/Telegram/SourceFiles/mainwindow.cpp +++ b/Telegram/SourceFiles/mainwindow.cpp @@ -212,71 +212,6 @@ void MainWindow::setupIntro() { } fixOrder(); - - _delayedServiceMsgs.clear(); - if (_serviceHistoryRequest) { - MTP::cancel(_serviceHistoryRequest); - _serviceHistoryRequest = 0; - } -} - -void MainWindow::serviceNotification(const TextWithEntities &message, const MTPMessageMedia &media, int32 date, bool force) { - if (date <= 0) date = unixtime(); - auto h = (_main && App::userLoaded(ServiceUserId)) ? App::history(ServiceUserId).get() : nullptr; - if (!h || (!force && h->isEmpty())) { - _delayedServiceMsgs.push_back(DelayedServiceMsg(message, media, date)); - return sendServiceHistoryRequest(); - } - - _main->insertCheckedServiceNotification(message, media, date); -} - -void MainWindow::showDelayedServiceMsgs() { - for (auto &delayed : base::take(_delayedServiceMsgs)) { - serviceNotification(delayed.message, delayed.media, delayed.date, true); - } -} - -void MainWindow::sendServiceHistoryRequest() { - if (!_main || !_main->started() || _delayedServiceMsgs.isEmpty() || _serviceHistoryRequest) return; - - auto user = App::userLoaded(ServiceUserId); - if (!user) { - auto userFlags = MTPDuser::Flag::f_first_name | MTPDuser::Flag::f_phone | MTPDuser::Flag::f_status | MTPDuser::Flag::f_verified; - user = App::feedUsers(MTP_vector(1, MTP_user( - MTP_flags(userFlags), - MTP_int(ServiceUserId), - MTPlong(), - MTP_string("Telegram"), - MTPstring(), - MTPstring(), - MTP_string("42777"), - MTP_userProfilePhotoEmpty(), - MTP_userStatusRecently(), - MTPint(), - MTPstring(), - MTPstring(), - MTPstring()))); - } - auto offsetId = 0; - auto offsetDate = 0; - auto addOffset = 0; - auto limit = 1; - auto maxId = 0; - auto minId = 0; - auto historyHash = 0; - _serviceHistoryRequest = MTP::send( - MTPmessages_GetHistory( - user->input, - MTP_int(offsetId), - MTP_int(offsetDate), - MTP_int(addOffset), - MTP_int(limit), - MTP_int(maxId), - MTP_int(minId), - MTP_int(historyHash)), - _main->rpcDone(&MainWidget::serviceHistoryDone), - _main->rpcFail(&MainWidget::serviceHistoryFail)); } void MainWindow::setupMain() { diff --git a/Telegram/SourceFiles/mainwindow.h b/Telegram/SourceFiles/mainwindow.h index dc4171dcb7fcb..3fe9471ae94f4 100644 --- a/Telegram/SourceFiles/mainwindow.h +++ b/Telegram/SourceFiles/mainwindow.h @@ -53,9 +53,6 @@ class MainWindow : public Platform::MainWindow { void clearPasscodeLock(); void setupIntro(); void setupMain(); - void serviceNotification(const TextWithEntities &message, const MTPMessageMedia &media = MTP_messageMediaEmpty(), int32 date = 0, bool force = false); - void sendServiceHistoryRequest(); - void showDelayedServiceMsgs(); MainWidget *chatsWidget() { return mainWidget(); @@ -166,15 +163,6 @@ public slots: void placeSmallCounter(QImage &img, int size, int count, style::color bg, const QPoint &shift, style::color color) override; QImage icon16, icon32, icon64, iconbig16, iconbig32, iconbig64; - struct DelayedServiceMsg { - DelayedServiceMsg(const TextWithEntities &message, const MTPMessageMedia &media, int32 date) : message(message), media(media), date(date) { - } - TextWithEntities message; - MTPMessageMedia media; - int32 date; - }; - QList _delayedServiceMsgs; - mtpRequestId _serviceHistoryRequest = 0; TimeMs _lastTrayClickTime = 0; object_ptr _passcodeLock = { nullptr }; diff --git a/Telegram/SourceFiles/mediaview.cpp b/Telegram/SourceFiles/mediaview.cpp index a064d67f4fc72..647ef4118b7ee 100644 --- a/Telegram/SourceFiles/mediaview.cpp +++ b/Telegram/SourceFiles/mediaview.cpp @@ -336,12 +336,12 @@ void MediaView::updateControls() { const auto dNow = QDateTime::currentDateTime(); const auto d = [&] { - if (_photo) { + if (const auto item = App::histItemById(_msgid)) { + return ItemDateTime(item); + } else if (_photo) { return ParseDateTime(_photo->date); } else if (_doc) { return ParseDateTime(_doc->date); - } else if (const auto item = App::histItemById(_msgid)) { - return ItemDateTime(item); } return dNow; }(); @@ -588,8 +588,8 @@ void MediaView::step_radial(TimeMs ms, bool timer) { } const auto wasAnimating = _radial.animating(); const auto updated = _radial.update( - radialProgress(), - !radialLoading(), + radialProgress(), + !radialLoading(), ms + radialTimeShift()); if (timer && (wasAnimating || _radial.animating()) && (!anim::Disabled() || updated)) { update(radialRect()); diff --git a/Telegram/SourceFiles/settings/settings_chat.cpp b/Telegram/SourceFiles/settings/settings_chat.cpp index d7609e6702399..0ceee59954c0e 100644 --- a/Telegram/SourceFiles/settings/settings_chat.cpp +++ b/Telegram/SourceFiles/settings/settings_chat.cpp @@ -707,30 +707,6 @@ void SetupChatBackground(not_null container) { }, adaptive->lifetime()); } -void SetupNightMode(not_null container) { - const auto calling = Ui::AttachAsChild(container, 0); - AddButton( - container, - lng_settings_use_night_mode, - st::settingsButton - )->toggleOn( - rpl::single(Window::Theme::IsNightMode()) - )->toggledValue( - ) | rpl::start_with_next([=](bool toggled) { - ++*calling; - const auto change = [=] { - if (!--*calling && toggled != Window::Theme::IsNightMode()) { - Window::Theme::ToggleNightMode(); - Window::Theme::KeepApplied(); - } - }; - App::CallDelayed( - st::settingsButton.toggle.duration, - container, - change); - }, container->lifetime()); -} - void SetupUseDefaultTheme(not_null container) { using Update = const Window::Theme::BackgroundUpdate; container->add( @@ -940,7 +916,6 @@ void SetupThemeOptions(not_null container) { AddSubsectionTitle(container, lng_settings_themes); SetupDefaultThemes(container); - //SetupNightMode(container); AddButton( container, diff --git a/Telegram/SourceFiles/settings/settings_chat.h b/Telegram/SourceFiles/settings/settings_chat.h index a3fcb3986e99b..5446efe6bcca8 100644 --- a/Telegram/SourceFiles/settings/settings_chat.h +++ b/Telegram/SourceFiles/settings/settings_chat.h @@ -12,7 +12,6 @@ For license and copyright information please follow this link: namespace Settings { void SetupDataStorage(not_null container); -void SetupNightMode(not_null container); void SetupUseDefaultTheme(not_null container); void SetupDefaultThemes(not_null container); diff --git a/Telegram/SourceFiles/settings/settings_common.cpp b/Telegram/SourceFiles/settings/settings_common.cpp index 5e752664e1e77..bc7b5530adf24 100644 --- a/Telegram/SourceFiles/settings/settings_common.cpp +++ b/Telegram/SourceFiles/settings/settings_common.cpp @@ -169,7 +169,7 @@ void AddSubsectionTitle( void FillMenu(Fn showOther, MenuCallback addAction) { addAction( - lang(lng_settings_edit_info), + lang(lng_settings_information), [=] { showOther(Type::Information); }); addAction( lang(lng_settings_logout), From f493d69bd26c541c5d244d2138df96a0cfe8616c Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 27 Sep 2018 23:41:49 +0300 Subject: [PATCH 2/7] Fix emoji button with disabled animations. --- Telegram/SourceFiles/ui/special_buttons.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/ui/special_buttons.cpp b/Telegram/SourceFiles/ui/special_buttons.cpp index e072b8449ad3e..f506311b162fe 100644 --- a/Telegram/SourceFiles/ui/special_buttons.cpp +++ b/Telegram/SourceFiles/ui/special_buttons.cpp @@ -201,7 +201,7 @@ void EmojiButton::paintEvent(QPaintEvent *e) { : (over ? st::historyEmojiCircleFgOver : st::historyEmojiCircleFg)); - if (_loading && anim::Disabled()) { + if (anim::Disabled() && _loading && _loading->animating()) { anim::DrawStaticLoading( p, inner, From 7ee1af53489584eda038e6dcd12955c8ba6f9018 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 28 Sep 2018 00:18:30 +0300 Subject: [PATCH 3/7] Move advanced notifications settings from box. --- Telegram/Resources/langs/lang.strings | 1 - Telegram/SourceFiles/boxes/boxes.style | 4 - .../SourceFiles/boxes/notifications_box.cpp | 420 --------------- .../SourceFiles/boxes/notifications_box.h | 65 --- .../settings/settings_notifications.cpp | 505 +++++++++++++++++- Telegram/gyp/telegram_sources.txt | 2 - 6 files changed, 489 insertions(+), 508 deletions(-) delete mode 100644 Telegram/SourceFiles/boxes/notifications_box.cpp delete mode 100644 Telegram/SourceFiles/boxes/notifications_box.h diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index f7e6ec51ddbcb..196b30b24490c 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -278,7 +278,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_settings_show_preview" = "Show message preview"; "lng_settings_use_windows" = "Use Windows notifications"; "lng_settings_use_native_notifications" = "Use native notifications"; -"lng_settings_advanced_notifications" = "Notifications position and count"; "lng_settings_notifications_position" = "Location on the screen"; "lng_settings_notifications_count" = "Notifications count"; "lng_settings_sound_notify" = "Play sound"; diff --git a/Telegram/SourceFiles/boxes/boxes.style b/Telegram/SourceFiles/boxes/boxes.style index c885d081959d9..e98d5aa913cb1 100644 --- a/Telegram/SourceFiles/boxes/boxes.style +++ b/Telegram/SourceFiles/boxes/boxes.style @@ -403,13 +403,9 @@ shareColumnSkip: 6px; shareActivateDuration: 150; shareScrollDuration: 300; -notificationsBoxHeight: 420px; -notificationsBoxMonitorTop: 63px; notificationsBoxMonitor: icon {{ "monitor", notificationsBoxMonitorFg }}; notificationsBoxScreenTop: 10px; notificationsBoxScreenSize: size(280px, 160px); -notificationsBoxCountLabelTop: 80px; -notificationsBoxCountTop: 30px; notificationsSampleSkip: 5px; notificationsSampleTopSkip: 5px; diff --git a/Telegram/SourceFiles/boxes/notifications_box.cpp b/Telegram/SourceFiles/boxes/notifications_box.cpp deleted file mode 100644 index 9685673a28979..0000000000000 --- a/Telegram/SourceFiles/boxes/notifications_box.cpp +++ /dev/null @@ -1,420 +0,0 @@ -/* -This file is part of Telegram Desktop, -the official desktop application for the Telegram messaging service. - -For license and copyright information please follow this link: -https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL -*/ -#include "boxes/notifications_box.h" - -#include "lang/lang_keys.h" -#include "ui/widgets/buttons.h" -#include "ui/widgets/discrete_sliders.h" -#include "styles/style_boxes.h" -#include "styles/style_dialogs.h" -#include "styles/style_window.h" -#include "messenger.h" -#include "storage/localstorage.h" -#include "auth_session.h" -#include "window/notifications_manager.h" -#include "platform/platform_specific.h" - -namespace { - -constexpr int kMaxNotificationsCount = 5; - -using ChangeType = Window::Notifications::ChangeType; - -} // namespace - -class NotificationsBox::SampleWidget : public QWidget { -public: - SampleWidget(NotificationsBox *owner, const QPixmap &cache) : QWidget(nullptr) - , _owner(owner) - , _cache(cache) { - resize(cache.width() / cache.devicePixelRatio(), cache.height() / cache.devicePixelRatio()); - - setWindowFlags(Qt::WindowFlags(Qt::FramelessWindowHint) | Qt::WindowStaysOnTopHint | Qt::BypassWindowManagerHint | Qt::NoDropShadowWindowHint | Qt::Tool); - setAttribute(Qt::WA_MacAlwaysShowToolWindow); - setAttribute(Qt::WA_TransparentForMouseEvents); - setAttribute(Qt::WA_OpaquePaintEvent); - - setWindowOpacity(0.); - show(); - } - - void detach() { - _owner = nullptr; - hideFast(); - } - - void showFast() { - _hiding = false; - startAnimation(); - } - - void hideFast() { - _hiding = true; - startAnimation(); - } - -protected: - virtual void paintEvent(QPaintEvent *e) { - Painter p(this); - p.drawPixmap(0, 0, _cache); - } - -private: - void startAnimation() { - _opacity.start([this] { animationCallback(); }, _hiding ? 1. : 0., _hiding ? 0. : 1., st::notifyFastAnim); - } - void animationCallback() { - setWindowOpacity(_opacity.current(_hiding ? 0. : 1.)); - if (!_opacity.animating() && _hiding) { - if (_owner) { - _owner->removeSample(this); - } - hide(); - destroyDelayed(); - } - } - - void destroyDelayed() { - if (_deleted) return; - _deleted = true; - - // Ubuntu has a lag if deleteLater() called immediately. -#if defined Q_OS_LINUX32 || defined Q_OS_LINUX64 - QTimer::singleShot(1000, [this] { delete this; }); -#else // Q_OS_LINUX32 || Q_OS_LINUX64 - deleteLater(); -#endif // Q_OS_LINUX32 || Q_OS_LINUX64 - } - - NotificationsBox *_owner; - QPixmap _cache; - Animation _opacity; - bool _hiding = false; - bool _deleted = false; - -}; - -NotificationsBox::NotificationsBox(QWidget *parent) -: _chosenCorner(Global::NotificationsCorner()) -, _oldCount(snap(Global::NotificationsCount(), 1, kMaxNotificationsCount)) -, _countSlider(this) { -} - -void NotificationsBox::prepare() { - addButton(langFactory(lng_close), [this] { closeBox(); }); - - _sampleOpacities.reserve(kMaxNotificationsCount); - for (int i = 0; i != kMaxNotificationsCount; ++i) { - _countSlider->addSection(QString::number(i + 1)); - _sampleOpacities.push_back(Animation()); - } - _countSlider->setActiveSectionFast(_oldCount - 1); - _countSlider->sectionActivated( - ) | rpl::start_with_next( - [this] { countChanged(); }, - lifetime()); - - setMouseTracking(true); - - prepareNotificationSampleSmall(); - prepareNotificationSampleLarge(); - - setDimensions(st::boxWideWidth, st::notificationsBoxHeight); -} - -void NotificationsBox::paintEvent(QPaintEvent *e) { - BoxContent::paintEvent(e); - - Painter p(this); - - auto contentLeft = getContentLeft(); - - p.setFont(st::boxTitleFont); - p.setPen(st::boxTitleFg); - p.drawTextLeft(contentLeft, st::boxTitlePosition.y(), width(), lang(lng_settings_notifications_position)); - - auto screenRect = getScreenRect(); - p.fillRect(screenRect.x(), screenRect.y(), st::notificationsBoxScreenSize.width(), st::notificationsBoxScreenSize.height(), st::notificationsBoxScreenBg); - - auto monitorTop = st::notificationsBoxMonitorTop; - st::notificationsBoxMonitor.paint(p, contentLeft, monitorTop, width()); - - for (int corner = 0; corner != 4; ++corner) { - auto screenCorner = static_cast(corner); - auto isLeft = Notify::IsLeftCorner(screenCorner); - auto isTop = Notify::IsTopCorner(screenCorner); - auto sampleLeft = isLeft ? (screenRect.x() + st::notificationsSampleSkip) : (screenRect.x() + screenRect.width() - st::notificationsSampleSkip - st::notificationSampleSize.width()); - auto sampleTop = isTop ? (screenRect.y() + st::notificationsSampleTopSkip) : (screenRect.y() + screenRect.height() - st::notificationsSampleBottomSkip - st::notificationSampleSize.height()); - if (corner == static_cast(_chosenCorner)) { - auto count = currentCount(); - for (int i = 0; i != kMaxNotificationsCount; ++i) { - auto opacity = _sampleOpacities[i].current(getms(), (i < count) ? 1. : 0.); - p.setOpacity(opacity); - p.drawPixmapLeft(sampleLeft, sampleTop, width(), _notificationSampleSmall); - sampleTop += (isTop ? 1 : -1) * (st::notificationSampleSize.height() + st::notificationsSampleMargin); - } - p.setOpacity(1.); - } else { - p.setOpacity(st::notificationSampleOpacity); - p.drawPixmapLeft(sampleLeft, sampleTop, width(), _notificationSampleSmall); - p.setOpacity(1.); - } - } - - auto labelTop = screenRect.y() + screenRect.height() + st::notificationsBoxCountLabelTop; - p.setFont(st::boxTitleFont); - p.setPen(st::boxTitleFg); - p.drawTextLeft(contentLeft, labelTop, width(), lang(lng_settings_notifications_count)); -} - -void NotificationsBox::countChanged() { - auto count = currentCount(); - auto moreSamples = (count > _oldCount); - auto from = moreSamples ? 0. : 1.; - auto to = moreSamples ? 1. : 0.; - auto indexDelta = moreSamples ? 1 : -1; - auto animatedDelta = moreSamples ? 0 : -1; - for (; _oldCount != count; _oldCount += indexDelta) { - _sampleOpacities[_oldCount + animatedDelta].start([this] { update(); }, from, to, st::notifyFastAnim); - } - - if (currentCount() != Global::NotificationsCount()) { - Global::SetNotificationsCount(currentCount()); - Auth().notifications().settingsChanged().notify(ChangeType::MaxCount); - Local::writeUserSettings(); - } -} - -int NotificationsBox::getContentLeft() const { - return (width() - st::notificationsBoxMonitor.width()) / 2; -} - -QRect NotificationsBox::getScreenRect() const { - auto screenLeft = (width() - st::notificationsBoxScreenSize.width()) / 2; - auto screenTop = st::notificationsBoxMonitorTop + st::notificationsBoxScreenTop; - return QRect(screenLeft, screenTop, st::notificationsBoxScreenSize.width(), st::notificationsBoxScreenSize.height()); -} - -void NotificationsBox::resizeEvent(QResizeEvent *e) { - BoxContent::resizeEvent(e); - - auto screenRect = getScreenRect(); - auto sliderTop = screenRect.y() + screenRect.height() + st::notificationsBoxCountLabelTop + st::notificationsBoxCountTop; - auto contentLeft = getContentLeft(); - _countSlider->resizeToWidth(width() - 2 * contentLeft); - _countSlider->move(contentLeft, sliderTop); -} - -void NotificationsBox::prepareNotificationSampleSmall() { - auto width = st::notificationSampleSize.width(); - auto height = st::notificationSampleSize.height(); - auto sampleImage = QImage(width * cIntRetinaFactor(), height * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied); - sampleImage.setDevicePixelRatio(cRetinaFactor()); - sampleImage.fill(st::notificationBg->c); - { - Painter p(&sampleImage); - PainterHighQualityEnabler hq(p); - - p.setPen(Qt::NoPen); - - auto padding = height / 8; - auto userpicSize = height - 2 * padding; - p.setBrush(st::notificationSampleUserpicFg); - p.drawEllipse(rtlrect(padding, padding, userpicSize, userpicSize, width)); - - auto rowLeft = height; - auto rowHeight = padding; - auto nameTop = (height - 5 * padding) / 2; - auto nameWidth = height; - p.setBrush(st::notificationSampleNameFg); - p.drawRoundedRect(rtlrect(rowLeft, nameTop, nameWidth, rowHeight, width), rowHeight / 2, rowHeight / 2); - - auto rowWidth = (width - rowLeft - 3 * padding); - auto rowTop = nameTop + rowHeight + padding; - p.setBrush(st::notificationSampleTextFg); - p.drawRoundedRect(rtlrect(rowLeft, rowTop, rowWidth, rowHeight, width), rowHeight / 2, rowHeight / 2); - rowTop += rowHeight + padding; - p.drawRoundedRect(rtlrect(rowLeft, rowTop, rowWidth, rowHeight, width), rowHeight / 2, rowHeight / 2); - - auto closeLeft = width - 2 * padding; - p.fillRect(rtlrect(closeLeft, padding, padding, padding, width), st::notificationSampleCloseFg); - } - _notificationSampleSmall = App::pixmapFromImageInPlace(std::move(sampleImage)); - _notificationSampleSmall.setDevicePixelRatio(cRetinaFactor()); -} - -void NotificationsBox::prepareNotificationSampleUserpic() { - if (_notificationSampleUserpic.isNull()) { - _notificationSampleUserpic = App::pixmapFromImageInPlace(Messenger::Instance().logoNoMargin().scaled(st::notifyPhotoSize * cIntRetinaFactor(), st::notifyPhotoSize * cIntRetinaFactor(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); - _notificationSampleUserpic.setDevicePixelRatio(cRetinaFactor()); - } -} - -void NotificationsBox::prepareNotificationSampleLarge() { - int w = st::notifyWidth, h = st::notifyMinHeight; - auto sampleImage = QImage(w * cIntRetinaFactor(), h * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied); - sampleImage.setDevicePixelRatio(cRetinaFactor()); - sampleImage.fill(st::notificationBg->c); - { - Painter p(&sampleImage); - p.fillRect(0, 0, w - st::notifyBorderWidth, st::notifyBorderWidth, st::notifyBorder->b); - p.fillRect(w - st::notifyBorderWidth, 0, st::notifyBorderWidth, h - st::notifyBorderWidth, st::notifyBorder->b); - p.fillRect(st::notifyBorderWidth, h - st::notifyBorderWidth, w - st::notifyBorderWidth, st::notifyBorderWidth, st::notifyBorder->b); - p.fillRect(0, st::notifyBorderWidth, st::notifyBorderWidth, h - st::notifyBorderWidth, st::notifyBorder->b); - - prepareNotificationSampleUserpic(); - p.drawPixmap(st::notifyPhotoPos.x(), st::notifyPhotoPos.y(), _notificationSampleUserpic); - - int itemWidth = w - st::notifyPhotoPos.x() - st::notifyPhotoSize - st::notifyTextLeft - st::notifyClosePos.x() - st::notifyClose.width; - - auto rectForName = rtlrect(st::notifyPhotoPos.x() + st::notifyPhotoSize + st::notifyTextLeft, st::notifyTextTop, itemWidth, st::msgNameFont->height, w); - - auto notifyText = st::dialogsTextFont->elided(lang(lng_notification_sample), 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); - p.setFont(st::msgNameFont); - - auto notifyTitle = st::msgNameFont->elided(qsl("Telegram Desktop"), rectForName.width()); - p.drawText(rectForName.left(), rectForName.top() + st::msgNameFont->ascent, notifyTitle); - - st::notifyClose.icon.paint(p, w - st::notifyClosePos.x() - st::notifyClose.width + st::notifyClose.iconPosition.x(), st::notifyClosePos.y() + st::notifyClose.iconPosition.y(), w); - } - - _notificationSampleLarge = App::pixmapFromImageInPlace(std::move(sampleImage)); -} - -void NotificationsBox::removeSample(SampleWidget *widget) { - for (auto &samples : _cornerSamples) { - for (int i = 0, size = samples.size(); i != size; ++i) { - if (samples[i] == widget) { - for (int j = i + 1; j != size; ++j) { - samples[j]->detach(); - } - samples.resize(i); - break; - } - } - } -} - -void NotificationsBox::mouseMoveEvent(QMouseEvent *e) { - auto screenRect = getScreenRect(); - auto cornerWidth = screenRect.width() / 3; - auto cornerHeight = screenRect.height() / 3; - auto topLeft = rtlrect(screenRect.x(), screenRect.y(), cornerWidth, cornerHeight, width()); - auto topRight = rtlrect(screenRect.x() + screenRect.width() - cornerWidth, screenRect.y(), cornerWidth, cornerHeight, width()); - auto bottomRight = rtlrect(screenRect.x() + screenRect.width() - cornerWidth, screenRect.y() + screenRect.height() - cornerHeight, cornerWidth, cornerHeight, width()); - auto bottomLeft = rtlrect(screenRect.x(), screenRect.y() + screenRect.height() - cornerHeight, cornerWidth, cornerHeight, width()); - if (topLeft.contains(e->pos())) { - setOverCorner(Notify::ScreenCorner::TopLeft); - } else if (topRight.contains(e->pos())) { - setOverCorner(Notify::ScreenCorner::TopRight); - } else if (bottomRight.contains(e->pos())) { - setOverCorner(Notify::ScreenCorner::BottomRight); - } else if (bottomLeft.contains(e->pos())) { - setOverCorner(Notify::ScreenCorner::BottomLeft); - } else { - clearOverCorner(); - } -} - -void NotificationsBox::leaveEventHook(QEvent *e) { - clearOverCorner(); -} - -void NotificationsBox::setOverCorner(Notify::ScreenCorner corner) { - if (_isOverCorner) { - if (corner == _overCorner) { - return; - } - for_const (auto widget, _cornerSamples[static_cast(_overCorner)]) { - widget->hideFast(); - } - } else { - _isOverCorner = true; - setCursor(style::cur_pointer); - Global::SetNotificationsDemoIsShown(true); - Auth().notifications().settingsChanged().notify(ChangeType::DemoIsShown); - } - _overCorner = corner; - - auto &samples = _cornerSamples[static_cast(_overCorner)]; - auto samplesAlready = samples.size(); - auto samplesNeeded = currentCount(); - auto samplesLeave = qMin(samplesAlready, samplesNeeded); - for (int i = 0; i != samplesLeave; ++i) { - samples[i]->showFast(); - } - if (samplesNeeded > samplesLeave) { - auto r = psDesktopRect(); - auto isLeft = Notify::IsLeftCorner(_overCorner); - auto isTop = Notify::IsTopCorner(_overCorner); - auto sampleLeft = (isLeft == rtl()) ? (r.x() + r.width() - st::notifyWidth - st::notifyDeltaX) : (r.x() + st::notifyDeltaX); - auto sampleTop = isTop ? (r.y() + st::notifyDeltaY) : (r.y() + r.height() - st::notifyDeltaY - st::notifyMinHeight); - for (int i = samplesLeave; i != samplesNeeded; ++i) { - auto widget = std::make_unique(this, _notificationSampleLarge); - widget->move(sampleLeft, sampleTop + (isTop ? 1 : -1) * i * (st::notifyMinHeight + st::notifyDeltaY)); - widget->showFast(); - samples.push_back(widget.release()); - } - } else { - for (int i = samplesLeave; i != samplesAlready; ++i) { - samples[i]->hideFast(); - } - } -} - -void NotificationsBox::clearOverCorner() { - if (_isOverCorner) { - _isOverCorner = false; - setCursor(style::cur_default); - Global::SetNotificationsDemoIsShown(false); - Auth().notifications().settingsChanged().notify(ChangeType::DemoIsShown); - - for_const (auto &samples, _cornerSamples) { - for_const (auto widget, samples) { - widget->hideFast(); - } - } - } -} - -int NotificationsBox::currentCount() const { - return _countSlider->activeSection() + 1; -} - -void NotificationsBox::mousePressEvent(QMouseEvent *e) { - _isDownCorner = _isOverCorner; - _downCorner = _overCorner; -} - -void NotificationsBox::mouseReleaseEvent(QMouseEvent *e) { - auto isDownCorner = base::take(_isDownCorner); - if (isDownCorner && _isOverCorner && _downCorner == _overCorner && _downCorner != _chosenCorner) { - _chosenCorner = _downCorner; - update(); - - if (_chosenCorner != Global::NotificationsCorner()) { - Global::SetNotificationsCorner(_chosenCorner); - Auth().notifications().settingsChanged().notify(ChangeType::Corner); - Local::writeUserSettings(); - } - } -} - -NotificationsBox::~NotificationsBox() { - for_const (auto &samples, _cornerSamples) { - for_const (auto widget, samples) { - widget->detach(); - } - } - clearOverCorner(); -} diff --git a/Telegram/SourceFiles/boxes/notifications_box.h b/Telegram/SourceFiles/boxes/notifications_box.h deleted file mode 100644 index 4035989ac3cc8..0000000000000 --- a/Telegram/SourceFiles/boxes/notifications_box.h +++ /dev/null @@ -1,65 +0,0 @@ -/* -This file is part of Telegram Desktop, -the official desktop application for the Telegram messaging service. - -For license and copyright information please follow this link: -https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL -*/ -#pragma once - -#include "boxes/abstract_box.h" - -namespace Ui { -class LinkButton; -class SettingsSlider; -} // namespace Ui - -class NotificationsBox : public BoxContent { -public: - NotificationsBox(QWidget*); - ~NotificationsBox(); - -protected: - void prepare() override; - - void paintEvent(QPaintEvent *e) override; - void resizeEvent(QResizeEvent *e) override; - void mousePressEvent(QMouseEvent *e) override; - void mouseMoveEvent(QMouseEvent *e) override; - void leaveEventHook(QEvent *e) override; - void mouseReleaseEvent(QMouseEvent *e) override; - -private: - using ScreenCorner = Notify::ScreenCorner; - void countChanged(); - void setOverCorner(ScreenCorner corner); - void clearOverCorner(); - - class SampleWidget; - void removeSample(SampleWidget *widget); - - int currentCount() const; - - QRect getScreenRect() const; - int getContentLeft() const; - void prepareNotificationSampleSmall(); - void prepareNotificationSampleLarge(); - void prepareNotificationSampleUserpic(); - - QPixmap _notificationSampleUserpic; - QPixmap _notificationSampleSmall; - QPixmap _notificationSampleLarge; - ScreenCorner _chosenCorner; - std::vector _sampleOpacities; - - bool _isOverCorner = false; - ScreenCorner _overCorner = ScreenCorner::TopLeft; - bool _isDownCorner = false; - ScreenCorner _downCorner = ScreenCorner::TopLeft; - - int _oldCount; - object_ptr _countSlider; - - QVector _cornerSamples[4]; - -}; diff --git a/Telegram/SourceFiles/settings/settings_notifications.cpp b/Telegram/SourceFiles/settings/settings_notifications.cpp index 9ece38f1c6a28..641e48542b859 100644 --- a/Telegram/SourceFiles/settings/settings_notifications.cpp +++ b/Telegram/SourceFiles/settings/settings_notifications.cpp @@ -12,19 +12,505 @@ For license and copyright information please follow this link: #include "ui/wrap/slide_wrap.h" #include "ui/widgets/checkbox.h" #include "ui/widgets/buttons.h" +#include "ui/widgets/discrete_sliders.h" #include "lang/lang_keys.h" #include "info/profile/info_profile_button.h" #include "storage/localstorage.h" #include "window/notifications_manager.h" -#include "boxes/notifications_box.h" #include "platform/platform_notifications_manager.h" #include "mainwindow.h" +#include "messenger.h" #include "auth_session.h" #include "styles/style_settings.h" +#include "styles/style_boxes.h" +#include "styles/style_window.h" +#include "styles/style_dialogs.h" namespace Settings { namespace { +constexpr auto kMaxNotificationsCount = 5; + +int CurrentCount() { + return snap(Global::NotificationsCount(), 1, kMaxNotificationsCount); +} + +using ChangeType = Window::Notifications::ChangeType; + +class NotificationsCount : public Ui::RpWidget { +public: + NotificationsCount(QWidget *parent); + + void setCount(int count); + + ~NotificationsCount(); + +protected: + void paintEvent(QPaintEvent *e) override; + void mousePressEvent(QMouseEvent *e) override; + void mouseMoveEvent(QMouseEvent *e) override; + void leaveEventHook(QEvent *e) override; + void mouseReleaseEvent(QMouseEvent *e) override; + + int resizeGetHeight(int newWidth) override; + +private: + using ScreenCorner = Notify::ScreenCorner; + void setOverCorner(ScreenCorner corner); + void clearOverCorner(); + + class SampleWidget; + void removeSample(SampleWidget *widget); + + QRect getScreenRect() const; + QRect getScreenRect(int width) const; + int getContentLeft() const; + void prepareNotificationSampleSmall(); + void prepareNotificationSampleLarge(); + void prepareNotificationSampleUserpic(); + + QPixmap _notificationSampleUserpic; + QPixmap _notificationSampleSmall; + QPixmap _notificationSampleLarge; + ScreenCorner _chosenCorner; + std::vector _sampleOpacities; + + bool _isOverCorner = false; + ScreenCorner _overCorner = ScreenCorner::TopLeft; + bool _isDownCorner = false; + ScreenCorner _downCorner = ScreenCorner::TopLeft; + + int _oldCount; + + QVector _cornerSamples[4]; + +}; + +class NotificationsCount::SampleWidget : public QWidget { +public: + SampleWidget(NotificationsCount *owner, const QPixmap &cache); + + void detach(); + void showFast(); + void hideFast(); + +protected: + void paintEvent(QPaintEvent *e) override; + +private: + void startAnimation(); + void animationCallback(); + + void destroyDelayed(); + + NotificationsCount *_owner; + QPixmap _cache; + Animation _opacity; + bool _hiding = false; + bool _deleted = false; + +}; + +NotificationsCount::NotificationsCount(QWidget *parent) +: _chosenCorner(Global::NotificationsCorner()) +, _oldCount(CurrentCount()) { + setMouseTracking(true); + + _sampleOpacities.resize(kMaxNotificationsCount); + + prepareNotificationSampleSmall(); + prepareNotificationSampleLarge(); +} + +void NotificationsCount::paintEvent(QPaintEvent *e) { + Painter p(this); + + auto contentLeft = getContentLeft(); + + auto screenRect = getScreenRect(); + p.fillRect( + screenRect.x(), + screenRect.y(), + st::notificationsBoxScreenSize.width(), + st::notificationsBoxScreenSize.height(), + st::notificationsBoxScreenBg); + + auto monitorTop = 0; + st::notificationsBoxMonitor.paint(p, contentLeft, monitorTop, width()); + + for (int corner = 0; corner != 4; ++corner) { + auto screenCorner = static_cast(corner); + auto isLeft = Notify::IsLeftCorner(screenCorner); + auto isTop = Notify::IsTopCorner(screenCorner); + auto sampleLeft = isLeft ? (screenRect.x() + st::notificationsSampleSkip) : (screenRect.x() + screenRect.width() - st::notificationsSampleSkip - st::notificationSampleSize.width()); + auto sampleTop = isTop ? (screenRect.y() + st::notificationsSampleTopSkip) : (screenRect.y() + screenRect.height() - st::notificationsSampleBottomSkip - st::notificationSampleSize.height()); + if (corner == static_cast(_chosenCorner)) { + auto count = _oldCount; + for (int i = 0; i != kMaxNotificationsCount; ++i) { + auto opacity = _sampleOpacities[i].current(getms(), (i < count) ? 1. : 0.); + p.setOpacity(opacity); + p.drawPixmapLeft(sampleLeft, sampleTop, width(), _notificationSampleSmall); + sampleTop += (isTop ? 1 : -1) * (st::notificationSampleSize.height() + st::notificationsSampleMargin); + } + p.setOpacity(1.); + } else { + p.setOpacity(st::notificationSampleOpacity); + p.drawPixmapLeft(sampleLeft, sampleTop, width(), _notificationSampleSmall); + p.setOpacity(1.); + } + } +} + +void NotificationsCount::setCount(int count) { + auto moreSamples = (count > _oldCount); + auto from = moreSamples ? 0. : 1.; + auto to = moreSamples ? 1. : 0.; + auto indexDelta = moreSamples ? 1 : -1; + auto animatedDelta = moreSamples ? 0 : -1; + for (; _oldCount != count; _oldCount += indexDelta) { + _sampleOpacities[_oldCount + animatedDelta].start([this] { update(); }, from, to, st::notifyFastAnim); + } + + if (count != Global::NotificationsCount()) { + Global::SetNotificationsCount(count); + Auth().notifications().settingsChanged().notify(ChangeType::MaxCount); + Local::writeUserSettings(); + } +} + +int NotificationsCount::getContentLeft() const { + return (width() - st::notificationsBoxMonitor.width()) / 2; +} + +QRect NotificationsCount::getScreenRect() const { + return getScreenRect(width()); +} + +QRect NotificationsCount::getScreenRect(int width) const { + auto screenLeft = (width - st::notificationsBoxScreenSize.width()) / 2; + auto screenTop = st::notificationsBoxScreenTop; + return QRect(screenLeft, screenTop, st::notificationsBoxScreenSize.width(), st::notificationsBoxScreenSize.height()); +} + +int NotificationsCount::resizeGetHeight(int newWidth) { + update(); + return st::notificationsBoxMonitor.height(); +} + +void NotificationsCount::prepareNotificationSampleSmall() { + auto width = st::notificationSampleSize.width(); + auto height = st::notificationSampleSize.height(); + auto sampleImage = QImage(width * cIntRetinaFactor(), height * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied); + sampleImage.setDevicePixelRatio(cRetinaFactor()); + sampleImage.fill(st::notificationBg->c); + { + Painter p(&sampleImage); + PainterHighQualityEnabler hq(p); + + p.setPen(Qt::NoPen); + + auto padding = height / 8; + auto userpicSize = height - 2 * padding; + p.setBrush(st::notificationSampleUserpicFg); + p.drawEllipse(rtlrect(padding, padding, userpicSize, userpicSize, width)); + + auto rowLeft = height; + auto rowHeight = padding; + auto nameTop = (height - 5 * padding) / 2; + auto nameWidth = height; + p.setBrush(st::notificationSampleNameFg); + p.drawRoundedRect(rtlrect(rowLeft, nameTop, nameWidth, rowHeight, width), rowHeight / 2, rowHeight / 2); + + auto rowWidth = (width - rowLeft - 3 * padding); + auto rowTop = nameTop + rowHeight + padding; + p.setBrush(st::notificationSampleTextFg); + p.drawRoundedRect(rtlrect(rowLeft, rowTop, rowWidth, rowHeight, width), rowHeight / 2, rowHeight / 2); + rowTop += rowHeight + padding; + p.drawRoundedRect(rtlrect(rowLeft, rowTop, rowWidth, rowHeight, width), rowHeight / 2, rowHeight / 2); + + auto closeLeft = width - 2 * padding; + p.fillRect(rtlrect(closeLeft, padding, padding, padding, width), st::notificationSampleCloseFg); + } + _notificationSampleSmall = App::pixmapFromImageInPlace(std::move(sampleImage)); + _notificationSampleSmall.setDevicePixelRatio(cRetinaFactor()); +} + +void NotificationsCount::prepareNotificationSampleUserpic() { + if (_notificationSampleUserpic.isNull()) { + _notificationSampleUserpic = App::pixmapFromImageInPlace( + Messenger::Instance().logoNoMargin().scaled( + st::notifyPhotoSize * cIntRetinaFactor(), + st::notifyPhotoSize * cIntRetinaFactor(), + Qt::IgnoreAspectRatio, + Qt::SmoothTransformation)); + _notificationSampleUserpic.setDevicePixelRatio(cRetinaFactor()); + } +} + +void NotificationsCount::prepareNotificationSampleLarge() { + int w = st::notifyWidth, h = st::notifyMinHeight; + auto sampleImage = QImage( + w * cIntRetinaFactor(), + h * cIntRetinaFactor(), + QImage::Format_ARGB32_Premultiplied); + sampleImage.setDevicePixelRatio(cRetinaFactor()); + sampleImage.fill(st::notificationBg->c); + { + Painter p(&sampleImage); + p.fillRect(0, 0, w - st::notifyBorderWidth, st::notifyBorderWidth, st::notifyBorder->b); + p.fillRect(w - st::notifyBorderWidth, 0, st::notifyBorderWidth, h - st::notifyBorderWidth, st::notifyBorder->b); + p.fillRect(st::notifyBorderWidth, h - st::notifyBorderWidth, w - st::notifyBorderWidth, st::notifyBorderWidth, st::notifyBorder->b); + p.fillRect(0, st::notifyBorderWidth, st::notifyBorderWidth, h - st::notifyBorderWidth, st::notifyBorder->b); + + prepareNotificationSampleUserpic(); + p.drawPixmap(st::notifyPhotoPos.x(), st::notifyPhotoPos.y(), _notificationSampleUserpic); + + int itemWidth = w - st::notifyPhotoPos.x() - st::notifyPhotoSize - st::notifyTextLeft - st::notifyClosePos.x() - st::notifyClose.width; + + auto rectForName = rtlrect(st::notifyPhotoPos.x() + st::notifyPhotoSize + st::notifyTextLeft, st::notifyTextTop, itemWidth, st::msgNameFont->height, w); + + auto notifyText = st::dialogsTextFont->elided(lang(lng_notification_sample), 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); + p.setFont(st::msgNameFont); + + auto notifyTitle = st::msgNameFont->elided(qsl("Telegram Desktop"), rectForName.width()); + p.drawText(rectForName.left(), rectForName.top() + st::msgNameFont->ascent, notifyTitle); + + st::notifyClose.icon.paint(p, w - st::notifyClosePos.x() - st::notifyClose.width + st::notifyClose.iconPosition.x(), st::notifyClosePos.y() + st::notifyClose.iconPosition.y(), w); + } + + _notificationSampleLarge = App::pixmapFromImageInPlace(std::move(sampleImage)); +} + +void NotificationsCount::removeSample(SampleWidget *widget) { + for (auto &samples : _cornerSamples) { + for (int i = 0, size = samples.size(); i != size; ++i) { + if (samples[i] == widget) { + for (int j = i + 1; j != size; ++j) { + samples[j]->detach(); + } + samples.resize(i); + break; + } + } + } +} + +void NotificationsCount::mouseMoveEvent(QMouseEvent *e) { + auto screenRect = getScreenRect(); + auto cornerWidth = screenRect.width() / 3; + auto cornerHeight = screenRect.height() / 3; + auto topLeft = rtlrect(screenRect.x(), screenRect.y(), cornerWidth, cornerHeight, width()); + auto topRight = rtlrect(screenRect.x() + screenRect.width() - cornerWidth, screenRect.y(), cornerWidth, cornerHeight, width()); + auto bottomRight = rtlrect(screenRect.x() + screenRect.width() - cornerWidth, screenRect.y() + screenRect.height() - cornerHeight, cornerWidth, cornerHeight, width()); + auto bottomLeft = rtlrect(screenRect.x(), screenRect.y() + screenRect.height() - cornerHeight, cornerWidth, cornerHeight, width()); + if (topLeft.contains(e->pos())) { + setOverCorner(Notify::ScreenCorner::TopLeft); + } else if (topRight.contains(e->pos())) { + setOverCorner(Notify::ScreenCorner::TopRight); + } else if (bottomRight.contains(e->pos())) { + setOverCorner(Notify::ScreenCorner::BottomRight); + } else if (bottomLeft.contains(e->pos())) { + setOverCorner(Notify::ScreenCorner::BottomLeft); + } else { + clearOverCorner(); + } +} + +void NotificationsCount::leaveEventHook(QEvent *e) { + clearOverCorner(); +} + +void NotificationsCount::setOverCorner(Notify::ScreenCorner corner) { + if (_isOverCorner) { + if (corner == _overCorner) { + return; + } + for_const (auto widget, _cornerSamples[static_cast(_overCorner)]) { + widget->hideFast(); + } + } else { + _isOverCorner = true; + setCursor(style::cur_pointer); + Global::SetNotificationsDemoIsShown(true); + Auth().notifications().settingsChanged().notify(ChangeType::DemoIsShown); + } + _overCorner = corner; + + auto &samples = _cornerSamples[static_cast(_overCorner)]; + auto samplesAlready = samples.size(); + auto samplesNeeded = _oldCount; + auto samplesLeave = qMin(samplesAlready, samplesNeeded); + for (int i = 0; i != samplesLeave; ++i) { + samples[i]->showFast(); + } + if (samplesNeeded > samplesLeave) { + auto r = psDesktopRect(); + auto isLeft = Notify::IsLeftCorner(_overCorner); + auto isTop = Notify::IsTopCorner(_overCorner); + auto sampleLeft = (isLeft == rtl()) ? (r.x() + r.width() - st::notifyWidth - st::notifyDeltaX) : (r.x() + st::notifyDeltaX); + auto sampleTop = isTop ? (r.y() + st::notifyDeltaY) : (r.y() + r.height() - st::notifyDeltaY - st::notifyMinHeight); + for (int i = samplesLeave; i != samplesNeeded; ++i) { + auto widget = std::make_unique(this, _notificationSampleLarge); + widget->move(sampleLeft, sampleTop + (isTop ? 1 : -1) * i * (st::notifyMinHeight + st::notifyDeltaY)); + widget->showFast(); + samples.push_back(widget.release()); + } + } else { + for (int i = samplesLeave; i != samplesAlready; ++i) { + samples[i]->hideFast(); + } + } +} + +void NotificationsCount::clearOverCorner() { + if (_isOverCorner) { + _isOverCorner = false; + setCursor(style::cur_default); + Global::SetNotificationsDemoIsShown(false); + Auth().notifications().settingsChanged().notify(ChangeType::DemoIsShown); + + for_const (auto &samples, _cornerSamples) { + for_const (auto widget, samples) { + widget->hideFast(); + } + } + } +} + +void NotificationsCount::mousePressEvent(QMouseEvent *e) { + _isDownCorner = _isOverCorner; + _downCorner = _overCorner; +} + +void NotificationsCount::mouseReleaseEvent(QMouseEvent *e) { + auto isDownCorner = base::take(_isDownCorner); + if (isDownCorner && _isOverCorner && _downCorner == _overCorner && _downCorner != _chosenCorner) { + _chosenCorner = _downCorner; + update(); + + if (_chosenCorner != Global::NotificationsCorner()) { + Global::SetNotificationsCorner(_chosenCorner); + Auth().notifications().settingsChanged().notify(ChangeType::Corner); + Local::writeUserSettings(); + } + } +} + +NotificationsCount::~NotificationsCount() { + for_const (auto &samples, _cornerSamples) { + for_const (auto widget, samples) { + widget->detach(); + } + } + clearOverCorner(); +} + +NotificationsCount::SampleWidget::SampleWidget( + NotificationsCount *owner, + const QPixmap &cache) +: QWidget(nullptr) +, _owner(owner) +, _cache(cache) { + resize( + cache.width() / cache.devicePixelRatio(), + cache.height() / cache.devicePixelRatio()); + + setWindowFlags(Qt::WindowFlags(Qt::FramelessWindowHint) + | Qt::WindowStaysOnTopHint + | Qt::BypassWindowManagerHint + | Qt::NoDropShadowWindowHint + | Qt::Tool); + setAttribute(Qt::WA_MacAlwaysShowToolWindow); + setAttribute(Qt::WA_TransparentForMouseEvents); + setAttribute(Qt::WA_OpaquePaintEvent); + + setWindowOpacity(0.); + show(); +} + +void NotificationsCount::SampleWidget::detach() { + _owner = nullptr; + hideFast(); +} + +void NotificationsCount::SampleWidget::showFast() { + _hiding = false; + startAnimation(); +} + +void NotificationsCount::SampleWidget::hideFast() { + _hiding = true; + startAnimation(); +} + +void NotificationsCount::SampleWidget::paintEvent(QPaintEvent *e) { + Painter p(this); + p.drawPixmap(0, 0, _cache); +} + +void NotificationsCount::SampleWidget::startAnimation() { + _opacity.start( + [=] { animationCallback(); }, + _hiding ? 1. : 0., + _hiding ? 0. : 1., + st::notifyFastAnim); +} + +void NotificationsCount::SampleWidget::animationCallback() { + setWindowOpacity(_opacity.current(_hiding ? 0. : 1.)); + if (!_opacity.animating() && _hiding) { + if (_owner) { + _owner->removeSample(this); + } + hide(); + destroyDelayed(); + } +} + +void NotificationsCount::SampleWidget::destroyDelayed() { + if (_deleted) return; + _deleted = true; + + // Ubuntu has a lag if deleteLater() called immediately. +#if defined Q_OS_LINUX32 || defined Q_OS_LINUX64 + QTimer::singleShot(1000, [this] { delete this; }); +#else // Q_OS_LINUX32 || Q_OS_LINUX64 + deleteLater(); +#endif // Q_OS_LINUX32 || Q_OS_LINUX64 +} + +void SetupAdvancedNotifications(not_null container) { + AddSkip(container, st::settingsCheckboxesSkip); + AddDivider(container); + AddSkip(container, st::settingsCheckboxesSkip); + AddSubsectionTitle(container, lng_settings_notifications_position); + AddSkip(container, st::settingsCheckboxesSkip); + + const auto position = container->add( + object_ptr(container)); + + AddSkip(container, st::settingsCheckboxesSkip); + AddSubsectionTitle(container, lng_settings_notifications_count); + + const auto count = container->add( + object_ptr(container, st::settingsSlider), + st::settingsBigScalePadding); + for (int i = 0; i != kMaxNotificationsCount; ++i) { + count->addSection(QString::number(i + 1)); + } + count->setActiveSectionFast(CurrentCount() - 1); + count->sectionActivated( + ) | rpl::start_with_next([=](int section) { + position->setCount(section + 1); + }, count->lifetime()); + AddSkip(container, st::settingsCheckboxesSkip); +} + void SetupNotificationsContent(not_null container) { const auto checkbox = [&](LangKey label, bool checked) { return object_ptr( @@ -86,16 +572,8 @@ void SetupNotificationsContent(not_null container) { ? advancedSlide->entity() : nullptr; if (advancedWrap) { - AddSkip(advancedWrap, st::settingsCheckboxesSkip); - AddDivider(advancedWrap); - AddSkip(advancedWrap, st::settingsCheckboxesSkip); - } - const auto advanced = advancedWrap - ? AddButton( - advancedWrap, - lng_settings_advanced_notifications, - st::settingsButton).get() - : nullptr; + SetupAdvancedNotifications(advancedWrap); + } if (!name->entity()->checked()) { preview->hide(anim::type::instant); @@ -206,11 +684,6 @@ void SetupNotificationsContent(not_null container) { } }, native->lifetime()); } - if (advanced) { - advanced->addClickHandler([=] { - Ui::show(Box()); - }); - } } void SetupNotifications(not_null container) { diff --git a/Telegram/gyp/telegram_sources.txt b/Telegram/gyp/telegram_sources.txt index 208d5092e94e3..f02296c8a9370 100644 --- a/Telegram/gyp/telegram_sources.txt +++ b/Telegram/gyp/telegram_sources.txt @@ -38,8 +38,6 @@ <(src_loc)/boxes/local_storage_box.h <(src_loc)/boxes/mute_settings_box.cpp <(src_loc)/boxes/mute_settings_box.h -<(src_loc)/boxes/notifications_box.cpp -<(src_loc)/boxes/notifications_box.h <(src_loc)/boxes/peer_list_box.cpp <(src_loc)/boxes/peer_list_box.h <(src_loc)/boxes/peer_list_controllers.cpp From d485a05935d7144e4c421c4b92af454d3a70682c Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 28 Sep 2018 14:20:36 +0300 Subject: [PATCH 4/7] Reorder chat settings sections. --- .../Resources/icons/settings_stickers.png | Bin 0 -> 1188 bytes .../Resources/icons/settings_stickers@2x.png | Bin 0 -> 2674 bytes Telegram/Resources/icons/settings_themes.png | Bin 0 -> 1041 bytes .../Resources/icons/settings_themes@2x.png | Bin 0 -> 1966 bytes Telegram/SourceFiles/base/bytes.h | 8 ++++++- Telegram/SourceFiles/settings/settings.style | 12 ++++++++-- .../SourceFiles/settings/settings_chat.cpp | 22 +++++++++++------- .../SourceFiles/settings/settings_common.cpp | 15 +++++++----- .../SourceFiles/settings/settings_common.h | 9 ++++--- .../cache/storage_cache_database_object.cpp | 4 ++-- .../SourceFiles/storage/file_download.cpp | 16 ++++--------- 11 files changed, 52 insertions(+), 34 deletions(-) create mode 100644 Telegram/Resources/icons/settings_stickers.png create mode 100644 Telegram/Resources/icons/settings_stickers@2x.png create mode 100644 Telegram/Resources/icons/settings_themes.png create mode 100644 Telegram/Resources/icons/settings_themes@2x.png diff --git a/Telegram/Resources/icons/settings_stickers.png b/Telegram/Resources/icons/settings_stickers.png new file mode 100644 index 0000000000000000000000000000000000000000..d041037b115ab4cf2ca0f0547e1f5c1556f1fc74 GIT binary patch literal 1188 zcmV;V1Y7%wP);LoB;1r@tW zAw{@d2wfgwt&-|_Kr0G5}R^8+cpQpRK8>iEmHzFR7 z2Y|!FLrO|Yas!Kti_vx60NLK&W@>7R_V#w{c6-5jwpy+1?Cb#G^Z9ZEqtPe;=jZ2) zjg8^)c(7Wn1w$U{^z<|Uv$M0gfp;Mc27?7}T2WDfuIqgM{Fx_Do)~OxZEY$QMMXu~ zz)U6sKut|e!N9)0J{A7e)m2O;ld{=tHum@T0cdS)HTY>FBFSV@L_}IzTBJ}(r_<_p zU0t1+&1Us{ad9E5tE(a+($&?K#b}y8<9u^fUjS_GC4WP zuV24ZB&w>aI6Xb(_wU~{G&C4no5f;bYikPtzu%v?Bq}Q_dG+d*YUaAG<8U}|I-LN# zc=1C0cV%S-fN(f$1d0f;SPX!7@7@^zE|-hW&Q1mf2Keyd1Lx=GhKbSC)I@oCIWsde z0MymhDc?{i1i;3|MmDguwH1K<{e4vicDr5mMu5x9OTK*h!qCtV&!0b6wyUcv0N%WL zV>oP0O^rHO7O<$Oh`qf%0NUEx5D`o!6ZQ4=_*Mw7*Z1?J zG#Cs5aBy&t4HOY(XJ-MJo}Mna%{^4B)r!aCVRUp9+e0V5Af?~EFf<(QZSO5o`Th1JC+WTCJbym- zo^$RwonK>uNpE_DEb7TJ;qAd^vIVj^wYw28D@EveONiin6Hhr>Y@i-j5*8mOtM ziH3)V7wiK|QPgTRPMkOalgR{!!vSA%`}S>Y-n@CCzTOUyQmKSSqru6OCt)_5F*-Wx z6KcNn_4Oe&HT8cBaQX7(&}y|X7z}7@Yx4_;PwwBp4~0Upw17&b5?NVUID7Uiy1KeB zH8mv|_^Vg1V6)lq^UpscFE0-%DJj^wb0<1GJ2`E?{`%{;4;UXGkHW%2R8>`>udh$k z+nAY|K}SaiDl03Io12S}kPwdDsHiABc<_MHGn>tjNF;#=jE;_mUa!Z63m5R{(IZh% zZnqm&s}%-=0T~$?h>VOB^plsDhlz;^j}52Oi47YzEIy!2CPQLkBJ_Gaj7B4zPNyiS z7cXAm)~#D8FE2-WdOCuGgZ+AtVPRpgTCI%Dva+(p158RvLTPC!E?&Hdk&zKmP!kgq zXl!i6(W6J9(P$u*O5bP*R8>_m_Dv=eZ-GKvrlzK%zrWurklXEs&1OSQO$`bP3J@0;7ci*#rM9+~iKV%@**`#qLV@=7 zb`F%wrd5Bd4|h=_<- z5~#Ul&6+jn?d@gaD=sb;4`?!(7-g%~idCyt1uWoCKKTUo_4R0IXuzI5d+^RX@A%zK z>+9>q13rKLoKgPt(@z5i_t8fmF&}RLsHmtA)Z4#*KiqD&N2jN!2OoU!fjGc_{`rS- zsL^Nw0wU2CU|_)0-tBgyu&~glj%P}OiT==rKS1Q0TDr^QZdUim&=8moScA+Lzzs5Uw{3TGY0qX-!Dq{;>C-MUUhY~ z@FWu)9E{7CFEff~&YTf+xMj;0T)A=uHk%E#wY5l0OcVtf6cmKAvNHVj*I&4E=MIh> zIl^fZ9v+U38#i)3AxDoMW#a7a?#6rXz2_T{h;aP)aYnJTvlA;gsW9rmuHHLGShS$J~i;H=u`>R*4A~ZDgjk@va)2BW5&Ye5Q>87o%t&C5D!NC9UXpUH|R_gBV z_FT(kGRn!xA#V~E7RGx&EiH{UZQA5jPe^v{+C`BRpRaI5RJ4R(P z87Gx->eMM=K)GBFv)Rlje)rvXUW1B{kLR@i{rBIoeED*};4(8aIlBemb@q*Kh9x3Y zR8%l+&1SPOAQ8b}FffX(t*u_WDbed(=vQBTh1%L$eEaRUzNT#6a_G<@X7N2UGXs;! zgt4(P0KnkjAaBMXBO?RT)6*Wk@$qpaB_#<1=H%pHa&pq6I5afGr})MtAt8a2P@0^a zL`g{rhzLLa_@n3kH{X22(OsCf*+qP|<`uX3&xxH=fq&PA%0+mW7449pr%>*zuHir24c+o%-i3IPy z`!14`lX3d=Y23Vd)9X3Kl`B_xvj^wTpZBymbm$PTpU}`yPR8xv!Gpqp3Wb7m&Y;uj zyaL6>#$wN&Jve^+IL@Cxj~h2`z;3rQW7(VZ_4VQ4!Gl=0ZXKedqmh`H$c)X2i3vnU zM|<`C(@#G!_8J=-g#jfJ3C^86$0&MB)hU%qSS%JnkXdPIX~EvTdr?zU!vVc}_bz8w zGdt;cD|vZ&jGf-zUSU8YLQzo>vsxG!7(i@nET^4ZF6T`aPfbl>aBvWhA3w&WOP5eu zS_+j)<(ULRLPGHU_uq5!GqW-{IEcfC4+{U^Hjx3#s=lP6CoE-sFU zh$15+DKj&Ze*5h=rrqf1DCOqnl3uT;_uqe?#>U3z*|TT#_uqe0Pfrg$di01~E*HoC z-Sy`k~sVF==oa}ZxSu7T+udk=Bt}b685)n5O;BYvYYo8NELqh}e zbi7U1i&2&>TZV{;2vI4-*|KWYD$bJ4Xf%rJqD0&+QEzWA)~s0*Fi5dQsZ=6AKOgt* z-Q#rad6S`UL#tP>=9~o<6cj88lw2({Tx@bEBWaQE)riv|=F6oiC?1n6`+7>!2Q?RHU6BO@a)o6RUG zDS=X{^k!c;fRK<7w6wG^#;dBT-Uv!6l|rM@;K-39Xl!ic936NQhr@y9=4O8X6j)*Xw<*Ll+HDDwT3l6AvCd zKvYx|ZpF07*qoM6N<$f&wWO6#xJL literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/settings_themes.png b/Telegram/Resources/icons/settings_themes.png new file mode 100644 index 0000000000000000000000000000000000000000..fd36932b562268931bbf42bbc97ba7885720f2d9 GIT binary patch literal 1041 zcmV+s1n&EZP)%Q*mcip!L0PzPU=ug7_ z6QJZPPLYw3(ChUmEiFY_S{hU;6~tmO?(Xhzb#;ZcwKbT{X4viaFG2Z{HZ(Nw?Cgx6 z$;-3TumX`M6dLjfU8o68!lgWgNiV6V0{rx?xRx36)H*tP`j@Q>$BqSstGcyxK zMMX$WO$7ivJUpPIqXR~x@#{N`ii+aK#)c66*w`4AO67-^73*5pjqU{h0*FrlWV zh5(qDn8^G4dy=HX;b2r$6ajE%W=8O>tgIveN+c34EiI8GT`m_D3PoU`OeW*i)fGu{ zVq!wD>vTGw0?}wR1i=0MeZkhz(INP&)oNZ}Uy~$zdwT-|tE;O?k`E6LOh`!ZNpoLc zA8j@pTU%QNdr3(Nx3;!8Jw45sm>8dh`}_Mzl3QC_fq|2glO)Nxxj6!0aBwg~LP9<) zmcOb7>D6piCy?)6)~(Zg*gy%jF_T=I7^gU|>KvpXKG{Pk~)sU4sAK-X3FOV(9gH{eV8b zR4f()0D^*oFgrU7m&*mW+l}$@aeO9=i;FltJ;meWBZh{Ckdu>xu&^-P-roB83iKa8 zZhd_{0WdZ;mMWF%%V#K)$*52$D3wZiczEbj4}Y7|g@px@q|s>nGUR7XNlD@A>MBX{ z_4SomSy?{gKDUL{YK2~}M_E}JA|fK-@puBJP%4$8wzd{Joesgl!4Qc=&}cL$C@6qb zDg^+vw6wrxvjtA6TCJwX;~`1*^z;PWg+wCp=`ugd$;nBew&s6Z3=R&Wy}cb?uNQ@d zh1lKQ^@}h$ITCwO~%gT-Qj$KwG>+}zw?XJ-d1D=Qyn$0vg5=x81t9g!rRPA4-m zGW?>{YPBRuuh+}?`1oHvXMdwss}*{o+wJDJZ{H{qiG=ac&`{d#c9NvYWcueo0L;$L zro-V7&Shg`gU!v&%+AiHQmN$d@GwczX0!bsAOOb2#nEIk@%{bXrzoDEpM~#{k&)jA z{GqwIxf~rG<@WYAFD@?VcDw0vxoELi7#kb=OTd6{ntx0F{}18svy0eD^q;Up00000 LNkvXXu0mjf*{1p1 literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/settings_themes@2x.png b/Telegram/Resources/icons/settings_themes@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..b26c2cd2b2f46fb702327733c7f1035067d81165 GIT binary patch literal 1966 zcmV;f2T}NmP)q9C=4M!ex<sNI8_jH1vs|0)`hWO8j*jP??QCw3_Rs~_hjZV*^SiF!y?giT zApij3KWvNUJAq`|Ux9zR{T2A98z&j0>FMcESXc;3r4rF}=2xIhCc~DNmV^nLZ67{- zz(a=)VMyLN%WU;v3k!iaIZ-7q*f2>t#2;B-1+VqyXi5kw*ptXZ=L zTc1OnW= zc{83pdlq|pdl`90M@LbuRwuuUUb%9GHi7BsX}odc24-hx$K9QHJRVk7R^r>YZy6hJ z>(;Hw6L|diaoWJ|-@iw#R-1?c0RaG)En9}?&Yi=lsVPbgpJI>+0&z<#Hh+qSNWb`uchbMkvD@0(aM7Yg za~DVu1U`NGloH_K!-tgNTc^{}cHye3Dhh8^RTV8(r_)iea=9EwM@K2xnwpxq3#_cH zq!9P^_Tuv8%PCm1*-V?X$z(!;AV`g7GMQ+xX0w?#k1boaU?316VMj(rP$UvX%s=8{ zo5SJ2kt0V)Wx-$&4jw!RU%!5(;Q4$$Ef0^!V^tQ3Y&9|Neb8 ze`-{zRH)bMv8bphDz>Po2=#hBs#Gdg+#5D*pv;daPo9ij;Oy=h3Wcz&tc+C>$#jAs z@b&B0q}(1odc=rl-0-T^YSQ!g_&9WSc7~tVu3Zbo#l{0000Hp{uJ43JMCs*zD}=h+MSFTU%R6tz@xS!gUoD73lGJ!gW18 zJy=jskg#8=pr8PIdV0eA9*+krDk{SD$BrE%<>qiWV(+4_UcDlb+`fGq0RS^IGig^f zR;v~HeEyup@%enTTCEg*uh$!1p4HaYlIlKv`oze`I1i?!rIDVUPA32Wl$4Z!P$;C} zl}aT@rBWt3)+UuoL8(+y%7sE9l$4YJ0Clbmg+h#ci~>_rQ%TP=6T9EiTCJFumxlm=TCEnRr>7ZnqjCC*uC6W;$*o(r$ny(_gZcUSn3I!} zFk!PjCnpE<^YgSeyaIs$u3NV*c7c(miTQGa!9W>ZBTe!V1zxytfkfo- zcrYz3ZC->C1c8?>U80El@#9Ch>&7f_+qP{aviVr5@pwEeD=R~b#X=E>h?}wEuSBA?TJb1ur|Hal63I*im=0a*}D(Oyw&*#JH)vH0H(U6v8zgtU7 z3+&mmht<@?sQ%u)d!!bNwq0WDYPA}lKYxy)P>A-IiDpKl5qUfw+jz{Cv%4u`V#3fE35TMOwi&DaKj zxjE)rpV`O$Znqm%Diw;wV$8_M2)j@yjI|raFAyNMgWpJg{rYv%`@_S-(GHCM9f1IV zJ9qA6eRR*{`}gmsynprT)rBDtfcf&Judk2Q<%>ijp&Vp=|Nb52a{0m#2mpBb@?~0) zY_HF1YHBFEfxUb8E*yaXbGrZ~2m;-1H|d=dCr%_yVBA;OyLaz~YuBzty~4KHY%nk| z08Xb9#>U1#p-_NcuZNVBlrV1JzJ1Wp&=5}=tSs)FMd9P$*#I#*LIuxq`tUba!`y z(P)I$*49LardU!0E+qTUe{J|z;Gb@P1^(&wKaL??&M@YAH2?qr07*qoM6N<$f>F-I AUjP6A literal 0 HcmV?d00001 diff --git a/Telegram/SourceFiles/base/bytes.h b/Telegram/SourceFiles/base/bytes.h index 09a4cc028db0c..4606a2d3fc32c 100644 --- a/Telegram/SourceFiles/base/bytes.h +++ b/Telegram/SourceFiles/base/bytes.h @@ -20,9 +20,15 @@ using vector = std::vector; template using array = std::array; +inline span make_detached_span(QByteArray &container) { + return gsl::as_writeable_bytes(gsl::make_span(container)); +} + template < typename Container, - typename = std::enable_if_t>> + typename = std::enable_if_t< + !std::is_const_v + && !std::is_same_v>> inline span make_span(Container &container) { return gsl::as_writeable_bytes(gsl::make_span(container)); } diff --git a/Telegram/SourceFiles/settings/settings.style b/Telegram/SourceFiles/settings/settings.style index 75338efdb2758..319550244b924 100644 --- a/Telegram/SourceFiles/settings/settings.style +++ b/Telegram/SourceFiles/settings/settings.style @@ -53,6 +53,8 @@ settingsIconPrivacySecurity: icon {{ "settings_privacy_security", menuIconFg }}; settingsIconLanguage: icon {{ "settings_language", menuIconFg }}; settingsIconInterfaceScale: icon {{ "settings_interface_scale", menuIconFg }}; settingsIconFaq: icon {{ "settings_faq", menuIconFg }}; +settingsIconStickers: icon {{ "settings_stickers", menuIconFg }}; +settingsIconThemes: icon {{ "settings_themes", menuIconFg }}; settingsSetPhotoSkip: 7px; @@ -64,7 +66,6 @@ settingsLink: boxLinkButton; settingsAdvancedNotificationsPadding: margins(22px, 20px, 10px, 10px); settingsLinkLabel: defaultFlatLabel; settingsCheckboxesSkip: 12px; -settingsStickersEmojiPadding: 17px; settingsSendType: settingsCheckbox; settingsSendTypePadding: margins(22px, 5px, 10px, 5px); @@ -153,6 +154,13 @@ settingsBioLabelPadding: margins(22px, 11px, 22px, 0px); settingsPrivacyEditLabelPadding: margins(22px, 11px, 22px, 11px); +settingsChatButton: InfoProfileButton(settingsSectionButton) { + padding: margins(59px, 13px, 22px, 11px); +} +settingsChatIconLeft: 19px; + +settingsThemesTopSkip: 10px; +settingsThemesBottomSkip: 8px; settingsTheme: Checkbox(defaultCheckbox) { textFg: windowSubTextFg; textFgActive: windowActiveTextFg; @@ -160,7 +168,7 @@ settingsTheme: Checkbox(defaultCheckbox) { width: 80px; margin: margins(0px, 0px, 0px, 0px); - textPosition: point(0px, 88px); + textPosition: point(0px, 86px); checkPosition: point(0px, 0px); style: defaultTextStyle; diff --git a/Telegram/SourceFiles/settings/settings_chat.cpp b/Telegram/SourceFiles/settings/settings_chat.cpp index 0ceee59954c0e..471dd43360dd5 100644 --- a/Telegram/SourceFiles/settings/settings_chat.cpp +++ b/Telegram/SourceFiles/settings/settings_chat.cpp @@ -416,7 +416,8 @@ QString DownloadPathText() { } void SetupStickersEmoji(not_null container) { - AddSkip(container, st::settingsStickersEmojiPadding); + AddDivider(container); + AddSkip(container); AddSubsectionTitle(container, lng_settings_stickers_emoji); @@ -472,7 +473,9 @@ void SetupStickersEmoji(not_null container) { AddButton( container, lng_stickers_you_have, - st::settingsButton + st::settingsChatButton, + &st::settingsIconStickers, + st::settingsChatIconLeft )->addClickHandler([] { Ui::show(Box(StickersBox::Section::Installed)); }); @@ -910,19 +913,22 @@ void SetupDefaultThemes(not_null container) { } void SetupThemeOptions(not_null container) { - AddDivider(container); - AddSkip(container); + AddSkip(container, st::settingsPrivacySkip); AddSubsectionTitle(container, lng_settings_themes); + AddSkip(container, st::settingsThemesTopSkip); SetupDefaultThemes(container); + AddSkip(container, st::settingsThemesBottomSkip); AddButton( container, lng_settings_bg_edit_theme, - st::settingsButton + st::settingsChatButton, + &st::settingsIconThemes, + st::settingsChatIconLeft )->addClickHandler(App::LambdaDelayed( - st::settingsButton.ripple.hideDuration, + st::settingsChatButton.ripple.hideDuration, container, [] { Window::Theme::Editor::Start(); })); @@ -940,10 +946,10 @@ Chat::Chat(QWidget *parent, not_null self) void Chat::setupContent() { const auto content = Ui::CreateChild(this); + SetupThemeOptions(content); + SetupChatBackground(content); SetupStickersEmoji(content); SetupMessages(content); - SetupChatBackground(content); - SetupThemeOptions(content); Ui::ResizeFitChild(this, content); } diff --git a/Telegram/SourceFiles/settings/settings_common.cpp b/Telegram/SourceFiles/settings/settings_common.cpp index bc7b5530adf24..1397ef53a3085 100644 --- a/Telegram/SourceFiles/settings/settings_common.cpp +++ b/Telegram/SourceFiles/settings/settings_common.cpp @@ -77,15 +77,17 @@ not_null AddButton( not_null container, LangKey text, const style::InfoProfileButton &st, - const style::icon *leftIcon) { - return AddButton(container, Lang::Viewer(text), st, leftIcon); + const style::icon *leftIcon, + int iconLeft) { + return AddButton(container, Lang::Viewer(text), st, leftIcon, iconLeft); } not_null AddButton( not_null container, rpl::producer text, const style::InfoProfileButton &st, - const style::icon *leftIcon) { + const style::icon *leftIcon, + int iconLeft) { const auto result = container->add(object_ptr