diff --git a/Telegram/SourceFiles/core/shortcuts.cpp b/Telegram/SourceFiles/core/shortcuts.cpp index 01bf152db..21fc3d4a6 100644 --- a/Telegram/SourceFiles/core/shortcuts.cpp +++ b/Telegram/SourceFiles/core/shortcuts.cpp @@ -54,6 +54,8 @@ const auto CommandByName = base::flat_map{ { qsl("previous_chat") , Command::ChatPrevious }, { qsl("next_chat") , Command::ChatNext }, + { qsl("first_chat") , Command::ChatFirst }, + { qsl("last_chat") , Command::ChatLast }, }; const auto CommandNames = base::flat_map{ @@ -73,6 +75,8 @@ const auto CommandNames = base::flat_map{ { Command::ChatPrevious , qsl("previous_chat") }, { Command::ChatNext , qsl("next_chat") }, + { Command::ChatFirst , qsl("first_chat") }, + { Command::ChatLast , qsl("last_chat") }, }; class Manager { @@ -283,6 +287,12 @@ void Manager::fillDefaults() { set(qsl("ctrl+shift+tab"), Command::ChatPrevious); set(qsl("ctrl+backtab"), Command::ChatPrevious); } + set(qsl("ctrl+alt+home"), Command::ChatFirst); + set(qsl("ctrl+alt+end"), Command::ChatLast); + + set(qsl("f5"), Command::SupportReloadTemplates); + set(qsl("ctrl+delete"), Command::SupportToggleMuted); + set(qsl("ctrl+insert"), Command::SupportScrollToCurrent); } void Manager::writeDefaultFile() { diff --git a/Telegram/SourceFiles/core/shortcuts.h b/Telegram/SourceFiles/core/shortcuts.h index 8f59c2e85..b15cd2870 100644 --- a/Telegram/SourceFiles/core/shortcuts.h +++ b/Telegram/SourceFiles/core/shortcuts.h @@ -26,6 +26,12 @@ enum class Command { ChatPrevious, ChatNext, + ChatFirst, + ChatLast, + + SupportReloadTemplates, + SupportToggleMuted, + SupportScrollToCurrent, }; bool Launch(Command command); diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index 9fa1ae662..bb9087d34 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -13,9 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/feed/history_feed_section.h" #include "history/history.h" #include "history/history_item.h" -#include "styles/style_dialogs.h" -#include "styles/style_chat_helpers.h" -#include "styles/style_window.h" +#include "core/shortcuts.h" #include "ui/widgets/buttons.h" #include "ui/widgets/popup_menu.h" #include "ui/text_options.h" @@ -36,6 +34,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "window/window_peer_menu.h" #include "ui/widgets/multi_select.h" #include "ui/empty_userpic.h" +#include "styles/style_dialogs.h" +#include "styles/style_chat_helpers.h" +#include "styles/style_window.h" namespace { @@ -160,6 +161,8 @@ DialogsInner::DialogsInner(QWidget *parent, not_null contro updateDialogRow(next, rect); }, lifetime()); refresh(); + + setupShortcuts(); } int DialogsInner::dialogsOffset() const { @@ -2288,16 +2291,16 @@ void DialogsInner::selectSkip(int32 direction) { update(); } -void DialogsInner::scrollToPeer(not_null history, MsgId msgId) { +void DialogsInner::scrollToEntry(const Dialogs::RowDescriptor &entry) { int32 fromY = -1; if (_state == State::Default) { - if (auto row = shownDialogs()->getRow(history)) { + if (auto row = shownDialogs()->getRow(entry.key)) { fromY = dialogsOffset() + row->pos() * st::dialogsRowHeight; } } else if (_state == State::Filtered) { - if (msgId) { + if (entry.fullId.msg) { for (int32 i = 0, c = _searchResults.size(); i < c; ++i) { - if (_searchResults[i]->item()->history() == history && _searchResults[i]->item()->id == msgId) { + if (_searchResults[i]->item()->fullId() == entry.fullId) { fromY = searchedOffset() + i * st::dialogsRowHeight; break; } @@ -2305,7 +2308,7 @@ void DialogsInner::scrollToPeer(not_null history, MsgId msgId) { } if (fromY < 0) { for (auto i = 0, c = _filterResults.size(); i != c; ++i) { - if (_filterResults[i]->history() == history) { + if (_filterResults[i]->key() == entry.key) { fromY = filteredOffset() + (i * st::dialogsRowHeight); break; } @@ -2551,7 +2554,6 @@ void DialogsInner::destroyData() { } } - Dialogs::RowDescriptor DialogsInner::chatListEntryBefore( const Dialogs::RowDescriptor &which) const { if (!which.key) { @@ -2700,6 +2702,56 @@ Dialogs::RowDescriptor DialogsInner::chatListEntryAfter( return Dialogs::RowDescriptor(); } +Dialogs::RowDescriptor DialogsInner::chatListEntryFirst() const { + if (_state == State::Default) { + const auto i = shownDialogs()->cbegin(); + if (i != shownDialogs()->cend()) { + return Dialogs::RowDescriptor( + (*i)->key(), + FullMsgId(NoChannel, ShowAtUnreadMsgId)); + } + return Dialogs::RowDescriptor(); + } else if (!_filterResults.empty()) { + return Dialogs::RowDescriptor( + _filterResults.front()->key(), + FullMsgId(NoChannel, ShowAtUnreadMsgId)); + } else if (!_peerSearchResults.empty()) { + return Dialogs::RowDescriptor( + App::history(_peerSearchResults.front()->peer), + FullMsgId(NoChannel, ShowAtUnreadMsgId)); + } else if (!_searchResults.empty()) { + return Dialogs::RowDescriptor( + _searchResults.front()->item()->history(), + _searchResults.front()->item()->fullId()); + } + return Dialogs::RowDescriptor(); +} + +Dialogs::RowDescriptor DialogsInner::chatListEntryLast() const { + if (_state == State::Default) { + const auto i = shownDialogs()->cend(); + if (i != shownDialogs()->cbegin()) { + return Dialogs::RowDescriptor( + (*(i - 1))->key(), + FullMsgId(NoChannel, ShowAtUnreadMsgId)); + } + return Dialogs::RowDescriptor(); + } else if (!_searchResults.empty()) { + return Dialogs::RowDescriptor( + _searchResults.back()->item()->history(), + _searchResults.back()->item()->fullId()); + } else if (!_peerSearchResults.empty()) { + return Dialogs::RowDescriptor( + App::history(_peerSearchResults.back()->peer), + FullMsgId(NoChannel, ShowAtUnreadMsgId)); + } else if (!_filterResults.empty()) { + return Dialogs::RowDescriptor( + _filterResults.back()->key(), + FullMsgId(NoChannel, ShowAtUnreadMsgId)); + } + return Dialogs::RowDescriptor(); +} + Dialogs::IndexedList *DialogsInner::contactsList() { return _contacts.get(); } @@ -2728,3 +2780,84 @@ MsgId DialogsInner::lastSearchMigratedId() const { return _lastSearchMigratedId; } +void DialogsInner::setupShortcuts() { + Shortcuts::Requests( + ) | rpl::filter([=] { + return isActiveWindow() && !Ui::isLayerShown(); + }) | rpl::start_with_next([=](not_null request) { + using Command = Shortcuts::Command; + + if (App::main()->selectingPeer()) { + return; + } + const auto row = _controller->activeChatEntryCurrent(); + if (row.key) { + request->check(Command::ChatPrevious) && request->handle([=] { + return showPreviousChat(row); + }); + request->check(Command::ChatNext) && request->handle([=] { + return showNextChat(row); + }); + } + request->check(Command::ChatFirst) && request->handle([=] { + return showFirstChat(); + }); + request->check(Command::ChatLast) && request->handle([=] { + return showLastChat(); + }); + if (Auth().supportMode() && row.key.history()) { + request->check( + Command::SupportScrollToCurrent + ) && request->handle([=] { + scrollToEntry(row); + return true; + }); + } + }, lifetime()); +} + +bool DialogsInner::showNextChat(const Dialogs::RowDescriptor ¤t) { + return jumpToDialogRow(chatListEntryAfter(current), 1); +} + +bool DialogsInner::showPreviousChat(const Dialogs::RowDescriptor ¤t) { + return jumpToDialogRow(chatListEntryBefore(current), -1); +} + +bool DialogsInner::showFirstChat() { + return jumpToDialogRow(chatListEntryFirst(), 1); +} + +bool DialogsInner::showLastChat() { + return jumpToDialogRow(chatListEntryLast(), -1); +} + +bool DialogsInner::jumpToDialogRow( + const Dialogs::RowDescriptor &to, + int skipDirection) { + const auto entry = [&] { + auto result = to; + if (Auth().supportMode()) { + while (result.key + && !result.key.entry()->chatListUnreadCount() + && !result.key.entry()->chatListUnreadMark()) { + result = (skipDirection > 0) + ? chatListEntryAfter(result) + : chatListEntryBefore(result); + } + } + return result; + }(); + if (const auto history = entry.key.history()) { + Ui::showPeerHistory(history, entry.fullId.msg); + return true; + } else if (const auto feed = entry.key.feed()) { + if (const auto item = App::histItemById(entry.fullId)) { + _controller->showSection( + HistoryFeed::Memento(feed, item->position())); + } else { + _controller->showSection(HistoryFeed::Memento(feed)); + } + } + return false; +} diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h index 48dcdd9bb..c50abdde3 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h @@ -66,12 +66,7 @@ public: void destroyData(); - Dialogs::RowDescriptor chatListEntryBefore( - const Dialogs::RowDescriptor &which) const; - Dialogs::RowDescriptor chatListEntryAfter( - const Dialogs::RowDescriptor &which) const; - - void scrollToPeer(not_null history, MsgId msgId); + void scrollToEntry(const Dialogs::RowDescriptor &entry); Dialogs::IndexedList *contactsList(); Dialogs::IndexedList *dialogsList(); @@ -192,6 +187,22 @@ private: bool uniqueSearchResults() const; bool hasHistoryInSearchResults(not_null history) const; + void setupShortcuts(); + bool showNextChat(const Dialogs::RowDescriptor ¤t); + bool showPreviousChat(const Dialogs::RowDescriptor ¤t); + bool showFirstChat(); + bool showLastChat(); + bool jumpToDialogRow( + const Dialogs::RowDescriptor &to, + int skipDirection); + + Dialogs::RowDescriptor chatListEntryBefore( + const Dialogs::RowDescriptor &which) const; + Dialogs::RowDescriptor chatListEntryAfter( + const Dialogs::RowDescriptor &which) const; + Dialogs::RowDescriptor chatListEntryFirst() const; + Dialogs::RowDescriptor chatListEntryLast() const; + void applyDialog(const MTPDdialog &dialog); // void applyFeedDialog(const MTPDdialogFeed &dialog); // #feed diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp index 75793db82..4252b612a 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp @@ -1450,18 +1450,8 @@ void DialogsWidget::destroyData() { _inner->destroyData(); } -Dialogs::RowDescriptor DialogsWidget::chatListEntryBefore( - const Dialogs::RowDescriptor &which) const { - return _inner->chatListEntryBefore(which); -} - -Dialogs::RowDescriptor DialogsWidget::chatListEntryAfter( - const Dialogs::RowDescriptor &which) const { - return _inner->chatListEntryAfter(which); -} - -void DialogsWidget::scrollToPeer(not_null history, MsgId msgId) { - _inner->scrollToPeer(history, msgId); +void DialogsWidget::scrollToEntry(const Dialogs::RowDescriptor &entry) { + _inner->scrollToEntry(entry); } void DialogsWidget::removeDialog(Dialogs::Key key) { diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.h b/Telegram/SourceFiles/dialogs/dialogs_widget.h index 6a77a5ff6..f57969ee7 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.h +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.h @@ -76,12 +76,7 @@ public: void destroyData(); - Dialogs::RowDescriptor chatListEntryBefore( - const Dialogs::RowDescriptor &which) const; - Dialogs::RowDescriptor chatListEntryAfter( - const Dialogs::RowDescriptor &which) const; - - void scrollToPeer(not_null history, MsgId msgId); + void scrollToEntry(const Dialogs::RowDescriptor &entry); Dialogs::IndexedList *contactsList(); Dialogs::IndexedList *dialogsList(); diff --git a/Telegram/SourceFiles/history/admin_log/history_admin_log_section.cpp b/Telegram/SourceFiles/history/admin_log/history_admin_log_section.cpp index cc9aa20f5..7d6df0621 100644 --- a/Telegram/SourceFiles/history/admin_log/history_admin_log_section.cpp +++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_section.cpp @@ -322,14 +322,14 @@ void Widget::setInternalState(const QRect &geometry, not_null m void Widget::setupShortcuts() { Shortcuts::Requests( - ) | rpl::start_with_next([=](not_null request) { + ) | rpl::filter([=] { + return isActiveWindow() && !Ui::isLayerShown() && inFocusChain(); + }) | rpl::start_with_next([=](not_null request) { using Command = Shortcuts::Command; - if (isActiveWindow() && !Ui::isLayerShown() && inFocusChain()) { - request->check(Command::Search, 1) && request->handle([=] { - _fixedBar->showSearch(); - return true; - }); - } + request->check(Command::Search, 1) && request->handle([=] { + _fixedBar->showSearch(); + return true; + }); }, lifetime()); } diff --git a/Telegram/SourceFiles/history/feed/history_feed_section.cpp b/Telegram/SourceFiles/history/feed/history_feed_section.cpp index b15ba1b7c..eaa63c260 100644 --- a/Telegram/SourceFiles/history/feed/history_feed_section.cpp +++ b/Telegram/SourceFiles/history/feed/history_feed_section.cpp @@ -299,14 +299,14 @@ void Widget::setInternalState( void Widget::setupShortcuts() { Shortcuts::Requests( - ) | rpl::start_with_next([=](not_null request) { + ) | rpl::filter([=] { + return isActiveWindow() && !Ui::isLayerShown() && inFocusChain(); + }) | rpl::start_with_next([=](not_null request) { using Command = Shortcuts::Command; - if (isActiveWindow() && !Ui::isLayerShown() && inFocusChain()) { - request->check(Command::Search, 1) && request->handle([=] { - App::main()->searchInChat(_feed); - return true; - }); - } + request->check(Command::Search, 1) && request->handle([=] { + App::main()->searchInChat(_feed); + return true; + }); }, lifetime()); } diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index d300a9197..9072af10c 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -1586,82 +1586,27 @@ void HistoryWidget::notify_migrateUpdated(PeerData *peer) { void HistoryWidget::setupShortcuts() { Shortcuts::Requests( - ) | rpl::start_with_next([=](not_null request) { + ) | rpl::filter([=] { + return isActiveWindow() && !Ui::isLayerShown() && inFocusChain(); + }) | rpl::start_with_next([=](not_null request) { using Command = Shortcuts::Command; - if (isActiveWindow() && !Ui::isLayerShown() && _history) { - if (inFocusChain()) { - request->check(Command::Search) && request->handle([=] { - App::main()->searchInChat(_history); + if (_history) { + request->check(Command::Search) && request->handle([=] { + App::main()->searchInChat(_history); + return true; + }); + if (Auth().supportMode()) { + request->check( + Command::SupportToggleMuted + ) && request->handle([=] { + onMuteUnmute(); return true; }); } - request->check(Command::ChatPrevious) && request->handle([=] { - return showPreviousChat(); - }); - request->check(Command::ChatNext) && request->handle([=] { - return showNextChat(); - }); } }, lifetime()); } -bool HistoryWidget::showNextChat() { - Expects(_history != nullptr); - - const auto next = App::main()->chatListEntryAfter( - Dialogs::RowDescriptor( - _history, - FullMsgId(_history->channelId(), std::max(_showAtMsgId, 0)))); - const auto to = [&] { - auto result = next; - if (Auth().supportMode()) { - while (result.key - && !result.key.entry()->chatListUnreadCount() - && !result.key.entry()->chatListUnreadMark()) { - result = App::main()->chatListEntryAfter(result); - } - } - return result; - }(); - return jumpToDialogRow(to); -} - -bool HistoryWidget::showPreviousChat() { - Expects(_history != nullptr); - - const auto previous = App::main()->chatListEntryBefore( - Dialogs::RowDescriptor( - _history, - FullMsgId(_history->channelId(), std::max(_showAtMsgId, 0)))); - const auto to = [&] { - auto result = previous; - if (Auth().supportMode()) { - while (result.key - && !result.key.entry()->chatListUnreadCount() - && !result.key.entry()->chatListUnreadMark()) { - result = App::main()->chatListEntryBefore(result); - } - } - return result; - }(); - return jumpToDialogRow(to); -} - -bool HistoryWidget::jumpToDialogRow(const Dialogs::RowDescriptor &to) { - if (const auto history = to.key.history()) { - Ui::showPeerHistory(history, to.fullId.msg); - return true; - } else if (const auto feed = to.key.feed()) { - if (const auto item = App::histItemById(to.fullId)) { - controller()->showSection( - HistoryFeed::Memento(feed, item->position())); - } else { - controller()->showSection(HistoryFeed::Memento(feed)); - } - } - return false; -} - void HistoryWidget::clearReplyReturns() { _replyReturns.clear(); _replyReturn = 0; diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 95c316778..a69600364 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -1807,7 +1807,9 @@ void MainWidget::ui_showPeerHistory( if (!_dialogs->isHidden()) { if (!back) { if (const auto history = _history->history()) { - _dialogs->scrollToPeer(history, showAtMsgId); + _dialogs->scrollToEntry(Dialogs::RowDescriptor( + history, + FullMsgId(history->channelId(), showAtMsgId))); } } _dialogs->update(); @@ -1820,22 +1822,6 @@ PeerData *MainWidget::ui_getPeerForMouseAction() { return _history->ui_getPeerForMouseAction(); } -Dialogs::RowDescriptor MainWidget::chatListEntryBefore( - const Dialogs::RowDescriptor &which) const { - if (selectingPeer()) { - return Dialogs::RowDescriptor(); - } - return _dialogs->chatListEntryBefore(which); -} - -Dialogs::RowDescriptor MainWidget::chatListEntryAfter( - const Dialogs::RowDescriptor &which) const { - if (selectingPeer()) { - return Dialogs::RowDescriptor(); - } - return _dialogs->chatListEntryAfter(which); -} - PeerData *MainWidget::peer() { return _history->peer(); } diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index 1bfc00940..e3165ed7c 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -137,11 +137,6 @@ public: not_null item); void markActiveHistoryAsRead(); - Dialogs::RowDescriptor chatListEntryBefore( - const Dialogs::RowDescriptor &which) const; - Dialogs::RowDescriptor chatListEntryAfter( - const Dialogs::RowDescriptor &which) const; - PeerData *peer(); int backgroundFromY() const; diff --git a/Telegram/SourceFiles/support/support_templates.cpp b/Telegram/SourceFiles/support/support_templates.cpp index f63f08bcc..8823ef5d2 100644 --- a/Telegram/SourceFiles/support/support_templates.cpp +++ b/Telegram/SourceFiles/support/support_templates.cpp @@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/toast/toast.h" #include "data/data_session.h" +#include "core/shortcuts.h" #include "auth_session.h" namespace Support { @@ -449,6 +450,16 @@ struct Templates::Updates { Templates::Templates(not_null session) : _session(session) { load(); + Shortcuts::Requests( + ) | rpl::start_with_next([=](not_null request) { + using Command = Shortcuts::Command; + request->check( + Command::SupportReloadTemplates + ) && request->handle([=] { + reload(); + return true; + }); + }, _lifetime); } void Templates::reload() { diff --git a/Telegram/SourceFiles/support/support_templates.h b/Telegram/SourceFiles/support/support_templates.h index 846885e35..b309fefb0 100644 --- a/Telegram/SourceFiles/support/support_templates.h +++ b/Telegram/SourceFiles/support/support_templates.h @@ -88,6 +88,8 @@ private: std::unique_ptr _updates; + rpl::lifetime _lifetime; + }; } // namespace Support