mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-15 21:57:10 +02:00
Allow creating separate windows for peers.
This commit is contained in:
parent
f4f36d85b9
commit
20411be9bd
8 changed files with 128 additions and 39 deletions
|
@ -1195,7 +1195,10 @@ base::unique_qptr<Ui::PopupMenu> Members::Controller::createRowContextMenu(
|
|||
const auto admin = IsGroupCallAdmin(_peer, participantPeer);
|
||||
const auto session = &_peer->session();
|
||||
const auto getCurrentWindow = [=]() -> Window::SessionController* {
|
||||
if (const auto window = Core::App().activeWindow()) {
|
||||
if (const auto window = Core::App().separateWindowForPeer(
|
||||
participantPeer)) {
|
||||
return window->sessionController();
|
||||
} else if (const auto window = Core::App().activeWindow()) {
|
||||
if (const auto controller = window->sessionController()) {
|
||||
if (&controller->session() == session) {
|
||||
return controller;
|
||||
|
@ -1221,7 +1224,7 @@ base::unique_qptr<Ui::PopupMenu> Members::Controller::createRowContextMenu(
|
|||
? st::groupCallPopupMenuWithVolume
|
||||
: st::groupCallPopupMenu));
|
||||
const auto weakMenu = Ui::MakeWeak(result.get());
|
||||
const auto performOnMainWindow = [=](auto callback) {
|
||||
const auto withActiveWindow = [=](auto callback) {
|
||||
if (const auto window = getWindow()) {
|
||||
if (const auto menu = weakMenu.data()) {
|
||||
menu->discardParentReActivate();
|
||||
|
@ -1236,12 +1239,12 @@ base::unique_qptr<Ui::PopupMenu> Members::Controller::createRowContextMenu(
|
|||
}
|
||||
};
|
||||
const auto showProfile = [=] {
|
||||
performOnMainWindow([=](not_null<Window::SessionController*> window) {
|
||||
withActiveWindow([=](not_null<Window::SessionController*> window) {
|
||||
window->showPeerInfo(participantPeer);
|
||||
});
|
||||
};
|
||||
const auto showHistory = [=] {
|
||||
performOnMainWindow([=](not_null<Window::SessionController*> window) {
|
||||
withActiveWindow([=](not_null<Window::SessionController*> window) {
|
||||
window->showPeerHistory(
|
||||
participantPeer,
|
||||
Window::SectionShow::Way::Forward);
|
||||
|
|
|
@ -123,6 +123,7 @@ Application *Application::Instance = nullptr;
|
|||
struct Application::Private {
|
||||
base::Timer quitTimer;
|
||||
UiIntegration uiIntegration;
|
||||
Settings settings;
|
||||
};
|
||||
|
||||
Application::Application(not_null<Launcher*> launcher)
|
||||
|
@ -170,6 +171,7 @@ Application::~Application() {
|
|||
// Depend on activeWindow() for now :(
|
||||
Shortcuts::Finish();
|
||||
|
||||
_separateWindows.clear();
|
||||
_window = nullptr;
|
||||
_mediaView = nullptr;
|
||||
_notifications->clearAllFast();
|
||||
|
@ -264,6 +266,7 @@ void Application::run() {
|
|||
QMimeDatabase().mimeTypeForName(qsl("text/plain"));
|
||||
|
||||
_window = std::make_unique<Window::Controller>();
|
||||
_lastActiveWindow = _window.get();
|
||||
|
||||
_domain->activeChanges(
|
||||
) | rpl::start_with_next([=](not_null<Main::Account*> account) {
|
||||
|
@ -371,8 +374,8 @@ void Application::startSettingsAndBackground() {
|
|||
}
|
||||
|
||||
void Application::checkSystemDarkMode() {
|
||||
const auto maybeDarkMode = _settings.systemDarkMode();
|
||||
const auto darkModeEnabled = _settings.systemDarkModeEnabled();
|
||||
const auto maybeDarkMode = settings().systemDarkMode();
|
||||
const auto darkModeEnabled = settings().systemDarkModeEnabled();
|
||||
const auto needToSwitch = darkModeEnabled
|
||||
&& maybeDarkMode
|
||||
&& (*maybeDarkMode != Window::Theme::IsNightMode());
|
||||
|
@ -384,11 +387,11 @@ void Application::checkSystemDarkMode() {
|
|||
|
||||
void Application::startSystemDarkModeViewer() {
|
||||
if (Window::Theme::Background()->editingTheme()) {
|
||||
_settings.setSystemDarkModeEnabled(false);
|
||||
settings().setSystemDarkModeEnabled(false);
|
||||
}
|
||||
rpl::merge(
|
||||
_settings.systemDarkModeChanges() | rpl::to_empty,
|
||||
_settings.systemDarkModeEnabledChanges() | rpl::to_empty
|
||||
settings().systemDarkModeChanges() | rpl::to_empty,
|
||||
settings().systemDarkModeEnabledChanges() | rpl::to_empty
|
||||
) | rpl::start_with_next([=] {
|
||||
checkSystemDarkMode();
|
||||
}, _lifetime);
|
||||
|
@ -397,7 +400,7 @@ void Application::startSystemDarkModeViewer() {
|
|||
auto Application::prepareEmojiSourceImages()
|
||||
-> std::shared_ptr<Ui::Emoji::UniversalImages> {
|
||||
const auto &images = Ui::Emoji::SourceImages();
|
||||
if (_settings.largeEmoji()) {
|
||||
if (settings().largeEmoji()) {
|
||||
return images;
|
||||
}
|
||||
Ui::Emoji::ClearSourceImages(images);
|
||||
|
@ -471,6 +474,10 @@ bool Application::eventFilter(QObject *object, QEvent *e) {
|
|||
return QObject::eventFilter(object, e);
|
||||
}
|
||||
|
||||
Settings &Application::settings() {
|
||||
return _private->settings;
|
||||
}
|
||||
|
||||
void Application::saveSettingsDelayed(crl::time delay) {
|
||||
if (_saveSettingsTimer) {
|
||||
_saveSettingsTimer->callOnce(delay);
|
||||
|
@ -508,18 +515,17 @@ void Application::constructFallbackProductionConfig(
|
|||
void Application::setCurrentProxy(
|
||||
const MTP::ProxyData &proxy,
|
||||
MTP::ProxyData::Settings settings) {
|
||||
auto &my = _private->settings.proxy();
|
||||
const auto current = [&] {
|
||||
return _settings.proxy().isEnabled()
|
||||
? _settings.proxy().selected()
|
||||
: MTP::ProxyData();
|
||||
return my.isEnabled() ? my.selected() : MTP::ProxyData();
|
||||
};
|
||||
const auto was = current();
|
||||
_settings.proxy().setSelected(proxy);
|
||||
_settings.proxy().setSettings(settings);
|
||||
my.setSelected(proxy);
|
||||
my.setSettings(settings);
|
||||
const auto now = current();
|
||||
refreshGlobalProxy();
|
||||
_proxyChanges.fire({ was, now });
|
||||
_settings.proxy().connectionTypeChangesNotify();
|
||||
my.connectionTypeChangesNotify();
|
||||
}
|
||||
|
||||
auto Application::proxyChanges() const -> rpl::producer<ProxyChange> {
|
||||
|
@ -527,10 +533,10 @@ auto Application::proxyChanges() const -> rpl::producer<ProxyChange> {
|
|||
}
|
||||
|
||||
void Application::badMtprotoConfigurationError() {
|
||||
if (_settings.proxy().isEnabled() && !_badProxyDisableBox) {
|
||||
if (settings().proxy().isEnabled() && !_badProxyDisableBox) {
|
||||
const auto disableCallback = [=] {
|
||||
setCurrentProxy(
|
||||
_settings.proxy().selected(),
|
||||
settings().proxy().selected(),
|
||||
MTP::ProxyData::Settings::System);
|
||||
};
|
||||
_badProxyDisableBox = Ui::show(Box<Ui::InformBox>(
|
||||
|
@ -542,7 +548,7 @@ void Application::badMtprotoConfigurationError() {
|
|||
void Application::startLocalStorage() {
|
||||
Local::start();
|
||||
_saveSettingsTimer.emplace([=] { saveSettings(); });
|
||||
_settings.saveDelayedRequests() | rpl::start_with_next([=] {
|
||||
settings().saveDelayedRequests() | rpl::start_with_next([=] {
|
||||
saveSettingsDelayed();
|
||||
}, _lifetime);
|
||||
}
|
||||
|
@ -550,12 +556,12 @@ void Application::startLocalStorage() {
|
|||
void Application::startEmojiImageLoader() {
|
||||
_emojiImageLoader.with([
|
||||
source = prepareEmojiSourceImages(),
|
||||
large = _settings.largeEmoji()
|
||||
large = settings().largeEmoji()
|
||||
](Stickers::EmojiImageLoader &loader) mutable {
|
||||
loader.init(std::move(source), large);
|
||||
});
|
||||
|
||||
_settings.largeEmojiChanges(
|
||||
settings().largeEmojiChanges(
|
||||
) | rpl::start_with_next([=](bool large) {
|
||||
if (large) {
|
||||
_clearEmojiImageLoaderTimer.cancel();
|
||||
|
@ -913,9 +919,11 @@ void Application::checkAutoLock(crl::time lastNonIdleTime) {
|
|||
|
||||
checkLocalTime();
|
||||
const auto now = crl::now();
|
||||
const auto shouldLockInMs = _settings.autoLock() * 1000LL;
|
||||
const auto shouldLockInMs = settings().autoLock() * 1000LL;
|
||||
const auto checkTimeMs = now - lastNonIdleTime;
|
||||
if (checkTimeMs >= shouldLockInMs || (_shouldLockAt > 0 && now > _shouldLockAt + kAutoLockTimeoutLateMs)) {
|
||||
if (checkTimeMs >= shouldLockInMs
|
||||
|| (_shouldLockAt > 0
|
||||
&& now > _shouldLockAt + kAutoLockTimeoutLateMs)) {
|
||||
_shouldLockAt = 0;
|
||||
_autoLockTimer.cancel();
|
||||
lockByPasscode();
|
||||
|
@ -961,10 +969,39 @@ void Application::saveCurrentDraftsToHistories() {
|
|||
}
|
||||
}
|
||||
|
||||
Window::Controller *Application::activeWindow() const {
|
||||
Window::Controller *Application::mainWindow() const {
|
||||
return _window.get();
|
||||
}
|
||||
|
||||
Window::Controller *Application::separateWindowForPeer(
|
||||
not_null<PeerData*> peer) const {
|
||||
for (const auto &[history, window] : _separateWindows) {
|
||||
if (history->peer == peer) {
|
||||
return window.get();
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Window::Controller *Application::ensureSeparateWindowForPeer(
|
||||
not_null<PeerData*> peer) {
|
||||
if (const auto existing = separateWindowForPeer(peer)) {
|
||||
return existing;
|
||||
}
|
||||
const auto result = _separateWindows.emplace(
|
||||
peer->owner().history(peer),
|
||||
std::make_unique<Window::Controller>()).first->second.get();
|
||||
result->showAccount(&peer->account());
|
||||
result->sessionController()->showPeerHistory(peer);
|
||||
result->widget()->show();
|
||||
result->finishFirstShow();
|
||||
return result;
|
||||
}
|
||||
|
||||
Window::Controller *Application::activeWindow() const {
|
||||
return _lastActiveWindow;
|
||||
}
|
||||
|
||||
bool Application::closeActiveWindow() {
|
||||
if (hideMediaView()) {
|
||||
return true;
|
||||
|
|
|
@ -133,7 +133,12 @@ public:
|
|||
// Windows interface.
|
||||
bool hasActiveWindow(not_null<Main::Session*> session) const;
|
||||
void saveCurrentDraftsToHistories();
|
||||
[[nodiscard]] Window::Controller *mainWindow() const;
|
||||
[[nodiscard]] Window::Controller *activeWindow() const;
|
||||
[[nodiscard]] Window::Controller *separateWindowForPeer(
|
||||
not_null<PeerData*> peer) const;
|
||||
Window::Controller *ensureSeparateWindowForPeer(
|
||||
not_null<PeerData*> peer);
|
||||
bool closeActiveWindow();
|
||||
bool minimizeActiveWindow();
|
||||
[[nodiscard]] QWidget *getFileDialogParent();
|
||||
|
@ -147,9 +152,7 @@ public:
|
|||
[[nodiscard]] QPoint getPointForCallPanelCenter() const;
|
||||
|
||||
void startSettingsAndBackground();
|
||||
[[nodiscard]] Settings &settings() {
|
||||
return _settings;
|
||||
}
|
||||
[[nodiscard]] Settings &settings();
|
||||
void saveSettingsDelayed(crl::time delay = kDefaultSaveDelay);
|
||||
void saveSettings();
|
||||
|
||||
|
@ -337,6 +340,11 @@ private:
|
|||
const std::unique_ptr<Export::Manager> _exportManager;
|
||||
const std::unique_ptr<Calls::Instance> _calls;
|
||||
std::unique_ptr<Window::Controller> _window;
|
||||
base::flat_map<
|
||||
not_null<History*>,
|
||||
std::unique_ptr<Window::Controller>> _separateWindows;
|
||||
Window::Controller *_lastActiveWindow = nullptr;
|
||||
|
||||
std::unique_ptr<Media::View::OverlayWidget> _mediaView;
|
||||
const std::unique_ptr<Lang::Instance> _langpack;
|
||||
const std::unique_ptr<Lang::CloudManager> _langCloudManager;
|
||||
|
|
|
@ -1052,7 +1052,7 @@ void InnerWidget::mousePressEvent(QMouseEvent *e) {
|
|||
}
|
||||
if (anim::Disabled()
|
||||
&& (!_pressed || !_pressed->entry()->isPinnedDialog(_filterId))) {
|
||||
mousePressReleased(e->globalPos(), e->button());
|
||||
mousePressReleased(e->globalPos(), e->button(), e->modifiers());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1274,12 +1274,13 @@ bool InnerWidget::pinnedShiftAnimationCallback(crl::time now) {
|
|||
}
|
||||
|
||||
void InnerWidget::mouseReleaseEvent(QMouseEvent *e) {
|
||||
mousePressReleased(e->globalPos(), e->button());
|
||||
mousePressReleased(e->globalPos(), e->button(), e->modifiers());
|
||||
}
|
||||
|
||||
void InnerWidget::mousePressReleased(
|
||||
QPoint globalPosition,
|
||||
Qt::MouseButton button) {
|
||||
Qt::MouseButton button,
|
||||
Qt::KeyboardModifiers modifiers) {
|
||||
auto wasDragging = (_dragging != nullptr);
|
||||
if (wasDragging) {
|
||||
updateReorderIndexGetCount();
|
||||
|
@ -1322,7 +1323,7 @@ void InnerWidget::mousePressReleased(
|
|||
&& peerSearchPressed == _peerSearchSelected)
|
||||
|| (searchedPressed >= 0
|
||||
&& searchedPressed == _searchedSelected)) {
|
||||
chooseRow();
|
||||
chooseRow(modifiers);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1758,7 +1759,7 @@ void InnerWidget::contextMenuEvent(QContextMenuEvent *e) {
|
|||
|
||||
_menuRow = row;
|
||||
if (_pressButton != Qt::LeftButton) {
|
||||
mousePressReleased(e->globalPos(), _pressButton);
|
||||
mousePressReleased(e->globalPos(), _pressButton, e->modifiers());
|
||||
}
|
||||
|
||||
_menu = base::make_unique_q<Ui::PopupMenu>(
|
||||
|
@ -2689,13 +2690,21 @@ ChosenRow InnerWidget::computeChosenRow() const {
|
|||
return ChosenRow();
|
||||
}
|
||||
|
||||
bool InnerWidget::chooseRow() {
|
||||
bool InnerWidget::chooseRow(Qt::KeyboardModifiers modifiers) {
|
||||
if (chooseCollapsedRow()) {
|
||||
return true;
|
||||
} else if (chooseHashtag()) {
|
||||
return true;
|
||||
}
|
||||
const auto chosen = computeChosenRow();
|
||||
const auto modifyChosenRow = [](
|
||||
ChosenRow row,
|
||||
Qt::KeyboardModifiers modifiers) {
|
||||
#ifdef _DEBUG
|
||||
row.newWindow = (modifiers & Qt::ControlModifier);
|
||||
#endif
|
||||
return row;
|
||||
};
|
||||
const auto chosen = modifyChosenRow(computeChosenRow(), modifiers);
|
||||
if (chosen.key) {
|
||||
if (IsServerMsgId(chosen.message.fullId.msg)) {
|
||||
session().local().saveRecentSearchHashtags(_filter);
|
||||
|
|
|
@ -46,6 +46,7 @@ struct ChosenRow {
|
|||
Key key;
|
||||
Data::MessagePosition message;
|
||||
bool filteredRow = false;
|
||||
bool newWindow = false;
|
||||
};
|
||||
|
||||
enum class SearchRequestType {
|
||||
|
@ -95,7 +96,7 @@ public:
|
|||
void refreshEmptyLabel();
|
||||
void resizeEmptyLabel();
|
||||
|
||||
bool chooseRow();
|
||||
bool chooseRow(Qt::KeyboardModifiers modifiers = {});
|
||||
|
||||
void scrollToEntry(const RowDescriptor &entry);
|
||||
|
||||
|
@ -192,7 +193,10 @@ private:
|
|||
void refreshDialogRow(RowDescriptor row);
|
||||
|
||||
void clearMouseSelection(bool clearSelection = false);
|
||||
void mousePressReleased(QPoint globalPosition, Qt::MouseButton button);
|
||||
void mousePressReleased(
|
||||
QPoint globalPosition,
|
||||
Qt::MouseButton button,
|
||||
Qt::KeyboardModifiers modifiers);
|
||||
void clearIrrelevantState();
|
||||
void selectByMouse(QPoint globalPosition);
|
||||
void loadPeerPhotos();
|
||||
|
|
|
@ -31,6 +31,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "boxes/peer_list_box.h"
|
||||
#include "boxes/peers/edit_participants_box.h"
|
||||
#include "window/window_adaptive.h"
|
||||
#include "window/window_controller.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "window/window_slide_animation.h"
|
||||
#include "window/window_connecting_widget.h"
|
||||
|
@ -226,7 +227,11 @@ Widget::Widget(
|
|||
const auto openSearchResult = !controller->selectingPeer()
|
||||
&& row.filteredRow;
|
||||
if (const auto history = row.key.history()) {
|
||||
controller->content()->choosePeer(
|
||||
const auto window = row.newWindow
|
||||
? Core::App().ensureSeparateWindowForPeer(
|
||||
history->peer)->sessionController()
|
||||
: controller.get();
|
||||
window->content()->choosePeer(
|
||||
history->peer->id,
|
||||
(controller->uniqueChatsInSearchResults()
|
||||
? ShowAtUnreadMsgId
|
||||
|
|
|
@ -30,6 +30,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "window/themes/window_theme.h"
|
||||
#include "window/themes/window_theme_editor.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "mainwindow.h"
|
||||
#include "apiwrap.h" // ApiWrap::acceptTerms.
|
||||
#include "facades.h"
|
||||
|
@ -40,8 +41,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
namespace Window {
|
||||
|
||||
Controller::Controller()
|
||||
: _widget(this)
|
||||
Controller::Controller() : Controller(CreateArgs{}) {
|
||||
}
|
||||
|
||||
Controller::Controller(not_null<PeerData*> singlePeer)
|
||||
: Controller(CreateArgs{ singlePeer.get() }) {
|
||||
}
|
||||
|
||||
Controller::Controller(CreateArgs &&args)
|
||||
: _singlePeer(args.singlePeer)
|
||||
, _widget(this)
|
||||
, _adaptive(std::make_unique<Adaptive>())
|
||||
, _isActiveTimer([=] { updateIsActive(); }) {
|
||||
_widget.init();
|
||||
|
@ -54,6 +63,8 @@ Controller::~Controller() {
|
|||
}
|
||||
|
||||
void Controller::showAccount(not_null<Main::Account*> account) {
|
||||
Expects(!_singlePeer || &_singlePeer->account() == account);
|
||||
|
||||
const auto prevSessionUniqueId = (_account && _account->sessionExists())
|
||||
? _account->session().uniqueId()
|
||||
: 0;
|
||||
|
@ -118,6 +129,10 @@ void Controller::showAccount(not_null<Main::Account*> account) {
|
|||
}, _accountLifetime);
|
||||
}
|
||||
|
||||
PeerData *Controller::singlePeer() const {
|
||||
return _singlePeer;
|
||||
}
|
||||
|
||||
void Controller::checkLockByTerms() {
|
||||
const auto data = account().sessionExists()
|
||||
? account().session().termsLocked()
|
||||
|
|
|
@ -24,12 +24,14 @@ namespace Window {
|
|||
class Controller final : public base::has_weak_ptr {
|
||||
public:
|
||||
Controller();
|
||||
explicit Controller(not_null<PeerData*> singlePeer);
|
||||
~Controller();
|
||||
|
||||
Controller(const Controller &other) = delete;
|
||||
Controller &operator=(const Controller &other) = delete;
|
||||
|
||||
void showAccount(not_null<Main::Account*> account);
|
||||
[[nodiscard]] PeerData *singlePeer() const;
|
||||
|
||||
[[nodiscard]] not_null<::MainWindow*> widget() {
|
||||
return &_widget;
|
||||
|
@ -100,6 +102,11 @@ public:
|
|||
rpl::lifetime &lifetime();
|
||||
|
||||
private:
|
||||
struct CreateArgs {
|
||||
PeerData *singlePeer = nullptr;
|
||||
};
|
||||
explicit Controller(CreateArgs &&args);
|
||||
|
||||
void showBox(
|
||||
object_ptr<Ui::BoxContent> content,
|
||||
Ui::LayerOptions options,
|
||||
|
@ -109,6 +116,7 @@ private:
|
|||
void showTermsDecline();
|
||||
void showTermsDelete();
|
||||
|
||||
PeerData *_singlePeer = nullptr;
|
||||
Main::Account *_account = nullptr;
|
||||
::MainWindow _widget;
|
||||
const std::unique_ptr<Adaptive> _adaptive;
|
||||
|
|
Loading…
Add table
Reference in a new issue