Merge tag 'v5.2.2' into dev

This commit is contained in:
AlexeyZavar 2024-07-02 22:53:41 +03:00
commit f73edfec94
51 changed files with 408 additions and 176 deletions

View file

@ -959,10 +959,10 @@ PRIVATE
history/history_view_highlight_manager.h history/history_view_highlight_manager.h
history/history_widget.cpp history/history_widget.cpp
history/history_widget.h history/history_widget.h
info/bot/earn/info_earn_inner_widget.cpp info/bot/earn/info_bot_earn_list.cpp
info/bot/earn/info_earn_inner_widget.h info/bot/earn/info_bot_earn_list.h
info/bot/earn/info_earn_widget.cpp info/bot/earn/info_bot_earn_widget.cpp
info/bot/earn/info_earn_widget.h info/bot/earn/info_bot_earn_widget.h
info/channel_statistics/boosts/create_giveaway_box.cpp info/channel_statistics/boosts/create_giveaway_box.cpp
info/channel_statistics/boosts/create_giveaway_box.h info/channel_statistics/boosts/create_giveaway_box.h
info/channel_statistics/boosts/giveaway/giveaway_list_controllers.cpp info/channel_statistics/boosts/giveaway/giveaway_list_controllers.cpp
@ -971,10 +971,10 @@ PRIVATE
info/channel_statistics/boosts/info_boosts_inner_widget.h info/channel_statistics/boosts/info_boosts_inner_widget.h
info/channel_statistics/boosts/info_boosts_widget.cpp info/channel_statistics/boosts/info_boosts_widget.cpp
info/channel_statistics/boosts/info_boosts_widget.h info/channel_statistics/boosts/info_boosts_widget.h
info/channel_statistics/earn/info_earn_inner_widget.cpp info/channel_statistics/earn/info_channel_earn_list.cpp
info/channel_statistics/earn/info_earn_inner_widget.h info/channel_statistics/earn/info_channel_earn_list.h
info/channel_statistics/earn/info_earn_widget.cpp info/channel_statistics/earn/info_channel_earn_widget.cpp
info/channel_statistics/earn/info_earn_widget.h info/channel_statistics/earn/info_channel_earn_widget.h
info/common_groups/info_common_groups_inner_widget.cpp info/common_groups/info_common_groups_inner_widget.cpp
info/common_groups/info_common_groups_inner_widget.h info/common_groups/info_common_groups_inner_widget.h
info/common_groups/info_common_groups_widget.cpp info/common_groups/info_common_groups_widget.cpp

Binary file not shown.

After

Width:  |  Height:  |  Size: 438 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 631 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 886 B

View file

@ -687,6 +687,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_settings_use_winhello_about" = "You need to enter your passcode once before unlocking Telegram with Windows Hello."; "lng_settings_use_winhello_about" = "You need to enter your passcode once before unlocking Telegram with Windows Hello.";
"lng_settings_use_touchid" = "Unlock with Touch ID"; "lng_settings_use_touchid" = "Unlock with Touch ID";
"lng_settings_use_touchid_about" = "You need to enter your passcode once before unlocking Telegram with Touch ID."; "lng_settings_use_touchid_about" = "You need to enter your passcode once before unlocking Telegram with Touch ID.";
"lng_settings_use_applewatch" = "Unlock with Apple Watch";
"lng_settings_use_applewatch_about" = "You need to enter your passcode once before unlocking Telegram with Apple Watch.";
"lng_settings_use_systempwd" = "Unlock with System Password";
"lng_settings_use_systempwd_about" = "You need to enter your passcode once before unlocking Telegram with System Password.";
"lng_settings_password_disable" = "Disable Cloud Password"; "lng_settings_password_disable" = "Disable Cloud Password";
"lng_settings_password_abort" = "Abort two-step verification setup"; "lng_settings_password_abort" = "Abort two-step verification setup";
"lng_settings_about_bio" = "Any details such as age, occupation or city.\nExample: 23 y.o. designer from San Francisco"; "lng_settings_about_bio" = "Any details such as age, occupation or city.\nExample: 23 y.o. designer from San Francisco";
@ -998,6 +1002,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_passcode_logout" = "Log out"; "lng_passcode_logout" = "Log out";
"lng_passcode_winhello" = "You need to enter your passcode\nbefore you can use Windows Hello."; "lng_passcode_winhello" = "You need to enter your passcode\nbefore you can use Windows Hello.";
"lng_passcode_touchid" = "You need to enter your passcode\nbefore you can use Touch ID."; "lng_passcode_touchid" = "You need to enter your passcode\nbefore you can use Touch ID.";
"lng_passcode_applewatch" = "You need to enter your passcode\nbefore you can use Watch to unlock.";
"lng_passcode_systempwd" = "You need to enter your passcode\nbefore you can use system password.";
"lng_passcode_winhello_unlock" = "Telegram wants to unlock with Windows Hello."; "lng_passcode_winhello_unlock" = "Telegram wants to unlock with Windows Hello.";
"lng_passcode_touchid_unlock" = "unlock"; "lng_passcode_touchid_unlock" = "unlock";
"lng_passcode_create_button" = "Save Passcode"; "lng_passcode_create_button" = "Save Passcode";

View file

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

View file

@ -44,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 5,2,0,0 FILEVERSION 5,2,2,0
PRODUCTVERSION 5,2,0,0 PRODUCTVERSION 5,2,2,0
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -62,10 +62,10 @@ BEGIN
BEGIN BEGIN
VALUE "CompanyName", "Radolyn Labs" VALUE "CompanyName", "Radolyn Labs"
VALUE "FileDescription", "AyuGram Desktop" VALUE "FileDescription", "AyuGram Desktop"
VALUE "FileVersion", "5.2.0.0" VALUE "FileVersion", "5.2.2.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2024" VALUE "LegalCopyright", "Copyright (C) 2014-2024"
VALUE "ProductName", "AyuGram Desktop" VALUE "ProductName", "AyuGram Desktop"
VALUE "ProductVersion", "5.2.0.0" VALUE "ProductVersion", "5.2.2.0"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View file

@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 5,2,0,0 FILEVERSION 5,2,2,0
PRODUCTVERSION 5,2,0,0 PRODUCTVERSION 5,2,2,0
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -53,10 +53,10 @@ BEGIN
BEGIN BEGIN
VALUE "CompanyName", "Radolyn Labs" VALUE "CompanyName", "Radolyn Labs"
VALUE "FileDescription", "AyuGram Desktop Updater" VALUE "FileDescription", "AyuGram Desktop Updater"
VALUE "FileVersion", "5.2.0.0" VALUE "FileVersion", "5.2.2.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2024" VALUE "LegalCopyright", "Copyright (C) 2014-2024"
VALUE "ProductName", "AyuGram Desktop" VALUE "ProductName", "AyuGram Desktop"
VALUE "ProductVersion", "5.2.0.0" VALUE "ProductVersion", "5.2.2.0"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View file

@ -293,6 +293,8 @@ passcodeSkip: 23px;
passcodeSystemUnlock: IconButton(defaultIconButton) { passcodeSystemUnlock: IconButton(defaultIconButton) {
width: 32px; width: 32px;
height: 36px; height: 36px;
icon: icon{{ "menu/passcode_winhello", lightButtonFg }};
iconOver: icon{{ "menu/passcode_winhello", lightButtonFg }};
iconPosition: point(4px, 4px); iconPosition: point(4px, 4px);
rippleAreaSize: 32px; rippleAreaSize: 32px;
rippleAreaPosition: point(0px, 0px); rippleAreaPosition: point(0px, 0px);
@ -300,14 +302,9 @@ passcodeSystemUnlock: IconButton(defaultIconButton) {
color: lightButtonBgOver; color: lightButtonBgOver;
} }
} }
passcodeSystemWinHello: IconButton(passcodeSystemUnlock) { passcodeSystemTouchID: icon{{ "menu/passcode_finger", lightButtonFg }};
icon: icon{{ "menu/passcode_winhello", lightButtonFg }}; passcodeSystemAppleWatch: icon{{ "menu/passcode_watch", lightButtonFg }};
iconOver: icon{{ "menu/passcode_winhello", lightButtonFg }}; passcodeSystemSystemPwd: icon{{ "menu/permissions", lightButtonFg }};
}
passcodeSystemTouchID: IconButton(passcodeSystemUnlock) {
icon: icon{{ "menu/passcode_finger", lightButtonFg }};
iconOver: icon{{ "menu/passcode_finger", lightButtonFg }};
}
passcodeSystemUnlockLater: FlatLabel(defaultFlatLabel) { passcodeSystemUnlockLater: FlatLabel(defaultFlatLabel) {
align: align(top); align: align(top);
textFg: windowSubTextFg; textFg: windowSubTextFg;

View file

@ -43,7 +43,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_premium_limits.h" #include "data/data_premium_limits.h"
#include "data/data_user.h" #include "data/data_user.h"
#include "history/admin_log/history_admin_log_section.h" #include "history/admin_log/history_admin_log_section.h"
#include "info/bot/earn/info_earn_widget.h" #include "info/bot/earn/info_bot_earn_widget.h"
#include "info/channel_statistics/boosts/info_boosts_widget.h" #include "info/channel_statistics/boosts/info_boosts_widget.h"
#include "info/profile/info_profile_values.h" #include "info/profile/info_profile_values.h"
#include "info/info_memento.h" #include "info/info_memento.h"
@ -2200,8 +2200,11 @@ void Controller::saveForum() {
channel->inputChannel, channel->inputChannel,
MTP_bool(*_savingData.forum) MTP_bool(*_savingData.forum)
)).done([=](const MTPUpdates &result) { )).done([=](const MTPUpdates &result) {
const auto weak = base::make_weak(this);
channel->session().api().applyUpdates(result); channel->session().api().applyUpdates(result);
continueSave(); if (weak) { // todo better to be able to save in closed already box.
continueSave();
}
}).fail([=](const MTP::Error &error) { }).fail([=](const MTP::Error &error) {
if (error.type() == u"CHAT_NOT_MODIFIED"_q) { if (error.type() == u"CHAT_NOT_MODIFIED"_q) {
continueSave(); continueSave();

View file

@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/battery_saving.h" #include "base/battery_saving.h"
#include "base/event_filter.h" #include "base/event_filter.h"
#include "base/concurrent_timer.h" #include "base/concurrent_timer.h"
#include "base/options.h"
#include "base/qt_signal_producer.h" #include "base/qt_signal_producer.h"
#include "base/timer.h" #include "base/timer.h"
#include "base/unixtime.h" #include "base/unixtime.h"
@ -144,10 +145,18 @@ void SetCrashAnnotationsGL() {
#endif // DESKTOP_APP_USE_ANGLE #endif // DESKTOP_APP_USE_ANGLE
} }
base::options::toggle OptionSkipUrlSchemeRegister({
.id = kOptionSkipUrlSchemeRegister,
.name = "Skip URL scheme register",
.description = "Don't re-register tg:// URL scheme on autoupdate.",
});
} // namespace } // namespace
Application *Application::Instance = nullptr; Application *Application::Instance = nullptr;
const char kOptionSkipUrlSchemeRegister[] = "skip-url-scheme-register";
struct Application::Private { struct Application::Private {
base::Timer quitTimer; base::Timer quitTimer;
UiIntegration uiIntegration; UiIntegration uiIntegration;
@ -265,9 +274,14 @@ void Application::run() {
refreshGlobalProxy(); // Depends on app settings being read. refreshGlobalProxy(); // Depends on app settings being read.
if (const auto old = Local::oldSettingsVersion(); old < AppVersion) { if (const auto old = Local::oldSettingsVersion()) {
InvokeQueued(this, [] { RegisterUrlScheme(); }); if (old < AppVersion) {
Platform::NewVersionLaunched(old); autoRegisterUrlScheme();
Platform::NewVersionLaunched(old);
}
} else {
// Initial launch.
autoRegisterUrlScheme();
} }
if (cAutoStart() && !Platform::AutostartSupported()) { if (cAutoStart() && !Platform::AutostartSupported()) {
@ -409,6 +423,12 @@ void Application::run() {
processCreatedWindow(_lastActivePrimaryWindow); processCreatedWindow(_lastActivePrimaryWindow);
} }
void Application::autoRegisterUrlScheme() {
if (!OptionSkipUrlSchemeRegister.value()) {
InvokeQueued(this, [] { RegisterUrlScheme(); });
}
}
void Application::showAccount(not_null<Main::Account*> account) { void Application::showAccount(not_null<Main::Account*> account) {
if (const auto separate = separateWindowFor(account)) { if (const auto separate = separateWindowFor(account)) {
_lastActivePrimaryWindow = separate; _lastActivePrimaryWindow = separate;

View file

@ -126,6 +126,8 @@ enum class QuitReason {
QtQuitEvent, QtQuitEvent,
}; };
extern const char kOptionSkipUrlSchemeRegister[];
class Application final : public QObject { class Application final : public QObject {
public: public:
struct ProxyChange { struct ProxyChange {
@ -352,6 +354,7 @@ private:
friend bool IsAppLaunched(); friend bool IsAppLaunched();
friend Application &App(); friend Application &App();
void autoRegisterUrlScheme();
void clearEmojiSourceImages(); void clearEmojiSourceImages();
[[nodiscard]] auto prepareEmojiSourceImages() [[nodiscard]] auto prepareEmojiSourceImages()
-> std::shared_ptr<Ui::Emoji::UniversalImages>; -> std::shared_ptr<Ui::Emoji::UniversalImages>;

View file

@ -22,7 +22,7 @@ constexpr auto AppId = "{53F49750-6209-4FBF-9CA8-7A333C87D666}"_cs;
constexpr auto AppNameOld = "AyuGram for Windows"_cs; constexpr auto AppNameOld = "AyuGram for Windows"_cs;
constexpr auto AppName = "AyuGram Desktop"_cs; constexpr auto AppName = "AyuGram Desktop"_cs;
constexpr auto AppFile = "AyuGram"_cs; constexpr auto AppFile = "AyuGram"_cs;
constexpr auto AppVersion = 5002000; constexpr auto AppVersion = 5002002;
constexpr auto AppVersionStr = "5.2"; constexpr auto AppVersionStr = "5.2.2";
constexpr auto AppBetaVersion = false; constexpr auto AppBetaVersion = false;
constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION; constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION;

View file

@ -3690,6 +3690,9 @@ bool InnerWidget::chooseCollapsedRow(Qt::KeyboardModifiers modifiers) {
} }
void InnerWidget::switchToFilter(FilterId filterId) { void InnerWidget::switchToFilter(FilterId filterId) {
if (_controller->windowId().type != Window::SeparateType::Primary) {
return;
}
const auto &list = session().data().chatsFilters().list(); const auto &list = session().data().chatsFilters().list();
const auto filterIt = filterId const auto filterIt = filterId
? ranges::find(list, filterId, &Data::ChatFilter::id) ? ranges::find(list, filterId, &Data::ChatFilter::id)

View file

@ -100,7 +100,9 @@ ChatSearchTab SearchState::defaultTabForMe() const {
} }
bool SearchState::filterChatsList() const { bool SearchState::filterChatsList() const {
return !inChat && (tab == ChatSearchTab::MyMessages); using Tab = ChatSearchTab;
return !inChat // ThisPeer can be in opened forum.
&& (tab == Tab::MyMessages || tab == Tab::ThisPeer);
} }
} // namespace Dialogs } // namespace Dialogs

View file

@ -29,6 +29,7 @@ public:
std::shared_ptr<Ui::DynamicImage> icon, std::shared_ptr<Ui::DynamicImage> icon,
const QString &label, const QString &label,
bool chosen); bool chosen);
~Action();
bool isEnabled() const override; bool isEnabled() const override;
not_null<QAction*> action() const override; not_null<QAction*> action() const override;
@ -111,6 +112,10 @@ Action::Action(
enableMouseSelecting(); enableMouseSelecting();
} }
Action::~Action() {
_icon->subscribeToUpdates(nullptr);
}
void Action::resolveMinWidth() { void Action::resolveMinWidth() {
const auto maxWidth = st::dialogsSearchInPhotoPadding const auto maxWidth = st::dialogsSearchInPhotoPadding
+ st::dialogsSearchInPhotoSize + st::dialogsSearchInPhotoSize

View file

@ -1736,7 +1736,9 @@ std::unique_ptr<QMimeData> HistoryInner::prepareDrag() {
updateDragSelection(nullptr, nullptr, false); updateDragSelection(nullptr, nullptr, false);
_selectScroll.cancel(); _selectScroll.cancel();
if (!urls.isEmpty()) mimeData->setUrls(urls); if (!urls.isEmpty()) {
mimeData->setUrls(urls);
}
if (uponSelected && !_controller->adaptive().isOneColumn()) { if (uponSelected && !_controller->adaptive().isOneColumn()) {
auto selectedState = getSelectionState(); auto selectedState = getSelectionState();
if (selectedState.count > 0 && selectedState.count == selectedState.canForwardCount) { if (selectedState.count > 0 && selectedState.count == selectedState.canForwardCount) {
@ -1757,21 +1759,21 @@ std::unique_ptr<QMimeData> HistoryInner::prepareDrag() {
== forwardSelectionState.canForwardCount)) { == forwardSelectionState.canForwardCount)) {
forwardIds = getSelectedItems(); forwardIds = getSelectedItems();
} else if (_mouseCursorState == CursorState::Date) { } else if (_mouseCursorState == CursorState::Date) {
forwardIds = session().data().itemOrItsGroup(_mouseActionItem); const auto item = _mouseActionItem;
if (item && item->allowsForward()) {
forwardIds = session().data().itemOrItsGroup(item);
}
} else if ((pressedView->isHiddenByGroup() && pressedHandler) } else if ((pressedView->isHiddenByGroup() && pressedHandler)
|| (pressedView->media() || (pressedView->media()
&& pressedView->media()->dragItemByHandler(pressedHandler))) { && pressedView->media()->dragItemByHandler(pressedHandler))) {
const auto item = _dragStateItem const auto item = _dragStateItem
? _dragStateItem ? _dragStateItem
: _mouseActionItem; : _mouseActionItem;
forwardIds = MessageIdsList(1, item->fullId()); if (item && item->allowsForward()) {
forwardIds = MessageIdsList(1, item->fullId());
}
} }
if (forwardIds.empty()) {
return nullptr;
}
session().data().setMimeForwardIds(std::move(forwardIds));
auto result = std::make_unique<QMimeData>();
result->setData(u"application/x-td-forward"_q, "1");
if (pressedHandler) { if (pressedHandler) {
const auto lnkDocument = reinterpret_cast<DocumentData*>( const auto lnkDocument = reinterpret_cast<DocumentData*>(
pressedHandler->property( pressedHandler->property(
@ -1779,12 +1781,23 @@ std::unique_ptr<QMimeData> HistoryInner::prepareDrag() {
if (lnkDocument) { if (lnkDocument) {
const auto filepath = lnkDocument->filepath(true); const auto filepath = lnkDocument->filepath(true);
if (!filepath.isEmpty()) { if (!filepath.isEmpty()) {
QList<QUrl> urls;
urls.push_back(QUrl::fromLocalFile(filepath)); urls.push_back(QUrl::fromLocalFile(filepath));
result->setUrls(urls);
} }
} }
} }
if (forwardIds.empty() && urls.isEmpty()) {
return nullptr;
}
auto result = std::make_unique<QMimeData>();
if (!forwardIds.empty()) {
session().data().setMimeForwardIds(std::move(forwardIds));
result->setData(u"application/x-td-forward"_q, "1");
}
if (!urls.isEmpty()) {
result->setUrls(urls);
}
return result; return result;
} }
return nullptr; return nullptr;

View file

@ -3786,12 +3786,7 @@ std::unique_ptr<QMimeData> ListWidget::prepareDrag() {
forwardIds = MessageIdsList(1, exactItem->fullId()); forwardIds = MessageIdsList(1, exactItem->fullId());
} }
} }
if (forwardIds.empty()) {
return nullptr;
}
session().data().setMimeForwardIds(std::move(forwardIds));
auto result = std::make_unique<QMimeData>();
result->setData(u"application/x-td-forward"_q, "1");
if (pressedHandler) { if (pressedHandler) {
const auto lnkDocument = reinterpret_cast<DocumentData*>( const auto lnkDocument = reinterpret_cast<DocumentData*>(
pressedHandler->property( pressedHandler->property(
@ -3799,12 +3794,23 @@ std::unique_ptr<QMimeData> ListWidget::prepareDrag() {
if (lnkDocument) { if (lnkDocument) {
const auto filepath = lnkDocument->filepath(true); const auto filepath = lnkDocument->filepath(true);
if (!filepath.isEmpty()) { if (!filepath.isEmpty()) {
QList<QUrl> urls;
urls.push_back(QUrl::fromLocalFile(filepath)); urls.push_back(QUrl::fromLocalFile(filepath));
result->setUrls(urls);
} }
} }
} }
if (forwardIds.empty() && urls.isEmpty()) {
return nullptr;
}
auto result = std::make_unique<QMimeData>();
if (!forwardIds.empty()) {
session().data().setMimeForwardIds(std::move(forwardIds));
result->setData(u"application/x-td-forward"_q, "1");
}
if (!urls.isEmpty()) {
result->setUrls(urls);
}
return result; return result;
} }
return nullptr; return nullptr;

View file

@ -5,7 +5,7 @@ the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link: For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#include "info/bot/earn/info_earn_inner_widget.h" #include "info/bot/earn/info_bot_earn_list.h"
#include "api/api_credits.h" #include "api/api_credits.h"
#include "api/api_filter_updates.h" #include "api/api_filter_updates.h"
@ -15,7 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_session.h" #include "data/data_session.h"
#include "data/data_user.h" #include "data/data_user.h"
#include "data/stickers/data_custom_emoji.h" #include "data/stickers/data_custom_emoji.h"
#include "info/bot/earn/info_earn_widget.h" #include "info/bot/earn/info_bot_earn_widget.h"
#include "info/channel_statistics/earn/earn_format.h" #include "info/channel_statistics/earn/earn_format.h"
#include "info/info_controller.h" #include "info/info_controller.h"
#include "info/statistics/info_statistics_inner_widget.h" // FillLoading. #include "info/statistics/info_statistics_inner_widget.h" // FillLoading.

View file

@ -5,9 +5,9 @@ the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link: For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#include "info/bot/earn/info_earn_widget.h" #include "info/bot/earn/info_bot_earn_widget.h"
#include "info/bot/earn/info_earn_inner_widget.h" #include "info/bot/earn/info_bot_earn_list.h"
#include "info/info_controller.h" #include "info/info_controller.h"
#include "info/info_memento.h" #include "info/info_memento.h"
#include "lang/lang_keys.h" #include "lang/lang_keys.h"

View file

@ -5,7 +5,7 @@ the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link: For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#include "info/channel_statistics/earn/info_earn_inner_widget.h" #include "info/channel_statistics/earn/info_channel_earn_list.h"
#include "api/api_credits.h" #include "api/api_credits.h"
#include "api/api_earn.h" #include "api/api_earn.h"
@ -24,7 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/stickers/data_custom_emoji.h" #include "data/stickers/data_custom_emoji.h"
#include "history/view/controls/history_view_webpage_processor.h" #include "history/view/controls/history_view_webpage_processor.h"
#include "info/channel_statistics/earn/earn_format.h" #include "info/channel_statistics/earn/earn_format.h"
#include "info/channel_statistics/earn/info_earn_widget.h" #include "info/channel_statistics/earn/info_channel_earn_widget.h"
#include "info/info_controller.h" #include "info/info_controller.h"
#include "info/profile/info_profile_values.h" // Info::Profile::NameValue. #include "info/profile/info_profile_values.h" // Info::Profile::NameValue.
#include "info/statistics/info_statistics_inner_widget.h" // FillLoading. #include "info/statistics/info_statistics_inner_widget.h" // FillLoading.

View file

@ -7,7 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#pragma once #pragma once
#include "info/channel_statistics/earn/info_earn_widget.h" #include "info/channel_statistics/earn/info_channel_earn_widget.h"
#include "ui/widgets/scroll_area.h" #include "ui/widgets/scroll_area.h"
#include "ui/wrap/vertical_layout.h" #include "ui/wrap/vertical_layout.h"

View file

@ -5,9 +5,9 @@ the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link: For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#include "info/channel_statistics/earn/info_earn_widget.h" #include "info/channel_statistics/earn/info_channel_earn_widget.h"
#include "info/channel_statistics/earn/info_earn_inner_widget.h" #include "info/channel_statistics/earn/info_channel_earn_list.h"
#include "info/info_controller.h" #include "info/info_controller.h"
#include "info/info_memento.h" #include "info/info_memento.h"
#include "lang/lang_keys.h" #include "lang/lang_keys.h"

View file

@ -346,9 +346,11 @@ void Controller::createWindow() {
_window = std::make_unique<Ui::RpWindow>(); _window = std::make_unique<Ui::RpWindow>();
const auto window = _window.get(); const auto window = _window.get();
window->windowActiveValue( base::qt_signal_producer(
) | rpl::filter([=](bool active) { window->window()->windowHandle(),
return _webview && active; &QWindow::activeChanged
) | rpl::filter([=] {
return _webview && window->window()->windowHandle()->isActive();
}) | rpl::start_with_next([=] { }) | rpl::start_with_next([=] {
setInnerFocus(); setInnerFocus();
}, window->lifetime()); }, window->lifetime());

View file

@ -71,6 +71,12 @@ bool Data::partial() const {
Data::~Data() = default; Data::~Data() = default;
void Data::updateCachedViews(int cachedViews) {
_source->updatedCachedViews = std::max(
_source->updatedCachedViews,
cachedViews);
}
void Data::prepare(const Options &options, Fn<void(Prepared)> done) const { void Data::prepare(const Options &options, Fn<void(Prepared)> done) const {
crl::async([source = *_source, options, done = std::move(done)] { crl::async([source = *_source, options, done = std::move(done)] {
done(Prepare(source, options)); done(Prepare(source, options));

View file

@ -45,6 +45,8 @@ public:
[[nodiscard]] QString id() const; [[nodiscard]] QString id() const;
[[nodiscard]] bool partial() const; [[nodiscard]] bool partial() const;
void updateCachedViews(int cachedViews);
void prepare(const Options &options, Fn<void(Prepared)> done) const; void prepare(const Options &options, Fn<void(Prepared)> done) const;
private: private:

View file

@ -57,6 +57,7 @@ constexpr auto kGeoPointScale = 1;
constexpr auto kGeoPointZoomMin = 13; constexpr auto kGeoPointZoomMin = 13;
constexpr auto kMaxLoadParts = 5; constexpr auto kMaxLoadParts = 5;
constexpr auto kKeepLoadingParts = 8; constexpr auto kKeepLoadingParts = 8;
constexpr auto kAllowPageReloadAfter = 3 * crl::time(1000);
} // namespace } // namespace
@ -815,19 +816,19 @@ void Instance::show(
} }
break; break;
case Type::OpenPage: case Type::OpenPage:
case Type::OpenLink: case Type::OpenLink: {
if (!urlChecked) { if (!urlChecked) {
break; break;
} }
_fullRequested[_shownSession].emplace(event.url); const auto session = _shownSession;
_shownSession->api().request(MTPmessages_GetWebPage( const auto url = event.url;
MTP_string(event.url), auto &requested = _fullRequested[session][url];
MTP_int(0) requested.lastRequestedAt = crl::now();
session->api().request(MTPmessages_GetWebPage(
MTP_string(url),
MTP_int(requested.hash)
)).done([=](const MTPmessages_WebPage &result) { )).done([=](const MTPmessages_WebPage &result) {
_shownSession->data().processUsers(result.data().vusers()); const auto page = processReceivedPage(session, url, result);
_shownSession->data().processChats(result.data().vchats());
const auto page = _shownSession->data().processWebpage(
result.data().vwebpage());
if (page && page->iv) { if (page && page->iv) {
const auto parts = event.url.split('#'); const auto parts = event.url.split('#');
const auto hash = (parts.size() > 1) ? parts[1] : u""_q; const auto hash = (parts.size() > 1) ? parts[1] : u""_q;
@ -838,7 +839,7 @@ void Instance::show(
}).fail([=] { }).fail([=] {
UrlClickHandler::Open(event.url); UrlClickHandler::Open(event.url);
}).send(); }).send();
break; } break;
case Type::Report: case Type::Report:
if (const auto controller = _shownSession->tryResolveWindow()) { if (const auto controller = _shownSession->tryResolveWindow()) {
controller->window().activate(); controller->window().activate();
@ -954,15 +955,13 @@ void Instance::openWithIvPreferred(
}; };
_ivRequestSession = session; _ivRequestSession = session;
_ivRequestUri = uri; _ivRequestUri = uri;
_fullRequested[session].emplace(url); auto &requested = _fullRequested[session][url];
requested.lastRequestedAt = crl::now();
_ivRequestId = session->api().request(MTPmessages_GetWebPage( _ivRequestId = session->api().request(MTPmessages_GetWebPage(
MTP_string(url), MTP_string(url),
MTP_int(0) MTP_int(requested.hash)
)).done([=](const MTPmessages_WebPage &result) { )).done([=](const MTPmessages_WebPage &result) {
const auto &data = result.data(); finish(processReceivedPage(session, url, result));
session->data().processUsers(data.vusers());
session->data().processChats(data.vchats());
finish(session->data().processWebpage(data.vwebpage()));
}).fail([=] { }).fail([=] {
finish(nullptr); finish(nullptr);
}).send(); }).send();
@ -971,24 +970,53 @@ void Instance::openWithIvPreferred(
void Instance::requestFull( void Instance::requestFull(
not_null<Main::Session*> session, not_null<Main::Session*> session,
const QString &id) { const QString &id) {
if (!_tracking.contains(session) if (!_tracking.contains(session)) {
|| !_fullRequested[session].emplace(id).second) {
return; return;
} }
auto &requested = _fullRequested[session][id];
const auto last = requested.lastRequestedAt;
const auto now = crl::now();
if (last && (now - last) < kAllowPageReloadAfter) {
return;
}
requested.lastRequestedAt = now;
session->api().request(MTPmessages_GetWebPage( session->api().request(MTPmessages_GetWebPage(
MTP_string(id), MTP_string(id),
MTP_int(0) MTP_int(requested.hash)
)).done([=](const MTPmessages_WebPage &result) { )).done([=](const MTPmessages_WebPage &result) {
session->data().processUsers(result.data().vusers()); const auto page = processReceivedPage(session, id, result);
session->data().processChats(result.data().vchats());
const auto page = session->data().processWebpage(
result.data().vwebpage());
if (page && page->iv && _shown && _shownSession == session) { if (page && page->iv && _shown && _shownSession == session) {
_shown->update(page->iv.get()); _shown->update(page->iv.get());
} }
}).send(); }).send();
} }
WebPageData *Instance::processReceivedPage(
not_null<Main::Session*> session,
const QString &url,
const MTPmessages_WebPage &result) {
const auto &data = result.data();
const auto owner = &session->data();
owner->processUsers(data.vusers());
owner->processChats(data.vchats());
auto &requested = _fullRequested[session][url];
const auto &mtp = data.vwebpage();
mtp.match([&](const MTPDwebPageNotModified &data) {
const auto page = requested.page;
if (const auto views = data.vcached_page_views()) {
if (page && page->iv) {
page->iv->updateCachedViews(views->v);
}
}
}, [&](const MTPDwebPage &data) {
requested.hash = data.vhash().v;
requested.page = owner->processWebpage(data).get();
}, [&](const auto &) {
requested.page = owner->processWebpage(mtp).get();
});
return requested.page;
}
void Instance::processOpenChannel(const QString &context) { void Instance::processOpenChannel(const QString &context) {
if (!_shownSession) { if (!_shownSession) {
return; return;

View file

@ -61,12 +61,23 @@ public:
[[nodiscard]] rpl::lifetime &lifetime(); [[nodiscard]] rpl::lifetime &lifetime();
private: private:
struct FullResult {
crl::time lastRequestedAt = 0;
WebPageData *page = nullptr;
int32 hash = 0;
};
void processOpenChannel(const QString &context); void processOpenChannel(const QString &context);
void processJoinChannel(const QString &context); void processJoinChannel(const QString &context);
void requestFull(not_null<Main::Session*> session, const QString &id); void requestFull(not_null<Main::Session*> session, const QString &id);
void trackSession(not_null<Main::Session*> session); void trackSession(not_null<Main::Session*> session);
WebPageData *processReceivedPage(
not_null<Main::Session*> session,
const QString &url,
const MTPmessages_WebPage &result);
const not_null<Delegate*> _delegate; const not_null<Delegate*> _delegate;
std::unique_ptr<Shown> _shown; std::unique_ptr<Shown> _shown;
@ -77,7 +88,7 @@ private:
base::flat_set<not_null<ChannelData*>>> _joining; base::flat_set<not_null<ChannelData*>>> _joining;
base::flat_map< base::flat_map<
not_null<Main::Session*>, not_null<Main::Session*>,
base::flat_set<QString>> _fullRequested; base::flat_map<QString, FullResult>> _fullRequested;
base::flat_map< base::flat_map<
not_null<Main::Session*>, not_null<Main::Session*>,

View file

@ -229,7 +229,9 @@ Parser::Parser(const Source &source, const Options &options)
_result.name = source.name; _result.name = source.name;
_result.rtl = source.page.data().is_rtl(); _result.rtl = source.page.data().is_rtl();
const auto views = source.page.data().vviews().value_or_empty(); const auto views = std::max(
source.page.data().vviews().value_or_empty(),
source.updatedCachedViews);
const auto content = list(source.page.data().vblocks()); const auto content = list(source.page.data().vblocks());
_result.content = wrap(content, views); _result.content = wrap(content, views);
} }

View file

@ -18,6 +18,7 @@ struct Source {
std::optional<MTPPhoto> webpagePhoto; std::optional<MTPPhoto> webpagePhoto;
std::optional<MTPDocument> webpageDocument; std::optional<MTPDocument> webpageDocument;
QString name; QString name;
int updatedCachedViews = 0;
}; };
[[nodiscard]] Prepared Prepare(const Source &source, const Options &options); [[nodiscard]] Prepared Prepare(const Source &source, const Options &options);

View file

@ -403,6 +403,8 @@ bool Domain::removePasscodeIfEmpty() {
return false; return false;
} }
_local->setPasscode(QByteArray()); _local->setPasscode(QByteArray());
Core::App().settings().setSystemUnlockEnabled(false);
Core::App().saveSettingsDelayed();
return true; return true;
} }

View file

@ -1193,9 +1193,11 @@ void MainWidget::setInnerFocus() {
_mainSection->setInnerFocus(); _mainSection->setInnerFocus();
} else if (!_hider && _thirdSection) { } else if (!_hider && _thirdSection) {
_thirdSection->setInnerFocus(); _thirdSection->setInnerFocus();
} else { } else if (_dialogs) {
Assert(_dialogs != nullptr);
_dialogs->setInnerFocus(); _dialogs->setInnerFocus();
} else {
// Maybe we're just closing a child window, content is destroyed.
_history->setFocus();
} }
} else if (_mainSection) { } else if (_mainSection) {
_mainSection->setInnerFocus(); _mainSection->setInnerFocus();
@ -1294,8 +1296,9 @@ void MainWidget::showHistory(
} }
const auto unavailable = peer->computeUnavailableReason(); const auto unavailable = peer->computeUnavailableReason();
if (!unavailable.isEmpty()) { if (!unavailable.isEmpty()) {
Assert(isPrimary()); // windows todo if (!isPrimary()) {
if (params.activation != anim::activation::background) { _controller->window().close();
} else if (params.activation != anim::activation::background) {
_controller->show(Ui::MakeInformBox(unavailable)); _controller->show(Ui::MakeInformBox(unavailable));
_controller->window().activate(); _controller->window().activate();
} }
@ -1951,10 +1954,9 @@ void MainWidget::showNonPremiumLimitToast(bool download) {
}); });
} }
void MainWidget::showBackFromStack( bool MainWidget::showBackFromStack(const SectionShow &params) {
const SectionShow &params) {
if (preventsCloseSection([=] { showBackFromStack(params); }, params)) { if (preventsCloseSection([=] { showBackFromStack(params); }, params)) {
return; return false;
} }
if (_stack.empty()) { if (_stack.empty()) {
@ -1964,7 +1966,7 @@ void MainWidget::showBackFromStack(
crl::on_main(this, [=] { crl::on_main(this, [=] {
_controller->widget()->setInnerFocus(); _controller->widget()->setInnerFocus();
}); });
return; return (_dialogs != nullptr);
} }
auto item = std::move(_stack.back()); auto item = std::move(_stack.back());
_stack.pop_back(); _stack.pop_back();
@ -1996,6 +1998,7 @@ void MainWidget::showBackFromStack(
anim::activation::background)); anim::activation::background));
} }
return true;
} }
void MainWidget::orderWidgets() { void MainWidget::orderWidgets() {

View file

@ -152,8 +152,7 @@ public:
const SectionShow &params); const SectionShow &params);
void updateColumnLayout(); void updateColumnLayout();
bool stackIsEmpty() const; bool stackIsEmpty() const;
void showBackFromStack( bool showBackFromStack(const SectionShow &params);
const SectionShow &params);
void orderWidgets(); void orderWidgets();
QPixmap grabForShowAnimation(const Window::SectionSlideParams &params); QPixmap grabForShowAnimation(const Window::SectionSlideParams &params);
void checkMainSectionToLayer(); void checkMainSectionToLayer();

View file

@ -510,15 +510,15 @@ OverlayWidget::OverlayWidget()
return base::EventFilterResult::Cancel; return base::EventFilterResult::Cancel;
} }
} else if (e->type() == QEvent::WindowStateChange) { } else if (e->type() == QEvent::WindowStateChange) {
const auto state = _window->windowState(); const auto state = window()->windowState();
if (state & Qt::WindowMinimized || Platform::IsMac()) { if (state == Qt::WindowMinimized || Platform::IsMac()) {
} else if (state & Qt::WindowMaximized) { } else if (state == Qt::WindowMaximized) {
if (_fullscreen || _windowed) { if (_fullscreen || _windowed) {
_fullscreen = _windowed = false; _fullscreen = _windowed = false;
savePosition(); savePosition();
} }
} else if (_fullscreen || _windowed) { } else if (_fullscreen || _windowed) {
} else if (state & Qt::WindowFullScreen) { } else if (state == Qt::WindowFullScreen) {
_fullscreen = true; _fullscreen = true;
savePosition(); savePosition();
} else { } else {
@ -3856,16 +3856,12 @@ void OverlayWidget::updatePowerSaveBlocker(
&& !IsPausedOrPausing(state.state) && !IsPausedOrPausing(state.state)
&& !IsStoppedOrStopping(state.state); && !IsStoppedOrStopping(state.state);
_window->shownValue() | rpl::filter([=](bool shown) { base::UpdatePowerSaveBlocker(
return shown; _streamed->powerSaveBlocker,
}) | rpl::take(1) | rpl::start_with_next([=] { block,
base::UpdatePowerSaveBlocker( base::PowerSaveBlockType::PreventDisplaySleep,
_streamed->powerSaveBlocker, [] { return u"Video playback is active"_q; },
block, [=] { return _window->windowHandle(); });
base::PowerSaveBlockType::PreventDisplaySleep,
[] { return u"Video playback is active"_q; },
[=] { return window(); });
}, lifetime());
} }
QImage OverlayWidget::transformedShownContent() const { QImage OverlayWidget::transformedShownContent() const {

View file

@ -65,7 +65,7 @@ QByteArray DnsUserAgent() {
static const auto kResult = QByteArray( static const auto kResult = QByteArray(
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) " "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) " "AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/124.0.0.0 Safari/537.36"); "Chrome/126.0.0.0 Safari/537.36");
return kResult; return kResult;
} }

View file

@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#include "platform/linux/specific_linux.h" #include "platform/linux/specific_linux.h"
#include "base/openssl_help.h"
#include "base/random.h" #include "base/random.h"
#include "base/platform/base_platform_info.h" #include "base/platform/base_platform_info.h"
#include "base/platform/linux/base_linux_dbus_utilities.h" #include "base/platform/linux/base_linux_dbus_utilities.h"
@ -480,6 +481,16 @@ void InstallLauncher() {
}); });
} }
[[nodiscard]] QByteArray HashForSocketPath(const QByteArray &data) {
constexpr auto kHashForSocketPathLength = 24;
const auto binary = openssl::Sha256(bytes::make_span(data));
const auto base64 = QByteArray(
reinterpret_cast<const char*>(binary.data()),
binary.size()).toBase64(QByteArray::Base64UrlEncoding);
return base64.mid(0, kHashForSocketPathLength);
}
} // namespace } // namespace
namespace Platform { namespace Platform {
@ -686,8 +697,8 @@ void start() {
Webview::WebKitGTK::SetSocketPath(u"%1/%2-%3-webview-%4"_q.arg( Webview::WebKitGTK::SetSocketPath(u"%1/%2-%3-webview-%4"_q.arg(
QDir::tempPath(), QDir::tempPath(),
h, HashForSocketPath(d),
QCoreApplication::applicationName(), u"TD"_q,//QCoreApplication::applicationName(), - make path smaller.
u"%1"_q).toStdString()); u"%1"_q).toStdString());
InstallLauncher(); InstallLauncher();

View file

@ -280,10 +280,7 @@ void FillCreditOptions(
inner->paintRequest( inner->paintRequest(
) | rpl::start_with_next([=](const QRect &rect) { ) | rpl::start_with_next([=](const QRect &rect) {
auto p = QPainter(inner); auto p = QPainter(inner);
p.drawImage( p.drawImage(0, 0, stars);
0,
(buttonHeight - stars.height()) / 2,
stars);
const auto textLeft = diffBetweenTextAndStar const auto textLeft = diffBetweenTextAndStar
+ stars.width() / style::DevicePixelRatio(); + stars.width() / style::DevicePixelRatio();
p.setPen(st.textFg); p.setPen(st.textFg);

View file

@ -152,6 +152,7 @@ void SetupExperimental(
addToggle(kOptionAutoScrollInactiveChat); addToggle(kOptionAutoScrollInactiveChat);
addToggle(Window::Notifications::kOptionGNotification); addToggle(Window::Notifications::kOptionGNotification);
addToggle(Core::kOptionFreeType); addToggle(Core::kOptionFreeType);
addToggle(Core::kOptionSkipUrlSchemeRegister);
addToggle(Data::kOptionExternalVideoPlayer); addToggle(Data::kOptionExternalVideoPlayer);
addToggle(Window::kOptionNewWindowsSizeAsFirst); addToggle(Window::kOptionNewWindowsSizeAsFirst);
} }

View file

@ -80,6 +80,7 @@ private:
rpl::event_stream<> _setInnerFocus; rpl::event_stream<> _setInnerFocus;
rpl::event_stream<Type> _showOther; rpl::event_stream<Type> _showOther;
rpl::event_stream<> _showBack; rpl::event_stream<> _showBack;
bool _systemUnlockWithBiometric = false;
}; };
@ -97,6 +98,13 @@ rpl::producer<QString> LocalPasscodeEnter::title() {
void LocalPasscodeEnter::setupContent() { void LocalPasscodeEnter::setupContent() {
const auto content = Ui::CreateChild<Ui::VerticalLayout>(this); const auto content = Ui::CreateChild<Ui::VerticalLayout>(this);
base::SystemUnlockStatus(
true
) | rpl::start_with_next([=](base::SystemUnlockAvailability status) {
_systemUnlockWithBiometric = status.available
&& status.withBiometrics;
}, lifetime());
const auto isCreate = (enterType() == EnterType::Create); const auto isCreate = (enterType() == EnterType::Create);
const auto isCheck = (enterType() == EnterType::Check); const auto isCheck = (enterType() == EnterType::Check);
[[maybe_unused]] const auto isChange = (enterType() == EnterType::Change); [[maybe_unused]] const auto isChange = (enterType() == EnterType::Change);
@ -242,8 +250,10 @@ void LocalPasscodeEnter::setupContent() {
} }
SetPasscode(_controller, newText); SetPasscode(_controller, newText);
if (isCreate) { if (isCreate) {
Core::App().settings().setSystemUnlockEnabled(true); if (Platform::IsWindows() || _systemUnlockWithBiometric) {
Core::App().saveSettingsDelayed(); Core::App().settings().setSystemUnlockEnabled(true);
Core::App().saveSettingsDelayed();
}
_showOther.fire(LocalPasscodeManageId()); _showOther.fire(LocalPasscodeManageId());
} else if (isChange) { } else if (isChange) {
_showBack.fire({}); _showBack.fire({});
@ -518,38 +528,77 @@ void LocalPasscodeManage::setupContent() {
)->setDuration(0); )->setDuration(0);
const auto systemUnlockContent = systemUnlockWrap->entity(); const auto systemUnlockContent = systemUnlockWrap->entity();
Ui::AddSkip(systemUnlockContent); enum class UnlockType {
None,
Default,
Biometrics,
Companion,
};
const auto unlockType = systemUnlockContent->lifetime().make_state<
rpl::variable<UnlockType>
>(base::SystemUnlockStatus(
true
) | rpl::map([](base::SystemUnlockAvailability status) {
return status.withBiometrics
? UnlockType::Biometrics
: status.withCompanion
? UnlockType::Companion
: status.available
? UnlockType::Default
: UnlockType::None;
}));
unlockType->value(
) | rpl::start_with_next([=](UnlockType type) {
while (systemUnlockContent->count()) {
delete systemUnlockContent->widgetAt(0);
}
Ui::AddSkip(systemUnlockContent);
AddButtonWithIcon(
systemUnlockContent,
(Platform::IsWindows()
? tr::lng_settings_use_winhello()
: (type == UnlockType::Biometrics)
? tr::lng_settings_use_touchid()
: (type == UnlockType::Companion)
? tr::lng_settings_use_applewatch()
: tr::lng_settings_use_systempwd()),
st::settingsButton,
{ Platform::IsWindows()
? &st::menuIconWinHello
: (type == UnlockType::Biometrics)
? &st::menuIconTouchID
: (type == UnlockType::Companion)
? &st::menuIconAppleWatch
: &st::menuIconSystemPwd }
)->toggleOn(
rpl::single(Core::App().settings().systemUnlockEnabled())
)->toggledChanges(
) | rpl::filter([=](bool value) {
return value != Core::App().settings().systemUnlockEnabled();
}) | rpl::start_with_next([=](bool value) {
Core::App().settings().setSystemUnlockEnabled(value);
Core::App().saveSettingsDelayed();
}, systemUnlockContent->lifetime());
Ui::AddSkip(systemUnlockContent);
Ui::AddDividerText(
systemUnlockContent,
(Platform::IsWindows()
? tr::lng_settings_use_winhello_about()
: (type == UnlockType::Biometrics)
? tr::lng_settings_use_touchid_about()
: (type == UnlockType::Companion)
? tr::lng_settings_use_applewatch_about()
: tr::lng_settings_use_systempwd_about()));
AddButtonWithIcon(
systemUnlockContent,
(Platform::IsWindows()
? tr::lng_settings_use_winhello()
: tr::lng_settings_use_touchid()),
st::settingsButton,
{ Platform::IsWindows()
? &st::menuIconWinHello
: &st::menuIconTouchID }
)->toggleOn(
rpl::single(Core::App().settings().systemUnlockEnabled())
)->toggledChanges(
) | rpl::filter([=](bool value) {
return value != Core::App().settings().systemUnlockEnabled();
}) | rpl::start_with_next([=](bool value) {
Core::App().settings().setSystemUnlockEnabled(value);
Core::App().saveSettingsDelayed();
}, systemUnlockContent->lifetime()); }, systemUnlockContent->lifetime());
Ui::AddSkip(systemUnlockContent); systemUnlockWrap->toggleOn(unlockType->value(
) | rpl::map(rpl::mappers::_1 != UnlockType::None));
Ui::AddDividerText(
systemUnlockContent,
(Platform::IsWindows()
? tr::lng_settings_use_winhello_about()
: tr::lng_settings_use_touchid_about()));
using namespace rpl::mappers;
systemUnlockWrap->toggleOn(base::SystemUnlockStatus(
) | rpl::map(_1 == base::SystemUnlockAvailability::Available));
Ui::ResizeFitChild(this, content); Ui::ResizeFitChild(this, content);
} }
@ -562,6 +611,8 @@ QPointer<Ui::RpWidget> LocalPasscodeManage::createPinnedToBottom(
.text = tr::lng_settings_passcode_disable_sure(), .text = tr::lng_settings_passcode_disable_sure(),
.confirmed = [=](Fn<void()> &&close) { .confirmed = [=](Fn<void()> &&close) {
SetPasscode(_controller, QString()); SetPasscode(_controller, QString());
Core::App().settings().setSystemUnlockEnabled(false);
Core::App().saveSettingsDelayed();
close(); close();
_showBack.fire({}); _showBack.fire({});

View file

@ -157,6 +157,8 @@ menuIconFont: icon {{ "menu/fonts", menuIconColor }};
menuIconFactcheck: icon {{ "menu/factcheck", menuIconColor }}; menuIconFactcheck: icon {{ "menu/factcheck", menuIconColor }};
menuIconWinHello: icon {{ "menu/passcode_winhello", menuIconColor }}; menuIconWinHello: icon {{ "menu/passcode_winhello", menuIconColor }};
menuIconTouchID: icon {{ "menu/passcode_finger", menuIconColor }}; menuIconTouchID: icon {{ "menu/passcode_finger", menuIconColor }};
menuIconAppleWatch: icon {{ "menu/passcode_watch", menuIconColor }};
menuIconSystemPwd: menuIconPermissions;
menuIconTTLAny: icon {{ "menu/auto_delete_plain", menuIconColor }}; menuIconTTLAny: icon {{ "menu/auto_delete_plain", menuIconColor }};
menuIconTTLAnyTextPosition: point(11px, 22px); menuIconTTLAnyTextPosition: point(11px, 22px);

View file

@ -110,8 +110,17 @@ PasscodeLockWidget::PasscodeLockWidget(
using namespace rpl::mappers; using namespace rpl::mappers;
if (Core::App().settings().systemUnlockEnabled()) { if (Core::App().settings().systemUnlockEnabled()) {
_systemUnlockAvailable = base::SystemUnlockStatus() _systemUnlockAvailable = base::SystemUnlockStatus(
| rpl::map(_1 == base::SystemUnlockAvailability::Available); true
) | rpl::map([](base::SystemUnlockAvailability status) {
return status.withBiometrics
? SystemUnlockType::Biometrics
: status.withCompanion
? SystemUnlockType::Companion
: status.available
? SystemUnlockType::Default
: SystemUnlockType::None;
});
if (Core::App().domain().started()) { if (Core::App().domain().started()) {
_systemUnlockAllowed = _systemUnlockAvailable.value(); _systemUnlockAllowed = _systemUnlockAvailable.value();
setupSystemUnlock(); setupSystemUnlock();
@ -122,11 +131,22 @@ PasscodeLockWidget::PasscodeLockWidget(
} }
void PasscodeLockWidget::setupSystemUnlockInfo() { void PasscodeLockWidget::setupSystemUnlockInfo() {
const auto macos = [&] {
return _systemUnlockAvailable.value(
) | rpl::map([](SystemUnlockType type) {
return (type == SystemUnlockType::Biometrics)
? tr::lng_passcode_touchid()
: (type == SystemUnlockType::Companion)
? tr::lng_passcode_applewatch()
: tr::lng_passcode_systempwd();
}) | rpl::flatten_latest();
};
auto text = Platform::IsWindows()
? tr::lng_passcode_winhello()
: macos();
const auto info = Ui::CreateChild<Ui::FlatLabel>( const auto info = Ui::CreateChild<Ui::FlatLabel>(
this, this,
(Platform::IsWindows() std::move(text),
? tr::lng_passcode_winhello()
: tr::lng_passcode_touchid()),
st::passcodeSystemUnlockLater); st::passcodeSystemUnlockLater);
_logout->geometryValue( _logout->geometryValue(
) | rpl::start_with_next([=](QRect logout) { ) | rpl::start_with_next([=](QRect logout) {
@ -137,7 +157,8 @@ void PasscodeLockWidget::setupSystemUnlockInfo() {
st::boxRowPadding.left(), st::boxRowPadding.left(),
logout.y() + logout.height() + st::passcodeSystemUnlockSkip); logout.y() + logout.height() + st::passcodeSystemUnlockSkip);
}, info->lifetime()); }, info->lifetime());
info->showOn(_systemUnlockAvailable.value()); info->showOn(_systemUnlockAvailable.value(
) | rpl::map(rpl::mappers::_1 != SystemUnlockType::None));
} }
void PasscodeLockWidget::setupSystemUnlock() { void PasscodeLockWidget::setupSystemUnlock() {
@ -152,10 +173,21 @@ void PasscodeLockWidget::setupSystemUnlock() {
const auto button = Ui::CreateChild<Ui::IconButton>( const auto button = Ui::CreateChild<Ui::IconButton>(
_passcode.data(), _passcode.data(),
(Platform::IsWindows() st::passcodeSystemUnlock);
? st::passcodeSystemWinHello if (!Platform::IsWindows()) {
: st::passcodeSystemTouchID)); using namespace base;
button->showOn(_systemUnlockAllowed.value()); _systemUnlockAllowed.value(
) | rpl::start_with_next([=](SystemUnlockType type) {
const auto icon = (type == SystemUnlockType::Biometrics)
? &st::passcodeSystemTouchID
: (type == SystemUnlockType::Companion)
? &st::passcodeSystemAppleWatch
: &st::passcodeSystemSystemPwd;
button->setIconOverride(icon, icon);
}, button->lifetime());
}
button->showOn(_systemUnlockAllowed.value(
) | rpl::map(rpl::mappers::_1 != SystemUnlockType::None));
_passcode->sizeValue() | rpl::start_with_next([=](QSize size) { _passcode->sizeValue() | rpl::start_with_next([=](QSize size) {
button->moveToRight(0, size.height() - button->height()); button->moveToRight(0, size.height() - button->height());
}, button->lifetime()); }, button->lifetime());
@ -177,7 +209,7 @@ void PasscodeLockWidget::suggestSystemUnlock() {
using namespace base; using namespace base;
_systemUnlockAllowed.value( _systemUnlockAllowed.value(
) | rpl::filter( ) | rpl::filter(
rpl::mappers::_1 rpl::mappers::_1 != SystemUnlockType::None
) | rpl::take(1) | rpl::start_with_next([=] { ) | rpl::take(1) | rpl::start_with_next([=] {
const auto weak = Ui::MakeWeak(this); const auto weak = Ui::MakeWeak(this);
const auto done = [weak](SystemUnlockResult result) { const auto done = [weak](SystemUnlockResult result) {

View file

@ -65,6 +65,13 @@ protected:
void resizeEvent(QResizeEvent *e) override; void resizeEvent(QResizeEvent *e) override;
private: private:
enum class SystemUnlockType : uchar {
None,
Default,
Biometrics,
Companion,
};
void paintContent(QPainter &p) override; void paintContent(QPainter &p) override;
void setupSystemUnlockInfo(); void setupSystemUnlockInfo();
@ -75,8 +82,8 @@ private:
void submit(); void submit();
void error(); void error();
rpl::variable<bool> _systemUnlockAvailable = false; rpl::variable<SystemUnlockType> _systemUnlockAvailable;
rpl::variable<bool> _systemUnlockAllowed = false; rpl::variable<SystemUnlockType> _systemUnlockAllowed;
object_ptr<Ui::PasswordInput> _passcode; object_ptr<Ui::PasswordInput> _passcode;
object_ptr<Ui::RoundButton> _submit; object_ptr<Ui::RoundButton> _submit;
object_ptr<Ui::LinkButton> _logout; object_ptr<Ui::LinkButton> _logout;

View file

@ -67,7 +67,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "info/info_controller.h" #include "info/info_controller.h"
#include "info/info_memento.h" #include "info/info_memento.h"
#include "info/channel_statistics/boosts/info_boosts_widget.h" #include "info/channel_statistics/boosts/info_boosts_widget.h"
#include "info/channel_statistics/earn/info_earn_widget.h" #include "info/channel_statistics/earn/info_channel_earn_widget.h"
#include "info/profile/info_profile_values.h" #include "info/profile/info_profile_values.h"
#include "info/statistics/info_statistics_widget.h" #include "info/statistics/info_statistics_widget.h"
#include "info/stories/info_stories_widget.h" #include "info/stories/info_stories_widget.h"
@ -694,8 +694,9 @@ void Filler::addNewWindow() {
_addAction(tr::lng_context_new_window(tr::now), [=] { _addAction(tr::lng_context_new_window(tr::now), [=] {
Ui::PreventDelayedActivation(); Ui::PreventDelayedActivation();
if (const auto strong = weak.get()) { if (const auto strong = weak.get()) {
const auto forum = !strong->asTopic() && peer->isForum();
controller->showInNewWindow(SeparateId( controller->showInNewWindow(SeparateId(
peer->isForum() ? SeparateType::Forum : SeparateType::Chat, forum ? SeparateType::Forum : SeparateType::Chat,
strong)); strong));
} }
}, &st::menuIconNewWindow); }, &st::menuIconNewWindow);

View file

@ -17,7 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "window/window_controller.h" #include "window/window_controller.h"
#include "window/window_filters_menu.h" #include "window/window_filters_menu.h"
#include "window/window_separate_id.h" #include "window/window_separate_id.h"
#include "info/channel_statistics/earn/info_earn_inner_widget.h" #include "info/channel_statistics/earn/info_channel_earn_list.h"
#include "info/info_memento.h" #include "info/info_memento.h"
#include "info/info_controller.h" #include "info/info_controller.h"
#include "inline_bots/bot_attach_web_view.h" #include "inline_bots/bot_attach_web_view.h"
@ -1668,8 +1668,9 @@ void SessionController::showForum(
) | rpl::start_with_next([=, history = forum->history()] { ) | rpl::start_with_next([=, history = forum->history()] {
const auto now = activeChatCurrent().owningHistory(); const auto now = activeChatCurrent().owningHistory();
const auto showHistory = !now || (now == history); const auto showHistory = !now || (now == history);
const auto weak = base::make_weak(this);
closeForum(); closeForum();
if (showHistory) { if (weak && showHistory) {
showPeerHistory(history, { showPeerHistory(history, {
SectionShow::Way::Backward, SectionShow::Way::Backward,
anim::type::normal, anim::type::normal,
@ -1684,7 +1685,7 @@ void SessionController::closeForum() {
if (const auto forum = _shownForum.current()) { if (const auto forum = _shownForum.current()) {
const auto id = windowId(); const auto id = windowId();
if (id.type == SeparateType::Forum) { if (id.type == SeparateType::Forum) {
const auto initial = id.thread->asForum(); const auto initial = id.forum();
if (!initial || initial == forum) { if (!initial || initial == forum) {
Core::App().closeWindow(_window); Core::App().closeWindow(_window);
} else { } else {
@ -2537,7 +2538,13 @@ void SessionController::showBackFromStack(const SectionShow &params) {
return topic && topic->forum()->topicDeleted(topic->rootId()); return topic && topic->forum()->topicDeleted(topic->rootId());
}; };
do { do {
content()->showBackFromStack(params); const auto empty = content()->stackIsEmpty();
const auto shown = content()->showBackFromStack(params);
if (empty && !shown && content()->stackIsEmpty() && bad()) {
clearSectionStack(anim::type::instant);
window().close();
break;
}
} while (bad()); } while (bad());
} }

View file

@ -1,7 +1,7 @@
AppVersion 5002000 AppVersion 5002002
AppVersionStrMajor 5.2 AppVersionStrMajor 5.2
AppVersionStrSmall 5.2 AppVersionStrSmall 5.2.2
AppVersionStr 5.2.0 AppVersionStr 5.2.2
BetaChannel 0 BetaChannel 0
AlphaVersion 0 AlphaVersion 0
AppVersionOriginal 5.2 AppVersionOriginal 5.2.2

@ -1 +1 @@
Subproject commit b512eead302cb7b509869778348d60fef64bc19b Subproject commit f30400147d997fedc787e214467d305db6c159e7

@ -1 +1 @@
Subproject commit 59d92261783ae403e8708f972c36be3d21ab064d Subproject commit 0b7622ff38778e9cd03d3997de59351973480a1f

View file

@ -1,3 +1,16 @@
5.2.2 (02.07.24)
- Fix topics search in topic groups.
- Fix Instant View pages content updating.
5.2.1 (01.07.24)
- Fix crash when opening topic in a new window.
- Fix crash in topic search scope dropdown.
- Fix crash in video player.
- Fix feeze and crash in Instant View (Windows).
- Allow unlock by Apple Watch or System Password (macOS).
5.2 (30.06.24) 5.2 (30.06.24)
- Pay for content with Telegram Stars. - Pay for content with Telegram Stars.