diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 2afe27cfa8..7f64054464 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -1163,6 +1163,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_proxy_menu_restore" = "Restore"; "lng_proxy_edit_share" = "Share"; "lng_proxy_edit_share_qr_box_title" = "Share proxy with QR code"; +"lng_proxy_edit_share_list_button" = "Share Proxy List"; +"lng_proxy_edit_share_list_toast" = "Proxy List copied to clipboard."; "lng_proxy_address_label" = "Socket address"; "lng_proxy_credentials_optional" = "Credentials (optional)"; "lng_proxy_credentials" = "Credentials"; diff --git a/Telegram/SourceFiles/boxes/connection_box.cpp b/Telegram/SourceFiles/boxes/connection_box.cpp index ef3dc0c2a4..3b48cf123f 100644 --- a/Telegram/SourceFiles/boxes/connection_box.cpp +++ b/Telegram/SourceFiles/boxes/connection_box.cpp @@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "lang/lang_keys.h" #include "main/main_account.h" #include "mtproto/facade.h" +#include "settings/settings_common.h" #include "storage/localstorage.h" #include "ui/basic_click_handlers.h" #include "ui/boxes/confirm_box.h" @@ -45,6 +46,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "styles/style_chat_helpers.h" #include "styles/style_info.h" #include "styles/style_menu_icons.h" +#include "styles/style_settings.h" #include #include @@ -67,6 +69,19 @@ using ProxyData = MTP::ProxyData; return urls; } +[[nodiscard]] QString ProxyDataToString(const ProxyData &proxy) { + using Type = ProxyData::Type; + return u"https://t.me/"_q + + (proxy.type == Type::Socks5 ? "socks" : "proxy") + + "?server=" + proxy.host + "&port=" + QString::number(proxy.port) + + ((proxy.type == Type::Socks5 && !proxy.user.isEmpty()) + ? "&user=" + qthelp::url_encode(proxy.user) : "") + + ((proxy.type == Type::Socks5 && !proxy.password.isEmpty()) + ? "&pass=" + qthelp::url_encode(proxy.password) : "") + + ((proxy.type == Type::Mtproto && !proxy.password.isEmpty()) + ? "&secret=" + proxy.password : ""); +} + [[nodiscard]] ProxyData ProxyDataFromFields( ProxyData::Type type, const QMap &fields) { @@ -825,6 +840,23 @@ void ProxiesBox::setupContent() { refreshProxyForCalls(); _proxyForCalls->finishAnimating(); + { + const auto wrap = inner->add( + object_ptr>( + inner, + object_ptr(inner))); + const auto shareList = Settings::AddButtonWithIcon( + wrap->entity(), + tr::lng_proxy_edit_share_list_button(), + st::settingsButton, + { &st::menuIconCopy }); + shareList->setClickedCallback([=] { + _controller->shareItems(); + }); + wrap->toggleOn(_controller->listShareableChanges()); + wrap->finishAnimating(); + } + inner->resizeToWidth(st::boxWideWidth); inner->heightValue( @@ -1451,6 +1483,20 @@ void ProxiesBoxController::shareItem(int id, bool qr) { share(findById(id)->data, qr); } +void ProxiesBoxController::shareItems() { + auto result = QString(); + for (const auto &item : _list) { + if (!item.deleted) { + result += ProxyDataToString(item.data) + '\n' + '\n'; + } + } + if (result.isEmpty()) { + return; + } + QGuiApplication::clipboard()->setText(result); + _show->showToast(tr::lng_proxy_edit_share_list_toast(tr::now)); +} + void ProxiesBoxController::applyItem(int id) { auto item = findById(id); if (_settings.isEnabled() && (_settings.selected() == item->data)) { @@ -1657,6 +1703,17 @@ auto ProxiesBoxController::views() const -> rpl::producer { return _views.events(); } +rpl::producer ProxiesBoxController::listShareableChanges() const { + return _views.events_starting_with(ItemView()) | rpl::map([=] { + for (const auto &item : _list) { + if (!item.deleted) { + return true; + } + } + return false; + }); +} + void ProxiesBoxController::updateView(const Item &item) { const auto selected = (_settings.selected() == item.data); const auto deleted = item.deleted; @@ -1697,15 +1754,7 @@ void ProxiesBoxController::share(const ProxyData &proxy, bool qr) { if (proxy.type == Type::Http) { return; } - const auto link = u"https://t.me/"_q - + (proxy.type == Type::Socks5 ? "socks" : "proxy") - + "?server=" + proxy.host + "&port=" + QString::number(proxy.port) - + ((proxy.type == Type::Socks5 && !proxy.user.isEmpty()) - ? "&user=" + qthelp::url_encode(proxy.user) : "") - + ((proxy.type == Type::Socks5 && !proxy.password.isEmpty()) - ? "&pass=" + qthelp::url_encode(proxy.password) : "") - + ((proxy.type == Type::Mtproto && !proxy.password.isEmpty()) - ? "&secret=" + proxy.password : ""); + const auto link = ProxyDataToString(proxy); if (qr) { _show->showBox(Box([=](not_null box) { Ui::FillPeerQrBox(box, nullptr, link, rpl::single(QString())); diff --git a/Telegram/SourceFiles/boxes/connection_box.h b/Telegram/SourceFiles/boxes/connection_box.h index 5c92904b79..27a7cc6b7a 100644 --- a/Telegram/SourceFiles/boxes/connection_box.h +++ b/Telegram/SourceFiles/boxes/connection_box.h @@ -74,6 +74,7 @@ public: void deleteItem(int id); void restoreItem(int id); void shareItem(int id, bool qr); + void shareItems(); void applyItem(int id); object_ptr editItemBox(int id); object_ptr addNewItemBox(); @@ -87,6 +88,8 @@ public: rpl::producer views() const; + rpl::producer listShareableChanges() const; + ~ProxiesBoxController(); private: