From e29458e8aa7b8617a8ee9ea79e2eeaf0c08be5aa Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Fri, 5 Jun 2026 13:41:02 +0300 Subject: [PATCH] Added dragging proxy links onto window to open connection box. --- Telegram/Resources/langs/lang.strings | 3 + .../SourceFiles/history/history_drag_area.cpp | 125 ++++++++++++++++++ .../SourceFiles/history/history_drag_area.h | 4 + Telegram/SourceFiles/mainwidget.cpp | 11 ++ Telegram/SourceFiles/mainwindow.cpp | 4 + 5 files changed, 147 insertions(+) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 83f36712ae..323e6090ec 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -5565,6 +5565,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_drag_to_send_files" = "to send them as documents"; "lng_drag_to_send_media" = "to send them as media files"; +"lng_drag_proxy_here" = "Connect to a proxy"; +"lng_drag_proxy_about" = "Drop the link here"; + "lng_selected_clear" = "Cancel"; "lng_selected_delete" = "Delete"; "lng_selected_forward" = "Forward"; diff --git a/Telegram/SourceFiles/history/history_drag_area.cpp b/Telegram/SourceFiles/history/history_drag_area.cpp index cbfd5e74d2..c4eed69925 100644 --- a/Telegram/SourceFiles/history/history_drag_area.cpp +++ b/Telegram/SourceFiles/history/history_drag_area.cpp @@ -24,8 +24,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "apiwrap.h" #include "mainwidget.h" #include "storage/storage_media_prepare.h" +#include "core/application.h" +#include "core/mime_type.h" +#include "core/local_url_handlers.h" #include "styles/style_chat_helpers.h" #include "styles/style_layers.h" +#include "styles/style_window.h" namespace { @@ -37,6 +41,33 @@ constexpr auto kDragAreaEvents = { QEvent::Leave, }; +[[nodiscard]] QString DetectProxyLink(const QMimeData *data) { + if (!data) { + return QString(); + } + const auto check = [](const QString &text) -> QString { + const auto local = Core::TryConvertUrlToLocal(text.trimmed()); + const auto proxy = [&](const QString &prefix) { + return local.startsWith(prefix, Qt::CaseInsensitive) + && (local.size() > prefix.size()); + }; + return (proxy(u"tg://proxy?"_q) || proxy(u"tg://socks?"_q)) + ? local + : QString(); + }; + for (const auto &url : Core::ReadMimeUrls(data)) { + if (auto result = check(url.toString()); !result.isEmpty()) { + return result; + } + } + if (const auto text = Core::ReadMimeText(data); !text.isEmpty()) { + if (auto result = check(text); !result.isEmpty()) { + return result; + } + } + return QString(); +} + } // namespace DragArea::Areas DragArea::SetupDragAreaToContainer( @@ -261,6 +292,100 @@ DragArea::Areas DragArea::SetupDragAreaToContainer( }; } +void DragArea::SetupProxyDropArea( + not_null container, + Fn connectProxy) { + auto &lifetime = container->lifetime(); + container->setAcceptDrops(true); + + const auto area = Ui::CreateChild(container.get()); + area->hide(); + area->raise(); + area->setText( + tr::lng_drag_proxy_here(tr::now), + tr::lng_drag_proxy_about(tr::now)); + + const auto updateGeometry = [=] { + const auto margin = st::dragMargin; + const auto width = st::windowMinWidth + - margin.left() + - margin.right(); + area->setGeometry( + (container->width() - width) / 2, + margin.top(), + width, + container->height() / 3 - margin.top()); + }; + container->sizeValue( + ) | rpl::on_next([=](QSize) { + updateGeometry(); + }, lifetime); + + const auto reset = [=] { + if (!area->isHidden()) { + area->otherLeave(); + } + }; + + const auto dragEnterEvent = [=](QDragEnterEvent *e) { + if (Core::App().passcodeLocked() + || DetectProxyLink(e->mimeData()).isEmpty()) { + reset(); + return; + } + updateGeometry(); + area->raise(); + area->otherEnter(); + e->setDropAction(Qt::IgnoreAction); + e->accept(); + }; + + const auto dropEvent = [=](QDropEvent *e) { + area->hideFast(); + e->setDropAction(Qt::IgnoreAction); + e->accept(); + }; + + const auto processDragEvents = [=](not_null event) { + switch (event->type()) { + case QEvent::DragEnter: + dragEnterEvent(static_cast(event.get())); + return true; + case QEvent::DragLeave: + reset(); + return true; + case QEvent::Drop: + dropEvent(static_cast(event.get())); + return true; + } + return false; + }; + + container->events( + ) | rpl::filter([=](not_null event) { + return ranges::contains(kDragAreaEvents, event->type()); + }) | rpl::on_next([=](not_null event) { + const auto type = event->type(); + if (processDragEvents(event)) { + return; + } else if (type == QEvent::Leave + || type == QEvent::MouseButtonRelease) { + reset(); + } + }, lifetime); + + base::install_event_filter(area, [=](not_null event) { + processDragEvents(event); + return base::EventFilterResult::Continue; + }); + + area->setDroppedCallback([=](const QMimeData *data) { + if (const auto local = DetectProxyLink(data); !local.isEmpty()) { + connectProxy(local); + } + }); +} + DragArea::DragArea(QWidget *parent) : Ui::RpWidget(parent) { setMouseTracking(true); setAcceptDrops(true); diff --git a/Telegram/SourceFiles/history/history_drag_area.h b/Telegram/SourceFiles/history/history_drag_area.h index c9c075c5af..8fc17b0108 100644 --- a/Telegram/SourceFiles/history/history_drag_area.h +++ b/Telegram/SourceFiles/history/history_drag_area.h @@ -34,6 +34,10 @@ public: CallbackComputeState &&computeState = nullptr, bool hideSubtext = false); + static void SetupProxyDropArea( + not_null container, + Fn connectProxy); + void setText(const QString &text, const QString &subtext); void otherEnter(); diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 36f856249a..af5e899b62 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -53,6 +53,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "apiwrap.h" #include "dialogs/dialogs_widget.h" #include "history/history_widget.h" +#include "history/history_drag_area.h" #include "history/history_item_helpers.h" // GetErrorForSending. #include "history/view/media/history_view_media.h" #include "history/view/history_view_chat_section.h" @@ -75,6 +76,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "core/update_checker.h" #include "core/shortcuts.h" #include "core/application.h" +#include "core/click_handler_types.h" #include "core/changelogs.h" #include "core/mime_type.h" #include "calls/calls_call.h" @@ -436,6 +438,15 @@ MainWidget::MainWidget( cSetOtherOnline(0); session().data().stickers().notifySavedGifsUpdated(); + + const auto weak = base::make_weak(controller); + DragArea::SetupProxyDropArea(this, [=](const QString &localUrl) { + Core::App().openLocalUrl( + localUrl, + QVariant::fromValue(ClickHandlerContext{ + .sessionWindow = weak, + })); + }); } MainWidget::~MainWidget() { diff --git a/Telegram/SourceFiles/mainwindow.cpp b/Telegram/SourceFiles/mainwindow.cpp index c62add918f..2627c02c7c 100644 --- a/Telegram/SourceFiles/mainwindow.cpp +++ b/Telegram/SourceFiles/mainwindow.cpp @@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_document_media.h" #include "dialogs/ui/dialogs_layout.h" #include "history/history.h" +#include "history/history_drag_area.h" #include "ui/widgets/popup_menu.h" #include "ui/widgets/buttons.h" #include "ui/widgets/shadow.h" @@ -296,6 +297,9 @@ void MainWindow::setupIntro( clearWidgets(); _intro = std::move(created); + DragArea::SetupProxyDropArea(_intro.data(), [](const QString &localUrl) { + Core::App().openLocalUrl(localUrl, {}); + }); if (_passcodeLock || _setupEmailLock) { _intro->hide(); } else {