mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-08-30 05:58:38 +00:00
First attempt of Ctrl+Tab/Ctrl+Shift+Tab UI.
This commit is contained in:
parent
a3cdae1e94
commit
0d8065fc1f
@ -1663,6 +1663,8 @@ PRIVATE
|
||||
window/window_adaptive.h
|
||||
window/window_chat_preview.cpp
|
||||
window/window_chat_preview.h
|
||||
window/window_chat_switch_process.cpp
|
||||
window/window_chat_switch_process.h
|
||||
window/window_connecting_widget.cpp
|
||||
window/window_connecting_widget.h
|
||||
window/window_controller.cpp
|
||||
|
@ -656,8 +656,20 @@ bool Application::eventFilter(QObject *object, QEvent *e) {
|
||||
updateNonIdle();
|
||||
} break;
|
||||
|
||||
case QEvent::KeyRelease: {
|
||||
const auto event = static_cast<QKeyEvent*>(e);
|
||||
if (Shortcuts::HandlePossibleChatSwitch(event)) {
|
||||
return true;
|
||||
}
|
||||
} break;
|
||||
|
||||
case QEvent::ShortcutOverride: {
|
||||
// handle shortcuts ourselves
|
||||
// Ctrl+Tab/Ctrl+Shift+Tab chat switch is a special shortcut case,
|
||||
// because it not only does an action on the shortcut activation,
|
||||
// but also keeps the UI visible until you release the Ctrl key.
|
||||
Shortcuts::HandlePossibleChatSwitch(static_cast<QKeyEvent*>(e));
|
||||
|
||||
// Handle all the shortcut management manually.
|
||||
return true;
|
||||
} break;
|
||||
|
||||
|
@ -30,6 +30,10 @@ constexpr auto kCountLimit = 256; // How many shortcuts can be in json file.
|
||||
rpl::event_stream<not_null<Request*>> RequestsStream;
|
||||
bool Paused/* = false*/;
|
||||
|
||||
Qt::Key ChatSwitchModifier/* = Qt::Key()*/;
|
||||
bool ChatSwitchStarted/* = false*/;
|
||||
rpl::event_stream<ChatSwitchRequest> ChatSwitchStream;
|
||||
|
||||
const auto AutoRepeatCommands = base::flat_set<Command>{
|
||||
Command::MediaPrevious,
|
||||
Command::MediaNext,
|
||||
@ -156,6 +160,7 @@ public:
|
||||
void toggleMedia(bool toggled);
|
||||
void toggleSupport(bool toggled);
|
||||
void listen(not_null<QWidget*> widget);
|
||||
[[nodiscard]] bool handles(const QKeySequence &sequence) const;
|
||||
|
||||
[[nodiscard]] const QStringList &errors() const;
|
||||
|
||||
@ -361,6 +366,10 @@ void Manager::listen(not_null<QWidget*> widget) {
|
||||
}
|
||||
}
|
||||
|
||||
bool Manager::handles(const QKeySequence &sequence) const {
|
||||
return _shortcuts.contains(sequence);
|
||||
}
|
||||
|
||||
void Manager::pruneListened() {
|
||||
for (auto i = begin(_listened); i != end(_listened);) {
|
||||
if (i->data()) {
|
||||
@ -470,10 +479,6 @@ void Manager::fillDefaults() {
|
||||
set(u"ctrl+pgup"_q, Command::ChatPrevious);
|
||||
set(u"alt+up"_q, Command::ChatPrevious);
|
||||
|
||||
set(u"%1+tab"_q.arg(ctrl), Command::ChatNext);
|
||||
set(u"%1+shift+tab"_q.arg(ctrl), Command::ChatPrevious);
|
||||
set(u"%1+backtab"_q.arg(ctrl), Command::ChatPrevious);
|
||||
|
||||
set(u"ctrl+alt+home"_q, Command::ChatFirst);
|
||||
set(u"ctrl+alt+end"_q, Command::ChatLast);
|
||||
|
||||
@ -800,6 +805,72 @@ bool HandleEvent(
|
||||
return Launch(Data.lookup(object));
|
||||
}
|
||||
|
||||
void CancelChatSwitch(Qt::Key result) {
|
||||
ChatSwitchModifier = Qt::Key();
|
||||
if (ChatSwitchStarted) {
|
||||
ChatSwitchStarted = false;
|
||||
ChatSwitchStream.fire({ .action = result });
|
||||
}
|
||||
}
|
||||
|
||||
rpl::producer<ChatSwitchRequest> ChatSwitchRequests() {
|
||||
return ChatSwitchStream.events();
|
||||
}
|
||||
|
||||
bool HandlePossibleChatSwitch(not_null<QKeyEvent*> event) {
|
||||
const auto type = event->type();
|
||||
if (Paused) {
|
||||
return false;
|
||||
} else if (type == QEvent::ShortcutOverride) {
|
||||
const auto key = Qt::Key(event->key());
|
||||
if (key == Qt::Key_Escape) {
|
||||
CancelChatSwitch(Qt::Key_Escape);
|
||||
return false;
|
||||
} else if (key == Qt::Key_Return || key == Qt::Key_Enter) {
|
||||
CancelChatSwitch(Qt::Key_Enter);
|
||||
return false;
|
||||
}
|
||||
const auto ctrl = Platform::IsMac()
|
||||
? Qt::MetaModifier
|
||||
: Qt::ControlModifier;
|
||||
|
||||
if (Data.handles(ctrl | Qt::ShiftModifier | Qt::Key_Tab)
|
||||
&& Data.handles(QKeySequence(ctrl | Qt::Key_Tab))
|
||||
&& Data.handles(QKeySequence(ctrl | Qt::Key_Backtab))) {
|
||||
return false;
|
||||
} else if (key == Qt::Key_Control || key == Qt::Key_Meta) {
|
||||
ChatSwitchModifier = key;
|
||||
} else if (key == Qt::Key_Tab || key == Qt::Key_Backtab) {
|
||||
const auto modifiers = event->modifiers();
|
||||
if (modifiers & ctrl) {
|
||||
if (Data.handles(modifiers | key)) {
|
||||
return false;
|
||||
}
|
||||
if (ChatSwitchModifier == Qt::Key()) {
|
||||
ChatSwitchModifier = Platform::IsMac()
|
||||
? Qt::Key_Meta
|
||||
: Qt::Key_Control;
|
||||
}
|
||||
const auto action = (modifiers & Qt::ShiftModifier)
|
||||
? Qt::Key_Backtab
|
||||
: key;
|
||||
const auto started = !std::exchange(ChatSwitchStarted, true);
|
||||
ChatSwitchStream.fire({
|
||||
.action = action,
|
||||
.started = started,
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else if (type == QEvent::KeyRelease) {
|
||||
const auto key = Qt::Key(event->key());
|
||||
if (key == ChatSwitchModifier) {
|
||||
CancelChatSwitch(Qt::Key_Enter);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ToggleMediaShortcuts(bool toggled) {
|
||||
Data.toggleMedia(toggled);
|
||||
}
|
||||
|
@ -7,6 +7,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
class QKeyEvent;
|
||||
class QShortcutEvent;
|
||||
|
||||
namespace Shortcuts {
|
||||
|
||||
enum class Command {
|
||||
@ -122,7 +125,7 @@ private:
|
||||
|
||||
};
|
||||
|
||||
rpl::producer<not_null<Request*>> Requests();
|
||||
[[nodiscard]] rpl::producer<not_null<Request*>> Requests();
|
||||
|
||||
void Start();
|
||||
void Finish();
|
||||
@ -132,7 +135,15 @@ void Listen(not_null<QWidget*> widget);
|
||||
bool Launch(Command command);
|
||||
bool HandleEvent(not_null<QObject*> object, not_null<QShortcutEvent*> event);
|
||||
|
||||
const QStringList &Errors();
|
||||
bool HandlePossibleChatSwitch(not_null<QKeyEvent*> event);
|
||||
|
||||
struct ChatSwitchRequest {
|
||||
Qt::Key action = Qt::Key_Tab; // Key_Tab, Key_Backtab or Key_Escape.
|
||||
bool started = false;
|
||||
};
|
||||
[[nodiscard]] rpl::producer<ChatSwitchRequest> ChatSwitchRequests();
|
||||
|
||||
[[nodiscard]] const QStringList &Errors();
|
||||
|
||||
// Media shortcuts are not enabled by default, because other
|
||||
// applications also use them. They are enabled only when
|
||||
|
@ -7,6 +7,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "data/components/recent_peers.h"
|
||||
|
||||
#include "data/data_peer.h"
|
||||
#include "data/data_session.h"
|
||||
#include "history/history.h"
|
||||
#include "main/main_session.h"
|
||||
#include "storage/serialize_common.h"
|
||||
#include "storage/serialize_peer.h"
|
||||
@ -133,4 +136,28 @@ void RecentPeers::applyLocal(QByteArray serialized) {
|
||||
("Suggestions: RecentPeers read OK, count: %1").arg(_list.size()));
|
||||
}
|
||||
|
||||
std::vector<not_null<Thread*>> RecentPeers::collectChatOpenHistory() const {
|
||||
_session->local().readSearchSuggestions();
|
||||
|
||||
auto result = _opens;
|
||||
result.reserve(result.size() + _list.size());
|
||||
for (const auto &peer : _list) {
|
||||
const auto history = peer->owner().history(peer);
|
||||
const auto thread = not_null<Data::Thread*>(history);
|
||||
if (!ranges::contains(result, thread)) {
|
||||
result.push_back(thread);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void RecentPeers::chatOpenPush(not_null<Thread*> thread) {
|
||||
const auto i = ranges::find(_opens, thread);
|
||||
if (i == end(_opens)) {
|
||||
_opens.insert(begin(_opens), thread);
|
||||
} else if (i != begin(_opens)) {
|
||||
ranges::rotate(begin(_opens), i, i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Data
|
||||
|
@ -13,6 +13,8 @@ class Session;
|
||||
|
||||
namespace Data {
|
||||
|
||||
class Thread;
|
||||
|
||||
class RecentPeers final {
|
||||
public:
|
||||
explicit RecentPeers(not_null<Main::Session*> session);
|
||||
@ -28,10 +30,16 @@ public:
|
||||
[[nodiscard]] QByteArray serialize() const;
|
||||
void applyLocal(QByteArray serialized);
|
||||
|
||||
[[nodiscard]] auto collectChatOpenHistory() const
|
||||
-> std::vector<not_null<Thread*>>;
|
||||
void chatOpenPush(not_null<Thread*> thread);
|
||||
|
||||
private:
|
||||
const not_null<Main::Session*> _session;
|
||||
|
||||
std::vector<not_null<PeerData*>> _list;
|
||||
std::vector<not_null<Thread*>> _opens;
|
||||
|
||||
rpl::event_stream<> _updates;
|
||||
|
||||
};
|
||||
|
@ -331,6 +331,14 @@ ivHeightDefault: 800px;
|
||||
|
||||
maxWidthSharedMediaWindow: 419px;
|
||||
|
||||
chatSwitchMargins: margins(16px, 16px, 16px, 16px);
|
||||
chatSwitchPadding: margins(12px, 12px, 12px, 12px);
|
||||
chatSwitchSize: size(72px, 72px);
|
||||
chatSwitchUserpic: UserpicButton(defaultUserpicButton) {
|
||||
size: size(56px, 56px);
|
||||
photoSize: 56px;
|
||||
}
|
||||
|
||||
// Windows specific
|
||||
|
||||
winQuitIcon: icon {{ "win_quit", windowFg }};
|
||||
|
225
Telegram/SourceFiles/window/window_chat_switch_process.cpp
Normal file
225
Telegram/SourceFiles/window/window_chat_switch_process.cpp
Normal file
@ -0,0 +1,225 @@
|
||||
/*
|
||||
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 "window/window_chat_switch_process.h"
|
||||
|
||||
#include "core/shortcuts.h"
|
||||
#include "data/components/recent_peers.h"
|
||||
#include "data/data_thread.h"
|
||||
#include "main/main_session.h"
|
||||
#include "ui/widgets/shadow.h"
|
||||
#include "ui/controls/userpic_button.h"
|
||||
#include "ui/rp_widget.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_window.h"
|
||||
|
||||
namespace Window {
|
||||
|
||||
ChatSwitchProcess::ChatSwitchProcess(
|
||||
not_null<Ui::RpWidget*> geometry,
|
||||
not_null<Main::Session*> session,
|
||||
Data::Thread *opened)
|
||||
: _session(session)
|
||||
, _widget(std::make_unique<Ui::RpWidget>(
|
||||
geometry->parentWidget() ? geometry->parentWidget() : geometry))
|
||||
, _view(Ui::CreateChild<Ui::RpWidget>(_widget.get()))\
|
||||
, _bg(st::boxRadius, st::boxBg)
|
||||
, _over(st::boxRadius, st::windowBgOver) {
|
||||
setupWidget(geometry);
|
||||
setupContent(opened);
|
||||
setupView();
|
||||
}
|
||||
|
||||
ChatSwitchProcess::~ChatSwitchProcess() = default;
|
||||
|
||||
rpl::producer<not_null<Data::Thread*>> ChatSwitchProcess::chosen() const {
|
||||
return _chosen.events();
|
||||
}
|
||||
|
||||
rpl::producer<> ChatSwitchProcess::closeRequests() const {
|
||||
return _closeRequests.events();
|
||||
}
|
||||
|
||||
void ChatSwitchProcess::process(const Request &request) {
|
||||
Expects(_selected < int(_list.size()));
|
||||
|
||||
const auto count = int(_list.size());
|
||||
if (request.action == Qt::Key_Escape) {
|
||||
_closeRequests.fire({});
|
||||
} else if (request.action == Qt::Key_Enter) {
|
||||
if (_selected >= 0) {
|
||||
_chosen.fire_copy(_list[_selected]);
|
||||
} else {
|
||||
_closeRequests.fire({});
|
||||
}
|
||||
} else if (request.action == Qt::Key_Tab) {
|
||||
if (_selected < 0 || _selected + 1 >= count) {
|
||||
setSelected(0);
|
||||
} else {
|
||||
setSelected(_selected + 1);
|
||||
}
|
||||
} else if (request.action == Qt::Key_Backtab) {
|
||||
if (_selected <= 0) {
|
||||
setSelected(count - 1);
|
||||
} else {
|
||||
setSelected(_selected - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ChatSwitchProcess::setSelected(int index) {
|
||||
if (_selected == index || _list.empty()) {
|
||||
return;
|
||||
}
|
||||
if (_selected >= 0) {
|
||||
_entries[_selected].button->update();
|
||||
}
|
||||
_selected = index;
|
||||
if (_selected >= 0) {
|
||||
_entries[_selected].button->update();
|
||||
}
|
||||
}
|
||||
|
||||
void ChatSwitchProcess::setupWidget(not_null<Ui::RpWidget*> geometry) {
|
||||
geometry->geometryValue(
|
||||
) | rpl::start_with_next([=](QRect value) {
|
||||
const auto parent = geometry->parentWidget();
|
||||
_widget->setGeometry((parent == _widget->parentWidget())
|
||||
? value
|
||||
: QRect(QPoint(), value.size()));
|
||||
}, _widget->lifetime());
|
||||
|
||||
_widget->events() | rpl::start_with_next([=](not_null<QEvent*> e) {
|
||||
if (e->type() == QEvent::MouseButtonPress) {
|
||||
_closeRequests.fire({});
|
||||
}
|
||||
}, _widget->lifetime());
|
||||
|
||||
_widget->show();
|
||||
}
|
||||
|
||||
void ChatSwitchProcess::setupContent(Data::Thread *opened) {
|
||||
_list = _session->recentPeers().collectChatOpenHistory();
|
||||
if (opened) {
|
||||
const auto i = ranges::find(_list, not_null(opened));
|
||||
if (i == end(_list)) {
|
||||
_list.insert(begin(_list), opened);
|
||||
} else if (i != begin(_list)) {
|
||||
ranges::rotate(begin(_list), i, i + 1);
|
||||
}
|
||||
_selected = 0;
|
||||
}
|
||||
|
||||
auto index = 0;
|
||||
for (const auto &thread : _list) {
|
||||
const auto button = Ui::CreateChild<Ui::AbstractButton>(_view.get());
|
||||
button->resize(st::chatSwitchSize);
|
||||
button->paintRequest() | rpl::start_with_next([=] {
|
||||
if (index == _selected) {
|
||||
auto p = QPainter(button);
|
||||
_over.paint(p, button->rect());
|
||||
}
|
||||
}, button->lifetime());
|
||||
button->setClickedCallback([=] {
|
||||
_chosen.fire_copy(thread);
|
||||
});
|
||||
button->events() | rpl::start_with_next([=](not_null<QEvent*> e) {
|
||||
if (e->type() == QEvent::MouseMove) {
|
||||
setSelected(index);
|
||||
}
|
||||
}, button->lifetime());
|
||||
button->show();
|
||||
|
||||
const auto userpic = Ui::CreateChild<Ui::UserpicButton>(
|
||||
button,
|
||||
thread->peer(),
|
||||
st::chatSwitchUserpic);
|
||||
userpic->show();
|
||||
userpic->move(
|
||||
((button->width() - userpic->width()) / 2),
|
||||
((button->height() - userpic->height()) / 2));
|
||||
userpic->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
|
||||
_entries.push_back({ .button = button });
|
||||
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
void ChatSwitchProcess::setupView() {
|
||||
_widget->sizeValue() | rpl::start_with_next([=](QSize size) {
|
||||
layout(size);
|
||||
}, _view->lifetime());
|
||||
_view->show();
|
||||
|
||||
_view->paintRequest() | rpl::start_with_next([=](QRect clip) {
|
||||
if (_outer.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
auto p = QPainter(_view);
|
||||
p.translate(-_shadowed.topLeft());
|
||||
Ui::Shadow::paint(p, _outer, _view->width(), st::boxRoundShadow);
|
||||
_bg.paint(p, _outer);
|
||||
}, _view->lifetime());
|
||||
|
||||
_view->events() | rpl::start_with_next([=](not_null<QEvent*> e) {
|
||||
if (e->type() == QEvent::MouseButtonPress) {
|
||||
e->accept();
|
||||
}
|
||||
}, _view->lifetime());
|
||||
}
|
||||
|
||||
void ChatSwitchProcess::layout(QSize size) {
|
||||
const auto full = QRect(QPoint(), size);
|
||||
const auto outer = full.marginsRemoved(st::chatSwitchMargins);
|
||||
auto inner = outer.marginsRemoved(st::chatSwitchPadding);
|
||||
const auto available = inner.width();
|
||||
const auto canPerRow = (available / st::chatSwitchSize.width());
|
||||
if (canPerRow < 1 || _list.empty()) {
|
||||
return;
|
||||
}
|
||||
const auto count = int(_list.size());
|
||||
const auto rows = (count + canPerRow - 1) / canPerRow;
|
||||
const auto minPerRow = count / rows;
|
||||
const auto wideRows = (count - (minPerRow * rows));
|
||||
const auto maxPerRow = wideRows ? (minPerRow + 1) : minPerRow;
|
||||
const auto narrowShift = wideRows ? (st::chatSwitchSize.width() / 2) : 0;
|
||||
const auto width = maxPerRow * st::chatSwitchSize.width();
|
||||
const auto height = rows * st::chatSwitchSize.height();
|
||||
|
||||
size = QSize(width, height);
|
||||
_inner = QRect(
|
||||
(full.width() - width) / 2,
|
||||
(full.height() - height) / 2,
|
||||
width,
|
||||
height);
|
||||
_outer = _inner.marginsAdded(st::chatSwitchPadding);
|
||||
|
||||
const auto padding = st::boxRoundShadow.extend + st::chatSwitchPadding;
|
||||
|
||||
auto index = 0;
|
||||
auto top = padding.top();
|
||||
for (auto row = 0; row != rows; ++row) {
|
||||
const auto columns = (row < wideRows) ? maxPerRow : minPerRow;
|
||||
auto left = padding.left() + ((row < wideRows) ? 0 : narrowShift);
|
||||
for (auto column = 0; column != columns; ++column) {
|
||||
auto &entry = _entries[index++];
|
||||
entry.button->moveToLeft(left, top, _inner.width());
|
||||
left += st::chatSwitchSize.width();
|
||||
}
|
||||
top += st::chatSwitchSize.height();
|
||||
}
|
||||
|
||||
_shadowed = _outer.marginsAdded(st::boxRoundShadow.extend);
|
||||
_view->setGeometry(_shadowed);
|
||||
}
|
||||
|
||||
rpl::lifetime &ChatSwitchProcess::lifetime() {
|
||||
return _lifetime;
|
||||
}
|
||||
|
||||
} // namespace Window
|
82
Telegram/SourceFiles/window/window_chat_switch_process.h
Normal file
82
Telegram/SourceFiles/window/window_chat_switch_process.h
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
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 "ui/round_rect.h"
|
||||
|
||||
namespace Data {
|
||||
class Thread;
|
||||
} // namespace Data
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
||||
namespace Shortcuts {
|
||||
struct ChatSwitchRequest;
|
||||
} // namespace Shortcuts
|
||||
|
||||
namespace Ui {
|
||||
class AbstractButton;
|
||||
class RpWidget;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Window {
|
||||
|
||||
class ChatSwitchProcess final {
|
||||
public:
|
||||
// Create widget in geometry->parentWidget() and geometry->geometry().
|
||||
ChatSwitchProcess(
|
||||
not_null<Ui::RpWidget*> geometry,
|
||||
not_null<Main::Session*> session,
|
||||
Data::Thread *opened);
|
||||
~ChatSwitchProcess();
|
||||
|
||||
[[nodiscard]] rpl::producer<not_null<Data::Thread*>> chosen() const;
|
||||
[[nodiscard]] rpl::producer<> closeRequests() const;
|
||||
|
||||
using Request = Shortcuts::ChatSwitchRequest;
|
||||
void process(const Request &request);
|
||||
|
||||
[[nodiscard]] rpl::lifetime &lifetime();
|
||||
|
||||
private:
|
||||
struct Entry {
|
||||
not_null<Ui::AbstractButton*> button;
|
||||
};
|
||||
void setupWidget(not_null<Ui::RpWidget*> geometry);
|
||||
void setupContent(Data::Thread *opened);
|
||||
void setupView();
|
||||
|
||||
void layout(QSize size);
|
||||
|
||||
void setSelected(int index);
|
||||
|
||||
const not_null<Main::Session*> _session;
|
||||
const std::unique_ptr<Ui::RpWidget> _widget;
|
||||
const not_null<Ui::RpWidget*> _view;
|
||||
|
||||
QRect _shadowed;
|
||||
QRect _outer;
|
||||
QRect _inner;
|
||||
Ui::RoundRect _bg;
|
||||
Ui::RoundRect _over;
|
||||
|
||||
std::vector<not_null<Data::Thread*>> _list;
|
||||
std::vector<Entry> _entries;
|
||||
|
||||
int _selected = -1;
|
||||
|
||||
rpl::event_stream<not_null<Data::Thread*>> _chosen;
|
||||
rpl::event_stream<> _closeRequests;
|
||||
|
||||
rpl::lifetime _lifetime;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Window
|
@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "boxes/peers/replace_boost_box.h"
|
||||
#include "boxes/delete_messages_box.h"
|
||||
#include "window/window_chat_preview.h"
|
||||
#include "window/window_chat_switch_process.h"
|
||||
#include "window/window_controller.h"
|
||||
#include "window/window_filters_menu.h"
|
||||
#include "window/window_separate_id.h"
|
||||
@ -32,6 +33,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "history/view/history_view_subsection_tabs.h"
|
||||
#include "media/player/media_player_instance.h"
|
||||
#include "media/view/media_view_open_common.h"
|
||||
#include "data/components/recent_peers.h"
|
||||
#include "data/stickers/data_custom_emoji.h"
|
||||
#include "data/data_document_resolver.h"
|
||||
#include "data/data_download_manager.h"
|
||||
@ -1735,18 +1737,50 @@ void SessionController::init() {
|
||||
}
|
||||
|
||||
void SessionController::setupShortcuts() {
|
||||
Shortcuts::Requests(
|
||||
using namespace Shortcuts;
|
||||
|
||||
ChatSwitchRequests(
|
||||
) | rpl::filter([=](const ChatSwitchRequest &request) {
|
||||
return !window().locked()
|
||||
&& (_chatSwitchProcess
|
||||
|| (request.started
|
||||
&& (Core::App().activeWindow() == &window())));
|
||||
}) | rpl::start_with_next([=](const ChatSwitchRequest &request) {
|
||||
if (!_chatSwitchProcess) {
|
||||
_chatSwitchProcess = std::make_unique<ChatSwitchProcess>(
|
||||
widget()->bodyWidget(),
|
||||
&session(),
|
||||
activeChatCurrent().thread());
|
||||
const auto close = [this, raw = _chatSwitchProcess.get()] {
|
||||
if (_chatSwitchProcess.get() == raw) {
|
||||
base::take(_chatSwitchProcess);
|
||||
}
|
||||
};
|
||||
|
||||
_chatSwitchProcess->chosen(
|
||||
) | rpl::start_with_next([=](not_null<Data::Thread*> thread) {
|
||||
close();
|
||||
jumpToChatListEntry({ Dialogs::Key(thread), FullMsgId() });
|
||||
}, _chatSwitchProcess->lifetime());
|
||||
|
||||
_chatSwitchProcess->closeRequests(
|
||||
) | rpl::start_with_next(close, _chatSwitchProcess->lifetime());
|
||||
}
|
||||
_chatSwitchProcess->process(request);
|
||||
}, _lifetime);
|
||||
|
||||
Requests(
|
||||
) | rpl::filter([=] {
|
||||
return (Core::App().activeWindow() == &window())
|
||||
&& !isLayerShown()
|
||||
&& !window().locked();
|
||||
}) | rpl::start_with_next([=](not_null<Shortcuts::Request*> request) {
|
||||
using C = Shortcuts::Command;
|
||||
}) | rpl::start_with_next([=](not_null<Request*> request) {
|
||||
using C = Command;
|
||||
|
||||
const auto app = &Core::App();
|
||||
const auto accountsCount = int(app->domain().accounts().size());
|
||||
auto &&accounts = ranges::views::zip(
|
||||
Shortcuts::kShowAccount,
|
||||
kShowAccount,
|
||||
ranges::views::ints(0, accountsCount));
|
||||
for (const auto &[command, index] : accounts) {
|
||||
request->check(command) && request->handle([=] {
|
||||
@ -2033,6 +2067,10 @@ void SessionController::setActiveChatEntry(Dialogs::RowDescriptor row) {
|
||||
{ anim::type::normal, anim::activation::background });
|
||||
}, _activeHistoryLifetime);
|
||||
}
|
||||
|
||||
if (const auto thread = row.key.thread()) {
|
||||
session().recentPeers().chatOpenPush(thread);
|
||||
}
|
||||
}
|
||||
if (session().supportMode()) {
|
||||
pushToChatEntryHistory(row);
|
||||
|
@ -99,6 +99,7 @@ class SectionMemento;
|
||||
class Controller;
|
||||
class FiltersMenu;
|
||||
class ChatPreviewManager;
|
||||
class ChatSwitchProcess;
|
||||
|
||||
struct PeerByLinkInfo;
|
||||
struct SeparateId;
|
||||
@ -784,6 +785,8 @@ private:
|
||||
std::deque<std::shared_ptr<Ui::ChatTheme>> _lastUsedCustomChatThemes;
|
||||
rpl::variable<PeerThemeOverride> _peerThemeOverride;
|
||||
|
||||
std::unique_ptr<ChatSwitchProcess> _chatSwitchProcess;
|
||||
|
||||
base::has_weak_ptr _storyOpenGuard;
|
||||
|
||||
QString _premiumRef;
|
||||
|
Loading…
x
Reference in New Issue
Block a user