diff --git a/AGENTS.md b/AGENTS.md index 3694a358a1..9fffd0a059 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -287,6 +287,8 @@ auto margin = st::myWidgetMargin; auto iconSize = st::myWidgetIconSize; ``` +**Duration constants**: Animation durations should NOT go in `.style` files, this is a legacy approach. Prefer `constexpr auto kName = crl::time(N)` in an anonymous namespace in the relevant `.cpp` file. + ### Usage in Code ```cpp diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index d9bff69e54..66847c81b5 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -255,7 +255,9 @@ set(ayugram_files info/profile/info_profile_music_button.h ) -telegram_add_apple_swift_runtime(Telegram) +if (NOT DESKTOP_APP_DISABLE_SWIFT6) + telegram_add_apple_swift_runtime(Telegram) +endif() target_precompile_headers(Telegram PRIVATE $<$:${src_loc}/stdafx.h>) nice_target_sources(Telegram ${src_loc} diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index a5e1e55341..7d9b0b0e7f 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -324,10 +324,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_sure_enable_socks" = "Are you sure you want to enable this proxy?\n\nServer: {server}\nPort: {port}\n\nYou can change your proxy server later in Settings > Advanced > Connection Type."; "lng_sure_enable" = "Enable"; "lng_proxy_box_title" = "Enable proxy"; +"lng_proxy_box_table_title" = "Proxy Server"; +"lng_proxy_box_table_button" = "Connect Proxy"; +"lng_proxy_box_table_checking" = "Checking…"; +"lng_proxy_box_table_available" = "Available (ping: {ping} ms)"; +"lng_proxy_box_table_unavailable" = "Not Available"; "lng_proxy_box_server" = "Server"; "lng_proxy_box_port" = "Port"; "lng_proxy_box_secret" = "Secret"; "lng_proxy_box_status" = "Status"; +"lng_proxy_box_check_status" = "Check Status"; "lng_proxy_box_username" = "Username"; "lng_proxy_box_password" = "Password"; "lng_proxy_invalid" = "The proxy link is invalid."; @@ -1597,6 +1603,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_profile_saved_messages#other" = "{count} saved messages"; "lng_profile_peer_gifts#one" = "{count} gift"; "lng_profile_peer_gifts#other" = "{count} gifts"; +"lng_profile_unofficial_warning" = "{icon} {name} uses an unofficial Telegram client — messages to this user may be less secure."; "lng_profile_participants_section" = "Members"; "lng_profile_subscribers_section" = "Subscribers"; "lng_profile_add_contact" = "Add Contact"; diff --git a/Telegram/Resources/uwp/AppX/AppxManifest.xml b/Telegram/Resources/uwp/AppX/AppxManifest.xml index d425fabc4d..b39491fa45 100644 --- a/Telegram/Resources/uwp/AppX/AppxManifest.xml +++ b/Telegram/Resources/uwp/AppX/AppxManifest.xml @@ -10,7 +10,7 @@ + Version="6.7.4.0" /> Telegram Desktop Telegram Messenger LLP diff --git a/Telegram/Resources/winrc/Telegram.rc b/Telegram/Resources/winrc/Telegram.rc index 31cd25a03c..daf7047b67 100644 --- a/Telegram/Resources/winrc/Telegram.rc +++ b/Telegram/Resources/winrc/Telegram.rc @@ -44,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 6,7,2,0 - PRODUCTVERSION 6,7,2,0 + FILEVERSION 6,7,4,0 + PRODUCTVERSION 6,7,4,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -62,10 +62,10 @@ BEGIN BEGIN VALUE "CompanyName", "Radolyn Labs" VALUE "FileDescription", "AyuGram Desktop" - VALUE "FileVersion", "6.7.2.0" + VALUE "FileVersion", "6.7.4.0" VALUE "LegalCopyright", "Copyright (C) 2014-2026" VALUE "ProductName", "AyuGram Desktop" - VALUE "ProductVersion", "6.7.2.0" + VALUE "ProductVersion", "6.7.4.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/Resources/winrc/Updater.rc b/Telegram/Resources/winrc/Updater.rc index 8166d6507b..9df16f35e5 100644 --- a/Telegram/Resources/winrc/Updater.rc +++ b/Telegram/Resources/winrc/Updater.rc @@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US // VS_VERSION_INFO VERSIONINFO - FILEVERSION 6,7,2,0 - PRODUCTVERSION 6,7,2,0 + FILEVERSION 6,7,4,0 + PRODUCTVERSION 6,7,4,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -53,10 +53,10 @@ BEGIN BEGIN VALUE "CompanyName", "Radolyn Labs" VALUE "FileDescription", "AyuGram Desktop Updater" - VALUE "FileVersion", "6.7.2.0" + VALUE "FileVersion", "6.7.4.0" VALUE "LegalCopyright", "Copyright (C) 2014-2026" VALUE "ProductName", "AyuGram Desktop" - VALUE "ProductVersion", "6.7.2.0" + VALUE "ProductVersion", "6.7.4.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/SourceFiles/api/api_transcribes.cpp b/Telegram/SourceFiles/api/api_transcribes.cpp index bc31e1b998..7c6b271ca5 100644 --- a/Telegram/SourceFiles/api/api_transcribes.cpp +++ b/Telegram/SourceFiles/api/api_transcribes.cpp @@ -116,19 +116,14 @@ void Transcribes::toggle(not_null item) { } } -void Transcribes::toggleSummary( - not_null item, - Fn onPremiumRequired) { +void Transcribes::toggleSummary(not_null item) { const auto id = item->fullId(); auto i = _summaries.find(id); if (i == _summaries.end()) { - auto &entry = _summaries.emplace(id).first->second; - entry.onPremiumRequired = std::move(onPremiumRequired); summarize(item); } else if (!i->second.loading) { auto &entry = i->second; if (entry.result.empty()) { - entry.onPremiumRequired = std::move(onPremiumRequired); summarize(item); } else { entry.shown = entry.premiumRequired ? false : !entry.shown; @@ -265,7 +260,6 @@ void Transcribes::summarize(not_null item) { entry.requestId = 0; entry.loading = false; entry.premiumRequired = false; - entry.onPremiumRequired = nullptr; entry.languageId = translatedTo; entry.result = TextWithEntities( qs(data.vtext()), @@ -277,15 +271,11 @@ void Transcribes::summarize(not_null item) { }).fail([=](const MTP::Error &error) { auto &entry = _summaries[id]; if (error.type() == u"SUMMARY_FLOOD_PREMIUM"_q) { - if (!entry.premiumRequired && entry.onPremiumRequired) { - entry.onPremiumRequired(); - } entry.premiumRequired = true; } entry.requestId = 0; entry.shown = false; entry.loading = false; - entry.onPremiumRequired = nullptr; if (const auto item = _session->data().message(id)) { _session->data().requestItemTextRefresh(item); } diff --git a/Telegram/SourceFiles/api/api_transcribes.h b/Telegram/SourceFiles/api/api_transcribes.h index eb248e7cc5..7eef8a4fb6 100644 --- a/Telegram/SourceFiles/api/api_transcribes.h +++ b/Telegram/SourceFiles/api/api_transcribes.h @@ -19,7 +19,6 @@ class Session; namespace Api { struct SummaryEntry { - Fn onPremiumRequired = nullptr; TextWithEntities result; LanguageId languageId; bool shown = false; @@ -45,9 +44,7 @@ public: void toggle(not_null item); [[nodiscard]] const Entry &entry(not_null item) const; - void toggleSummary( - not_null item, - Fn onPremiumRequired); + void toggleSummary(not_null item); [[nodiscard]] const SummaryEntry &summary( not_null item) const; void checkSummaryToTranslate(FullMsgId id); diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index d0b3bd656c..855cacec6d 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -2623,7 +2623,15 @@ void ApiWrap::refreshFileReference( fail(); } }, [&](Data::FileOriginPeerPhoto data) { - fail(); + const auto peer = _session->data().peer(data.peerId); + if (const auto channel = peer->asChannel()) { + request(MTPchannels_GetFullChannel( + channel->inputChannel())); + } else if (const auto chat = peer->asChat()) { + request(MTPmessages_GetFullChat(chat->inputChat())); + } else { + fail(); + } }, [&](Data::FileOriginStickerSet data) { const auto isRecentAttached = (data.setId == Data::Stickers::CloudRecentAttachedSetId); diff --git a/Telegram/SourceFiles/boxes/about_box.cpp b/Telegram/SourceFiles/boxes/about_box.cpp index ff63e2a502..976f18d283 100644 --- a/Telegram/SourceFiles/boxes/about_box.cpp +++ b/Telegram/SourceFiles/boxes/about_box.cpp @@ -254,8 +254,6 @@ void ArchiveHintBox( box, tr::lng_archive_hint_button(), st::defaultActiveButton); - button->setTextTransform( - Ui::RoundButton::TextTransform::NoTransform); button->resizeToWidth(box->width() - st.buttonPadding.left() - st.buttonPadding.left()); diff --git a/Telegram/SourceFiles/boxes/about_sponsored_box.cpp b/Telegram/SourceFiles/boxes/about_sponsored_box.cpp index f377c34782..e4af2b8a1a 100644 --- a/Telegram/SourceFiles/boxes/about_sponsored_box.cpp +++ b/Telegram/SourceFiles/boxes/about_sponsored_box.cpp @@ -38,7 +38,6 @@ void AboutSponsoredBox(not_null box) { st); button->setBrushOverride(Qt::NoBrush); button->setPenOverride(QPen(st::historyLinkInFg)); - button->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); rpl::combine( row->sizeValue(), button->sizeValue() diff --git a/Telegram/SourceFiles/boxes/background_preview_box.cpp b/Telegram/SourceFiles/boxes/background_preview_box.cpp index 24cd9b852b..dd07ffd5e7 100644 --- a/Telegram/SourceFiles/boxes/background_preview_box.cpp +++ b/Telegram/SourceFiles/boxes/background_preview_box.cpp @@ -792,10 +792,6 @@ void BackgroundPreviewBox::applyForPeer() { }), raw->lifetime()); raw->toggle(false, anim::type::normal); }); - forMe->setTextTransform(RoundButton::TextTransform::NoTransform); - forBoth->setTextTransform(RoundButton::TextTransform::NoTransform); - cancel->setTextTransform(RoundButton::TextTransform::NoTransform); - overlay->sizeValue( ) | rpl::on_next([=](QSize size) { const auto padding = st::backgroundConfirmPadding; diff --git a/Telegram/SourceFiles/boxes/boxes.style b/Telegram/SourceFiles/boxes/boxes.style index 8829b76322..56d0f48529 100644 --- a/Telegram/SourceFiles/boxes/boxes.style +++ b/Telegram/SourceFiles/boxes/boxes.style @@ -669,6 +669,41 @@ proxyAboutSponsorPadding: margins(22px, 7px, 22px, 0px); proxyApplyBoxLabel : FlatLabel(defaultFlatLabel) { maxHeight: 30px; } +proxyApplyBoxTable: Table(defaultTable) { + labelMinWidth: 91px; +} +proxyApplyBoxTableMargin: margins(24px, 4px, 24px, 4px); +proxyApplyBoxTableLabelMargin: margins(13px, 10px, 13px, 10px); +proxyApplyBoxTableValueMargin: margins(13px, 9px, 13px, 9px); +proxyApplyBoxValueMultiline: FlatLabel(defaultTableValue) { + minWidth: 128px; + maxHeight: 100px; + style: TextStyle(defaultTextStyle) { + font: font(10px); + linkUnderline: kLinkUnderlineNever; + } +} +proxyApplyBoxSponsorLabel: FlatLabel(defaultFlatLabel) { + textFg: windowBoldFg; + minWidth: 100px; + align: align(top); + style: TextStyle(defaultTextStyle) { + font: font(11px); + } +} +proxyApplyBoxSponsorMargin: margins(13px, 8px, 13px, 8px); +proxyApplyBoxButton: RoundButton(defaultActiveButton) { + height: 38px; + textTop: 10px; + style: semiboldTextStyle; +} +proxyApplyBox: Box(defaultBox) { + buttonPadding: margins(22px, 11px, 22px, 22px); + buttonHeight: 38px; + buttonWide: true; + button: proxyApplyBoxButton; + shadowIgnoreTopSkip: true; +} markdownLinkFieldPadding: margins(22px, 0px, 22px, 10px); @@ -1294,3 +1329,11 @@ aiComposeBoxWithSend: Box(aiComposeBox) { buttonPadding: margins(16px, 12px, 66px, 12px); } aiComposeSendButtonSkip: 8px; +aiComposeBoxClose: IconButton(boxTitleClose) { + ripple: defaultRippleAnimation; +} +aiComposeBoxInfoButton: IconButton(boxTitleClose) { + icon: icon {{ "menu/info", boxTitleCloseFg }}; + iconOver: icon {{ "menu/info", boxTitleCloseFgOver }}; + ripple: defaultRippleAnimation; +} diff --git a/Telegram/SourceFiles/boxes/compose_ai_box.cpp b/Telegram/SourceFiles/boxes/compose_ai_box.cpp index 2fb272151a..8b20695ee0 100644 --- a/Telegram/SourceFiles/boxes/compose_ai_box.cpp +++ b/Telegram/SourceFiles/boxes/compose_ai_box.cpp @@ -26,6 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "main/main_session.h" #include "settings/sections/settings_premium.h" #include "spellcheck/platform/platform_language.h" +#include "ui/boxes/about_cocoon_box.h" #include "ui/boxes/choose_language_box.h" #include "ui/chat/chat_style.h" #include "ui/controls/labeled_emoji_tabs.h" @@ -386,6 +387,7 @@ private: void updatePinnedTabs(anim::type animated); void cancelRequest(); void request(); + void resetState(CardState state); void applyResult(Api::ComposeWithAi::Result &&result); void showError(const QString &error = {}); void notifyLoadingChanged(); @@ -1127,8 +1129,12 @@ void ComposeAiContent::updateTitles() { ? ToTitle(_to, currentTranslateStyleLabel()) : tr::lng_ai_compose_result(tr::now, tr::marked)) : tr::lng_ai_compose_original(tr::now, tr::marked)); + const auto emojifyOnlyMode = !hasResult + && (_mode == ComposeAiMode::Style) + && (_styleIndex < 0); _preview->setEmojifyVisible( - hasResult && (_mode != ComposeAiMode::Fix)); + (hasResult && (_mode != ComposeAiMode::Fix)) + || emojifyOnlyMode); _preview->setEmojifyChecked(_emojify); } @@ -1154,15 +1160,13 @@ void ComposeAiContent::cancelRequest() { void ComposeAiContent::request() { cancelRequest(); - if (_mode == ComposeAiMode::Style && _styleIndex < 0) { + if (_mode == ComposeAiMode::Style && _styleIndex < 0 && !_emojify) { + if (_state != CardState::Waiting) { + resetState(CardState::Waiting); + } return; } - _state = CardState::Loading; - _result = {}; - _preview->setState(CardState::Loading); - notifyLoadingChanged(); - updateTitles(); - notifyReadyChanged(); + resetState(CardState::Loading); auto request = Api::ComposeWithAi::Request{ .text = _original, @@ -1174,7 +1178,9 @@ void ComposeAiContent::request() { request.changeTone = currentTranslateStyle(); break; case ComposeAiMode::Style: - request.changeTone = _stylesData[_styleIndex].id; + if (_styleIndex >= 0) { + request.changeTone = _stylesData[_styleIndex].id; + } break; case ComposeAiMode::Fix: request.proofread = true; @@ -1201,6 +1207,15 @@ void ComposeAiContent::request() { }); } +void ComposeAiContent::resetState(CardState state) { + _state = state; + _result = {}; + _preview->setState(state); + notifyLoadingChanged(); + updateTitles(); + notifyReadyChanged(); +} + void ComposeAiContent::applyResult(Api::ComposeWithAi::Result &&result) { _result = std::move(result.resultText); if (_result.text.isEmpty()) { @@ -1397,9 +1412,12 @@ void ComposeAiBox(not_null box, ComposeAiBoxArgs &&args) { box->setNoContentMargin(true); box->setWidth(st::boxWideWidth); const auto session = args.session; - box->addTopButton(st::boxTitleClose, [=] { + box->addTopButton(st::aiComposeBoxClose, [=] { box->closeBox(); }); + box->addTopButton(st::aiComposeBoxInfoButton, [=] { + box->uiShow()->show(Box(Ui::AboutCocoonBox)); + }); const auto body = box->verticalLayout(); const auto tabsSkip = QMargins(0, 0, 0, st::aiComposeBoxStyleTabsSkip); @@ -1493,9 +1511,12 @@ void ComposeAiBox(not_null box, ComposeAiBoxArgs &&args) { } *sendButton = nullptr; box->clearButtons(); - box->addTopButton(st::boxTitleClose, [=] { + box->addTopButton(st::aiComposeBoxClose, [=] { box->closeBox(); }); + box->addTopButton(st::aiComposeBoxInfoButton, [=] { + box->uiShow()->show(Box(Ui::AboutCocoonBox)); + }); if (*premiumFlooded) { auto helper = Ui::Text::CustomEmojiHelper(); @@ -1525,7 +1546,8 @@ void ComposeAiBox(not_null box, ComposeAiBoxArgs &&args) { close(); }); } else if (content->mode() == ComposeAiMode::Style - && !content->hasStyleSelection()) { + && !content->hasStyleSelection() + && !content->hasResult()) { const auto btn = addApplyButton( *boxStyleNoSend, tr::lng_ai_compose_select_style(), nullptr); diff --git a/Telegram/SourceFiles/boxes/connection_box.cpp b/Telegram/SourceFiles/boxes/connection_box.cpp index b687c074e7..1bdb77d824 100644 --- a/Telegram/SourceFiles/boxes/connection_box.cpp +++ b/Telegram/SourceFiles/boxes/connection_box.cpp @@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/call_delayed.h" #include "base/qthelp_regex.h" #include "base/qthelp_url.h" +#include "base/weak_ptr.h" #include "core/application.h" #include "core/core_settings.h" #include "core/local_url_handlers.h" @@ -39,6 +40,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/widgets/menu/menu_add_action_callback_factory.h" #include "ui/widgets/popup_menu.h" #include "ui/wrap/slide_wrap.h" +#include "ui/wrap/table_layout.h" #include "ui/wrap/vertical_layout.h" #include "ui/vertical_list.h" #include "ui/ui_utility.h" @@ -74,7 +76,7 @@ using ProxyData = MTP::ProxyData; [[nodiscard]] QString ProxyDataToString(const ProxyData &proxy) { using Type = ProxyData::Type; - return u"https://t.me/"_q + return u"tg://"_q + (proxy.type == Type::Socks5 ? "socks" : "proxy") + "?server=" + proxy.host + "&port=" + QString::number(proxy.port) + ((proxy.type == Type::Socks5 && !proxy.user.isEmpty()) @@ -151,9 +153,13 @@ void AddProxyFromClipboard( const auto type = isSocks ? ProxyData::Type::Socks5 : ProxyData::Type::Mtproto; - const auto fields = url_parse_params( + auto fields = url_parse_params( match->captured(1), qthelp::UrlParamNameTransform::ToLower); + if (type == ProxyData::Type::Mtproto) { + auto &secret = fields[u"secret"_q]; + secret.replace('+', '-').replace('/', '_'); + } const auto proxy = ProxyDataFromFields(type, fields); if (!proxy) { const auto status = proxy.status(); @@ -1352,6 +1358,97 @@ void ProxyBox::addLabel( st::proxyEditTitlePadding); } +using Connection = MTP::details::AbstractConnection; +using Checker = MTP::details::ConnectionPointer; + +void ResetProxyCheckers(Checker &v4, Checker &v6) { + v4 = nullptr; + v6 = nullptr; +} + +void DropProxyChecker(Checker &v4, Checker &v6, not_null raw) { + if (v4.get() == raw) { + v4 = nullptr; + } else if (v6.get() == raw) { + v6 = nullptr; + } +} + +[[nodiscard]] bool HasProxyCheckers(const Checker &v4, const Checker &v6) { + return v4 || v6; +} + +void StartProxyCheck( + not_null mtproto, + const ProxyData &proxy, + Checker &v4, + Checker &v6, + Fn done, + Fn fail) { + using Variants = MTP::DcOptions::Variants; + + ResetProxyCheckers(v4, v6); + const auto connType = (proxy.type == ProxyData::Type::Http) + ? Variants::Http + : Variants::Tcp; + const auto dcId = mtproto->mainDcId(); + const auto setup = [&](Checker &checker, const bytes::vector &secret) { + checker = Connection::Create( + mtproto, + connType, + QThread::currentThread(), + secret, + proxy); + const auto raw = checker.get(); + raw->connect(raw, &Connection::connected, [=] { + if (done) { + done(raw, raw->pingTime()); + } + }); + const auto failed = [=] { + if (fail) { + fail(raw); + } + }; + raw->connect(raw, &Connection::disconnected, failed); + raw->connect(raw, &Connection::error, failed); + }; + if (proxy.type == ProxyData::Type::Mtproto) { + const auto secret = proxy.secretFromMtprotoPassword(); + setup(v4, secret); + v4->connectToServer( + proxy.host, + proxy.port, + secret, + dcId, + false); + return; + } + const auto options = mtproto->dcOptions().lookup( + dcId, + MTP::DcType::Regular, + true); + const auto tryConnect = [&](Checker &checker, Variants::Address address) { + const auto &list = options.data[address][connType]; + if (list.empty() + || ((address == Variants::IPv6) + && !Core::App().settings().proxy().tryIPv6())) { + checker = nullptr; + return; + } + const auto &endpoint = list.front(); + setup(checker, endpoint.secret); + checker->connectToServer( + QString::fromStdString(endpoint.ip), + endpoint.port, + endpoint.secret, + dcId, + false); + }; + tryConnect(v4, Variants::IPv4); + tryConnect(v6, Variants::IPv6); +} + } // namespace ProxiesBoxController::ProxiesBoxController(not_null account) @@ -1416,53 +1513,177 @@ void ProxiesBoxController::ShowApplyConfirmation( QString() ).replace(UrlEndRegExp, QString()); const auto box = [=](not_null box) { - box->setTitle(tr::lng_proxy_box_title()); - if (type == Type::Mtproto) { - box->addRow(object_ptr( + box->setTitle(tr::lng_proxy_box_table_title()); + box->setStyle(st::proxyApplyBox); + box->addTopButton(st::boxTitleClose, [=] { + box->closeBox(); + }); + + const auto table = box->addRow( + object_ptr( box, - tr::lng_proxy_sponsor_warning(), - st::boxDividerLabel)); - Ui::AddSkip(box->verticalLayout()); - Ui::AddSkip(box->verticalLayout()); - } - const auto &stL = st::proxyApplyBoxLabel; - const auto &stSubL = st::boxDividerLabel; - const auto add = [&](const QString &s, tr::phrase<> phrase) { - if (!s.isEmpty()) { - box->addRow(object_ptr(box, s, stL)); - box->addRow(object_ptr(box, phrase(), stSubL)); - Ui::AddSkip(box->verticalLayout()); - Ui::AddSkip(box->verticalLayout()); + st::proxyApplyBoxTable), + st::proxyApplyBoxTableMargin); + const auto addRow = [&]( + rpl::producer label, + object_ptr value) { + table->addRow( + object_ptr( + table, + std::move(label), + table->st().defaultLabel), + std::move(value), + st::proxyApplyBoxTableLabelMargin, + st::proxyApplyBoxTableValueMargin); + }; + const auto add = [&]( + const QString &value, + rpl::producer label) { + if (!value.isEmpty()) { + constexpr auto kOneLineCount = 20; + const auto oneLine = value.length() <= kOneLineCount; + auto widget = object_ptr( + table, + rpl::single(Ui::Text::Wrapped( + { value }, + EntityType::Code, + {})), + (oneLine + ? table->st().defaultValue + : st::proxyApplyBoxValueMultiline), + st::defaultPopupMenu); + addRow(std::move(label), std::move(widget)); } }; if (!displayServer.isEmpty()) { - add(displayServer, tr::lng_proxy_box_server); + add(displayServer, tr::lng_proxy_box_server()); } - add(QString::number(proxy.port), tr::lng_proxy_box_port); + add(QString::number(proxy.port), tr::lng_proxy_box_port()); if (type == Type::Socks5) { - add(proxy.user, tr::lng_proxy_box_username); - add(proxy.password, tr::lng_proxy_box_password); + add(proxy.user, tr::lng_proxy_box_username()); + add(proxy.password, tr::lng_proxy_box_password()); } else if (type == Type::Mtproto) { - add(proxy.password, tr::lng_proxy_box_secret); + add(proxy.password, tr::lng_proxy_box_secret()); } - const auto enableButton = box->addButton(tr::lng_sure_enable(), [=] { - auto &proxies = Core::App().settings().proxy().list(); - if (!ranges::contains(proxies, proxy)) { - proxies.push_back(proxy); - } - Core::App().setCurrentProxy(proxy, ProxyData::Settings::Enabled); - Local::writeSettings(); - box->closeBox(); - }); - box->addButton(tr::lng_cancel(), [=] { box->closeBox(); }); - box->events( - ) | rpl::on_next([=](not_null e) { + + { + struct ProxyCheckStatusState { + Checker v4; + Checker v6; + rpl::variable statusValue; + bool finished = false; + }; + const auto state + = box->lifetime().make_state(); + state->statusValue = Ui::Text::Link( + tr::lng_proxy_box_check_status(tr::now)); + const auto weak = base::make_weak(box); + auto statusWidget = object_ptr( + table, + state->statusValue.value(), + table->st().defaultValue, + st::defaultPopupMenu); + const auto statusLabel = statusWidget.data(); + addRow(tr::lng_proxy_box_status(), std::move(statusWidget)); + const auto relayout = [=] { + table->resizeToWidth(table->width()); + }; + const auto setUnavailable = [=] { + state->statusValue = TextWithEntities{ + tr::lng_proxy_box_table_unavailable(tr::now), + }; + statusLabel->setTextColorOverride( + st::proxyRowStatusFgOffline->c); + relayout(); + }; + const auto runCheck = [=] { + if (!weak) { + return; + } + const auto account = controller + ? &controller->session().account() + : &Core::App().activeAccount(); + state->finished = false; + state->statusValue = TextWithEntities{ + tr::lng_proxy_box_table_checking(tr::now), + }; + statusLabel->setTextColorOverride(st::proxyRowStatusFg->c); + relayout(); + StartProxyCheck( + &account->mtp(), + proxy, + state->v4, + state->v6, + [=](Connection *raw, int ping) { + if (!weak || state->finished) { + return; + } + DropProxyChecker(state->v4, state->v6, raw); + state->finished = true; + ResetProxyCheckers(state->v4, state->v6); + state->statusValue = TextWithEntities{ + tr::lng_proxy_box_table_available( + tr::now, + lt_ping, + QString::number(ping)), + }; + statusLabel->setTextColorOverride( + st::proxyRowStatusFgAvailable->c); + relayout(); + }, + [=](Connection *raw) { + if (!weak || state->finished) { + return; + } + DropProxyChecker(state->v4, state->v6, raw); + if (!HasProxyCheckers(state->v4, state->v6)) { + state->finished = true; + setUnavailable(); + } + }); + if (!HasProxyCheckers(state->v4, state->v6)) { + state->finished = true; + setUnavailable(); + } + }; + statusLabel->setClickHandlerFilter([=](const auto &...) { + runCheck(); + return false; + }); + } + + if (type == Type::Mtproto) { + table->addRow( + object_ptr( + table, + tr::lng_proxy_sponsor_warning(), + st::proxyApplyBoxSponsorLabel), + object_ptr(nullptr), + st::proxyApplyBoxSponsorMargin, + st::proxyApplyBoxSponsorMargin); + } + + const auto enableButton = box->addButton( + tr::lng_proxy_box_table_button(), + [=] { + auto &proxies = Core::App().settings().proxy().list(); + if (!ranges::contains(proxies, proxy)) { + proxies.push_back(proxy); + } + Core::App().setCurrentProxy( + proxy, + ProxyData::Settings::Enabled); + Local::writeSettings(); + box->closeBox(); + }); + enableButton->setFullRadius(true); + box->events() | rpl::on_next([=](not_null e) { if ((e->type() != QEvent::KeyPress) || !enableButton) { return; } const auto k = static_cast(e.get()); if (k->key() == Qt::Key_Enter || k->key() == Qt::Key_Return) { - enableButton->clicked(Qt::KeyboardModifiers(), Qt::LeftButton); + enableButton->clicked({}, Qt::LeftButton); } }, box->lifetime()); }; @@ -1481,98 +1702,49 @@ auto ProxiesBoxController::proxySettingsValue() const } void ProxiesBoxController::refreshChecker(Item &item) { - using Variants = MTP::DcOptions::Variants; - const auto type = (item.data.type == Type::Http) - ? Variants::Http - : 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) { - checker = MTP::details::AbstractConnection::Create( - mtproto, - type, - QThread::currentThread(), - secret, - item.data); - setupChecker(item.id, checker); - }; - if (item.data.type == Type::Mtproto) { - const auto secret = item.data.secretFromMtprotoPassword(); - setup(item.checker, secret); - item.checker->connectToServer( - item.data.host, - item.data.port, - secret, - dcId, - forFiles); - item.checkerv6 = nullptr; - } else { - const auto options = mtproto->dcOptions().lookup( - dcId, - MTP::DcType::Regular, - true); - const auto connect = [&]( - Checker &checker, - Variants::Address address) { - const auto &list = options.data[address][type]; - if (list.empty() - || ((address == Variants::IPv6) - && !Core::App().settings().proxy().tryIPv6())) { - checker = nullptr; + const auto id = item.id; + StartProxyCheck( + &_account->mtp(), + item.data, + item.checker, + item.checkerv6, + [=](Connection *raw, int pingTime) { + const auto item = ranges::find( + _list, + id, + [](const Item &item) { return item.id; }); + if (item == end(_list)) { return; } - const auto &endpoint = list.front(); - setup(checker, endpoint.secret); - checker->connectToServer( - QString::fromStdString(endpoint.ip), - endpoint.port, - endpoint.secret, - dcId, - forFiles); - }; - connect(item.checker, Variants::IPv4); - connect(item.checkerv6, Variants::IPv6); - if (!item.checker && !item.checkerv6) { - item.state = ItemState::Unavailable; - } + DropProxyChecker(item->checker, item->checkerv6, raw); + ResetProxyCheckers(item->checker, item->checkerv6); + if (item->state == ItemState::Checking) { + item->state = ItemState::Available; + item->ping = pingTime; + updateView(*item); + } + }, + [=](Connection *raw) { + const auto item = ranges::find( + _list, + id, + [](const Item &item) { return item.id; }); + if (item == end(_list)) { + return; + } + DropProxyChecker(item->checker, item->checkerv6, raw); + if (!HasProxyCheckers(item->checker, item->checkerv6) + && item->state == ItemState::Checking) { + item->state = ItemState::Unavailable; + updateView(*item); + } + }); + if (!HasProxyCheckers(item.checker, item.checkerv6)) { + item.state = ItemState::Unavailable; } } -void ProxiesBoxController::setupChecker(int id, const Checker &checker) { - using Connection = MTP::details::AbstractConnection; - const auto pointer = checker.get(); - pointer->connect(pointer, &Connection::connected, [=] { - const auto item = findById(id); - const auto pingTime = pointer->pingTime(); - item->checker = nullptr; - item->checkerv6 = nullptr; - if (item->state == ItemState::Checking) { - item->state = ItemState::Available; - item->ping = pingTime; - updateView(*item); - } - }); - const auto failed = [=] { - const auto item = findById(id); - if (item->checker == pointer) { - item->checker = nullptr; - } else if (item->checkerv6 == pointer) { - item->checkerv6 = nullptr; - } - if (!item->checker - && !item->checkerv6 - && item->state == ItemState::Checking) { - item->state = ItemState::Unavailable; - updateView(*item); - } - }; - pointer->connect(pointer, &Connection::disconnected, failed); - pointer->connect(pointer, &Connection::error, failed); -} - object_ptr ProxiesBoxController::CreateOwningBox( not_null account, const QString &highlightId) { diff --git a/Telegram/SourceFiles/boxes/connection_box.h b/Telegram/SourceFiles/boxes/connection_box.h index fcbe5ad6f6..c33f8ea0f4 100644 --- a/Telegram/SourceFiles/boxes/connection_box.h +++ b/Telegram/SourceFiles/boxes/connection_box.h @@ -117,7 +117,6 @@ private: void share(const ProxyData &proxy, bool qr = false); void saveDelayed(); void refreshChecker(Item &item); - void setupChecker(int id, const Checker &checker); void replaceItemWith( std::vector::iterator which, diff --git a/Telegram/SourceFiles/boxes/local_storage_box.cpp b/Telegram/SourceFiles/boxes/local_storage_box.cpp index 3936aeb492..cf1fdc0456 100644 --- a/Telegram/SourceFiles/boxes/local_storage_box.cpp +++ b/Telegram/SourceFiles/boxes/local_storage_box.cpp @@ -169,7 +169,6 @@ LocalStorageBox::Row::Row( sizeText(data), st::localStorageRowSize) , _clear(this, std::move(clear), st::localStorageClear) { - _clear->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); _clear->setVisible(data.count != 0); } diff --git a/Telegram/SourceFiles/boxes/peers/add_bot_to_chat_box.cpp b/Telegram/SourceFiles/boxes/peers/add_bot_to_chat_box.cpp index 0dc3bd9d06..d8c6001d4c 100644 --- a/Telegram/SourceFiles/boxes/peers/add_bot_to_chat_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/add_bot_to_chat_box.cpp @@ -217,7 +217,7 @@ void AddBotToGroupBoxController::addBotToGroup(not_null chat) { controller->hideLayer(); controller->showPeerHistory(chat, Way::ClearStack, ShowAtUnreadMsgId); }; - const auto rights = requestedAddAdmin + const auto rights = (requestedAddAdmin && _requestedRights != 0) ? _requestedRights : (chat->isBroadcast() && chat->asBroadcast()->canAddAdmins()) diff --git a/Telegram/SourceFiles/boxes/peers/create_managed_bot_box.cpp b/Telegram/SourceFiles/boxes/peers/create_managed_bot_box.cpp index a5a3c6c065..2897ce904a 100644 --- a/Telegram/SourceFiles/boxes/peers/create_managed_bot_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/create_managed_bot_box.cpp @@ -125,6 +125,7 @@ void CreateManagedBotBox( tr::lng_create_bot_username_placeholder(), initialUsername, QString()); + username->setPlaceholderHidden(true); username->setMaxLength( Ui::EditPeer::kMaxUsernameLength - int(botSuffixText.size())); usernameWrap->widthValue() | rpl::on_next([=](int width) { @@ -133,6 +134,7 @@ void CreateManagedBotBox( username->heightValue() | rpl::on_next([=](int height) { usernameWrap->resize(usernameWrap->width(), height); }, username->lifetime()); + username->finishAnimating(); const auto botPrefix = Ui::CreateChild( username, @@ -391,10 +393,12 @@ void CreateManagedBotBox( tr::rich), u"managed_bots"_q); } + } else if (MTP::IsFloodError(error)) { + show->showToast(tr::lng_flood_error(tr::now)); } else { show->showToast(type); } - }).send(); + }).handleFloodErrors().send(); }; QObject::connect(username, &Ui::UsernameInput::changed, [=] { diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_color_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_peer_color_box.cpp index fe2e90d5cf..5f813d2b79 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_peer_color_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_peer_color_box.cpp @@ -1546,7 +1546,6 @@ not_null CreateProfilePreview( } void ProcessButton(not_null button) { - button->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); // Raise to be above right emoji from buttons. crl::on_main(button, [=] { button->raise(); }); } @@ -2426,10 +2425,12 @@ void EditPeerColorBox( buttonContainer, tr::lng_settings_color_apply(), box->getDelegate()->style().button); + profileButton->setTextTransform(Ui::RoundButtonTextTransform::ToUpper); const auto nameButton = Ui::CreateChild( buttonContainer, tr::lng_settings_color_apply(), box->getDelegate()->style().button); + nameButton->setTextTransform(Ui::RoundButtonTextTransform::ToUpper); rpl::combine( buttonContainer->widthValue(), profileButton->sizeValue(), diff --git a/Telegram/SourceFiles/boxes/select_future_owner_box.cpp b/Telegram/SourceFiles/boxes/select_future_owner_box.cpp index dcefc7d68c..6b7967ad4f 100644 --- a/Telegram/SourceFiles/boxes/select_future_owner_box.cpp +++ b/Telegram/SourceFiles/boxes/select_future_owner_box.cpp @@ -477,8 +477,6 @@ void SelectFutureOwnerbox( tr::lng_select_next_owner_box_confirm(), tr::lng_close()), st::defaultActiveButton); - button->setTextTransform( - Ui::RoundButton::TextTransform::NoTransform); const auto raw = button.data(); rpl::combine( state->selectionChanges.events() | rpl::map_to(0), @@ -523,7 +521,6 @@ void SelectFutureOwnerbox( }); for (const auto &b : { select, cancel, leave }) { b->setFullRadius(true); - b->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); } box->setStyle(st::futureOwnerBox); } \ No newline at end of file diff --git a/Telegram/SourceFiles/boxes/star_gift_auction_box.cpp b/Telegram/SourceFiles/boxes/star_gift_auction_box.cpp index 81475cff97..312b75351b 100644 --- a/Telegram/SourceFiles/boxes/star_gift_auction_box.cpp +++ b/Telegram/SourceFiles/boxes/star_gift_auction_box.cpp @@ -1985,7 +1985,6 @@ object_ptr MakeActiveAuctionRow( rpl::single(QString()), st::auctionListRaise), st::auctionListRaisePadding); - button->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); auto secondsLeft = rpl::duplicate( value diff --git a/Telegram/SourceFiles/boxes/star_gift_preview_box.cpp b/Telegram/SourceFiles/boxes/star_gift_preview_box.cpp index 1c35a778e9..72ac5b9d32 100644 --- a/Telegram/SourceFiles/boxes/star_gift_preview_box.cpp +++ b/Telegram/SourceFiles/boxes/star_gift_preview_box.cpp @@ -1556,10 +1556,12 @@ void StarGiftPreviewBox( const style::RoundButton &st, const style::icon &active, Tab tab) { - auto owned = object_ptr(buttonsParent, text(), st); + auto owned = object_ptr( + buttonsParent, + text(), + st); const auto raw = owned.data(); - raw->setTextTransform(RoundButton::TextTransform::NoTransform); raw->setClickedCallback([=] { state->tab = tab; }); diff --git a/Telegram/SourceFiles/boxes/url_auth_box_content.cpp b/Telegram/SourceFiles/boxes/url_auth_box_content.cpp index 291be3d8d1..726d7ceaef 100644 --- a/Telegram/SourceFiles/boxes/url_auth_box_content.cpp +++ b/Telegram/SourceFiles/boxes/url_auth_box_content.cpp @@ -35,7 +35,6 @@ void PrepareFullWidthRoundButton( not_null button, not_null content, const style::margins &padding) { - button->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); button->setFullRadius(true); const auto paddingHorizontal = padding.left() + padding.right(); content->widthValue() | rpl::on_next([=](int w) { @@ -165,7 +164,6 @@ void ShowMatchCodesBox( (overlay->height() - visible) / 2); }); } - button->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); button->setFullRadius(true); button->setClickedCallback([=] { callback(code); diff --git a/Telegram/SourceFiles/calls/calls.style b/Telegram/SourceFiles/calls/calls.style index 5dd1aea73b..ebcaa85619 100644 --- a/Telegram/SourceFiles/calls/calls.style +++ b/Telegram/SourceFiles/calls/calls.style @@ -101,6 +101,7 @@ callButtonLabel: FlatLabel(defaultFlatLabel) { style: TextStyle(defaultTextStyle) { font: font(11px); } + maxHeight: 16px; } callAnswer: CallButton { diff --git a/Telegram/SourceFiles/calls/group/calls_group_rtmp.cpp b/Telegram/SourceFiles/calls/group/calls_group_rtmp.cpp index e0ed9edc27..7fd579b465 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_rtmp.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_rtmp.cpp @@ -258,7 +258,6 @@ void StartRtmpProcess::FillRtmpRows( wrap.data(), rpl::duplicate(text), st::groupCallRtmpCopyButton); - button->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); button->setClickedCallback(key ? Fn([=] { QGuiApplication::clipboard()->setText(state->key.current()); diff --git a/Telegram/SourceFiles/calls/group/ui/desktop_capture_choose_source.cpp b/Telegram/SourceFiles/calls/group/ui/desktop_capture_choose_source.cpp index 3dfc1fa526..542c4246cd 100644 --- a/Telegram/SourceFiles/calls/group/ui/desktop_capture_choose_source.cpp +++ b/Telegram/SourceFiles/calls/group/ui/desktop_capture_choose_source.cpp @@ -272,6 +272,8 @@ ChooseSourceProcess::ChooseSourceProcess( tr::lng_group_call_screen_share_audio(tr::now), false, st::desktopCaptureWithAudio)) { + _submit->setTextTransform(RoundButtonTextTransform::ToUpper); + _finish->setTextTransform(RoundButtonTextTransform::ToUpper); setupPanel(); setupSources(); activate(); @@ -370,6 +372,7 @@ void ChooseSourceProcess::setupPanel() { _bottom.get(), tr::lng_cancel(), st::desktopCaptureCancel); + cancel->setTextTransform(RoundButtonTextTransform::ToUpper); cancel->setClickedCallback([=] { _window->close(); }); diff --git a/Telegram/SourceFiles/chat_helpers/ttl_media_layer_widget.cpp b/Telegram/SourceFiles/chat_helpers/ttl_media_layer_widget.cpp index 4c5d996d10..9ccdd5813f 100644 --- a/Telegram/SourceFiles/chat_helpers/ttl_media_layer_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/ttl_media_layer_widget.cpp @@ -207,7 +207,6 @@ PreviewWrap::PreviewWrap( st::ttlMediaButton); close->setFullRadius(true); close->setClickedCallback(closeCallback); - close->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); rpl::combine( sizeValue(), diff --git a/Telegram/SourceFiles/core/deep_links/deep_links_router.cpp b/Telegram/SourceFiles/core/deep_links/deep_links_router.cpp index cb045bc498..4cdeabb64f 100644 --- a/Telegram/SourceFiles/core/deep_links/deep_links_router.cpp +++ b/Telegram/SourceFiles/core/deep_links/deep_links_router.cpp @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "core/deep_links/deep_links_router.h" +#include "base/qthelp_url.h" #include "core/deep_links/deep_links_chats.h" #include "core/deep_links/deep_links_contacts.h" #include "core/deep_links/deep_links_new.h" @@ -33,7 +34,7 @@ Context ParseCommand( for (const auto &pair : query.split('&')) { const auto eq = pair.indexOf('='); if (eq > 0) { - result.params[pair.left(eq).toLower()] = pair.mid(eq + 1); + result.params[pair.left(eq).toLower()] = qthelp::url_decode(pair.mid(eq + 1)); } else if (!pair.isEmpty()) { result.params[pair.toLower()] = QString(); } diff --git a/Telegram/SourceFiles/core/local_url_handlers.cpp b/Telegram/SourceFiles/core/local_url_handlers.cpp index 21cca8366a..7595146a20 100644 --- a/Telegram/SourceFiles/core/local_url_handlers.cpp +++ b/Telegram/SourceFiles/core/local_url_handlers.cpp @@ -392,6 +392,8 @@ bool ApplyMtprotoProxy( auto params = url_parse_params( match->captured(1), qthelp::UrlParamNameTransform::ToLower); + auto &secret = params[u"secret"_q]; + secret.replace('+', '-').replace('/', '_'); ProxiesBoxController::ShowApplyConfirmation( controller, MTP::ProxyData::Type::Mtproto, @@ -464,7 +466,9 @@ bool ShowWallPaper( const QString &value) { auto result = ChatAdminRights(); for (const auto &element : value.split(QRegularExpression(u"[+ ]"_q))) { - if (element == u"change_info"_q) { + if (element.isEmpty()) { + continue; + } else if (element == u"change_info"_q) { result |= ChatAdminRight::ChangeInfo; } else if (element == u"post_messages"_q) { result |= ChatAdminRight::PostMessages; @@ -482,6 +486,12 @@ bool ShowWallPaper( result |= ChatAdminRight::PinMessages; } else if (element == u"promote_members"_q) { result |= ChatAdminRight::AddAdmins; + } else if (element == u"post_stories"_q) { + result |= ChatAdminRight::PostStories; + } else if (element == u"edit_stories"_q) { + result |= ChatAdminRight::EditStories; + } else if (element == u"delete_stories"_q) { + result |= ChatAdminRight::DeleteStories; } else if (element == u"manage_video_chats"_q) { result |= ChatAdminRight::ManageCall; } else if (element == u"manage_direct_messages"_q) { @@ -491,7 +501,7 @@ bool ShowWallPaper( } else if (element == u"manage_chat"_q) { result |= ChatAdminRight::Other; } else { - return {}; + continue; } } return result; @@ -1940,7 +1950,7 @@ QString TryConvertUrlToLocal(QString url) { } else if (const auto callMatch = regex_match(u"^call/([a-zA-Z0-9\\.\\_\\-]+)(\\?|$)"_q, query, matchOptions)) { const auto slug = callMatch->captured(1); return u"tg://call?slug="_q + slug; - } else if (const auto newbotMatch = regex_match(u"^newbot/([a-zA-Z0-9\\.\\_]+)(/([a-zA-Z0-9\\.\\_]+))?(\\?(.+))?$"_q, query, matchOptions)) { + } else if (const auto newbotMatch = regex_match(u"^newbot/([a-zA-Z0-9\\.\\_]+)(/([a-zA-Z0-9\\.\\_]*))?(/?\\?(.+))?$"_q, query, matchOptions)) { const auto manager = newbotMatch->captured(1); const auto username = newbotMatch->captured(3); const auto params = newbotMatch->captured(5); diff --git a/Telegram/SourceFiles/core/version.h b/Telegram/SourceFiles/core/version.h index 5ebcf6910a..53b3e716bb 100644 --- a/Telegram/SourceFiles/core/version.h +++ b/Telegram/SourceFiles/core/version.h @@ -22,7 +22,7 @@ constexpr auto AppId = "{53F49750-6209-4FBF-9CA8-7A333C87D666}"_cs; constexpr auto AppNameOld = "AyuGram for Windows"_cs; constexpr auto AppName = "AyuGram Desktop"_cs; constexpr auto AppFile = "AyuGram"_cs; -constexpr auto AppVersion = 6007002; -constexpr auto AppVersionStr = "6.7.2"; +constexpr auto AppVersion = 6007004; +constexpr auto AppVersionStr = "6.7.4"; constexpr auto AppBetaVersion = false; constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION; diff --git a/Telegram/SourceFiles/data/data_file_origin.cpp b/Telegram/SourceFiles/data/data_file_origin.cpp index ffeb2f719e..9a832c36f3 100644 --- a/Telegram/SourceFiles/data/data_file_origin.cpp +++ b/Telegram/SourceFiles/data/data_file_origin.cpp @@ -174,7 +174,20 @@ struct FileReferenceAccumulator { }); } void push(const MTPusers_UserFull &data) { - push(data.data().vfull_user().data().vpersonal_photo()); + const auto &full = data.data().vfull_user().data(); + push(full.vpersonal_photo()); + push(full.vfallback_photo()); + push(full.vprofile_photo()); + } + void push(const MTPChatFull &data) { + data.match([&](const MTPDchatFull &data) { + push(data.vchat_photo()); + }, [&](const MTPDchannelFull &data) { + push(data.vchat_photo()); + }); + } + void push(const MTPmessages_ChatFull &data) { + push(data.data().vfull_chat()); } void push(const MTPmessages_RecentStickers &data) { data.match([&](const MTPDmessages_recentStickers &data) { @@ -246,6 +259,10 @@ UpdatedFileReferences GetFileReferences(const MTPusers_UserFull &data) { return GetFileReferencesHelper(data); } +UpdatedFileReferences GetFileReferences(const MTPmessages_ChatFull &data) { + return GetFileReferencesHelper(data); +} + UpdatedFileReferences GetFileReferences( const MTPmessages_RecentStickers &data) { return GetFileReferencesHelper(data); diff --git a/Telegram/SourceFiles/data/data_file_origin.h b/Telegram/SourceFiles/data/data_file_origin.h index 283a0fe034..47ce47a990 100644 --- a/Telegram/SourceFiles/data/data_file_origin.h +++ b/Telegram/SourceFiles/data/data_file_origin.h @@ -208,6 +208,7 @@ struct UpdatedFileReferences { UpdatedFileReferences GetFileReferences(const MTPmessages_Messages &data); UpdatedFileReferences GetFileReferences(const MTPphotos_Photos &data); UpdatedFileReferences GetFileReferences(const MTPusers_UserFull &data); +UpdatedFileReferences GetFileReferences(const MTPmessages_ChatFull &data); UpdatedFileReferences GetFileReferences( const MTPmessages_RecentStickers &data); UpdatedFileReferences GetFileReferences( diff --git a/Telegram/SourceFiles/data/data_peer.cpp b/Telegram/SourceFiles/data/data_peer.cpp index 58319a6164..6533de4250 100644 --- a/Telegram/SourceFiles/data/data_peer.cpp +++ b/Telegram/SourceFiles/data/data_peer.cpp @@ -566,7 +566,7 @@ Data::FileOrigin PeerData::userpicOrigin() const { Data::FileOrigin PeerData::userpicPhotoOrigin() const { return (isUser() && userpicPhotoId()) - ? Data::FileOriginUserPhoto(peerToUser(id).bare, userpicPhotoId()) + ? Data::FileOriginFullUser(peerToUser(id)) : Data::FileOrigin(); } diff --git a/Telegram/SourceFiles/data/data_user.cpp b/Telegram/SourceFiles/data/data_user.cpp index ac2957c247..20924d2a01 100644 --- a/Telegram/SourceFiles/data/data_user.cpp +++ b/Telegram/SourceFiles/data/data_user.cpp @@ -919,7 +919,8 @@ void ApplyUserUpdate(not_null user, const MTPDuserFull &update) { : Flag()) | (user->starsPerMessage() ? Flag::HasStarsPerMessage : Flag()) | Flag::MessageMoneyRestrictionsKnown - | Flag::RequiresPremiumToWrite; + | Flag::RequiresPremiumToWrite + | Flag::UnofficialSecurityRisk; user->setFlags((user->flags() & ~mask) | (update.is_phone_calls_private() ? Flag::PhoneCallsPrivate @@ -935,6 +936,9 @@ void ApplyUserUpdate(not_null user, const MTPDuserFull &update) { | Flag::MessageMoneyRestrictionsKnown | (update.is_contact_require_premium() ? (Flag::RequiresPremiumToWrite | Flag::HasRequirePremiumToWrite) + : Flag()) + | (update.is_unofficial_security_risk() + ? Flag::UnofficialSecurityRisk : Flag())); user->setIsBlocked(update.is_blocked()); user->setCallsStatus(update.is_phone_calls_private() diff --git a/Telegram/SourceFiles/data/data_user.h b/Telegram/SourceFiles/data/data_user.h index c9b1a6a17a..2a4d58791b 100644 --- a/Telegram/SourceFiles/data/data_user.h +++ b/Telegram/SourceFiles/data/data_user.h @@ -130,7 +130,7 @@ enum class UserDataFlag : uint32 { DiscardMinPhoto = (1 << 12), Self = (1 << 13), Premium = (1 << 14), - //CanReceiveGifts = (1 << 15), + UnofficialSecurityRisk = (1 << 15), VoiceMessagesForbidden = (1 << 16), PersonalPhoto = (1 << 17), StoriesHidden = (1 << 18), @@ -304,6 +304,10 @@ public: [[nodiscard]] UserId botManagerId() const; void setBotManagerId(UserId managerId); + [[nodiscard]] bool unofficialSecurityRisk() const { + return flags() & Flag::UnofficialSecurityRisk; + } + [[nodiscard]] MTPInputUser inputUser() const; QString firstName; diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index 4e81e2905d..f23d8f8fd9 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -4468,8 +4468,6 @@ void InnerWidget::refreshEmpty() { this, tr::lng_no_conversations_button(), st::dialogEmptyButton); - _emptyButton->setTextTransform( - Ui::RoundButton::TextTransform::NoTransform); _emptyButton->setVisible(isListVisible); _emptyButton->setClickedCallback([=, window = _controller] { window->show(PrepareContactsBox(window)); diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_top_bar_suggestion_content.cpp b/Telegram/SourceFiles/dialogs/ui/dialogs_top_bar_suggestion_content.cpp index b88b8886d7..97e368a451 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_top_bar_suggestion_content.cpp +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_top_bar_suggestion_content.cpp @@ -131,8 +131,6 @@ not_null*> CreateUnconfirmedAuthContent( buttons, tr::lng_unconfirmed_auth_deny(), st::dialogsUnconfirmedAuthButtonNo); - yes->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); - no->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); yes->setClickedCallback([=] { wrap->toggle(false, anim::type::normal); base::call_delayed(st::universalDuration, wrap, [=] { @@ -372,7 +370,6 @@ void TopBarSuggestionContent::setRightButton( _rightButton->moveToRight(top, top, outer.width()); }, _rightButton->lifetime()); _rightButton->setFullRadius(true); - _rightButton->setTextTransform(RoundButton::TextTransform::NoTransform); _rightButton->setClickedCallback(std::move(callback)); _rightButton->show(); } diff --git a/Telegram/SourceFiles/dialogs/ui/posts_search_intro.cpp b/Telegram/SourceFiles/dialogs/ui/posts_search_intro.cpp index 83d4ce40de..d21aea9c00 100644 --- a/Telegram/SourceFiles/dialogs/ui/posts_search_intro.cpp +++ b/Telegram/SourceFiles/dialogs/ui/posts_search_intro.cpp @@ -187,7 +187,6 @@ void PostsSearchIntro::setup() { rpl::single(QString()), st::postsSearchIntroButton), style::al_top); - _button->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); _footer = _content->add( object_ptr( _content.get(), diff --git a/Telegram/SourceFiles/export/view/export_view_progress.cpp b/Telegram/SourceFiles/export/view/export_view_progress.cpp index a1746d9313..9ffcbe2fd4 100644 --- a/Telegram/SourceFiles/export/view/export_view_progress.cpp +++ b/Telegram/SourceFiles/export/view/export_view_progress.cpp @@ -297,7 +297,6 @@ rpl::producer<> ProgressWidget::doneClicks() const { } void ProgressWidget::setupBottomButton(not_null button) { - button->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); button->show(); sizeValue( diff --git a/Telegram/SourceFiles/export/view/export_view_settings.cpp b/Telegram/SourceFiles/export/view/export_view_settings.cpp index 85c7061cc0..1964ff00f0 100644 --- a/Telegram/SourceFiles/export/view/export_view_settings.cpp +++ b/Telegram/SourceFiles/export/view/export_view_settings.cpp @@ -888,7 +888,6 @@ void SettingsWidget::refreshButtons( st::defaultBoxButton) : nullptr; if (start) { - start->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); start->show(); _startClicks = start->clicks() | rpl::to_empty; @@ -904,7 +903,6 @@ void SettingsWidget::refreshButtons( container.get(), tr::lng_cancel(), st::defaultBoxButton); - cancel->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); cancel->show(); _cancelClicks = cancel->clicks() | rpl::to_empty; diff --git a/Telegram/SourceFiles/ffmpeg/ffmpeg_frame_generator.cpp b/Telegram/SourceFiles/ffmpeg/ffmpeg_frame_generator.cpp index 365ce64529..0f35c5ff23 100644 --- a/Telegram/SourceFiles/ffmpeg/ffmpeg_frame_generator.cpp +++ b/Telegram/SourceFiles/ffmpeg/ffmpeg_frame_generator.cpp @@ -182,7 +182,7 @@ FrameGenerator::Frame FrameGenerator::Impl::renderCurrent( const auto withAlpha = bgra || (srcFormat == AV_PIX_FMT_YUVA420P); const auto dstPerLine = storage.bytesPerLine(); auto dst = storage.bits() + dx * sizeof(int32) + dy * dstPerLine; - if (srcSize == dstSize && bgra) { + if (bgra && srcSize == dstSize && frame->linesize[0] > 0) { const auto srcPerLine = frame->linesize[0]; const auto perLine = std::min(srcPerLine, int(dstPerLine)); auto src = frame->data[0]; diff --git a/Telegram/SourceFiles/ffmpeg/ffmpeg_utility.cpp b/Telegram/SourceFiles/ffmpeg/ffmpeg_utility.cpp index d1fbc73486..56e612358e 100644 --- a/Telegram/SourceFiles/ffmpeg/ffmpeg_utility.cpp +++ b/Telegram/SourceFiles/ffmpeg/ffmpeg_utility.cpp @@ -691,7 +691,7 @@ QImage CreateFrameStorage(QSize size) { ? (widthAlign - (width % widthAlign)) : 0); const auto perLine = neededWidth * kPixelBytesSize; - const auto buffer = new uchar[perLine * height + kAlignImageBy]; + const auto buffer = new uchar[size_t(perLine) * height + kAlignImageBy]; const auto cleanupData = static_cast(buffer); const auto address = reinterpret_cast(buffer); const auto alignedBuffer = buffer + ((address % kAlignImageBy) diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 5351b27dfb..27188a8a4e 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -54,6 +54,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/painter.h" #include "ui/rect.h" #include "ui/power_saving.h" +#include "ui/controls/compose_ai_button_factory.h" #include "ui/controls/emoji_button.h" #include "ui/controls/send_button.h" #include "ui/controls/send_as_button.h" @@ -6075,8 +6076,6 @@ bool HistoryWidget::updateCmdStartShown() { st::historyBotMenuButton); orderWidgets(); - _botMenu.button->setTextTransform( - Ui::RoundButton::TextTransform::NoTransform); _botMenu.button->setFullRadius(true); _botMenu.button->setClickedCallback([=] { const auto user = _peer ? _peer->asUser() : nullptr; @@ -6440,21 +6439,9 @@ bool HistoryWidget::fieldOrDisabledShown() const { } bool HistoryWidget::hasEnoughLinesForAi() const { - if (!_history - || _voiceRecordBar->isActive() - || !AyuSettings::getInstance().showCocoonAiButtonInMessageField() - || session().appConfig().aiComposeStyles().empty()) { - return false; - } - const auto &style = _field->st().style; - const auto lineHeight = style.lineHeight - ? style.lineHeight - : style.font->height; - const auto margins = _field->fullTextMargins(); - const auto contentHeight = _field->height() - - margins.top() - - margins.bottom(); - return contentHeight >= (3 * lineHeight); + return _history + && !_voiceRecordBar->isActive() + && Ui::HasEnoughLinesForAi(&session(), _field); } void HistoryWidget::updateAiButtonVisibility() { diff --git a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp index e27490bf1a..0ac4b8701f 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp @@ -92,6 +92,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/widgets/dropdown_menu.h" #include "ui/widgets/popup_menu.h" #include "ui/text/format_values.h" +#include "ui/controls/compose_ai_button_factory.h" #include "ui/controls/emoji_button.h" #include "ui/controls/send_button.h" #include "ui/controls/send_as_button.h" @@ -3127,7 +3128,6 @@ void SetupRestrictionView( st->premiumRequired.button); unlock->show(); unlock->setAttribute(Qt::WA_TransparentForMouseEvents); - unlock->setTextTransform(RoundButton::TextTransform::NoTransform); unlock->setFullRadius(true); return unlock; }; @@ -3698,21 +3698,9 @@ bool ComposeControls::canSendAiComposeDirect() const { } bool ComposeControls::hasEnoughLinesForAi() const { - if (!_history - || _recording.current() - || !AyuSettings::getInstance().showCocoonAiButtonInMessageField() - || session().appConfig().aiComposeStyles().empty()) { - return false; - } - const auto &style = _field->st().style; - const auto lineHeight = style.lineHeight - ? style.lineHeight - : style.font->height; - const auto margins = _field->fullTextMargins(); - const auto contentHeight = _field->height() - - margins.top() - - margins.bottom(); - return contentHeight >= (3 * lineHeight); + return _history + && !_recording.current() + && Ui::HasEnoughLinesForAi(&session(), _field); } bool ComposeControls::updateBotCommandShown() { diff --git a/Telegram/SourceFiles/history/view/history_view_contact_status.cpp b/Telegram/SourceFiles/history/view/history_view_contact_status.cpp index db7accde10..f3c826f09d 100644 --- a/Telegram/SourceFiles/history/view/history_view_contact_status.cpp +++ b/Telegram/SourceFiles/history/view/history_view_contact_status.cpp @@ -1019,8 +1019,6 @@ BusinessBotStatus::Bar::Bar(QWidget *parent) _name->setAttribute(Qt::WA_TransparentForMouseEvents); _status->setAttribute(Qt::WA_TransparentForMouseEvents); _togglePaused->setFullRadius(true); - _togglePaused->setTextTransform( - Ui::RoundButton::TextTransform::NoTransform); _settings->setClickedCallback([=] { showMenu(); }); diff --git a/Telegram/SourceFiles/history/view/history_view_pinned_bar.cpp b/Telegram/SourceFiles/history/view/history_view_pinned_bar.cpp index 6636fd858c..5ac0728691 100644 --- a/Telegram/SourceFiles/history/view/history_view_pinned_bar.cpp +++ b/Telegram/SourceFiles/history/view/history_view_pinned_bar.cpp @@ -192,7 +192,6 @@ auto WithPinnedTitle(not_null session, PinnedId id) { label->setTextColorOverride(stButton.textFg->c); // Use button's text color for label. label->setAttribute(Qt::WA_TransparentForMouseEvents); - button->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); button->setFullRadius(true); button->setClickedCallback(std::move(clickCallback)); diff --git a/Telegram/SourceFiles/history/view/history_view_reaction_preview.cpp b/Telegram/SourceFiles/history/view/history_view_reaction_preview.cpp index 310d47c38e..32d1af5279 100644 --- a/Telegram/SourceFiles/history/view/history_view_reaction_preview.cpp +++ b/Telegram/SourceFiles/history/view/history_view_reaction_preview.cpp @@ -24,6 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/widgets/dropdown_menu.h" #include "ui/widgets/labels.h" #include "ui/widgets/shadow.h" +#include "ui/wrap/fade_wrap.h" #include "ui/painter.h" #include "ui/rect.h" #include "ui/text/text_utilities.h" @@ -56,7 +57,7 @@ void SetupOverlayHideOnEscape( struct PreviewOverlayState { base::unique_qptr mediaPreview; base::unique_qptr clickable; - base::unique_qptr menu; + base::unique_qptr> menuWrap; base::unique_qptr background; base::unique_qptr label; Fn extraHide; @@ -64,7 +65,7 @@ struct PreviewOverlayState { void clear() { shutdownGuard.destroy(); - menu.reset(); + menuWrap.reset(); background.reset(); label.reset(); mediaPreview.reset(); @@ -131,18 +132,23 @@ void SetupPreviewMenu( const auto mainwidget = controller->widget()->bodyWidget(); if (fillMenu) { state->mediaPreview->setHideEmoji(true); - state->menu = base::make_unique_q( + auto menu = object_ptr( mainwidget, st::dropdownMenuWithIcons); - state->menu->setAutoHiding(false); - state->menu->setHiddenCallback( + menu->setAutoHiding(false); + menu->setHiddenCallback( crl::guard(state->clickable.get(), overlay.hideAll)); - fillMenu(state->menu.get()); + fillMenu(menu.data()); + state->menuWrap = base::make_unique_q>( + mainwidget, + std::move(menu)); + state->menuWrap->setDuration(st::defaultToggle.duration); + state->menuWrap->hide(anim::type::instant); } - const auto menuRaw = state->menu.get(); + const auto wrapRaw = state->menuWrap.get(); state->extraHide = [=] { - if (menuRaw) { - menuRaw->hideAnimated(); + if (wrapRaw) { + wrapRaw->hide(anim::type::normal); } }; @@ -150,7 +156,9 @@ void SetupPreviewMenu( mainwidget->sizeValue() | rpl::on_next([=](QSize size) { mediaPreviewRaw->setGeometry(Rect(size)); - if (menuRaw) { + if (wrapRaw) { + const auto menuRaw = wrapRaw->entity(); + menuRaw->showFast(); const auto gap = st::defaultMenu.itemPadding.top(); const auto menuH = menuRaw->height(); const auto shift = -(gap + menuH) / 2; @@ -158,9 +166,9 @@ void SetupPreviewMenu( const auto menuX = (size.width() - menuRaw->width()) / 2; const auto menuY = mediaPreviewRaw->contentBottom() + gap; - menuRaw->move(menuX, menuY); - menuRaw->showAnimated(Ui::PanelAnimation::Origin::TopLeft); - menuRaw->raise(); + wrapRaw->move(menuX, menuY); + wrapRaw->show(anim::type::normal); + wrapRaw->raise(); } }, mediaPreviewRaw->lifetime()); } @@ -309,7 +317,7 @@ void ShowWidgetPreview( struct State { base::unique_qptr preview; base::unique_qptr clickable; - base::unique_qptr menu; + base::unique_qptr> menuWrap; }; const auto state = std::make_shared(); const auto mainwidget = controller->widget()->bodyWidget(); @@ -326,28 +334,33 @@ void ShowWidgetPreview( const auto hideAll = [=] { state->clickable->setAttribute(Qt::WA_TransparentForMouseEvents); - if (state->menu) { - state->menu->hideAnimated(); + if (state->menuWrap) { + state->menuWrap->hide(anim::type::normal); } base::call_delayed( st::defaultToggle.duration, [s = state] { s->preview.reset(); - s->menu.reset(); + s->menuWrap.reset(); s->clickable.reset(); }); }; SetupOverlayHideOnEscape(state->clickable.get(), hideAll); - state->menu = base::make_unique_q( + auto menu = object_ptr( mainwidget, st::dropdownMenuWithIcons); - state->menu->setAutoHiding(false); - state->menu->setHiddenCallback( + menu->setAutoHiding(false); + menu->setHiddenCallback( crl::guard(state->clickable.get(), hideAll)); - fillMenu(state->menu.get()); + fillMenu(menu.data()); + state->menuWrap = base::make_unique_q>( + mainwidget, + std::move(menu)); + state->menuWrap->setDuration(st::defaultToggle.duration); + state->menuWrap->hide(anim::type::instant); - const auto menuRaw = state->menu.get(); + const auto wrapRaw = state->menuWrap.get(); state->clickable->show(); previewRaw->show(); @@ -363,17 +376,19 @@ void ShowWidgetPreview( state->clickable->setGeometry(Rect(size)); state->clickable->raise(); + const auto menuRaw = wrapRaw->entity(); + menuRaw->showFast(); const auto gap = st::defaultMenu.itemPadding.top(); const auto totalH = fullH + gap + menuRaw->height(); const auto previewY = (size.height() - totalH) / 2; previewRaw->move((size.width() - fullW) / 2, previewY); previewRaw->raise(); - menuRaw->move( + wrapRaw->move( (size.width() - menuRaw->width()) / 2, previewY + fullH + gap); - menuRaw->showAnimated(Ui::PanelAnimation::Origin::TopLeft); - menuRaw->raise(); + wrapRaw->show(anim::type::normal); + wrapRaw->raise(); }, previewRaw->lifetime()); } diff --git a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp index 0e5395653e..035c4003b6 100644 --- a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp @@ -1751,7 +1751,6 @@ bool ShowScheduledVideoPublished( widget.get(), rpl::single(view), st::processingVideoView); - button->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); button->show(); rpl::combine( widget->sizeValue(), diff --git a/Telegram/SourceFiles/history/view/history_view_sticker_toast.cpp b/Telegram/SourceFiles/history/view/history_view_sticker_toast.cpp index db494e5d02..44358f35f3 100644 --- a/Telegram/SourceFiles/history/view/history_view_sticker_toast.cpp +++ b/Telegram/SourceFiles/history/view/history_view_sticker_toast.cpp @@ -202,7 +202,6 @@ void StickerToast::showWithTitle(const QString &title) { widget.get(), rpl::single(view), st::historyPremiumViewSet); - button->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); button->show(); rpl::combine( widget->sizeValue(), diff --git a/Telegram/SourceFiles/history/view/history_view_summary_header.cpp b/Telegram/SourceFiles/history/view/history_view_summary_header.cpp index 1855bcd62b..70ee9ec07c 100644 --- a/Telegram/SourceFiles/history/view/history_view_summary_header.cpp +++ b/Telegram/SourceFiles/history/view/history_view_summary_header.cpp @@ -73,7 +73,7 @@ void SummaryHeader::update(not_null view) { } } if (const auto item = session->data().message(itemId)) { - session->api().transcribes().toggleSummary(item, nullptr); + session->api().transcribes().toggleSummary(item); } }); } diff --git a/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp b/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp index db67dbacac..7f8a8a452d 100644 --- a/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp @@ -144,6 +144,11 @@ TopBarWidget::TopBarWidget( , _onlineUpdater([=] { updateOnlineDisplay(); }) { setAttribute(Qt::WA_OpaquePaintEvent); + _clear->setTextTransform(Ui::RoundButtonTextTransform::ToUpper); + _forward->setTextTransform(Ui::RoundButtonTextTransform::ToUpper); + _sendNow->setTextTransform(Ui::RoundButtonTextTransform::ToUpper); + _delete->setTextTransform(Ui::RoundButtonTextTransform::ToUpper); + Lang::Updated( ) | rpl::on_next([=] { refreshLang(); @@ -1128,7 +1133,7 @@ void TopBarWidget::updateControlsGeometry() { _messageShot->moveToLeft(buttonsLeft, selectedButtonsTop); { - const auto large = _forward->height() / 3; + const auto large = st::topBarActionButtonLargeRadius; const auto &buttonSt = st::defaultActiveButton; const auto small = buttonSt.radius ? buttonSt.radius @@ -1526,7 +1531,8 @@ void TopBarWidget::showSelected(SelectedState state) { _messageShot->finishNumbersAnimation(); } } - if (visibilityChanged) { + if (visibilityChanged + || (!wasSelectedState && nowSelectedState)) { updateControlsVisibility(); } if (wasSelectedState != nowSelectedState && !_chooseForReportReason) { diff --git a/Telegram/SourceFiles/history/view/history_view_top_peers_selector.cpp b/Telegram/SourceFiles/history/view/history_view_top_peers_selector.cpp index 50644eea78..63da74acd6 100644 --- a/Telegram/SourceFiles/history/view/history_view_top_peers_selector.cpp +++ b/Telegram/SourceFiles/history/view/history_view_top_peers_selector.cpp @@ -90,10 +90,11 @@ void ShowTopPeersSelector( const auto contentHeight = int( st::topPeersSelectorUserpicSize * (1. + st::topPeersSelectorUserpicExpand)); - const auto selectorWidth = contentWidth - + 2 * st::topPeersSelectorPadding; const auto selectorHeight = contentHeight + 2 * st::topPeersSelectorPadding; + const auto selectorWidth = (peers.size() == 1) + ? selectorHeight + : (contentWidth + 2 * st::topPeersSelectorPadding); struct State { base::unique_qptr selector; @@ -159,7 +160,10 @@ void ShowTopPeersSelector( peers[info.index]->isSelf() ? tr::lng_saved_messages(tr::rich) : NameValue(peers[info.index]) | rpl::map(tr::rich), - userpicsWidget->width(), + std::max( + userpicsWidget->width(), + st::topPeersSelectorImportantTooltipLabel.minWidth + + st::lineWidth), st::topPeersSelectorImportantTooltipLabel), st::topPeersSelectorImportantTooltip.padding), st::topPeersSelectorImportantTooltip); diff --git a/Telegram/SourceFiles/history/view/history_view_transcribe_button.cpp b/Telegram/SourceFiles/history/view/history_view_transcribe_button.cpp index 3dc87cb155..d414422435 100644 --- a/Telegram/SourceFiles/history/view/history_view_transcribe_button.cpp +++ b/Telegram/SourceFiles/history/view/history_view_transcribe_button.cpp @@ -84,7 +84,8 @@ void TranscribeButton::setLoading(bool loading) { item, _lastPaintedPoint.isNull() ? QRect() - : QRect(_lastPaintedPoint, size())); + : (QRect(_lastPaintedPoint, size())) + + Margins(st::lineWidth)); } }, st::historyTranscribeRadialAnimation); @@ -380,7 +381,7 @@ ClickHandlerPtr TranscribeButton::link() { if (session->premium()) { auto &transcribes = session->api().transcribes(); return summarize - ? transcribes.toggleSummary(item, nullptr) + ? transcribes.toggleSummary(item) : transcribes.toggle(item); } const auto my = context.other.value(); @@ -409,15 +410,7 @@ ClickHandlerPtr TranscribeButton::link() { } } if (summarize) { - const auto weak = my.sessionWindow; - session->api().transcribes().toggleSummary(item, [=] { - if (const auto strong = weak.get()) { - Settings::ShowPremium(strong, u"summary"_q); - // ShowPremiumPreviewBox( - // strong, - // PremiumFeature::VoiceToText); - } - }); + session->api().transcribes().toggleSummary(item); } else { session->api().transcribes().toggle(item); } diff --git a/Telegram/SourceFiles/history/view/history_view_translate_bar.cpp b/Telegram/SourceFiles/history/view/history_view_translate_bar.cpp index a4808887f6..87b87d74b2 100644 --- a/Telegram/SourceFiles/history/view/history_view_translate_bar.cpp +++ b/Telegram/SourceFiles/history/view/history_view_translate_bar.cpp @@ -606,7 +606,6 @@ void TranslateBar::showToast( widget.get(), rpl::single(buttonText), st::historyPremiumViewSet); - button->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); button->show(); rpl::combine( widget->sizeValue(), diff --git a/Telegram/SourceFiles/history/view/media/history_view_poll.cpp b/Telegram/SourceFiles/history/view/media/history_view_poll.cpp index 9ac9d2d1e3..3084323713 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_poll.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_poll.cpp @@ -198,12 +198,14 @@ struct PollThumbnailData { [[nodiscard]] PollThumbnailData MakePollThumbnail( not_null poll, const PollAnswer &answer, - Window::SessionController::MessageContext messageContext); + Window::SessionController::MessageContext messageContext, + Fn paused = nullptr); [[nodiscard]] PollThumbnailData MakePollThumbnail( not_null poll, const PollMedia &media, - Window::SessionController::MessageContext messageContext) { + Window::SessionController::MessageContext messageContext, + Fn paused = nullptr) { auto result = PollThumbnailData(); if (!media) { return result; @@ -220,7 +222,8 @@ struct PollThumbnailData { if (media.document->sticker()) { result.thumbnail = Ui::MakeEmojiThumbnail( &poll->owner(), - Data::SerializeCustomEmojiId(media.document)); + Data::SerializeCustomEmojiId(media.document), + paused); result.kind = PollThumbnailKind::Emoji; } else if (media.document->isSong() || media.document->isVoiceMessage()) { @@ -292,8 +295,10 @@ struct PollThumbnailData { PollThumbnailData MakePollThumbnail( not_null poll, const PollAnswer &answer, - Window::SessionController::MessageContext messageContext) { - auto result = MakePollThumbnail(poll, answer.media, messageContext); + Window::SessionController::MessageContext messageContext, + Fn paused) { + auto result + = MakePollThumbnail(poll, answer.media, messageContext, paused); if (result.kind == PollThumbnailKind::Emoji && result.id) { const auto documentId = DocumentId(result.id); const auto option = answer.option; @@ -366,7 +371,8 @@ struct Poll::Answer { not_null poll, const PollAnswer &original, Window::SessionController::MessageContext messageContext, - Fn repaint); + Fn repaint, + Fn paused); Ui::Text::String text; QByteArray option; @@ -1737,11 +1743,13 @@ void Poll::Answer::fillMedia( not_null poll, const PollAnswer &original, Window::SessionController::MessageContext messageContext, - Fn repaint) { + Fn repaint, + Fn paused) { const auto updated = MakePollThumbnail( poll, original, - messageContext); + messageContext, + paused); const auto same = (updated.kind == thumbnailKind) && (updated.id == thumbnailId) && (updated.rounded == thumbnailRounded); @@ -2040,7 +2048,11 @@ void Poll::updateTexts() { options, Core::TextContext({ .session = &_poll->session(), - .repaint = [=] { repaint(); }, + .repaint = [=] { + if (!_parent->delegate()->elementAnimationsPaused()) { + repaint(); + } + }, .customEmojiLoopLimit = 2, })); } @@ -2100,7 +2112,11 @@ void Poll::Header::updateDescription() { } const auto context = Core::TextContext({ .session = &_owner->_poll->session(), - .repaint = [=] { _owner->_parent->customEmojiRepaint(); }, + .repaint = [=] { + if (!_owner->_parent->delegate()->elementAnimationsPaused()) { + _owner->_parent->customEmojiRepaint(); + } + }, .customEmojiLoopLimit = 2, }); _description.setMarkedText( @@ -2126,7 +2142,11 @@ void Poll::Header::updateSolutionText() { Ui::ItemTextOptions(_owner->_parent->data()), Core::TextContext({ .session = &_owner->_poll->session(), - .repaint = [=] { _owner->repaint(); }, + .repaint = [=] { + if (!_owner->_parent->delegate()->elementAnimationsPaused()) { + _owner->repaint(); + } + }, })); InitElementTextPart(_owner->_parent, _solutionText); } @@ -2138,10 +2158,14 @@ void Poll::Header::updateSolutionMedia() { .topicRootId = item->topicRootId(), .monoforumPeerId = item->sublistPeerId(), }; + const auto paused = [=] { + return _owner->_parent->delegate()->elementAnimationsPaused(); + }; const auto updated = MakePollThumbnail( _owner->_poll, _owner->_poll->solutionMedia, - messageContext); + messageContext, + paused); if (!updated.thumbnail) { _solutionMedia = nullptr; _solutionAttach = nullptr; @@ -2189,10 +2213,14 @@ void Poll::Header::updateAttachedMedia() { .topicRootId = item->topicRootId(), .monoforumPeerId = item->sublistPeerId(), }; + const auto paused = [=] { + return _owner->_parent->delegate()->elementAnimationsPaused(); + }; const auto updated = MakePollThumbnail( _owner->_poll, _owner->_poll->attachedMedia, - messageContext); + messageContext, + paused); const auto same = (_attachedMedia->kind == updated.kind) && (_attachedMedia->id == updated.id) && (_attachedMedia->rounded == updated.rounded); @@ -2220,8 +2248,8 @@ void Poll::Header::updateAttachedMedia() { _owner->_parent->data()->fullId()); if (const auto size = photo->size(Data::PhotoSize::Large)) { _attachedMedia->photoSize = *size; - } else if (const auto size = photo->size(Data::PhotoSize::Thumbnail)) { - _attachedMedia->photoSize = *size; + } else if (const auto s = photo->size(Data::PhotoSize::Thumbnail)) { + _attachedMedia->photoSize = *s; } } if ((updated.kind == PollThumbnailKind::Document @@ -2238,8 +2266,10 @@ void Poll::Header::updateAttachedMedia() { if (_attachedMedia->thumbnail) { _attachedMedia->thumbnail->subscribeToUpdates( crl::guard(_owner, [=] { - _attachedMediaCache = QImage(); - _owner->repaint(); + if (!_owner->_parent->delegate()->elementAnimationsPaused()) { + _attachedMediaCache = QImage(); + _owner->repaint(); + } })); } } @@ -2421,28 +2451,35 @@ uint16 Poll::Header::solutionSelectionLength() const { : uint16(0); } -TextSelection Poll::Header::toSolutionSelection(TextSelection selection) const { +TextSelection Poll::Header::toSolutionSelection( + TextSelection selection) const { return UnshiftItemSelection(selection, _description); } -TextSelection Poll::Header::fromSolutionSelection(TextSelection selection) const { +TextSelection Poll::Header::fromSolutionSelection( + TextSelection selection) const { return ShiftItemSelection(selection, _description); } -TextSelection Poll::Header::toQuestionSelection(TextSelection selection) const { +TextSelection Poll::Header::toQuestionSelection( + TextSelection selection) const { return UnshiftItemSelection( selection, uint16(_description.length() + solutionSelectionLength())); } -TextSelection Poll::Header::fromQuestionSelection(TextSelection selection) const { +TextSelection Poll::Header::fromQuestionSelection( + TextSelection selection) const { return ShiftItemSelection( selection, uint16(_description.length() + solutionSelectionLength())); } void Poll::Options::checkQuizAnswered() { - if (!_owner->_voted || !_votedFromHere || !_owner->_poll->quiz() || anim::Disabled()) { + if (!_owner->_voted + || !_votedFromHere + || !_owner->_poll->quiz() + || anim::Disabled()) { return; } const auto i = ranges::find(_answers, true, &Answer::chosen); @@ -2532,10 +2569,21 @@ void Poll::Header::updateRecentVoters() { void Poll::Options::updateAnswers() { const auto context = Core::TextContext({ .session = &_owner->_poll->session(), - .repaint = [=] { _owner->repaint(); }, + .repaint = [=] { + if (!_owner->_parent->delegate()->elementAnimationsPaused()) { + _owner->repaint(); + } + }, .customEmojiLoopLimit = 2, }); - const auto repaintThumbnail = crl::guard(_owner, [=] { _owner->repaint(); }); + const auto repaintThumbnail = crl::guard(_owner, [=] { + if (!_owner->_parent->delegate()->elementAnimationsPaused()) { + _owner->repaint(); + } + }); + const auto paused = [=] { + return _owner->_parent->delegate()->elementAnimationsPaused(); + }; const auto item = _owner->_parent->data(); const auto messageContext = Window::SessionController::MessageContext{ .id = item->fullId(), @@ -2569,7 +2617,12 @@ void Poll::Options::updateAnswers() { &PollAnswer::option); Assert(i != end(_owner->_poll->answers)); answer.fillData(_owner->_poll, *i, context); - answer.fillMedia(_owner->_poll, *i, messageContext, repaintThumbnail); + answer.fillMedia( + _owner->_poll, + *i, + messageContext, + repaintThumbnail, + paused); } _anyAnswerHasMedia = ranges::any_of(_answers, [](const Answer &a) { return a.thumbnail != nullptr; @@ -2586,7 +2639,12 @@ void Poll::Options::updateAnswers() { &PollAnswer::option); Assert(i != end(_owner->_poll->answers)); result.fillData(_owner->_poll, *i, context); - result.fillMedia(_owner->_poll, *i, messageContext, repaintThumbnail); + result.fillMedia( + _owner->_poll, + *i, + messageContext, + repaintThumbnail, + paused); return result; }) | ranges::to_vector; @@ -2995,7 +3053,9 @@ void Poll::Header::paintSolutionBlock( } if (!_closeSolutionLink) { _closeSolutionLink = std::make_shared( - crl::guard(_owner, [=] { _owner->_headerPart->solutionToggled(false); })); + crl::guard( + _owner, + [=] { _owner->_headerPart->solutionToggled(false); })); } const auto &qst = st::historyPagePreview; @@ -3376,11 +3436,15 @@ void Poll::Options::paintRadio( const auto o = p.opacity(); if (checkmark < 1.) { p.setBrush(Qt::NoBrush); - p.setOpacity(o * (over ? st::historyPollRadioOpacityOver : st::historyPollRadioOpacity)); + p.setOpacity(o + * (over + ? st::historyPollRadioOpacityOver + : st::historyPollRadioOpacity)); } const auto multiChoice = (_owner->_flags & PollData::Flag::MultiChoice); - const auto rect = QRectF(left, top, radio.diameter, radio.diameter).marginsRemoved(QMarginsF(radio.thickness / 2., radio.thickness / 2., radio.thickness / 2., radio.thickness / 2.)); + const auto rect = QRectF(left, top, radio.diameter, radio.diameter) + - Margins(radio.thickness / 2.); const auto radius = st::historyPollCheckboxRadius; if (_sendingAnimation && _sendingAnimation->option == answer.option) { const auto &active = stm->msgServiceFg; @@ -3427,7 +3491,11 @@ void Poll::Options::paintRadio( p.drawEllipse(inner); } const auto &icon = stm->historyPollChosen; - icon.paint(p, left + (radio.diameter - icon.width()) / 2, top + (radio.diameter - icon.height()) / 2, _owner->width()); + icon.paint( + p, + left + (radio.diameter - icon.width()) / 2, + top + (radio.diameter - icon.height()) / 2, + _owner->width()); } } @@ -3451,7 +3519,12 @@ void Poll::Options::paintPercent( p.setFont(st::historyPollPercentFont); p.setPen(stm->historyTextFg); const auto pleft = aleft - percentWidth - st::historyPollPercentSkip; - p.drawTextLeft(pleft, top + st::historyPollPercentTop, outerWidth, percent, percentWidth); + p.drawTextLeft( + pleft, + top + st::historyPollPercentTop, + outerWidth, + percent, + percentWidth); } void Poll::Options::paintFilling( @@ -3474,7 +3547,8 @@ void Poll::Options::paintFilling( const auto thickness = st::historyPollFillingHeight; const auto max = contentWidth - st::historyPollFillingRight; - const auto size = anim::interpolate(st::historyPollFillingMin, max, filling); + const auto size + = anim::interpolate(st::historyPollFillingMin, max, filling); const auto radius = st::historyPollFillingRadius; const auto ftop = top + std::max(st::historyPollPercentFont->height, contentHeight) @@ -3488,7 +3562,10 @@ void Poll::Options::paintFilling( const auto style = [&] { if (chosen && !correct) { return Style::Incorrect; - } else if (chosen && correct && _owner->_poll->quiz() && !context.outbg) { + } else if (chosen + && correct + && _owner->_poll->quiz() + && !context.outbg) { return Style::Correct; } else { return Style::Default; @@ -3603,7 +3680,8 @@ bool Poll::Options::checkAnimationStart() const { // Skip initial changes. return false; } - const auto result = (_owner->showVotes() != (_owner->_poll->voted() || _owner->_poll->closed())) + const auto result = _owner->showVotes() + != (_owner->_poll->voted() || _owner->_poll->closed()) || answerVotesChanged(); if (result) { saveStateInAnimation(); diff --git a/Telegram/SourceFiles/info/bot/starref/info_bot_starref_setup_widget.cpp b/Telegram/SourceFiles/info/bot/starref/info_bot_starref_setup_widget.cpp index ffff738e9c..c85728ced9 100644 --- a/Telegram/SourceFiles/info/bot/starref/info_bot_starref_setup_widget.cpp +++ b/Telegram/SourceFiles/info/bot/starref/info_bot_starref_setup_widget.cpp @@ -449,6 +449,7 @@ private: rpl::single(QString()), st::starrefBottomButton); const auto raw = result.data(); + raw->setTextTransform(Ui::RoundButtonTextTransform::ToUpper); rpl::combine( parent->widthValue(), raw->widthValue() diff --git a/Telegram/SourceFiles/info/channel_statistics/boosts/create_giveaway_box.cpp b/Telegram/SourceFiles/info/channel_statistics/boosts/create_giveaway_box.cpp index ca66330a8b..df14f19bbd 100644 --- a/Telegram/SourceFiles/info/channel_statistics/boosts/create_giveaway_box.cpp +++ b/Telegram/SourceFiles/info/channel_statistics/boosts/create_giveaway_box.cpp @@ -1379,7 +1379,6 @@ void CreateGiveawayBox( loadingAnimation->showOn(state->confirmButtonBusy.value()); } - button->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); state->typeValue.value( ) | rpl::on_next([=, raw = button.data()] { raw->resizeToWidth(box->width() diff --git a/Telegram/SourceFiles/info/channel_statistics/boosts/info_boosts_inner_widget.cpp b/Telegram/SourceFiles/info/channel_statistics/boosts/info_boosts_inner_widget.cpp index c527b7690d..0475266629 100644 --- a/Telegram/SourceFiles/info/channel_statistics/boosts/info_boosts_inner_widget.cpp +++ b/Telegram/SourceFiles/info/channel_statistics/boosts/info_boosts_inner_widget.cpp @@ -203,13 +203,11 @@ void FillShareLink( wrap, tr::lng_group_invite_context_copy(), st::inviteLinkCopy); - copy->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); copy->setClickedCallback(copyLink); const auto share = CreateChild( wrap, tr::lng_group_invite_context_share(), st::inviteLinkShare); - share->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); share->setClickedCallback(shareLink); wrap->widthValue( diff --git a/Telegram/SourceFiles/info/channel_statistics/earn/info_channel_earn_list.cpp b/Telegram/SourceFiles/info/channel_statistics/earn/info_channel_earn_list.cpp index 64c791018b..6614ac66ab 100644 --- a/Telegram/SourceFiles/info/channel_statistics/earn/info_channel_earn_list.cpp +++ b/Telegram/SourceFiles/info/channel_statistics/earn/info_channel_earn_list.cpp @@ -146,6 +146,7 @@ void AddRecipient(not_null box, const TextWithEntities &t) { rpl::single(QString()), st::channelEarnHistoryRecipientButton), style::al_top); + container->setTextTransform(Ui::RoundButtonTextTransform::ToUpper); const auto label = Ui::CreateChild( container, rpl::single(t), @@ -594,8 +595,6 @@ void InnerWidget::fill() { container, tr::lng_channel_earn_learn_close(), st::defaultActiveButton); - button->setTextTransform( - Ui::RoundButton::TextTransform::NoTransform); button->resizeToWidth(box->width() - st.buttonPadding.left() - st.buttonPadding.left()); @@ -887,6 +886,7 @@ void InnerWidget::fill() { stButton), st::boxRowPadding, style::al_justify); + button->setTextTransform(Ui::RoundButtonTextTransform::ToUpper); const auto label = Ui::CreateChild( button, @@ -1237,6 +1237,7 @@ void InnerWidget::fill() { ? tr::lng_channel_earn_history_out_button() : tr::lng_box_ok(), st::defaultActiveButton); + button->setTextTransform(Ui::RoundButtonTextTransform::ToUpper); button->resizeToWidth(box->width() - st.buttonPadding.left() - st.buttonPadding.left()); diff --git a/Telegram/SourceFiles/info/info.style b/Telegram/SourceFiles/info/info.style index 3c12f046dc..0a282bfde6 100644 --- a/Telegram/SourceFiles/info/info.style +++ b/Telegram/SourceFiles/info/info.style @@ -1074,6 +1074,7 @@ topBarInfo: IconButton(topBarSearch) { } topBarInfoActive: icon {{ "top_bar_profile", windowActiveTextFg }}; topBarActionSkip: 10px; +topBarActionButtonLargeRadius: 8px; topBarInfoButtonSize: size(52px, topBarHeight); topBarInfoButtonInnerSize: 42px; @@ -1473,3 +1474,6 @@ infoMusicButtonBottom: 8px; infoMusicButtonLine: 2px; memberTagPillPadding: margins(5px, -1px, 5px, 0px); + +infoSecurityRiskIconSize: 16px; +infoSecurityRiskIconMargin: margins(0px, 2px, 0px, 0px); diff --git a/Telegram/SourceFiles/info/info_flexible_scroll.cpp b/Telegram/SourceFiles/info/info_flexible_scroll.cpp index 24255dae5a..3730e04fac 100644 --- a/Telegram/SourceFiles/info/info_flexible_scroll.cpp +++ b/Telegram/SourceFiles/info/info_flexible_scroll.cpp @@ -242,7 +242,7 @@ void FlexibleScrollHelper::setupScrollHandlingWithFilter() { } const auto wheel = static_cast(e.get()); const auto delta = wheel->angleDelta().y(); - if (std::abs(delta) != 120) { + if (std::abs(delta) != 120 || (wheel->phase() != Qt::NoScrollPhase)) { scrollToY(_scroll->scrollTop() - delta); return base::EventFilterResult::Cancel; } diff --git a/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_widget.cpp b/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_widget.cpp index f27c2b02dc..37c790ccd8 100644 --- a/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_widget.cpp +++ b/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_widget.cpp @@ -1312,8 +1312,6 @@ void InnerWidget::refreshAbout() { ) | rpl::map([](const QString &text) { return Ui::Text::IconEmoji(&st::collectionAddIcon).append(text); })); - button->setTextTransform( - Ui::RoundButton::TextTransform::NoTransform); button->setClickedCallback([=] { editCollectionGifts(collectionId); }); @@ -2497,7 +2495,6 @@ void Widget::setupBottomButton(int wasBottomHeight) { bottom, rpl::single(QString()), st::collectionEditBox.button); - button->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); button->setText(tr::lng_gift_collection_add_button( ) | rpl::map([](const QString &text) { return Ui::Text::IconEmoji(&st::collectionAddIcon).append(text); diff --git a/Telegram/SourceFiles/info/polls/info_polls_list_widget.cpp b/Telegram/SourceFiles/info/polls/info_polls_list_widget.cpp index 11d7521136..0c848e506f 100644 --- a/Telegram/SourceFiles/info/polls/info_polls_list_widget.cpp +++ b/Telegram/SourceFiles/info/polls/info_polls_list_widget.cpp @@ -270,8 +270,6 @@ void ListWidget::Inner::setupHistory() { _scroll.get(), tr::lng_polls_create_title(), st::defaultActiveButton); - _newPollButton->setTextTransform( - Ui::RoundButton::TextTransform::NoTransform); _newPollButton->setFullRadius(true); _newPollButton->setClickedCallback([=] { Window::PeerMenuCreatePoll( diff --git a/Telegram/SourceFiles/info/profile/info_profile_actions.cpp b/Telegram/SourceFiles/info/profile/info_profile_actions.cpp index b38efe960d..6b8d362a4f 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_actions.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_actions.cpp @@ -407,6 +407,7 @@ base::options::toggle ShowChannelJoinedBelowAbout({ st::infoHoursOuter), st::infoProfileLabeledPadding - st::infoHoursOuterMargin); const auto button = result->entity(); + button->setTextTransform(Ui::RoundButtonTextTransform::ToUpper); const auto inner = Ui::CreateChild(button); button->widthValue() | rpl::on_next([=](int width) { const auto margin = st::infoHoursOuterMargin; @@ -643,7 +644,6 @@ base::options::toggle ShowChannelJoinedBelowAbout({ labelWrap, std::move(linkText), st::defaultTableSmallButton); - link->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); link->setClickedCallback([=] { state->myTimezone = !state->myTimezone.current(); state->expanded = true; @@ -897,6 +897,7 @@ void DeleteContactNote( st::infoProfileLabeledPadding - st::infoHoursOuterMargin); result->setDuration(st::infoSlideDuration); const auto button = result->entity(); + button->setTextTransform(Ui::RoundButtonTextTransform::ToUpper); auto outer = Ui::CreateChild>( button, @@ -2335,7 +2336,6 @@ void DetailsFiller::setupMainApp(bool suppressBottom) { st::infoOpenApp), st::infoOpenAppMargin, style::al_justify); - button->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); const auto user = _peer->asUser(); const auto controller = _controller->parentController(); diff --git a/Telegram/SourceFiles/info/profile/info_profile_inner_widget.cpp b/Telegram/SourceFiles/info/profile/info_profile_inner_widget.cpp index 5fa684c0ca..500e97ddc3 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_inner_widget.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_inner_widget.cpp @@ -33,14 +33,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "apiwrap.h" #include "api/api_peer_photo.h" #include "lang/lang_keys.h" +#include "ui/text/custom_emoji_helper.h" #include "ui/text/format_song_document_name.h" #include "ui/widgets/buttons.h" #include "ui/widgets/checkbox.h" +#include "ui/widgets/labels.h" #include "ui/widgets/scroll_area.h" #include "ui/widgets/shadow.h" #include "ui/wrap/fade_wrap.h" #include "ui/wrap/vertical_layout.h" #include "ui/wrap/slide_wrap.h" +#include "ui/painter.h" #include "ui/vertical_list.h" #include "ui/ui_utility.h" #include "styles/style_info.h" @@ -83,6 +86,68 @@ void AddAboutVerification( }, inner->lifetime()); } +void AddUnofficialSecurityRiskWarning( + not_null container, + not_null user) { + const auto content = container->add( + object_ptr(container)); + user->session().changes().peerFlagsValue( + user, + Data::PeerUpdate::Flag::FullInfo + ) | rpl::on_next([=] { + while (content->count()) { + delete content->widgetAt(0); + } + if (user->unofficialSecurityRisk()) { + auto helper = Ui::Text::CustomEmojiHelper(); + auto icon = helper.paletteDependent({ + .factory = [] { + const auto s = st::infoSecurityRiskIconSize; + const auto ratio = style::DevicePixelRatio(); + const auto rect = QRect(0, 0, s, s); + auto result = QImage( + rect.size() * ratio, + QImage::Format_ARGB32_Premultiplied); + result.setDevicePixelRatio(ratio); + result.fill(Qt::transparent); + + auto p = QPainter(&result); + auto hq = PainterHighQualityEnabler(p); + p.setPen(Qt::NoPen); + p.setBrush(st::attentionButtonFg); + p.drawEllipse(rect); + + p.setPen(st::windowFgActive); + p.setFont(st::semiboldFont); + p.drawText(rect, u"!"_q, style::al_center); + + p.end(); + return result; + }, + .margin = st::infoSecurityRiskIconMargin, + }); + auto label = object_ptr( + content, + tr::lng_profile_unofficial_warning( + lt_icon, + rpl::single(std::move(icon)), + lt_name, + rpl::single(TextWithEntities{ user->firstName }), + tr::marked), + st::defaultDividerLabel.label, + st::defaultPopupMenu, + helper.context([=] { content->update(); })); + content->add(object_ptr( + content, + std::move(label), + st::defaultBoxDividerLabelPadding, + st::defaultDividerLabel.bar, + RectPart::Top | RectPart::Bottom)); + } + content->resizeToWidth(content->width()); + }, content->lifetime()); +} + } // namespace InnerWidget::InnerWidget( @@ -129,6 +194,9 @@ object_ptr InnerWidget::setupContent( auto result = object_ptr(parent); setupSavedMusic(result); + if (const auto user = _peer->asUser()) { + AddUnofficialSecurityRiskWarning(result.data(), user); + } if (_topic && _topic->creating()) { return result; } diff --git a/Telegram/SourceFiles/info/profile/info_profile_top_bar.cpp b/Telegram/SourceFiles/info/profile/info_profile_top_bar.cpp index a08dc9a90a..bc50d7b6e6 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_top_bar.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_top_bar.cpp @@ -103,7 +103,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "styles/style_menu_icons.h" #include "styles/style_settings.h" -#include #include #include @@ -337,8 +336,10 @@ TopBar::TopBar( , _statusLabel(std::make_unique(_status.data(), _peer)) , _showLastSeen( this, - tr::lng_status_lastseen_when(), - st::infoProfileTopBarShowLastSeen) + object_ptr( + this, + tr::lng_status_lastseen_when(), + st::infoProfileTopBarShowLastSeen)) , _forumButton([&, controller = descriptor.controller] { const auto topic = _key.topic(); if (!topic) { @@ -355,7 +356,6 @@ TopBar::TopBar( .append(' ') .append(Ui::Text::IconEmoji(&st::textMoreIconEmoji, QString())); })); - owned->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); owned->setClickedCallback([=, peer = _peer] { if (const auto forum = peer->forum()) { if (peer->useSubsectionTabs()) { @@ -533,14 +533,14 @@ void TopBar::adjustColors(const std::optional &edgeColor) { : shouldOverrideTitle ? std::optional(st::groupCallMembersFg->c) : std::nullopt); - if (!_showLastSeen->isHidden()) { + if (_showLastSeen->toggled()) { if (shouldOverrideTitle) { const auto st = mapActionStyle(edgeColor); - _showLastSeen->setBrushOverride(st.bgColor); - _showLastSeen->setTextFgOverride(st.fgColor); + _showLastSeen->entity()->setBrushOverride(st.bgColor); + _showLastSeen->entity()->setTextFgOverride(st.fgColor); } else { - _showLastSeen->setBrushOverride(std::nullopt); - _showLastSeen->setTextFgOverride(std::nullopt); + _showLastSeen->entity()->setBrushOverride(std::nullopt); + _showLastSeen->entity()->setTextFgOverride(std::nullopt); } } { @@ -1718,7 +1718,7 @@ void TopBar::updateStatusPosition(float64 progressCurrent) { _status->hide(); // _starsRating->hide(); - _showLastSeen->hide(); + _showLastSeen->hide(anim::type::instant); return; } @@ -1728,7 +1728,7 @@ void TopBar::updateStatusPosition(float64 progressCurrent) { progressCurrent); const auto totalElementsWidth = _status->width() + (_starsRating ? _starsRating->width() : 0) - + (!_showLastSeen->isHidden() ? _showLastSeen->width() : 0); + + (_showLastSeen->toggled() ? _showLastSeen->width() : 0); const auto statusLeft = anim::interpolate( statusMostLeft(), (width() - totalElementsWidth) / 2, @@ -1743,17 +1743,15 @@ void TopBar::updateStatusPosition(float64 progressCurrent) { _status->moveToLeft(statusLeft + statusShift, statusTop); - if (!_showLastSeen->isHidden()) { + if (_showLastSeen->toggled()) { _showLastSeen->moveToLeft( statusLeft + statusShift + _status->textMaxWidth() + st::infoProfileTopBarLastSeenSkip.x(), statusTop + st::infoProfileTopBarLastSeenSkip.y()); - if (_showLastSeenOpacity) { - _showLastSeenOpacity->setOpacity(progressCurrent); - } - _showLastSeen->setAttribute( + _showLastSeen->setOpacity(progressCurrent); + _showLastSeen->entity()->setAttribute( Qt::WA_TransparentForMouseEvents, !progressCurrent); } @@ -2133,7 +2131,7 @@ void TopBar::setupShowLastSeen( || user->isBot() || user->isServiceUser() || !user->session().premiumPossible()) { - _showLastSeen->hide(); + _showLastSeen->hide(anim::type::instant); return; } @@ -2141,7 +2139,7 @@ void TopBar::setupShowLastSeen( if (user->lastseen().isHiddenByMe()) { user->updateFullForced(); } - _showLastSeen->hide(); + _showLastSeen->hide(anim::type::instant); return; } @@ -2151,13 +2149,13 @@ void TopBar::setupShowLastSeen( Data::PeerUpdate::Flag::OnlineStatus), Data::AmPremiumValue(&user->session()) ) | rpl::on_next([=](auto, bool premium) { - const auto wasShown = !_showLastSeen->isHidden(); + const auto wasShown = _showLastSeen->toggled(); const auto hiddenByMe = user->lastseen().isHiddenByMe(); const auto shown = hiddenByMe && !user->lastseen().isOnline(base::unixtime::now()) && !premium && user->session().premiumPossible(); - _showLastSeen->setVisible(shown); + _showLastSeen->toggle(shown, anim::type::instant); if (wasShown && premium && hiddenByMe) { user->updateFullForced(); } @@ -2173,16 +2171,11 @@ void TopBar::setupShowLastSeen( } }, _showLastSeen->lifetime()); - _showLastSeenOpacity = Ui::CreateChild( - _showLastSeen.get()); - _showLastSeen->setGraphicsEffect(_showLastSeenOpacity); - _showLastSeenOpacity->setOpacity(0.); + _showLastSeen->setOpacity(0.); - using TextTransform = Ui::RoundButton::TextTransform; - _showLastSeen->setTextTransform(TextTransform::NoTransform); - _showLastSeen->setFullRadius(true); + _showLastSeen->entity()->setFullRadius(true); - _showLastSeen->setClickedCallback([=] { + _showLastSeen->entity()->setClickedCallback([=] { const auto type = Ui::ShowOrPremium::LastSeen; controller->show(Box( Ui::ShowOrPremiumBox, diff --git a/Telegram/SourceFiles/info/profile/info_profile_top_bar.h b/Telegram/SourceFiles/info/profile/info_profile_top_bar.h index 7531e94a66..deaedd9f03 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_top_bar.h +++ b/Telegram/SourceFiles/info/profile/info_profile_top_bar.h @@ -52,8 +52,6 @@ struct InfoPeerBadge; struct FlatLabel; } //namespace style -class QGraphicsOpacityEffect; - namespace Ui { class FlatLabel; class IconButton; @@ -224,9 +222,8 @@ private: object_ptr _status; std::unique_ptr _statusLabel; rpl::variable _statusShift = 0; - object_ptr _showLastSeen = { nullptr }; + object_ptr> _showLastSeen = { nullptr }; object_ptr _forumButton = { nullptr }; - QGraphicsOpacityEffect *_showLastSeenOpacity = nullptr; std::shared_ptr _statusSt; std::shared_ptr _botVerifySt; diff --git a/Telegram/SourceFiles/info/similar_peers/info_similar_peers_widget.cpp b/Telegram/SourceFiles/info/similar_peers/info_similar_peers_widget.cpp index f67b18f090..ad7d45248c 100644 --- a/Telegram/SourceFiles/info/similar_peers/info_similar_peers_widget.cpp +++ b/Telegram/SourceFiles/info/similar_peers/info_similar_peers_widget.cpp @@ -157,6 +157,7 @@ void ListController::setupUnlock() { : tr::lng_similar_bots_show_more()), st::similarChannelsLock, rpl::single(true)); + button->setTextTransform(Ui::RoundButtonTextTransform::ToUpper); button->setClickedCallback([=] { const auto window = _controller->parentController(); ::Settings::ShowPremium(window, u"similar_channels"_q); diff --git a/Telegram/SourceFiles/info/stories/info_stories_inner_widget.cpp b/Telegram/SourceFiles/info/stories/info_stories_inner_widget.cpp index 93b61df858..bceac09a79 100644 --- a/Telegram/SourceFiles/info/stories/info_stories_inner_widget.cpp +++ b/Telegram/SourceFiles/info/stories/info_stories_inner_widget.cpp @@ -724,8 +724,6 @@ void InnerWidget::refreshEmpty() { ) | rpl::map([](const QString &text) { return Ui::Text::IconEmoji(&st::collectionAddIcon).append(text); })); - button->setTextTransform( - Ui::RoundButton::TextTransform::NoTransform); button->setClickedCallback([=] { editAlbumStories(albumId); }); diff --git a/Telegram/SourceFiles/info/stories/info_stories_widget.cpp b/Telegram/SourceFiles/info/stories/info_stories_widget.cpp index 4c7f98689e..08a870fc76 100644 --- a/Telegram/SourceFiles/info/stories/info_stories_widget.cpp +++ b/Telegram/SourceFiles/info/stories/info_stories_widget.cpp @@ -231,7 +231,6 @@ void Widget::setupBottomButton(int wasBottomHeight) { bottom, rpl::single(QString()), st::collectionEditBox.button); - button->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); button->setText(tr::lng_stories_album_add_button( ) | rpl::map([](const QString &text) { return Ui::Text::IconEmoji(&st::collectionAddIcon).append(text); diff --git a/Telegram/SourceFiles/info/userpic/info_userpic_emoji_builder.cpp b/Telegram/SourceFiles/info/userpic/info_userpic_emoji_builder.cpp index cb725eb0d1..83a30ef868 100644 --- a/Telegram/SourceFiles/info/userpic/info_userpic_emoji_builder.cpp +++ b/Telegram/SourceFiles/info/userpic/info_userpic_emoji_builder.cpp @@ -45,7 +45,6 @@ void ShowLayer( content.get(), tr::lng_connection_save(), st::userpicBuilderEmojiButton); - save->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); content->sizeValue( ) | rpl::on_next([=] { const auto &p = st::userpicBuilderEmojiSavePosiiton; diff --git a/Telegram/SourceFiles/inline_bots/inline_results_inner.cpp b/Telegram/SourceFiles/inline_bots/inline_results_inner.cpp index 6eff0b86d6..de39ecef54 100644 --- a/Telegram/SourceFiles/inline_bots/inline_results_inner.cpp +++ b/Telegram/SourceFiles/inline_bots/inline_results_inner.cpp @@ -514,7 +514,6 @@ void Inner::refreshSwitchPmButton(const CacheEntry *entry) { if (!_switchPmButton) { _switchPmButton.create(this, nullptr, st::switchPmButton); _switchPmButton->show(); - _switchPmButton->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); _switchPmButton->addClickHandler([=] { switchPm(); }); } _switchPmButton->setText(rpl::single(entry->switchPmText)); diff --git a/Telegram/SourceFiles/intro/intro_widget.cpp b/Telegram/SourceFiles/intro/intro_widget.cpp index 9905f7221f..d278e366be 100644 --- a/Telegram/SourceFiles/intro/intro_widget.cpp +++ b/Telegram/SourceFiles/intro/intro_widget.cpp @@ -93,6 +93,7 @@ Widget::Widget( this, account, rpl::single(true))) { + _settings->entity()->setTextTransform(Ui::RoundButtonTextTransform::ToUpper); controller->setDefaultFloatPlayerDelegate(floatPlayerDelegate()); getData()->country = ComputeNewAccountCountry(); @@ -318,6 +319,7 @@ void Widget::checkUpdateStatus() { this, tr::lng_menu_update(), st::defaultBoxButton)); + _update->entity()->setTextTransform(Ui::RoundButtonTextTransform::ToUpper); if (!_showAnimation) { _update->setVisible(true); } @@ -492,6 +494,7 @@ void Widget::showResetButton() { this, tr::lng_signin_reset_account(), st::introResetButton); + entity->setTextTransform(Ui::RoundButtonTextTransform::ToUpper); _resetAccount.create(this, std::move(entity)); _resetAccount->hide(anim::type::instant); _resetAccount->entity()->setClickedCallback([this] { resetAccount(); }); @@ -722,8 +725,6 @@ void Widget::showControls() { void Widget::setupNextButton() { _next->entity()->setClickedCallback([=] { getStep()->submit(); }); - _next->entity()->setTextTransform( - Ui::RoundButton::TextTransform::NoTransform); _next->entity()->setText(getStep()->nextButtonText( ) | rpl::filter([](const QString &text) { diff --git a/Telegram/SourceFiles/iv/iv_controller.cpp b/Telegram/SourceFiles/iv/iv_controller.cpp index cd114da341..02a2e09e6a 100644 --- a/Telegram/SourceFiles/iv/iv_controller.cpp +++ b/Telegram/SourceFiles/iv/iv_controller.cpp @@ -108,7 +108,6 @@ public: tr::lng_background_reset_default(), st::ivResetZoomLabel); resetLabel->setAttribute(Qt::WA_TransparentForMouseEvents); - reset->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); reset->setClickedCallback([this] { _delegate->ivSetZoom(0); }); diff --git a/Telegram/SourceFiles/media/clip/media_clip_ffmpeg.cpp b/Telegram/SourceFiles/media/clip/media_clip_ffmpeg.cpp index 22bbfd6d5f..67d6df50e4 100644 --- a/Telegram/SourceFiles/media/clip/media_clip_ffmpeg.cpp +++ b/Telegram/SourceFiles/media/clip/media_clip_ffmpeg.cpp @@ -231,7 +231,10 @@ bool FFMpegReaderImplementation::renderFrame( : _frame->format; const auto bgra = (format == AV_PIX_FMT_BGRA); hasAlpha = bgra || (format == AV_PIX_FMT_YUVA420P); - if (_frame->width == toSize.width() && _frame->height == toSize.height() && bgra) { + if (bgra + && _frame->width == toSize.width() + && _frame->height == toSize.height() + && _frame->linesize[0] > 0) { int32 sbpl = _frame->linesize[0], dbpl = to.bytesPerLine(), bpl = qMin(sbpl, dbpl); uchar *s = _frame->data[0], *d = to.bits(); for (int32 i = 0, l = _frame->height; i < l; ++i) { diff --git a/Telegram/SourceFiles/media/stories/media_stories_controller.cpp b/Telegram/SourceFiles/media/stories/media_stories_controller.cpp index 40bb3eea63..60f47e1922 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_controller.cpp +++ b/Telegram/SourceFiles/media/stories/media_stories_controller.cpp @@ -266,7 +266,6 @@ void Controller::Unsupported::setup(not_null peer) { wrap, tr::ayu_UpdateAyuGram(), st::storiesUnsupportedUpdate); - _button->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); _button->show(); rpl::combine( diff --git a/Telegram/SourceFiles/media/stories/media_stories_stealth.cpp b/Telegram/SourceFiles/media/stories/media_stories_stealth.cpp index 89b8d533ae..10c4c05ef4 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_stealth.cpp +++ b/Telegram/SourceFiles/media/stories/media_stories_stealth.cpp @@ -242,6 +242,7 @@ struct State { rpl::single(QString()), st.box.button); const auto raw = result.data(); + raw->setTextTransform(Ui::RoundButtonTextTransform::ToUpper); const auto label = Ui::CreateChild( raw, diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_utility.cpp b/Telegram/SourceFiles/media/streaming/media_streaming_utility.cpp index fdfbe20f82..68ccc55370 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_utility.cpp +++ b/Telegram/SourceFiles/media/streaming/media_streaming_utility.cpp @@ -158,7 +158,9 @@ QImage ConvertFrame( const auto format = AV_PIX_FMT_BGRA; const auto hasDesiredFormat = (frame->format == format); - if (frameSize == storage.size() && hasDesiredFormat) { + if (hasDesiredFormat + && frameSize == storage.size() + && frame->linesize[0] > 0) { static_assert(sizeof(uint32) == FFmpeg::kPixelBytesSize); auto to = reinterpret_cast(storage.bits()); auto from = reinterpret_cast(frame->data[0]); diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_video_track.cpp b/Telegram/SourceFiles/media/streaming/media_streaming_video_track.cpp index bf5521c2cd..fc1e09ef2f 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_video_track.cpp +++ b/Telegram/SourceFiles/media/streaming/media_streaming_video_track.cpp @@ -373,6 +373,11 @@ auto VideoTrackObject::readFrame(not_null frame) -> FrameResult { _waitingForData.fire({}); return FrameResult::Waiting; } + const auto decodedFrame = _stream.decodedFrame.get(); + if (int64(decodedFrame->width) * decodedFrame->height > kMaxFrameArea) { + fail(Error::InvalidData); + return FrameResult::Error; + } const auto position = currentFramePosition(); if (position == kTimeUnknown) { fail(Error::InvalidData); @@ -649,7 +654,7 @@ bool VideoTrackObject::tryReadFirstFrame(FFmpeg::Packet &&packet) { bool VideoTrackObject::processFirstFrame() { const auto decodedFrame = _stream.decodedFrame.get(); - if (decodedFrame->width * decodedFrame->height > kMaxFrameArea) { + if (int64(decodedFrame->width) * decodedFrame->height > kMaxFrameArea) { return false; } else if (decodedFrame->hw_frames_ctx) { if (!_stream.transferredFrame) { diff --git a/Telegram/SourceFiles/media/view/media_view.style b/Telegram/SourceFiles/media/view/media_view.style index df593cf3a6..1777f23734 100644 --- a/Telegram/SourceFiles/media/view/media_view.style +++ b/Telegram/SourceFiles/media/view/media_view.style @@ -223,6 +223,19 @@ mediaviewSaveMsgHiding: 2500; mediaviewSaveMsgStyle: TextStyle(defaultTextStyle) { font: font(16px); } +mediaviewChapterPadding: margins(20px, 12px, 20px, 12px); +mediaviewChapterFont: font(15px semibold); +mediaviewChapterShowing: 200; +mediaviewChapterShown: 1500; +mediaviewChapterHiding: 400; +mediaviewChapterArrowSize: 10px; +mediaviewChapterArrowWidth: 6px; +mediaviewChapterArrowShift: 16px; +mediaviewChapterArrowGap: 12px; +mediaviewChapterArrowSlide: 350; +mediaviewChapterArrowPause: 1500; +mediaviewChapterArrowFade: 300; + mediaviewTextPalette: TextPalette(defaultTextPalette) { linkFg: mediaviewTextLinkFg; monoFg: mediaviewCaptionFg; diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_opengl.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_opengl.cpp index cacf4d7de0..8092b29078 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_opengl.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_opengl.cpp @@ -28,7 +28,8 @@ constexpr auto kRadialLoadingOffset = kNotchOffset + 4; constexpr auto kThemePreviewOffset = kRadialLoadingOffset + 4; constexpr auto kDocumentBubbleOffset = kThemePreviewOffset + 4; constexpr auto kSaveMsgOffset = kDocumentBubbleOffset + 4; -constexpr auto kFooterOffset = kSaveMsgOffset + 4; +constexpr auto kChapterOffset = kSaveMsgOffset + 4; +constexpr auto kFooterOffset = kChapterOffset + 4; constexpr auto kCaptionOffset = kFooterOffset + 4; constexpr auto kGroupThumbsOffset = kCaptionOffset + 4; constexpr auto kControlsOffset = kGroupThumbsOffset + 4; @@ -724,6 +725,13 @@ void OverlayWidget::RendererGL::paintSaveMsg(QRect outer) { }, kSaveMsgOffset, true); } +void OverlayWidget::RendererGL::paintChapter(QRect outer) { + paintUsingRaster(_chapterImage, outer, [&](Painter &&p) { + const auto newOuter = QRect(QPoint(), outer.size()); + _owner->paintChapterContent(p, newOuter, newOuter); + }, kChapterOffset, true); +} + void OverlayWidget::RendererGL::paintControlsStart() { validateControls(); _f->glActiveTexture(GL_TEXTURE0); diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_opengl.h b/Telegram/SourceFiles/media/view/media_view_overlay_opengl.h index 8438bc9dc5..f0f36592c4 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_opengl.h +++ b/Telegram/SourceFiles/media/view/media_view_overlay_opengl.h @@ -59,6 +59,7 @@ private: void paintThemePreview(QRect outer) override; void paintDocumentBubble(QRect outer, QRect icon) override; void paintSaveMsg(QRect outer) override; + void paintChapter(QRect outer) override; void paintControlsStart() override; void paintControl( Over control, @@ -144,6 +145,7 @@ private: Ui::GL::Image _documentBubbleImage; Ui::GL::Image _themePreviewImage; Ui::GL::Image _saveMsgImage; + Ui::GL::Image _chapterImage; Ui::GL::Image _footerImage; Ui::GL::Image _captionImage; Ui::GL::Image _groupThumbsImage; diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_raster.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_raster.cpp index d45becf852..2bb415e7eb 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_raster.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_raster.cpp @@ -275,6 +275,12 @@ void OverlayWidget::RendererSW::paintSaveMsg(QRect outer) { } } +void OverlayWidget::RendererSW::paintChapter(QRect outer) { + if (outer.intersects(_clipOuter)) { + _owner->paintChapterContent(*_p, outer, _clipOuter); + } +} + void OverlayWidget::RendererSW::paintControlsStart() { } diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_raster.h b/Telegram/SourceFiles/media/view/media_view_overlay_raster.h index f8b2d89f1d..2d20aab9e2 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_raster.h +++ b/Telegram/SourceFiles/media/view/media_view_overlay_raster.h @@ -43,6 +43,7 @@ private: void paintThemePreview(QRect outer) override; void paintDocumentBubble(QRect outer, QRect icon) override; void paintSaveMsg(QRect outer) override; + void paintChapter(QRect outer) override; void paintControlsStart() override; void paintControl( Over control, diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_renderer.h b/Telegram/SourceFiles/media/view/media_view_overlay_renderer.h index 1ed82dde9d..98296a5b12 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_renderer.h +++ b/Telegram/SourceFiles/media/view/media_view_overlay_renderer.h @@ -33,6 +33,7 @@ public: virtual void paintThemePreview(QRect outer) = 0; virtual void paintDocumentBubble(QRect outer, QRect icon) = 0; virtual void paintSaveMsg(QRect outer) = 0; + virtual void paintChapter(QRect outer) = 0; virtual void paintControlsStart() = 0; virtual void paintControl( Over control, diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp index 71b94204c9..6096588001 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp @@ -607,6 +607,10 @@ OverlayWidget::OverlayWidget() _saveMsgAnimation.start([=] { updateSaveMsg(); }, 1., 0., delay); }); + _chapterTimer.setCallback([=, delay = st::mediaviewChapterHiding] { + _chapterAnimation.start([=] { updateChapter(); }, 1., 0., delay); + }); + _docRectImage = QImage( st::mediaviewFileSize * style::DevicePixelRatio(), QImage::Format_ARGB32_Premultiplied); @@ -1794,12 +1798,10 @@ void OverlayWidget::refreshVoteButton() { return; } if (!_voteButton) { - using TextTransform = Ui::RoundButton::TextTransform; _voteButton.create( _body, tr::lng_polls_submit_votes(), st::mediaviewVoteButton); - _voteButton->setTextTransform(TextTransform::NoTransform); const auto effect = Ui::CreateChild( _voteButton.data()); effect->setOpacity(_controlsOpacity.current()); @@ -3529,6 +3531,12 @@ Data::FileOrigin OverlayWidget::fileOrigin() const { } else if (_message) { return _message->fullId(); } else if (_photo && _user) { + const auto dominated = (_user->hasPersonalPhoto() + && _photo->id == _user->userpicPhotoId()) + || SyncUserFallbackPhotoViewer(_user) == _photo->id; + if (dominated) { + return Data::FileOriginFullUser(peerToUser(_user->id)); + } return Data::FileOriginUserPhoto(peerToUser(_user->id), _photo->id); } else if (_photo && _peer && _peer->userpicPhotoId() == _photo->id) { return Data::FileOriginPeerPhoto(_peer->id); @@ -3544,6 +3552,12 @@ Data::FileOrigin OverlayWidget::fileOrigin(const Entity &entity) const { } const auto photo = v::get>(entity.data); if (_user) { + const auto dominated = (_user->hasPersonalPhoto() + && photo->id == _user->userpicPhotoId()) + || SyncUserFallbackPhotoViewer(_user) == photo->id; + if (dominated) { + return Data::FileOriginFullUser(peerToUser(_user->id)); + } return Data::FileOriginUserPhoto(peerToUser(_user->id), photo->id); } else if (_peer && _peer->userpicPhotoId() == photo->id) { return Data::FileOriginPeerPhoto(_peer->id); @@ -4904,12 +4918,10 @@ void OverlayWidget::initThemePreview() { _themePreviewId = 0; _themePreview = std::move(result); if (_themePreview) { - using TextTransform = Ui::RoundButton::TextTransform; _themeApply.create( _body, tr::lng_theme_preview_apply(), st::themePreviewApplyButton); - _themeApply->setTextTransform(TextTransform::NoTransform); _themeApply->show(); _themeApply->setClickedCallback([=] { const auto &object = Background()->themeObject(); @@ -4926,7 +4938,6 @@ void OverlayWidget::initThemePreview() { _body, tr::lng_cancel(), st::themePreviewCancelButton); - _themeCancel->setTextTransform(TextTransform::NoTransform); _themeCancel->show(); _themeCancel->setClickedCallback([this] { close(); }); if (const auto slug = _themeCloudData.slug; !slug.isEmpty()) { @@ -4934,7 +4945,6 @@ void OverlayWidget::initThemePreview() { _body, tr::lng_theme_share(), st::themePreviewCancelButton); - _themeShare->setTextTransform(TextTransform::NoTransform); _themeShare->show(); _themeShare->setClickedCallback([=] { QGuiApplication::clipboard()->setText( @@ -5254,11 +5264,14 @@ void OverlayWidget::applyVideoQuality(VideoQuality value) { const auto startStreaming = StartStreaming(false, time); if (!canInitStreaming() || !initStreaming(startStreaming)) { redisplayContent(); - } else if (_fullScreenVideo != wasFullScreen) { - _fullScreenVideo = wasFullScreen; - if (_streamed->controls) { - _streamed->controls->setInFullScreen(_fullScreenVideo); + } else { + if (_fullScreenVideo != wasFullScreen) { + _fullScreenVideo = wasFullScreen; + if (_streamed->controls) { + _streamed->controls->setInFullScreen(_fullScreenVideo); + } } + refreshCaption(); } } @@ -5732,6 +5745,9 @@ void OverlayWidget::paint(not_null renderer) { if (isSaveMsgShown()) { renderer->paintSaveMsg(_saveMsg); } + if (isChapterShown()) { + renderer->paintChapter(_chapterRect); + } const auto opacity = _fullScreenVideo ? 0. : _controlsOpacity.current(); if (opacity > 0) { @@ -5992,6 +6008,154 @@ void OverlayWidget::paintSaveMsgContent( p.setOpacity(1); } +void OverlayWidget::showChapterIndicator( + const QString &name, + int direction) { + if (name.isEmpty()) { + return; + } + _chapterText = name; + + const auto font = st::mediaviewChapterFont; + const auto padding = st::mediaviewChapterPadding; + const auto arrowSpace = st::mediaviewChapterArrowWidth + + st::mediaviewChapterArrowGap; + const auto textWidth = font->width(_chapterText); + const auto w = padding.left() + + arrowSpace + + textWidth + + arrowSpace + + padding.right(); + const auto h = rect::m::sum::v(padding) + font->height; + _chapterRect = QRect( + (width() - w) / 2, + _minUsedTop + (_maxUsedHeight - h) / 2, + w, + h); + + if (isChapterShown()) { + _chapterTimer.callOnce(st::mediaviewChapterShown); + } else { + const auto callback = [=](float64 value) { + updateChapter(); + if (!_chapterAnimation.animating()) { + _chapterTimer.callOnce(st::mediaviewChapterShown); + } + }; + _chapterAnimation.start( + callback, + 0., + 1., + st::mediaviewChapterShowing); + } + + _chapterArrows.erase( + ranges::remove_if( + _chapterArrows, + [&](const auto &a) { + return !a->animation.animating() + || (a->direction != direction); + }), + _chapterArrows.end()); + auto arrow = std::make_unique(); + arrow->direction = direction; + arrow->animation.start( + [=] { updateChapter(); }, + 0., + 1., + st::mediaviewChapterArrowSlide + + st::mediaviewChapterArrowPause + + st::mediaviewChapterArrowFade); + _chapterArrows.push_back(std::move(arrow)); + updateChapter(); +} + +void OverlayWidget::paintChapterContent( + Painter &p, + QRect outer, + QRect clip) { + const auto opacity = _chapterAnimation.value(1.); + p.setOpacity(opacity); + Ui::FillRoundRect( + p, + outer, + st::mediaviewSaveMsgBg, + Ui::MediaviewSaveCorners); + + const auto font = st::mediaviewChapterFont; + const auto padding = st::mediaviewChapterPadding; + const auto arrowSize = st::mediaviewChapterArrowSize; + const auto arrowWidth = st::mediaviewChapterArrowWidth; + const auto arrowGap = st::mediaviewChapterArrowGap; + const auto textX = outer.x() + + padding.left() + + arrowWidth + + arrowGap; + const auto textY = outer.y() + padding.top(); + + p.setFont(font); + p.setPen(st::mediaviewSaveMsgFg); + p.drawText(textX, textY + font->ascent, _chapterText); + + const auto cy = outer.y() + outer.height() / 2.; + const auto halfH = arrowSize / 2.; + const auto totalDuration = float64(st::mediaviewChapterArrowSlide + + st::mediaviewChapterArrowPause + + st::mediaviewChapterArrowFade); + const auto slideEnd = st::mediaviewChapterArrowSlide / totalDuration; + const auto fadeStart = 1. - st::mediaviewChapterArrowFade / totalDuration; + auto hq = PainterHighQualityEnabler(p); + auto pen = QPen(st::mediaviewSaveMsgFg->c); + pen.setWidthF(st::lineWidth * 1.5); + pen.setCapStyle(Qt::RoundCap); + pen.setJoinStyle(Qt::RoundJoin); + p.setPen(pen); + p.setBrush(Qt::NoBrush); + for (const auto &arrow : _chapterArrows) { + if (!arrow->animation.animating()) { + continue; + } + const auto progress = arrow->animation.value(1.); + const auto slideProgress = std::min(progress / slideEnd, 1.); + const auto shift = st::mediaviewChapterArrowShift * slideProgress; + const auto arrowOpacity = (progress <= fadeStart) + ? slideProgress + : (1. - progress) / (1. - fadeStart); + p.setOpacity(opacity * arrowOpacity); + auto path = QPainterPath(); + if (arrow->direction > 0) { + const auto ax = outer.x() + + outer.width() + - padding.right() + - arrowGap + - arrowWidth + + shift; + path.moveTo(ax, cy - halfH); + path.lineTo(ax + arrowWidth, cy); + path.lineTo(ax, cy + halfH); + } else { + const auto ax = outer.x() + + padding.left() + + arrowGap + + arrowWidth + - shift; + path.moveTo(ax, cy - halfH); + path.lineTo(ax - arrowWidth, cy); + path.lineTo(ax, cy + halfH); + } + p.drawPath(path); + } + p.setOpacity(1); +} + +bool OverlayWidget::isChapterShown() const { + return _chapterAnimation.animating() || _chapterTimer.isActive(); +} + +void OverlayWidget::updateChapter() { + update(_chapterRect); +} + bool OverlayWidget::saveControlLocked() const { const auto story = _stories ? _stories->story() : nullptr; return story @@ -6271,6 +6435,34 @@ void OverlayWidget::handleKeyPress(not_null e) { } else if (key == Qt::Key_Space) { playbackPauseResume(); return; + } else if (modifiers.testFlag(Qt::AltModifier) + && (key == Qt::Key_Left || key == Qt::Key_Right) + && _streamed->controls + && _streamed->controls->hasTimestamps()) { + const auto &state = _streamed->instance.info().video.state; + const auto duration = state.duration; + if (duration > 0) { + const auto progress = state.position + / float64(duration); + const auto &controls = _streamed->controls; + if (key == Qt::Key_Right) { + if (const auto ts = controls->nextTimestamp(progress)) { + activateControls(); + restartAtProgress(ts->position); + showChapterIndicator(ts->label, 1); + } + } else { + if (const auto ts = controls->prevTimestamp(progress)) { + activateControls(); + restartAtProgress(ts->position); + showChapterIndicator(ts->label, -1); + } else { + activateControls(); + restartAtSeekPosition(0); + } + } + } + return; } else if (_fullScreenVideo) { if (key == Qt::Key_Escape) { playbackToggleFullScreen(); @@ -7444,6 +7636,11 @@ void OverlayWidget::clearBeforeHide() { if (_menu) { _menu->hideMenu(true); } + _chapterText = QString(); + _chapterRect = QRect(); + _chapterAnimation.stop(); + _chapterTimer.cancel(); + _chapterArrows.clear(); _controlsHideTimer.cancel(); _controlsState = ControlsShown; _controlsOpacity = anim::value(1); diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.h b/Telegram/SourceFiles/media/view/media_view_overlay_widget.h index a2f2373103..39f301063e 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.h +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.h @@ -517,6 +517,11 @@ private: bool nonbright = false) const; [[nodiscard]] bool isSaveMsgShown() const; + void showChapterIndicator(const QString &name, int direction); + void paintChapterContent(Painter &p, QRect outer, QRect clip); + [[nodiscard]] bool isChapterShown() const; + void updateChapter(); + void updateOverRect(Over state); bool updateOverState(Over newState); float64 overLevel(Over control) const; @@ -774,6 +779,16 @@ private: Ui::Animations::Simple _saveMsgAnimation; base::Timer _saveMsgTimer; + QString _chapterText; + QRect _chapterRect; + Ui::Animations::Simple _chapterAnimation; + base::Timer _chapterTimer; + struct ChapterArrow { + Ui::Animations::Simple animation; + int direction = 0; + }; + std::vector> _chapterArrows; + base::flat_map _animations; base::flat_map _animationOpacities; diff --git a/Telegram/SourceFiles/media/view/media_view_playback_controls.cpp b/Telegram/SourceFiles/media/view/media_view_playback_controls.cpp index 08522a6ca5..e680d3a909 100644 --- a/Telegram/SourceFiles/media/view/media_view_playback_controls.cpp +++ b/Telegram/SourceFiles/media/view/media_view_playback_controls.cpp @@ -24,6 +24,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace Media { namespace View { +namespace { + +constexpr auto kEps = 0.005; + +} // namespace PlaybackControls::PlaybackControls( QWidget *parent, @@ -303,6 +308,26 @@ bool PlaybackControls::hasTimestamps() const { return _timestampLabel != nullptr; } +auto PlaybackControls::nextTimestamp(float64 progress) const +-> std::optional { + for (const auto &ts : _timestamps) { + if (ts.position > progress + kEps) { + return ts; + } + } + return std::nullopt; +} + +auto PlaybackControls::prevTimestamp(float64 progress) const +-> std::optional { + for (auto i = int(_timestamps.size()) - 1; i >= 0; --i) { + if (_timestamps[i].position < progress - kEps) { + return _timestamps[i]; + } + } + return std::nullopt; +} + void PlaybackControls::updateTimestampLabel() { if (!_timestampLabel) { return; diff --git a/Telegram/SourceFiles/media/view/media_view_playback_controls.h b/Telegram/SourceFiles/media/view/media_view_playback_controls.h index 91c5272c3b..881c109a4e 100644 --- a/Telegram/SourceFiles/media/view/media_view_playback_controls.h +++ b/Telegram/SourceFiles/media/view/media_view_playback_controls.h @@ -72,6 +72,10 @@ public: void setTimestamps(std::vector timestamps); void setInFullScreen(bool inFullScreen); [[nodiscard]] bool hasTimestamps() const; + [[nodiscard]] std::optional nextTimestamp( + float64 progress) const; + [[nodiscard]] std::optional prevTimestamp( + float64 progress) const; [[nodiscard]] bool hasMenu() const; [[nodiscard]] bool dragging() const; diff --git a/Telegram/SourceFiles/media/view/media_view_playback_sponsored.cpp b/Telegram/SourceFiles/media/view/media_view_playback_sponsored.cpp index 805f31003a..8024ceed8c 100644 --- a/Telegram/SourceFiles/media/view/media_view_playback_sponsored.cpp +++ b/Telegram/SourceFiles/media/view/media_view_playback_sponsored.cpp @@ -331,7 +331,6 @@ PlaybackSponsored::Message::Message( this, _aboutSt.ripple, std::move(allowCloseAt))) { - _about->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); setMouseTracking(true); populate(); hide(); diff --git a/Telegram/SourceFiles/menu/menu_sponsored.cpp b/Telegram/SourceFiles/menu/menu_sponsored.cpp index 83340bcb03..49d723102b 100644 --- a/Telegram/SourceFiles/menu/menu_sponsored.cpp +++ b/Telegram/SourceFiles/menu/menu_sponsored.cpp @@ -249,6 +249,7 @@ void AboutBox( box, tr::lng_box_ok(), st::defaultActiveButton); + button->setTextTransform(Ui::RoundButtonTextTransform::ToUpper); button->resizeToWidth(box->width() - st.buttonPadding.left() - st.buttonPadding.left()); diff --git a/Telegram/SourceFiles/passport/passport_panel_edit_contact.cpp b/Telegram/SourceFiles/passport/passport_panel_edit_contact.cpp index 4f1251c9b3..4fb39508f8 100644 --- a/Telegram/SourceFiles/passport/passport_panel_edit_contact.cpp +++ b/Telegram/SourceFiles/passport/passport_panel_edit_contact.cpp @@ -148,8 +148,6 @@ void VerifyBox::setupControls( button->setFullWidth(w - small.left() - small.right()); }, button->lifetime()); button->setClickedCallback([=] { ::File::OpenUrl(openUrl); }); - button->setTextTransform( - Ui::RoundButton::TextTransform::NoTransform); } if (resend) { auto link = TextWithEntities{ tr::lng_cloud_password_resend(tr::now) }; @@ -238,6 +236,7 @@ PanelEditContact::PanelEditContact( this, tr::lng_passport_save_value(), st::passportPanelSaveValue) { + _done->setTextTransform(Ui::RoundButtonTextTransform::ToUpper); setupControls(data, existing); } diff --git a/Telegram/SourceFiles/passport/passport_panel_edit_document.cpp b/Telegram/SourceFiles/passport/passport_panel_edit_document.cpp index e8da525cb8..686d280ad2 100644 --- a/Telegram/SourceFiles/passport/passport_panel_edit_document.cpp +++ b/Telegram/SourceFiles/passport/passport_panel_edit_document.cpp @@ -222,6 +222,7 @@ PanelEditDocument::PanelEditDocument( this, tr::lng_passport_save_value(), st::passportPanelSaveValue) { + _done->setTextTransform(Ui::RoundButtonTextTransform::ToUpper); setupControls( &error, &data, @@ -248,6 +249,7 @@ PanelEditDocument::PanelEditDocument( this, tr::lng_passport_save_value(), st::passportPanelSaveValue) { + _done->setTextTransform(Ui::RoundButtonTextTransform::ToUpper); setupControls( nullptr, nullptr, @@ -271,6 +273,7 @@ PanelEditDocument::PanelEditDocument( this, tr::lng_passport_save_value(), st::passportPanelSaveValue) { + _done->setTextTransform(Ui::RoundButtonTextTransform::ToUpper); setupControls(&error, &data, nullptr, nullptr, {}, {}, {}); } diff --git a/Telegram/SourceFiles/passport/passport_panel_edit_scans.cpp b/Telegram/SourceFiles/passport/passport_panel_edit_scans.cpp index fcc631ce66..503cb74418 100644 --- a/Telegram/SourceFiles/passport/passport_panel_edit_scans.cpp +++ b/Telegram/SourceFiles/passport/passport_panel_edit_scans.cpp @@ -327,6 +327,7 @@ ScanButton::ScanButton( this, tr::lng_passport_delete_scan_undo(), _st.restore)) { + _restore->entity()->setTextTransform(Ui::RoundButtonTextTransform::ToUpper); _delete->toggle(!deleted, anim::type::instant); _restore->toggle(deleted, anim::type::instant); } diff --git a/Telegram/SourceFiles/passport/passport_panel_form.cpp b/Telegram/SourceFiles/passport/passport_panel_form.cpp index 4710c4a1ba..a1dd34c22c 100644 --- a/Telegram/SourceFiles/passport/passport_panel_form.cpp +++ b/Telegram/SourceFiles/passport/passport_panel_form.cpp @@ -41,6 +41,7 @@ PanelForm::PanelForm( this, tr::lng_passport_authorize(), st::passportPanelAuthorize) { + _submit->setTextTransform(Ui::RoundButtonTextTransform::ToUpper); setupControls(); } diff --git a/Telegram/SourceFiles/passport/passport_panel_password.cpp b/Telegram/SourceFiles/passport/passport_panel_password.cpp index 1df93f51ec..58b4ff3a2b 100644 --- a/Telegram/SourceFiles/passport/passport_panel_password.cpp +++ b/Telegram/SourceFiles/passport/passport_panel_password.cpp @@ -49,6 +49,7 @@ PanelAskPassword::PanelAskPassword( tr::lng_passport_password_placeholder()) , _submit(this, tr::lng_passport_next(), st::passportPasswordSubmit) , _forgot(this, tr::lng_signin_recover(tr::now), st::defaultLinkButton) { + _submit->setTextTransform(Ui::RoundButtonTextTransform::ToUpper); connect(_password, &Ui::PasswordInput::submitted, this, [=] { submit(); }); @@ -229,6 +230,7 @@ void PanelNoPassword::refreshBottom() { tr::lng_passport_password_create(), st::defaultBoxButton), style::al_top); + button->setTextTransform(Ui::RoundButtonTextTransform::ToUpper); button->addClickHandler([=] { _controller->setupPassword(); }); @@ -241,8 +243,6 @@ void PanelNoPassword::refreshBottom() { container, tr::lng_cancel(), st::defaultBoxButton); - cancel->setTextTransform( - Ui::RoundButton::TextTransform::NoTransform); cancel->addClickHandler([=] { _controller->cancelPasswordSubmit(); }); @@ -250,8 +250,6 @@ void PanelNoPassword::refreshBottom() { container, tr::lng_passport_email_validate(), st::defaultBoxButton); - validate->setTextTransform( - Ui::RoundButton::TextTransform::NoTransform); validate->addClickHandler([=] { _controller->validateRecoveryEmail(); }); diff --git a/Telegram/SourceFiles/payments/ui/payments_edit_card.cpp b/Telegram/SourceFiles/payments/ui/payments_edit_card.cpp index 7dbcbee985..0c2aac434e 100644 --- a/Telegram/SourceFiles/payments/ui/payments_edit_card.cpp +++ b/Telegram/SourceFiles/payments/ui/payments_edit_card.cpp @@ -221,6 +221,8 @@ EditCard::EditCard( this, tr::lng_cancel(), st::paymentsPanelButton) { + _submit->setTextTransform(RoundButtonTextTransform::ToUpper); + _cancel->setTextTransform(RoundButtonTextTransform::ToUpper); setupControls(); } diff --git a/Telegram/SourceFiles/payments/ui/payments_edit_information.cpp b/Telegram/SourceFiles/payments/ui/payments_edit_information.cpp index 7f15574587..aa409b72c2 100644 --- a/Telegram/SourceFiles/payments/ui/payments_edit_information.cpp +++ b/Telegram/SourceFiles/payments/ui/payments_edit_information.cpp @@ -52,6 +52,8 @@ EditInformation::EditInformation( this, tr::lng_cancel(), st::paymentsPanelButton) { + _submit->setTextTransform(RoundButtonTextTransform::ToUpper); + _cancel->setTextTransform(RoundButtonTextTransform::ToUpper); setupControls(); } diff --git a/Telegram/SourceFiles/payments/ui/payments_form_summary.cpp b/Telegram/SourceFiles/payments/ui/payments_form_summary.cpp index 00e5ec49eb..bb178a0530 100644 --- a/Telegram/SourceFiles/payments/ui/payments_form_summary.cpp +++ b/Telegram/SourceFiles/payments/ui/payments_form_summary.cpp @@ -170,13 +170,10 @@ void FormSummary::setupControls() { setupContent(_layout.get()); if (_submit) { - _submit->setTextTransform( - Ui::RoundButton::TextTransform::NoTransform); _submit->addClickHandler([=] { _delegate->panelSubmit(); }); } - _cancel->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); _cancel->addClickHandler([=] { _delegate->panelRequestClose(); }); diff --git a/Telegram/SourceFiles/platform/mac/translate_provider_mac.mm b/Telegram/SourceFiles/platform/mac/translate_provider_mac.mm index f686dc7771..ff85d63bb5 100644 --- a/Telegram/SourceFiles/platform/mac/translate_provider_mac.mm +++ b/Telegram/SourceFiles/platform/mac/translate_provider_mac.mm @@ -7,6 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "platform/mac/translate_provider_mac.h" +#ifndef TDESKTOP_DISABLE_SWIFT6 + #include "base/weak_ptr.h" #include "spellcheck/platform/platform_language.h" #include "translate_provider_mac_swift_bridge.h" @@ -102,4 +104,19 @@ bool IsTranslateProviderAvailable() { return TranslateProviderMacSwiftIsAvailable(); } +#else // TDESKTOP_DISABLE_SWIFT6 + +// Local on-device translation disabled (no Swift 6). +namespace Platform { + +std::unique_ptr CreateTranslateProvider() { + return nullptr; +} + +bool IsTranslateProviderAvailable() { + return false; +} + +#endif // TDESKTOP_DISABLE_SWIFT6 + } // namespace Platform diff --git a/Telegram/SourceFiles/platform/mac/tray_mac.mm b/Telegram/SourceFiles/platform/mac/tray_mac.mm index cd4af761df..6f2d565826 100644 --- a/Telegram/SourceFiles/platform/mac/tray_mac.mm +++ b/Telegram/SourceFiles/platform/mac/tray_mac.mm @@ -174,7 +174,7 @@ void UpdateIcon(const NSStatusItem *status) { return; } - const auto appearance = [NSApp effectiveAppearance]; + const auto appearance = status.button.effectiveAppearance; const auto darkMode = [[appearance.name lowercaseString] containsString:@"dark"]; diff --git a/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_common.cpp b/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_common.cpp index b9917e268b..4418d6415a 100644 --- a/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_common.cpp +++ b/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_common.cpp @@ -232,7 +232,6 @@ not_null AddDoneButton( st::changePhoneButton), st::settingLocalPasscodeButtonPadding, style::al_top); - button->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); return button; } diff --git a/Telegram/SourceFiles/settings/detailed_settings_button.cpp b/Telegram/SourceFiles/settings/detailed_settings_button.cpp index 7c305fed52..ffaf8e19bb 100644 --- a/Telegram/SourceFiles/settings/detailed_settings_button.cpp +++ b/Telegram/SourceFiles/settings/detailed_settings_button.cpp @@ -16,6 +16,10 @@ DetailedSettingsButton::DetailedSettingsButton( , _style(rowStyle) , _title(0) , _description(0) +, _toggle(std::make_unique( + _style.button.toggle, + false, + [this] { rtlupdate(toggleRect()); })) , _iconForeground(icon.icon) , _iconBackground(icon.background) , _iconBackgroundBrush(std::move(icon.backgroundBrush)) { @@ -38,10 +42,6 @@ DetailedSettingsButton::DetailedSettingsButton( kDefaultTextOptions); refreshLayout(); }, lifetime()); - _toggle = std::make_unique( - _style.button.toggle, - false, - [this] { rtlupdate(toggleRect()); }); addClickHandler([=] { if (!_toggleLocked) { _toggle->setChecked(!_toggle->checked(), anim::type::normal); diff --git a/Telegram/SourceFiles/settings/sections/settings_credits.cpp b/Telegram/SourceFiles/settings/sections/settings_credits.cpp index 942f63d67a..c2d1c009a2 100644 --- a/Telegram/SourceFiles/settings/sections/settings_credits.cpp +++ b/Telegram/SourceFiles/settings/sections/settings_credits.cpp @@ -534,7 +534,6 @@ void Credits::setupContent() { lt_emoji, rpl::single(Ui::Text::SingleCustomEmoji(u"+"_q)), tr::marked))); - button->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); const auto show = controller()->uiShow(); if (isCurrency) { const auto url = tr::lng_suggest_low_ton_fragment_url(tr::now); @@ -869,6 +868,7 @@ void BuildCurrencyWithdrawalSection( stButton), st::boxRowPadding, style::al_top); + button->setTextTransform(Ui::RoundButtonTextTransform::ToUpper); const auto label = Ui::CreateChild( button, diff --git a/Telegram/SourceFiles/settings/sections/settings_folders.cpp b/Telegram/SourceFiles/settings/sections/settings_folders.cpp index 952c17ad41..3ea34301bc 100644 --- a/Telegram/SourceFiles/settings/sections/settings_folders.cpp +++ b/Telegram/SourceFiles/settings/sections/settings_folders.cpp @@ -186,9 +186,7 @@ FilterRowButton::FilterRowButton( tr::lng_filters_recommended_add(), st::settingsFilterAddRecommended) , _state(description.isEmpty() ? State::Normal : State::Suggested) { - _restore.setTextTransform(Ui::RoundButton::TextTransform::NoTransform); _restore.setFullRadius(true); - _add.setTextTransform(Ui::RoundButton::TextTransform::NoTransform); _add.setFullRadius(true); setup(filter, description.isEmpty() ? ComputeCountString(session, filter) diff --git a/Telegram/SourceFiles/settings/sections/settings_local_passcode.cpp b/Telegram/SourceFiles/settings/sections/settings_local_passcode.cpp index 7b44182a85..ac204ade07 100644 --- a/Telegram/SourceFiles/settings/sections/settings_local_passcode.cpp +++ b/Telegram/SourceFiles/settings/sections/settings_local_passcode.cpp @@ -212,7 +212,6 @@ void LocalPasscodeEnter::setupContent() { st::changePhoneButton), st::settingLocalPasscodeButtonPadding, style::al_top); - button->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); button->setClickedCallback([=] { const auto newText = newPasscode->text(); const auto reenterText = reenterPasscode diff --git a/Telegram/SourceFiles/settings/sections/settings_main.cpp b/Telegram/SourceFiles/settings/sections/settings_main.cpp index 0a8814516d..92dc98fdd1 100644 --- a/Telegram/SourceFiles/settings/sections/settings_main.cpp +++ b/Telegram/SourceFiles/settings/sections/settings_main.cpp @@ -896,7 +896,6 @@ void SetupValidatePhoneNumberSuggestion( wrap, tr::lng_box_yes(), st::inviteLinkButton); - yes->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); yes->setClickedCallback([=] { controller->session().promoSuggestions().dismiss( kSugValidatePhone.utf8()); @@ -906,7 +905,6 @@ void SetupValidatePhoneNumberSuggestion( wrap, tr::lng_box_no(), st::inviteLinkButton); - no->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); no->setClickedCallback([=] { const auto sharedLabel = std::make_shared>(); const auto height = st::boxLabel.style.font->height; @@ -998,7 +996,6 @@ void SetupValidatePasswordSuggestion( wrap, tr::lng_settings_suggestion_password_yes(), st::inviteLinkButton); - yes->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); yes->setClickedCallback([=] { controller->session().promoSuggestions().dismiss( Data::PromoSuggestions::SugValidatePassword()); @@ -1008,7 +1005,6 @@ void SetupValidatePasswordSuggestion( wrap, tr::lng_settings_suggestion_password_no(), st::inviteLinkButton); - no->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); no->setClickedCallback([=] { showOther(Settings::CloudPasswordSuggestionInputId()); }); diff --git a/Telegram/SourceFiles/settings/sections/settings_passkeys.cpp b/Telegram/SourceFiles/settings/sections/settings_passkeys.cpp index f762a3a0df..9d0f52dd8a 100644 --- a/Telegram/SourceFiles/settings/sections/settings_passkeys.cpp +++ b/Telegram/SourceFiles/settings/sections/settings_passkeys.cpp @@ -455,7 +455,6 @@ void PasskeysNoneBox( : tr::lng_settings_passkeys_none_button_unsupported(), st::defaultActiveButton); const auto createButton = button.data(); - button->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); button->resizeToWidth(box->width() - st.buttonPadding.left() - st.buttonPadding.left()); diff --git a/Telegram/SourceFiles/settings/settings_credits_graphics.cpp b/Telegram/SourceFiles/settings/settings_credits_graphics.cpp index c2d14bf90a..9ac4584e40 100644 --- a/Telegram/SourceFiles/settings/settings_credits_graphics.cpp +++ b/Telegram/SourceFiles/settings/settings_credits_graphics.cpp @@ -3341,13 +3341,12 @@ void AddWithdrawalWidget( buttonsContainer, rpl::never(), stButton); + button->setTextTransform(Ui::RoundButtonTextTransform::ToUpper); const auto buttonCredits = Ui::CreateChild( buttonsContainer, tr::lng_bot_earn_balance_button_buy_ads(), stButton); - buttonCredits->setTextTransform( - Ui::RoundButton::TextTransform::NoTransform); { const auto icon = Ui::CreateChild(buttonCredits); const auto &st = st::msgBotKbUrlIcon; diff --git a/Telegram/SourceFiles/settings/settings_experimental.cpp b/Telegram/SourceFiles/settings/settings_experimental.cpp index 0c281c52d5..3429d19c2c 100644 --- a/Telegram/SourceFiles/settings/settings_experimental.cpp +++ b/Telegram/SourceFiles/settings/settings_experimental.cpp @@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/vertical_list.h" #include "ui/gl/gl_detection.h" #include "ui/chat/chat_style_radius.h" +#include "ui/controls/compose_ai_button_factory.h" #include "base/options.h" #include "boxes/moderate_messages_box.h" #include "core/application.h" @@ -233,6 +234,7 @@ void SetupExperimental( addToggle(kModerateCommonGroups); addToggle(kForceComposeSearchOneColumn); addToggle(ChatHelpers::kOptionUnlimitedRecentStickers); + addToggle(Ui::kOptionHideAiButton); } } // namespace diff --git a/Telegram/SourceFiles/statistics/chart_widget.cpp b/Telegram/SourceFiles/statistics/chart_widget.cpp index 0c85b9f4a3..600299e168 100644 --- a/Telegram/SourceFiles/statistics/chart_widget.cpp +++ b/Telegram/SourceFiles/statistics/chart_widget.cpp @@ -1324,8 +1324,6 @@ void ChartWidget::processLocalZoom(int xIndex) { 0, (header->height() - zoomOutButton->height()) / 2); zoomOutButton->show(); - zoomOutButton->setTextTransform( - Ui::RoundButton::TextTransform::NoTransform); zoomOutButton->setClickedCallback([=] { auto lifetime = _localZoomLifetime.make_state(); const auto animation = lifetime->make_state(); @@ -1534,8 +1532,6 @@ void ChartWidget::setZoomedChartData( customHeader, tr::lng_stats_zoom_out(), st::statisticsHeaderButton); - zoomOutButton->setTextTransform( - Ui::RoundButton::TextTransform::NoTransform); zoomOutButton->moveToRight( 0, (customHeader->height() - zoomOutButton->height()) / 2); diff --git a/Telegram/SourceFiles/ui/boxes/collectible_info_box.cpp b/Telegram/SourceFiles/ui/boxes/collectible_info_box.cpp index 22ab7e05db..9f9ec3ed5f 100644 --- a/Telegram/SourceFiles/ui/boxes/collectible_info_box.cpp +++ b/Telegram/SourceFiles/ui/boxes/collectible_info_box.cpp @@ -232,7 +232,6 @@ void CollectibleInfoBox( tr::lng_collectible_learn_more(), st::collectibleMore), st::collectibleMorePadding); - more->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); more->setClickedCallback([url = info.url] { File::OpenUrl(url); }); @@ -245,7 +244,6 @@ void CollectibleInfoBox( phrase(), st::collectibleCopy); const auto copy = owned.data(); - copy->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); copy->setClickedCallback([copyCallback] { copyCallback(true); }); diff --git a/Telegram/SourceFiles/ui/boxes/confirm_phone_box.cpp b/Telegram/SourceFiles/ui/boxes/confirm_phone_box.cpp index ec309d5ea6..6d8526f92a 100644 --- a/Telegram/SourceFiles/ui/boxes/confirm_phone_box.cpp +++ b/Telegram/SourceFiles/ui/boxes/confirm_phone_box.cpp @@ -34,8 +34,6 @@ ConfirmPhoneBox::ConfirmPhoneBox( tr::lng_intro_fragment_button(), st::fragmentBoxButton); _fragment->setClickedCallback([=] { File::OpenUrl(openUrl); }); - _fragment->setTextTransform( - Ui::RoundButton::TextTransform::NoTransform); } if (timeout) { _call.setStatus({ Ui::SentCodeCall::State::Waiting, *timeout }); diff --git a/Telegram/SourceFiles/ui/boxes/emoji_stake_box.cpp b/Telegram/SourceFiles/ui/boxes/emoji_stake_box.cpp index 1cb6d28242..6b32fd3c0d 100644 --- a/Telegram/SourceFiles/ui/boxes/emoji_stake_box.cpp +++ b/Telegram/SourceFiles/ui/boxes/emoji_stake_box.cpp @@ -387,6 +387,7 @@ void AddStakePresets( wrap, rpl::single(FormatTonAmount(nanoTon).full + diamond), st::stakePresetButton); + button->setTextTransform(RoundButtonTextTransform::ToUpper); button->setClickedCallback([=] { callback(nanoTon); }); diff --git a/Telegram/SourceFiles/ui/boxes/show_or_premium_box.cpp b/Telegram/SourceFiles/ui/boxes/show_or_premium_box.cpp index 0cc7c8faeb..fd1fb8ecfc 100644 --- a/Telegram/SourceFiles/ui/boxes/show_or_premium_box.cpp +++ b/Telegram/SourceFiles/ui/boxes/show_or_premium_box.cpp @@ -159,7 +159,6 @@ void ShowOrPremiumBox( std::move(skin.showButton), st::showOrShowButton), buttonPadding); - show->setTextTransform(RoundButton::TextTransform::NoTransform); box->addRow( MakeShowOrLabel(box, std::move(skin.orPremium)), st::showOrLabelPadding + buttonPadding, diff --git a/Telegram/SourceFiles/ui/chat/attach/attach_abstract_single_media_preview.cpp b/Telegram/SourceFiles/ui/chat/attach/attach_abstract_single_media_preview.cpp index e1629203b2..d312bbc458 100644 --- a/Telegram/SourceFiles/ui/chat/attach/attach_abstract_single_media_preview.cpp +++ b/Telegram/SourceFiles/ui/chat/attach/attach_abstract_single_media_preview.cpp @@ -259,7 +259,7 @@ void AbstractSingleMediaPreview::mouseMoveEvent(QMouseEvent *e) { void AbstractSingleMediaPreview::mouseReleaseEvent(QMouseEvent *e) { if (base::take(_pressed) && isOverPreview(e->pos())) { - if (isPhoto()) { + if (e->button() == Qt::LeftButton && isPhoto()) { _photoEditorRequests.fire({}); } } diff --git a/Telegram/SourceFiles/ui/chat/attach/attach_album_preview.cpp b/Telegram/SourceFiles/ui/chat/attach/attach_album_preview.cpp index 1642dc0848..6082a4bb24 100644 --- a/Telegram/SourceFiles/ui/chat/attach/attach_album_preview.cpp +++ b/Telegram/SourceFiles/ui/chat/attach/attach_album_preview.cpp @@ -618,7 +618,7 @@ void AlbumPreview::mouseReleaseEvent(QMouseEvent *e) { } else if (const auto thumb = base::take(_pressedThumb)) { const auto was = _pressedButtonType; const auto now = thumb->buttonTypeFromPoint(e->pos()); - if (e->button() != Qt::RightButton && was == now) { + if (e->button() == Qt::LeftButton && was == now) { thumbButtonsCallback(thumb, now); } } diff --git a/Telegram/SourceFiles/ui/chat/choose_theme_controller.cpp b/Telegram/SourceFiles/ui/chat/choose_theme_controller.cpp index 3a0924e134..68d3770400 100644 --- a/Telegram/SourceFiles/ui/chat/choose_theme_controller.cpp +++ b/Telegram/SourceFiles/ui/chat/choose_theme_controller.cpp @@ -292,12 +292,10 @@ void ChooseThemeController::initButtons() { controls, tr::lng_chat_theme_apply(), st::defaultLightButton); - apply->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); const auto choose = CreateChild( controls, tr::lng_chat_theme_change_wallpaper(), st::defaultLightButton); - choose->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); const auto &margin = st::chatThemeButtonMargin; controls->resize( diff --git a/Telegram/SourceFiles/ui/chat/group_call_bar.cpp b/Telegram/SourceFiles/ui/chat/group_call_bar.cpp index d8740e3be6..13481b99dd 100644 --- a/Telegram/SourceFiles/ui/chat/group_call_bar.cpp +++ b/Telegram/SourceFiles/ui/chat/group_call_bar.cpp @@ -191,7 +191,6 @@ void GroupCallBar::refreshScheduledProcess() { _inner.get(), tr::lng_group_call_join(), st::groupCallTopBarJoin); - _join->setTextTransform(RoundButton::TextTransform::NoTransform); setupRightButton(_join.get()); } } else if (!_scheduledProcess) { @@ -201,6 +200,7 @@ void GroupCallBar::refreshScheduledProcess() { _inner.get(), _scheduledProcess->text(GroupCallScheduledLeft::Negative::Show), st::groupCallTopBarOpen); + _open->setTextTransform(RoundButtonTextTransform::ToUpper); setupRightButton(_open.get()); _open->widthValue( ) | rpl::on_next([=] { diff --git a/Telegram/SourceFiles/ui/controls/call_mute_button.cpp b/Telegram/SourceFiles/ui/controls/call_mute_button.cpp index 1493592c76..a8f9c2745f 100644 --- a/Telegram/SourceFiles/ui/controls/call_mute_button.cpp +++ b/Telegram/SourceFiles/ui/controls/call_mute_button.cpp @@ -200,6 +200,7 @@ public: const style::FlatLabel &st = st::defaultFlatLabel); int contentHeight() const; + void setMaxWidth(int width); private: void setText(const QString &text); @@ -212,6 +213,8 @@ private: Text::String _text; Text::String _previousText; + int _maxLabelWidth = 0; + Animations::Simple _animation; }; @@ -248,28 +251,36 @@ AnimatedLabel::AnimatedLabel( p.setOpacity(1. - progress); if (p.opacity()) { - _previousText.draw( + _previousText.drawElided( p, 0, anim::interpolate(center, diffHeight, progress), width(), + 1, style::al_center); } p.setOpacity(progress); if (p.opacity()) { - _text.draw( + _text.drawElided( p, 0, anim::interpolate(0, center, progress), width(), + 1, style::al_center); } }, lifetime()); } int AnimatedLabel::contentHeight() const { - return _st.style.font->height; + const auto lineHeight = _st.style.font->height; + if (!_maxLabelWidth) { + return lineHeight; + } + const auto textHeight = _text.countHeight(_maxLabelWidth); + const auto previousHeight = _previousText.countHeight(_maxLabelWidth); + return std::min(std::max(textHeight, previousHeight), lineHeight * 2); } void AnimatedLabel::setText(const QString &text) { @@ -279,9 +290,11 @@ void AnimatedLabel::setText(const QString &text) { _previousText = std::move(_text); _text = Ui::Text::String(_st.style, text, _options); - const auto width = std::max( - _st.style.font->width(_text.toString()), - _st.style.font->width(_previousText.toString())); + const auto width = _maxLabelWidth + ? _maxLabelWidth + : std::max( + _st.style.font->width(_text.toString()), + _st.style.font->width(_previousText.toString())); resize( width + _additionalHeight, contentHeight() + _additionalHeight * 2); @@ -290,6 +303,16 @@ void AnimatedLabel::setText(const QString &text) { _animation.start([=] { update(); }, 0., 1., _duration); } +void AnimatedLabel::setMaxWidth(int width) { + _maxLabelWidth = width; + if (!_text.isEmpty()) { + resize( + _maxLabelWidth + _additionalHeight, + contentHeight() + _additionalHeight * 2); + update(); + } +} + class BlobsWidget final : public RpWidget { public: BlobsWidget( @@ -614,6 +637,16 @@ void CallMuteButton::refreshLabels() { updateCenterLabelGeometry(my, size); }, _centerLabel->lifetime()); _centerLabel->setAttribute(Qt::WA_TransparentForMouseEvents); + + _content->sizeValue( + ) | rpl::map([](QSize size) { + return size.width(); + }) | rpl::distinct_until_changed( + ) | rpl::on_next([=](int w) { + _centerLabel->setMaxWidth(w); + _label->setMaxWidth(w); + _sublabel->setMaxWidth(w); + }, _centerLabel->lifetime()); } void CallMuteButton::refreshIcons() { diff --git a/Telegram/SourceFiles/ui/controls/compose_ai_button_factory.cpp b/Telegram/SourceFiles/ui/controls/compose_ai_button_factory.cpp index 03bf12010c..362c033ea6 100644 --- a/Telegram/SourceFiles/ui/controls/compose_ai_button_factory.cpp +++ b/Telegram/SourceFiles/ui/controls/compose_ai_button_factory.cpp @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "ui/controls/compose_ai_button_factory.h" +#include "base/options.h" #include "boxes/compose_ai_box.h" #include "history/view/controls/history_view_compose_ai_button.h" #include "lang/lang_keys.h" @@ -23,6 +24,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace Ui { +const char kOptionHideAiButton[] = "hide-ai-button"; + +base::options::toggle HideAiButtonOption({ + .id = kOptionHideAiButton, + .name = "Hide AI button", + .description = "Hide the AI Tools button in message compose fields.", +}); + bool HasEnoughLinesForAi( not_null session, not_null field) { diff --git a/Telegram/SourceFiles/ui/controls/compose_ai_button_factory.h b/Telegram/SourceFiles/ui/controls/compose_ai_button_factory.h index 5acb15b297..6044c8fe14 100644 --- a/Telegram/SourceFiles/ui/controls/compose_ai_button_factory.h +++ b/Telegram/SourceFiles/ui/controls/compose_ai_button_factory.h @@ -23,6 +23,8 @@ class ComposeAiButton; namespace Ui { +extern const char kOptionHideAiButton[]; + [[nodiscard]] bool HasEnoughLinesForAi( not_null session, not_null field); diff --git a/Telegram/SourceFiles/ui/controls/filter_link_header.cpp b/Telegram/SourceFiles/ui/controls/filter_link_header.cpp index e525783116..2d2c8b9fe1 100644 --- a/Telegram/SourceFiles/ui/controls/filter_link_header.cpp +++ b/Telegram/SourceFiles/ui/controls/filter_link_header.cpp @@ -495,6 +495,7 @@ object_ptr FilterLinkProcessButton( const auto st = &st::filterInviteBox.button; const auto badgeSt = &st::filterInviteButtonBadgeStyle; auto result = object_ptr(parent, rpl::single(u""_q), *st); + result->setTextTransform(RoundButtonTextTransform::ToUpper); struct Data { TextWithEntities text; diff --git a/Telegram/SourceFiles/ui/controls/invite_link_buttons.cpp b/Telegram/SourceFiles/ui/controls/invite_link_buttons.cpp index 83da0bc972..b798465965 100644 --- a/Telegram/SourceFiles/ui/controls/invite_link_buttons.cpp +++ b/Telegram/SourceFiles/ui/controls/invite_link_buttons.cpp @@ -42,13 +42,11 @@ void AddCopyShareLinkButtons( wrap, tr::lng_group_invite_copy(), st::inviteLinkCopy); - copy->setTextTransform(RoundButton::TextTransform::NoTransform); copy->setClickedCallback(copyLink); const auto share = CreateChild( wrap, tr::lng_group_invite_share(), st::inviteLinkShare); - share->setTextTransform(RoundButton::TextTransform::NoTransform); share->setClickedCallback(shareLink); wrap->widthValue( @@ -71,7 +69,6 @@ void AddReactivateLinkButton( tr::lng_group_invite_reactivate(), st::inviteLinkReactivate), st::inviteLinkButtonsPadding); - button->setTextTransform(RoundButton::TextTransform::NoTransform); button->setClickedCallback(editLink); } @@ -84,7 +81,6 @@ void AddDeleteLinkButton( tr::lng_group_invite_delete(), st::inviteLinkDelete), st::inviteLinkButtonsPadding); - button->setTextTransform(RoundButton::TextTransform::NoTransform); button->setClickedCallback(deleteLink); } diff --git a/Telegram/SourceFiles/ui/controls/location_picker.cpp b/Telegram/SourceFiles/ui/controls/location_picker.cpp index 0bd6ffbbc7..dd9c20334c 100644 --- a/Telegram/SourceFiles/ui/controls/location_picker.cpp +++ b/Telegram/SourceFiles/ui/controls/location_picker.cpp @@ -688,7 +688,6 @@ not_null SetupMapPlaceholder( tr::lng_maps_select_on_map(), st::pickLocationChooseOnMap); button->setFullRadius(true); - button->setTextTransform(RoundButton::TextTransform::NoTransform); button->setClickedCallback(choose); parent->sizeValue() | rpl::on_next([=](QSize size) { diff --git a/Telegram/SourceFiles/ui/controls/table_rows.cpp b/Telegram/SourceFiles/ui/controls/table_rows.cpp index 78054e3020..40692d96ea 100644 --- a/Telegram/SourceFiles/ui/controls/table_rows.cpp +++ b/Telegram/SourceFiles/ui/controls/table_rows.cpp @@ -110,7 +110,6 @@ ValueWithSmallButton MakeValueWithSmallButton( raw, std::move(buttonText), table->st().smallButton); - button->setTextTransform(RoundButton::TextTransform::NoTransform); if (handler) { button->setClickedCallback([button, handler = std::move(handler)] { handler(button); diff --git a/Telegram/SourceFiles/window/notifications_manager_default.cpp b/Telegram/SourceFiles/window/notifications_manager_default.cpp index 1f61d97bf4..d827648734 100644 --- a/Telegram/SourceFiles/window/notifications_manager_default.cpp +++ b/Telegram/SourceFiles/window/notifications_manager_default.cpp @@ -676,6 +676,8 @@ Notification::Notification( , _fromScheduled(fromScheduled) , _close(this, st::notifyClose) , _reply(this, tr::lng_notification_reply(), st::defaultBoxButton) { + _reply->setTextTransform(Ui::RoundButtonTextTransform::ToUpper); + Lang::Updated( ) | rpl::on_next([=] { refreshLang(); diff --git a/Telegram/SourceFiles/window/themes/window_theme_warning.cpp b/Telegram/SourceFiles/window/themes/window_theme_warning.cpp index bb53332f7f..4de7a3b8c8 100644 --- a/Telegram/SourceFiles/window/themes/window_theme_warning.cpp +++ b/Telegram/SourceFiles/window/themes/window_theme_warning.cpp @@ -31,10 +31,7 @@ WarningWidget::WarningWidget(QWidget *parent) , _secondsLeft(kWaitBeforeRevertMs / 1000) , _keepChanges(this, tr::lng_theme_keep_changes(), st::defaultBoxButton) , _revert(this, tr::lng_theme_revert(), st::defaultBoxButton) { - using TextTransform = Ui::RoundButton::TextTransform; - _keepChanges->setTextTransform(TextTransform::NoTransform); _keepChanges->setClickedCallback([] { KeepApplied(); }); - _revert->setTextTransform(TextTransform::NoTransform); _revert->setClickedCallback([] { Revert(); }); updateText(); } diff --git a/Telegram/SourceFiles/window/window_lock_widgets.cpp b/Telegram/SourceFiles/window/window_lock_widgets.cpp index 13160a7763..0ae535df96 100644 --- a/Telegram/SourceFiles/window/window_lock_widgets.cpp +++ b/Telegram/SourceFiles/window/window_lock_widgets.cpp @@ -102,8 +102,6 @@ PasscodeLockWidget::PasscodeLockWidget( , _logout(this, tr::lng_passcode_logout(tr::now)) { connect(_passcode, &Ui::MaskedInputField::changed, [=] { changed(); }); connect(_passcode, &Ui::MaskedInputField::submitted, [=] { submit(); }); - - _submit->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); _submit->setClickedCallback([=] { submit(); }); _logout->setClickedCallback([=] { window->showLogoutConfirmation(); diff --git a/Telegram/SourceFiles/window/window_peer_menu.cpp b/Telegram/SourceFiles/window/window_peer_menu.cpp index 1a45183627..824add532d 100644 --- a/Telegram/SourceFiles/window/window_peer_menu.cpp +++ b/Telegram/SourceFiles/window/window_peer_menu.cpp @@ -134,6 +134,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ayu/ui/context_menu/context_menu.h" #include "ayu/features/forward/ayu_forward.h" + namespace Window { namespace { @@ -2653,9 +2654,11 @@ object_ptr PrepareChooseRecipientBox( return ChooseRecipientBoxController::rowClicked(row); } const auto count = delegate()->peerListSelectedRowsCount(); - if (showLockedError(row) || (count && row->peer()->isForum())) { + const auto forum = row->peer()->isForum(); + const auto monoforum = row->peer()->isMonoforum(); + if (showLockedError(row) || (count && (forum || monoforum))) { return; - } else if (row->peer()->isForum()) { + } else if (forum || monoforum) { ChooseRecipientBoxController::rowClicked(row); } else { delegate()->peerListSetRowChecked(row, !row->checked()); @@ -2671,7 +2674,9 @@ object_ptr PrepareChooseRecipientBox( parent, row); } - if (!row->checked() && !row->peer()->isForum()) { + if (!row->checked() + && !row->peer()->isForum() + && !row->peer()->isMonoforum()) { auto menu = base::make_unique_q( parent, st::popupMenuWithIcons); @@ -2956,9 +2961,11 @@ base::weak_qptr ShowForwardMessagesBox( void rowClicked(not_null row) override final { const auto count = delegate()->peerListSelectedRowsCount(); - if (showLockedError(row) || (count && row->peer()->isForum())) { + const auto forum = row->peer()->isForum(); + const auto monoforum = row->peer()->isMonoforum(); + if (showLockedError(row) || (count && (forum || monoforum))) { return; - } else if (!count || row->peer()->isForum()) { + } else if (!count || forum || monoforum) { if (base::IsCtrlPressed() || base::IsShiftPressed()) { delegate()->peerListSetRowChecked(row, !row->checked()); _selectionChanges.fire({}); @@ -2974,7 +2981,9 @@ base::weak_qptr ShowForwardMessagesBox( base::unique_qptr rowContextMenu( QWidget *parent, not_null row) override final { - if (!row->checked() && !row->peer()->isForum()) { + if (!row->checked() + && !row->peer()->isForum() + && !row->peer()->isMonoforum()) { auto menu = base::make_unique_q( parent, st::popupMenuWithIcons); diff --git a/Telegram/SourceFiles/window/window_setup_email.cpp b/Telegram/SourceFiles/window/window_setup_email.cpp index f7f7b2ec84..48b71a1258 100644 --- a/Telegram/SourceFiles/window/window_setup_email.cpp +++ b/Telegram/SourceFiles/window/window_setup_email.cpp @@ -126,8 +126,6 @@ SetupEmailLockWidget::SetupEmailLockWidget( this, tr::lng_settings_logout(), st::defaultBoxButton); - _logoutButton->setTextTransform( - Ui::RoundButton::TextTransform::NoTransform); if (session) { session->promoSuggestions().setSetupEmailState( Data::SetupEmailState::SettingUpNoSkip); @@ -152,8 +150,6 @@ SetupEmailLockWidget::SetupEmailLockWidget( this, rpl::single(u"[DEBUG] Clear bio"_q), st::defaultBoxButton); - _debugButton->setTextTransform( - Ui::RoundButton::TextTransform::NoTransform); _debugButton->setClickedCallback([=] { session->api().saveSelfBio({}); }); @@ -230,8 +226,6 @@ SetupEmailLockWidget::SetupEmailLockWidget( st::changePhoneButton), st::boxRowPadding, style::al_top); - submit->setTextTransform( - Ui::RoundButton::TextTransform::NoTransform); _emailInput = emailInput; _errorLabel = errorLabel; diff --git a/Telegram/build/version b/Telegram/build/version index 8fce414cb2..ad6d505e3f 100644 --- a/Telegram/build/version +++ b/Telegram/build/version @@ -1,7 +1,7 @@ -AppVersion 6007002 +AppVersion 6007004 AppVersionStrMajor 6.7 -AppVersionStrSmall 6.7.2 -AppVersionStr 6.7.2 +AppVersionStrSmall 6.7.4 +AppVersionStr 6.7.4 BetaChannel 0 AlphaVersion 0 -AppVersionOriginal 6.7.2 +AppVersionOriginal 6.7.4 diff --git a/Telegram/cmake/telegram_options.cmake b/Telegram/cmake/telegram_options.cmake index 18fa73671a..402040d7f0 100644 --- a/Telegram/cmake/telegram_options.cmake +++ b/Telegram/cmake/telegram_options.cmake @@ -51,3 +51,8 @@ endif() if (DESKTOP_APP_SPECIAL_TARGET) target_compile_definitions(Telegram PRIVATE TDESKTOP_ALLOW_CLOSED_ALPHA) endif() + +option(DESKTOP_APP_DISABLE_SWIFT6 "Disable local on-device translation (build without Swift 6 on macOS)." OFF) +if (DESKTOP_APP_DISABLE_SWIFT6) + target_compile_definitions(Telegram PRIVATE TDESKTOP_DISABLE_SWIFT6) +endif() diff --git a/Telegram/lib_spellcheck b/Telegram/lib_spellcheck index 98fb380701..6fa694087b 160000 --- a/Telegram/lib_spellcheck +++ b/Telegram/lib_spellcheck @@ -1 +1 @@ -Subproject commit 98fb380701a1342dc913c4835f2f6683993fde5d +Subproject commit 6fa694087b25e0a2cf997dfca9e54d327e031743 diff --git a/Telegram/lib_translate b/Telegram/lib_translate index 2eb70a8cce..09c1072622 160000 --- a/Telegram/lib_translate +++ b/Telegram/lib_translate @@ -1 +1 @@ -Subproject commit 2eb70a8cceb80e96076ae8cc0e79fb049bce2fa1 +Subproject commit 09c10726220e6862ca91d39b5dec5119aa0177bc diff --git a/Telegram/lib_webview b/Telegram/lib_webview index d159fcea73..ab20dc8b33 160000 --- a/Telegram/lib_webview +++ b/Telegram/lib_webview @@ -1 +1 @@ -Subproject commit d159fcea73c878a84b65166240bdebbf54c04e50 +Subproject commit ab20dc8b33fde5a1d936ad96a65f735e76f051ae diff --git a/changelog.txt b/changelog.txt index 99834adccb..94170bcb3e 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,22 @@ +6.7.4 (07.04.26) + +- Add experimental option for "AI Tools" button. +- Jump between markers with Alt+Arrows in video player. +- Cocoon info button in AI Tools box. +- Show warning for unofficial app builds. +- Allow text emojify without selecting a style. +- Accept also base64 (non-url) proxy secrets. +- Use tg:// deeplinks for proxy share links. +- Fix newbot deeplink parsing with trailing slash and unicode names. +- Fix file reference refresh for user, group and channel photos. +- Fix stale macOS tray icon colors after appearance switches. +- Fix tooltip crash in top peers selector with small width. +- Fix preserving markers after video quality switch in media view. + +6.7.3 (04.04.26) + +- Fix launch on older macOS versions. + 6.7.2 (03.04.26) - System audio capture for desktop sharing on macOS.