Compare commits

..

80 Commits

Author SHA1 Message Date
John Preston
55e494f55a Beta version 2.7.9.
- Added "Enable noise suppression" option to group calls Settings.
- Fix media viewer with Retina + Non-Retina dual monitor setup on macOS.
- Several bug and crash fixes.
2021-06-17 12:11:08 +04:00
John Preston
0b4605a656 Don't pass Quality::Medium for screencast to tgcalls. 2021-06-17 12:03:26 +04:00
John Preston
18a86e500b Update tgcalls and tg_owt. 2021-06-17 11:55:10 +04:00
John Preston
e19af1257c Improve video in voice chats controls layout. 2021-06-17 11:52:53 +04:00
John Preston
e0159e15b2 Close StickerSetBox on error. 2021-06-17 11:06:17 +04:00
23rd
b6e77537e2 Fixed logo size in box of invite link QR code generation. 2021-06-17 10:57:46 +04:00
23rd
beaa4190eb Removed Q_OBJECT from GroupMembersWidget.
Removed unused onlineCountUpdated since d93c1ccbaa.
2021-06-17 10:57:46 +04:00
23rd
7924979dfb Removed Ui::showPeerHistoryAtItem from facades. 2021-06-17 10:57:46 +04:00
23rd
570ed5691d Added Window::Controller pointer to data of intro widget. 2021-06-17 10:57:45 +04:00
23rd
c25779b844 Removed showDocument and showPhoto from Media::View::OverlayWidget. 2021-06-17 10:57:45 +04:00
23rd
7304f2b695 Removed Application::showTheme. 2021-06-17 10:57:45 +04:00
23rd
b4bff939b1 Removed showDocument and showPhoto from Application. 2021-06-17 10:57:45 +04:00
23rd
1f816c249b Replaced DocumentOpenClickHandler. 2021-06-17 10:57:45 +04:00
23rd
8591d58798 Added ability to show content from Controller for Shared Media. 2021-06-17 10:57:45 +04:00
23rd
9290cd3a16 Added SessionController pointer to Media::View::OverlayWidget. 2021-06-17 10:57:45 +04:00
23rd
dc0aaec4a4 Added ability to show document from Controller for sections. 2021-06-17 10:57:45 +04:00
23rd
eefa7263b5 Added ability to show photo from Controller for sections. 2021-06-17 10:57:45 +04:00
23rd
7885be4a94 Added ability to show content from Controller for inline results. 2021-06-17 10:57:45 +04:00
23rd
583c3d3429 Moved static functions from DocumentData to separated file. 2021-06-17 10:57:45 +04:00
23rd
6d0d399250 Added initial ability to show documents in OverlayWidget from Controller. 2021-06-17 10:57:45 +04:00
23rd
0e89c93993 Added initial ability to show content in OverlayWidget from Controller. 2021-06-17 10:57:45 +04:00
23rd
b422ec025e Removed Ui::show from classes that have pointer to Controller. 2021-06-17 10:57:45 +04:00
John Preston
c8535acad8 Fix crash in hunspell initialization. 2021-06-17 10:11:08 +04:00
John Preston
e2a97e2ae9 Fix possible crash in media viewer. 2021-06-17 10:09:22 +04:00
John Preston
77a019325d Show information about unsupported gradient backgrounds. 2021-06-16 11:30:33 +04:00
23rd
115dc460ac Removed unused variables from LastCrashedWindow. 2021-06-16 09:31:32 +03:00
23rd
3df1a73cf5 Removed Q_OBJECT from LastCrashedWindow. 2021-06-16 09:31:32 +03:00
23rd
5cf69366d1 Removed Q_OBJECT from NetworkSettingsWindow. 2021-06-16 09:31:32 +03:00
23rd
8c2b1168af Fixed background color of input fields in crash reports with dark theme. 2021-06-16 09:31:32 +03:00
23rd
a425024f21 Fixed userpic updating of pinned peers in touchbar. 2021-06-16 09:31:32 +03:00
23rd
e85026ec46 Removed observable in Intro::details::Step. 2021-06-16 09:31:32 +03:00
23rd
1c6e2eae04 Removed unused enum from local legacy storage settings scheme. 2021-06-16 09:31:32 +03:00
23rd
4db5624beb Completely removed Global namespace. 2021-06-16 09:31:32 +03:00
23rd
6d08542afa Moved proxy global variables from facades to core settings. 2021-06-16 09:31:32 +03:00
23rd
707b36dc12 Moved DBIWorkMode to Core::Settings. 2021-06-16 09:31:32 +03:00
23rd
da3e140069 Moved DBINotifyView to Core::Settings. 2021-06-16 09:31:32 +03:00
23rd
5334372671 Moved WorkMode global variable from facades to core settings. 2021-06-16 09:31:32 +03:00
23rd
16db8468fa Moved ScreenIsLocked variable from facades to application. 2021-06-16 09:31:32 +03:00
23rd
2ed3543b53 Renamed class back from AdaptiveModern to Adaptive. 2021-06-16 09:31:32 +03:00
23rd
5b4d442799 Removed Adaptive namespace and related global variables from facades. 2021-06-16 09:31:32 +03:00
23rd
9669a8a44a Moved Core::Settings:chatWide to Window::Adaptive. 2021-06-16 09:31:32 +03:00
23rd
80fe2f57e9 Removed Adaptive namespace from Window::Controller and MainWidget. 2021-06-16 09:31:32 +03:00
23rd
824fbc21e8 Removed Adaptive namespace from peer context menu. 2021-06-16 09:31:32 +03:00
23rd
bf7f117323 Removed Adaptive namespace from Window::HistoryHider. 2021-06-16 09:31:32 +03:00
23rd
9b488f03a1 Removed Adaptive namespace from Settings::Chat. 2021-06-16 09:31:32 +03:00
23rd
295a863d69 Removed Adaptive namespace from Profile::BackButton. 2021-06-16 09:31:32 +03:00
23rd
0d814066d6 Removed Adaptive namespace from top bar widgets. 2021-06-16 09:31:32 +03:00
23rd
1af8e89eb9 Removed Adaptive namespace from HistoryWidget. 2021-06-16 09:31:32 +03:00
23rd
7cf79e1f8a Removed Adaptive namespace from sections. 2021-06-16 09:31:32 +03:00
23rd
019fd83c8a Removed Adaptive namespace from Dialogs::Widget. 2021-06-16 09:31:32 +03:00
23rd
65779ec37e Removed Adaptive namespace from FieldAutocomplete. 2021-06-16 09:31:32 +03:00
23rd
2d90a06078 Added new Adaptive class to replace legacy Adaptive namespace.
Temporarily named class as AdaptiveModern.
2021-06-16 09:31:32 +03:00
23rd
d2c8780c0f Removed NotificationsDemoIsShown global variable from facades. 2021-06-16 09:31:32 +03:00
23rd
54dd63d61a Removed LocalPasscode global variable from facades. 2021-06-16 09:31:32 +03:00
23rd
7852c82eab Simplified updating of autolock time in Settings::PrivacySecurity. 2021-06-16 09:31:32 +03:00
23rd
77c8bf8176 Removed PeerChooseCancel global variable from facades. 2021-06-16 09:31:32 +03:00
23rd
daa14466e5 Replaced observable in Lang::CloudManager with rpl. 2021-06-16 09:31:32 +03:00
23rd
aad38c2809 Replaced observable in Window::Notifications::System with rpl. 2021-06-16 09:31:32 +03:00
23rd
2c50d3d87b Replaced observable in Intro::details::Data with rpl. 2021-06-16 09:31:32 +03:00
23rd
0fe7c07007 Replaced observable with rpl in FixedBar of admin log. 2021-06-16 09:31:32 +03:00
23rd
c22d200c17 Removed unused observable trackFinished from Media::Audio::Instance. 2021-06-16 09:31:32 +03:00
23rd
9e6afa0d4e Removed observable dragFinished from MainWindow. 2021-06-16 09:31:32 +03:00
23rd
3340b2dc03 Replaced observable in Dialogs::InnerWidget with rpl. 2021-06-16 09:31:32 +03:00
23rd
386fae952b Replaced observable in SessionController with rpl. 2021-06-16 09:31:32 +03:00
23rd
a164cb9480 Removed unused observable passcodedChanged from Application. 2021-06-16 09:31:32 +03:00
23rd
bc9b288617 Replaced observable in StickersBox with rpl. 2021-06-16 09:31:32 +03:00
23rd
5c7229f875 Replaced observable in EditColorBox with rpl. 2021-06-16 09:31:31 +03:00
John Preston
658d5a1322 Fix move between Retina / Non-Retina. 2021-06-16 10:30:08 +04:00
John Preston
52e841ec29 Select correct quality for incoming screencast. 2021-06-16 08:59:15 +04:00
John Preston
df28da4d97 Show "Video is paused" in wide panel mode. 2021-06-15 16:49:53 +04:00
John Preston
8dac6896d6 Set Send/Receive buffer size for download TCP sockets. 2021-06-15 16:45:48 +04:00
John Preston
f18e157e46 Add video placeholder if can't receive it. 2021-06-15 14:30:51 +04:00
John Preston
b2bf8244dd Add "Enable noise suppression" setting to group calls. 2021-06-15 12:33:02 +04:00
John Preston
4e0355d09f Fix semi-transparent .webp in media viewer. 2021-06-14 15:28:39 +04:00
John Preston
7059336ff0 Show red mute icon for force-muted. 2021-06-14 15:15:33 +04:00
John Preston
94f10ce72e Fix dropping self level around mute button. 2021-06-14 14:57:25 +04:00
John Preston
68be54288c Fix working using OpenGLES / ANGLE. 2021-06-14 12:16:00 +04:00
John Preston
10636d931f Validate video speed before applying. 2021-06-14 11:22:57 +04:00
John Preston
3b1aa55d21 Don't send OpenGL initialization crash reports. 2021-06-14 11:22:39 +04:00
mid-kid
37f59095f4 Fix building with LINK_TO_GTK 2021-06-12 15:08:11 +04:00
238 changed files with 3659 additions and 2028 deletions

View File

@@ -373,6 +373,8 @@ PRIVATE
core/core_cloud_password.h
core/core_settings.cpp
core/core_settings.h
core/core_settings_proxy.cpp
core/core_settings_proxy.h
core/crash_report_window.cpp
core/crash_report_window.h
core/crash_reports.cpp
@@ -420,6 +422,8 @@ PRIVATE
data/data_document.h
data/data_document_media.cpp
data/data_document_media.h
data/data_document_resolver.cpp
data/data_document_resolver.h
data/data_drafts.cpp
data/data_drafts.h
data/data_folder.cpp
@@ -803,6 +807,7 @@ PRIVATE
media/view/media_view_playback_controls.h
media/view/media_view_playback_progress.cpp
media/view/media_view_playback_progress.h
media/view/media_view_open_common.h
mtproto/config_loader.cpp
mtproto/config_loader.h
mtproto/connection_abstract.cpp
@@ -1086,6 +1091,8 @@ PRIVATE
window/section_memento.h
window/section_widget.cpp
window/section_widget.h
window/window_adaptive.cpp
window/window_adaptive.h
window/window_connecting_widget.cpp
window/window_connecting_widget.h
window/window_controller.cpp

View File

@@ -497,6 +497,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_background_text1" = "Ah, you kids today with techno music! You should enjoy the classics, like Hasselhoff!";
"lng_background_text2" = "I can't even take you seriously right now.";
"lng_background_bad_link" = "This background link appears to be invalid.";
"lng_background_gradient_unsupported" = "Telegram Desktop doesn't support gradient backgrounds yet.";
"lng_background_apply" = "Apply";
"lng_background_share" = "Share";
"lng_background_link_copied" = "Link copied to clipboard";
@@ -2057,6 +2058,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_group_call_ptt_delay_s" = "{amount}s";
"lng_group_call_ptt_delay" = "Push to Talk release delay: {delay}";
"lng_group_call_share" = "Share Invite Link";
"lng_group_call_noise_suppression" = "Enable Noise Suppression";
"lng_group_call_limit#one" = "Video is only available\nfor the first {count} member";
"lng_group_call_limit#other" = "Video is only available\nfor the first {count} members";
"lng_group_call_video_paused" = "Video is paused";
"lng_group_call_share_speaker" = "Users with this link can speak";
"lng_group_call_copy_speaker_link" = "Copy Speaker Link";
"lng_group_call_copy_listener_link" = "Copy Listener Link";

View File

@@ -9,7 +9,7 @@
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
ProcessorArchitecture="ARCHITECTURE"
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
Version="2.7.8.0" />
Version="2.7.9.0" />
<Properties>
<DisplayName>Telegram Desktop</DisplayName>
<PublisherDisplayName>Telegram Messenger LLP</PublisherDisplayName>

View File

@@ -44,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 2,7,8,0
PRODUCTVERSION 2,7,8,0
FILEVERSION 2,7,9,0
PRODUCTVERSION 2,7,9,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -62,10 +62,10 @@ BEGIN
BEGIN
VALUE "CompanyName", "Telegram FZ-LLC"
VALUE "FileDescription", "Telegram Desktop"
VALUE "FileVersion", "2.7.8.0"
VALUE "FileVersion", "2.7.9.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2021"
VALUE "ProductName", "Telegram Desktop"
VALUE "ProductVersion", "2.7.8.0"
VALUE "ProductVersion", "2.7.9.0"
END
END
BLOCK "VarFileInfo"

View File

@@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 2,7,8,0
PRODUCTVERSION 2,7,8,0
FILEVERSION 2,7,9,0
PRODUCTVERSION 2,7,9,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -53,10 +53,10 @@ BEGIN
BEGIN
VALUE "CompanyName", "Telegram FZ-LLC"
VALUE "FileDescription", "Telegram Desktop Updater"
VALUE "FileVersion", "2.7.8.0"
VALUE "FileVersion", "2.7.9.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2021"
VALUE "ProductName", "Telegram Desktop"
VALUE "ProductVersion", "2.7.8.0"
VALUE "ProductVersion", "2.7.9.0"
END
END
BLOCK "VarFileInfo"

View File

@@ -36,10 +36,12 @@ void AttachedStickers::request(
return;
}
if (result.v.isEmpty()) {
Ui::show(Box<InformBox>(tr::lng_stickers_not_found(tr::now)));
strongController->show(
Box<InformBox>(tr::lng_stickers_not_found(tr::now)));
return;
} else if (result.v.size() > 1) {
Ui::show(Box<StickersBox>(strongController, result));
strongController->show(
Box<StickersBox>(strongController, result));
return;
}
// Single attached sticker pack.
@@ -52,12 +54,15 @@ void AttachedStickers::request(
const auto setId = (setData->vid().v && setData->vaccess_hash().v)
? MTP_inputStickerSetID(setData->vid(), setData->vaccess_hash())
: MTP_inputStickerSetShortName(setData->vshort_name());
Ui::show(
strongController->show(
Box<StickerSetBox>(strongController, setId),
Ui::LayerOption::KeepOther);
}).fail([=](const MTP::Error &error) {
_requestId = 0;
Ui::show(Box<InformBox>(tr::lng_stickers_not_found(tr::now)));
if (const auto strongController = weak.get()) {
strongController->show(
Box<InformBox>(tr::lng_stickers_not_found(tr::now)));
}
}).send();
}

View File

@@ -34,7 +34,11 @@ void CheckChatInvite(
session->api().checkChatInvite(hash, [=](const MTPChatInvite &result) {
Core::App().hideMediaView();
result.match([=](const MTPDchatInvite &data) {
const auto box = Ui::show(Box<ConfirmInviteBox>(
const auto strongController = weak.get();
if (!strongController) {
return;
}
const auto box = strongController->show(Box<ConfirmInviteBox>(
session,
data,
invitePeekChannel,
@@ -80,7 +84,10 @@ void CheckChatInvite(
return;
}
Core::App().hideMediaView();
Ui::show(Box<InformBox>(tr::lng_group_invite_bad_link(tr::now)));
if (const auto strong = weak.get()) {
strong->show(
Box<InformBox>(tr::lng_group_invite_bad_link(tr::now)));
}
});
}

View File

@@ -212,6 +212,11 @@ ApiWrap::ApiWrap(not_null<Main::Session*> session)
}, _session->lifetime());
setupSupportMode();
Core::App().settings().proxy().connectionTypeValue(
) | rpl::start_with_next([=] {
refreshTopPromotion();
}, _session->lifetime());
});
}
@@ -261,10 +266,10 @@ void ApiWrap::refreshTopPromotion() {
return;
}
const auto key = [&]() -> std::pair<QString, uint32> {
if (Global::ProxySettings() != MTP::ProxyData::Settings::Enabled) {
if (!Core::App().settings().proxy().isEnabled()) {
return {};
}
const auto &proxy = Global::SelectedProxy();
const auto &proxy = Core::App().settings().proxy().selected();
if (proxy.type != MTP::ProxyData::Type::Mtproto) {
return {};
}

View File

@@ -12,7 +12,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "core/application.h"
#include "mainwindow.h"
#include "ui/widgets/checkbox.h"
#include "facades.h"
#include "styles/style_layers.h"
#include "styles/style_boxes.h"
@@ -45,7 +44,6 @@ void AutoLockBox::prepare() {
void AutoLockBox::durationChanged(int seconds) {
Core::App().settings().setAutoLock(seconds);
Core::App().saveSettingsDelayed();
Global::RefLocalPasscodeChanged().notify();
Core::App().checkAutoLock();
closeBox();

View File

@@ -151,7 +151,7 @@ void BackgroundBox::prepare() {
_inner->chooseEvents(
) | rpl::start_with_next([=](const Data::WallPaper &paper) {
Ui::show(
_controller->show(
Box<BackgroundPreviewBox>(_controller, paper),
Ui::LayerOption::KeepOther);
}, _inner->lifetime());
@@ -176,7 +176,7 @@ void BackgroundBox::removePaper(const Data::WallPaper &paper) {
paper.mtpSettings()
)).send();
};
Ui::show(
_controller->show(
Box<ConfirmBox>(
tr::lng_background_sure_delete(tr::now),
tr::lng_selected_delete(tr::now),

View File

@@ -23,6 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_user.h"
#include "data/data_document.h"
#include "data/data_document_media.h"
#include "data/data_document_resolver.h"
#include "data/data_file_origin.h"
#include "base/unixtime.h"
#include "boxes/confirm_box.h"
@@ -769,23 +770,25 @@ bool BackgroundPreviewBox::Start(
const QString &slug,
const QMap<QString, QString> &params) {
if (const auto paper = Data::WallPaper::FromColorSlug(slug)) {
Ui::show(Box<BackgroundPreviewBox>(
controller->show(Box<BackgroundPreviewBox>(
controller,
paper->withUrlParams(params)));
return true;
}
if (!IsValidWallPaperSlug(slug)) {
Ui::show(Box<InformBox>(tr::lng_background_bad_link(tr::now)));
controller->show(
Box<InformBox>(tr::lng_background_bad_link(tr::now)));
return false;
}
controller->session().api().requestWallPaper(slug, crl::guard(controller, [=](
const Data::WallPaper &result) {
Ui::show(Box<BackgroundPreviewBox>(
controller->show(Box<BackgroundPreviewBox>(
controller,
result.withUrlParams(params)));
}), [](const MTP::Error &error) {
Ui::show(Box<InformBox>(tr::lng_background_bad_link(tr::now)));
});
}), crl::guard(controller, [=](const MTP::Error &error) {
controller->show(
Box<InformBox>(tr::lng_background_bad_link(tr::now)));
}));
return true;
}

View File

@@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/qthelp_url.h"
#include "base/call_delayed.h"
#include "core/application.h"
#include "core/core_settings.h"
#include "main/main_account.h"
#include "mtproto/facade.h"
#include "ui/widgets/checkbox.h"
@@ -27,7 +28,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/effects/radial_animation.h"
#include "ui/text/text_options.h"
#include "ui/basic_click_handlers.h"
#include "facades.h"
#include "styles/style_layers.h"
#include "styles/style_boxes.h"
#include "styles/style_chat_helpers.h"
@@ -186,7 +186,10 @@ class ProxiesBox : public Ui::BoxContent {
public:
using View = ProxiesBoxController::ItemView;
ProxiesBox(QWidget*, not_null<ProxiesBoxController*> controller);
ProxiesBox(
QWidget*,
not_null<ProxiesBoxController*> controller,
Core::SettingsProxy &settings);
protected:
void prepare() override;
@@ -201,6 +204,7 @@ private:
void refreshProxyForCalls();
not_null<ProxiesBoxController*> _controller;
Core::SettingsProxy &_settings;
QPointer<Ui::Checkbox> _tryIPv6;
std::shared_ptr<Ui::RadioenumGroup<ProxyData::Settings>> _proxySettings;
QPointer<Ui::SlideWrap<Ui::Checkbox>> _proxyForCalls;
@@ -566,8 +570,10 @@ void ProxyRow::showMenu() {
ProxiesBox::ProxiesBox(
QWidget*,
not_null<ProxiesBoxController*> controller)
not_null<ProxiesBoxController*> controller,
Core::SettingsProxy &settings)
: _controller(controller)
, _settings(settings)
, _initialWrap(this) {
_controller->views(
) | rpl::start_with_next([=](View &&view) {
@@ -591,11 +597,11 @@ void ProxiesBox::setupContent() {
object_ptr<Ui::Checkbox>(
inner,
tr::lng_connection_try_ipv6(tr::now),
Global::TryIPv6()),
_settings.tryIPv6()),
st::proxyTryIPv6Padding);
_proxySettings
= std::make_shared<Ui::RadioenumGroup<ProxyData::Settings>>(
Global::ProxySettings());
_settings.settings());
inner->add(
object_ptr<Ui::Radioenum<ProxyData::Settings>>(
inner,
@@ -623,7 +629,7 @@ void ProxiesBox::setupContent() {
object_ptr<Ui::Checkbox>(
inner,
tr::lng_proxy_use_for_calls(tr::now),
Global::UseProxyForCalls()),
_settings.useProxyForCalls()),
style::margins(
0,
st::proxyUsePadding.top(),
@@ -652,7 +658,7 @@ void ProxiesBox::setupContent() {
_proxySettings->setChangedCallback([=](ProxyData::Settings value) {
if (!_controller->setProxySettings(value)) {
_proxySettings->setValue(Global::ProxySettings());
_proxySettings->setValue(_settings.settings());
addNewProxy();
}
refreshProxyForCalls();
@@ -1051,20 +1057,22 @@ void ProxyBox::addLabel(
ProxiesBoxController::ProxiesBoxController(not_null<Main::Account*> account)
: _account(account)
, _settings(Core::App().settings().proxy())
, _saveTimer([] { Local::writeSettings(); }) {
_list = ranges::views::all(
Global::ProxiesList()
_settings.list()
) | ranges::views::transform([&](const ProxyData &proxy) {
return Item{ ++_idCounter, proxy };
}) | ranges::to_vector;
subscribe(Global::RefConnectionTypeChanged(), [=] {
_proxySettingsChanges.fire_copy(Global::ProxySettings());
const auto i = findByProxy(Global::SelectedProxy());
_settings.connectionTypeChanges(
) | rpl::start_with_next([=] {
_proxySettingsChanges.fire_copy(_settings.settings());
const auto i = findByProxy(_settings.selected());
if (i != end(_list)) {
updateView(*i);
}
});
}, _lifetime);
for (auto &item : _list) {
refreshChecker(item);
@@ -1112,7 +1120,7 @@ void ProxiesBoxController::ShowApplyConfirmation(
? "\n\n" + tr::lng_proxy_sponsor_warning(tr::now)
: QString());
auto callback = [=](Fn<void()> &&close) {
auto &proxies = Global::RefProxiesList();
auto &proxies = Core::App().settings().proxy().list();
if (!ranges::contains(proxies, proxy)) {
proxies.push_back(proxy);
}
@@ -1139,7 +1147,7 @@ void ProxiesBoxController::ShowApplyConfirmation(
auto ProxiesBoxController::proxySettingsValue() const
-> rpl::producer<ProxyData::Settings> {
return _proxySettingsChanges.events_starting_with_copy(
Global::ProxySettings()
_settings.settings()
) | rpl::distinct_until_changed();
}
@@ -1150,6 +1158,7 @@ void ProxiesBoxController::refreshChecker(Item &item) {
: Variants::Tcp;
const auto mtproto = &_account->mtp();
const auto dcId = mtproto->mainDcId();
const auto forFiles = false;
item.state = ItemState::Checking;
const auto setup = [&](Checker &checker, const bytes::vector &secret) {
@@ -1168,7 +1177,8 @@ void ProxiesBoxController::refreshChecker(Item &item) {
item.data.host,
item.data.port,
secret,
dcId);
dcId,
forFiles);
item.checkerv6 = nullptr;
} else {
const auto options = mtproto->dcOptions().lookup(
@@ -1180,7 +1190,8 @@ void ProxiesBoxController::refreshChecker(Item &item) {
Variants::Address address) {
const auto &list = options.data[address][type];
if (list.empty()
|| (address == Variants::IPv6 && !Global::TryIPv6())) {
|| ((address == Variants::IPv6)
&& !Core::App().settings().proxy().tryIPv6())) {
checker = nullptr;
return;
}
@@ -1190,7 +1201,8 @@ void ProxiesBoxController::refreshChecker(Item &item) {
QString::fromStdString(endpoint.ip),
endpoint.port,
endpoint.secret,
dcId);
dcId,
forFiles);
};
connect(item.checker, Variants::IPv4);
connect(item.checkerv6, Variants::IPv6);
@@ -1241,7 +1253,7 @@ object_ptr<Ui::BoxContent> ProxiesBoxController::CreateOwningBox(
}
object_ptr<Ui::BoxContent> ProxiesBoxController::create() {
auto result = Box<ProxiesBox>(this);
auto result = Box<ProxiesBox>(this, _settings);
for (const auto &item : _list) {
updateView(item);
}
@@ -1279,14 +1291,13 @@ void ProxiesBoxController::shareItem(int id) {
void ProxiesBoxController::applyItem(int id) {
auto item = findById(id);
if ((Global::ProxySettings() == ProxyData::Settings::Enabled)
&& Global::SelectedProxy() == item->data) {
if (_settings.isEnabled() && (_settings.selected() == item->data)) {
return;
} else if (item->deleted) {
return;
}
auto j = findByProxy(Global::SelectedProxy());
auto j = findByProxy(_settings.selected());
Core::App().setCurrentProxy(
item->data,
@@ -1304,12 +1315,13 @@ void ProxiesBoxController::setDeleted(int id, bool deleted) {
item->deleted = deleted;
if (deleted) {
auto &proxies = Global::RefProxiesList();
auto &proxies = _settings.list();
proxies.erase(ranges::remove(proxies, item->data), end(proxies));
if (item->data == Global::SelectedProxy()) {
_lastSelectedProxy = base::take(Global::RefSelectedProxy());
if (Global::ProxySettings() == ProxyData::Settings::Enabled) {
if (item->data == _settings.selected()) {
_lastSelectedProxy = _settings.selected();
_settings.setSelected(MTP::ProxyData());
if (_settings.isEnabled()) {
_lastSelectedProxyUsed = true;
Core::App().setCurrentProxy(
ProxyData(),
@@ -1320,7 +1332,7 @@ void ProxiesBoxController::setDeleted(int id, bool deleted) {
}
}
} else {
auto &proxies = Global::RefProxiesList();
auto &proxies = _settings.list();
if (ranges::find(proxies, item->data) == end(proxies)) {
auto insertBefore = item + 1;
while (insertBefore != end(_list) && insertBefore->deleted) {
@@ -1332,15 +1344,15 @@ void ProxiesBoxController::setDeleted(int id, bool deleted) {
proxies.insert(insertBeforeIt, item->data);
}
if (!Global::SelectedProxy() && _lastSelectedProxy == item->data) {
Assert(Global::ProxySettings() != ProxyData::Settings::Enabled);
if (!_settings.selected() && _lastSelectedProxy == item->data) {
Assert(!_settings.isEnabled());
if (base::take(_lastSelectedProxyUsed)) {
Core::App().setCurrentProxy(
base::take(_lastSelectedProxy),
ProxyData::Settings::Enabled);
} else {
Global::SetSelectedProxy(base::take(_lastSelectedProxy));
_settings.setSelected(base::take(_lastSelectedProxy));
}
}
}
@@ -1368,7 +1380,7 @@ object_ptr<Ui::BoxContent> ProxiesBoxController::editItemBox(int id) {
void ProxiesBoxController::replaceItemWith(
std::vector<Item>::iterator which,
std::vector<Item>::iterator with) {
auto &proxies = Global::RefProxiesList();
auto &proxies = _settings.list();
proxies.erase(ranges::remove(proxies, which->data), end(proxies));
_views.fire({ which->id });
@@ -1388,7 +1400,7 @@ void ProxiesBoxController::replaceItemValue(
restoreItem(which->id);
}
auto &proxies = Global::RefProxiesList();
auto &proxies = _settings.list();
const auto i = ranges::find(proxies, which->data);
Assert(i != end(proxies));
*i = proxy;
@@ -1419,7 +1431,7 @@ object_ptr<Ui::BoxContent> ProxiesBoxController::addNewItemBox() {
}
void ProxiesBoxController::addNewItem(const ProxyData &proxy) {
auto &proxies = Global::RefProxiesList();
auto &proxies = _settings.list();
proxies.push_back(proxy);
_list.push_back({ ++_idCounter, proxy });
@@ -1428,43 +1440,42 @@ void ProxiesBoxController::addNewItem(const ProxyData &proxy) {
}
bool ProxiesBoxController::setProxySettings(ProxyData::Settings value) {
if (Global::ProxySettings() == value) {
if (_settings.settings() == value) {
return true;
} else if (value == ProxyData::Settings::Enabled) {
if (Global::ProxiesList().empty()) {
if (_settings.list().empty()) {
return false;
} else if (!Global::SelectedProxy()) {
Global::SetSelectedProxy(Global::ProxiesList().back());
auto j = findByProxy(Global::SelectedProxy());
} else if (!_settings.selected()) {
_settings.setSelected(_settings.list().back());
auto j = findByProxy(_settings.selected());
if (j != end(_list)) {
updateView(*j);
}
}
}
Core::App().setCurrentProxy(Global::SelectedProxy(), value);
Core::App().setCurrentProxy(_settings.selected(), value);
saveDelayed();
return true;
}
void ProxiesBoxController::setProxyForCalls(bool enabled) {
if (Global::UseProxyForCalls() == enabled) {
if (_settings.useProxyForCalls() == enabled) {
return;
}
Global::SetUseProxyForCalls(enabled);
if ((Global::ProxySettings() == ProxyData::Settings::Enabled)
&& Global::SelectedProxy().supportsCalls()) {
Global::RefConnectionTypeChanged().notify();
_settings.setUseProxyForCalls(enabled);
if (_settings.isEnabled() && _settings.selected().supportsCalls()) {
_settings.connectionTypeChangesNotify();
}
saveDelayed();
}
void ProxiesBoxController::setTryIPv6(bool enabled) {
if (Global::TryIPv6() == enabled) {
if (Core::App().settings().proxy().tryIPv6() == enabled) {
return;
}
Global::SetTryIPv6(enabled);
Core::App().settings().proxy().setTryIPv6(enabled);
_account->mtp().restart();
Global::RefConnectionTypeChanged().notify();
_settings.connectionTypeChangesNotify();
saveDelayed();
}
@@ -1477,7 +1488,7 @@ auto ProxiesBoxController::views() const -> rpl::producer<ItemView> {
}
void ProxiesBoxController::updateView(const Item &item) {
const auto selected = (Global::SelectedProxy() == item.data);
const auto selected = (_settings.selected() == item.data);
const auto deleted = item.deleted;
const auto type = [&] {
switch (item.data.type) {
@@ -1491,8 +1502,7 @@ void ProxiesBoxController::updateView(const Item &item) {
Unexpected("Proxy type in ProxiesBoxController::updateView.");
}();
const auto state = [&] {
if (!selected
|| (Global::ProxySettings() != ProxyData::Settings::Enabled)) {
if (!selected || !_settings.isEnabled()) {
return item.state;
} else if (_account->mtp().dcstate() == MTP::ConnectedState) {
return ItemState::Online;

View File

@@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/timer.h"
#include "base/object_ptr.h"
#include "core/core_settings.h"
#include "mtproto/connection_abstract.h"
#include "mtproto/mtproto_proxy_data.h"
@@ -28,7 +29,7 @@ namespace Main {
class Account;
} // namespace Main
class ProxiesBoxController : public base::Subscriber {
class ProxiesBoxController {
public:
using ProxyData = MTP::ProxyData;
using Type = ProxyData::Type;
@@ -110,6 +111,7 @@ private:
void addNewItem(const ProxyData &proxy);
const not_null<Main::Account*> _account;
Core::SettingsProxy &_settings;
int _idCounter = 0;
std::vector<Item> _list;
rpl::event_stream<ItemView> _views;
@@ -119,4 +121,6 @@ private:
ProxyData _lastSelectedProxy;
bool _lastSelectedProxyUsed = false;
rpl::lifetime _lifetime;
};

View File

@@ -1085,7 +1085,7 @@ object_ptr<Ui::RpWidget> CreatePollBox::setupContent() {
send({ .silent = true });
};
const auto sendScheduled = [=] {
Ui::show(
_controller->show(
HistoryView::PrepareScheduleBox(
this,
SendMenu::Type::Scheduled,

View File

@@ -27,8 +27,8 @@ public:
return _y;
}
base::Observable<void> &changed() {
return _changed;
rpl::producer<> changed() const {
return _changed.events();
}
void setHSB(HSB hsb);
void setRGB(int red, int green, int blue);
@@ -61,7 +61,7 @@ private:
float64 _y = 0.;
bool _choosing = false;
base::Observable<void> _changed;
rpl::event_stream<> _changed;
};
@@ -234,7 +234,7 @@ void EditColorBox::Picker::updateCurrentPoint(QPoint localPosition) {
_x = x;
_y = y;
update();
_changed.notify();
_changed.fire({});
}
}
@@ -284,8 +284,8 @@ public:
};
Slider(QWidget *parent, Direction direction, Type type, QColor color);
base::Observable<void> &changed() {
return _changed;
rpl::producer<> changed() const {
return _changed.events();
}
float64 value() const {
return _value;
@@ -335,7 +335,7 @@ private:
QBrush _transparent;
bool _choosing = false;
base::Observable<void> _changed;
rpl::event_stream<> _changed;
};
@@ -540,7 +540,7 @@ void EditColorBox::Slider::updateCurrentPoint(QPoint localPosition) {
if (_value != value) {
_value = value;
update();
_changed.notify();
_changed.fire({});
}
}
@@ -826,16 +826,14 @@ void EditColorBox::prepare() {
auto height = st::colorEditSkip + st::colorPickerSize + st::colorEditSkip + st::colorSliderWidth + st::colorEditSkip;
setDimensions(st::colorEditWidth, height);
subscribe(_picker->changed(), [=] { updateFromControls(); });
if (_hueSlider) {
subscribe(_hueSlider->changed(), [=] { updateFromControls(); });
}
if (_opacitySlider) {
subscribe(_opacitySlider->changed(), [=] { updateFromControls(); });
}
if (_lightnessSlider) {
subscribe(_lightnessSlider->changed(), [=] { updateFromControls(); });
}
rpl::merge(
_picker->changed(),
(_hueSlider ? _hueSlider->changed() : rpl::never<>()),
(_opacitySlider ? _opacitySlider->changed() : rpl::never<>()),
(_lightnessSlider ? _lightnessSlider->changed() : rpl::never<>())
) | rpl::start_with_next([=] {
updateFromControls();
}, lifetime());
boxClosing() | rpl::start_with_next([=] {
if (_cancelCallback) {

View File

@@ -9,7 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/abstract_box.h"
class EditColorBox : public Ui::BoxContent, private base::Subscriber {
class EditColorBox : public Ui::BoxContent {
public:
enum class Mode {
RGBA,

View File

@@ -165,7 +165,7 @@ void EditPrivacyBox::editExceptions(
}));
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
};
Ui::show(
_window->show(
Box<PeerListBox>(std::move(controller), std::move(initBox)),
Ui::LayerOption::KeepOther);
}

View File

@@ -1166,15 +1166,19 @@ base::binary_guard LanguageBox::Show() {
if (manager.languageList().empty()) {
auto guard = std::make_shared<base::binary_guard>(
result.make_guard());
auto alive = std::make_shared<std::unique_ptr<base::Subscription>>(
std::make_unique<base::Subscription>());
**alive = manager.languageListChanged().add_subscription([=] {
auto lifetime = std::make_shared<rpl::lifetime>();
manager.languageListChanged(
) | rpl::take(
1
) | rpl::start_with_next([=]() mutable {
const auto show = guard->alive();
*alive = nullptr;
if (lifetime) {
base::take(lifetime)->destroy();
}
if (show) {
Ui::show(Box<LanguageBox>());
}
});
}, *lifetime);
} else {
Ui::show(Box<LanguageBox>());
}

View File

@@ -27,7 +27,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "passport/passport_encryption.h"
#include "passport/passport_panel_edit_contact.h"
#include "settings/settings_privacy_security.h"
#include "facades.h"
#include "styles/style_layers.h"
#include "styles/style_passport.h"
#include "styles/style_boxes.h"
@@ -119,7 +118,12 @@ PasscodeBox::PasscodeBox(
, _turningOff(turningOff)
, _about(st::boxWidth - st::boxPadding.left() * 1.5)
, _oldPasscode(this, st::defaultInputField, tr::lng_passcode_enter_old())
, _newPasscode(this, st::defaultInputField, Global::LocalPasscode() ? tr::lng_passcode_enter_new() : tr::lng_passcode_enter_first())
, _newPasscode(
this,
st::defaultInputField,
session->domain().local().hasLocalPasscode()
? tr::lng_passcode_enter_new()
: tr::lng_passcode_enter_first())
, _reenterPasscode(this, st::defaultInputField, tr::lng_passcode_confirm_new())
, _passwordHint(this, st::defaultInputField, tr::lng_cloud_password_hint())
, _recoverEmail(this, st::defaultInputField, tr::lng_cloud_password_email())
@@ -164,7 +168,9 @@ rpl::producer<> PasscodeBox::clearUnconfirmedPassword() const {
}
bool PasscodeBox::currentlyHave() const {
return _cloudPwd ? (!!_cloudFields.curRequest) : Global::LocalPasscode();
return _cloudPwd
? (!!_cloudFields.curRequest)
: _session->domain().local().hasLocalPasscode();
}
bool PasscodeBox::onlyCheckCurrent() const {
@@ -520,7 +526,7 @@ void PasscodeBox::save(bool force) {
return;
}
if (Core::App().domain().local().checkPasscode(old.toUtf8())) {
if (_session->domain().local().checkPasscode(old.toUtf8())) {
cSetPasscodeBadTries(0);
if (_turningOff) pwd = conf = QString();
} else {
@@ -588,7 +594,7 @@ void PasscodeBox::save(bool force) {
closeReplacedBy();
const auto weak = Ui::MakeWeak(this);
cSetPasscodeBadTries(0);
Core::App().domain().local().setPasscode(pwd.toUtf8());
_session->domain().local().setPasscode(pwd.toUtf8());
Core::App().localPasscodeChanged();
if (weak) {
closeBox();

View File

@@ -201,8 +201,10 @@ void SaveSlowmodeSeconds(
void ShowEditPermissions(
not_null<Window::SessionNavigation*> navigation,
not_null<PeerData*> peer) {
const auto box = Ui::show(
Box<EditPeerPermissionsBox>(navigation, peer),
auto content = Box<EditPeerPermissionsBox>(navigation, peer);
const auto box = QPointer<EditPeerPermissionsBox>(content.data());
navigation->parentController()->show(
std::move(content),
Ui::LayerOption::KeepOther);
const auto saving = box->lifetime().make_state<int>(0);
const auto save = [=](
@@ -244,8 +246,10 @@ void ShowEditPermissions(
void ShowEditInviteLinks(
not_null<Window::SessionNavigation*> navigation,
not_null<PeerData*> peer) {
const auto box = Ui::show(
Box<EditPeerPermissionsBox>(navigation, peer),
auto content = Box<EditPeerPermissionsBox>(navigation, peer);
const auto box = QPointer<EditPeerPermissionsBox>(content.data());
navigation->parentController()->show(
std::move(content),
Ui::LayerOption::KeepOther);
const auto saving = box->lifetime().make_state<int>(0);
const auto save = [=](
@@ -612,7 +616,7 @@ object_ptr<Ui::RpWidget> Controller::createStickersEdit() {
tr::lng_group_stickers_add(tr::now),
st::editPeerInviteLinkButton)
)->addClickHandler([=] {
Ui::show(
_navigation->parentController()->show(
Box<StickersBox>(_navigation->parentController(), channel),
Ui::LayerOption::KeepOther);
});
@@ -649,7 +653,7 @@ void Controller::showEditPeerTypeBox(
_usernameSavedValue = publicLink;
refreshHistoryVisibility();
});
Ui::show(
_navigation->parentController()->show(
Box<EditPeerTypeBox>(
_peer,
_channelHasLocationOriginalValue,
@@ -681,7 +685,7 @@ void Controller::showEditLinkedChatBox() {
|| channel->canEditPreHistoryHidden()));
if (const auto chat = *_linkedChatSavedValue) {
*box = Ui::show(
*box = _navigation->parentController()->show(
EditLinkedChatBox(
_navigation,
channel,
@@ -709,7 +713,7 @@ void Controller::showEditLinkedChatBox() {
for (const auto &item : list) {
chats.emplace_back(_peer->owner().processChat(item));
}
*box = Ui::show(
*box = _navigation->parentController()->show(
EditLinkedChatBox(
_navigation,
channel,
@@ -858,7 +862,7 @@ void Controller::fillHistoryVisibilityButton() {
_historyVisibilitySavedValue = checked;
});
const auto buttonCallback = [=] {
Ui::show(
_navigation->parentController()->show(
Box<EditPeerHistoryVisibilityBox>(
_peer,
boxCallback,
@@ -1023,9 +1027,15 @@ void Controller::fillManageSection() {
wrap->entity(),
tr::lng_manage_peer_invite_links(),
rpl::duplicate(count) | ToPositiveNumberString(),
[=] { Ui::show(
Box(ManageInviteLinksBox, _peer, _peer->session().user(), 0, 0),
Ui::LayerOption::KeepOther);
[=] {
_navigation->parentController()->show(
Box(
ManageInviteLinksBox,
_peer,
_peer->session().user(),
0,
0),
Ui::LayerOption::KeepOther);
},
st::infoIconInviteLinks);
@@ -1520,7 +1530,7 @@ void Controller::deleteWithConfirmation() {
const auto deleteCallback = crl::guard(this, [=] {
deleteChannel();
});
Ui::show(
_navigation->parentController()->show(
Box<ConfirmBox>(
text,
tr::lng_box_delete(tr::now),

View File

@@ -133,8 +133,8 @@ QImage QrExact(const Qr::Data &data, int pixel, QColor color) {
skip,
skip,
Intro::details::TelegramLogoImage().scaled(
logoSize,
logoSize,
logoSize * cIntRetinaFactor(),
logoSize * cIntRetinaFactor(),
Qt::IgnoreAspectRatio,
Qt::SmoothTransformation));
}

View File

@@ -1002,7 +1002,7 @@ void SendFilesBox::sendScheduled() {
? SendMenu::Type::ScheduledToUser
: _sendMenuType;
const auto callback = [=](Api::SendOptions options) { send(options); };
Ui::show(
_controller->show(
HistoryView::PrepareScheduleBox(this, type, callback),
Ui::LayerOption::KeepOther);
}

View File

@@ -63,12 +63,14 @@ public:
bool loaded() const;
bool notInstalled() const;
bool official() const;
rpl::producer<TextWithEntities> title() const;
QString shortName() const;
[[nodiscard]] rpl::producer<TextWithEntities> title() const;
[[nodiscard]] QString shortName() const;
void install();
rpl::producer<uint64> setInstalled() const;
rpl::producer<> updateControls() const;
[[nodiscard]] rpl::producer<uint64> setInstalled() const;
[[nodiscard]] rpl::producer<> updateControls() const;
[[nodiscard]] rpl::producer<Error> errors() const;
~Inner();
@@ -137,6 +139,7 @@ private:
rpl::event_stream<uint64> _setInstalled;
rpl::event_stream<> _updateControls;
rpl::event_stream<Error> _errors;
};
@@ -153,7 +156,7 @@ QPointer<Ui::BoxContent> StickerSetBox::Show(
not_null<DocumentData*> document) {
if (const auto sticker = document->sticker()) {
if (sticker->set.type() != mtpc_inputStickerSetEmpty) {
return Ui::show(
return controller->show(
Box<StickerSetBox>(controller, sticker->set),
Ui::LayerOption::KeepOther).data();
}
@@ -186,6 +189,11 @@ void StickerSetBox::prepare() {
_controller->session().api().stickerSetInstalled(setId);
closeBox();
}, lifetime());
_inner->errors(
) | rpl::start_with_next([=](Error error) {
handleError(error);
}, lifetime());
}
void StickerSetBox::addStickers() {
@@ -198,6 +206,20 @@ void StickerSetBox::copyStickersLink() {
QGuiApplication::clipboard()->setText(url);
}
void StickerSetBox::handleError(Error error) {
const auto guard = gsl::finally(crl::guard(this, [=] {
closeBox();
}));
switch (error) {
case Error::NotFound:
_controller->show(
Box<InformBox>(tr::lng_stickers_not_found(tr::now)));
break;
default: Unexpected("Error in StickerSetBox::handleError.");
}
}
void StickerSetBox::archiveStickers() {
const auto weak = base::make_weak(_controller.get());
const auto setId = _set.c_inputStickerSetID().vid().v;
@@ -211,7 +233,7 @@ void StickerSetBox::archiveStickers() {
}
if (result.type() == mtpc_messages_stickerSetInstallResultSuccess) {
Ui::Toast::Show(tr::lng_stickers_has_been_archived(tr::now));
const auto &session = controller->session();
auto &order = session.data().stickers().setsOrderRef();
const auto index = order.indexOf(setId);
@@ -219,10 +241,10 @@ void StickerSetBox::archiveStickers() {
return;
}
order.removeAt(index);
session.local().writeInstalledStickers();
session.local().writeArchivedStickers();
session.data().stickers().notifyUpdated();
}
}).fail([](const MTP::Error &error) {
@@ -324,7 +346,7 @@ StickerSetBox::Inner::Inner(
gotSet(result);
}).fail([=](const MTP::Error &error) {
_loaded = true;
Ui::show(Box<InformBox>(tr::lng_stickers_not_found(tr::now)));
_errors.fire(Error::NotFound);
}).send();
_controller->session().api().updateStickers();
@@ -419,7 +441,7 @@ void StickerSetBox::Inner::gotSet(const MTPmessages_StickerSet &set) {
});
if (_pack.isEmpty()) {
Ui::show(Box<InformBox>(tr::lng_stickers_not_found(tr::now)));
_errors.fire(Error::NotFound);
return;
} else {
int32 rows = _pack.size() / kStickersPanelPerRow + ((_pack.size() % kStickersPanelPerRow) ? 1 : 0);
@@ -439,6 +461,10 @@ rpl::producer<> StickerSetBox::Inner::updateControls() const {
return _updateControls.events();
}
rpl::producer<StickerSetBox::Error> StickerSetBox::Inner::errors() const {
return _errors.events();
}
void StickerSetBox::Inner::installDone(
const MTPmessages_StickerSetInstallResult &result) {
auto &sets = _controller->session().data().stickers().setsRef();
@@ -795,7 +821,7 @@ QString StickerSetBox::Inner::shortName() const {
void StickerSetBox::Inner::install() {
if (isMasksSet()) {
Ui::show(
_controller->show(
Box<InformBox>(tr::lng_stickers_masks_pack(tr::now)),
Ui::LayerOption::KeepOther);
return;
@@ -808,7 +834,7 @@ void StickerSetBox::Inner::install() {
)).done([=](const MTPmessages_StickerSetInstallResult &result) {
installDone(result);
}).fail([=](const MTP::Error &error) {
Ui::show(Box<InformBox>(tr::lng_stickers_not_found(tr::now)));
_errors.fire(Error::NotFound);
}).send();
}

View File

@@ -38,11 +38,16 @@ protected:
void resizeEvent(QResizeEvent *e) override;
private:
enum class Error {
NotFound,
};
void updateTitleAndButtons();
void updateButtons();
void addStickers();
void copyStickersLink();
void archiveStickers();
void handleError(Error error);
const not_null<Window::SessionController*> _controller;
MTPInputStickerSet _set;

View File

@@ -68,9 +68,7 @@ private:
};
// This class is hold in header because it requires Qt preprocessing.
class StickersBox::Inner
: public Ui::RpWidget
, private base::Subscriber {
class StickersBox::Inner : public Ui::RpWidget {
public:
using Section = StickersBox::Section;
@@ -85,7 +83,9 @@ public:
[[nodiscard]] Main::Session &session() const;
base::Observable<int> scrollToY;
rpl::producer<int> scrollsToY() const {
return _scrollsToY.events();
}
void setInnerFocus();
void saveGroupSet();
@@ -276,6 +276,8 @@ private:
int _above = -1;
rpl::event_stream<int> _draggingScrollDelta;
rpl::event_stream<int> _scrollsToY;
int _minHeight = 0;
int _scrollbar = 0;
@@ -387,9 +389,10 @@ StickersBox::StickersBox(
, _section(Section::Installed)
, _installed(0, this, controller, megagroup)
, _megagroupSet(megagroup) {
subscribe(_installed.widget()->scrollToY, [=](int y) {
_installed.widget()->scrollsToY(
) | rpl::start_with_next([=](int y) {
onScrollToY(y);
});
}, lifetime());
}
StickersBox::StickersBox(
@@ -1589,7 +1592,7 @@ void StickersBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
}();
const auto showSetByRow = [&](const Row &row) {
setSelected(SelectedRow());
Ui::show(
_controller->show(
Box<StickerSetBox>(_controller, row.set->mtpInput()),
Ui::LayerOption::KeepOther);
};
@@ -1898,7 +1901,7 @@ void StickersBox::Inner::rebuild() {
void StickersBox::Inner::setMegagroupSelectedSet(const MTPInputStickerSet &set) {
_megagroupSetInput = set;
rebuild();
scrollToY.notify(0, true);
_scrollsToY.fire(0);
updateSelected();
}

View File

@@ -862,7 +862,7 @@ groupCallButtonSkip: 40px;
groupCallButtonSkipSmall: 5px;
groupCallButtonBottomSkip: 113px;
groupCallButtonBottomSkipSmall: 95px;
groupCallButtonBottomSkipWide: 122px;
groupCallButtonBottomSkipWide: 108px;
groupCallControlsBackMargin: margins(10px, 0px, 10px, 0px);
groupCallControlsBackRadius: 12px;
groupCallMuteBottomSkip: 116px;
@@ -1229,6 +1229,9 @@ groupCallVideoTile: GroupCallVideoTile {
groupCallVideoSmallSkip: 4px;
groupCallVideoLargeSkip: 6px;
groupCallVideoPlaceholderHeight: 212px;
groupCallVideoPlaceholderIconTop: 50px;
groupCallVideoPlaceholderTextTop: 120px;
groupCallTooltip: Tooltip(defaultTooltip) {
textBg: groupCallMembersBg;

View File

@@ -357,7 +357,7 @@ base::unique_qptr<Ui::PopupMenu> BoxController::rowContextMenu(
auto result = base::make_unique_q<Ui::PopupMenu>(parent);
result->addAction(tr::lng_context_delete_selected(tr::now), [=] {
Ui::show(
_window->show(
Box<DeleteMessagesBox>(session, base::duplicate(ids)),
Ui::LayerOption::KeepOther);
});

View File

@@ -28,7 +28,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "webrtc/webrtc_create_adm.h"
#include "data/data_user.h"
#include "data/data_session.h"
#include "facades.h"
#include <tgcalls/Instance.h>
#include <tgcalls/VideoCaptureInterface.h>
@@ -805,16 +804,19 @@ void Call::createAndStartController(const MTPDphoneCall &call) {
AppendServer(descriptor.rtcServers, connection);
}
if (Global::UseProxyForCalls()
&& (Global::ProxySettings() == MTP::ProxyData::Settings::Enabled)) {
const auto &selected = Global::SelectedProxy();
if (selected.supportsCalls() && !selected.host.isEmpty()) {
Assert(selected.type == MTP::ProxyData::Type::Socks5);
descriptor.proxy = std::make_unique<tgcalls::Proxy>();
descriptor.proxy->host = selected.host.toStdString();
descriptor.proxy->port = selected.port;
descriptor.proxy->login = selected.user.toStdString();
descriptor.proxy->password = selected.password.toStdString();
{
auto &settingsProxy = Core::App().settings().proxy();
using ProxyData = MTP::ProxyData;
if (settingsProxy.useProxyForCalls() && settingsProxy.isEnabled()) {
const auto &selected = settingsProxy.selected();
if (selected.supportsCalls() && !selected.host.isEmpty()) {
Assert(selected.type == ProxyData::Type::Socks5);
descriptor.proxy = std::make_unique<tgcalls::Proxy>();
descriptor.proxy->host = selected.host.toStdString();
descriptor.proxy->port = selected.port;
descriptor.proxy->login = selected.user.toStdString();
descriptor.proxy->password = selected.password.toStdString();
}
}
}

View File

@@ -821,6 +821,9 @@ void GroupCall::setState(State state) {
if (const auto call = _peer->groupCall(); call && call->id() == _id) {
call->setInCall();
}
if (!videoIsWorking()) {
refreshHasNotShownVideo();
}
}
if (false
@@ -1043,6 +1046,9 @@ void GroupCall::markEndpointActive(
bool paused) {
if (!endpoint) {
return;
} else if (active && !videoIsWorking()) {
refreshHasNotShownVideo();
return;
}
const auto i = _activeVideoTracks.find(endpoint);
const auto changed = active
@@ -1067,26 +1073,34 @@ void GroupCall::markEndpointActive(
.peer = endpoint.peer,
}).first;
const auto track = i->second.track.get();
if (!track->frameSize().isEmpty()
|| track->state() == Webrtc::VideoState::Paused) {
track->renderNextFrame(
) | rpl::start_with_next([=] {
auto &activeTrack = _activeVideoTracks[endpoint];
const auto size = track->frameSize();
if (size.isEmpty()) {
track->markFrameShown();
} else if (!activeTrack.shown) {
activeTrack.shown = true;
markTrackShown(endpoint, true);
}
activeTrack.trackSize = size;
}, i->second.lifetime);
const auto size = track->frameSize();
i->second.trackSize = size;
if (!size.isEmpty() || paused) {
i->second.shown = true;
shown = true;
} else {
auto hasFrame = track->renderNextFrame() | rpl::map([=] {
return !track->frameSize().isEmpty();
});
auto isPaused = track->stateValue(
) | rpl::map([=](Webrtc::VideoState state) {
return (state == Webrtc::VideoState::Paused);
});
rpl::merge(
std::move(hasFrame),
std::move(isPaused)
) | rpl::filter([=](bool shouldShow) {
return shouldShow;
track->stateValue(
) | rpl::filter([=](Webrtc::VideoState state) {
return (state == Webrtc::VideoState::Paused)
&& !_activeVideoTracks[endpoint].shown;
}) | rpl::start_with_next([=] {
_activeVideoTracks[endpoint].shownTrackingLifetime.destroy();
_activeVideoTracks[endpoint].shown = true;
markTrackShown(endpoint, true);
}, i->second.shownTrackingLifetime);
}, i->second.lifetime);
}
addVideoOutput(i->first.id, { track->sink() });
} else {
@@ -1109,10 +1123,11 @@ void GroupCall::markTrackShown(const VideoEndpoint &endpoint, bool shown) {
const auto changed = shown
? _shownVideoTracks.emplace(endpoint).second
: _shownVideoTracks.remove(endpoint);
if (changed) {
_videoStreamShownUpdates.fire_copy({ endpoint, shown });
if (!changed) {
return;
}
if (shown && changed && endpoint.type == VideoEndpointType::Screen) {
_videoStreamShownUpdates.fire_copy({ endpoint, shown });
if (shown && endpoint.type == VideoEndpointType::Screen) {
crl::on_main(this, [=] {
if (_shownVideoTracks.contains(endpoint)) {
pinVideoEndpoint(endpoint);
@@ -1606,6 +1621,12 @@ void GroupCall::toggleScheduleStartSubscribed(bool subscribed) {
}).send();
}
void GroupCall::setNoiseSuppression(bool enabled) {
if (_instance) {
_instance->setIsNoiseSuppressionEnabled(enabled);
}
}
void GroupCall::addVideoOutput(
const std::string &endpoint,
not_null<Webrtc::VideoTrack*> track) {
@@ -1614,13 +1635,19 @@ void GroupCall::addVideoOutput(
void GroupCall::setMuted(MuteState mute) {
const auto set = [=] {
const auto wasMuted = (muted() == MuteState::Muted)
|| (muted() == MuteState::PushToTalk);
const auto wasRaiseHand = (muted() == MuteState::RaisedHand);
const auto was = muted();
const auto wasSpeaking = (was == MuteState::Active)
|| (was == MuteState::PushToTalk);
const auto wasMuted = (was == MuteState::Muted)
|| (was == MuteState::PushToTalk);
const auto wasRaiseHand = (was == MuteState::RaisedHand);
_muted = mute;
const auto nowMuted = (muted() == MuteState::Muted)
|| (muted() == MuteState::PushToTalk);
const auto nowRaiseHand = (muted() == MuteState::RaisedHand);
const auto now = muted();
const auto nowSpeaking = (now == MuteState::Active)
|| (now == MuteState::PushToTalk);
const auto nowMuted = (now == MuteState::Muted)
|| (now == MuteState::PushToTalk);
const auto nowRaiseHand = (now == MuteState::RaisedHand);
if (wasMuted != nowMuted || wasRaiseHand != nowRaiseHand) {
applyMeInCallLocally();
}
@@ -1628,6 +1655,14 @@ void GroupCall::setMuted(MuteState mute) {
toggleVideo(false);
toggleScreenSharing(std::nullopt);
}
if (wasSpeaking && !nowSpeaking && _joinState.ssrc) {
_levelUpdates.fire(LevelUpdate{
.ssrc = _joinState.ssrc,
.value = 0.f,
.voice = false,
.me = true,
});
}
};
if (mute == MuteState::Active || mute == MuteState::PushToTalk) {
_delegate->groupCallRequestPermissionsOrFail(crl::guard(this, set));
@@ -2157,6 +2192,8 @@ bool GroupCall::tryCreateController() {
return result;
},
.videoContentType = tgcalls::VideoContentType::Generic,
.initialEnableNoiseSuppression
= settings.groupCallNoiseSuppression(),
.requestMediaChannelDescriptions = [=, call = base::make_weak(this)](
const std::vector<uint32_t> &ssrcs,
std::function<void(
@@ -2203,10 +2240,8 @@ bool GroupCall::tryCreateScreencast() {
if (_screenInstance) {
return false;
}
//const auto &settings = Core::App().settings();
const auto weak = base::make_weak(&_screenInstanceGuard);
//const auto myLevel = std::make_shared<tgcalls::GroupLevelValue>();
tgcalls::GroupInstanceDescriptor descriptor = {
.threads = tgcalls::StaticThreads::getThreads(),
.config = tgcalls::GroupConfig{
@@ -2219,20 +2254,6 @@ bool GroupCall::tryCreateScreencast() {
.videoCapture = _screenCapture,
.videoContentType = tgcalls::VideoContentType::Screencast,
};
// if (Logs::DebugEnabled()) {
// auto callLogFolder = cWorkingDir() + qsl("DebugLogs");
// auto callLogPath = callLogFolder + qsl("/last_group_call_log.txt");
// auto callLogNative = QDir::toNativeSeparators(callLogPath);
//#ifdef Q_OS_WIN
// descriptor.config.logPath.data = callLogNative.toStdWString();
//#else // Q_OS_WIN
// const auto callLogUtf = QFile::encodeName(callLogNative);
// descriptor.config.logPath.data.resize(callLogUtf.size());
// ranges::copy(callLogUtf, descriptor.config.logPath.data.begin());
//#endif // Q_OS_WIN
// QFile(callLogPath).remove();
// QDir().mkpath(callLogFolder);
// }
LOG(("Call Info: Creating group screen instance"));
_screenInstance = std::make_unique<tgcalls::GroupInstanceCustomImpl>(
@@ -2403,9 +2424,10 @@ void GroupCall::updateRequestedVideoChannels() {
&& endpoint.type == VideoEndpointType::Screen)
? Quality::Full
: Quality::Thumbnail),
.maxQuality = (video.quality == Group::VideoQuality::Full
.maxQuality = ((video.quality == Group::VideoQuality::Full)
? Quality::Full
: video.quality == Group::VideoQuality::Medium
: (video.quality == Group::VideoQuality::Medium
&& endpoint.type != VideoEndpointType::Screen)
? Quality::Medium
: Quality::Thumbnail),
});
@@ -2425,21 +2447,37 @@ void GroupCall::updateRequestedVideoChannelsDelayed() {
});
}
void GroupCall::refreshHasNotShownVideo() {
if (!_joinState.ssrc || hasNotShownVideo()) {
return;
}
const auto real = lookupReal();
Assert(real != nullptr);
const auto hasVideo = [&](const Data::GroupCallParticipant &data) {
return (data.peer != _joinAs)
&& (!GetCameraEndpoint(data.videoParams).empty()
|| !GetScreenEndpoint(data.videoParams).empty());
};
_hasNotShownVideo = _joinState.ssrc
&& ranges::any_of(real->participants(), hasVideo);
}
void GroupCall::fillActiveVideoEndpoints() {
const auto real = lookupReal();
Assert(real != nullptr);
if (const auto participant = real->participantByPeer(_joinAs)) {
_videoIsWorking = participant->videoJoined;
const auto me = real->participantByPeer(_joinAs);
if (me && me->videoJoined) {
_videoIsWorking = true;
_hasNotShownVideo = false;
} else {
refreshHasNotShownVideo();
_videoIsWorking = false;
}
if (!videoIsWorking()) {
toggleVideo(false);
toggleScreenSharing(std::nullopt);
}
const auto &participants = real->participants();
const auto &large = _videoEndpointLarge.current();
auto largeFound = false;
auto endpoints = _activeVideoTracks | ranges::views::transform([](
@@ -2463,7 +2501,7 @@ void GroupCall::fillActiveVideoEndpoints() {
};
using Type = VideoEndpointType;
if (_videoIsWorking.current()) {
for (const auto &participant : participants) {
for (const auto &participant : real->participants()) {
const auto camera = GetCameraEndpoint(participant.videoParams);
if (camera != _cameraEndpoint
&& camera != _screenEndpoint
@@ -2479,7 +2517,6 @@ void GroupCall::fillActiveVideoEndpoints() {
feedOne({ Type::Screen, participant.peer, screen }, paused);
}
}
const auto pausedState = Webrtc::VideoState::Paused;
feedOne(
{ Type::Camera, _joinAs, cameraSharingEndpoint() },
isCameraPaused());
@@ -2530,6 +2567,11 @@ void GroupCall::audioLevelsUpdated(const tgcalls::GroupLevelsUpdate &data) {
auto check = false;
auto checkNow = false;
const auto now = crl::now();
const auto meMuted = [&] {
const auto state = muted();
return (state != MuteState::Active)
&& (state != MuteState::PushToTalk);
};
for (const auto &[ssrcOrZero, value] : data.updates) {
const auto ssrc = ssrcOrZero ? ssrcOrZero : _joinState.ssrc;
if (!ssrc) {
@@ -2538,11 +2580,12 @@ void GroupCall::audioLevelsUpdated(const tgcalls::GroupLevelsUpdate &data) {
const auto level = value.level;
const auto voice = value.voice;
const auto me = (ssrc == _joinState.ssrc);
const auto ignore = me && meMuted();
_levelUpdates.fire(LevelUpdate{
.ssrc = ssrc,
.value = level,
.voice = voice,
.me = me
.value = ignore ? 0.f : level,
.voice = (!ignore && voice),
.me = me,
});
if (level <= kSpeakLevelThreshold) {
continue;

View File

@@ -235,6 +235,7 @@ public:
}
void startScheduledNow();
void toggleScheduleStartSubscribed(bool subscribed);
void setNoiseSuppression(bool enabled);
bool emitShareScreenError();
bool emitShareCameraError();
@@ -323,9 +324,11 @@ public:
struct VideoTrack {
std::unique_ptr<Webrtc::VideoTrack> track;
rpl::variable<QSize> trackSize;
PeerData *peer = nullptr;
rpl::lifetime shownTrackingLifetime;
rpl::lifetime lifetime;
Group::VideoQuality quality = Group::VideoQuality();
bool shown = false;
[[nodiscard]] explicit operator bool() const {
return (track != nullptr);
@@ -365,6 +368,12 @@ public:
[[nodiscard]] rpl::producer<bool> videoIsWorkingValue() const {
return _videoIsWorking.value();
}
[[nodiscard]] bool hasNotShownVideo() const {
return _hasNotShownVideo.current();
}
[[nodiscard]] rpl::producer<bool> hasNotShownVideoValue() const {
return _hasNotShownVideo.value();
}
void setCurrentAudioDevice(bool input, const QString &deviceId);
void setCurrentVideoDevice(const QString &deviceId);
@@ -513,6 +522,7 @@ private:
void updateRequestedVideoChannels();
void updateRequestedVideoChannelsDelayed();
void fillActiveVideoEndpoints();
void refreshHasNotShownVideo();
void editParticipant(
not_null<PeerData*> participantPeer,
@@ -569,6 +579,7 @@ private:
rpl::variable<MuteState> _muted = MuteState::Muted;
rpl::variable<bool> _canManage = false;
rpl::variable<bool> _videoIsWorking = false;
rpl::variable<bool> _hasNotShownVideo = false;
bool _initialMuteStateSent = false;
bool _acceptFields = false;

View File

@@ -29,6 +29,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "core/application.h" // Core::App().domain, .activeWindow.
#include "main/main_domain.h" // Core::App().domain().activate.
#include "main/main_session.h"
#include "main/main_account.h" // account().appConfig().
#include "main/main_app_config.h" // appConfig().get<double>().
#include "boxes/peers/edit_participants_box.h" // SubscribeToMigration.
#include "window/window_controller.h" // Controller::sessionController.
#include "window/window_session_controller.h"
@@ -41,9 +43,110 @@ namespace {
constexpr auto kKeepRaisedHandStatusDuration = 3 * crl::time(1000);
constexpr auto kShadowMaxAlpha = 74;
constexpr auto kUserpicSizeForBlur = 40;
constexpr auto kUserpicBlurRadius = 8;
using Row = MembersRow;
void SetupVideoPlaceholder(
not_null<Ui::RpWidget*> widget,
not_null<PeerData*> chat) {
struct State {
QImage blurred;
QImage rounded;
InMemoryKey key = {};
std::shared_ptr<Data::CloudImageView> view;
qint64 blurredCacheKey = 0;
};
const auto state = widget->lifetime().make_state<State>();
const auto refreshBlurred = [=] {
const auto key = chat->userpicUniqueKey(state->view);
if (state->key == key && !state->blurred.isNull()) {
return;
}
constexpr auto size = kUserpicSizeForBlur;
state->key = key;
state->blurred = QImage(
QSize(size, size),
QImage::Format_ARGB32_Premultiplied);
{
auto p = Painter(&state->blurred);
auto hq = PainterHighQualityEnabler(p);
chat->paintUserpicSquare(p, state->view, 0, 0, size);
}
state->blurred = Images::BlurLargeImage(
std::move(state->blurred),
kUserpicBlurRadius);
widget->update();
};
const auto refreshRounded = [=](QSize size) {
refreshBlurred();
const auto key = state->blurred.cacheKey();
if (state->rounded.size() == size && state->blurredCacheKey == key) {
return;
}
state->blurredCacheKey = key;
state->rounded = Images::prepare(
state->blurred,
size.width(),
size.width(), // Square
Images::Option::Smooth,
size.width(),
size.height());
{
auto p = QPainter(&state->rounded);
p.fillRect(
0,
0,
size.width(),
size.height(),
QColor(0, 0, 0, Viewport::kShadowMaxAlpha));
}
state->rounded = Images::prepare(
std::move(state->rounded),
size.width(),
size.height(),
(Images::Option::RoundedLarge | Images::Option::RoundedAll),
size.width(),
size.height());
};
chat->loadUserpic();
refreshBlurred();
widget->paintRequest(
) | rpl::start_with_next([=] {
const auto size = QSize(
widget->width(),
widget->height() - st::groupCallVideoSmallSkip);
refreshRounded(size * cIntRetinaFactor());
auto p = QPainter(widget);
const auto inner = QRect(QPoint(), size);
p.drawImage(inner, state->rounded);
st::groupCallPaused.paint(
p,
(size.width() - st::groupCallPaused.width()) / 2,
st::groupCallVideoPlaceholderIconTop,
size.width());
const auto skip = st::groupCallVideoLargeSkip;
const auto limit = chat->session().account().appConfig().get<double>(
"groupcall_video_participants_max",
30.);
p.setPen(st::groupCallVideoTextFg);
const auto text = QRect(
skip,
st::groupCallVideoPlaceholderTextTop,
(size.width() - 2 * skip),
size.height() - st::groupCallVideoPlaceholderTextTop);
p.setFont(st::semiboldFont);
p.drawText(
text,
tr::lng_group_call_limit(tr::now, lt_count, int(limit)),
style::al_top);
}, widget->lifetime());
}
} // namespace
class Members::Controller final
@@ -953,9 +1056,7 @@ void Members::Controller::rowPaintIcon(
: _coloredCrossLine;
const auto color = video
? std::nullopt
: std::make_optional(narrow
? st::groupCallMemberNotJoinedStatus->c
: st::groupCallMemberMutedIcon->c);
: std::make_optional(st::groupCallMemberMutedIcon->c);
line.paint(
p,
left,
@@ -987,9 +1088,7 @@ void Members::Controller::rowPaintIcon(
state.speaking);
const auto iconColor = anim::color(
activeInactiveColor,
(narrow
? st::groupCallMemberNotJoinedStatus
: st::groupCallMemberMutedIcon),
st::groupCallMemberMutedIcon,
state.muted);
const auto color = video
? std::nullopt
@@ -1471,6 +1570,7 @@ Members::Members(
, _layout(_scroll->setOwnedWidget(
object_ptr<Ui::VerticalLayout>(_scroll.data())))
, _videoWrap(_layout->add(object_ptr<Ui::RpWidget>(_layout.get())))
, _videoPlaceholder(std::make_unique<Ui::RpWidget>(_videoWrap.get()))
, _viewport(
std::make_unique<Viewport>(
_videoWrap.get(),
@@ -1708,11 +1808,27 @@ void Members::trackViewportGeometry() {
_scroll->scrollTopValue(
) | rpl::skip(1) | rpl::start_with_next(move, _viewport->lifetime());
_viewport->fullHeightValue(
) | rpl::start_with_next([=](int height) {
_videoWrap->resize(_videoWrap->width(), height);
move();
resize();
rpl::combine(
_layout->widthValue(),
_call->hasNotShownVideoValue()
) | rpl::start_with_next([=](int width, bool has) {
const auto height = has ? st::groupCallVideoPlaceholderHeight : 0;
_videoPlaceholder->setGeometry(0, 0, width, height);
}, _videoPlaceholder->lifetime());
SetupVideoPlaceholder(_videoPlaceholder.get(), _call->peer());
rpl::combine(
_videoPlaceholder->heightValue(),
_viewport->fullHeightValue()
) | rpl::start_with_next([=](int placeholder, int viewport) {
_videoWrap->resize(
_videoWrap->width(),
std::max(placeholder, viewport));
if (viewport > 0) {
move();
resize();
}
}, _viewport->lifetime());
}

View File

@@ -101,6 +101,7 @@ private:
std::unique_ptr<Controller> _listController;
not_null<Ui::VerticalLayout*> _layout;
const not_null<Ui::RpWidget*> _videoWrap;
const std::unique_ptr<Ui::RpWidget> _videoPlaceholder;
std::unique_ptr<Viewport> _viewport;
rpl::variable<Ui::RpWidget*> _addMemberButton = nullptr;
RpWidget *_topSkip = nullptr;

View File

@@ -854,6 +854,7 @@ void Panel::setupVideo(not_null<Viewport*> viewport) {
viewport->add(
endpoint,
VideoTileTrack{ track.track.get(), row },
track.trackSize.value(),
std::move(pinned));
};
for (const auto &[endpoint, track] : _call->activeVideoTracks()) {

View File

@@ -306,6 +306,20 @@ void SettingsBox(
//AddDivider(layout);
//AddSkip(layout);
AddButton(
layout,
tr::lng_group_call_noise_suppression(),
st::groupCallSettingsButton
)->toggleOn(rpl::single(
settings.groupCallNoiseSuppression()
))->toggledChanges(
) | rpl::start_with_next([=](bool enabled) {
Core::App().settings().setGroupCallNoiseSuppression(enabled);
call->setNoiseSuppression(enabled);
Core::App().saveSettingsDelayed();
}, layout->lifetime());
using GlobalShortcut = base::GlobalShortcut;
struct PushToTalkState {
rpl::variable<QString> recordText = tr::lng_group_call_ptt_shortcut();

View File

@@ -225,10 +225,12 @@ void Viewport::setControlsShown(float64 shown) {
void Viewport::add(
const VideoEndpoint &endpoint,
VideoTileTrack track,
rpl::producer<QSize> trackSize,
rpl::producer<bool> pinned) {
_tiles.push_back(std::make_unique<VideoTile>(
endpoint,
track,
std::move(trackSize),
std::move(pinned),
[=] { widget()->update(); }));
@@ -711,11 +713,13 @@ void Viewport::updateTilesGeometryColumn(int outerWidth) {
const auto layoutNext = [&](not_null<VideoTile*> tile) {
const auto size = tile->trackOrUserpicSize();
const auto shown = !size.isEmpty() && _large && tile != _large;
const auto height = shown
? st::groupCallNarrowVideoHeight
: 0;
setTileGeometry(tile, { 0, y + top, outerWidth, height });
top += height ? (height + st::groupCallVideoSmallSkip) : 0;
const auto height = st::groupCallNarrowVideoHeight;
if (!shown) {
tile->hide();
} else {
setTileGeometry(tile, { 0, y + top, outerWidth, height });
top += height + st::groupCallVideoSmallSkip;
}
};
const auto topPeer = _large ? _large->row()->peer().get() : nullptr;
const auto reorderNeeded = [&] {
@@ -758,6 +762,7 @@ void Viewport::setTileGeometry(not_null<VideoTile*> tile, QRect geometry) {
const auto min = std::min(geometry.width(), geometry.height());
const auto kMedium = style::ConvertScale(540);
const auto kSmall = style::ConvertScale(240);
const auto &endpoint = tile->endpoint();
const auto quality = (min >= kMedium)
? VideoQuality::Full
: (min >= kSmall)
@@ -765,7 +770,7 @@ void Viewport::setTileGeometry(not_null<VideoTile*> tile, QRect geometry) {
: VideoQuality::Thumbnail;
if (tile->updateRequestedQuality(quality)) {
_qualityRequests.fire(VideoQualityRequest{
.endpoint = tile->endpoint(),
.endpoint = endpoint,
.quality = quality,
});
}

View File

@@ -39,6 +39,7 @@ enum class VideoQuality;
struct VideoTileTrack {
Webrtc::VideoTrack *track = nullptr;
MembersRow *row = nullptr;
rpl::variable<QSize> trackSize;
[[nodiscard]] explicit operator bool() const {
return track != nullptr;
@@ -77,6 +78,7 @@ public:
void add(
const VideoEndpoint &endpoint,
VideoTileTrack track,
rpl::producer<QSize> trackSize,
rpl::producer<bool> pinned);
void remove(const VideoEndpoint &endpoint);
void showLarge(const VideoEndpoint &endpoint);
@@ -91,6 +93,8 @@ public:
[[nodiscard]] rpl::lifetime &lifetime();
static constexpr auto kShadowMaxAlpha = 80;
private:
struct Textures;
class VideoTile;
@@ -132,8 +136,6 @@ private:
}
};
static constexpr auto kShadowMaxAlpha = 80;
void setup();
[[nodiscard]] bool wide() const;

View File

@@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "webrtc/webrtc_video_track.h"
#include "media/view/media_view_pip.h"
#include "calls/group/calls_group_members_row.h"
#include "lang/lang_keys.h"
#include "ui/gl/gl_shader.h"
#include "data/data_peer.h"
#include "styles/style_calls.h"
@@ -32,7 +33,7 @@ constexpr auto kBlurOpacity = 0.65;
constexpr auto kDitherNoiseAmount = 0.002;
constexpr auto kMinCameraVisiblePart = 0.75;
constexpr auto kQuads = 8;
constexpr auto kQuads = 9;
constexpr auto kQuadVertices = kQuads * 4;
constexpr auto kQuadValues = kQuadVertices * 4;
constexpr auto kValues = kQuadValues + 8; // Blur texture coordinates.
@@ -197,7 +198,7 @@ float insideTexture() {
vec2 fromTextureCenter = abs(v_texcoord - textureHalf);
vec2 fromTextureEdge = max(fromTextureCenter, textureHalf) - textureHalf;
float outsideCheck = dot(fromTextureEdge, fromTextureEdge);
return step(outsideCheck, 0);
return step(outsideCheck, 0.);
}
vec4 background() {
@@ -320,7 +321,6 @@ Viewport::RendererGL::RendererGL(not_null<Viewport*> owner)
void Viewport::RendererGL::init(
not_null<QOpenGLWidget*> widget,
QOpenGLFunctions &f) {
_factor = widget->devicePixelRatio();
_frameBuffer.emplace();
_frameBuffer->setUsagePattern(QOpenGLBuffer::DynamicDraw);
_frameBuffer->create();
@@ -427,7 +427,11 @@ void Viewport::RendererGL::setDefaultViewport(QOpenGLFunctions &f) {
void Viewport::RendererGL::paint(
not_null<QOpenGLWidget*> widget,
QOpenGLFunctions &f) {
_factor = widget->devicePixelRatio();
const auto factor = widget->devicePixelRatio();
if (_factor != factor) {
_factor = factor;
_buttons.invalidate();
}
_viewport = widget->size();
const auto defaultFramebufferObject = widget->defaultFramebufferObject();
@@ -551,16 +555,50 @@ void Viewport::RendererGL::paintTile(
texCoords.end());
}
// Paused.
const auto &pauseIcon = st::groupCallPaused;
const auto pausedIcon = _buttons.texturedRect(
const auto nameTop = y + (height
- st.namePosition.y()
- st::semiboldFont->height);
// Paused icon and text.
const auto middle = (st::groupCallVideoPlaceholderHeight
- st::groupCallPaused.height()) / 2;
const auto pausedSpace = (nameTop - y)
- st::groupCallPaused.height()
- st::semiboldFont->height;
const auto pauseIconSkip = middle - st::groupCallVideoPlaceholderIconTop;
const auto pauseTextSkip = st::groupCallVideoPlaceholderTextTop
- st::groupCallVideoPlaceholderIconTop;
const auto pauseIconTop = !_owner->wide()
? (y + (height - st::groupCallPaused.height()) / 2)
: (pausedSpace < 3 * st::semiboldFont->height)
? (pausedSpace / 3)
: std::min(
y + (height / 2) - pauseIconSkip,
(nameTop
- st::semiboldFont->height * 3
- st::groupCallPaused.height()));
const auto pauseTextTop = (pausedSpace < 3 * st::semiboldFont->height)
? (nameTop - (pausedSpace / 3) - st::semiboldFont->height)
: std::min(
pauseIconTop + pauseTextSkip,
nameTop - st::semiboldFont->height * 2);
const auto pauseIcon = _buttons.texturedRect(
QRect(
geometry.x() + (geometry.width() - pauseIcon.width()) / 2,
geometry.y() + (geometry.height() - pauseIcon.height()) / 2,
pauseIcon.width(),
pauseIcon.height()),
x + (width - st::groupCallPaused.width()) / 2,
pauseIconTop,
st::groupCallPaused.width(),
st::groupCallPaused.height()),
_paused);
const auto pausedRect = transformRect(pausedIcon.geometry);
const auto pauseRect = transformRect(pauseIcon.geometry);
const auto pausedPosition = QPoint(
x + (width - (_pausedTextRect.width() / cIntRetinaFactor())) / 2,
pauseTextTop);
const auto pausedText = _names.texturedRect(
QRect(pausedPosition, _pausedTextRect.size() / cIntRetinaFactor()),
_pausedTextRect);
const auto pausedRect = transformRect(pausedText.geometry);
// Pin.
const auto pin = _buttons.texturedRect(
@@ -594,10 +632,7 @@ void Viewport::RendererGL::paintTile(
// Name.
const auto namePosition = QPoint(
x + st.namePosition.x(),
y + (height
- st.namePosition.y()
- st::semiboldFont->height
+ nameShift));
nameTop + nameShift);
const auto name = _names.texturedRect(
QRect(namePosition, tileData.nameRect.size() / cIntRetinaFactor()),
tileData.nameRect,
@@ -703,17 +738,30 @@ void Viewport::RendererGL::paintTile(
name.texture.left(), name.texture.top(),
// Paused icon.
pauseRect.left(), pauseRect.top(),
pauseIcon.texture.left(), pauseIcon.texture.bottom(),
pauseRect.right(), pauseRect.top(),
pauseIcon.texture.right(), pauseIcon.texture.bottom(),
pauseRect.right(), pauseRect.bottom(),
pauseIcon.texture.right(), pauseIcon.texture.top(),
pauseRect.left(), pauseRect.bottom(),
pauseIcon.texture.left(), pauseIcon.texture.top(),
// Paused text.
pausedRect.left(), pausedRect.top(),
pausedIcon.texture.left(), pausedIcon.texture.bottom(),
pausedText.texture.left(), pausedText.texture.bottom(),
pausedRect.right(), pausedRect.top(),
pausedIcon.texture.right(), pausedIcon.texture.bottom(),
pausedText.texture.right(), pausedText.texture.bottom(),
pausedRect.right(), pausedRect.bottom(),
pausedIcon.texture.right(), pausedIcon.texture.top(),
pausedText.texture.right(), pausedText.texture.top(),
pausedRect.left(), pausedRect.bottom(),
pausedIcon.texture.left(), pausedIcon.texture.top(),
pausedText.texture.left(), pausedText.texture.top(),
};
_frameBuffer->bind();
@@ -784,7 +832,9 @@ void Viewport::RendererGL::paintTile(
const auto pinVisible = _owner->wide()
&& (pin.geometry.bottom() > y);
if (nameShift == fullNameShift && !pinVisible && paused == 0.) {
const auto nameVisible = (nameShift != fullNameShift);
const auto pausedVisible = (paused > 0.);
if (!nameVisible && !pinVisible && !pausedVisible) {
return;
}
@@ -801,31 +851,40 @@ void Viewport::RendererGL::paintTile(
f.glActiveTexture(GL_TEXTURE0);
_buttons.bind(f);
if (paused > 0) {
// Paused icon.
if (pausedVisible) {
_imageProgram->setUniformValue("g_opacity", GLfloat(paused));
FillTexturedRectangle(f, &*_imageProgram, 30);
}
_imageProgram->setUniformValue("g_opacity", GLfloat(1.f));
// Pin.
if (pinVisible) {
FillTexturedRectangle(f, &*_imageProgram, 14);
FillTexturedRectangle(f, &*_imageProgram, 18);
}
if (nameShift == fullNameShift) {
return;
}
// Mute.
if (!muteRect.empty()) {
if (nameVisible && !muteRect.empty()) {
FillTexturedRectangle(f, &*_imageProgram, 22);
}
if (!nameVisible && !pausedVisible) {
return;
}
_names.bind(f);
// Name.
if (!nameRect.empty()) {
_names.bind(f);
if (nameVisible && !nameRect.empty()) {
FillTexturedRectangle(f, &*_imageProgram, 26);
}
// Paused text.
if (pausedVisible && _owner->wide()) {
_imageProgram->setUniformValue("g_opacity", GLfloat(paused));
FillTexturedRectangle(f, &*_imageProgram, 34);
}
}
void Viewport::RendererGL::prepareObjects(
@@ -1054,7 +1113,6 @@ void Viewport::RendererGL::ensureButtonsImage() {
if (_buttons) {
return;
}
const auto factor = cIntRetinaFactor();
const auto pinOnSize = VideoTile::PinInnerSize(true);
const auto pinOffSize = VideoTile::PinInnerSize(false);
const auto backSize = VideoTile::BackInnerSize();
@@ -1074,18 +1132,18 @@ void Viewport::RendererGL::ensureButtonsImage() {
+ backSize.height()
+ muteSize.height()
+ pausedSize.height()));
const auto imageSize = fullSize * factor;
const auto imageSize = fullSize * _factor;
auto image = _buttons.takeImage();
if (image.size() != imageSize) {
image = QImage(imageSize, QImage::Format_ARGB32_Premultiplied);
}
image.fill(Qt::transparent);
image.setDevicePixelRatio(cRetinaFactor());
image.setDevicePixelRatio(_factor);
{
auto p = Painter(&image);
auto hq = PainterHighQualityEnabler(p);
_pinOn = QRect(QPoint(), pinOnSize * factor);
_pinOn = QRect(QPoint(), pinOnSize * _factor);
VideoTile::PaintPinButton(
p,
true,
@@ -1096,7 +1154,9 @@ void Viewport::RendererGL::ensureButtonsImage() {
&_pinIcon);
const auto pinOffTop = pinOnSize.height();
_pinOff = QRect(QPoint(0, pinOffTop) * factor, pinOffSize * factor);
_pinOff = QRect(
QPoint(0, pinOffTop) * _factor,
pinOffSize * _factor);
VideoTile::PaintPinButton(
p,
false,
@@ -1107,7 +1167,7 @@ void Viewport::RendererGL::ensureButtonsImage() {
&_pinIcon);
const auto backTop = pinOffTop + pinOffSize.height();
_back = QRect(QPoint(0, backTop) * factor, backSize * factor);
_back = QRect(QPoint(0, backTop) * _factor, backSize * _factor);
VideoTile::PaintBackButton(
p,
0,
@@ -1116,16 +1176,18 @@ void Viewport::RendererGL::ensureButtonsImage() {
&_pinBackground);
const auto muteTop = backTop + backSize.height();
_muteOn = QRect(QPoint(0, muteTop) * factor, muteSize * factor);
_muteOn = QRect(QPoint(0, muteTop) * _factor, muteSize * _factor);
_muteIcon.paint(p, { 0, muteTop }, 1.);
_muteOff = QRect(
QPoint(muteSize.width(), muteTop) * factor,
muteSize * factor);
QPoint(muteSize.width(), muteTop) * _factor,
muteSize * _factor);
_muteIcon.paint(p, { muteSize.width(), muteTop }, 0.);
const auto pausedTop = muteTop + muteSize.height();
_paused = QRect(QPoint(0, pausedTop) * factor, pausedSize * factor);
_paused = QRect(
QPoint(0, pausedTop) * _factor,
pausedSize * _factor);
st::groupCallPaused.paint(p, 0, pausedTop, fullSize.width());
}
_buttons.setImage(std::move(image));
@@ -1137,12 +1199,15 @@ void Viewport::RendererGL::validateDatas() {
const auto count = int(tiles.size());
const auto factor = cIntRetinaFactor();
const auto nameHeight = st::semiboldFont->height * factor;
const auto pausedText = tr::lng_group_call_video_paused(tr::now);
const auto pausedBottom = nameHeight;
const auto pausedWidth = st::semiboldFont->width(pausedText) * factor;
struct Request {
int index = 0;
bool updating = false;
};
auto requests = std::vector<Request>();
auto available = _names.image().width();
auto available = std::max(_names.image().width(), pausedWidth);
for (auto &data : _tileData) {
data.stale = true;
}
@@ -1174,7 +1239,7 @@ void Viewport::RendererGL::validateDatas() {
if (peer != j->peer
|| peer->nameVersion != j->nameVersion
|| width != j->nameRect.width()) {
const auto nameTop = index * nameHeight;
const auto nameTop = pausedBottom + index * nameHeight;
j->nameRect = QRect(0, nameTop, width, nameHeight);
requests.push_back({ .index = i, .updating = true });
}
@@ -1219,16 +1284,19 @@ void Viewport::RendererGL::validateDatas() {
.pause = paused,
});
}
const auto nameTop = pausedBottom + index * nameHeight;
_tileData[index].nameVersion = peer->nameVersion;
_tileData[index].nameRect = QRect(
0,
index * nameHeight,
nameTop,
nameWidth(i),
nameHeight);
_tileDataIndices[i] = index;
}
auto image = _names.takeImage();
const auto imageSize = QSize(available, _tileData.size() * nameHeight);
const auto imageSize = QSize(
available,
pausedBottom + _tileData.size() * nameHeight);
const auto allocate = (image.size() != imageSize);
auto paintToImage = allocate
? QImage(imageSize, QImage::Format_ARGB32_Premultiplied)
@@ -1239,6 +1307,7 @@ void Viewport::RendererGL::validateDatas() {
}
{
auto p = Painter(&paintToImage);
p.setPen(st::groupCallVideoTextFg);
if (!image.isNull()) {
p.setCompositionMode(QPainter::CompositionMode_Source);
p.drawImage(0, 0, image);
@@ -1259,8 +1328,11 @@ void Viewport::RendererGL::validateDatas() {
Qt::transparent);
}
p.setCompositionMode(QPainter::CompositionMode_SourceOver);
} else if (allocate) {
p.setFont(st::semiboldFont);
p.drawText(0, st::semiboldFont->ascent, pausedText);
_pausedTextRect = QRect(0, 0, pausedWidth, nameHeight);
}
p.setPen(st::groupCallVideoTextFg);
for (const auto &request : requests) {
const auto i = request.index;
const auto index = _tileDataIndices[i];

View File

@@ -152,6 +152,7 @@ private:
QRect _paused;
Ui::GL::Image _names;
QRect _pausedTextRect;
std::vector<TileData> _tileData;
std::vector<int> _tileDataIndices;

View File

@@ -232,9 +232,48 @@ void Viewport::RendererSW::paintTileControls(
&_pinBackground);
}
const auto &st = st::groupCallVideoTile;
const auto nameTop = y + (height
- st.namePosition.y()
- st::semiboldFont->height);
if (_pausedFrame) {
p.fillRect(x, y, width, height, QColor(0, 0, 0, kShadowMaxAlpha));
st::groupCallPaused.paintInCenter(p, { x, y, width, height });
const auto middle = (st::groupCallVideoPlaceholderHeight
- st::groupCallPaused.height()) / 2;
const auto pausedSpace = (nameTop - y)
- st::groupCallPaused.height()
- st::semiboldFont->height;
const auto pauseIconSkip = middle - st::groupCallVideoPlaceholderIconTop;
const auto pauseTextSkip = st::groupCallVideoPlaceholderTextTop
- st::groupCallVideoPlaceholderIconTop;
const auto pauseIconTop = !_owner->wide()
? (y + (height - st::groupCallPaused.height()) / 2)
: (pausedSpace < 3 * st::semiboldFont->height)
? (pausedSpace / 3)
: std::min(
y + (height / 2) - pauseIconSkip,
(nameTop
- st::semiboldFont->height * 3
- st::groupCallPaused.height()));
const auto pauseTextTop = (pausedSpace < 3 * st::semiboldFont->height)
? (nameTop - (pausedSpace / 3) - st::semiboldFont->height)
: std::min(
pauseIconTop + pauseTextSkip,
nameTop - st::semiboldFont->height * 2);
st::groupCallPaused.paint(
p,
x + (width - st::groupCallPaused.width()) / 2,
pauseIconTop,
width);
if (_owner->wide()) {
p.drawText(
QRect(x, pauseTextTop, width, y + height - pauseTextTop),
tr::lng_group_call_video_paused(tr::now),
style::al_top);
}
}
const auto shown = _owner->_controlsShownRatio;
@@ -242,7 +281,6 @@ void Viewport::RendererSW::paintTileControls(
return;
}
const auto &st = st::groupCallVideoTile;
const auto fullShift = st.namePosition.y() + st::normalFont->height;
const auto shift = anim::interpolate(fullShift, 0, shown);
@@ -291,11 +329,12 @@ void Viewport::RendererSW::paintTileControls(
- st.iconPosition.x() - icon.width()
- st.namePosition.x();
const auto nameLeft = x + st.namePosition.x();
const auto nameTop = y + (height
- st.namePosition.y()
- st::semiboldFont->height
+ shift);
row->name().drawLeftElided(p, nameLeft, nameTop, hasWidth, width);
row->name().drawLeftElided(
p,
nameLeft,
nameTop + shift,
hasWidth,
width);
}
} // namespace Calls::Group

View File

@@ -25,11 +25,13 @@ constexpr auto kPausedVideoSize = 90;
Viewport::VideoTile::VideoTile(
const VideoEndpoint &endpoint,
VideoTileTrack track,
rpl::producer<QSize> trackSize,
rpl::producer<bool> pinned,
Fn<void()> update)
: _endpoint(endpoint)
, _update(std::move(update))
, _track(track) {
, _track(track)
, _trackSize(std::move(trackSize)) {
Expects(track.track != nullptr);
Expects(track.row != nullptr);
@@ -254,19 +256,7 @@ void Viewport::VideoTile::setup(rpl::producer<bool> pinned) {
}, _lifetime);
_track.track->renderNextFrame(
) | rpl::start_with_next([=] {
const auto size = _track.track->frameSize();
if (size.isEmpty()) {
_track.track->markFrameShown();
} else {
_trackSize = size;
}
_update();
}, _lifetime);
if (const auto size = _track.track->frameSize(); !size.isEmpty()) {
_trackSize = size;
}
) | rpl::start_with_next(_update, _lifetime);
updateTopControlsSize();
}

View File

@@ -26,6 +26,7 @@ public:
VideoTile(
const VideoEndpoint &endpoint,
VideoTileTrack track,
rpl::producer<QSize> trackSize,
rpl::producer<bool> pinned,
Fn<void()> update);

View File

@@ -529,8 +529,7 @@ void EmojiKeywords::apiChanged(ApiWrap *api) {
_api = api;
if (_api) {
crl::on_main(&_api->session(), crl::guard(&_guard, [=] {
base::ObservableViewer(
Lang::CurrentCloudManager().firstLanguageSuggestion()
Lang::CurrentCloudManager().firstLanguageSuggestion(
) | rpl::filter([=] {
// Refresh with the suggested language if we already were asked.
return !_data.empty();

View File

@@ -34,8 +34,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/cached_round_corners.h"
#include "base/unixtime.h"
#include "base/openssl_help.h"
#include "window/window_adaptive.h"
#include "window/window_session_controller.h"
#include "facades.h"
#include "styles/style_chat.h"
#include "styles/style_widgets.h"
#include "styles/style_chat_helpers.h"
@@ -123,6 +123,8 @@ private:
bool _previewShown = false;
bool _isOneColumn = false;
Fn<SendMenu::Type()> _sendMenuType;
rpl::event_stream<FieldAutocomplete::MentionChosen> _mentionChosen;
@@ -741,6 +743,12 @@ FieldAutocomplete::Inner::Inner(
) | rpl::start_with_next([=] {
update();
}, lifetime());
controller->adaptive().changed(
) | rpl::start_with_next([=] {
_isOneColumn = controller->adaptive().isOneColumn();
update();
}, lifetime());
}
void FieldAutocomplete::Inner::paintEvent(QPaintEvent *e) {
@@ -937,9 +945,9 @@ void FieldAutocomplete::Inner::paintEvent(QPaintEvent *e) {
}
}
}
p.fillRect(Adaptive::OneColumn() ? 0 : st::lineWidth, _parent->innerBottom() - st::lineWidth, width() - (Adaptive::OneColumn() ? 0 : st::lineWidth), st::lineWidth, st::shadowFg);
p.fillRect(_isOneColumn ? 0 : st::lineWidth, _parent->innerBottom() - st::lineWidth, width() - (_isOneColumn ? 0 : st::lineWidth), st::lineWidth, st::shadowFg);
}
p.fillRect(Adaptive::OneColumn() ? 0 : st::lineWidth, _parent->innerTop(), width() - (Adaptive::OneColumn() ? 0 : st::lineWidth), st::lineWidth, st::shadowFg);
p.fillRect(_isOneColumn ? 0 : st::lineWidth, _parent->innerTop(), width() - (_isOneColumn ? 0 : st::lineWidth), st::lineWidth, st::shadowFg);
}
void FieldAutocomplete::Inner::resizeEvent(QResizeEvent *e) {

View File

@@ -188,12 +188,13 @@ GifsListWidget::GifsListWidget(
update();
}, lifetime());
subscribe(controller->gifPauseLevelChanged(), [=] {
controller->gifPauseLevelChanged(
) | rpl::start_with_next([=] {
if (!controller->isGifPausedAtLeastFor(
Window::GifPauseReason::SavedGifs)) {
update();
}
});
}, lifetime());
}
rpl::producer<TabbedSelector::FileChosen> GifsListWidget::fileChosen() const {

View File

@@ -46,8 +46,7 @@ void AddGifAction(
class GifsListWidget
: public TabbedSelector::Inner
, public InlineBots::Layout::Context
, private base::Subscriber {
, public InlineBots::Layout::Context {
public:
using InlineChosen = TabbedSelector::InlineChosen;

View File

@@ -281,7 +281,7 @@ Fn<bool(
return Ui::InputField::IsValidMarkdownLink(link)
&& !TextUtilities::IsMentionLink(link);
}
Ui::show(Box<EditLinkBox>(controller, text, link, [=](
controller->show(Box<EditLinkBox>(controller, text, link, [=](
const QString &text,
const QString &link) {
if (const auto strong = weak.data()) {
@@ -321,7 +321,9 @@ void InitSpellchecker(
Core::App().settings().spellcheckerEnabledValue(),
Spellchecker::SpellingHighlighter::CustomContextMenuItem{
tr::lng_settings_manage_dictionaries(tr::now),
[=] { Ui::show(Box<Ui::ManageDictionariesBox>(controller)); }
[=] {
controller->show(Box<Ui::ManageDictionariesBox>(controller));
}
});
field->setExtendedContextMenu(s->contextMenuCreated());
#endif // TDESKTOP_DISABLE_SPELLCHECK

View File

@@ -534,7 +534,7 @@ void StickersListWidget::Footer::mousePressEvent(QMouseEvent *e) {
updateSelected();
if (_iconOver == SpecialOver::Settings) {
Ui::show(Box<StickersBox>(
_pan->controller()->show(Box<StickersBox>(
_pan->controller(),
(hasOnlyFeaturedSets()
? StickersBox::Section::Featured
@@ -909,7 +909,7 @@ StickersListWidget::StickersListWidget(
setAttribute(Qt::WA_OpaquePaintEvent);
_settings->addClickHandler([=] {
Ui::show(
controller->show(
Box<StickersBox>(controller, StickersBox::Section::Installed));
});
@@ -2185,7 +2185,7 @@ void StickersListWidget::mouseReleaseEvent(QMouseEvent *e) {
removeSet(sets[button->section].id);
}
} else if (std::get_if<OverGroupAdd>(&pressed)) {
Ui::show(Box<StickersBox>(controller(), _megagroupSet));
controller()->show(Box<StickersBox>(controller(), _megagroupSet));
}
}
}
@@ -3005,7 +3005,7 @@ void StickersListWidget::displaySet(uint64 setId) {
if (setId == Data::Stickers::MegagroupSetId) {
if (_megagroupSet->canEditStickers()) {
_displayingSet = true;
checkHideWithBox(Ui::show(
checkHideWithBox(controller()->show(
Box<StickersBox>(controller(), _megagroupSet),
Ui::LayerOption::KeepOther).data());
return;
@@ -3019,7 +3019,7 @@ void StickersListWidget::displaySet(uint64 setId) {
auto it = sets.find(setId);
if (it != sets.cend()) {
_displayingSet = true;
checkHideWithBox(Ui::show(
checkHideWithBox(controller()->show(
Box<StickerSetBox>(controller(), it->second->mtpInput()),
Ui::LayerOption::KeepOther).data());
}
@@ -3083,7 +3083,7 @@ void StickersListWidget::removeMegagroupSet(bool locally) {
return;
}
_removingSetId = Data::Stickers::MegagroupSetId;
Ui::show(Box<ConfirmBox>(tr::lng_stickers_remove_group_set(tr::now), crl::guard(this, [this, group = _megagroupSet] {
controller()->show(Box<ConfirmBox>(tr::lng_stickers_remove_group_set(tr::now), crl::guard(this, [this, group = _megagroupSet] {
Expects(group->mgInfo != nullptr);
if (group->mgInfo->stickerSet.type() != mtpc_inputStickerSetEmpty) {
@@ -3105,7 +3105,7 @@ void StickersListWidget::removeSet(uint64 setId) {
const auto set = it->second.get();
_removingSetId = set->id;
auto text = tr::lng_stickers_remove_pack(tr::now, lt_sticker_pack, set->title);
Ui::show(Box<ConfirmBox>(text, tr::lng_stickers_remove_pack_confirm(tr::now), crl::guard(this, [=] {
controller()->show(Box<ConfirmBox>(text, tr::lng_stickers_remove_pack_confirm(tr::now), crl::guard(this, [=] {
Ui::hideLayer();
const auto &sets = session().data().stickers().sets();
const auto it = sets.find(_removingSetId);

View File

@@ -44,6 +44,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "main/main_domain.h"
#include "main/main_session.h"
#include "media/view/media_view_overlay_widget.h"
#include "media/view/media_view_open_common.h"
#include "mtproto/mtproto_dc_options.h"
#include "mtproto/mtproto_config.h"
#include "mtproto/mtp_instance.h"
@@ -75,7 +76,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/confirm_phone_box.h"
#include "boxes/confirm_box.h"
#include "boxes/share_box.h"
#include "facades.h"
#include "app.h"
#include <QtWidgets/QDesktopWidget>
@@ -177,7 +177,6 @@ Application::~Application() {
Media::Player::finish(_audio.get());
style::stopManager();
Global::finish();
ThirdParty::finish();
Instance = nullptr;
@@ -187,8 +186,7 @@ void Application::run() {
style::internal::StartFonts();
ThirdParty::start();
Global::start();
refreshGlobalProxy(); // Depends on Global::start().
refreshGlobalProxy(); // Depends on Core::IsAppLaunched().
// Depends on OpenSSL on macOS, so on ThirdParty::start().
// Depends on notifications settings.
@@ -287,6 +285,13 @@ void Application::run() {
&& Ui::Integration::Instance().openglLastCheckFailed()) {
showOpenGLCrashNotification();
}
_window->openInMediaViewRequests(
) | rpl::start_with_next([=](Media::View::OpenRequest &&request) {
if (_mediaView) {
_mediaView->show(std::move(request));
}
}, _window->lifetime());
}
void Application::showOpenGLCrashNotification() {
@@ -304,10 +309,10 @@ void Application::showOpenGLCrashNotification() {
Local::writeSettings();
};
_window->show(Box<ConfirmBox>(
"Last time OpenGL crashed on initialization. "
"Perhaps it is a problem with your graphics card driver.\n\n"
"Right now OpenGL was disabled. You can try to enable it back "
"or keep it disabled, if it continues crashing.",
"There may be a problem with your graphics drivers and OpenGL. "
"Try updating your drivers.\n\n"
"OpenGL has been disabled. You can try to enable it again "
"or keep it disabled if crashes continue.",
"Enable",
"Keep Disabled",
enable,
@@ -321,8 +326,6 @@ void Application::startDomain() {
startSettingsAndBackground();
}
if (state != Storage::StartResult::Success) {
Global::SetLocalPasscode(true);
Global::RefLocalPasscodeChanged().notify();
lockByPasscode();
DEBUG_LOG(("Application Info: passcode needed..."));
}
@@ -387,49 +390,6 @@ bool Application::hideMediaView() {
return false;
}
void Application::showPhoto(not_null<const PhotoOpenClickHandler*> link) {
const auto photo = link->photo();
const auto peer = link->peer();
const auto item = photo->owner().message(link->context());
return (!item && peer)
? showPhoto(photo, peer)
: showPhoto(photo, item);
}
void Application::showPhoto(not_null<PhotoData*> photo, HistoryItem *item) {
Expects(_mediaView != nullptr);
_mediaView->showPhoto(photo, item);
}
void Application::showPhoto(
not_null<PhotoData*> photo,
not_null<PeerData*> peer) {
Expects(_mediaView != nullptr);
_mediaView->showPhoto(photo, peer);
}
void Application::showDocument(not_null<DocumentData*> document, HistoryItem *item) {
Expects(_mediaView != nullptr);
if (cUseExternalVideoPlayer()
&& document->isVideoFile()
&& !document->filepath().isEmpty()) {
File::Launch(document->location(false).fname);
} else {
_mediaView->showDocument(document, item);
}
}
void Application::showTheme(
not_null<DocumentData*> document,
const Data::CloudTheme &cloud) {
Expects(_mediaView != nullptr);
_mediaView->showTheme(document, cloud);
}
PeerData *Application::ui_getPeerForMouseAction() {
if (_mediaView && !_mediaView->isHidden()) {
return _mediaView->ui_getPeerForMouseAction();
@@ -525,17 +485,17 @@ void Application::setCurrentProxy(
const MTP::ProxyData &proxy,
MTP::ProxyData::Settings settings) {
const auto current = [&] {
return (Global::ProxySettings() == MTP::ProxyData::Settings::Enabled)
? Global::SelectedProxy()
return _settings.proxy().isEnabled()
? _settings.proxy().selected()
: MTP::ProxyData();
};
const auto was = current();
Global::SetSelectedProxy(proxy);
Global::SetProxySettings(settings);
_settings.proxy().setSelected(proxy);
_settings.proxy().setSettings(settings);
const auto now = current();
refreshGlobalProxy();
_proxyChanges.fire({ was, now });
Global::RefConnectionTypeChanged().notify();
_settings.proxy().connectionTypeChangesNotify();
}
auto Application::proxyChanges() const -> rpl::producer<ProxyChange> {
@@ -543,11 +503,10 @@ auto Application::proxyChanges() const -> rpl::producer<ProxyChange> {
}
void Application::badMtprotoConfigurationError() {
if (Global::ProxySettings() == MTP::ProxyData::Settings::Enabled
&& !_badProxyDisableBox) {
if (_settings.proxy().isEnabled() && !_badProxyDisableBox) {
const auto disableCallback = [=] {
setCurrentProxy(
Global::SelectedProxy(),
_settings.proxy().selected(),
MTP::ProxyData::Settings::System);
};
_badProxyDisableBox = Ui::show(Box<InformBox>(
@@ -592,6 +551,14 @@ void Application::startEmojiImageLoader() {
}, _lifetime);
}
void Application::setScreenIsLocked(bool locked) {
_screenIsLocked = locked;
}
bool Application::screenIsLocked() const {
return _screenIsLocked;
}
void Application::setDefaultFloatPlayerDelegate(
not_null<Media::Player::FloatDelegate*> delegate) {
Expects(!_defaultFloatPlayerDelegate == !_floatPlayers);
@@ -910,7 +877,7 @@ bool Application::someSessionExists() const {
}
void Application::checkAutoLock() {
if (!Global::LocalPasscode()
if (!_domain->local().hasLocalPasscode()
|| passcodeLocked()
|| !someSessionExists()) {
_shouldLockAt = 0;
@@ -1146,7 +1113,7 @@ void Application::startShortcuts() {
return true;
});
request->check(Command::Lock) && request->handle([=] {
if (!passcodeLocked() && Global::LocalPasscode()) {
if (!passcodeLocked() && _domain->local().hasLocalPasscode()) {
lockByPasscode();
return true;
}

View File

@@ -10,7 +10,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "core/core_settings.h"
#include "mtproto/mtproto_auth_key.h"
#include "mtproto/mtproto_proxy_data.h"
#include "base/observer.h"
#include "base/timer.h"
class MainWindow;
@@ -104,7 +103,7 @@ namespace Core {
class Launcher;
struct LocalUrlHandler;
class Application final : public QObject, private base::Subscriber {
class Application final : public QObject {
public:
struct ProxyChange {
MTP::ProxyData was;
@@ -144,13 +143,6 @@ public:
// Media view interface.
void checkMediaViewActivation();
bool hideMediaView();
void showPhoto(not_null<const PhotoOpenClickHandler*> link);
void showPhoto(not_null<PhotoData*> photo, HistoryItem *item);
void showPhoto(not_null<PhotoData*> photo, not_null<PeerData*> item);
void showDocument(not_null<DocumentData*> document, HistoryItem *item);
void showTheme(
not_null<DocumentData*> document,
const Data::CloudTheme &cloud);
[[nodiscard]] PeerData *ui_getPeerForMouseAction();
[[nodiscard]] QPoint getPointForCallPanelCenter() const;
@@ -281,6 +273,10 @@ public:
void call_handleObservables();
// Global runtime variables.
void setScreenIsLocked(bool locked);
bool screenIsLocked() const;
protected:
bool eventFilter(QObject *object, QEvent *event) override;
@@ -351,7 +347,6 @@ private:
const std::unique_ptr<Lang::CloudManager> _langCloudManager;
const std::unique_ptr<ChatHelpers::EmojiKeywords> _emojiKeywords;
std::unique_ptr<Lang::Translator> _translator;
base::Observable<void> _passcodedChanged;
QPointer<Ui::BoxContent> _badProxyDisableBox;
std::unique_ptr<Media::Player::FloatController> _floatPlayers;
@@ -362,6 +357,7 @@ private:
const QImage _logoNoMargin;
rpl::variable<bool> _passcodeLock;
bool _screenIsLocked = false;
crl::time _shouldLockAt = 0;
base::Timer _autoLockTimer;

View File

@@ -21,60 +21,6 @@ namespace {
std::map<int, const char*> BetaLogs() {
return {
{
2004006,
"- Fix image compression option when sending files with drag-n-drop.\n"
"- Fix caption text selection in media albums.\n"
"- Fix drafts display in personal chats in the chats list.\n"
"- Bug fixes and other minor improvements.\n"
},
{
2004008,
"- Upgrade several third party libraries to latest versions.\n"
},
{
2004010,
"- Use inline bots and sticker by emoji suggestions in channel comments.\n"
"- Lock voice message recording, listen to your voice message before sending.\n"
},
{
2004011,
"- Improve locked voice message recording.\n"
"- Fix main window closing to tray on Windows.\n"
"- Fix crash in bot command sending.\n"
"- Fix adding additional photos when sending an album to a group with enabled slow mode.\n"
},
{
2004012,
"- Voice chats in groups. (alpha version)\n"
},
{
2004014,
"- Create voice chats in legacy groups.\n"
"- Fix sticker pack opening.\n"
"- Fix group status display.\n"
"- Fix group members display.\n"
},
{
2004015,
"- Improve design of voice chats.\n"
"- Fix sending of voice messages as replies.\n"
"- Fix 'Open With' menu position in macOS.\n"
"- Fix freeze on secondary screen disconnect.\n"
},
{
2005002,
"- Fix possible crash in video calls.\n"
@@ -173,6 +119,14 @@ std::map<int, const char*> BetaLogs() {
"- Several crash fixes.\n"
},
{
2007009,
"- Added \"Enable noise suppression\" option to group calls Settings.\n"
"- Fix media viewer with Retina + Non-Retina dual monitor setup on macOS.\n"
"- Several bug and crash fixes.\n"
},
};
};

View File

@@ -77,6 +77,7 @@ Settings::Settings()
QByteArray Settings::serialize() const {
const auto themesAccentColors = _themesAccentColors.serialize();
const auto windowPosition = Serialize(_windowPosition);
const auto proxy = _proxy.serialize();
auto recentEmojiPreloadGenerated = std::vector<RecentEmojiId>();
if (_recentEmojiPreload.empty()) {
@@ -97,7 +98,8 @@ QByteArray Settings::serialize() const {
+ Serialize::stringSize(_callOutputDeviceId)
+ Serialize::stringSize(_callInputDeviceId)
+ Serialize::stringSize(_callVideoInputDeviceId)
+ sizeof(qint32) * 5;
+ sizeof(qint32) * 5
+ Serialize::bytearraySize(proxy);
for (const auto &[key, value] : _soundOverrides) {
size += Serialize::stringSize(key) + Serialize::stringSize(value);
}
@@ -117,7 +119,7 @@ QByteArray Settings::serialize() const {
stream.setVersion(QDataStream::Qt_5_1);
stream
<< themesAccentColors
<< qint32(_adaptiveForWide ? 1 : 0)
<< qint32(_adaptiveForWide.current() ? 1 : 0)
<< qint32(_moderateModeEnabled ? 1 : 0)
<< qint32(qRound(_songVolume.current() * 1e6))
<< qint32(qRound(_videoVolume.current() * 1e6))
@@ -195,7 +197,11 @@ QByteArray Settings::serialize() const {
for (const auto &[id, variant] : _emojiVariants) {
stream << id << quint8(variant);
}
stream << qint32(_disableOpenGL ? 1 : 0);
stream
<< qint32(_disableOpenGL ? 1 : 0)
<< qint32(_groupCallNoiseSuppression ? 1 : 0)
<< _workMode.current()
<< proxy;
}
return result;
}
@@ -209,7 +215,7 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
stream.setVersion(QDataStream::Qt_5_1);
QByteArray themesAccentColors;
qint32 adaptiveForWide = _adaptiveForWide ? 1 : 0;
qint32 adaptiveForWide = _adaptiveForWide.current() ? 1 : 0;
qint32 moderateModeEnabled = _moderateModeEnabled ? 1 : 0;
qint32 songVolume = qint32(qRound(_songVolume.current() * 1e6));
qint32 videoVolume = qint32(qRound(_videoVolume.current() * 1e6));
@@ -272,6 +278,9 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
std::vector<RecentEmojiId> recentEmojiPreload;
base::flat_map<QString, uint8> emojiVariants;
qint32 disableOpenGL = _disableOpenGL ? 1 : 0;
qint32 groupCallNoiseSuppression = _groupCallNoiseSuppression ? 1 : 0;
qint32 workMode = static_cast<qint32>(_workMode.current());
QByteArray proxy;
stream >> themesAccentColors;
if (!stream.atEnd()) {
@@ -403,12 +412,23 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
if (!stream.atEnd()) {
stream >> disableOpenGL;
}
if (!stream.atEnd()) {
stream >> groupCallNoiseSuppression;
}
if (!stream.atEnd()) {
stream >> workMode;
}
if (!stream.atEnd()) {
stream >> proxy;
}
if (stream.status() != QDataStream::Ok) {
LOG(("App Error: "
"Bad data for Core::Settings::constructFromSerialized()"));
return;
} else if (!_themesAccentColors.setFromSerialized(themesAccentColors)) {
return;
} else if (!_proxy.setFromSerialized(proxy)) {
return;
}
_adaptiveForWide = (adaptiveForWide == 1);
_moderateModeEnabled = (moderateModeEnabled == 1);
@@ -421,11 +441,11 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
_soundNotify = (soundNotify == 1);
_desktopNotify = (desktopNotify == 1);
_flashBounceNotify = (flashBounceNotify == 1);
const auto uncheckedNotifyView = static_cast<DBINotifyView>(notifyView);
const auto uncheckedNotifyView = static_cast<NotifyView>(notifyView);
switch (uncheckedNotifyView) {
case dbinvShowNothing:
case dbinvShowName:
case dbinvShowPreview: _notifyView = uncheckedNotifyView; break;
case NotifyView::ShowNothing:
case NotifyView::ShowName:
case NotifyView::ShowPreview: _notifyView = uncheckedNotifyView; break;
}
switch (nativeNotifications) {
case 0: _nativeNotifications = std::nullopt; break;
@@ -513,11 +533,13 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
Ui::GL::ForceDisable(_disableOpenGL
|| Ui::Integration::Instance().openglLastCheckFailed());
}
}
bool Settings::chatWide() const {
return _adaptiveForWide
&& (Global::AdaptiveChatLayout() == Adaptive::ChatLayout::Wide);
_groupCallNoiseSuppression = (groupCallNoiseSuppression == 1);
const auto uncheckedWorkMode = static_cast<WorkMode>(workMode);
switch (uncheckedWorkMode) {
case WorkMode::WindowAndTray:
case WorkMode::TrayOnly:
case WorkMode::WindowOnly: _workMode = uncheckedWorkMode; break;
}
}
QString Settings::getSoundPath(const QString &key) const {
@@ -719,7 +741,7 @@ void Settings::resetOnLastLogout() {
_soundNotify = true;
_desktopNotify = true;
_flashBounceNotify = true;
_notifyView = dbinvShowPreview;
_notifyView = NotifyView::ShowPreview;
//_nativeNotifications = std::nullopt;
//_notificationsCount = 3;
//_notificationsCorner = ScreenCorner::BottomRight;
@@ -741,6 +763,8 @@ void Settings::resetOnLastLogout() {
_groupCallPushToTalkShortcut = QByteArray();
_groupCallPushToTalkDelay = 20;
_groupCallNoiseSuppression = true;
//_themesAccentColors = Window::Theme::AccentColors();
_lastSeenWarningSeen = false;
@@ -775,6 +799,8 @@ void Settings::resetOnLastLogout() {
_recentEmojiPreload.clear();
_recentEmoji.clear();
_emojiVariants.clear();
_workMode = WorkMode::WindowAndTray;
}
bool Settings::ThirdColumnByDefault() {

View File

@@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "core/core_settings_proxy.h"
#include "window/themes/window_themes_embedded.h"
#include "ui/chat/attach/attach_send_files_way.h"
#include "platform/platform_notifications_manager.h"
@@ -48,6 +49,16 @@ public:
BottomRight = 2,
BottomLeft = 3,
};
enum class NotifyView {
ShowPreview = 0,
ShowName = 1,
ShowNothing = 2,
};
enum class WorkMode {
WindowAndTray = 0,
TrayOnly = 1,
WindowOnly = 2,
};
static constexpr auto kDefaultVolume = 0.9;
@@ -57,6 +68,10 @@ public:
return _saveDelayed.events();
}
[[nodiscard]] SettingsProxy &proxy() {
return _proxy;
}
[[nodiscard]] static bool IsLeftCorner(ScreenCorner corner) {
return (corner == ScreenCorner::TopLeft)
|| (corner == ScreenCorner::BottomLeft);
@@ -69,9 +84,11 @@ public:
[[nodiscard]] QByteArray serialize() const;
void addFromSerialized(const QByteArray &serialized);
[[nodiscard]] bool chatWide() const;
[[nodiscard]] bool adaptiveForWide() const {
return _adaptiveForWide;
return _adaptiveForWide.current();
}
[[nodiscard]] rpl::producer<bool> adaptiveForWideValue() const {
return _adaptiveForWide.value();
}
void setAdaptiveForWide(bool value) {
_adaptiveForWide = value;
@@ -145,10 +162,10 @@ public:
void setFlashBounceNotify(bool value) {
_flashBounceNotify = value;
}
[[nodiscard]] DBINotifyView notifyView() const {
[[nodiscard]] NotifyView notifyView() const {
return _notifyView;
}
void setNotifyView(DBINotifyView value) {
void setNotifyView(NotifyView value) {
_notifyView = value;
}
[[nodiscard]] bool nativeNotifications() const {
@@ -265,6 +282,12 @@ public:
void setGroupCallPushToTalkDelay(crl::time delay) {
_groupCallPushToTalkDelay = delay;
}
[[nodiscard]] bool groupCallNoiseSuppression() const {
return _groupCallNoiseSuppression;
}
void setGroupCallNoiseSuppression(bool value) {
_groupCallNoiseSuppression = value;
}
[[nodiscard]] Window::Theme::AccentColors &themesAccentColors() {
return _themesAccentColors;
}
@@ -513,6 +536,18 @@ public:
void setWindowPosition(const WindowPosition &position) {
_windowPosition = position;
}
void setWorkMode(WorkMode value) {
_workMode = value;
}
[[nodiscard]] WorkMode workMode() const {
return _workMode.current();
}
[[nodiscard]] rpl::producer<WorkMode> workModeValue() const {
return _workMode.value();
}
[[nodiscard]] rpl::producer<WorkMode> workModeChanges() const {
return _workMode.changes();
}
struct RecentEmoji {
EmojiPtr emoji = nullptr;
@@ -567,7 +602,9 @@ private:
ushort rating = 0;
};
bool _adaptiveForWide = true;
SettingsProxy _proxy;
rpl::variable<bool> _adaptiveForWide = true;
bool _moderateModeEnabled = false;
rpl::variable<float64> _songVolume = kDefaultVolume;
rpl::variable<float64> _videoVolume = kDefaultVolume;
@@ -578,7 +615,7 @@ private:
bool _soundNotify = true;
bool _desktopNotify = true;
bool _flashBounceNotify = true;
DBINotifyView _notifyView = dbinvShowPreview;
NotifyView _notifyView = NotifyView::ShowPreview;
std::optional<bool> _nativeNotifications;
int _notificationsCount = 3;
ScreenCorner _notificationsCorner = ScreenCorner::BottomRight;
@@ -594,6 +631,7 @@ private:
bool _callAudioDuckingEnabled = true;
bool _disableCalls = false;
bool _groupCallPushToTalk = false;
bool _groupCallNoiseSuppression = true;
QByteArray _groupCallPushToTalkShortcut;
crl::time _groupCallPushToTalkDelay = 20;
Window::Theme::AccentColors _themesAccentColors;
@@ -632,6 +670,7 @@ private:
rpl::variable<bool> _systemDarkModeEnabled = false;
WindowPosition _windowPosition; // per-window
bool _disableOpenGL = false;
rpl::variable<WorkMode> _workMode = WorkMode::WindowAndTray;
bool _tabbedReplacedWithInfo = false; // per-window
rpl::event_stream<bool> _tabbedReplacedWithInfoValue; // per-window

View File

@@ -0,0 +1,238 @@
/*
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 "core/core_settings_proxy.h"
#include "base/platform/base_platform_info.h"
#include "storage/serialize_common.h"
namespace Core {
namespace {
[[nodiscard]] qint32 ProxySettingsToInt(MTP::ProxyData::Settings settings) {
switch(settings) {
case MTP::ProxyData::Settings::System: return 0;
case MTP::ProxyData::Settings::Enabled: return 1;
case MTP::ProxyData::Settings::Disabled: return 2;
}
Unexpected("Bad type in ProxySettingsToInt");
}
[[nodiscard]] MTP::ProxyData::Settings IntToProxySettings(qint32 value) {
switch(value) {
case 0: return MTP::ProxyData::Settings::System;
case 1: return MTP::ProxyData::Settings::Enabled;
case 2: return MTP::ProxyData::Settings::Disabled;
}
Unexpected("Bad type in IntToProxySettings");
}
[[nodiscard]] MTP::ProxyData DeserializeProxyData(const QByteArray &data) {
QDataStream stream(data);
stream.setVersion(QDataStream::Qt_5_1);
qint32 proxyType, port;
MTP::ProxyData proxy;
stream
>> proxyType
>> proxy.host
>> port
>> proxy.user
>> proxy.password;
proxy.port = port;
proxy.type = [&] {
switch(proxyType) {
case 0: return MTP::ProxyData::Type::None;
case 1: return MTP::ProxyData::Type::Socks5;
case 2: return MTP::ProxyData::Type::Http;
case 3: return MTP::ProxyData::Type::Mtproto;
}
Unexpected("Bad type in DeserializeProxyData");
}();
return proxy;
}
[[nodiscard]] QByteArray SerializeProxyData(const MTP::ProxyData &proxy) {
auto result = QByteArray();
const auto size = 1 * sizeof(qint32)
+ Serialize::stringSize(proxy.host)
+ 1 * sizeof(qint32)
+ Serialize::stringSize(proxy.user)
+ Serialize::stringSize(proxy.password);
result.reserve(size);
{
const auto proxyType = [&] {
switch(proxy.type) {
case MTP::ProxyData::Type::None: return 0;
case MTP::ProxyData::Type::Socks5: return 1;
case MTP::ProxyData::Type::Http: return 2;
case MTP::ProxyData::Type::Mtproto: return 3;
}
Unexpected("Bad type in SerializeProxyData");
}();
QDataStream stream(&result, QIODevice::WriteOnly);
stream.setVersion(QDataStream::Qt_5_1);
stream
<< qint32(proxyType)
<< proxy.host
<< qint32(proxy.port)
<< proxy.user
<< proxy.password;
}
return result;
}
} // namespace
SettingsProxy::SettingsProxy()
: _tryIPv6(!Platform::IsWindows()) {
}
QByteArray SettingsProxy::serialize() const {
auto result = QByteArray();
auto stream = QDataStream(&result, QIODevice::WriteOnly);
const auto serializedSelected = SerializeProxyData(_selected);
const auto serializedList = ranges::views::all(
_list
) | ranges::views::transform(SerializeProxyData) | ranges::to_vector;
const auto size = 3 * sizeof(qint32)
+ Serialize::bytearraySize(serializedSelected)
+ 1 * sizeof(qint32)
+ ranges::accumulate(
serializedList,
0,
ranges::plus(),
&Serialize::bytearraySize);
result.reserve(size);
stream.setVersion(QDataStream::Qt_5_1);
stream
<< qint32(_tryIPv6 ? 1 : 0)
<< qint32(_useProxyForCalls ? 1 : 0)
<< ProxySettingsToInt(_settings)
<< serializedSelected
<< qint32(_list.size());
for (const auto &i : serializedList) {
stream << i;
}
stream.device()->close();
return result;
}
bool SettingsProxy::setFromSerialized(const QByteArray &serialized) {
if (serialized.isEmpty()) {
return true;
}
auto stream = QDataStream(serialized);
auto tryIPv6 = qint32(_tryIPv6 ? 1 : 0);
auto useProxyForCalls = qint32(_useProxyForCalls ? 1 : 0);
auto settings = ProxySettingsToInt(_settings);
auto listCount = qint32(_list.size());
auto selectedProxy = QByteArray();
if (!stream.atEnd()) {
stream
>> tryIPv6
>> useProxyForCalls
>> settings
>> selectedProxy
>> listCount;
if (stream.status() == QDataStream::Ok) {
for (auto i = 0; i != listCount; ++i) {
QByteArray data;
stream >> data;
_list.push_back(DeserializeProxyData(data));
}
}
}
if (stream.status() != QDataStream::Ok) {
LOG(("App Error: "
"Bad data for Core::SettingsProxy::setFromSerialized()"));
return false;
}
_tryIPv6 = (tryIPv6 == 1);
_useProxyForCalls = (useProxyForCalls == 1);
_settings = IntToProxySettings(settings);
_selected = DeserializeProxyData(selectedProxy);
return true;
}
bool SettingsProxy::isEnabled() const {
return _settings == MTP::ProxyData::Settings::Enabled;
}
bool SettingsProxy::isSystem() const {
return _settings == MTP::ProxyData::Settings::System;
}
bool SettingsProxy::isDisabled() const {
return _settings == MTP::ProxyData::Settings::Disabled;
}
bool SettingsProxy::tryIPv6() const {
return _tryIPv6;
}
void SettingsProxy::setTryIPv6(bool value) {
_tryIPv6 = value;
}
bool SettingsProxy::useProxyForCalls() const {
return _useProxyForCalls;
}
void SettingsProxy::setUseProxyForCalls(bool value) {
_useProxyForCalls = value;
}
MTP::ProxyData::Settings SettingsProxy::settings() const {
return _settings;
}
void SettingsProxy::setSettings(MTP::ProxyData::Settings value) {
_settings = value;
}
MTP::ProxyData SettingsProxy::selected() const {
return _selected;
}
void SettingsProxy::setSelected(MTP::ProxyData value) {
_selected = value;
}
const std::vector<MTP::ProxyData> &SettingsProxy::list() const {
return _list;
}
std::vector<MTP::ProxyData> &SettingsProxy::list() {
return _list;
}
rpl::producer<> SettingsProxy::connectionTypeValue() const {
return _connectionTypeChanges.events_starting_with({});
}
rpl::producer<> SettingsProxy::connectionTypeChanges() const {
return _connectionTypeChanges.events();
}
void SettingsProxy::connectionTypeChangesNotify() {
_connectionTypeChanges.fire({});
}
} // namespace Core

View File

@@ -0,0 +1,56 @@
/*
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 "mtproto/mtproto_proxy_data.h"
namespace Core {
class SettingsProxy final {
public:
SettingsProxy();
[[nodiscard]] bool isEnabled() const;
[[nodiscard]] bool isSystem() const;
[[nodiscard]] bool isDisabled() const;
[[nodiscard]] rpl::producer<> connectionTypeChanges() const;
[[nodiscard]] rpl::producer<> connectionTypeValue() const;
void connectionTypeChangesNotify();
[[nodiscard]] bool tryIPv6() const;
void setTryIPv6(bool value);
[[nodiscard]] bool useProxyForCalls() const;
void setUseProxyForCalls(bool value);
[[nodiscard]] MTP::ProxyData::Settings settings() const;
void setSettings(MTP::ProxyData::Settings value);
[[nodiscard]] MTP::ProxyData selected() const;
void setSelected(MTP::ProxyData value);
[[nodiscard]] const std::vector<MTP::ProxyData> &list() const;
[[nodiscard]] std::vector<MTP::ProxyData> &list();
[[nodiscard]] QByteArray serialize() const;
bool setFromSerialized(const QByteArray &serialized);
private:
bool _tryIPv6 = false;
bool _useProxyForCalls = false;
MTP::ProxyData::Settings _settings = MTP::ProxyData::Settings::System;
MTP::ProxyData _selected;
std::vector<MTP::ProxyData> _list;
rpl::event_stream<> _connectionTypeChanges;
};
} // namespace Core

View File

@@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "core/launcher.h"
#include "core/sandbox.h"
#include "core/update_checker.h"
#include "core/ui_integration.h"
#include "window/main_window.h"
#include "platform/platform_specific.h"
#include "base/zlib_help.h"
@@ -103,6 +104,8 @@ PreLaunchInput::PreLaunchInput(QWidget *parent, bool password) : QLineEdit(paren
p.setColor(QPalette::Text, QColor(0, 0, 0));
setPalette(p);
setStyleSheet("QLineEdit { background-color: white; }");
QLineEdit::setTextMargins(0, 0, 0, 0);
setContentsMargins(0, 0, 0, 0);
if (password) {
@@ -182,7 +185,7 @@ NotStartedWindow::NotStartedWindow()
_log.setPlainText(Logs::full());
connect(&_close, SIGNAL(clicked()), this, SLOT(close()));
connect(&_close, &QPushButton::clicked, [=] { close(); });
_close.setText(qsl("CLOSE"));
QRect scr(QApplication::primaryScreen()->availableGeometry());
@@ -227,7 +230,6 @@ LastCrashedWindow::LastCrashedWindow(
const QByteArray &crashdump,
Fn<void()> launch)
: _dumpraw(crashdump)
, _port(kDefaultProxyPort)
, _label(this)
, _pleaseSendReport(this)
, _yourReportName(this)
@@ -252,7 +254,11 @@ LastCrashedWindow::LastCrashedWindow(
, _launch(std::move(launch)) {
excludeReportUsername();
if (!cInstallBetaVersion() && !cAlphaVersion()) { // currently accept crash reports only from testers
if (!cInstallBetaVersion() && !cAlphaVersion()) {
// Currently accept crash reports only from testers.
_sendingState = SendingNoReport;
} else if (Core::OpenGLLastCheckFailed()) {
// Nothing we can do right now with graphics driver crashes in GL.
_sendingState = SendingNoReport;
}
if (_sendingState != SendingNoReport) {
@@ -312,7 +318,10 @@ LastCrashedWindow::LastCrashedWindow(
}
_networkSettings.setText(qsl("NETWORK SETTINGS"));
connect(&_networkSettings, SIGNAL(clicked()), this, SLOT(onNetworkSettings()));
connect(
&_networkSettings,
&QPushButton::clicked,
[=] { networkSettings(); });
if (_sendingState == SendingNoReport) {
_label.setText(qsl("Last time Telegram Desktop was not closed properly."));
@@ -322,24 +331,53 @@ LastCrashedWindow::LastCrashedWindow(
if (_updaterData) {
_updaterData->check.setText(qsl("TRY AGAIN"));
connect(&_updaterData->check, SIGNAL(clicked()), this, SLOT(onUpdateRetry()));
connect(
&_updaterData->check,
&QPushButton::clicked,
[=] { updateRetry(); });
_updaterData->skip.setText(qsl("SKIP"));
connect(&_updaterData->skip, SIGNAL(clicked()), this, SLOT(onUpdateSkip()));
connect(
&_updaterData->skip,
&QPushButton::clicked,
[=] { updateSkip(); });
Core::UpdateChecker checker;
using Progress = Core::UpdateChecker::Progress;
checker.checking(
) | rpl::start_with_next([=] { onUpdateChecking(); }, _lifetime);
) | rpl::start_with_next([=] {
Assert(_updaterData != nullptr);
setUpdatingState(UpdatingCheck);
}, _lifetime);
checker.isLatest(
) | rpl::start_with_next([=] { onUpdateLatest(); }, _lifetime);
) | rpl::start_with_next([=] {
Assert(_updaterData != nullptr);
setUpdatingState(UpdatingLatest);
}, _lifetime);
checker.progress(
) | rpl::start_with_next([=](const Progress &result) {
onUpdateDownloading(result.already, result.size);
Assert(_updaterData != nullptr);
setUpdatingState(UpdatingDownload);
setDownloadProgress(result.already, result.size);
}, _lifetime);
checker.failed(
) | rpl::start_with_next([=] { onUpdateFailed(); }, _lifetime);
) | rpl::start_with_next([=] {
Assert(_updaterData != nullptr);
setUpdatingState(UpdatingFail);
}, _lifetime);
checker.ready(
) | rpl::start_with_next([=] { onUpdateReady(); }, _lifetime);
) | rpl::start_with_next([=] {
Assert(_updaterData != nullptr);
setUpdatingState(UpdatingReady);
}, _lifetime);
switch (checker.state()) {
case Core::UpdateChecker::State::Download:
@@ -373,19 +411,24 @@ LastCrashedWindow::LastCrashedWindow(
_report.setPlainText(_reportTextNoUsername);
_showReport.setText(qsl("VIEW REPORT"));
connect(&_showReport, SIGNAL(clicked()), this, SLOT(onViewReport()));
connect(&_showReport, &QPushButton::clicked, [=] {
_reportShown = !_reportShown;
updateControls();
});
_saveReport.setText(qsl("SAVE TO FILE"));
connect(&_saveReport, SIGNAL(clicked()), this, SLOT(onSaveReport()));
connect(&_saveReport, &QPushButton::clicked, [=] { saveReport(); });
_getApp.setText(qsl("GET THE LATEST OFFICIAL VERSION OF TELEGRAM DESKTOP"));
connect(&_getApp, SIGNAL(clicked()), this, SLOT(onGetApp()));
connect(&_getApp, &QPushButton::clicked, [=] {
QDesktopServices::openUrl(qsl("https://desktop.telegram.org"));
});
_send.setText(qsl("SEND CRASH REPORT"));
connect(&_send, SIGNAL(clicked()), this, SLOT(onSendReport()));
connect(&_send, &QPushButton::clicked, [=] { sendReport(); });
_sendSkip.setText(qsl("SKIP"));
connect(&_sendSkip, SIGNAL(clicked()), this, SLOT(onContinue()));
connect(&_sendSkip, &QPushButton::clicked, [=] { processContinue(); });
_continue.setText(qsl("CONTINUE"));
connect(&_continue, SIGNAL(clicked()), this, SLOT(onContinue()));
connect(&_continue, &QPushButton::clicked, [=] { processContinue(); });
QRect scr(QApplication::primaryScreen()->availableGeometry());
move(scr.x() + (scr.width() / 6), scr.y() + (scr.height() / 6));
@@ -393,12 +436,7 @@ LastCrashedWindow::LastCrashedWindow(
show();
}
void LastCrashedWindow::onViewReport() {
_reportShown = !_reportShown;
updateControls();
}
void LastCrashedWindow::onSaveReport() {
void LastCrashedWindow::saveReport() {
QString to = QFileDialog::getSaveFileName(0, qsl("Telegram Crash Report"), QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + qsl("/report.telegramcrash"), qsl("Telegram crash report (*.telegramcrash)"));
if (!to.isEmpty()) {
QFile file(to);
@@ -420,10 +458,6 @@ QByteArray LastCrashedWindow::getCrashReportRaw() const {
return result;
}
void LastCrashedWindow::onGetApp() {
QDesktopServices::openUrl(qsl("https://desktop.telegram.org"));
}
void LastCrashedWindow::excludeReportUsername() {
QString prefix = qstr("Username:");
QStringList lines = _reportText.split('\n');
@@ -467,7 +501,7 @@ void LastCrashedWindow::addReportFieldPart(const QLatin1String &name, const QLat
}
}
void LastCrashedWindow::onSendReport() {
void LastCrashedWindow::sendReport() {
if (_checkReply) {
_checkReply->deleteLater();
_checkReply = nullptr;
@@ -484,8 +518,14 @@ void LastCrashedWindow::onSendReport() {
QString::number(minidumpFileName().isEmpty() ? 0 : 1),
CrashReports::PlatformString())));
connect(_checkReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onSendingError(QNetworkReply::NetworkError)));
connect(_checkReply, SIGNAL(finished()), this, SLOT(onCheckingFinished()));
connect(
_checkReply,
&QNetworkReply::errorOccurred,
[=](QNetworkReply::NetworkError code) { sendingError(code); });
connect(
_checkReply,
&QNetworkReply::finished,
[=] { checkingFinished(); });
_pleaseSendReport.setText(qsl("Sending crash report..."));
_sendingState = SendingProgress;
@@ -502,7 +542,7 @@ QString LastCrashedWindow::minidumpFileName() {
return QString();
}
void LastCrashedWindow::onCheckingFinished() {
void LastCrashedWindow::checkingFinished() {
if (!_checkReply || _sendReply) return;
QByteArray result = _checkReply->readAll().trimmed();
@@ -574,9 +614,18 @@ void LastCrashedWindow::onCheckingFinished() {
_sendReply = _sendManager.post(QNetworkRequest(qsl("https://tdesktop.com/crash.php?act=report")), multipart);
multipart->setParent(_sendReply);
connect(_sendReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onSendingError(QNetworkReply::NetworkError)));
connect(_sendReply, SIGNAL(finished()), this, SLOT(onSendingFinished()));
connect(_sendReply, SIGNAL(uploadProgress(qint64,qint64)), this, SLOT(onSendingProgress(qint64,qint64)));
connect(
_sendReply,
&QNetworkReply::errorOccurred,
[=](QNetworkReply::NetworkError code) { sendingError(code); });
connect(
_sendReply,
&QNetworkReply::finished,
[=] { sendingFinished(); });
connect(
_sendReply,
&QNetworkReply::uploadProgress,
[=](qint64 sent, qint64 total) { sendingProgress(sent, total); });
updateControls();
}
@@ -804,41 +853,23 @@ void LastCrashedWindow::updateControls() {
}
}
void LastCrashedWindow::onNetworkSettings() {
void LastCrashedWindow::networkSettings() {
const auto &proxy = Core::Sandbox::Instance().sandboxProxy();
const auto box = new NetworkSettingsWindow(
this,
proxy.host,
proxy.port ? proxy.port : 80,
proxy.port ? proxy.port : kDefaultProxyPort,
proxy.user,
proxy.password);
connect(
box,
SIGNAL(saved(QString,quint32,QString,QString)),
this,
SLOT(onNetworkSettingsSaved(QString,quint32,QString,QString)));
box->saveRequests(
) | rpl::start_with_next([=](MTP::ProxyData &&data) {
Assert(data.host.isEmpty() || data.port != 0);
_proxyChanges.fire(std::move(data));
proxyUpdated();
}, _lifetime);
box->show();
}
void LastCrashedWindow::onNetworkSettingsSaved(
QString host,
quint32 port,
QString username,
QString password) {
Expects(host.isEmpty() || port != 0);
auto proxy = MTP::ProxyData();
proxy.type = host.isEmpty()
? MTP::ProxyData::Type::None
: MTP::ProxyData::Type::Http;
proxy.host = host;
proxy.port = port;
proxy.user = username;
proxy.password = password;
_proxyChanges.fire(std::move(proxy));
proxyUpdated();
}
void LastCrashedWindow::proxyUpdated() {
if (_updaterData
&& ((_updaterData->state == UpdatingCheck)
@@ -851,7 +882,7 @@ void LastCrashedWindow::proxyUpdated() {
checker.start();
} else if (_sendingState == SendingFail
|| _sendingState == SendingProgress) {
onSendReport();
sendReport();
}
activate();
}
@@ -869,7 +900,7 @@ void LastCrashedWindow::setUpdatingState(UpdatingState state, bool force) {
case UpdatingLatest:
_updating.setText(qsl("Latest version is installed."));
if (_sendingState == SendingNoReport) {
QTimer::singleShot(0, this, SLOT(onContinue()));
InvokeQueued(this, [=] { processContinue(); });
} else {
_sendingState = SendingNone;
}
@@ -909,7 +940,7 @@ void LastCrashedWindow::setDownloadProgress(qint64 ready, qint64 total) {
}
}
void LastCrashedWindow::onUpdateRetry() {
void LastCrashedWindow::updateRetry() {
Expects(_updaterData != nullptr);
cSetLastUpdateCheck(0);
@@ -917,11 +948,11 @@ void LastCrashedWindow::onUpdateRetry() {
checker.start();
}
void LastCrashedWindow::onUpdateSkip() {
void LastCrashedWindow::updateSkip() {
Expects(_updaterData != nullptr);
if (_sendingState == SendingNoReport) {
onContinue();
processContinue();
} else {
if (_updaterData->state == UpdatingCheck
|| _updaterData->state == UpdatingDownload) {
@@ -934,42 +965,11 @@ void LastCrashedWindow::onUpdateSkip() {
}
}
void LastCrashedWindow::onUpdateChecking() {
Expects(_updaterData != nullptr);
setUpdatingState(UpdatingCheck);
}
void LastCrashedWindow::onUpdateLatest() {
Expects(_updaterData != nullptr);
setUpdatingState(UpdatingLatest);
}
void LastCrashedWindow::onUpdateDownloading(qint64 ready, qint64 total) {
Expects(_updaterData != nullptr);
setUpdatingState(UpdatingDownload);
setDownloadProgress(ready, total);
}
void LastCrashedWindow::onUpdateReady() {
Expects(_updaterData != nullptr);
setUpdatingState(UpdatingReady);
}
void LastCrashedWindow::onUpdateFailed() {
Expects(_updaterData != nullptr);
setUpdatingState(UpdatingFail);
}
void LastCrashedWindow::onContinue() {
void LastCrashedWindow::processContinue() {
close();
}
void LastCrashedWindow::onSendingError(QNetworkReply::NetworkError e) {
void LastCrashedWindow::sendingError(QNetworkReply::NetworkError e) {
LOG(("Crash report sending error: %1").arg(e));
_pleaseSendReport.setText(qsl("Sending crash report failed :("));
@@ -985,7 +985,7 @@ void LastCrashedWindow::onSendingError(QNetworkReply::NetworkError e) {
updateControls();
}
void LastCrashedWindow::onSendingFinished() {
void LastCrashedWindow::sendingFinished() {
if (_sendReply) {
QByteArray result = _sendReply->readAll();
LOG(("Crash report sending done, result: %1").arg(QString::fromUtf8(result)));
@@ -1000,7 +1000,7 @@ void LastCrashedWindow::onSendingFinished() {
}
}
void LastCrashedWindow::onSendingProgress(qint64 uploaded, qint64 total) {
void LastCrashedWindow::sendingProgress(qint64 uploaded, qint64 total) {
if (_sendingState != SendingProgress && _sendingState != SendingUploading) return;
_sendingState = SendingUploading;
@@ -1098,9 +1098,9 @@ NetworkSettingsWindow::NetworkSettingsWindow(QWidget *parent, QString host, quin
_passwordLabel.setText(qsl("Password"));
_save.setText(qsl("SAVE"));
connect(&_save, SIGNAL(clicked()), this, SLOT(onSave()));
connect(&_save, &QPushButton::clicked, [=] { save(); });
_cancel.setText(qsl("CANCEL"));
connect(&_cancel, SIGNAL(clicked()), this, SLOT(close()));
connect(&_cancel, &QPushButton::clicked, [=] { close(); });
_hostInput.setText(host);
_portInput.setText(QString::number(port));
@@ -1131,7 +1131,7 @@ void NetworkSettingsWindow::resizeEvent(QResizeEvent *e) {
_cancel.move(_save.x() - padding - _cancel.width(), _save.y());
}
void NetworkSettingsWindow::onSave() {
void NetworkSettingsWindow::save() {
QString host = _hostInput.text().trimmed(), port = _portInput.text().trimmed(), username = _usernameInput.text().trimmed(), password = _passwordInput.text().trimmed();
if (!port.isEmpty() && !port.toUInt()) {
_portInput.setFocus();
@@ -1140,7 +1140,15 @@ void NetworkSettingsWindow::onSave() {
_portInput.setFocus();
return;
}
saved(host, port.toUInt(), username, password);
_saveRequests.fire({
.type = host.isEmpty()
? MTP::ProxyData::Type::None
: MTP::ProxyData::Type::Http,
.host = host,
.port = port.toUInt(),
.user = username,
.password = password,
});
close();
}
@@ -1148,6 +1156,10 @@ void NetworkSettingsWindow::closeEvent(QCloseEvent *e) {
deleteLater();
}
rpl::producer<MTP::ProxyData> NetworkSettingsWindow::saveRequests() const {
return _saveRequests.events();
}
void NetworkSettingsWindow::updateControls() {
_hostInput.updateGeometry();
_hostInput.resize(_hostInput.sizeHint());

View File

@@ -92,7 +92,6 @@ private:
};
class LastCrashedWindow : public PreLaunchWindow {
Q_OBJECT
public:
LastCrashedWindow(
@@ -106,29 +105,19 @@ public:
return _lifetime;
}
public Q_SLOTS:
void onViewReport();
void onSaveReport();
void onSendReport();
void onGetApp();
void saveReport();
void sendReport();
void onNetworkSettings();
void onNetworkSettingsSaved(QString host, quint32 port, QString username, QString password);
void onContinue();
void networkSettings();
void processContinue();
void onCheckingFinished();
void onSendingError(QNetworkReply::NetworkError e);
void onSendingFinished();
void onSendingProgress(qint64 uploaded, qint64 total);
void checkingFinished();
void sendingError(QNetworkReply::NetworkError e);
void sendingFinished();
void sendingProgress(qint64 uploaded, qint64 total);
void onUpdateRetry();
void onUpdateSkip();
void onUpdateChecking();
void onUpdateLatest();
void onUpdateDownloading(qint64 ready, qint64 total);
void onUpdateReady();
void onUpdateFailed();
void updateRetry();
void updateSkip();
protected:
void closeEvent(QCloseEvent *e) override;
@@ -146,9 +135,6 @@ private:
QByteArray _dumpraw;
QString _host, _username, _password;
quint32 _port;
PreLaunchLabel _label, _pleaseSendReport, _yourReportName, _minidump;
PreLaunchLog _report;
PreLaunchButton _send, _sendSkip, _networkSettings, _continue, _showReport, _saveReport, _getApp;
@@ -175,8 +161,6 @@ private:
SendingState _sendingState;
PreLaunchLabel _updating;
qint64 _sendingProgress = 0;
qint64 _sendingTotal = 0;
QNetworkAccessManager _sendManager;
QNetworkReply *_checkReply = nullptr;
@@ -209,16 +193,12 @@ private:
};
class NetworkSettingsWindow : public PreLaunchWindow {
Q_OBJECT
public:
NetworkSettingsWindow(QWidget *parent, QString host, quint32 port, QString username, QString password);
Q_SIGNALS:
void saved(QString host, quint32 port, QString username, QString password);
public Q_SLOTS:
void onSave();
[[nodiscard]] rpl::producer<MTP::ProxyData> saveRequests() const;
void save();
protected:
void closeEvent(QCloseEvent *e);
@@ -233,4 +213,6 @@ private:
QWidget *_parent;
rpl::event_stream<MTP::ProxyData> _saveRequests;
};

View File

@@ -18,7 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "core/sandbox.h"
#include "base/concurrent_timer.h"
//#include <QtCore/QLoggingCategory>
#include <QtCore/QLoggingCategory>
namespace Core {
namespace {
@@ -100,6 +100,9 @@ void ComputeDebugMode() {
if (cDebugMode()) {
Logs::SetDebugEnabled(true);
}
if (Logs::DebugEnabled()) {
QLoggingCategory::setFilterRules("qt.qpa.gl.debug=true");
}
}
void ComputeExternalUpdater() {
@@ -527,7 +530,6 @@ void Launcher::processArguments() {
int Launcher::executeApplication() {
FilteredCommandLineArguments arguments(_argc, _argv);
Sandbox sandbox(this, arguments.count(), arguments.values());
//QLoggingCategory::setFilterRules("qt.qpa.gl.debug=true");
Ui::MainQueueProcessor processor;
base::ConcurrentTimerEnvironment environment;
return sandbox.start();

View File

@@ -68,7 +68,7 @@ bool ShowStickerSet(
return false;
}
Core::App().hideMediaView();
Ui::show(Box<StickerSetBox>(
controller->show(Box<StickerSetBox>(
controller,
MTP_inputStickerSetShortName(MTP_string(match->captured(1)))));
return true;
@@ -84,6 +84,7 @@ bool ShowTheme(
const auto fromMessageId = context.value<ClickHandlerContext>().itemId;
Core::App().hideMediaView();
controller->session().data().cloudThemes().resolve(
&controller->window(),
match->captured(1),
fromMessageId);
return true;
@@ -231,9 +232,15 @@ bool ShowWallPaper(
const auto params = url_parse_params(
match->captured(1),
qthelp::UrlParamNameTransform::ToLower);
if (!params.value("gradient").isEmpty()) {
Ui::show(Box<InformBox>(
tr::lng_background_gradient_unsupported(tr::now)));
return false;
}
const auto color = params.value("color");
return BackgroundPreviewBox::Start(
controller,
params.value(qsl("slug")),
(color.isEmpty() ? params.value(qsl("slug")) : color),
params);
}
@@ -362,7 +369,7 @@ bool ResolveSettings(
}
if (section == qstr("devices")) {
controller->session().api().authorizations().reload();
Ui::show(Box<SessionsBox>(&controller->session()));
controller->show(Box<SessionsBox>(&controller->session()));
return true;
} else if (section == qstr("language")) {
ShowLanguagesBox();
@@ -395,12 +402,12 @@ bool HandleUnknown(
Core::UpdateApplication();
close();
};
Ui::show(Box<ConfirmBox>(
controller->show(Box<ConfirmBox>(
text,
tr::lng_menu_update(tr::now),
callback));
} else {
Ui::show(Box<InformBox>(text));
controller->show(Box<InformBox>(text));
}
});
controller->session().api().requestDeepLinkInfo(request, callback);
@@ -431,9 +438,7 @@ bool OpenMediaTimestamp(
documentId,
time * crl::time(1000));
if (document->isVideoFile()) {
Core::App().showDocument(
document,
session->data().message(itemId));
controller->openDocument(document, itemId, true);
} else if (document->isSong() || document->isVoiceMessage()) {
Media::Player::instance()->play({ document, itemId });
}
@@ -578,9 +583,16 @@ QString TryConvertUrlToLocal(QString url) {
return qsl("tg://socks?") + socksMatch->captured(1);
} else if (auto proxyMatch = regex_match(qsl("^proxy/?\\?(.+)(#|$)"), query, matchOptions)) {
return qsl("tg://proxy?") + proxyMatch->captured(1);
} else if (auto bgMatch = regex_match(qsl("^bg/([a-zA-Z0-9\\.\\_\\-]+)(\\?(.+)?)?$"), query, matchOptions)) {
} else if (auto bgMatch = regex_match(qsl("^bg/([a-zA-Z0-9\\.\\_\\-\\~]+)(\\?(.+)?)?$"), query, matchOptions)) {
const auto params = bgMatch->captured(3);
return qsl("tg://bg?slug=") + bgMatch->captured(1) + (params.isEmpty() ? QString() : '&' + params);
const auto bg = bgMatch->captured(1);
const auto type = regex_match(qsl("^[a-fA-F0-9]{6}^"), bg)
? "color"
: (regex_match(qsl("^[a-fA-F0-9]{6}\\-[a-fA-F0-9]{6}$"), bg)
|| regex_match(qsl("^[a-fA-F0-9]{6}(\\~[a-fA-F0-9]{6}){1,3}$"), bg))
? "gradient"
: "slug";
return qsl("tg://bg?") + type + '=' + bg + (params.isEmpty() ? QString() : '&' + params);
} else if (auto postMatch = regex_match(qsl("^c/(\\-?\\d+)/(\\d+)(/?\\?|/?$)"), query, matchOptions)) {
auto params = query.mid(postMatch->captured(0).size()).toString();
return qsl("tg://privatepost?channel=%1&post=%2").arg(postMatch->captured(1), postMatch->captured(2)) + (params.isEmpty() ? QString() : '&' + params);

View File

@@ -26,7 +26,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/qthelp_regex.h"
#include "base/qt_adapters.h"
#include "ui/effects/animations.h"
#include "facades.h"
#include "app.h"
#include <QtGui/QSessionManager>
@@ -450,17 +449,17 @@ void Sandbox::checkForQuit() {
}
void Sandbox::refreshGlobalProxy() {
const auto proxy = !Global::started()
const auto proxy = !Core::IsAppLaunched()
? _sandboxProxy
: (Global::ProxySettings() == MTP::ProxyData::Settings::Enabled)
? Global::SelectedProxy()
: Core::App().settings().proxy().isEnabled()
? Core::App().settings().proxy().selected()
: MTP::ProxyData();
if (proxy.type == MTP::ProxyData::Type::Socks5
|| proxy.type == MTP::ProxyData::Type::Http) {
QNetworkProxy::setApplicationProxy(
MTP::ToNetworkProxy(MTP::ToDirectIpProxy(proxy)));
} else if (!Global::started()
|| Global::ProxySettings() == MTP::ProxyData::Settings::System) {
} else if (!Core::IsAppLaunched()
|| Core::App().settings().proxy().isSystem()) {
QNetworkProxyFactory::setUseSystemConfiguration(true);
} else {
QNetworkProxy::setApplicationProxy(QNetworkProxy::NoProxy);

View File

@@ -15,7 +15,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/platform/base_platform_info.h"
#include "platform/platform_specific.h"
#include "base/parse_helper.h"
#include "facades.h"
#include <QtWidgets/QShortcut>
#include <QtCore/QJsonDocument>
@@ -553,8 +552,6 @@ rpl::producer<not_null<Request*>> Requests() {
}
void Start() {
Assert(Global::started());
Data.fill();
}

View File

@@ -21,7 +21,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "main/main_session.h"
#include "main/main_app_config.h"
#include "mainwindow.h"
#include "facades.h" // Global::ScreenIsLocked.
namespace Core {
namespace {
@@ -120,7 +119,7 @@ void UiIntegration::openglCheckFinish() {
}
bool UiIntegration::openglLastCheckFailed() {
return QFile::exists(OpenGLCheckFilePath());
return OpenGLLastCheckFailed();
}
void UiIntegration::textActionsUpdated() {
@@ -134,7 +133,7 @@ void UiIntegration::activationFromTopPanel() {
}
bool UiIntegration::screenIsLocked() {
return Global::ScreenIsLocked();
return Core::App().screenIsLocked();
}
QString UiIntegration::timeFormat() {
@@ -320,4 +319,8 @@ QString UiIntegration::phraseFormattingMonospace() {
return tr::lng_menu_formatting_monospace(tr::now);
}
bool OpenGLLastCheckFailed() {
return QFile::exists(OpenGLCheckFilePath());
}
} // namespace Core

View File

@@ -75,6 +75,6 @@ public:
};
[[nodiscard]] bool OpenglLastCheckFailed();
[[nodiscard]] bool OpenGLLastCheckFailed();
} // namespace Core

View File

@@ -121,18 +121,6 @@ void memset_rand(void *data, uint32 len);
QString translitRusEng(const QString &rus);
QString rusKeyboardLayoutSwitch(const QString &from);
enum DBINotifyView {
dbinvShowPreview = 0,
dbinvShowName = 1,
dbinvShowNothing = 2,
};
enum DBIWorkMode {
dbiwmWindowAndTray = 0,
dbiwmTrayOnly = 1,
dbiwmWindowOnly = 2,
};
static const int MatrixRowShift = 40000;
inline int rowscount(int fullCount, int countPerRow) {

View File

@@ -22,7 +22,7 @@ constexpr auto AppId = "{53F49750-6209-4FBF-9CA8-7A333C87D1ED}"_cs;
constexpr auto AppNameOld = "Telegram Win (Unofficial)"_cs;
constexpr auto AppName = "Telegram Desktop"_cs;
constexpr auto AppFile = "Telegram"_cs;
constexpr auto AppVersion = 2007008;
constexpr auto AppVersionStr = "2.7.8";
constexpr auto AppVersion = 2007009;
constexpr auto AppVersionStr = "2.7.9";
constexpr auto AppBetaVersion = true;
constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION;

View File

@@ -17,11 +17,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_document_media.h"
#include "main/main_session.h"
#include "boxes/confirm_box.h"
#include "core/application.h" // Core::App().showTheme.
#include "media/view/media_view_open_common.h"
#include "lang/lang_keys.h"
#include "apiwrap.h"
#include "app.h"
#include "mainwindow.h"
namespace Data {
namespace {
@@ -140,6 +138,7 @@ void CloudThemes::applyUpdate(const MTPTheme &theme) {
}
void CloudThemes::resolve(
not_null<Window::Controller*> controller,
const QString &slug,
const FullMsgId &clickFromMessageId) {
_session->api().request(_resolveRequestId).cancel();
@@ -148,31 +147,35 @@ void CloudThemes::resolve(
MTP_inputThemeSlug(MTP_string(slug)),
MTP_long(0)
)).done([=](const MTPTheme &result) {
showPreview(result);
showPreview(controller, result);
}).fail([=](const MTP::Error &error) {
if (error.type() == qstr("THEME_FORMAT_INVALID")) {
Ui::show(Box<InformBox>(
controller->show(Box<InformBox>(
tr::lng_theme_no_desktop(tr::now)));
}
}).send();
}
void CloudThemes::showPreview(const MTPTheme &data) {
void CloudThemes::showPreview(
not_null<Window::Controller*> controller,
const MTPTheme &data) {
data.match([&](const MTPDtheme &data) {
showPreview(CloudTheme::Parse(_session, data));
showPreview(controller, CloudTheme::Parse(_session, data));
});
}
void CloudThemes::showPreview(const CloudTheme &cloud) {
void CloudThemes::showPreview(
not_null<Window::Controller*> controller,
const CloudTheme &cloud) {
if (const auto documentId = cloud.documentId) {
previewFromDocument(cloud);
previewFromDocument(controller, cloud);
} else if (cloud.createdBy == _session->userId()) {
Ui::show(Box(
controller->show(Box(
Window::Theme::CreateForExistingBox,
&App::wnd()->controller(),
controller,
cloud));
} else {
Ui::show(Box<InformBox>(
controller->show(Box<InformBox>(
tr::lng_theme_no_desktop(tr::now)));
}
}
@@ -193,12 +196,19 @@ void CloudThemes::applyFromDocument(const CloudTheme &cloud) {
});
}
void CloudThemes::previewFromDocument(const CloudTheme &cloud) {
void CloudThemes::previewFromDocument(
not_null<Window::Controller*> controller,
const CloudTheme &cloud) {
const auto sessionController = controller->sessionController();
if (!sessionController) {
return;
}
const auto document = _session->data().document(cloud.documentId);
loadDocumentAndInvoke(_previewFrom, cloud, document, [=](
std::shared_ptr<Data::DocumentMedia> media) {
const auto document = media->owner();
Core::App().showTheme(document, cloud);
using Open = Media::View::OpenRequest;
controller->openInMediaView(Open(sessionController, document, cloud));
});
}

View File

@@ -15,6 +15,10 @@ namespace Main {
class Session;
} // namespace Main
namespace Window {
class Controller;
} // namespace Window
namespace Data {
class DocumentMedia;
@@ -47,9 +51,16 @@ public:
void applyUpdate(const MTPTheme &theme);
void resolve(const QString &slug, const FullMsgId &clickFromMessageId);
void showPreview(const MTPTheme &data);
void showPreview(const CloudTheme &cloud);
void resolve(
not_null<Window::Controller*> controller,
const QString &slug,
const FullMsgId &clickFromMessageId);
void showPreview(
not_null<Window::Controller*> controller,
const MTPTheme &data);
void showPreview(
not_null<Window::Controller*> controller,
const CloudTheme &cloud);
void applyFromDocument(const CloudTheme &cloud);
private:
@@ -69,7 +80,9 @@ private:
[[nodiscard]] bool needReload() const;
void scheduleReload();
void reloadCurrent();
void previewFromDocument(const CloudTheme &cloud);
void previewFromDocument(
not_null<Window::Controller*> controller,
const CloudTheme &cloud);
void loadDocumentAndInvoke(
LoadingDocument &value,
const CloudTheme &cloud,

View File

@@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "data/data_document.h"
#include "data/data_document_resolver.h"
#include "data/data_session.h"
#include "data/data_streaming.h"
#include "data/data_document_media.h"
@@ -315,73 +316,17 @@ DocumentClickHandler::DocumentClickHandler(
, _document(document) {
}
void DocumentOpenClickHandler::Open(
Data::FileOrigin origin,
not_null<DocumentData*> data,
HistoryItem *context) {
if (!data->date) {
return;
}
const auto media = data->createMediaView();
const auto openImageInApp = [&] {
if (data->size >= App::kImageSizeLimit) {
return false;
}
const auto &location = data->location(true);
if (!location.isEmpty() && location.accessEnable()) {
const auto guard = gsl::finally([&] {
location.accessDisable();
});
const auto path = location.name();
if (Core::MimeTypeForFile(path).name().startsWith("image/")
&& QImageReader(path).canRead()) {
Core::App().showDocument(data, context);
return true;
}
} else if (data->mimeString().startsWith("image/")
&& !media->bytes().isEmpty()) {
auto bytes = media->bytes();
auto buffer = QBuffer(&bytes);
if (QImageReader(&buffer).canRead()) {
Core::App().showDocument(data, context);
return true;
}
}
return false;
};
const auto &location = data->location(true);
if (data->isTheme() && media->loaded(true)) {
Core::App().showDocument(data, context);
location.accessDisable();
} else if (media->canBePlayed()) {
if (data->isAudioFile()
|| data->isVoiceMessage()
|| data->isVideoMessage()) {
const auto msgId = context ? context->fullId() : FullMsgId();
Media::Player::instance()->playPause({ data, msgId });
} else if (context
&& data->isAnimation()
&& HistoryView::Gif::CanPlayInline(data)) {
data->owner().requestAnimationPlayInline(context);
} else {
Core::App().showDocument(data, context);
}
} else {
data->saveFromDataSilent();
if (!openImageInApp()) {
if (!data->filepath(true).isEmpty()) {
LaunchWithWarning(&data->session(), location.name(), context);
} else if (data->status == FileReady
|| data->status == FileDownloadFailed) {
DocumentSaveClickHandler::Save(origin, data);
}
}
}
DocumentOpenClickHandler::DocumentOpenClickHandler(
not_null<DocumentData*> document,
Fn<void()> &&callback)
: DocumentClickHandler(document)
, _handler(std::move(callback)) {
}
void DocumentOpenClickHandler::onClickImpl() const {
Open(context(), document(), getActionItem());
if (_handler) {
_handler();
}
}
void DocumentSaveClickHandler::Save(
@@ -1634,126 +1579,3 @@ void DocumentData::collectLocalData(not_null<DocumentData*> local) {
session().local().writeFileLocation(mediaKey(), _location);
}
}
namespace Data {
QString FileExtension(const QString &filepath) {
const auto reversed = ranges::views::reverse(filepath);
const auto last = ranges::find_first_of(reversed, ".\\/");
if (last == reversed.end() || *last != '.') {
return QString();
}
return QString(last.base(), last - reversed.begin());
}
bool IsValidMediaFile(const QString &filepath) {
static const auto kExtensions = [] {
const auto list = qsl("\
16svx 2sf 3g2 3gp 8svx aac aaf aif aifc aiff amr amv ape asf ast au aup \
avchd avi brstm bwf cam cdda cust dat divx drc dsh dsf dts dtshd dtsma \
dvr-ms dwd evo f4a f4b f4p f4v fla flac flr flv gif gifv gsf gsm gym iff \
ifo it jam la ly m1v m2p m2ts m2v m4a m4p m4v mcf mid mk3d mka mks mkv mng \
mov mp1 mp2 mp3 mp4 minipsf mod mpc mpe mpeg mpg mpv mscz mt2 mus mxf mxl \
niff nsf nsv off ofr ofs ogg ogv opus ots pac ps psf psf2 psflib ptb qsf \
qt ra raw rka rm rmj rmvb roq s3m shn sib sid smi smp sol spc spx ssf svi \
swa swf tak ts tta txm usf vgm vob voc vox vqf wav webm wma wmv wrap wtv \
wv xm xml ym yuv").split(' ');
return base::flat_set<QString>(list.begin(), list.end());
}();
return ranges::binary_search(
kExtensions,
FileExtension(filepath).toLower());
}
bool IsExecutableName(const QString &filepath) {
static const auto kExtensions = [] {
const auto joined =
#ifdef Q_OS_MAC
qsl("\
applescript action app bin command csh osx workflow terminal url caction \
mpkg pkg scpt scptd xhtm webarchive");
#elif defined Q_OS_UNIX // Q_OS_MAC
qsl("bin csh deb desktop ksh out pet pkg pup rpm run sh shar \
slp zsh");
#else // Q_OS_MAC || Q_OS_UNIX
qsl("\
ad ade adp app application appref-ms asp asx bas bat bin cab cdxml cer cfg \
chi chm cmd cnt com cpl crt csh der diagcab dll drv eml exe fon fxp gadget \
grp hlp hpj hta htt inf ini ins inx isp isu its jar jnlp job js jse key ksh \
lnk local lua mad maf mag mam manifest maq mar mas mat mau mav maw mcf mda \
mdb mde mdt mdw mdz mht mhtml mjs mmc mof msc msg msh msh1 msh2 msh1xml \
msh2xml mshxml msi msp mst ops osd paf pcd phar php php3 php4 php5 php7 phps \
php-s pht phtml pif pl plg pm pod prf prg ps1 ps2 ps1xml ps2xml psc1 psc2 \
psd1 psm1 pssc pst py py3 pyc pyd pyi pyo pyw pywz pyz rb reg rgs scf scr \
sct search-ms settingcontent-ms sh shb shs slk sys t tmp u3p url vb vbe vbp \
vbs vbscript vdx vsmacros vsd vsdm vsdx vss vssm vssx vst vstm vstx vsw vsx \
vtx website ws wsc wsf wsh xbap xll xnk xs");
#endif // !Q_OS_MAC && !Q_OS_UNIX
const auto list = joined.split(' ');
return base::flat_set<QString>(list.begin(), list.end());
}();
return ranges::binary_search(
kExtensions,
FileExtension(filepath).toLower());
}
bool IsIpRevealingName(const QString &filepath) {
static const auto kExtensions = [] {
const auto joined = u"htm html svg"_q;
const auto list = joined.split(' ');
return base::flat_set<QString>(list.begin(), list.end());
}();
static const auto kMimeTypes = [] {
const auto joined = u"text/html image/svg+xml"_q;
const auto list = joined.split(' ');
return base::flat_set<QString>(list.begin(), list.end());
}();
return ranges::binary_search(
kExtensions,
FileExtension(filepath).toLower()
) || ranges::binary_search(
kMimeTypes,
QMimeDatabase().mimeTypeForFile(QFileInfo(filepath)).name()
);
}
base::binary_guard ReadImageAsync(
not_null<Data::DocumentMedia*> media,
FnMut<QImage(QImage)> postprocess,
FnMut<void(QImage&&)> done) {
auto result = base::binary_guard();
crl::async([
bytes = media->bytes(),
path = media->owner()->filepath(),
postprocess = std::move(postprocess),
guard = result.make_guard(),
callback = std::move(done)
]() mutable {
auto format = QByteArray();
if (bytes.isEmpty()) {
QFile f(path);
if (f.size() <= App::kImageSizeLimit
&& f.open(QIODevice::ReadOnly)) {
bytes = f.readAll();
}
}
auto image = bytes.isEmpty()
? QImage()
: App::readImage(bytes, &format, false, nullptr);
if (postprocess) {
image = postprocess(std::move(image));
}
crl::on_main(std::move(guard), [
image = std::move(image),
callback = std::move(callback)
]() mutable {
callback(std::move(image));
});
});
return result;
}
} // namespace Data

View File

@@ -362,15 +362,16 @@ protected:
class DocumentOpenClickHandler : public DocumentClickHandler {
public:
using DocumentClickHandler::DocumentClickHandler;
static void Open(
Data::FileOrigin origin,
DocumentOpenClickHandler(
not_null<DocumentData*> document,
HistoryItem *context);
Fn<void()> &&callback);
protected:
void onClickImpl() const override;
private:
Fn<void()> _handler;
};
class DocumentCancelClickHandler : public DocumentClickHandler {
@@ -438,16 +439,3 @@ QString DocumentFileNameForSave(
bool forceSavingAs = false,
const QString &already = QString(),
const QDir &dir = QDir());
namespace Data {
[[nodiscard]] QString FileExtension(const QString &filepath);
[[nodiscard]] bool IsValidMediaFile(const QString &filepath);
[[nodiscard]] bool IsExecutableName(const QString &filepath);
[[nodiscard]] bool IsIpRevealingName(const QString &filepath);
base::binary_guard ReadImageAsync(
not_null<Data::DocumentMedia*> media,
FnMut<QImage(QImage)> postprocess,
FnMut<void(QImage&&)> done);
} // namespace Data

View File

@@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_document_media.h"
#include "data/data_document.h"
#include "data/data_document_resolver.h"
#include "data/data_session.h"
#include "data/data_cloud_themes.h"
#include "data/data_file_origin.h"

View File

@@ -0,0 +1,287 @@
/*
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 "data/data_document_resolver.h"
#include "app.h"
#include "facades.h"
#include "base/platform/base_platform_info.h"
#include "boxes/confirm_box.h"
#include "core/application.h"
#include "core/core_settings.h"
#include "core/mime_type.h"
#include "data/data_document.h"
#include "data/data_document_media.h"
#include "data/data_file_origin.h"
#include "data/data_session.h"
#include "history/view/media/history_view_gif.h"
#include "history/history.h"
#include "history/history_item.h"
#include "media/player/media_player_instance.h"
#include "platform/platform_file_utilities.h"
#include "ui/text/text_utilities.h"
#include "window/window_session_controller.h"
#include <QtCore/QBuffer>
#include <QtCore/QMimeType>
#include <QtCore/QMimeDatabase>
namespace Data {
namespace {
void LaunchWithWarning(
// not_null<Window::Controller*> controller,
const QString &name,
HistoryItem *item) {
const auto isExecutable = Data::IsExecutableName(name);
const auto isIpReveal = Data::IsIpRevealingName(name);
auto &app = Core::App();
const auto warn = [&] {
if (item && item->history()->peer->isVerified()) {
return false;
}
return (isExecutable && app.settings().exeLaunchWarning())
|| (isIpReveal && app.settings().ipRevealWarning());
}();
const auto extension = '.' + Data::FileExtension(name);
if (Platform::IsWindows() && extension == u"."_q) {
// If you launch a file without extension, like "test", in case
// there is an executable file with the same name in this folder,
// like "test.bat", the executable file will be launched.
//
// Now we always force an Open With dialog box for such files.
crl::on_main([=] {
Platform::File::UnsafeShowOpenWith(name);
});
return;
} else if (!warn) {
File::Launch(name);
return;
}
const auto callback = [=, &app](bool checked) {
if (checked) {
if (isExecutable) {
app.settings().setExeLaunchWarning(false);
} else if (isIpReveal) {
app.settings().setIpRevealWarning(false);
}
app.saveSettingsDelayed();
}
File::Launch(name);
};
auto text = isExecutable
? tr::lng_launch_exe_warning(
lt_extension,
rpl::single(Ui::Text::Bold(extension)),
Ui::Text::WithEntities)
: tr::lng_launch_svg_warning(Ui::Text::WithEntities);
Ui::show(Box<ConfirmDontWarnBox>(
std::move(text),
tr::lng_launch_exe_dont_ask(tr::now),
(isExecutable ? tr::lng_launch_exe_sure : tr::lng_continue)(),
callback));
}
} // namespace
QString FileExtension(const QString &filepath) {
const auto reversed = ranges::views::reverse(filepath);
const auto last = ranges::find_first_of(reversed, ".\\/");
if (last == reversed.end() || *last != '.') {
return QString();
}
return QString(last.base(), last - reversed.begin());
}
// bool IsValidMediaFile(const QString &filepath) {
// static const auto kExtensions = [] {
// const auto list = qsl("\
// 16svx 2sf 3g2 3gp 8svx aac aaf aif aifc aiff amr amv ape asf ast au aup \
// avchd avi brstm bwf cam cdda cust dat divx drc dsh dsf dts dtshd dtsma \
// dvr-ms dwd evo f4a f4b f4p f4v fla flac flr flv gif gifv gsf gsm gym iff \
// ifo it jam la ly m1v m2p m2ts m2v m4a m4p m4v mcf mid mk3d mka mks mkv mng \
// mov mp1 mp2 mp3 mp4 minipsf mod mpc mpe mpeg mpg mpv mscz mt2 mus mxf mxl \
// niff nsf nsv off ofr ofs ogg ogv opus ots pac ps psf psf2 psflib ptb qsf \
// qt ra raw rka rm rmj rmvb roq s3m shn sib sid smi smp sol spc spx ssf svi \
// swa swf tak ts tta txm usf vgm vob voc vox vqf wav webm wma wmv wrap wtv \
// wv xm xml ym yuv").split(' ');
// return base::flat_set<QString>(list.begin(), list.end());
// }();
// return ranges::binary_search(
// kExtensions,
// FileExtension(filepath).toLower());
// }
bool IsExecutableName(const QString &filepath) {
static const auto kExtensions = [] {
const auto joined =
#ifdef Q_OS_MAC
qsl("\
applescript action app bin command csh osx workflow terminal url caction \
mpkg pkg scpt scptd xhtm webarchive");
#elif defined Q_OS_UNIX // Q_OS_MAC
qsl("bin csh deb desktop ksh out pet pkg pup rpm run sh shar \
slp zsh");
#else // Q_OS_MAC || Q_OS_UNIX
qsl("\
ad ade adp app application appref-ms asp asx bas bat bin cab cdxml cer cfg \
chi chm cmd cnt com cpl crt csh der diagcab dll drv eml exe fon fxp gadget \
grp hlp hpj hta htt inf ini ins inx isp isu its jar jnlp job js jse key ksh \
lnk local lua mad maf mag mam manifest maq mar mas mat mau mav maw mcf mda \
mdb mde mdt mdw mdz mht mhtml mjs mmc mof msc msg msh msh1 msh2 msh1xml \
msh2xml mshxml msi msp mst ops osd paf pcd phar php php3 php4 php5 php7 phps \
php-s pht phtml pif pl plg pm pod prf prg ps1 ps2 ps1xml ps2xml psc1 psc2 \
psd1 psm1 pssc pst py py3 pyc pyd pyi pyo pyw pywz pyz rb reg rgs scf scr \
sct search-ms settingcontent-ms sh shb shs slk sys t tmp u3p url vb vbe vbp \
vbs vbscript vdx vsmacros vsd vsdm vsdx vss vssm vssx vst vstm vstx vsw vsx \
vtx website ws wsc wsf wsh xbap xll xnk xs");
#endif // !Q_OS_MAC && !Q_OS_UNIX
const auto list = joined.split(' ');
return base::flat_set<QString>(list.begin(), list.end());
}();
return ranges::binary_search(
kExtensions,
FileExtension(filepath).toLower());
}
bool IsIpRevealingName(const QString &filepath) {
static const auto kExtensions = [] {
const auto joined = u"htm html svg"_q;
const auto list = joined.split(' ');
return base::flat_set<QString>(list.begin(), list.end());
}();
static const auto kMimeTypes = [] {
const auto joined = u"text/html image/svg+xml"_q;
const auto list = joined.split(' ');
return base::flat_set<QString>(list.begin(), list.end());
}();
return ranges::binary_search(
kExtensions,
FileExtension(filepath).toLower()
) || ranges::binary_search(
kMimeTypes,
QMimeDatabase().mimeTypeForFile(QFileInfo(filepath)).name()
);
}
base::binary_guard ReadImageAsync(
not_null<Data::DocumentMedia*> media,
FnMut<QImage(QImage)> postprocess,
FnMut<void(QImage&&)> done) {
auto result = base::binary_guard();
crl::async([
bytes = media->bytes(),
path = media->owner()->filepath(),
postprocess = std::move(postprocess),
guard = result.make_guard(),
callback = std::move(done)
]() mutable {
auto format = QByteArray();
if (bytes.isEmpty()) {
QFile f(path);
if (f.size() <= App::kImageSizeLimit
&& f.open(QIODevice::ReadOnly)) {
bytes = f.readAll();
}
}
auto image = bytes.isEmpty()
? QImage()
: App::readImage(bytes, &format, false, nullptr);
if (postprocess) {
image = postprocess(std::move(image));
}
crl::on_main(std::move(guard), [
image = std::move(image),
callback = std::move(callback)
]() mutable {
callback(std::move(image));
});
});
return result;
}
void ResolveDocument(
not_null<Window::SessionController*> controller,
not_null<DocumentData*> document,
HistoryItem *item) {
if (!document->date) {
return;
}
const auto msgId = item ? item->fullId() : FullMsgId();
const auto showDocument = [&] {
if (cUseExternalVideoPlayer()
&& document->isVideoFile()
&& !document->filepath().isEmpty()) {
File::Launch(document->location(false).fname);
} else {
controller->openDocument(document, msgId, true);
}
};
const auto media = document->createMediaView();
const auto openImageInApp = [&] {
if (document->size >= App::kImageSizeLimit) {
return false;
}
const auto &location = document->location(true);
if (!location.isEmpty() && location.accessEnable()) {
const auto guard = gsl::finally([&] {
location.accessDisable();
});
const auto path = location.name();
if (Core::MimeTypeForFile(path).name().startsWith("image/")
&& QImageReader(path).canRead()) {
showDocument();
return true;
}
} else if (document->mimeString().startsWith("image/")
&& !media->bytes().isEmpty()) {
auto bytes = media->bytes();
auto buffer = QBuffer(&bytes);
if (QImageReader(&buffer).canRead()) {
showDocument();
return true;
}
}
return false;
};
const auto &location = document->location(true);
if (document->isTheme() && media->loaded(true)) {
showDocument();
location.accessDisable();
} else if (media->canBePlayed()) {
if (document->isAudioFile()
|| document->isVoiceMessage()
|| document->isVideoMessage()) {
::Media::Player::instance()->playPause({ document, msgId });
} else if (item
&& document->isAnimation()
&& HistoryView::Gif::CanPlayInline(document)) {
document->owner().requestAnimationPlayInline(item);
} else {
showDocument();
}
} else {
document->saveFromDataSilent();
if (!openImageInApp()) {
if (!document->filepath(true).isEmpty()) {
LaunchWithWarning(location.name(), item);
} else if (document->status == FileReady
|| document->status == FileDownloadFailed) {
DocumentSaveClickHandler::Save(
item ? item->fullId() : Data::FileOrigin(),
document);
}
}
}
}
} // namespace Data

View File

@@ -0,0 +1,37 @@
/*
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 "base/binary_guard.h"
class DocumentData;
class HistoryItem;
namespace Window {
class SessionController;
} // namespace Window
namespace Data {
class DocumentMedia;
[[nodiscard]] QString FileExtension(const QString &filepath);
// [[nodiscard]] bool IsValidMediaFile(const QString &filepath);
[[nodiscard]] bool IsExecutableName(const QString &filepath);
[[nodiscard]] bool IsIpRevealingName(const QString &filepath);
base::binary_guard ReadImageAsync(
not_null<Data::DocumentMedia*> media,
FnMut<QImage(QImage)> postprocess,
FnMut<void(QImage&&)> done);
void ResolveDocument(
not_null<Window::SessionController*> controller,
not_null<DocumentData*> document,
HistoryItem *item);
} // namespace Data

View File

@@ -478,8 +478,17 @@ PhotoClickHandler::PhotoClickHandler(
, _peer(peer) {
}
PhotoOpenClickHandler::PhotoOpenClickHandler(
not_null<PhotoData*> photo,
Fn<void()> &&callback)
: PhotoClickHandler(photo)
, _handler(std::move(callback)) {
}
void PhotoOpenClickHandler::onClickImpl() const {
Core::App().showPhoto(this);
if (_handler) {
_handler();
}
}
void PhotoSaveClickHandler::onClickImpl() const {

View File

@@ -198,11 +198,14 @@ private:
class PhotoOpenClickHandler : public PhotoClickHandler {
public:
using PhotoClickHandler::PhotoClickHandler;
PhotoOpenClickHandler(not_null<PhotoData*> photo, Fn<void()> &&callback);
protected:
void onClickImpl() const override;
private:
Fn<void()> _handler;
};
class PhotoSaveClickHandler : public PhotoClickHandler {

View File

@@ -199,7 +199,6 @@ class PhotoSaveClickHandler;
class PhotoCancelClickHandler;
class DocumentClickHandler;
class DocumentSaveClickHandler;
class DocumentOpenClickHandler;
class DocumentCancelClickHandler;
class DocumentWrappedClickHandler;
class VoiceSeekClickHandler;

View File

@@ -126,9 +126,6 @@ InnerWidget::InnerWidget(
_cancelSearchInChat->setClickedCallback([=] { cancelSearchInChat(); });
_cancelSearchInChat->hide();
_cancelSearchFromUser->setClickedCallback([=] {
searchFromUserChanged.notify(nullptr);
});
_cancelSearchFromUser->hide();
session().downloaderTaskFinished(
@@ -136,13 +133,13 @@ InnerWidget::InnerWidget(
update();
}, lifetime());
subscribe(Core::App().notifications().settingsChanged(), [=](
Window::Notifications::ChangeType change) {
Core::App().notifications().settingsChanged(
) | rpl::start_with_next([=](Window::Notifications::ChangeType change) {
if (change == Window::Notifications::ChangeType::CountMessages) {
// Folder rows change their unread badge with this setting.
update();
}
});
}, lifetime());
session().data().contactsLoaded().changes(
) | rpl::start_with_next([=] {
@@ -1957,6 +1954,10 @@ rpl::producer<> InnerWidget::listBottomReached() const {
return _listBottomReached.events();
}
rpl::producer<> InnerWidget::cancelSearchFromUserRequests() const {
return _cancelSearchFromUser->clicks() | rpl::to_empty;
}
void InnerWidget::visibleTopBottomUpdated(
int visibleTop,
int visibleBottom) {
@@ -3191,7 +3192,7 @@ void InnerWidget::setupShortcuts() {
});
request->check(Command::ShowContacts) && request->handle([=] {
Ui::show(PrepareContactsBox(_controller));
_controller->show(PrepareContactsBox(_controller));
return true;
});

View File

@@ -120,9 +120,7 @@ public:
void setLoadMoreCallback(Fn<void()> callback);
[[nodiscard]] rpl::producer<> listBottomReached() const;
base::Observable<PeerData*> searchFromUserChanged;
[[nodiscard]] rpl::producer<> cancelSearchFromUserRequests() const;
[[nodiscard]] rpl::producer<ChosenRow> chosenRow() const;
[[nodiscard]] rpl::producer<> updated() const;

View File

@@ -20,6 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "lang/lang_keys.h"
#include "mainwindow.h"
#include "mainwidget.h"
#include "main/main_domain.h"
#include "main/main_session.h"
#include "main/main_session_settings.h"
#include "apiwrap.h"
@@ -28,12 +29,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "core/update_checker.h"
#include "boxes/peer_list_box.h"
#include "boxes/peers/edit_participants_box.h"
#include "window/window_adaptive.h"
#include "window/window_session_controller.h"
#include "window/window_slide_animation.h"
#include "window/window_connecting_widget.h"
#include "window/window_main_menu.h"
#include "storage/storage_media_prepare.h"
#include "storage/storage_account.h"
#include "storage/storage_domain.h"
#include "data/data_session.h"
#include "data/data_channel.h"
#include "data/data_chat.h"
@@ -207,10 +210,11 @@ Widget::Widget(
connect(_inner, SIGNAL(completeHashtag(QString)), this, SLOT(onCompleteHashtag(QString)));
connect(_inner, SIGNAL(refreshHashtags()), this, SLOT(onFilterCursorMoved()));
connect(_inner, SIGNAL(cancelSearchInChat()), this, SLOT(onCancelSearchInChat()));
subscribe(_inner->searchFromUserChanged, [this](PeerData *from) {
setSearchInChat(_searchInChat, from);
_inner->cancelSearchFromUserRequests(
) | rpl::start_with_next([=] {
setSearchInChat(_searchInChat, nullptr);
applyFilterUpdate(true);
});
}, lifetime());
_inner->chosenRow(
) | rpl::start_with_next([=](const ChosenRow &row) {
const auto openSearchResult = !controller->selectingPeer()
@@ -262,13 +266,21 @@ Widget::Widget(
}, lifetime());
}
subscribe(Adaptive::Changed(), [this] { updateForwardBar(); });
controller->adaptive().changed(
) | rpl::start_with_next([=] {
updateForwardBar();
}, lifetime());
_cancelSearch->setClickedCallback([this] { onCancelSearch(); });
_jumpToDate->entity()->setClickedCallback([this] { showJumpToDate(); });
_chooseFromUser->entity()->setClickedCallback([this] { showSearchFrom(); });
_lockUnlock->setVisible(Global::LocalPasscode());
subscribe(Global::RefLocalPasscodeChanged(), [this] { updateLockUnlockVisibility(); });
rpl::single(
rpl::empty_value()
) | rpl::then(
session().domain().local().localPasscodeChanged()
) | rpl::start_with_next([=] {
updateLockUnlockVisibility();
}, lifetime());
_lockUnlock->setClickedCallback([this] {
_lockUnlock->setIconOverride(&st::dialogsUnlockIcon, &st::dialogsUnlockIconOver);
Core::App().lockByPasscode();
@@ -406,7 +418,7 @@ void Widget::setupConnectingWidget() {
_connecting = std::make_unique<Window::ConnectionState>(
this,
&session().account(),
Window::AdaptiveIsOneColumn());
controller()->adaptive().oneColumnValue());
}
void Widget::setupSupportMode() {
@@ -1269,7 +1281,7 @@ void Widget::dragEnterEvent(QDragEnterEvent *e) {
const auto data = e->mimeData();
_dragInScroll = false;
_dragForward = Adaptive::OneColumn()
_dragForward = controller()->adaptive().isOneColumn()
? false
: data->hasFormat(qsl("application/x-td-forward"));
if (_dragForward) {
@@ -1501,7 +1513,7 @@ void Widget::updateLockUnlockVisibility() {
if (_a_show.animating()) {
return;
}
const auto hidden = !Global::LocalPasscode();
const auto hidden = !session().domain().local().hasLocalPasscode();
if (_lockUnlock->isHidden() != hidden) {
_lockUnlock->setVisible(!hidden);
updateControlsGeometry();
@@ -1559,7 +1571,7 @@ void Widget::updateControlsGeometry() {
auto smallLayoutWidth = (st::dialogsPadding.x() + st::dialogsPhotoSize + st::dialogsPadding.x());
auto smallLayoutRatio = (width() < st::columnMinimalWidthLeft) ? (st::columnMinimalWidthLeft - width()) / float64(st::columnMinimalWidthLeft - smallLayoutWidth) : 0.;
auto filterLeft = (controller()->filtersWidth() ? st::dialogsFilterSkip : st::dialogsFilterPadding.x() + _mainMenuToggle->width()) + st::dialogsFilterPadding.x();
auto filterRight = (Global::LocalPasscode() ? (st::dialogsFilterPadding.x() + _lockUnlock->width()) : st::dialogsFilterSkip) + st::dialogsFilterPadding.x();
auto filterRight = (_lockUnlock->isVisible() ? (st::dialogsFilterPadding.x() + _lockUnlock->width()) : st::dialogsFilterSkip) + st::dialogsFilterPadding.x();
auto filterWidth = qMax(width(), st::columnMinimalWidthLeft) - filterLeft - filterRight;
auto filterAreaHeight = st::topBarHeight;
_searchControls->setGeometry(0, filterAreaTop, width(), filterAreaHeight);
@@ -1616,16 +1628,21 @@ void Widget::updateControlsGeometry() {
}
}
rpl::producer<> Widget::closeForwardBarRequests() const {
return _closeForwardBarRequests.events();
}
void Widget::updateForwardBar() {
auto selecting = controller()->selectingPeer();
auto oneColumnSelecting = (Adaptive::OneColumn() && selecting);
auto oneColumnSelecting = (controller()->adaptive().isOneColumn()
&& selecting);
if (!oneColumnSelecting == !_forwardCancel) {
return;
}
if (oneColumnSelecting) {
_forwardCancel.create(this, st::dialogsForwardCancel);
_forwardCancel->setClickedCallback([] {
Global::RefPeerChooseCancel().notify(true);
_forwardCancel->setClickedCallback([=] {
_closeForwardBarRequests.fire({});
});
if (!_a_show.animating()) _forwardCancel->show();
} else {
@@ -1738,7 +1755,7 @@ bool Widget::onCancelSearch() {
bool clearing = !_filter->getLastText().isEmpty();
cancelSearchRequest();
if (_searchInChat && !clearing) {
if (Adaptive::OneColumn()) {
if (controller()->adaptive().isOneColumn()) {
if (const auto peer = _searchInChat.peer()) {
Ui::showPeerHistory(peer, ShowAtUnreadMsgId);
} else {
@@ -1757,8 +1774,9 @@ bool Widget::onCancelSearch() {
void Widget::onCancelSearchInChat() {
cancelSearchRequest();
const auto isOneColumn = controller()->adaptive().isOneColumn();
if (_searchInChat) {
if (Adaptive::OneColumn()
if (isOneColumn
&& !controller()->selectingPeer()
&& _filter->getLastText().trimmed().isEmpty()) {
if (const auto peer = _searchInChat.peer()) {
@@ -1770,7 +1788,7 @@ void Widget::onCancelSearchInChat() {
setSearchInChat(Key());
}
applyFilterUpdate(true);
if (!Adaptive::OneColumn() && !controller()->selectingPeer()) {
if (!isOneColumn && !controller()->selectingPeer()) {
cancelled();
}
}

View File

@@ -87,6 +87,8 @@ public:
void updateForwardBar();
[[nodiscard]] rpl::producer<> closeForwardBarRequests() const;
// Float player interface.
bool floatPlayerHandleWheelEvent(QEvent *e) override;
QRect floatPlayerAvailableRect() override;
@@ -245,6 +247,8 @@ private:
int _topDelta = 0;
rpl::event_stream<> _closeForwardBarRequests;
};
} // namespace Dialogs

View File

@@ -269,10 +269,6 @@ void showChatsList(not_null<Main::Session*> session) {
}
}
void showPeerHistoryAtItem(not_null<const HistoryItem*> item) {
showPeerHistory(item->history()->peer, item->id);
}
void showPeerHistory(not_null<const History*> history, MsgId msgId) {
showPeerHistory(history->peer, msgId);
}
@@ -318,87 +314,3 @@ bool switchInlineBotButtonReceived(
}
} // namespace Notify
#define DefineReadOnlyVar(Namespace, Type, Name) const Type &Name() { \
AssertCustom(Namespace##Data != nullptr, #Namespace "Data != nullptr in " #Namespace "::" #Name); \
return Namespace##Data->Name; \
}
#define DefineRefVar(Namespace, Type, Name) DefineReadOnlyVar(Namespace, Type, Name) \
Type &Ref##Name() { \
AssertCustom(Namespace##Data != nullptr, #Namespace "Data != nullptr in " #Namespace "::Ref" #Name); \
return Namespace##Data->Name; \
}
#define DefineVar(Namespace, Type, Name) DefineRefVar(Namespace, Type, Name) \
void Set##Name(const Type &Name) { \
AssertCustom(Namespace##Data != nullptr, #Namespace "Data != nullptr in " #Namespace "::Set" #Name); \
Namespace##Data->Name = Name; \
}
namespace Global {
namespace internal {
struct Data {
bool ScreenIsLocked = false;
Adaptive::WindowLayout AdaptiveWindowLayout = Adaptive::WindowLayout::Normal;
Adaptive::ChatLayout AdaptiveChatLayout = Adaptive::ChatLayout::Normal;
base::Observable<void> AdaptiveChanged;
bool NotificationsDemoIsShown = false;
bool TryIPv6 = !Platform::IsWindows();
std::vector<MTP::ProxyData> ProxiesList;
MTP::ProxyData SelectedProxy;
MTP::ProxyData::Settings ProxySettings = MTP::ProxyData::Settings::System;
bool UseProxyForCalls = false;
base::Observable<void> ConnectionTypeChanged;
bool LocalPasscode = false;
base::Observable<void> LocalPasscodeChanged;
base::Variable<DBIWorkMode> WorkMode = { dbiwmWindowAndTray };
base::Observable<void> PeerChooseCancel;
};
} // namespace internal
} // namespace Global
Global::internal::Data *GlobalData = nullptr;
namespace Global {
bool started() {
return GlobalData != nullptr;
}
void start() {
GlobalData = new internal::Data();
}
void finish() {
delete GlobalData;
GlobalData = nullptr;
}
DefineVar(Global, bool, ScreenIsLocked);
DefineVar(Global, Adaptive::WindowLayout, AdaptiveWindowLayout);
DefineVar(Global, Adaptive::ChatLayout, AdaptiveChatLayout);
DefineRefVar(Global, base::Observable<void>, AdaptiveChanged);
DefineVar(Global, bool, NotificationsDemoIsShown);
DefineVar(Global, bool, TryIPv6);
DefineVar(Global, std::vector<MTP::ProxyData>, ProxiesList);
DefineVar(Global, MTP::ProxyData, SelectedProxy);
DefineVar(Global, MTP::ProxyData::Settings, ProxySettings);
DefineVar(Global, bool, UseProxyForCalls);
DefineRefVar(Global, base::Observable<void>, ConnectionTypeChanged);
DefineVar(Global, bool, LocalPasscode);
DefineRefVar(Global, base::Observable<void>, LocalPasscodeChanged);
DefineRefVar(Global, base::Variable<DBIWorkMode>, WorkMode);
DefineRefVar(Global, base::Observable<void>, PeerChooseCancel);
} // namespace Global

View File

@@ -58,7 +58,6 @@ namespace Ui {
void showPeerProfile(not_null<PeerData*> peer);
void showPeerProfile(not_null<const History*> history);
void showPeerHistoryAtItem(not_null<const HistoryItem*> item);
void showPeerHistory(not_null<const PeerData*> peer, MsgId msgId);
void showPeerHistory(not_null<const History*> history, MsgId msgId);
void showChatsList(not_null<Main::Session*> session);
@@ -82,73 +81,3 @@ bool switchInlineBotButtonReceived(
MsgId samePeerReplyTo = 0);
} // namespace Notify
#define DeclareReadOnlyVar(Type, Name) const Type &Name();
#define DeclareRefVar(Type, Name) DeclareReadOnlyVar(Type, Name) \
Type &Ref##Name();
#define DeclareVar(Type, Name) DeclareRefVar(Type, Name) \
void Set##Name(const Type &Name);
namespace Adaptive {
enum class WindowLayout {
OneColumn,
Normal,
ThreeColumn,
};
enum class ChatLayout {
Normal,
Wide,
};
} // namespace Adaptive
namespace Global {
bool started();
void start();
void finish();
DeclareVar(bool, ScreenIsLocked);
DeclareVar(Adaptive::ChatLayout, AdaptiveChatLayout);
DeclareVar(Adaptive::WindowLayout, AdaptiveWindowLayout);
DeclareRefVar(base::Observable<void>, AdaptiveChanged);
DeclareVar(bool, NotificationsDemoIsShown);
DeclareVar(bool, TryIPv6);
DeclareVar(std::vector<MTP::ProxyData>, ProxiesList);
DeclareVar(MTP::ProxyData, SelectedProxy);
DeclareVar(MTP::ProxyData::Settings, ProxySettings);
DeclareVar(bool, UseProxyForCalls);
DeclareRefVar(base::Observable<void>, ConnectionTypeChanged);
DeclareVar(bool, LocalPasscode);
DeclareRefVar(base::Observable<void>, LocalPasscodeChanged);
DeclareRefVar(base::Variable<DBIWorkMode>, WorkMode);
DeclareRefVar(base::Observable<void>, PeerChooseCancel);
} // namespace Global
namespace Adaptive {
inline base::Observable<void> &Changed() {
return Global::RefAdaptiveChanged();
}
inline bool OneColumn() {
return Global::AdaptiveWindowLayout() == WindowLayout::OneColumn;
}
inline bool Normal() {
return Global::AdaptiveWindowLayout() == WindowLayout::Normal;
}
inline bool ThreeColumn() {
return Global::AdaptiveWindowLayout() == WindowLayout::ThreeColumn;
}
} // namespace Adaptive

View File

@@ -478,7 +478,8 @@ void InnerWidget::showFilter(Fn<void(FilterValue &&filter)> callback) {
if (_admins.empty()) {
_showFilterCallback = std::move(callback);
} else {
Ui::show(Box<FilterBox>(_channel, _admins, _filter, std::move(callback)));
_controller->show(
Box<FilterBox>(_channel, _admins, _filter, std::move(callback)));
}
}
@@ -601,6 +602,19 @@ void InnerWidget::elementShowPollResults(
FullMsgId context) {
}
void InnerWidget::elementOpenPhoto(
not_null<PhotoData*> photo,
FullMsgId context) {
_controller->openPhoto(photo, context);
}
void InnerWidget::elementOpenDocument(
not_null<DocumentData*> document,
FullMsgId context,
bool showInMediaView) {
_controller->openDocument(document, context, showInMediaView);
}
void InnerWidget::elementShowTooltip(
const TextWithEntities &text,
Fn<void()> hiddenCallback) {
@@ -626,6 +640,10 @@ void InnerWidget::elementSendBotCommand(
void InnerWidget::elementHandleViaClick(not_null<UserData*> bot) {
}
bool InnerWidget::elementIsChatWide() {
return _controller->adaptive().isChatWide();
}
void InnerWidget::saveState(not_null<SectionMemento*> memento) {
memento->setFilter(std::move(_filter));
memento->setAdmins(std::move(_admins));
@@ -941,14 +959,17 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
p.setOpacity(opacity);
const auto dateY = /*noFloatingDate ? itemtop :*/ (dateTop - st::msgServiceMargin.top());
const auto width = view->width();
const auto chatWide =
_controller->adaptive().isChatWide();
if (const auto date = view->Get<HistoryView::DateBadge>()) {
date->paint(p, dateY, width);
date->paint(p, dateY, width, chatWide);
} else {
HistoryView::ServiceMessagePainter::paintDate(
p,
view->dateTime(),
dateY,
width);
width,
chatWide);
}
}
}
@@ -1272,7 +1293,7 @@ void InnerWidget::openContextGif(FullMsgId itemId) {
if (const auto item = session().data().message(itemId)) {
if (const auto media = item->media()) {
if (const auto document = media->document()) {
Core::App().showDocument(document, item);
_controller->openDocument(document, itemId, true);
}
}
}
@@ -1310,7 +1331,8 @@ void InnerWidget::suggestRestrictUser(not_null<UserData*> user) {
(*weakBox)->closeBox();
}
});
*weakBox = Ui::show(
*weakBox = QPointer<EditRestrictedBox>(box.data());
_controller->show(
std::move(box),
Ui::LayerOption::KeepOther);
};

View File

@@ -108,6 +108,13 @@ public:
void elementShowPollResults(
not_null<PollData*> poll,
FullMsgId context) override;
void elementOpenPhoto(
not_null<PhotoData*> photo,
FullMsgId context) override;
void elementOpenDocument(
not_null<DocumentData*> document,
FullMsgId context,
bool showInMediaView = false) override;
void elementShowTooltip(
const TextWithEntities &text,
Fn<void()> hiddenCallback) override;
@@ -120,6 +127,7 @@ public:
const QString &command,
const FullMsgId &context) override;
void elementHandleViaClick(not_null<UserData*> bot) override;
bool elementIsChatWide() override;
~InnerWidget();

View File

@@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "mainwindow.h"
#include "apiwrap.h"
#include "window/themes/window_theme.h"
#include "window/window_adaptive.h"
#include "window/window_session_controller.h"
#include "boxes/confirm_box.h"
#include "base/timer.h"
@@ -34,16 +35,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace AdminLog {
class FixedBar final : public TWidget, private base::Subscriber {
class FixedBar final : public TWidget {
public:
FixedBar(
QWidget *parent,
not_null<Window::SessionController*> controller,
not_null<ChannelData*> channel);
base::Observable<void> showFilterSignal;
base::Observable<void> searchCancelledSignal;
base::Observable<QString> searchSignal;
[[nodiscard]] rpl::producer<> showFilterRequests() const;
[[nodiscard]] rpl::producer<> searchCancelRequests() const;
[[nodiscard]] rpl::producer<QString> searchRequests() const;
// When animating mode is enabled the content is hidden and the
// whole fixed bar acts like a back button.
@@ -85,6 +86,9 @@ private:
bool _animatingMode = false;
base::Timer _searchTimer;
rpl::event_stream<> _searchCancelRequests;
rpl::event_stream<QString> _searchRequests;
};
object_ptr<Window::SectionWidget> SectionMemento::createWidget(
@@ -110,13 +114,13 @@ FixedBar::FixedBar(
, _backButton(
this,
&controller->session(),
tr::lng_admin_log_title_all(tr::now))
tr::lng_admin_log_title_all(tr::now),
controller->adaptive().oneColumnValue())
, _search(this, st::topBarSearch)
, _cancel(this, st::historyAdminLogCancelSearch)
, _filter(this, tr::lng_admin_log_filter(), st::topBarButton) {
_backButton->moveToLeft(0, 0);
_backButton->setClickedCallback([=] { goBack(); });
_filter->setClickedCallback([=] { showFilterSignal.notify(); });
_search->setClickedCallback([=] { showSearch(); });
_cancel->setClickedCallback([=] { cancelSearch(); });
_field->hide();
@@ -158,7 +162,7 @@ void FixedBar::toggleSearch() {
_field->show();
_field->setFocus();
} else {
searchCancelledSignal.notify(true);
_searchCancelRequests.fire({});
}
}
@@ -198,7 +202,7 @@ void FixedBar::searchUpdated() {
}
void FixedBar::applySearch() {
searchSignal.notify(_field->getLastText());
_searchRequests.fire_copy(_field->getLastText());
}
int FixedBar::resizeGetHeight(int newWidth) {
@@ -223,6 +227,18 @@ int FixedBar::resizeGetHeight(int newWidth) {
return newHeight;
}
rpl::producer<> FixedBar::showFilterRequests() const {
return _filter->clicks() | rpl::to_empty;
}
rpl::producer<> FixedBar::searchCancelRequests() const {
return _searchCancelRequests.events();
}
rpl::producer<QString> FixedBar::searchRequests() const {
return _searchRequests.events();
}
void FixedBar::setAnimatingMode(bool enabled) {
if (_animatingMode != enabled) {
_animatingMode = enabled;
@@ -266,14 +282,29 @@ Widget::Widget(
, _whatIsThis(this, tr::lng_admin_log_about(tr::now).toUpper(), st::historyComposeButton) {
_fixedBar->move(0, 0);
_fixedBar->resizeToWidth(width());
subscribe(_fixedBar->showFilterSignal, [this] { showFilter(); });
subscribe(_fixedBar->searchCancelledSignal, [this] { setInnerFocus(); });
subscribe(_fixedBar->searchSignal, [this](const QString &query) { _inner->applySearch(query); });
_fixedBar->showFilterRequests(
) | rpl::start_with_next([=] {
showFilter();
}, lifetime());
_fixedBar->searchCancelRequests(
) | rpl::start_with_next([=] {
setInnerFocus();
}, lifetime());
_fixedBar->searchRequests(
) | rpl::start_with_next([=](const QString &query) {
_inner->applySearch(query);
}, lifetime());
_fixedBar->show();
_fixedBarShadow->raise();
updateAdaptiveLayout();
subscribe(Adaptive::Changed(), [this] { updateAdaptiveLayout(); });
rpl::single(
rpl::empty_value()
) | rpl::then(
controller->adaptive().changed()
) | rpl::start_with_next([=] {
updateAdaptiveLayout();
}, lifetime());
_inner = _scroll->setOwnedWidget(object_ptr<InnerWidget>(this, controller, channel));
_inner->showSearchSignal(
@@ -295,7 +326,7 @@ Widget::Widget(
connect(_scroll, &Ui::ScrollArea::scrolled, this, [this] { onScroll(); });
_whatIsThis->setClickedCallback([=] {
Ui::show(Box<InformBox>(channel->isMegagroup()
controller->show(Box<InformBox>(channel->isMegagroup()
? tr::lng_admin_log_about_text(tr::now)
: tr::lng_admin_log_about_text_channel(tr::now)));
});
@@ -311,7 +342,11 @@ void Widget::showFilter() {
}
void Widget::updateAdaptiveLayout() {
_fixedBarShadow->moveToLeft(Adaptive::OneColumn() ? 0 : st::lineWidth, _fixedBar->height());
_fixedBarShadow->moveToLeft(
controller()->adaptive().isOneColumn()
? 0
: st::lineWidth,
_fixedBar->height());
}
not_null<ChannelData*> Widget::channel() const {

View File

@@ -32,6 +32,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/ui_utility.h"
#include "ui/cached_round_corners.h"
#include "ui/inactive_press.h"
#include "window/window_adaptive.h"
#include "window/window_session_controller.h"
#include "window/window_peer_menu.h"
#include "window/window_controller.h"
@@ -169,14 +170,13 @@ HistoryInner::HistoryInner(
notifyIsBotChanged();
setMouseTracking(true);
subscribe(_controller->gifPauseLevelChanged(), [this] {
if (!_controller->isGifPausedAtLeastFor(Window::GifPauseReason::Any)) {
_controller->gifPauseLevelChanged(
) | rpl::start_with_next([=] {
if (!_controller->isGifPausedAtLeastFor(
Window::GifPauseReason::Any)) {
update();
}
});
subscribe(_controller->widget()->dragFinished(), [this] {
mouseActionUpdate(QCursor::pos());
});
}, lifetime());
session().data().itemRemoved(
) | rpl::start_with_next(
[this](auto item) { itemRemoved(item); },
@@ -209,6 +209,11 @@ HistoryInner::HistoryInner(
) | rpl::start_with_next([=] {
update();
}, lifetime());
controller->adaptive().chatWideValue(
) | rpl::start_with_next([=](bool wide) {
_isChatWide = wide;
}, lifetime());
}
Main::Session &HistoryInner::session() const {
@@ -358,7 +363,7 @@ bool HistoryInner::canHaveFromUserpics() const {
if (_peer->isUser()
&& !_peer->isSelf()
&& !_peer->isRepliesChat()
&& !Core::App().settings().chatWide()) {
&& !_isChatWide) {
return false;
} else if (_peer->isChannel() && !_peer->isMegagroup()) {
return false;
@@ -772,13 +777,14 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
? itemtop
: (dateTop - st::msgServiceMargin.top());
if (const auto date = view->Get<HistoryView::DateBadge>()) {
date->paint(p, dateY, _contentWidth);
date->paint(p, dateY, _contentWidth, _isChatWide);
} else {
HistoryView::ServiceMessagePainter::paintDate(
p,
view->dateTime(),
dateY,
_contentWidth);
_contentWidth,
_isChatWide);
}
}
}
@@ -1211,7 +1217,7 @@ std::unique_ptr<QMimeData> HistoryInner::prepareDrag() {
_widget->noSelectingScroll();
if (!urls.isEmpty()) mimeData->setUrls(urls);
if (uponSelected && !Adaptive::OneColumn()) {
if (uponSelected && !_controller->adaptive().isOneColumn()) {
auto selectedState = getSelectionState();
if (selectedState.count > 0 && selectedState.count == selectedState.canForwardCount) {
session().data().setMimeForwardIds(getSelectedItems());
@@ -1259,7 +1265,9 @@ std::unique_ptr<QMimeData> HistoryInner::prepareDrag() {
void HistoryInner::performDrag() {
if (auto mimeData = prepareDrag()) {
// This call enters event loop and can destroy any QObject.
_controller->widget()->launchDrag(std::move(mimeData));
_controller->widget()->launchDrag(
std::move(mimeData),
crl::guard(this, [=] { mouseActionUpdate(QCursor::pos()); }));
}
}
@@ -1949,7 +1957,7 @@ void HistoryInner::openContextGif(FullMsgId itemId) {
if (const auto item = session().data().message(itemId)) {
if (const auto media = item->media()) {
if (const auto document = media->document()) {
Core::App().showDocument(document, item);
_controller->openDocument(document, itemId, true);
}
}
}
@@ -2161,7 +2169,7 @@ void HistoryInner::recountHistoryGeometry() {
: (st::msgNameFont->height + st::botDescSkip);
int32 descH = st::msgMargin.top() + st::msgPadding.top() + descriptionHeight + _botAbout->height + st::msgPadding.bottom() + st::msgMargin.bottom();
int32 descMaxWidth = _scroll->width();
if (Core::App().settings().chatWide()) {
if (_isChatWide) {
descMaxWidth = qMin(descMaxWidth, int32(st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left()));
}
int32 descAtX = (descMaxWidth - _botAbout->width) / 2 - st::msgPadding.left();
@@ -2368,7 +2376,7 @@ void HistoryInner::updateSize() {
: (st::msgNameFont->height + st::botDescSkip);
int32 descH = st::msgMargin.top() + st::msgPadding.top() + descriptionHeight + _botAbout->height + st::msgPadding.bottom() + st::msgMargin.bottom();
int32 descMaxWidth = _scroll->width();
if (Core::App().settings().chatWide()) {
if (_isChatWide) {
descMaxWidth = qMin(descMaxWidth, int32(st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left()));
}
int32 descAtX = (descMaxWidth - _botAbout->width) / 2 - st::msgPadding.left();
@@ -2559,6 +2567,19 @@ void HistoryInner::elementShowPollResults(
_controller->showPollResults(poll, context);
}
void HistoryInner::elementOpenPhoto(
not_null<PhotoData*> photo,
FullMsgId context) {
_controller->openPhoto(photo, context);
}
void HistoryInner::elementOpenDocument(
not_null<DocumentData*> document,
FullMsgId context,
bool showInMediaView) {
_controller->openDocument(document, context, showInMediaView);
}
void HistoryInner::elementShowTooltip(
const TextWithEntities &text,
Fn<void()> hiddenCallback) {
@@ -2591,6 +2612,10 @@ void HistoryInner::elementHandleViaClick(not_null<UserData*> bot) {
App::insertBotCommand('@' + bot->username);
}
bool HistoryInner::elementIsChatWide() {
return _isChatWide;
}
auto HistoryInner::getSelectionState() const
-> HistoryView::TopBarWidget::SelectedState {
auto result = HistoryView::TopBarWidget::SelectedState {};
@@ -2747,7 +2772,7 @@ void HistoryInner::mouseActionUpdate() {
dateWidth += st::msgServicePadding.left() + st::msgServicePadding.right();
auto dateLeft = st::msgServiceMargin.left();
auto maxwidth = _contentWidth;
if (Core::App().settings().chatWide()) {
if (_isChatWide) {
maxwidth = qMin(maxwidth, int32(st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left()));
}
auto widthForDate = maxwidth - st::msgServiceMargin.left() - st::msgServiceMargin.left();
@@ -3214,7 +3239,7 @@ void HistoryInner::deleteItem(not_null<HistoryItem*> item) {
}
}
const auto suggestModerateActions = true;
Ui::show(Box<DeleteMessagesBox>(item, suggestModerateActions));
_controller->show(Box<DeleteMessagesBox>(item, suggestModerateActions));
}
bool HistoryInner::hasPendingResizedItems() const {
@@ -3228,7 +3253,7 @@ void HistoryInner::deleteAsGroup(FullMsgId itemId) {
if (!group) {
return deleteItem(item);
}
Ui::show(Box<DeleteMessagesBox>(
_controller->show(Box<DeleteMessagesBox>(
&session(),
session().data().itemsToIds(group->items)));
}
@@ -3251,7 +3276,7 @@ void HistoryInner::reportAsGroup(FullMsgId itemId) {
void HistoryInner::blockSenderItem(FullMsgId itemId) {
if (const auto item = session().data().message(itemId)) {
Ui::show(Box(
_controller->show(Box(
Window::BlockSenderFromRepliesBox,
_controller,
itemId));
@@ -3433,6 +3458,24 @@ not_null<HistoryView::ElementDelegate*> HistoryInner::ElementDelegate() {
Instance->elementShowPollResults(poll, context);
}
}
void elementOpenPhoto(
not_null<PhotoData*> photo,
FullMsgId context) override {
if (Instance) {
Instance->elementOpenPhoto(photo, context);
}
}
void elementOpenDocument(
not_null<DocumentData*> document,
FullMsgId context,
bool showInMediaView = false) override {
if (Instance) {
Instance->elementOpenDocument(
document,
context,
showInMediaView);
}
}
void elementShowTooltip(
const TextWithEntities &text,
Fn<void()> hiddenCallback) override {
@@ -3461,6 +3504,11 @@ not_null<HistoryView::ElementDelegate*> HistoryInner::ElementDelegate() {
Instance->elementHandleViaClick(bot);
}
}
bool elementIsChatWide() override {
return Instance
? Instance->elementIsChatWide()
: false;
}
};
static Result result;

View File

@@ -41,8 +41,7 @@ enum class ReportReason;
class HistoryWidget;
class HistoryInner
: public Ui::RpWidget
, public Ui::AbstractTooltipShower
, private base::Subscriber {
, public Ui::AbstractTooltipShower {
// The Q_OBJECT meta info is used for qobject_cast!
Q_OBJECT
@@ -89,6 +88,13 @@ public:
void elementShowPollResults(
not_null<PollData*> poll,
FullMsgId context);
void elementOpenPhoto(
not_null<PhotoData*> photo,
FullMsgId context);
void elementOpenDocument(
not_null<DocumentData*> document,
FullMsgId context,
bool showInMediaView = false);
void elementShowTooltip(
const TextWithEntities &text,
Fn<void()> hiddenCallback);
@@ -97,6 +103,7 @@ public:
const QString &command,
const FullMsgId &context);
void elementHandleViaClick(not_null<UserData*> bot);
bool elementIsChatWide();
void updateBotInfo(bool recount = true);
@@ -357,6 +364,8 @@ private:
SelectedItems _selected;
std::optional<Ui::ReportReason> _chooseForReportReason;
bool _isChatWide = false;
base::flat_set<not_null<const HistoryItem*>> _animatedStickersPlayed;
base::flat_map<
not_null<PeerData*>,

View File

@@ -113,6 +113,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "main/main_session_settings.h"
#include "window/themes/window_theme.h"
#include "window/notifications_manager.h"
#include "window/window_adaptive.h"
#include "window/window_controller.h"
#include "window/window_session_controller.h"
#include "window/window_slide_animation.h"
@@ -412,7 +413,8 @@ HistoryWidget::HistoryWidget(
Window::ActivateWindow(controller);
});
subscribe(Adaptive::Changed(), [=] {
controller->adaptive().changed(
) | rpl::start_with_next([=] {
if (_history) {
_history->forceFullResize();
if (_migrated) {
@@ -421,7 +423,7 @@ HistoryWidget::HistoryWidget(
updateHistoryGeometry();
update();
}
});
}, lifetime());
session().data().unreadItemAdded(
) | rpl::start_with_next([=](not_null<HistoryItem*> item) {
@@ -625,7 +627,7 @@ HistoryWidget::HistoryWidget(
const auto unavailable = _peer->computeUnavailableReason();
if (!unavailable.isEmpty()) {
controller->showBackFromStack();
Ui::show(Box<InformBox>(unavailable));
controller->show(Box<InformBox>(unavailable));
return;
}
}
@@ -789,7 +791,7 @@ void HistoryWidget::initVoiceRecordBar() {
? Data::RestrictionError(_peer, ChatRestriction::f_send_media)
: std::nullopt;
if (error) {
Ui::show(Box<InformBox>(*error));
controller()->show(Box<InformBox>(*error));
return true;
} else if (showSlowmodeError()) {
return true;
@@ -946,7 +948,7 @@ void HistoryWidget::supportShareContact(Support::Contact contact) {
contact.lastName,
action);
};
const auto box = Ui::show(Box<Support::ConfirmContactBox>(
const auto box = controller()->show(Box<Support::ConfirmContactBox>(
controller(),
_history,
contact,
@@ -1263,7 +1265,16 @@ void HistoryWidget::applyInlineBotQuery(UserData *bot, const QString &query) {
_inlineResults.create(this, controller());
_inlineResults->setResultSelectedCallback([=](
InlineBots::ResultSelected result) {
sendInlineResult(result);
if (result.open) {
const auto request = result.result->openRequest();
if (const auto photo = request.photo()) {
controller()->openPhoto(photo, FullMsgId());
} else if (const auto document = request.document()) {
controller()->openDocument(document, FullMsgId());
}
} else {
sendInlineResult(result);
}
});
_inlineResults->setCurrentDialogsEntryState(
computeDialogsEntryState());
@@ -3087,10 +3098,11 @@ void HistoryWidget::saveEditMsg() {
if (!TextUtilities::CutPart(sending, left, MaxMessageSize)) {
const auto suggestModerateActions = false;
Ui::show(Box<DeleteMessagesBox>(item, suggestModerateActions));
controller()->show(
Box<DeleteMessagesBox>(item, suggestModerateActions));
return;
} else if (!left.text.isEmpty()) {
Ui::show(Box<InformBox>(tr::lng_edit_too_long(tr::now)));
controller()->show(Box<InformBox>(tr::lng_edit_too_long(tr::now)));
return;
}
@@ -3124,14 +3136,16 @@ void HistoryWidget::saveEditMsg() {
}
const auto &err = error.type();
if (ranges::contains(Api::kDefaultEditMessagesErrors, err)) {
Ui::show(Box<InformBox>(tr::lng_edit_error(tr::now)));
controller()->show(
Box<InformBox>(tr::lng_edit_error(tr::now)));
} else if (err == u"MESSAGE_NOT_MODIFIED"_q) {
cancelEdit();
} else if (err == u"MESSAGE_EMPTY"_q) {
_field->selectAll();
_field->setFocus();
} else {
Ui::show(Box<InformBox>(tr::lng_edit_error(tr::now)));
controller()->show(
Box<InformBox>(tr::lng_edit_error(tr::now)));
}
update();
})();
@@ -3254,7 +3268,7 @@ void HistoryWidget::sendScheduled() {
return;
}
const auto callback = [=](Api::SendOptions options) { send(options); };
Ui::show(
controller()->show(
HistoryView::PrepareScheduleBox(_list, sendMenuType(), callback),
Ui::LayerOption::KeepOther);
}
@@ -3468,7 +3482,7 @@ void HistoryWidget::checkSuggestToGigagroup() {
group->input,
MTP_string("convert_to_gigagroup")
)).send();
Ui::show(Box([=](not_null<Ui::GenericBox*> box) {
controller()->show(Box([=](not_null<Ui::GenericBox*> box) {
box->setTitle(tr::lng_gigagroup_suggest_title());
box->addRow(
object_ptr<Ui::FlatLabel>(
@@ -3506,7 +3520,8 @@ void HistoryWidget::unreadMentionsAnimationFinish() {
void HistoryWidget::chooseAttach() {
if (_editMsgId) {
Ui::show(Box<InformBox>(tr::lng_edit_caption_attach(tr::now)));
controller()->show(
Box<InformBox>(tr::lng_edit_caption_attach(tr::now)));
return;
}
@@ -4068,7 +4083,8 @@ void HistoryWidget::toggleTabbedSelectorMode() {
return;
}
if (_tabbedPanel) {
if (controller()->canShowThirdSection() && !Adaptive::OneColumn()) {
if (controller()->canShowThirdSection()
&& !controller()->adaptive().isOneColumn()) {
Core::App().settings().setTabbedSelectorSectionEnabled(true);
Core::App().saveSettingsDelayed();
pushTabbedSelectorToThirdSection(
@@ -4083,13 +4099,10 @@ void HistoryWidget::toggleTabbedSelectorMode() {
}
void HistoryWidget::recountChatWidth() {
auto layout = (width() < st::adaptiveChatWideWidth)
? Adaptive::ChatLayout::Normal
: Adaptive::ChatLayout::Wide;
if (layout != Global::AdaptiveChatLayout()) {
Global::SetAdaptiveChatLayout(layout);
Adaptive::Changed().notify(true);
}
const auto layout = (width() < st::adaptiveChatWideWidth)
? Window::Adaptive::ChatLayout::Normal
: Window::Adaptive::ChatLayout::Wide;
controller()->adaptive().setChatLayout(layout);
}
void HistoryWidget::moveFieldControls() {
@@ -4335,7 +4348,8 @@ bool HistoryWidget::confirmSendingFiles(
return false;
}
if (_editMsgId) {
Ui::show(Box<InformBox>(tr::lng_edit_caption_attach(tr::now)));
controller()->show(
Box<InformBox>(tr::lng_edit_caption_attach(tr::now)));
return false;
}
@@ -4379,7 +4393,7 @@ bool HistoryWidget::confirmSendingFiles(
}));
Window::ActivateWindow(controller());
const auto shown = Ui::show(std::move(box));
const auto shown = controller()->show(std::move(box));
shown->setCloseByOutsideClick(false);
return true;
@@ -4639,8 +4653,14 @@ void HistoryWidget::updateControlsGeometry() {
_membersDropdown->setMaxHeight(countMembersDropdownHeightMax());
}
auto topShadowLeft = (Adaptive::OneColumn() || _inGrab) ? 0 : st::lineWidth;
auto topShadowRight = (Adaptive::ThreeColumn() && !_inGrab && _peer) ? st::lineWidth : 0;
const auto isOneColumn = controller()->adaptive().isOneColumn();
const auto isThreeColumn = controller()->adaptive().isThreeColumn();
const auto topShadowLeft = (isOneColumn || _inGrab)
? 0
: st::lineWidth;
const auto topShadowRight = (isThreeColumn && !_inGrab && _peer)
? st::lineWidth
: 0;
_topShadow->setGeometryToLeft(
topShadowLeft,
_topBar->bottomNoMargins(),
@@ -5243,14 +5263,14 @@ bool HistoryWidget::replyToPreviousMessage() {
if (const auto view = item->mainView()) {
if (const auto previousView = view->previousDisplayedInBlocks()) {
const auto previous = previousView->data();
Ui::showPeerHistoryAtItem(previous);
controller()->showPeerHistoryAtItem(previous);
replyToMessage(previous);
return true;
}
}
} else if (const auto previousView = _history->findLastDisplayed()) {
const auto previous = previousView->data();
Ui::showPeerHistoryAtItem(previous);
controller()->showPeerHistoryAtItem(previous);
replyToMessage(previous);
return true;
}
@@ -5268,7 +5288,7 @@ bool HistoryWidget::replyToNextMessage() {
if (const auto view = item->mainView()) {
if (const auto nextView = view->nextDisplayedInBlocks()) {
const auto next = nextView->data();
Ui::showPeerHistoryAtItem(next);
controller()->showPeerHistoryAtItem(next);
replyToMessage(next);
} else {
clearHighlightMessages();
@@ -5324,7 +5344,7 @@ void HistoryWidget::sendInlineResult(InlineBots::ResultSelected result) {
auto errorText = result.result->getErrorOnSend(_history);
if (!errorText.isEmpty()) {
Ui::show(Box<InformBox>(errorText));
controller()->show(Box<InformBox>(errorText));
return;
}
@@ -5479,13 +5499,8 @@ void HistoryWidget::checkPinnedBarState() {
refreshPinnedBarButton(many);
}, _pinnedBar->lifetime());
rpl::single(
rpl::empty_value()
) | rpl::then(
base::ObservableViewer(Adaptive::Changed())
) | rpl::map([] {
return Adaptive::OneColumn();
}) | rpl::start_with_next([=](bool one) {
controller()->adaptive().oneColumnValue(
) | rpl::start_with_next([=](bool one) {
_pinnedBar->setShadowGeometryPostprocess([=](QRect geometry) {
if (!one) {
geometry.setLeft(geometry.left() + st::lineWidth);
@@ -5608,13 +5623,8 @@ void HistoryWidget::setupGroupCallTracker() {
_groupCallTracker->content(),
Core::App().appDeactivatedValue());
rpl::single(
rpl::empty_value()
) | rpl::then(
base::ObservableViewer(Adaptive::Changed())
) | rpl::map([] {
return Adaptive::OneColumn();
}) | rpl::start_with_next([=](bool one) {
controller()->adaptive().oneColumnValue(
) | rpl::start_with_next([=](bool one) {
_groupCallBar->setShadowGeometryPostprocess([=](QRect geometry) {
if (!one) {
geometry.setLeft(geometry.left() + st::lineWidth);
@@ -5668,7 +5678,9 @@ bool HistoryWidget::sendExistingDocument(
? Data::RestrictionError(_peer, ChatRestriction::f_send_stickers)
: std::nullopt;
if (error) {
Ui::show(Box<InformBox>(*error), Ui::LayerOption::KeepOther);
controller()->show(
Box<InformBox>(*error),
Ui::LayerOption::KeepOther);
return false;
} else if (!_peer || !_peer->canWrite()) {
return false;
@@ -5702,7 +5714,9 @@ bool HistoryWidget::sendExistingPhoto(
? Data::RestrictionError(_peer, ChatRestriction::f_send_media)
: std::nullopt;
if (error) {
Ui::show(Box<InformBox>(*error), Ui::LayerOption::KeepOther);
controller()->show(
Box<InformBox>(*error),
Ui::LayerOption::KeepOther);
return false;
} else if (!_peer || !_peer->canWrite()) {
return false;
@@ -5786,14 +5800,18 @@ void HistoryWidget::replyToMessage(not_null<HistoryItem*> item) {
}
if (item->history() == _migrated) {
if (item->serviceMsg()) {
Ui::show(Box<InformBox>(tr::lng_reply_cant(tr::now)));
controller()->show(Box<InformBox>(tr::lng_reply_cant(tr::now)));
} else {
const auto itemId = item->fullId();
Ui::show(Box<ConfirmBox>(tr::lng_reply_cant_forward(tr::now), tr::lng_selected_forward(tr::now), crl::guard(this, [=] {
controller()->content()->setForwardDraft(
_peer->id,
{ 1, itemId });
})));
controller()->show(
Box<ConfirmBox>(
tr::lng_reply_cant_forward(tr::now),
tr::lng_selected_forward(tr::now),
crl::guard(this, [=] {
controller()->content()->setForwardDraft(
_peer->id,
{ 1, itemId });
})));
}
return;
}
@@ -5836,12 +5854,13 @@ void HistoryWidget::editMessage(FullMsgId itemId) {
void HistoryWidget::editMessage(not_null<HistoryItem*> item) {
if (_voiceRecordBar->isActive()) {
Ui::show(Box<InformBox>(tr::lng_edit_caption_voice(tr::now)));
controller()->show(
Box<InformBox>(tr::lng_edit_caption_voice(tr::now)));
return;
}
if (const auto media = item->media()) {
if (media->allowsEditCaption()) {
Ui::show(Box<EditCaptionBox>(controller(), item));
controller()->show(Box<EditCaptionBox>(controller(), item));
return;
}
}
@@ -6287,14 +6306,13 @@ void HistoryWidget::confirmDeleteSelected() {
return;
}
const auto weak = Ui::MakeWeak(this);
const auto box = Ui::show(Box<DeleteMessagesBox>(
&session(),
std::move(items)));
auto box = Box<DeleteMessagesBox>(&session(), std::move(items));
box->setDeleteConfirmedCallback([=] {
if (const auto strong = weak.data()) {
strong->clearSelected();
}
});
controller()->show(std::move(box));
}
void HistoryWidget::escape() {
@@ -6307,7 +6325,7 @@ void HistoryWidget::escape() {
} else if (_editMsgId) {
if (_replyEditMsg
&& PrepareEditText(_replyEditMsg) != _field->getTextWithTags()) {
Ui::show(Box<ConfirmBox>(
controller()->show(Box<ConfirmBox>(
tr::lng_cancel_edit_post_sure(tr::now),
tr::lng_cancel_edit_post_yes(tr::now),
tr::lng_cancel_edit_post_no(tr::now),

View File

@@ -30,7 +30,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/stickers/data_stickers.h"
#include "data/data_web_page.h"
#include "storage/storage_account.h"
#include "facades.h"
#include "apiwrap.h"
#include "boxes/confirm_box.h"
#include "history/history.h"
@@ -52,6 +51,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/controls/emoji_button.h"
#include "ui/controls/send_button.h"
#include "ui/special_buttons.h"
#include "window/window_adaptive.h"
#include "window/window_session_controller.h"
#include "mainwindow.h"
@@ -795,7 +795,8 @@ rpl::producer<> ComposeControls::attachRequests() const {
_attachRequests.events()
) | rpl::filter([=] {
if (isEditingMessage()) {
Ui::show(Box<InformBox>(tr::lng_edit_caption_attach(tr::now)));
_window->show(
Box<InformBox>(tr::lng_edit_caption_attach(tr::now)));
return false;
}
return true;
@@ -1655,7 +1656,7 @@ void ComposeControls::initVoiceRecordBar() {
ChatRestriction::f_send_media)
: std::nullopt;
if (error) {
Ui::show(Box<InformBox>(*error));
_window->show(Box<InformBox>(*error));
return true;
} else if (_showSlowmodeError && _showSlowmodeError()) {
return true;
@@ -1919,7 +1920,8 @@ void ComposeControls::toggleTabbedSelectorMode() {
return;
}
if (_tabbedPanel) {
if (_window->canShowThirdSection() && !Adaptive::OneColumn()) {
if (_window->canShowThirdSection()
&& !_window->adaptive().isOneColumn()) {
Core::App().settings().setTabbedSelectorSectionEnabled(true);
Core::App().saveSettingsDelayed();
pushTabbedSelectorToThirdSection(
@@ -1953,7 +1955,7 @@ void ComposeControls::editMessage(not_null<HistoryItem*> item) {
Expects(draftKeyCurrent() != Data::DraftKey::None());
if (_voiceRecordBar->isActive()) {
Ui::show(Box<InformBox>(tr::lng_edit_caption_voice(tr::now)));
_window->show(Box<InformBox>(tr::lng_edit_caption_voice(tr::now)));
return;
}
@@ -2392,7 +2394,16 @@ void ComposeControls::applyInlineBotQuery(
_currentDialogsEntryState);
_inlineResults->setResultSelectedCallback([=](
InlineBots::ResultSelected result) {
_inlineResultChosen.fire_copy(result);
if (result.open) {
const auto request = result.result->openRequest();
if (const auto photo = request.photo()) {
_window->openPhoto(photo, FullMsgId());
} else if (const auto document = request.document()) {
_window->openDocument(document, FullMsgId());
}
} else {
_inlineResultChosen.fire_copy(result);
}
});
_inlineResults->setSendMenuType([=] { return sendMenuType(); });
_inlineResults->requesting(

View File

@@ -1638,7 +1638,7 @@ void VoiceRecordBar::showDiscardBox(
callback();
}
};
Ui::show(Box<ConfirmBox>(
_controller->show(Box<ConfirmBox>(
(isListenState()
? tr::lng_record_listen_cancel_sure
: tr::lng_record_lock_cancel_sure)(tr::now),

View File

@@ -157,11 +157,13 @@ void AddPhotoActions(
}
}
void OpenGif(not_null<Main::Session*> session, FullMsgId itemId) {
if (const auto item = session->data().message(itemId)) {
void OpenGif(
not_null<Window::SessionController*> controller,
FullMsgId itemId) {
if (const auto item = controller->session().data().message(itemId)) {
if (const auto media = item->media()) {
if (const auto document = media->document()) {
Core::App().showDocument(document, item);
controller->openDocument(document, itemId, true);
}
}
}
@@ -223,7 +225,7 @@ void AddDocumentActions(
}();
if (notAutoplayedGif) {
menu->addAction(tr::lng_context_open_gif(tr::now), [=] {
OpenGif(session, contextId);
OpenGif(list->controller(), contextId);
});
}
}
@@ -508,7 +510,7 @@ bool AddRescheduleAction(
? HistoryView::DefaultScheduleTime()
: itemDate + 600;
const auto box = Ui::show(
const auto box = request.navigation->parentController()->show(
HistoryView::PrepareScheduleBox(
&request.navigation->session(),
sendMenuType,
@@ -676,14 +678,15 @@ bool AddDeleteSelectedAction(
menu->addAction(tr::lng_context_delete_selected(tr::now), [=] {
const auto weak = Ui::MakeWeak(list);
auto items = ExtractIdsList(request.selectedItems);
const auto box = Ui::show(Box<DeleteMessagesBox>(
auto box = Box<DeleteMessagesBox>(
&request.navigation->session(),
std::move(items)));
std::move(items));
box->setDeleteConfirmedCallback([=] {
if (const auto strong = weak.data()) {
strong->cancelSelection();
}
});
request.navigation->parentController()->show(std::move(box));
});
return true;
}
@@ -716,7 +719,7 @@ bool AddDeleteMessageAction(
if (const auto item = owner->message(itemId)) {
if (asGroup) {
if (const auto group = owner->groups().find(item)) {
Ui::show(Box<DeleteMessagesBox>(
controller->show(Box<DeleteMessagesBox>(
&owner->session(),
owner->itemsToIds(group->items)));
return;
@@ -729,7 +732,8 @@ bool AddDeleteMessageAction(
}
}
const auto suggestModerateActions = true;
Ui::show(Box<DeleteMessagesBox>(item, suggestModerateActions));
controller->show(
Box<DeleteMessagesBox>(item, suggestModerateActions));
}
});
if (const auto message = item->toHistoryMessage()) {

View File

@@ -107,6 +107,17 @@ void SimpleElementDelegate::elementShowPollResults(
FullMsgId context) {
}
void SimpleElementDelegate::elementOpenPhoto(
not_null<PhotoData*> photo,
FullMsgId context) {
}
void SimpleElementDelegate::elementOpenDocument(
not_null<DocumentData*> document,
FullMsgId context,
bool showInMediaView) {
}
void SimpleElementDelegate::elementShowTooltip(
const TextWithEntities &text,
Fn<void()> hiddenCallback) {
@@ -133,6 +144,10 @@ void SimpleElementDelegate::elementSendBotCommand(
void SimpleElementDelegate::elementHandleViaClick(not_null<UserData*> bot) {
}
bool SimpleElementDelegate::elementIsChatWide() {
return false;
}
TextSelection UnshiftItemSelection(
TextSelection selection,
uint16 byLength) {
@@ -220,7 +235,7 @@ int UnreadBar::marginTop() {
return st::lineWidth + st::historyUnreadBarMargin;
}
void UnreadBar::paint(Painter &p, int y, int w) const {
void UnreadBar::paint(Painter &p, int y, int w, bool chatWide) const {
const auto bottom = y + height();
y += marginTop();
p.fillRect(
@@ -240,7 +255,7 @@ void UnreadBar::paint(Painter &p, int y, int w) const {
int left = st::msgServiceMargin.left();
int maxwidth = w;
if (Core::App().settings().chatWide()) {
if (chatWide) {
maxwidth = qMin(
maxwidth,
st::msgMaxWidth
@@ -272,8 +287,8 @@ int DateBadge::height() const {
+ st::msgServiceMargin.bottom();
}
void DateBadge::paint(Painter &p, int y, int w) const {
ServiceMessagePainter::paintDate(p, text, width, y, w);
void DateBadge::paint(Painter &p, int y, int w, bool chatWide) const {
ServiceMessagePainter::paintDate(p, text, width, y, w, chatWide);
}
Element::Element(

View File

@@ -60,6 +60,13 @@ public:
virtual void elementShowPollResults(
not_null<PollData*> poll,
FullMsgId context) = 0;
virtual void elementOpenPhoto(
not_null<PhotoData*> photo,
FullMsgId context) = 0;
virtual void elementOpenDocument(
not_null<DocumentData*> document,
FullMsgId context,
bool showInMediaView = false) = 0;
virtual void elementShowTooltip(
const TextWithEntities &text,
Fn<void()> hiddenCallback) = 0;
@@ -70,6 +77,7 @@ public:
const QString &command,
const FullMsgId &context) = 0;
virtual void elementHandleViaClick(not_null<UserData*> bot) = 0;
virtual bool elementIsChatWide() = 0;
};
@@ -96,6 +104,13 @@ public:
void elementShowPollResults(
not_null<PollData*> poll,
FullMsgId context) override;
void elementOpenPhoto(
not_null<PhotoData*> photo,
FullMsgId context) override;
void elementOpenDocument(
not_null<DocumentData*> document,
FullMsgId context,
bool showInMediaView = false) override;
void elementShowTooltip(
const TextWithEntities &text,
Fn<void()> hiddenCallback) override;
@@ -106,6 +121,7 @@ public:
const QString &command,
const FullMsgId &context) override;
void elementHandleViaClick(not_null<UserData*> bot) override;
bool elementIsChatWide() override;
private:
const not_null<Window::SessionController*> _controller;
@@ -135,7 +151,7 @@ struct UnreadBar : public RuntimeComponent<UnreadBar, Element> {
static int height();
static int marginTop();
void paint(Painter &p, int y, int w) const;
void paint(Painter &p, int y, int w, bool chatWide) const;
QString text;
int width = 0;
@@ -149,7 +165,7 @@ struct DateBadge : public RuntimeComponent<DateBadge, Element> {
void init(const QString &date);
int height() const;
void paint(Painter &p, int y, int w) const;
void paint(Painter &p, int y, int w, bool chatWide) const;
QString text;
int width = 0;

View File

@@ -21,10 +21,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "chat_helpers/message_field.h"
#include "mainwindow.h"
#include "mainwidget.h"
#include "core/application.h"
#include "core/click_handler_types.h"
#include "apiwrap.h"
#include "layout.h"
#include "window/window_adaptive.h"
#include "window/window_session_controller.h"
#include "window/window_peer_menu.h"
#include "main/main_session.h"
@@ -311,6 +311,11 @@ ListWidget::ListWidget(
}
}
});
controller->adaptive().chatWideValue(
) | rpl::start_with_next([=](bool wide) {
_isChatWide = wide;
}, lifetime());
}
Main::Session &ListWidget::session() const {
@@ -1295,6 +1300,19 @@ void ListWidget::elementShowPollResults(
_controller->showPollResults(poll, context);
}
void ListWidget::elementOpenPhoto(
not_null<PhotoData*> photo,
FullMsgId context) {
_controller->openPhoto(photo, context);
}
void ListWidget::elementOpenDocument(
not_null<DocumentData*> document,
FullMsgId context,
bool showInMediaView) {
_controller->openDocument(document, context, showInMediaView);
}
void ListWidget::elementShowTooltip(
const TextWithEntities &text,
Fn<void()> hiddenCallback) {
@@ -1322,6 +1340,10 @@ void ListWidget::elementHandleViaClick(not_null<UserData*> bot) {
_delegate->listHandleViaClick(bot);
}
bool ListWidget::elementIsChatWide() {
return _isChatWide;
}
void ListWidget::saveState(not_null<ListMemento*> memento) {
memento->setAroundPosition(_aroundPosition);
auto state = countScrollState();
@@ -1557,13 +1579,14 @@ void ListWidget::paintEvent(QPaintEvent *e) {
int dateY = /*noFloatingDate ? itemtop :*/ (dateTop - st::msgServiceMargin.top());
int width = view->width();
if (const auto date = view->Get<HistoryView::DateBadge>()) {
date->paint(p, dateY, width);
date->paint(p, dateY, width, _isChatWide);
} else {
ServiceMessagePainter::paintDate(
p,
ItemDateText(view->data(), IsItemScheduledUntilOnline(view->data())),
dateY,
width);
width,
_isChatWide);
}
}
}
@@ -2347,7 +2370,7 @@ void ListWidget::mouseActionUpdate() {
dateWidth += st::msgServicePadding.left() + st::msgServicePadding.right();
auto dateLeft = st::msgServiceMargin.left();
auto maxwidth = view->width();
if (Core::App().settings().chatWide()) {
if (_isChatWide) {
maxwidth = qMin(maxwidth, int32(st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left()));
}
auto widthForDate = maxwidth - st::msgServiceMargin.left() - st::msgServiceMargin.left();
@@ -2504,7 +2527,7 @@ std::unique_ptr<QMimeData> ListWidget::prepareDrag() {
if (!urls.isEmpty()) {
mimeData->setUrls(urls);
}
if (uponSelected && !Adaptive::OneColumn()) {
if (uponSelected && !_controller->adaptive().isOneColumn()) {
const auto canForwardAll = [&] {
for (const auto &[itemId, data] : _selected) {
if (!data.canForward) {
@@ -2567,7 +2590,9 @@ std::unique_ptr<QMimeData> ListWidget::prepareDrag() {
void ListWidget::performDrag() {
if (auto mimeData = prepareDrag()) {
// This call enters event loop and can destroy any QObject.
_controller->widget()->launchDrag(std::move(mimeData));
_controller->widget()->launchDrag(
std::move(mimeData),
crl::guard(this, [=] { mouseActionUpdate(QCursor::pos()); }));;
}
}
@@ -2814,14 +2839,15 @@ void ConfirmDeleteSelectedItems(not_null<ListWidget*> widget) {
}
}
const auto weak = Ui::MakeWeak(widget);
const auto box = Ui::show(Box<DeleteMessagesBox>(
auto box = Box<DeleteMessagesBox>(
&widget->controller()->session(),
widget->getSelectedIds()));
widget->getSelectedIds());
box->setDeleteConfirmedCallback([=] {
if (const auto strong = weak.data()) {
strong->cancelSelection();
}
});
widget->controller()->show(std::move(box));
}
void ConfirmForwardSelectedItems(not_null<ListWidget*> widget) {

View File

@@ -234,6 +234,13 @@ public:
void elementShowPollResults(
not_null<PollData*> poll,
FullMsgId context) override;
void elementOpenPhoto(
not_null<PhotoData*> photo,
FullMsgId context) override;
void elementOpenDocument(
not_null<DocumentData*> document,
FullMsgId context,
bool showInMediaView = false) override;
void elementShowTooltip(
const TextWithEntities &text,
Fn<void()> hiddenCallback) override;
@@ -244,6 +251,7 @@ public:
const QString &command,
const FullMsgId &context) override;
void elementHandleViaClick(not_null<UserData*> bot) override;
bool elementIsChatWide() override;
~ListWidget();
@@ -546,6 +554,8 @@ private:
bool _wasSelectedText = false;
Qt::CursorShape _cursor = style::cur_default;
bool _isChatWide = false;
base::unique_qptr<Ui::PopupMenu> _menu;
QPoint _trippleClickPoint;

View File

@@ -16,8 +16,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history.h"
#include "ui/effects/ripple_animation.h"
#include "base/unixtime.h"
#include "core/application.h"
#include "core/core_settings.h"
#include "ui/toast/toast.h"
#include "ui/text/text_utilities.h"
#include "ui/text/text_entity.h"
@@ -564,7 +562,7 @@ void Message::draw(
auto unreadbarh = bar->height();
if (clip.intersects(QRect(0, dateh, width(), unreadbarh))) {
p.translate(0, dateh);
bar->paint(p, 0, width());
bar->paint(p, 0, width(), delegate()->elementIsChatWide());
p.translate(0, -dateh);
}
}
@@ -644,7 +642,7 @@ void Message::draw(
|| (context() == Context::Replies && data()->isDiscussionPost());
auto displayTail = skipTail
? RectPart::None
: (outbg && !Core::App().settings().chatWide())
: (outbg && !delegate()->elementIsChatWide())
? RectPart::Right
: RectPart::Left;
PaintBubble(
@@ -1207,7 +1205,7 @@ bool Message::hasFromPhoto() const {
|| item->isEmpty()
|| (context() == Context::Replies && item->isDiscussionPost())) {
return false;
} else if (Core::App().settings().chatWide()) {
} else if (delegate()->elementIsChatWide()) {
return true;
} else if (const auto forwarded = item->Get<HistoryMessageForwarded>()) {
const auto peer = item->history()->peer;
@@ -2517,7 +2515,7 @@ QRect Message::countGeometry() const {
const auto availableWidth = width()
- st::msgMargin.left()
- (commentsRoot ? st::msgMargin.left() : st::msgMargin.right());
auto contentLeft = (outbg && !Core::App().settings().chatWide())
auto contentLeft = (outbg && !delegate()->elementIsChatWide())
? st::msgMargin.right()
: st::msgMargin.left();
auto contentWidth = availableWidth;
@@ -2540,7 +2538,7 @@ QRect Message::countGeometry() const {
contentWidth = mediaWidth;
}
}
if (contentWidth < availableWidth && !Core::App().settings().chatWide()) {
if (contentWidth < availableWidth && !delegate()->elementIsChatWide()) {
if (outbg) {
contentLeft += availableWidth - contentWidth;
} else if (commentsRoot) {

View File

@@ -25,6 +25,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/toasts/common_toasts.h"
#include "base/timer_rpl.h"
#include "apiwrap.h"
#include "window/window_adaptive.h"
#include "window/window_session_controller.h"
#include "window/window_peer_menu.h"
#include "base/event_filter.h"
@@ -127,8 +128,13 @@ PinnedWidget::PinnedWidget(
}, _topBar->lifetime());
_topBarShadow->raise();
updateAdaptiveLayout();
subscribe(Adaptive::Changed(), [=] { updateAdaptiveLayout(); });
rpl::single(
rpl::empty_value()
) | rpl::then(
controller->adaptive().changed()
) | rpl::start_with_next([=] {
updateAdaptiveLayout();
}, lifetime());
_inner = _scroll->setOwnedWidget(object_ptr<ListWidget>(
this,
@@ -297,7 +303,7 @@ void PinnedWidget::scrollDownAnimationFinish() {
void PinnedWidget::updateAdaptiveLayout() {
_topBarShadow->moveToLeft(
Adaptive::OneColumn() ? 0 : st::lineWidth,
controller()->adaptive().isOneColumn() ? 0 : st::lineWidth,
_topBar->height());
}
@@ -387,12 +393,9 @@ void PinnedWidget::resizeEvent(QResizeEvent *e) {
void PinnedWidget::recountChatWidth() {
auto layout = (width() < st::adaptiveChatWideWidth)
? Adaptive::ChatLayout::Normal
: Adaptive::ChatLayout::Wide;
if (layout != Global::AdaptiveChatLayout()) {
Global::SetAdaptiveChatLayout(layout);
Adaptive::Changed().notify(true);
}
? Window::Adaptive::ChatLayout::Normal
: Window::Adaptive::ChatLayout::Wide;
controller()->adaptive().setChatLayout(layout);
}
void PinnedWidget::setMessagesCount(int count) {

View File

@@ -39,6 +39,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/confirm_box.h"
#include "boxes/edit_caption_box.h"
#include "boxes/send_files_box.h"
#include "window/window_adaptive.h"
#include "window/window_session_controller.h"
#include "window/window_peer_menu.h"
#include "base/event_filter.h"
@@ -191,8 +192,14 @@ RepliesWidget::RepliesWidget(
_rootView->raise();
_topBarShadow->raise();
updateAdaptiveLayout();
subscribe(Adaptive::Changed(), [=] { updateAdaptiveLayout(); });
rpl::single(
rpl::empty_value()
) | rpl::then(
controller->adaptive().changed()
) | rpl::start_with_next([=] {
updateAdaptiveLayout();
}, lifetime());
_inner = _scroll->setOwnedWidget(object_ptr<ListWidget>(
this,
@@ -208,7 +215,7 @@ RepliesWidget::RepliesWidget(
const auto media = item->media();
if (media && !media->webpage()) {
if (media->allowsEditCaption()) {
Ui::show(Box<EditCaptionBox>(controller, item));
controller->show(Box<EditCaptionBox>(controller, item));
}
} else {
_composeControls->editMessage(fullId);
@@ -327,13 +334,8 @@ void RepliesWidget::setupRootView() {
});
_rootView = std::make_unique<Ui::PinnedBar>(this, std::move(content));
rpl::single(
rpl::empty_value()
) | rpl::then(
base::ObservableViewer(Adaptive::Changed())
) | rpl::map([] {
return Adaptive::OneColumn();
}) | rpl::start_with_next([=](bool one) {
controller()->adaptive().oneColumnValue(
) | rpl::start_with_next([=](bool one) {
_rootView->setShadowGeometryPostprocess([=](QRect geometry) {
if (!one) {
geometry.setLeft(geometry.left() + st::lineWidth);
@@ -653,7 +655,7 @@ bool RepliesWidget::confirmSendingFiles(
insertTextOnCancel));
//ActivateWindow(controller());
const auto shown = Ui::show(std::move(box));
const auto shown = controller()->show(std::move(box));
shown->setCloseByOutsideClick(false);
return true;
@@ -943,13 +945,13 @@ void RepliesWidget::edit(
if (!TextUtilities::CutPart(sending, left, MaxMessageSize)) {
if (item) {
Ui::show(Box<DeleteMessagesBox>(item, false));
controller()->show(Box<DeleteMessagesBox>(item, false));
} else {
doSetInnerFocus();
}
return;
} else if (!left.text.isEmpty()) {
Ui::show(Box<InformBox>(tr::lng_edit_too_long(tr::now)));
controller()->show(Box<InformBox>(tr::lng_edit_too_long(tr::now)));
return;
}
@@ -974,13 +976,13 @@ void RepliesWidget::edit(
const auto &err = error.type();
if (ranges::contains(Api::kDefaultEditMessagesErrors, err)) {
Ui::show(Box<InformBox>(tr::lng_edit_error(tr::now)));
controller()->show(Box<InformBox>(tr::lng_edit_error(tr::now)));
} else if (err == u"MESSAGE_NOT_MODIFIED"_q) {
_composeControls->cancelEditMessage();
} else if (err == u"MESSAGE_EMPTY"_q) {
doSetInnerFocus();
} else {
Ui::show(Box<InformBox>(tr::lng_edit_error(tr::now)));
controller()->show(Box<InformBox>(tr::lng_edit_error(tr::now)));
}
update();
return true;
@@ -1016,7 +1018,9 @@ bool RepliesWidget::sendExistingDocument(
_history->peer,
ChatRestriction::f_send_stickers);
if (error) {
Ui::show(Box<InformBox>(*error), Ui::LayerOption::KeepOther);
controller()->show(
Box<InformBox>(*error),
Ui::LayerOption::KeepOther);
return false;
} else if (showSlowmodeError()) {
return false;
@@ -1050,7 +1054,9 @@ bool RepliesWidget::sendExistingPhoto(
_history->peer,
ChatRestriction::f_send_media);
if (error) {
Ui::show(Box<InformBox>(*error), Ui::LayerOption::KeepOther);
controller()->show(
Box<InformBox>(*error),
Ui::LayerOption::KeepOther);
return false;
} else if (showSlowmodeError()) {
return false;
@@ -1071,7 +1077,7 @@ void RepliesWidget::sendInlineResult(
not_null<UserData*> bot) {
const auto errorText = result->getErrorOnSend(_history);
if (!errorText.isEmpty()) {
Ui::show(Box<InformBox>(errorText));
controller()->show(Box<InformBox>(errorText));
return;
}
sendInlineResult(result, bot, Api::SendOptions());
@@ -1284,7 +1290,7 @@ void RepliesWidget::scrollDownAnimationFinish() {
void RepliesWidget::updateAdaptiveLayout() {
_topBarShadow->moveToLeft(
Adaptive::OneColumn() ? 0 : st::lineWidth,
controller()->adaptive().isOneColumn() ? 0 : st::lineWidth,
_topBar->height());
}
@@ -1462,12 +1468,9 @@ void RepliesWidget::resizeEvent(QResizeEvent *e) {
void RepliesWidget::recountChatWidth() {
auto layout = (width() < st::adaptiveChatWideWidth)
? Adaptive::ChatLayout::Normal
: Adaptive::ChatLayout::Wide;
if (layout != Global::AdaptiveChatLayout()) {
Global::SetAdaptiveChatLayout(layout);
Adaptive::Changed().notify(true);
}
? Window::Adaptive::ChatLayout::Normal
: Window::Adaptive::ChatLayout::Wide;
controller()->adaptive().setChatLayout(layout);
}
void RepliesWidget::updateControlsGeometry() {

View File

@@ -32,6 +32,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/confirm_box.h"
#include "boxes/edit_caption_box.h"
#include "boxes/send_files_box.h"
#include "window/window_adaptive.h"
#include "window/window_session_controller.h"
#include "window/window_peer_menu.h"
#include "base/event_filter.h"
@@ -125,8 +126,13 @@ ScheduledWidget::ScheduledWidget(
}, _topBar->lifetime());
_topBarShadow->raise();
updateAdaptiveLayout();
subscribe(Adaptive::Changed(), [=] { updateAdaptiveLayout(); });
rpl::single(
rpl::empty_value()
) | rpl::then(
controller->adaptive().changed()
) | rpl::start_with_next([=] {
updateAdaptiveLayout();
}, lifetime());
_inner = _scroll->setOwnedWidget(object_ptr<ListWidget>(
this,
@@ -142,7 +148,7 @@ ScheduledWidget::ScheduledWidget(
const auto media = item->media();
if (media && !media->webpage()) {
if (media->allowsEditCaption()) {
Ui::show(Box<EditCaptionBox>(controller, item));
controller->show(Box<EditCaptionBox>(controller, item));
}
} else {
_composeControls->editMessage(fullId);
@@ -378,7 +384,7 @@ bool ScheduledWidget::confirmSendingFiles(
insertTextOnCancel));
//ActivateWindow(controller());
const auto shown = Ui::show(std::move(box));
const auto shown = controller()->show(std::move(box));
shown->setCloseByOutsideClick(false);
return true;
@@ -448,7 +454,7 @@ void ScheduledWidget::uploadFile(
action.options = options;
session().api().sendFile(fileContent, type, action);
};
Ui::show(
controller()->show(
PrepareScheduleBox(this, sendMenuType(), callback),
Ui::LayerOption::KeepOther);
}
@@ -493,7 +499,7 @@ void ScheduledWidget::send() {
return;
}
const auto callback = [=](Api::SendOptions options) { send(options); };
Ui::show(
controller()->show(
PrepareScheduleBox(this, sendMenuType(), callback),
Ui::LayerOption::KeepOther);
}
@@ -538,7 +544,7 @@ void ScheduledWidget::sendVoice(
const auto callback = [=](Api::SendOptions options) {
sendVoice(bytes, waveform, duration, options);
};
Ui::show(
controller()->show(
PrepareScheduleBox(this, sendMenuType(), callback),
Ui::LayerOption::KeepOther);
}
@@ -573,13 +579,13 @@ void ScheduledWidget::edit(
if (!TextUtilities::CutPart(sending, left, MaxMessageSize)) {
if (item) {
Ui::show(Box<DeleteMessagesBox>(item, false));
controller()->show(Box<DeleteMessagesBox>(item, false));
} else {
_composeControls->focus();
}
return;
} else if (!left.text.isEmpty()) {
Ui::show(Box<InformBox>(tr::lng_edit_too_long(tr::now)));
controller()->show(Box<InformBox>(tr::lng_edit_too_long(tr::now)));
return;
}
@@ -604,13 +610,13 @@ void ScheduledWidget::edit(
const auto &err = error.type();
if (ranges::contains(Api::kDefaultEditMessagesErrors, err)) {
Ui::show(Box<InformBox>(tr::lng_edit_error(tr::now)));
controller()->show(Box<InformBox>(tr::lng_edit_error(tr::now)));
} else if (err == u"MESSAGE_NOT_MODIFIED"_q) {
_composeControls->cancelEditMessage();
} else if (err == u"MESSAGE_EMPTY"_q) {
_composeControls->focus();
} else {
Ui::show(Box<InformBox>(tr::lng_edit_error(tr::now)));
controller()->show(Box<InformBox>(tr::lng_edit_error(tr::now)));
}
update();
return true;
@@ -632,7 +638,7 @@ void ScheduledWidget::sendExistingDocument(
const auto callback = [=](Api::SendOptions options) {
sendExistingDocument(document, options);
};
Ui::show(
controller()->show(
PrepareScheduleBox(this, sendMenuType(), callback),
Ui::LayerOption::KeepOther);
}
@@ -644,7 +650,9 @@ bool ScheduledWidget::sendExistingDocument(
_history->peer,
ChatRestriction::f_send_stickers);
if (error) {
Ui::show(Box<InformBox>(*error), Ui::LayerOption::KeepOther);
controller()->show(
Box<InformBox>(*error),
Ui::LayerOption::KeepOther);
return false;
}
@@ -662,7 +670,7 @@ void ScheduledWidget::sendExistingPhoto(not_null<PhotoData*> photo) {
const auto callback = [=](Api::SendOptions options) {
sendExistingPhoto(photo, options);
};
Ui::show(
controller()->show(
PrepareScheduleBox(this, sendMenuType(), callback),
Ui::LayerOption::KeepOther);
}
@@ -674,7 +682,9 @@ bool ScheduledWidget::sendExistingPhoto(
_history->peer,
ChatRestriction::f_send_media);
if (error) {
Ui::show(Box<InformBox>(*error), Ui::LayerOption::KeepOther);
controller()->show(
Box<InformBox>(*error),
Ui::LayerOption::KeepOther);
return false;
}
@@ -693,13 +703,13 @@ void ScheduledWidget::sendInlineResult(
not_null<UserData*> bot) {
const auto errorText = result->getErrorOnSend(_history);
if (!errorText.isEmpty()) {
Ui::show(Box<InformBox>(errorText));
controller()->show(Box<InformBox>(errorText));
return;
}
const auto callback = [=](Api::SendOptions options) {
sendInlineResult(result, bot, options);
};
Ui::show(
controller()->show(
PrepareScheduleBox(this, sendMenuType(), callback),
Ui::LayerOption::KeepOther);
}
@@ -855,7 +865,7 @@ void ScheduledWidget::scrollDownAnimationFinish() {
void ScheduledWidget::updateAdaptiveLayout() {
_topBarShadow->moveToLeft(
Adaptive::OneColumn() ? 0 : st::lineWidth,
controller()->adaptive().isOneColumn() ? 0 : st::lineWidth,
_topBar->height());
}
@@ -1168,7 +1178,7 @@ void ScheduledWidget::listSendBotCommand(
message.action.options = options;
session().api().sendMessage(std::move(message));
};
Ui::show(
controller()->show(
PrepareScheduleBox(this, sendMenuType(), callback),
Ui::LayerOption::KeepOther);
}

View File

@@ -16,8 +16,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_chat.h"
#include "data/data_channel.h"
#include "ui/text/text_options.h"
#include "core/core_settings.h"
#include "core/application.h"
#include "mainwidget.h"
#include "layout.h"
#include "lang/lang_keys.h"
@@ -216,13 +214,13 @@ void paintPreparedDate(
int dateTextWidth,
int y,
int w,
bool chatWide,
const style::color &bg,
const style::color &fg) {
int left = st::msgServiceMargin.left();
int maxwidth = w;
if (Core::App().settings().chatWide()) {
maxwidth = qMin(maxwidth, WideChatWidth());
}
const auto maxwidth = chatWide
? std::min(w, WideChatWidth())
: w;
w = maxwidth - st::msgServiceMargin.left() - st::msgServiceMargin.left();
left += (w - dateTextWidth - st::msgServicePadding.left() - st::msgServicePadding.right()) / 2;
@@ -262,11 +260,12 @@ void ServiceMessagePainter::paintDate(
const QDateTime &date,
int y,
int w,
bool chatWide,
const style::color &bg,
const style::color &fg) {
const auto dateText = langDayOfMonthFull(date.date());
const auto dateTextWidth = st::msgServiceFont->width(dateText);
paintPreparedDate(p, dateText, dateTextWidth, y, w, bg, fg);
paintPreparedDate(p, dateText, dateTextWidth, y, w, chatWide, bg, fg);
}
void ServiceMessagePainter::paintDate(
@@ -274,6 +273,7 @@ void ServiceMessagePainter::paintDate(
const QString &dateText,
int y,
int w,
bool chatWide,
const style::color &bg,
const style::color &fg) {
paintPreparedDate(
@@ -282,6 +282,7 @@ void ServiceMessagePainter::paintDate(
st::msgServiceFont->width(dateText),
y,
w,
chatWide,
bg,
fg);
}
@@ -292,9 +293,10 @@ void ServiceMessagePainter::paintDate(
int dateTextWidth,
int y,
int w,
bool chatWide,
const style::color &bg,
const style::color &fg) {
paintPreparedDate(p, dateText, dateTextWidth, y, w, bg, fg);
paintPreparedDate(p, dateText, dateTextWidth, y, w, chatWide, bg, fg);
}
void ServiceMessagePainter::paintBubble(
@@ -439,7 +441,7 @@ not_null<HistoryService*> Service::message() const {
QRect Service::countGeometry() const {
auto result = QRect(0, 0, width(), height());
if (Core::App().settings().chatWide()) {
if (delegate()->elementIsChatWide()) {
result.setWidth(qMin(result.width(), st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left()));
}
return result.marginsRemoved(st::msgServiceMargin);
@@ -462,7 +464,7 @@ QSize Service::performCountCurrentSize(int newWidth) {
item->_textHeight = 0;
} else {
auto contentWidth = newWidth;
if (Core::App().settings().chatWide()) {
if (delegate()->elementIsChatWide()) {
accumulate_min(contentWidth, st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left());
}
contentWidth -= st::msgServiceMargin.left() + st::msgServiceMargin.left(); // two small margins
@@ -536,7 +538,7 @@ void Service::draw(
if (const auto bar = Get<UnreadBar>()) {
unreadbarh = bar->height();
if (clip.intersects(QRect(0, 0, width(), unreadbarh))) {
bar->paint(p, 0, width());
bar->paint(p, 0, width(), delegate()->elementIsChatWide());
}
p.translate(0, unreadbarh);
clip.translate(0, -unreadbarh);

View File

@@ -68,6 +68,7 @@ public:
const QDateTime &date,
int y,
int w,
bool chatWide,
const style::color &bg = st::msgServiceBg,
const style::color &fg = st::msgServiceFg);
static void paintDate(
@@ -75,6 +76,7 @@ public:
const QString &dateText,
int y,
int w,
bool chatWide,
const style::color &bg = st::msgServiceBg,
const style::color &fg = st::msgServiceFg);
static void paintDate(
@@ -83,6 +85,7 @@ public:
int dateTextWidth,
int y,
int w,
bool chatWide,
const style::color &bg = st::msgServiceBg,
const style::color &fg = st::msgServiceFg);

View File

@@ -32,6 +32,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/special_buttons.h"
#include "ui/unread_badge.h"
#include "ui/ui_utility.h"
#include "window/window_adaptive.h"
#include "window/window_session_controller.h"
#include "window/window_peer_menu.h"
#include "calls/calls_instance.h"
@@ -46,7 +47,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/unixtime.h"
#include "support/support_helper.h"
#include "apiwrap.h"
#include "facades.h"
#include "styles/style_window.h"
#include "styles/style_dialogs.h"
#include "styles/style_chat.h"
@@ -117,7 +117,11 @@ TopBarWidget::TopBarWidget(
_search->setForceRippled(searchInActiveChat, animated);
}, lifetime());
subscribe(Adaptive::Changed(), [=] { updateAdaptiveLayout(); });
controller->adaptive().changed(
) | rpl::start_with_next([=] {
updateAdaptiveLayout();
}, lifetime());
refreshUnreadBadge();
{
using AnimationUpdate = Data::Session::SendActionAnimationUpdate;
@@ -167,8 +171,7 @@ TopBarWidget::TopBarWidget(
updateInfoToggleActive();
}, lifetime());
rpl::single(rpl::empty_value()) | rpl::then(
base::ObservableViewer(Global::RefConnectionTypeChanged())
Core::App().settings().proxy().connectionTypeValue(
) | rpl::start_with_next([=] {
updateConnectingState();
}, lifetime());
@@ -297,7 +300,8 @@ void TopBarWidget::showMenu() {
}
void TopBarWidget::toggleInfoSection() {
if (Adaptive::ThreeColumn()
const auto isThreeColumn = _controller->adaptive().isThreeColumn();
if (isThreeColumn
&& (Core::App().settings().thirdSectionInfoEnabled()
|| Core::App().settings().tabbedReplacedWithInfo())) {
_controller->closeThirdSection();
@@ -305,7 +309,7 @@ void TopBarWidget::toggleInfoSection() {
if (_controller->canShowThirdSection()) {
Core::App().settings().setThirdSectionInfoEnabled(true);
Core::App().saveSettingsDelayed();
if (Adaptive::ThreeColumn()) {
if (isThreeColumn) {
_controller->showSection(
Info::Memento::Default(_activeChat.key.peer()),
Window::SectionShow().withThirdColumn());
@@ -672,7 +676,8 @@ void TopBarWidget::updateControlsGeometry() {
auto hasSelected = showSelectedActions();
auto selectedButtonsTop = countSelectedButtonsTop(_selectedShown.value(hasSelected ? 1. : 0.));
auto otherButtonsTop = selectedButtonsTop + st::topBarHeight;
auto buttonsLeft = st::topBarActionSkip + (Adaptive::OneColumn() ? 0 : st::lineWidth);
auto buttonsLeft = st::topBarActionSkip
+ (_controller->adaptive().isOneColumn() ? 0 : st::lineWidth);
auto buttonsWidth = (_forward->isHidden() ? 0 : _forward->contentWidth())
+ (_sendNow->isHidden() ? 0 : _sendNow->contentWidth())
+ (_delete->isHidden() ? 0 : _delete->contentWidth())
@@ -767,13 +772,14 @@ void TopBarWidget::updateControlsVisibility() {
_forward->setVisible(_canForward);
_sendNow->setVisible(_canSendNow);
auto backVisible = Adaptive::OneColumn()
const auto isOneColumn = _controller->adaptive().isOneColumn();
auto backVisible = isOneColumn
|| !_controller->content()->stackIsEmpty()
|| _activeChat.key.folder();
_back->setVisible(backVisible && !_chooseForReportReason);
_cancelChoose->setVisible(_chooseForReportReason.has_value());
if (_info) {
_info->setVisible(Adaptive::OneColumn() && !_chooseForReportReason);
_info->setVisible(isOneColumn && !_chooseForReportReason);
}
if (_unreadBadge) {
_unreadBadge->setVisible(!_chooseForReportReason);
@@ -790,7 +796,7 @@ void TopBarWidget::updateControlsVisibility() {
_menuToggle->setVisible(hasMenu && !_chooseForReportReason);
_infoToggle->setVisible(historyMode
&& !_activeChat.key.folder()
&& !Adaptive::OneColumn()
&& !isOneColumn
&& _controller->canShowThirdSection()
&& !_chooseForReportReason);
const auto callsEnabled = [&] {
@@ -921,7 +927,7 @@ void TopBarWidget::updateAdaptiveLayout() {
}
void TopBarWidget::refreshUnreadBadge() {
if (!Adaptive::OneColumn() && !_activeChat.key.folder()) {
if (!_controller->adaptive().isOneColumn() && !_activeChat.key.folder()) {
_unreadBadge.destroy();
return;
} else if (_unreadBadge) {
@@ -965,7 +971,7 @@ void TopBarWidget::updateUnreadBadge() {
}
void TopBarWidget::updateInfoToggleActive() {
auto infoThirdActive = Adaptive::ThreeColumn()
auto infoThirdActive = _controller->adaptive().isThreeColumn()
&& (Core::App().settings().thirdSectionInfoEnabled()
|| Core::App().settings().tabbedReplacedWithInfo());
auto iconOverride = infoThirdActive

Some files were not shown because too many files have changed in this diff Show More