Separate window for forums/topics/sublists/archive.

This commit is contained in:
John Preston 2024-06-28 21:44:06 +04:00
parent 6dc3bd65e8
commit 69d21f73ef
34 changed files with 753 additions and 414 deletions

View file

@ -1546,6 +1546,8 @@ PRIVATE
window/window_peer_menu.cpp
window/window_peer_menu.h
window/window_section_common.h
window/window_separate_id.cpp
window/window_separate_id.h
window/window_session_controller.cpp
window/window_session_controller.h
window/window_session_controller_link_info.h

View file

@ -81,7 +81,7 @@ void ChangeFilterById(
MTP_int(filter.id()),
filter.tl()
)).done([=, chat = history->peer->name(), name = filter.title()] {
const auto account = &history->session().account();
const auto account = not_null(&history->session().account());
if (const auto controller = Core::App().windowFor(account)) {
controller->showToast((add
? tr::lng_filters_toast_add

View file

@ -706,7 +706,8 @@ bool Call::handleUpdate(const MTPPhoneCall &call) {
}
}
if (data.is_need_rating() && _id && _accessHash) {
const auto window = Core::App().windowFor(_user);
const auto window = Core::App().windowFor(
Window::SeparateId(_user));
const auto session = &_user->session();
const auto callId = _id;
const auto callAccessHash = _accessHash;
@ -1402,7 +1403,8 @@ void Call::handleRequestError(const QString &error) {
_user->name())
: QString();
if (!inform.isEmpty()) {
if (const auto window = Core::App().windowFor(_user)) {
if (const auto window = Core::App().windowFor(
Window::SeparateId(_user))) {
window->show(Ui::MakeInformBox(inform));
} else {
Ui::show(Ui::MakeInformBox(inform));
@ -1420,7 +1422,8 @@ void Call::handleControllerError(const QString &error) {
? tr::lng_call_error_audio_io(tr::now)
: QString();
if (!inform.isEmpty()) {
if (const auto window = Core::App().windowFor(_user)) {
if (const auto window = Core::App().windowFor(
Window::SeparateId(_user))) {
window->show(Ui::MakeInformBox(inform));
} else {
Ui::show(Ui::MakeInformBox(inform));

View file

@ -30,15 +30,15 @@ ResolveWindow ResolveWindowDefault() {
return (Window::SessionController*)nullptr;
};
auto &app = Core::App();
const auto account = not_null(&session->account());
if (const auto a = check(app.activeWindow())) {
return a;
} else if (const auto b = check(app.activePrimaryWindow())) {
return b;
} else if (const auto c = check(app.windowFor(&session->account()))) {
} else if (const auto c = check(app.windowFor(account))) {
return c;
} else if (const auto d = check(
app.ensureSeparateWindowForAccount(
&session->account()))) {
} else if (const auto d = check(app.ensureSeparateWindowFor(
account))) {
return d;
}
return nullptr;

View file

@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "core/application.h"
#include "data/data_abstract_structure.h"
#include "data/data_forum.h"
#include "data/data_photo.h"
#include "data/data_document.h"
#include "data/data_session.h"
@ -91,6 +92,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "payments/payments_checkout_process.h"
#include "export/export_manager.h"
#include "webrtc/webrtc_environment.h"
#include "window/window_separate_id.h"
#include "window/window_session_controller.h"
#include "window/window_controller.h"
#include "boxes/abstract_box.h"
@ -209,8 +211,7 @@ Application::~Application() {
setLastActiveWindow(nullptr);
_windowInSettings = _lastActivePrimaryWindow = nullptr;
_closingAsyncWindows.clear();
_secondaryWindows.clear();
_primaryWindows.clear();
_windows.clear();
_mediaView = nullptr;
_notifications->clearAllFast();
@ -315,8 +316,8 @@ void Application::run() {
// Create mime database, so it won't be slow later.
QMimeDatabase().mimeTypeForName(u"text/plain"_q);
_primaryWindows.emplace(nullptr, std::make_unique<Window::Controller>());
setLastActiveWindow(_primaryWindows.front().second.get());
_windows.emplace(nullptr, std::make_unique<Window::Controller>());
setLastActiveWindow(_windows.front().second.get());
_windowInSettings = _lastActivePrimaryWindow = _lastActiveWindow;
_domain->activeChanges(
@ -405,7 +406,7 @@ void Application::run() {
}
void Application::showAccount(not_null<Main::Account*> account) {
if (const auto separate = separateWindowForAccount(account)) {
if (const auto separate = separateWindowFor(account)) {
_lastActivePrimaryWindow = separate;
separate->activate();
} else if (const auto last = activePrimaryWindow()) {
@ -413,13 +414,13 @@ void Application::showAccount(not_null<Main::Account*> account) {
}
}
void Application::checkWindowAccount(not_null<Window::Controller*> window) {
const auto account = window->maybeAccount();
for (auto &[key, existing] : _primaryWindows) {
if (existing.get() == window && key != account) {
void Application::checkWindowId(not_null<Window::Controller*> window) {
const auto id = window->id();
for (auto &[existingId, existing] : _windows) {
if (existing.get() == window && existingId != id) {
auto found = std::move(existing);
_primaryWindows.remove(key);
_primaryWindows.emplace(account, std::move(found));
_windows.remove(existingId);
_windows.emplace(id, std::move(found));
break;
}
}
@ -495,10 +496,7 @@ void Application::startSystemDarkModeViewer() {
void Application::enumerateWindows(Fn<void(
not_null<Window::Controller*>)> callback) const {
for (const auto &window : ranges::views::values(_primaryWindows)) {
callback(window.get());
}
for (const auto &window : ranges::views::values(_secondaryWindows)) {
for (const auto &window : ranges::views::values(_windows)) {
callback(window.get());
}
}
@ -607,10 +605,7 @@ void Application::clearEmojiSourceImages() {
}
bool Application::isActiveForTrayMenu() const {
return ranges::any_of(ranges::views::values(_primaryWindows), [=](
const std::unique_ptr<Window::Controller> &controller) {
return controller->widget()->isActiveForTrayMenu();
}) || ranges::any_of(ranges::views::values(_secondaryWindows), [=](
return ranges::any_of(ranges::views::values(_windows), [=](
const std::unique_ptr<Window::Controller> &controller) {
return controller->widget()->isActiveForTrayMenu();
});
@ -1287,44 +1282,36 @@ Window::Controller *Application::activePrimaryWindow() const {
return _lastActivePrimaryWindow;
}
Window::Controller *Application::separateWindowForAccount(
not_null<Main::Account*> account) const {
for (const auto &[openedAccount, window] : _primaryWindows) {
if (openedAccount == account.get()) {
Window::Controller *Application::separateWindowFor(
Window::SeparateId id) const {
for (const auto &[existingId, window] : _windows) {
if (existingId == id) {
return window.get();
}
}
return nullptr;
}
Window::Controller *Application::separateWindowForPeer(
not_null<PeerData*> peer) const {
for (const auto &[history, window] : _secondaryWindows) {
if (history->peer == peer) {
return window.get();
}
}
return nullptr;
}
Window::Controller *Application::ensureSeparateWindowForPeer(
not_null<PeerData*> peer,
Window::Controller *Application::ensureSeparateWindowFor(
Window::SeparateId id,
MsgId showAtMsgId) {
const auto activate = [&](not_null<Window::Controller*> window) {
window->activate();
return window;
};
if (const auto existing = separateWindowForPeer(peer)) {
existing->sessionController()->showPeerHistory(
peer,
Window::SectionShow::Way::ClearStack,
showAtMsgId);
if (const auto existing = separateWindowFor(id)) {
if (id.thread && id.type == Window::SeparateType::Chat) {
existing->sessionController()->showThread(
id.thread,
showAtMsgId,
Window::SectionShow::Way::ClearStack);
}
return activate(existing);
}
const auto result = _secondaryWindows.emplace(
peer->owner().history(peer),
std::make_unique<Window::Controller>(peer, showAtMsgId)
const auto result = _windows.emplace(
id,
std::make_unique<Window::Controller>(id, showAtMsgId)
).first->second.get();
processCreatedWindow(result);
result->firstShow();
@ -1332,55 +1319,63 @@ Window::Controller *Application::ensureSeparateWindowForPeer(
return activate(result);
}
Window::Controller *Application::ensureSeparateWindowForAccount(
not_null<Main::Account*> account) {
const auto activate = [&](not_null<Window::Controller*> window) {
window->activate();
return window;
};
if (const auto existing = separateWindowForAccount(account)) {
return activate(existing);
}
const auto result = _primaryWindows.emplace(
account,
std::make_unique<Window::Controller>(account)
).first->second.get();
processCreatedWindow(result);
result->firstShow();
result->finishFirstShow();
return activate(result);
}
Window::Controller *Application::windowFor(not_null<PeerData*> peer) const {
if (const auto separate = separateWindowForPeer(peer)) {
return separate;
}
return windowFor(&peer->account());
}
Window::Controller *Application::windowFor(
not_null<Main::Account*> account) const {
if (const auto separate = separateWindowForAccount(account)) {
Window::Controller *Application::windowFor(Window::SeparateId id) const {
if (const auto separate = separateWindowFor(id)) {
return separate;
} else if (id && id.primary()) {
return windowFor(not_null(id.account));
}
return activePrimaryWindow();
}
Window::Controller *Application::windowForShowingHistory(
not_null<PeerData*> peer) const {
if (const auto separate = separateWindowFor(peer)) {
return separate;
}
auto result = (Window::Controller*)nullptr;
enumerateWindows([&](not_null<Window::Controller*> window) {
if (const auto controller = window->sessionController()) {
const auto current = controller->activeChatCurrent();
if (const auto history = current.history()) {
if (history->peer == peer) {
result = window;
}
}
}
});
return result;
}
Window::Controller *Application::windowForShowingForum(
not_null<Data::Forum*> forum) const {
const auto id = Window::SeparateId(
Window::SeparateType::Forum,
forum->history());
if (const auto separate = separateWindowFor(id)) {
return separate;
}
auto result = (Window::Controller*)nullptr;
enumerateWindows([&](not_null<Window::Controller*> window) {
if (const auto controller = window->sessionController()) {
const auto current = controller->shownForum().current();
if (forum == current) {
result = window;
}
}
});
return result;
}
Window::Controller *Application::findWindow(
not_null<QWidget*> widget) const {
const auto window = widget->window();
if (_lastActiveWindow && _lastActiveWindow->widget() == window) {
return _lastActiveWindow;
}
for (const auto &[account, primary] : _primaryWindows) {
if (primary->widget() == window) {
return primary.get();
}
}
for (const auto &[history, secondary] : _secondaryWindows) {
if (secondary->widget() == window) {
return secondary.get();
for (const auto &[id, controller] : _windows) {
if (controller->widget() == window) {
return controller.get();
}
}
return nullptr;
@ -1392,10 +1387,11 @@ Window::Controller *Application::activeWindow() const {
bool Application::closeNonLastAsync(not_null<Window::Controller*> window) {
const auto hasOther = [&] {
for (const auto &[account, primary] : _primaryWindows) {
if (!_closingAsyncWindows.contains(primary.get())
&& primary.get() != window
&& primary->maybeSession()) {
for (const auto &[id, controller] : _windows) {
if (id.primary()
&& !_closingAsyncWindows.contains(controller.get())
&& controller.get() != window
&& controller->maybeSession()) {
return true;
}
}
@ -1457,10 +1453,10 @@ void Application::closeWindow(not_null<Window::Controller*> window) {
: nullptr;
const auto next = nextFromStack
? nextFromStack
: (_primaryWindows.front().second.get() != window)
? _primaryWindows.front().second.get()
: (_primaryWindows.back().second.get() != window)
? _primaryWindows.back().second.get()
: (_windows.front().second.get() != window)
? _windows.front().second.get()
: (_windows.back().second.get() != window)
? _windows.back().second.get()
: nullptr;
Assert(next != window);
@ -1481,20 +1477,12 @@ void Application::closeWindow(not_null<Window::Controller*> window) {
}
}
_closingAsyncWindows.remove(window);
for (auto i = begin(_primaryWindows); i != end(_primaryWindows);) {
for (auto i = begin(_windows); i != end(_windows);) {
if (i->second.get() == window) {
Assert(_lastActiveWindow != window);
Assert(_lastActivePrimaryWindow != window);
Assert(_windowInSettings != window);
i = _primaryWindows.erase(i);
} else {
++i;
}
}
for (auto i = begin(_secondaryWindows); i != end(_secondaryWindows);) {
if (i->second.get() == window) {
Assert(_lastActiveWindow != window);
i = _secondaryWindows.erase(i);
i = _windows.erase(i);
} else {
++i;
}
@ -1502,36 +1490,34 @@ void Application::closeWindow(not_null<Window::Controller*> window) {
const auto account = domain().started()
? &domain().active()
: nullptr;
if (account && !_primaryWindows.contains(account) && _lastActiveWindow) {
if (account
&& !_windows.contains(Window::SeparateId(account))
&& _lastActiveWindow) {
domain().activate(&_lastActiveWindow->account());
}
}
void Application::closeChatFromWindows(not_null<PeerData*> peer) {
if (const auto window = windowFor(peer)
; window && !window->isPrimary()) {
closeWindow(window);
}
for (const auto &[history, window] : _secondaryWindows) {
if (const auto session = window->sessionController()) {
if (session->activeChatCurrent().peer() == peer) {
session->showPeerHistory(
window->singlePeer()->id,
Window::SectionShow::Way::ClearStack);
}
}
}
if (const auto window = windowFor(&peer->account())) {
if (const auto primary = window->sessionController()) {
if (primary->activeChatCurrent().peer() == peer) {
primary->clearSectionStack();
}
if (const auto forum = primary->shownForum().current()) {
if (peer->forum() == forum) {
primary->closeForum();
const auto closeOne = [&] {
for (const auto &[id, window] : _windows) {
if (id.thread && id.thread->peer() == peer) {
closeWindow(window.get());
return true;
} else if (const auto controller = window->sessionController()) {
if (controller->activeChatCurrent().peer() == peer) {
controller->showByInitialId();
}
if (const auto forum = controller->shownForum().current()) {
if (peer->forum() == forum) {
controller->closeForum();
}
}
}
}
return false;
};
while (closeOne()) {
}
}
@ -1737,11 +1723,8 @@ void Application::quitPreventFinished() {
}
void Application::quitDelayed() {
for (const auto &[account, window] : _primaryWindows) {
window->widget()->hide();
}
for (const auto &[history, window] : _secondaryWindows) {
window->widget()->hide();
for (const auto &[id, controller] : _windows) {
controller->widget()->hide();
}
if (!_private->quitTimer.isActive()) {
_private->quitTimer.setCallback([] { Sandbox::QuitWhenStarted(); });

View file

@ -7,9 +7,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "base/timer.h"
#include "mtproto/mtproto_auth_key.h"
#include "mtproto/mtproto_proxy_data.h"
#include "base/timer.h"
#include "window/window_separate_id.h"
class History;
@ -29,11 +30,9 @@ namespace Window {
class Controller;
} // namespace Window
namespace Window {
namespace Notifications {
namespace Window::Notifications {
class System;
} // namespace Notifications
} // namespace Window
} // namespace Window::Notifications
namespace ChatHelpers {
class EmojiKeywords;
@ -170,19 +169,17 @@ public:
not_null<QWidget*> widget) const;
[[nodiscard]] Window::Controller *activeWindow() const;
[[nodiscard]] Window::Controller *activePrimaryWindow() const;
[[nodiscard]] Window::Controller *separateWindowForAccount(
not_null<Main::Account*> account) const;
[[nodiscard]] Window::Controller *separateWindowForPeer(
not_null<PeerData*> peer) const;
Window::Controller *ensureSeparateWindowForPeer(
not_null<PeerData*> peer,
MsgId showAtMsgId);
Window::Controller *ensureSeparateWindowForAccount(
not_null<Main::Account*> account);
[[nodiscard]] Window::Controller *separateWindowFor(
Window::SeparateId id) const;
Window::Controller *ensureSeparateWindowFor(
Window::SeparateId id,
MsgId showAtMsgId = 0);
[[nodiscard]] Window::Controller *windowFor( // Doesn't auto-switch.
Window::SeparateId id) const;
[[nodiscard]] Window::Controller *windowForShowingHistory(
not_null<PeerData*> peer) const;
[[nodiscard]] Window::Controller *windowFor( // Doesn't auto-switch.
not_null<Main::Account*> account) const;
[[nodiscard]] Window::Controller *windowForShowingForum(
not_null<Data::Forum*> forum) const;
[[nodiscard]] bool closeNonLastAsync(
not_null<Window::Controller*> window);
void closeWindow(not_null<Window::Controller*> window);
@ -195,7 +192,7 @@ public:
void checkSystemDarkMode();
[[nodiscard]] bool isActiveForTrayMenu() const;
void closeChatFromWindows(not_null<PeerData*> peer);
void checkWindowAccount(not_null<Window::Controller*> window);
void checkWindowId(not_null<Window::Controller*> window);
void activate();
// Media view interface.
@ -423,12 +420,9 @@ private:
const std::unique_ptr<Calls::Instance> _calls;
const std::unique_ptr<Iv::Instance> _iv;
base::flat_map<
Main::Account*,
std::unique_ptr<Window::Controller>> _primaryWindows;
Window::SeparateId,
std::unique_ptr<Window::Controller>> _windows;
base::flat_set<not_null<Window::Controller*>> _closingAsyncWindows;
base::flat_map<
not_null<History*>,
std::unique_ptr<Window::Controller>> _secondaryWindows;
std::vector<not_null<Window::Controller*>> _windowStack;
Window::Controller *_lastActiveWindow = nullptr;
Window::Controller *_lastActivePrimaryWindow = nullptr;

View file

@ -531,7 +531,7 @@ void DownloadManager::loadingStopWithConfirmation(
return;
}
const auto window = Core::App().windowFor(
&item->history()->session().account());
not_null(&item->history()->session().account()));
if (!window) {
return;
}

View file

@ -3676,7 +3676,7 @@ void InnerWidget::preloadRowsData() {
}
}
bool InnerWidget::chooseCollapsedRow() {
bool InnerWidget::chooseCollapsedRow(Qt::KeyboardModifiers modifiers) {
if (_state != WidgetState::Default) {
return false;
} else if ((_collapsedSelected < 0)
@ -3769,7 +3769,15 @@ bool InnerWidget::chooseHashtag() {
ChosenRow InnerWidget::computeChosenRow() const {
if (_state == WidgetState::Default) {
if (_selected) {
if ((_collapsedSelected >= 0)
&& (_collapsedSelected < _collapsedRows.size())) {
const auto &row = _collapsedRows[_collapsedSelected];
Assert(row->folder != nullptr);
return {
.key = row->folder,
.message = Data::UnreadMessagePosition,
};
} else if (_selected) {
return {
.key = _selected->key(),
.message = Data::UnreadMessagePosition,
@ -3813,9 +3821,7 @@ bool InnerWidget::isUserpicPressOnWide() const {
bool InnerWidget::chooseRow(
Qt::KeyboardModifiers modifiers,
MsgId pressedTopicRootId) {
if (chooseCollapsedRow()) {
return true;
} else if (chooseHashtag()) {
if (chooseHashtag()) {
return true;
}
const auto modifyChosenRow = [&](

View file

@ -252,7 +252,7 @@ private:
void repaintCollapsedFolderRow(not_null<Data::Folder*> folder);
void refreshWithCollapsedRows(bool toTop = false);
bool needCollapsedRowsRefresh() const;
bool chooseCollapsedRow();
bool chooseCollapsedRow(Qt::KeyboardModifiers modifiers);
void switchToFilter(FilterId filterId);
bool chooseHashtag();
ChosenRow computeChosenRow() const;

View file

@ -562,6 +562,8 @@ void Widget::chosenRow(const ChosenRow &row) {
if (topicJump) {
if (controller()->shownForum().current() == topicJump->forum()) {
controller()->closeForum();
} else if (row.newWindow) {
controller()->showInNewWindow(Window::SeparateId(topicJump));
} else {
if (!controller()->adaptive().isOneColumn()) {
controller()->showForum(
@ -575,11 +577,17 @@ void Widget::chosenRow(const ChosenRow &row) {
}
return;
} else if (const auto topic = row.key.topic()) {
session().data().saveViewAsMessages(topic->forum(), false);
controller()->showThread(
topic,
row.message.fullId.msg,
Window::SectionShow::Way::ClearStack);
if (row.newWindow) {
controller()->showInNewWindow(
Window::SeparateId(topic),
row.message.fullId.msg);
} else {
session().data().saveViewAsMessages(topic->forum(), false);
controller()->showThread(
topic,
row.message.fullId.msg,
Window::SectionShow::Way::ClearStack);
}
} else if (history
&& row.userpicClick
&& (row.message.fullId.msg == ShowAtUnreadMsgId)
@ -595,16 +603,19 @@ void Widget::chosenRow(const ChosenRow &row) {
const auto forum = history->peer->forum();
if (controller()->shownForum().current() == forum) {
controller()->closeForum();
return;
}
controller()->showForum(
forum,
Window::SectionShow().withChildColumn());
if (forum->channel()->viewForumAsMessages()) {
controller()->showThread(
history,
ShowAtUnreadMsgId,
Window::SectionShow::Way::ClearStack);
} else if (row.newWindow) {
controller()->showInNewWindow(
Window::SeparateId(Window::SeparateType::Forum, history));
} else {
controller()->showForum(
forum,
Window::SectionShow().withChildColumn());
if (forum->channel()->viewForumAsMessages()) {
controller()->showThread(
history,
ShowAtUnreadMsgId,
Window::SectionShow::Way::ClearStack);
}
}
return;
} else if (history) {
@ -630,6 +641,12 @@ void Widget::chosenRow(const ChosenRow &row) {
return;
}
}
if (row.newWindow) {
controller()->showInNewWindow(Window::SeparateId(
Window::SeparateType::Archive,
&session()));
return;
}
controller()->openFolder(folder);
hideChildList();
}
@ -1847,13 +1864,21 @@ void Widget::slideFinished() {
void Widget::escape() {
if (!cancelSearch({ .jumpBackToSearchedChat = true })) {
if (controller()->shownForum().current()) {
controller()->closeForum();
if (const auto forum = controller()->shownForum().current()) {
const auto id = controller()->windowId();
const auto initial = id.forum();
if (!initial) {
controller()->closeForum();
} else if (initial != forum) {
controller()->showForum(initial);
}
} else if (controller()->openedFolder().current()) {
controller()->closeFolder();
if (!controller()->windowId().folder()) {
controller()->closeFolder();
}
} else if (controller()->activeChatEntryCurrent().key) {
controller()->content()->dialogsCancelled();
} else {
} else if (controller()->isPrimary()) {
const auto filters = &session().data().chatsFilters();
const auto &list = filters->list();
const auto first = list.empty() ? FilterId() : list.front().id();
@ -2704,6 +2729,9 @@ void Widget::updateForceDisplayWide() {
void Widget::showForum(
not_null<Data::Forum*> forum,
const Window::SectionShow &params) {
if (_openedForum == forum) {
return;
}
const auto nochat = !controller()->mainSectionShown();
if (!params.childColumn
|| (Core::App().settings().dialogsWidthRatio(nochat) == 0.)

View file

@ -57,6 +57,7 @@ namespace Window {
class SessionController;
class ConnectionState;
struct SectionShow;
struct SeparateId;
} // namespace Window
namespace Dialogs::Stories {

View file

@ -41,6 +41,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/dynamic_thumbnails.h"
#include "ui/painter.h"
#include "ui/unread_badge_paint.h"
#include "window/window_separate_id.h"
#include "window/window_session_controller.h"
#include "window/window_peer_menu.h"
#include "styles/style_chat.h"

View file

@ -317,7 +317,7 @@ ClickHandlerPtr JumpToMessageClickHandler(
TextWithEntities highlightPart,
int highlightPartOffsetHint) {
return std::make_shared<LambdaClickHandler>([=] {
const auto separate = Core::App().separateWindowForPeer(peer);
const auto separate = Core::App().separateWindowFor(peer);
const auto controller = separate
? separate->sessionController()
: peer->session().tryResolveWindow();
@ -347,7 +347,7 @@ ClickHandlerPtr JumpToStoryClickHandler(
not_null<PeerData*> peer,
StoryId storyId) {
return std::make_shared<LambdaClickHandler>([=] {
const auto separate = Core::App().separateWindowForPeer(peer);
const auto separate = Core::App().separateWindowFor(peer);
const auto controller = separate
? separate->sessionController()
: peer->session().tryResolveWindow();

View file

@ -823,7 +823,7 @@ HistoryWidget::HistoryWidget(
if (flags & PeerUpdateFlag::UnavailableReason) {
const auto unavailable = _peer->computeUnavailableReason();
if (!unavailable.isEmpty()) {
const auto account = &_peer->account();
const auto account = not_null(&_peer->account());
closeCurrent();
if (const auto primary = Core::App().windowFor(account)) {
primary->showToast(unavailable);
@ -3342,7 +3342,8 @@ void HistoryWidget::messagesFailed(const MTP::Error &error, int requestId) {
|| error.type() == u"USER_BANNED_IN_CHANNEL"_q) {
auto was = _peer;
closeCurrent();
if (const auto primary = Core::App().windowFor(&was->account())) {
const auto wasAccount = not_null(&was->account());
if (const auto primary = Core::App().windowFor(wasAccount)) {
primary->showToast((was && was->isMegagroup())
? tr::lng_group_not_accessible(tr::now)
: tr::lng_channel_not_accessible(tr::now));
@ -4974,8 +4975,8 @@ bool HistoryWidget::updateCmdStartShown() {
}
bool HistoryWidget::searchInChatEmbedded(Dialogs::Key chat, QString query) {
const auto peer = chat.peer();
if (!peer || peer != controller()->singlePeer()) {
const auto peer = chat.peer(); // windows todo
if (!peer || Window::SeparateId(peer) != controller()->windowId()) {
return false;
} else if (_peer != peer) {
const auto weak = Ui::MakeWeak(this);

View file

@ -44,6 +44,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_peer_values.h"
#include "data/data_group_call.h" // GroupCall::input.
#include "data/data_folder.h"
#include "data/data_forum.h"
#include "data/data_saved_sublist.h"
#include "data/data_session.h"
#include "data/data_stories.h"
@ -714,10 +715,13 @@ void TopBarWidget::mousePressEvent(QMouseEvent *e) {
&& !showSelectedState()
&& !_chooseForReportReason;
if (handleClick) {
const auto archiveTop = (_activeChat.section == Section::ChatsList)
&& _activeChat.key.folder();
if ((_animatingMode && _back->rect().contains(e->pos()))
|| (_activeChat.section == Section::ChatsList
&& _activeChat.key.folder())) {
backClicked();
|| archiveTop) {
if (!rootChatsListBar()) {
backClicked();
}
} else {
infoClicked();
}
@ -890,9 +894,22 @@ void TopBarWidget::setCustomTitle(const QString &title) {
}
}
bool TopBarWidget::rootChatsListBar() const {
if (_activeChat.section != Section::ChatsList) {
return false;
}
const auto id = _controller->windowId();
const auto separateFolder = id.folder();
const auto separateForum = id.forum();
const auto active = _activeChat.key;
return (separateForum && separateForum->history() == active.history())
|| (separateFolder && separateFolder == active.folder());
}
void TopBarWidget::refreshInfoButton() {
if (_activeChat.key.topic()
|| _activeChat.section == Section::ChatsList) {
|| (_activeChat.section == Section::ChatsList
&& !rootChatsListBar())) {
_info.destroy();
} else if (const auto peer = _activeChat.key.peer()) {
auto info = object_ptr<Ui::UserpicButton>(
@ -989,6 +1006,14 @@ void TopBarWidget::updateControlsGeometry() {
_leftTaken += _back->width();
}
if (_info && !_info->isHidden()) {
if (_back->isHidden() && _narrowRatio > 0.) {
const auto &infoSt = st::topBarInfoButton;
const auto middle = (_narrowWidth - infoSt.photoSize) / 2;
_leftTaken = anim::interpolate(
_leftTaken,
middle - infoSt.photoPosition.x(),
_narrowRatio);
}
_info->moveToLeft(_leftTaken, otherButtonsTop);
_leftTaken += _info->width();
} else if (_activeChat.key.topic()
@ -997,7 +1022,9 @@ void TopBarWidget::updateControlsGeometry() {
}
if (_searchField) {
const auto fieldLeft = _leftTaken;
const auto fieldLeft = _back->isHidden()
? st::topBarArrowPadding.right()
: _leftTaken;
const auto fieldTop = searchFieldTop
+ (height() - _searchField->height()) / 2;
const auto fieldRight = st::dialogsFilterSkip
@ -1075,9 +1102,10 @@ void TopBarWidget::updateControlsVisibility() {
_sendNow->setVisible(_canSendNow);
const auto isOneColumn = _controller->adaptive().isOneColumn();
auto backVisible = isOneColumn
|| !_controller->content()->stackIsEmpty()
|| (_activeChat.section == Section::ChatsList);
const auto backVisible = !rootChatsListBar()
&& (isOneColumn
|| (_activeChat.section == Section::ChatsList)
|| !_controller->content()->stackIsEmpty());
_back->setVisible(backVisible && !_chooseForReportReason);
_cancelChoose->setVisible(_chooseForReportReason.has_value());
if (_info) {
@ -1085,7 +1113,8 @@ void TopBarWidget::updateControlsVisibility() {
&& (isOneColumn || !_primaryWindow));
}
if (_unreadBadge) {
_unreadBadge->setVisible(!_chooseForReportReason);
_unreadBadge->setVisible(!_chooseForReportReason
&& !rootChatsListBar());
}
const auto topic = _activeChat.key.topic();
const auto section = _activeChat.section;

View file

@ -131,6 +131,7 @@ protected:
private:
struct EmojiInteractionSeenAnimation;
[[nodiscard]] bool rootChatsListBar() const;
void refreshInfoButton();
void refreshLang();
void updateSearchVisibility();

View file

@ -318,8 +318,8 @@ not_null<Main::Account*> Domain::add(MTP::Environment environment) {
void Domain::addActivated(MTP::Environment environment, bool newWindow) {
const auto added = [&](not_null<Main::Account*> account) {
if (newWindow) {
Core::App().ensureSeparateWindowForAccount(account);
} else if (const auto window = Core::App().separateWindowForAccount(
Core::App().ensureSeparateWindowFor(account);
} else if (const auto window = Core::App().separateWindowFor(
account)) {
window->activate();
} else {
@ -371,11 +371,11 @@ void Domain::watchSession(not_null<Account*> account) {
void Domain::closeAccountWindows(not_null<Main::Account*> account) {
auto another = (Main::Account*)nullptr;
for (auto i = _accounts.begin(); i != _accounts.end(); ++i) {
const auto other = i->account.get();
const auto other = not_null(i->account.get());
if (other == account) {
continue;
} else if (Core::App().separateWindowForAccount(other)) {
const auto that = Core::App().separateWindowForAccount(account);
} else if (Core::App().separateWindowFor(other)) {
const auto that = Core::App().separateWindowFor(account);
if (that) {
that->close();
}
@ -411,7 +411,7 @@ void Domain::removeRedundantAccounts() {
const auto was = _accounts.size();
for (auto i = _accounts.begin(); i != _accounts.end();) {
if (Core::App().separateWindowForAccount(i->account.get())
if (Core::App().separateWindowFor(not_null(i->account.get()))
|| i->account->sessionExists()) {
++i;
continue;
@ -442,7 +442,7 @@ void Domain::checkForLastProductionConfig(
}
void Domain::maybeActivate(not_null<Main::Account*> account) {
if (Core::App().separateWindowForAccount(account)) {
if (Core::App().separateWindowFor(account)) {
activate(account);
} else {
Core::App().preventOrInvoke(crl::guard(account, [=] {
@ -452,7 +452,7 @@ void Domain::maybeActivate(not_null<Main::Account*> account) {
}
void Domain::activate(not_null<Main::Account*> account) {
if (const auto window = Core::App().separateWindowForAccount(account)) {
if (const auto window = Core::App().separateWindowFor(account)) {
window->activate();
}
if (_active.current() == account.get()) {

View file

@ -497,7 +497,8 @@ Window::SessionController *Session::tryResolveWindow(
if (forPeer) {
auto primary = (Window::SessionController*)nullptr;
for (const auto &window : _windows) {
if (window->singlePeer() == forPeer) {
const auto thread = window->windowId().thread;
if (thread && thread->peer() == forPeer) {
return window;
} else if (window->isPrimary()) {
primary = window;

View file

@ -37,6 +37,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "window/window_connecting_widget.h"
#include "window/window_top_bar_wrap.h"
#include "window/notifications_manager.h"
#include "window/window_separate_id.h"
#include "window/window_slide_animation.h"
#include "window/window_history_hider.h"
#include "window/window_controller.h"
@ -232,19 +233,19 @@ MainWidget::MainWidget(
, _controller(controller)
, _dialogsWidth(st::columnMinimalWidthLeft)
, _thirdColumnWidth(st::columnMinimalWidthThird)
, _sideShadow(isPrimary()
? base::make_unique_q<Ui::PlainShadow>(this)
: nullptr)
, _dialogs(isPrimary()
, _dialogs(windowId().hasChatsList()
? base::make_unique_q<Dialogs::Widget>(
this,
_controller,
Dialogs::Widget::Layout::Main)
: nullptr)
, _history(std::in_place, this, _controller)
, _sideShadow(_dialogs
? base::make_unique_q<Ui::PlainShadow>(this)
: nullptr)
, _playerPlaylist(this, _controller)
, _changelogs(Core::Changelogs::Create(&controller->session())) {
if (isPrimary()) {
if (_dialogs) {
setupConnectingWidget();
}
@ -732,7 +733,7 @@ void MainWidget::hideSingleUseKeyboard(FullMsgId replyToId) {
void MainWidget::searchMessages(const QString &query, Dialogs::Key inChat) {
auto tags = Data::SearchTagsFromQuery(query);
if (controller()->isPrimary()) {
if (_dialogs) {
auto state = Dialogs::SearchState{
.inChat = ((tags.empty() || inChat.sublist())
? inChat
@ -758,7 +759,7 @@ void MainWidget::searchMessages(const QString &query, Dialogs::Key inChat) {
if ((!_mainSection
|| !_mainSection->searchInChatEmbedded(inChat, query))
&& !_history->searchInChatEmbedded(inChat, query)) {
const auto account = &session().account();
const auto account = not_null(&session().account());
if (const auto window = Core::App().windowFor(account)) {
if (const auto controller = window->sessionController()) {
controller->content()->searchMessages(query, inChat);
@ -1238,36 +1239,35 @@ bool MainWidget::showHistoryInDifferentWindow(
PeerId peerId,
const SectionShow &params,
MsgId showAtMsgId) {
if (!peerId) {
return false;
}
const auto peer = session().data().peer(peerId);
const auto account = &session().account();
auto primary = Core::App().separateWindowForAccount(account);
if (const auto separate = Core::App().separateWindowForPeer(peer)) {
if (separate == &_controller->window()) {
return false;
if (const auto separateChat = _controller->windowId().chat()) {
if (const auto history = separateChat->asHistory()) {
if (history->peer == peer) {
return false;
}
}
separate->sessionController()->showPeerHistory(
}
const auto window = Core::App().windowForShowingHistory(peer);
if (window == &_controller->window()) {
return false;
} else if (window) {
window->sessionController()->showPeerHistory(
peerId,
params,
showAtMsgId);
separate->activate();
window->activate();
return true;
} else if (isPrimary()) {
if (primary && primary != &_controller->window()) {
primary->sessionController()->showPeerHistory(
peerId,
params,
showAtMsgId);
primary->activate();
return true;
}
} else if (windowId().hasChatsList()) {
return false;
} else if (!peerId) {
return true;
} else if (singlePeer()->id == peerId) {
return false;
} else if (!primary) {
}
const auto account = not_null(&session().account());
auto primary = Core::App().separateWindowFor(account);
if (!primary) {
Core::App().domain().activate(account);
primary = Core::App().separateWindowForAccount(account);
primary = Core::App().separateWindowFor(account);
}
if (primary && &primary->account() == account) {
primary->sessionController()->showPeerHistory(
@ -1293,7 +1293,7 @@ void MainWidget::showHistory(
}
const auto unavailable = peer->computeUnavailableReason();
if (!unavailable.isEmpty()) {
Assert(isPrimary());
Assert(isPrimary()); // windows todo
if (params.activation != anim::activation::background) {
_controller->show(Ui::MakeInformBox(unavailable));
_controller->window().activate();
@ -1510,7 +1510,7 @@ void MainWidget::showMessage(
void MainWidget::showForum(
not_null<Data::Forum*> forum,
const SectionShow &params) {
Expects(isPrimary() || (singlePeer() && singlePeer()->forum() == forum));
Expects(_dialogs != nullptr);
_dialogs->showForum(forum, params);
@ -1846,8 +1846,8 @@ void MainWidget::checkMainSectionToLayer() {
updateMainSectionShown();
}
PeerData *MainWidget::singlePeer() const {
return _controller->singlePeer();
Window::SeparateId MainWidget::windowId() const {
return _controller->windowId();
}
bool MainWidget::isPrimary() const {
@ -1957,7 +1957,7 @@ void MainWidget::showBackFromStack(
}
if (_stack.empty()) {
if (isPrimary()) {
if (_dialogs) {
_controller->clearSectionStack(params);
}
crl::on_main(this, [=] {

View file

@ -90,6 +90,7 @@ struct SectionSlideParams;
struct SectionShow;
enum class Column;
class HistoryHider;
struct SeparateId;
} // namespace Window
namespace Calls {
@ -121,7 +122,7 @@ public:
[[nodiscard]] Main::Session &session() const;
[[nodiscard]] not_null<Window::SessionController*> controller() const;
[[nodiscard]] PeerData *singlePeer() const;
[[nodiscard]] Window::SeparateId windowId() const;
[[nodiscard]] bool isPrimary() const;
[[nodiscard]] bool isMainSectionShown() const;
[[nodiscard]] bool isThirdSectionShown() const;
@ -350,10 +351,6 @@ private:
int _thirdColumnWidth = 0;
Ui::Animations::Simple _a_dialogsWidth;
const base::unique_qptr<Ui::PlainShadow> _sideShadow;
object_ptr<Ui::PlainShadow> _thirdShadow = { nullptr };
object_ptr<Ui::ResizeArea> _firstColumnResizeArea = { nullptr };
object_ptr<Ui::ResizeArea> _thirdColumnResizeArea = { nullptr };
const base::unique_qptr<Dialogs::Widget> _dialogs;
const base::unique_qptr<HistoryWidget> _history;
object_ptr<Window::SectionWidget> _mainSection = { nullptr };
@ -361,6 +358,11 @@ private:
std::shared_ptr<Window::SectionMemento> _thirdSectionFromStack;
std::unique_ptr<Window::ConnectionState> _connecting;
const base::unique_qptr<Ui::PlainShadow> _sideShadow;
object_ptr<Ui::PlainShadow> _thirdShadow = { nullptr };
object_ptr<Ui::ResizeArea> _firstColumnResizeArea = { nullptr };
object_ptr<Ui::ResizeArea> _thirdColumnResizeArea = { nullptr };
base::weak_ptr<Calls::Call> _currentCall;
base::weak_ptr<Calls::GroupCall> _currentGroupCall;
rpl::lifetime _currentCallLifetime;

View file

@ -269,13 +269,11 @@ void MainWindow::setupMain(
auto created = object_ptr<MainWidget>(bodyWidget(), sessionController());
clearWidgets();
_main = std::move(created);
if (const auto peer = singlePeer()) {
updateControlsGeometry();
_main->controller()->showPeerHistory(
peer,
Window::SectionShow::Way::ClearStack,
singlePeerShowAtMsgId);
}
updateControlsGeometry();
Ui::SendPendingMoveResizeEvents(_main);
_main->controller()->showByInitialId(
Window::SectionShow::Way::ClearStack,
singlePeerShowAtMsgId);
if (_passcodeLock) {
_main->hide();
} else {

View file

@ -6158,7 +6158,7 @@ Window::SessionController *OverlayWidget::findWindow(bool switchTo) const {
if (switchTo) {
auto controllerPtr = (Window::SessionController*)nullptr;
const auto account = &_session->account();
const auto account = not_null(&_session->account());
const auto sessionWindow = Core::App().windowFor(account);
const auto anyWindow = (sessionWindow
&& &sessionWindow->account() == account)

View file

@ -983,13 +983,13 @@ void AccountsList::rebuild() {
_reorder->finishReordering();
if (newWindow) {
_closeRequests.fire({});
Core::App().ensureSeparateWindowForAccount(
account);
Core::App().ensureSeparateWindowFor(account);
}
Core::App().domain().maybeActivate(account);
}
};
if (const auto window = Core::App().separateWindowForAccount(account)) {
if (const auto window = Core::App().separateWindowFor(
account)) {
_closeRequests.fire({});
window->activate();
} else {

View file

@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/platform/ui_platform_window.h"
#include "platform/platform_window_title.h"
#include "history/history.h"
#include "window/window_separate_id.h"
#include "window/window_session_controller.h"
#include "window/window_lock_widgets.h"
#include "window/window_controller.h"
@ -387,8 +388,8 @@ Main::Account &MainWindow::account() const {
return _controller->account();
}
PeerData *MainWindow::singlePeer() const {
return _controller->singlePeer();
Window::SeparateId MainWindow::id() const {
return _controller->id();
}
bool MainWindow::isPrimary() const {
@ -602,20 +603,27 @@ WindowPosition MainWindow::initialPosition() const {
? Core::AdjustToScale(
Core::App().settings().windowPosition(),
u"Window"_q)
: active->widget()->nextInitialChildPosition(isPrimary());
: active->widget()->nextInitialChildPosition(id());
}
WindowPosition MainWindow::nextInitialChildPosition(bool primary) {
WindowPosition MainWindow::nextInitialChildPosition(SeparateId childId) {
const auto rect = geometry().marginsRemoved(frameMargins());
const auto position = rect.topLeft();
const auto adjust = [&](int value) {
return primary ? value : (value * 3 / 4);
return (value * 3 / 4);
};
const auto secondaryWithChatsList = !childId.primary() && childId.hasChatsList();
const auto width = OptionNewWindowsSizeAsFirst.value()
? Core::App().settings().windowPosition().w
: childId.primary()
? st::windowDefaultWidth
: childId.hasChatsList()
? (st::columnMinimalWidthLeft + adjust(st::windowDefaultWidth))
: adjust(st::windowDefaultWidth);
const auto height = OptionNewWindowsSizeAsFirst.value()
? Core::App().settings().windowPosition().h
: childId.primary()
? st::windowDefaultHeight
: adjust(st::windowDefaultHeight);
const auto skip = ChildSkip();
const auto delta = _lastChildIndex

View file

@ -33,6 +33,7 @@ class Controller;
class SessionController;
class TitleWidget;
struct TermsLock;
struct SeparateId;
[[nodiscard]] const QImage &Logo();
[[nodiscard]] const QImage &LogoNoMargin();
@ -66,7 +67,7 @@ public:
[[nodiscard]] Window::Controller &controller() const {
return *_controller;
}
[[nodiscard]] PeerData *singlePeer() const;
[[nodiscard]] Window::SeparateId id() const;
[[nodiscard]] bool isPrimary() const;
[[nodiscard]] Main::Account &account() const;
[[nodiscard]] Window::SessionController *sessionController() const;
@ -200,7 +201,7 @@ private:
[[nodiscard]] Core::WindowPosition initialPosition() const;
[[nodiscard]] Core::WindowPosition nextInitialChildPosition(
bool primary);
SeparateId childId);
[[nodiscard]] QRect countInitialGeometry(Core::WindowPosition position);
bool computeIsActive() const;

View file

@ -1096,7 +1096,7 @@ void Manager::openNotificationMessage(
&& item->isRegular()
&& (item->out() || (item->mentionsMe() && !history->peer->isUser()));
const auto topic = item ? item->topic() : nullptr;
const auto separate = Core::App().separateWindowForPeer(history->peer);
const auto separate = Core::App().separateWindowFor(history->peer);
const auto window = separate
? separate->sessionController()
: history->session().tryResolveWindow();

View file

@ -28,7 +28,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "window/window_session_controller.h"
#include "window/themes/window_theme_editor.h"
#include "ui/boxes/confirm_box.h"
#include "data/data_peer.h"
#include "data/data_thread.h"
#include "apiwrap.h" // ApiWrap::acceptTerms.
#include "styles/style_layers.h"
@ -93,23 +93,18 @@ Show::operator bool() const {
} // namespace
Controller::Controller() : Controller(CreateArgs{}) {
Controller::Controller() : Controller(CreateArgs{ nullptr }) {
}
Controller::Controller(not_null<Main::Account*> account)
: Controller(CreateArgs{}) {
showAccount(account);
}
Controller::Controller(
not_null<PeerData*> singlePeer,
MsgId showAtMsgId)
: Controller(CreateArgs{ singlePeer.get() }) {
showAccount(&singlePeer->account(), showAtMsgId);
Controller::Controller(SeparateId id, MsgId showAtMsgId)
: Controller(CreateArgs{ id }) {
if (id) {
showAccount(id.account, showAtMsgId);
}
}
Controller::Controller(CreateArgs &&args)
: _singlePeer(args.singlePeer)
: _id(args.id)
, _isActiveTimer([=] { updateIsActive(); })
, _widget(this)
, _adaptive(std::make_unique<Adaptive>()) {
@ -125,6 +120,20 @@ Controller::~Controller() {
_sessionController = nullptr;
}
SeparateId Controller::id() const {
return _id;
}
bool Controller::isPrimary() const {
return _id.primary();
}
Main::Account &Controller::account() const {
Expects(_id.account != nullptr);
return *_id.account;
}
void Controller::showAccount(not_null<Main::Account*> account) {
showAccount(account, ShowAtUnreadMsgId);
}
@ -132,20 +141,22 @@ void Controller::showAccount(not_null<Main::Account*> account) {
void Controller::showAccount(
not_null<Main::Account*> account,
MsgId singlePeerShowAtMsgId) {
Expects(isPrimary() || &_singlePeer->account() == account);
Expects(isPrimary() || _id.account == account);
const auto prevSessionUniqueId = (_account && _account->sessionExists())
? _account->session().uniqueId()
const auto prevAccount = _id.account;
const auto prevSession = maybeSession();
const auto prevSessionUniqueId = prevSession
? prevSession->uniqueId()
: 0;
_accountLifetime.destroy();
_account = account;
Core::App().checkWindowAccount(this);
_id.account = account;
Core::App().checkWindowId(this);
const auto updateOnlineOfPrevSesssion = crl::guard(_account, [=] {
const auto updateOnlineOfPrevSesssion = crl::guard(account, [=] {
if (!prevSessionUniqueId) {
return;
}
for (auto &[index, account] : _account->domain().accounts()) {
for (auto &[index, account] : _id.account->domain().accounts()) {
if (const auto anotherSession = account->maybeSession()) {
if (anotherSession->uniqueId() == prevSessionUniqueId) {
anotherSession->updates().updateOnline(crl::now());
@ -155,12 +166,15 @@ void Controller::showAccount(
}
});
_account->sessionValue(
) | rpl::start_with_next([=](Main::Session *session) {
if (!isPrimary() && (&_singlePeer->session() != session)) {
if (!isPrimary()) {
_id.account->sessionChanges(
) | rpl::start_with_next([=](Main::Session *session) {
Core::App().closeWindow(this);
return;
}
}, _accountLifetime);
}
_id.account->sessionValue(
) | rpl::start_with_next([=](Main::Session *session) {
const auto was = base::take(_sessionController);
_sessionController = session
? std::make_unique<SessionController>(session, this)
@ -205,10 +219,6 @@ void Controller::showAccount(
}, _accountLifetime);
}
PeerData *Controller::singlePeer() const {
return _singlePeer;
}
void Controller::setupSideBar() {
Expects(_sessionController != nullptr);
@ -321,7 +331,7 @@ void Controller::finishFirstShow() {
}
Main::Session *Controller::maybeSession() const {
return _account ? _account->maybeSession() : nullptr;
return _id.account ? _id.account->maybeSession() : nullptr;
}
auto Controller::sessionControllerValue() const
@ -356,7 +366,7 @@ void Controller::setupPasscodeLock() {
}
void Controller::clearPasscodeLock() {
if (!_account) {
if (!_id) {
showAccount(&Core::App().activeAccount());
} else {
_widget.clearPasscodeLock();
@ -482,7 +492,7 @@ void Controller::invokeForSessionController(
PeerData *singlePeer,
Fn<void(not_null<SessionController*>)> &&callback) {
const auto separateWindow = singlePeer
? Core::App().separateWindowForPeer(singlePeer)
? Core::App().separateWindowFor(not_null(singlePeer))
: nullptr;
const auto separateSession = separateWindow
? separateWindow->sessionController()
@ -490,7 +500,7 @@ void Controller::invokeForSessionController(
if (separateSession) {
return callback(separateSession);
}
_account->domain().activate(std::move(account));
_id.account->domain().activate(std::move(account));
if (_sessionController) {
callback(_sessionController.get());
}

View file

@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "mainwindow.h"
#include "window/window_adaptive.h"
#include "window/window_separate_id.h"
namespace Main {
class Account;
@ -36,32 +37,20 @@ namespace Window {
class Controller final : public base::has_weak_ptr {
public:
Controller();
explicit Controller(not_null<Main::Account*> account);
Controller(
not_null<PeerData*> singlePeer,
MsgId showAtMsgId);
Controller(SeparateId id, MsgId showAtMsgId);
~Controller();
Controller(const Controller &other) = delete;
Controller &operator=(const Controller &other) = delete;
void showAccount(not_null<Main::Account*> account);
[[nodiscard]] PeerData *singlePeer() const;
[[nodiscard]] bool isPrimary() const {
return (singlePeer() == nullptr);
}
[[nodiscard]] SeparateId id() const;
[[nodiscard]] bool isPrimary() const;
[[nodiscard]] not_null<::MainWindow*> widget() {
return &_widget;
}
[[nodiscard]] Main::Account &account() const {
Expects(_account != nullptr);
return *_account;
}
[[nodiscard]] Main::Account *maybeAccount() const {
return _account;
}
[[nodiscard]] Main::Account &account() const;
[[nodiscard]] Main::Session *maybeSession() const;
[[nodiscard]] SessionController *sessionController() const {
return _sessionController.get();
@ -155,7 +144,7 @@ public:
private:
struct CreateArgs {
PeerData *singlePeer = nullptr;
SeparateId id;
};
explicit Controller(CreateArgs &&args);
@ -173,8 +162,7 @@ private:
void showTermsDecline();
void showTermsDelete();
PeerData *_singlePeer = nullptr;
Main::Account *_account = nullptr;
SeparateId _id;
base::Timer _isActiveTimer;
::MainWindow _widget;
const std::unique_ptr<Adaptive> _adaptive;

View file

@ -47,6 +47,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/text/text_utilities.h"
#include "ui/unread_badge_paint.h"
#include "ui/vertical_list.h"
#include "ui/widgets/menu/menu_add_action_callback_factory.h"
#include "ui/widgets/popup_menu.h"
#include "ui/widgets/scroll_area.h"
#include "ui/widgets/shadow.h"
@ -551,9 +552,15 @@ void MainMenu::setupArchive() {
const auto folder = [=] {
return controller->session().data().folderLoaded(Data::Folder::kId);
};
const auto showArchive = [=] {
const auto showArchive = [=](Qt::KeyboardModifiers modifiers) {
if (const auto f = folder()) {
controller->openFolder(f);
if (modifiers & Qt::ControlModifier) {
controller->showInNewWindow(Window::SeparateId(
Window::SeparateType::Archive,
&controller->session()));
} else {
controller->openFolder(f);
}
controller->window().hideSettingsAndLayer();
}
};
@ -583,7 +590,7 @@ void MainMenu::setupArchive() {
button->clicks(
) | rpl::start_with_next([=](Qt::MouseButton which) {
if (which == Qt::LeftButton) {
showArchive();
showArchive(button->clickModifiers());
return;
} else if (which != Qt::RightButton) {
return;
@ -591,35 +598,13 @@ void MainMenu::setupArchive() {
_contextMenu = base::make_unique_q<Ui::PopupMenu>(
this,
st::popupMenuExpandedSeparator);
const auto addAction = PeerMenuCallback([&](
PeerMenuCallback::Args a) {
return _contextMenu->addAction(
a.text,
std::move(a.handler),
a.icon);
});
const auto hide = [=] {
controller->session().settings().setArchiveInMainMenu(false);
controller->session().saveSettingsDelayed();
controller->window().hideSettingsAndLayer();
};
addAction(
tr::lng_context_archive_to_list(tr::now),
std::move(hide),
&st::menuIconFromMainMenu);
MenuAddMarkAsReadChatListAction(
controller,
[f = folder()] { return f->chatsList(); },
addAction);
_contextMenu->addSeparator();
Settings::PreloadArchiveSettings(&controller->session());
addAction(tr::lng_context_archive_settings(tr::now), [=] {
controller->show(Box(Settings::ArchiveSettingsBox, controller));
}, &st::menuIconManage);
Window::FillDialogsEntryMenu(
_controller,
Dialogs::EntryState{
.key = folder(),
.section = Dialogs::EntryState::Section::ContextMenu,
},
Ui::Menu::CreateAddActionCallback(_contextMenu));
_contextMenu->popup(QCursor::pos());
}, button->lifetime());

View file

@ -59,6 +59,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history.h"
#include "history/history_item_helpers.h" // GetErrorTextForSending.
#include "history/view/history_view_context_menu.h"
#include "window/window_separate_id.h"
#include "window/window_session_controller.h"
#include "window/window_controller.h"
#include "settings/settings_advanced.h"
@ -650,20 +651,48 @@ void Filler::addToggleUnreadMark() {
}
void Filler::addNewWindow() {
const auto controller = _controller;
if (_folder) {
_addAction(tr::lng_context_new_window(tr::now), [=] {
Ui::PreventDelayedActivation();
controller->showInNewWindow(SeparateId(
SeparateType::Archive,
&controller->session()));
}, &st::menuIconNewWindow);
AddSeparatorAndShiftUp(_addAction);
return;
} else if (const auto weak = base::make_weak(_sublist)) {
_addAction(tr::lng_context_new_window(tr::now), [=] {
Ui::PreventDelayedActivation();
if (const auto sublist = weak.get()) {
const auto peer = sublist->peer();
controller->showInNewWindow(SeparateId(
SeparateType::SavedSublist,
peer->owner().history(peer)));
}
}, &st::menuIconNewWindow);
AddSeparatorAndShiftUp(_addAction);
return;
}
const auto history = _request.key.history();
if (!_peer
|| _topic
|| _peer->isForum()
|| (history
&& history->useTopPromotion()
&& !history->topPromotionType().isEmpty())) {
return;
}
const auto peer = _peer;
const auto controller = _controller;
const auto thread = _topic
? not_null<Data::Thread*>(_topic)
: _peer->owner().history(_peer);
const auto weak = base::make_weak(thread);
_addAction(tr::lng_context_new_window(tr::now), [=] {
Ui::PreventDelayedActivation();
controller->showInNewWindow(peer);
if (const auto strong = weak.get()) {
controller->showInNewWindow(SeparateId(
peer->isForum() ? SeparateType::Forum : SeparateType::Chat,
strong));
}
}, &st::menuIconNewWindow);
AddSeparatorAndShiftUp(_addAction);
}
@ -1253,6 +1282,12 @@ void Filler::addViewAsMessages() {
FullMsgId(),
}, callback, QApplication::activePopupWidget());
return true;
} else if (base::IsCtrlPressed()) {
Ui::PreventDelayedActivation();
controller->showInNewWindow(SeparateId(
SeparateType::Chat,
peer->owner().history(peer)));
return true;
}
return false;
};
@ -1432,27 +1467,39 @@ void Filler::fillArchiveActions() {
if (_folder->id() != Data::Folder::kId) {
return;
}
addNewWindow();
const auto controller = _controller;
const auto hidden = controller->session().settings().archiveCollapsed();
const auto text = hidden
? tr::lng_context_archive_expand(tr::now)
: tr::lng_context_archive_collapse(tr::now);
_addAction(text, [=] {
controller->session().settings().setArchiveCollapsed(!hidden);
controller->session().saveSettingsDelayed();
}, hidden ? &st::menuIconExpand : &st::menuIconCollapse);
_addAction(tr::lng_context_archive_to_menu(tr::now), [=] {
controller->showToast({
.text = { tr::lng_context_archive_to_menu_info(tr::now) },
.st = &st::windowArchiveToast,
.duration = kArchivedToastDuration,
});
controller->session().settings().setArchiveInMainMenu(
!controller->session().settings().archiveInMainMenu());
controller->session().saveSettingsDelayed();
}, &st::menuIconToMainMenu);
{
const auto text = hidden
? tr::lng_context_archive_expand(tr::now)
: tr::lng_context_archive_collapse(tr::now);
_addAction(text, [=] {
controller->session().settings().setArchiveCollapsed(!hidden);
controller->session().saveSettingsDelayed();
}, hidden ? &st::menuIconExpand : &st::menuIconCollapse);
}
const auto inmenu = controller->session().settings().archiveInMainMenu();
{
const auto text = inmenu
? tr::lng_context_archive_to_list(tr::now)
: tr::lng_context_archive_to_menu(tr::now);
_addAction(text, [=] {
if (!inmenu) {
controller->showToast({
.text = {
tr::lng_context_archive_to_menu_info(tr::now)
},
.st = &st::windowArchiveToast,
.duration = kArchivedToastDuration,
});
}
controller->session().settings().setArchiveInMainMenu(!inmenu);
controller->session().saveSettingsDelayed();
controller->window().hideSettingsAndLayer();
}, inmenu ? &st::menuIconFromMainMenu : &st::menuIconToMainMenu);
}
MenuAddMarkAsReadChatListAction(
controller,
@ -1460,6 +1507,7 @@ void Filler::fillArchiveActions() {
_addAction);
_addAction({ .isSeparator = true });
Settings::PreloadArchiveSettings(&controller->session());
_addAction(tr::lng_context_archive_settings(tr::now), [=] {
controller->show(Box(Settings::ArchiveSettingsBox, controller));
@ -1467,6 +1515,7 @@ void Filler::fillArchiveActions() {
}
void Filler::fillSavedSublistActions() {
addNewWindow();
addTogglePin();
}
@ -1983,17 +2032,17 @@ QPointer<Ui::BoxContent> ShowForwardMessagesBox(
ForwardToSelf(show, draft);
return true;
}
auto controller = Core::App().windowFor(peer);
const auto id = SeparateId(
(peer->isForum()
? SeparateType::Forum
: SeparateType::Chat),
thread);
auto controller = Core::App().windowFor(id);
if (!controller) {
return false;
}
if (controller->maybeSession() != &peer->session()) {
controller = peer->isForum()
? Core::App().ensureSeparateWindowForAccount(
&peer->account())
: Core::App().ensureSeparateWindowForPeer(
peer,
ShowAtUnreadMsgId);
controller = Core::App().ensureSeparateWindowFor(id);
if (controller->maybeSession() != &peer->session()) {
return false;
}

View file

@ -0,0 +1,77 @@
/*
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_separate_id.h"
#include "data/data_folder.h"
#include "data/data_peer.h"
#include "data/data_saved_messages.h"
#include "data/data_session.h"
#include "data/data_thread.h"
#include "history/history.h"
#include "main/main_account.h"
#include "main/main_session.h"
namespace Window {
SeparateId::SeparateId(std::nullptr_t) {
}
SeparateId::SeparateId(not_null<Main::Account*> account)
: account(account) {
}
SeparateId::SeparateId(SeparateType type, not_null<Main::Session*> session)
: type(type)
, account(&session->account()) {
}
SeparateId::SeparateId(SeparateType type, not_null<Data::Thread*> thread)
: type(type)
, account(&thread->session().account())
, thread(thread) {
}
SeparateId::SeparateId(not_null<Data::Thread*> thread)
: SeparateId(SeparateType::Chat, thread) {
}
SeparateId::SeparateId(not_null<PeerData*> peer)
: SeparateId(SeparateType::Chat, peer->owner().history(peer)) {
}
bool SeparateId::primary() const {
return (type == SeparateType::Primary);
}
Data::Thread *SeparateId::chat() const {
return (type == SeparateType::Chat) ? thread : nullptr;
}
Data::Forum *SeparateId::forum() const {
return (type == SeparateType::Forum) ? thread->asForum() : nullptr;
}
Data::Folder *SeparateId::folder() const {
return (type == SeparateType::Archive)
? account->session().data().folder(Data::Folder::kId).get()
: nullptr;
}
Data::SavedSublist *SeparateId::sublist() const {
return (type == SeparateType::SavedSublist)
? thread->owner().savedMessages().sublist(thread->peer()).get()
: nullptr;
}
bool SeparateId::hasChatsList() const {
return (type == SeparateType::Primary)
|| (type == SeparateType::Archive)
|| (type == SeparateType::Forum);
}
} // namespace Window

View file

@ -0,0 +1,69 @@
/*
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
class PeerData;
namespace Data {
class Thread;
class Folder;
class Forum;
class SavedSublist;
} // namespace Data
namespace Main {
class Account;
class Session;
} // namespace Main
namespace Window {
enum class SeparateType {
Primary,
Archive,
Chat,
Forum,
SavedSublist,
};
struct SeparateId {
SeparateId(std::nullptr_t);
SeparateId(not_null<Main::Account*> account);
SeparateId(SeparateType type, not_null<Main::Session*> session);
SeparateId(SeparateType type, not_null<Data::Thread*> thread);
SeparateId(not_null<Data::Thread*> thread);
SeparateId(not_null<PeerData*> peer);
SeparateType type = SeparateType::Primary;
Main::Account *account = nullptr;
Data::Thread *thread = nullptr; // For types except Main and Archive.
[[nodiscard]] bool valid() const {
return account != nullptr;
}
explicit operator bool() const {
return valid();
}
[[nodiscard]] bool primary() const;
[[nodiscard]] Data::Thread *chat() const;
[[nodiscard]] Data::Forum *forum() const;
[[nodiscard]] Data::Folder *folder() const;
[[nodiscard]] Data::SavedSublist *sublist() const;
[[nodiscard]] bool hasChatsList() const;
friend inline auto operator<=>(
const SeparateId &,
const SeparateId &) = default;
friend inline bool operator==(
const SeparateId &,
const SeparateId &) = default;
};
} // namespace Window

View file

@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "window/window_chat_preview.h"
#include "window/window_controller.h"
#include "window/window_filters_menu.h"
#include "window/window_separate_id.h"
#include "info/channel_statistics/earn/info_earn_inner_widget.h"
#include "info/info_memento.h"
#include "info/info_controller.h"
@ -26,11 +27,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
//#include "history/view/reactions/history_view_reactions_button.h"
#include "history/view/history_view_replies_section.h"
#include "history/view/history_view_scheduled_section.h"
#include "history/view/history_view_sublist_section.h"
#include "media/player/media_player_instance.h"
#include "media/view/media_view_open_common.h"
#include "data/stickers/data_custom_emoji.h"
#include "data/data_document_resolver.h"
#include "data/data_download_manager.h"
#include "data/data_saved_messages.h"
#include "data/data_session.h"
#include "data/data_file_origin.h"
#include "data/data_folder.h"
@ -1100,6 +1103,36 @@ void SessionNavigation::showPeerHistory(
showPeerHistory(history->peer->id, params, msgId);
}
void SessionNavigation::showByInitialId(
const SectionShow &params,
MsgId msgId) {
const auto parent = parentController();
const auto id = parent->window().id();
auto instant = params;
instant.animated = anim::type::instant;
switch (id.type) {
case SeparateType::Archive:
clearSectionStack(instant);
parent->openFolder(id.folder());
break;
case SeparateType::Forum:
clearSectionStack(instant);
parent->showForum(id.forum(), instant);
break;
case SeparateType::Primary:
clearSectionStack(instant);
break;
case SeparateType::Chat:
showThread(id.thread, msgId, instant);
break;
case SeparateType::SavedSublist:
showSection(
std::make_shared<HistoryView::SublistMemento>(id.sublist()),
instant);
break;
}
}
void SessionNavigation::showSettings(
Settings::Type type,
const SectionShow &params) {
@ -1182,6 +1215,7 @@ SessionController::SessionController(
std::make_unique<ChatHelpers::EmojiInteractions>(session))
, _chatPreviewManager(std::make_unique<ChatPreviewManager>(this))
, _isPrimary(window->isPrimary())
, _hasDialogs(window->id().hasChatsList())
, _sendingAnimation(
std::make_unique<Ui::MessageSendingAnimationController>(this))
, _tabbedSelector(
@ -1191,6 +1225,7 @@ SessionController::SessionController(
GifPauseReason::TabbedPanel))
, _invitePeekTimer([=] { checkInvitePeek(); })
, _activeChatsFilter(session->data().chatsFilters().defaultId())
, _openedFolder(window->id().folder())
, _defaultChatTheme(std::make_shared<Ui::ChatTheme>())
, _chatStyle(std::make_unique<Ui::ChatStyle>(session->colorIndicesValue()))
, _giftPremiumValidator(this) {
@ -1373,8 +1408,8 @@ void SessionController::suggestArchiveAndMute() {
}));
}
PeerData *SessionController::singlePeer() const {
return _window->singlePeer();
SeparateId SessionController::windowId() const {
return _window->id();
}
bool SessionController::isPrimary() const {
@ -1466,7 +1501,7 @@ void SessionController::setupShortcuts() {
if (account == &session().account()) {
return false;
}
const auto window = app->separateWindowForAccount(account);
const auto window = app->separateWindowFor(account);
if (window) {
window->activate();
} else {
@ -1523,7 +1558,9 @@ void SessionController::checkOpenedFilter() {
}
void SessionController::activateFirstChatsFilter() {
if (_filtersActivated || !session().data().chatsFilters().loaded()) {
if (_filtersActivated
|| !isPrimary()
|| !session().data().chatsFilters().loaded()) {
return;
}
_filtersActivated = true;
@ -1536,8 +1573,24 @@ bool SessionController::uniqueChatsInSearchResults() const {
&& !_searchInChat.current();
}
bool SessionController::openFolderInDifferentWindow(
not_null<Data::Folder*> folder) {
const auto id = SeparateId(SeparateType::Archive, &session());
if (const auto separate = Core::App().separateWindowFor(id)) {
if (separate == _window) {
return false;
}
separate->sessionController()->showByInitialId();
separate->activate();
return true;
}
return false;
}
void SessionController::openFolder(not_null<Data::Folder*> folder) {
if (_openedFolder.current() != folder) {
if (openFolderInDifferentWindow(folder)) {
return;
} else if (_openedFolder.current() != folder) {
resetFakeUnreadWhileOpened();
}
if (activeChatsFilterCurrent() != 0) {
@ -1550,22 +1603,44 @@ void SessionController::openFolder(not_null<Data::Folder*> folder) {
}
void SessionController::closeFolder() {
if (_openedFolder.current()
&& windowId().type == SeparateType::Archive) {
Core::App().closeWindow(_window);
return;
}
_openedFolder = nullptr;
}
bool SessionController::showForumInDifferentWindow(
not_null<Data::Forum*> forum,
const SectionShow &params) {
const auto window = Core::App().windowForShowingForum(forum);
if (window == _window) {
return false;
} else if (window) {
window->sessionController()->showForum(forum, params);
window->activate();
return true;
} else if (windowId().hasChatsList()) {
return false;
}
const auto account = not_null(&session().account());
auto primary = Core::App().separateWindowFor(account);
if (!primary) {
Core::App().domain().activate(account);
primary = Core::App().separateWindowFor(account);
}
if (primary && &primary->account() == account) {
primary->sessionController()->showForum(forum, params);
primary->activate();
}
return true;
}
void SessionController::showForum(
not_null<Data::Forum*> forum,
const SectionShow &params) {
if (!isPrimary()) {
auto primary = Core::App().windowFor(&session().account());
if (&primary->account() != &session().account()) {
Core::App().domain().activate(&session().account());
primary = Core::App().windowFor(&session().account());
}
if (&primary->account() == &session().account()) {
primary->sessionController()->showForum(forum, params);
}
primary->activate();
if (showForumInDifferentWindow(forum, params)) {
return;
}
_shownForumLifetime.destroy();
@ -1598,6 +1673,18 @@ void SessionController::showForum(
}
void SessionController::closeForum() {
if (const auto forum = _shownForum.current()) {
const auto id = windowId();
if (id.type == SeparateType::Forum) {
const auto initial = id.thread->asForum();
if (!initial || initial == forum) {
Core::App().closeWindow(_window);
} else {
showForum(initial);
}
return;
}
}
_shownForumLifetime.destroy();
_shownForum = nullptr;
}
@ -1889,7 +1976,7 @@ int SessionController::dialogsSmallColumnWidth() const {
}
int SessionController::minimalThreeColumnWidth() const {
return (_isPrimary ? st::columnMinimalWidthLeft : 0)
return (_hasDialogs ? st::columnMinimalWidthLeft : 0)
+ st::columnMinimalWidthMain
+ st::columnMinimalWidthThird;
}
@ -1903,7 +1990,7 @@ auto SessionController::computeColumnLayout() const -> ColumnLayout {
auto useOneColumnLayout = [&] {
auto minimalNormal = st::columnMinimalWidthLeft
+ st::columnMinimalWidthMain;
if (_isPrimary && bodyWidth < minimalNormal) {
if (_hasDialogs && bodyWidth < minimalNormal) {
return true;
}
return false;
@ -1945,7 +2032,7 @@ auto SessionController::computeColumnLayout() const -> ColumnLayout {
}
int SessionController::countDialogsWidthFromRatio(int bodyWidth) const {
if (!_isPrimary) {
if (!_hasDialogs) {
return 0;
}
const auto nochat = !mainSectionShown();
@ -1979,8 +2066,8 @@ SessionController::ShrinkResult SessionController::shrinkDialogsAndThirdColumns(
if (thirdWidthNew < st::columnMinimalWidthThird) {
thirdWidthNew = st::columnMinimalWidthThird;
dialogsWidthNew = bodyWidth - thirdWidthNew - chatWidth;
Assert(!_isPrimary || dialogsWidthNew >= st::columnMinimalWidthLeft);
} else if (_isPrimary && dialogsWidthNew < st::columnMinimalWidthLeft) {
Assert(!_hasDialogs || dialogsWidthNew >= st::columnMinimalWidthLeft);
} else if (_hasDialogs && dialogsWidthNew < st::columnMinimalWidthLeft) {
dialogsWidthNew = st::columnMinimalWidthLeft;
thirdWidthNew = bodyWidth - dialogsWidthNew - chatWidth;
Assert(thirdWidthNew >= st::columnMinimalWidthThird);
@ -2089,9 +2176,11 @@ void SessionController::closeThirdSection() {
}
}
bool SessionController::canShowSeparateWindow(
not_null<PeerData*> peer) const {
return !peer->isForum() && peer->computeUnavailableReason().isEmpty();
bool SessionController::canShowSeparateWindow(SeparateId id) const {
if (const auto thread = id.thread) {
return thread->peer()->computeUnavailableReason().isEmpty();
}
return true;
}
void SessionController::showPeer(not_null<PeerData*> peer, MsgId msgId) {
@ -2314,21 +2403,20 @@ void SessionController::clearChooseReportMessages() const {
}
void SessionController::showInNewWindow(
not_null<PeerData*> peer,
SeparateId id,
MsgId msgId) {
if (!canShowSeparateWindow(peer)) {
showThread(
peer->owner().history(peer),
msgId,
Window::SectionShow::Way::ClearStack);
if (!canShowSeparateWindow(id)) {
Assert(id.thread != nullptr);
showThread(id.thread, msgId, SectionShow::Way::ClearStack);
return;
}
const auto active = activeChatCurrent();
const auto fromActive = active.history()
? (active.history()->peer == peer)
// windows check active forum / active archive
const auto fromActive = active.thread()
? (active.thread() == id.thread)
: false;
const auto toSeparate = [=] {
Core::App().ensureSeparateWindowForPeer(peer, msgId);
Core::App().ensureSeparateWindowFor(id, msgId);
};
if (fromActive) {
window().preventOrInvoke([=] {
@ -2485,6 +2573,9 @@ FilterId SessionController::activeChatsFilterCurrent() const {
void SessionController::setActiveChatsFilter(
FilterId id,
const SectionShow &params) {
if (!isPrimary()) {
return;
}
const auto changed = (activeChatsFilterCurrent() != id);
if (changed) {
resetFakeUnreadWhileOpened();

View file

@ -91,6 +91,7 @@ class FiltersMenu;
class ChatPreviewManager;
struct PeerByLinkInfo;
struct SeparateId;
struct PeerThemeOverride {
PeerData *peer = nullptr;
@ -232,6 +233,10 @@ public:
ShowAtUnreadMsgId);
}
void showByInitialId(
const SectionShow &params = SectionShow::Way::ClearStack,
MsgId msgId = ShowAtUnreadMsgId);
void showSettings(
Settings::Type type,
const SectionShow &params = SectionShow());
@ -326,7 +331,7 @@ public:
[[nodiscard]] Controller &window() const {
return *_window;
}
[[nodiscard]] PeerData *singlePeer() const;
[[nodiscard]] SeparateId windowId() const;
[[nodiscard]] bool isPrimary() const;
[[nodiscard]] not_null<::MainWindow*> widget() const;
[[nodiscard]] not_null<MainWidget*> content() const;
@ -432,7 +437,7 @@ public:
void resizeForThirdSection();
void closeThirdSection();
[[nodiscard]] bool canShowSeparateWindow(not_null<PeerData*> peer) const;
[[nodiscard]] bool canShowSeparateWindow(SeparateId id) const;
void showPeer(not_null<PeerData*> peer, MsgId msgId = ShowAtUnreadMsgId);
void startOrJoinGroupCall(not_null<PeerData*> peer);
@ -509,7 +514,7 @@ public:
void clearChooseReportMessages() const;
void showInNewWindow(
not_null<PeerData*> peer,
SeparateId id,
MsgId msgId = ShowAtUnreadMsgId);
void toggleChooseChatTheme(
@ -667,10 +672,16 @@ private:
void checkNonPremiumLimitToastDownload(DocumentId id);
void checkNonPremiumLimitToastUpload(FullMsgId id);
bool openFolderInDifferentWindow(not_null<Data::Folder*> folder);
bool showForumInDifferentWindow(
not_null<Data::Forum*> forum,
const SectionShow &params);
const not_null<Controller*> _window;
const std::unique_ptr<ChatHelpers::EmojiInteractions> _emojiInteractions;
const std::unique_ptr<ChatPreviewManager> _chatPreviewManager;
const bool _isPrimary = false;
const bool _hasDialogs = false;
mutable std::shared_ptr<ChatHelpers::Show> _cachedShow;