init
Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
Close stale issues and PRs / stale (push) Has been cancelled

This commit is contained in:
allhaileris
2026-02-16 15:50:16 +03:00
commit afb81b8278
13816 changed files with 3689732 additions and 0 deletions

View File

@@ -0,0 +1,79 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
using "ui/basic.style";
using "ui/widgets/widgets.style";
ivMenuToggle: IconButton(defaultIconButton) {
width: 48px;
height: 48px;
icon: icon {{ "title_menu_dots", menuIconColor }};
iconOver: icon {{ "title_menu_dots", menuIconColor }};
rippleAreaPosition: point(6px, 6px);
rippleAreaSize: 36px;
ripple: defaultRippleAnimationBgOver;
}
ivMenuPosition: point(-2px, 40px);
ivBackIcon: icon {{ "box_button_back", menuIconColor }};
ivBack: IconButton(ivMenuToggle) {
width: 60px;
icon: ivBackIcon;
iconOver: ivBackIcon;
rippleAreaPosition: point(12px, 6px);
}
ivZoomButtonsSize: 26px;
ivPlusMinusZoom: IconButton(ivMenuToggle) {
width: ivZoomButtonsSize;
height: ivZoomButtonsSize;
rippleAreaPosition: point(0px, 0px);
rippleAreaSize: ivZoomButtonsSize;
ripple: defaultRippleAnimationBgOver;
}
ivResetZoomStyle: TextStyle(defaultTextStyle) {
font: font(12px);
}
ivResetZoom: RoundButton(defaultActiveButton) {
textFg: windowFg;
textFgOver: windowFgOver;
textBg: windowBg;
textBgOver: windowBgOver;
height: ivZoomButtonsSize;
padding: margins(0px, 0px, 0px, 0px);
style: ivResetZoomStyle;
ripple: defaultRippleAnimation;
}
ivResetZoomLabel: FlatLabel(defaultFlatLabel) {
textFg: windowFg;
style: ivResetZoomStyle;
}
ivResetZoomInnerPadding: 20px;
ivBackIconDisabled: icon {{ "box_button_back", menuIconFg }};
ivForwardIcon: icon {{ "box_button_back-flip_horizontal", menuIconColor }};
ivForward: IconButton(ivBack) {
width: 48px;
icon: ivForwardIcon;
iconOver: ivForwardIcon;
rippleAreaPosition: point(0px, 6px);
}
ivSubtitleFont: font(16px semibold);
ivSubtitle: FlatLabel(defaultFlatLabel) {
textFg: boxTitleFg;
maxHeight: 26px;
style: TextStyle(defaultTextStyle) {
font: ivSubtitleFont;
}
}
ivSubtitleHeight: 48px;
ivSubtitleTop: 12px;
ivSubtitleLeft: 22px;
ivSubtitleSkip: 0px;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,174 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "base/invoke_queued.h"
#include "base/object_ptr.h"
#include "base/unique_qptr.h"
#include "iv/iv_delegate.h"
#include "ui/effects/animations.h"
#include "ui/text/text.h"
#include "webview/webview_common.h"
class Painter;
namespace Webview {
struct DataRequest;
class Window;
} // namespace Webview
namespace Ui {
class RpWidget;
class RpWindow;
class PopupMenu;
class FlatLabel;
class IconButton;
template <typename Widget>
class FadeWrapScaled;
} // namespace Ui
namespace Iv {
struct Prepared;
struct ShareBoxResult {
Fn<void()> focus;
Fn<void()> hide;
rpl::producer<> destroyRequests;
};
struct ShareBoxDescriptor {
not_null<Ui::RpWidget*> parent;
QString url;
};
class Controller final {
public:
Controller(
not_null<Delegate*> delegate,
Fn<ShareBoxResult(ShareBoxDescriptor)> showShareBox);
~Controller();
struct Event {
enum class Type {
Close,
Quit,
OpenChannel,
JoinChannel,
OpenPage,
OpenLink,
OpenLinkExternal,
OpenMedia,
Report,
};
Type type = Type::Close;
QString url;
QString context;
};
void show(
const Webview::StorageId &storageId,
Prepared page,
base::flat_map<QByteArray, rpl::producer<bool>> inChannelValues);
void update(Prepared page);
[[nodiscard]] static bool IsGoodTonSiteUrl(const QString &uri);
void showTonSite(const Webview::StorageId &storageId, QString uri);
[[nodiscard]] bool active() const;
void showJoinedTooltip();
void minimize();
[[nodiscard]] rpl::producer<Webview::DataRequest> dataRequests() const {
return _dataRequests.events();
}
[[nodiscard]] rpl::producer<Event> events() const {
return _events.events();
}
[[nodiscard]] rpl::lifetime &lifetime();
private:
void createWindow();
void createWebview(const Webview::StorageId &storageId);
[[nodiscard]] QByteArray navigateScript(int index, const QString &hash);
[[nodiscard]] QByteArray reloadScript(int index);
void showInWindow(const Webview::StorageId &storageId, Prepared page);
[[nodiscard]] QByteArray fillInChannelValuesScript(
base::flat_map<QByteArray, rpl::producer<bool>> inChannelValues);
[[nodiscard]] QByteArray toggleInChannelScript(
const QByteArray &id,
bool in) const;
void processKey(const QString &key, const QString &modifier);
void processLink(const QString &url, const QString &context);
void initControls();
void updateTitleGeometry(int newWidth) const;
void activate();
void setInnerFocus();
void showMenu();
void escape();
void close();
void quit();
[[nodiscard]] QString composeCurrentUrl() const;
[[nodiscard]] uint64 compuseCurrentPageId() const;
void showShareMenu();
void destroyShareMenu();
void showWebviewError();
void showWebviewError(TextWithEntities text);
const not_null<Delegate*> _delegate;
std::unique_ptr<Ui::RpWindow> _window;
std::unique_ptr<Ui::RpWidget> _subtitleWrap;
rpl::variable<QString> _url;
rpl::variable<QString> _subtitleText;
rpl::variable<QString> _windowTitleText;
std::unique_ptr<Ui::FlatLabel> _subtitle;
Ui::Animations::Simple _subtitleBackShift;
Ui::Animations::Simple _subtitleForwardShift;
object_ptr<Ui::IconButton> _menuToggle = { nullptr };
object_ptr<Ui::FadeWrapScaled<Ui::IconButton>> _back = { nullptr };
object_ptr<Ui::FadeWrapScaled<Ui::IconButton>> _forward = { nullptr };
base::unique_qptr<Ui::PopupMenu> _menu;
Ui::RpWidget *_container = nullptr;
std::unique_ptr<Webview::Window> _webview;
rpl::event_stream<Webview::DataRequest> _dataRequests;
rpl::event_stream<Event> _events;
base::flat_map<QByteArray, bool> _inChannelChanged;
base::flat_set<QByteArray> _inChannelSubscribed;
SingleQueuedInvokation _updateStyles;
bool _reloadInitialWhenReady = false;
bool _subscribedToColors = false;
bool _ready = false;
rpl::variable<int> _index = -1;
QString _hash;
Fn<ShareBoxResult(ShareBoxDescriptor)> _showShareBox;
std::unique_ptr<Ui::RpWidget> _shareWrap;
std::unique_ptr<QWidget> _shareContainer;
Fn<void()> _shareFocus;
Fn<void()> _shareHide;
bool _shareHidesContent = false;
std::vector<Prepared> _pages;
base::flat_map<QString, int> _indices;
QString _navigateToHashWhenReady;
int _navigateToIndexWhenReady = -1;
rpl::lifetime _lifetime;
};
} // namespace Iv

View File

@@ -0,0 +1,121 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "iv/iv_data.h"
#include "iv/iv_prepare.h"
#include "webview/webview_interface.h"
#include <QtCore/QRegularExpression>
#include <QtCore/QUrl>
namespace Iv {
namespace {
bool FailureRecorded/* = false*/;
} // namespace
QByteArray GeoPointId(Geo point) {
const auto lat = int(point.lat * 1000000);
const auto lon = int(point.lon * 1000000);
const auto combined = (std::uint64_t(std::uint32_t(lat)) << 32)
| std::uint64_t(std::uint32_t(lon));
return QByteArray::number(quint64(combined))
+ ','
+ QByteArray::number(point.access);
}
Geo GeoPointFromId(QByteArray data) {
const auto parts = data.split(',');
if (parts.size() != 2) {
return {};
}
const auto combined = parts[0].toULongLong();
const auto lat = int(std::uint32_t(combined >> 32));
const auto lon = int(std::uint32_t(combined & 0xFFFFFFFFULL));
return {
.lat = lat / 1000000.,
.lon = lon / 1000000.,
.access = parts[1].toULongLong(),
};
}
Data::Data(const MTPDwebPage &webpage, const MTPPage &page)
: _source(std::make_unique<Source>(Source{
.pageId = webpage.vid().v,
.page = page,
.webpagePhoto = (webpage.vphoto()
? *webpage.vphoto()
: std::optional<MTPPhoto>()),
.webpageDocument = (webpage.vdocument()
? *webpage.vdocument()
: std::optional<MTPDocument>()),
.name = (webpage.vsite_name()
? qs(*webpage.vsite_name())
: SiteNameFromUrl(qs(webpage.vurl())))
})) {
}
QString Data::id() const {
return qs(_source->page.data().vurl());
}
bool Data::partial() const {
return _source->page.data().is_part();
}
Data::~Data() = default;
void Data::updateCachedViews(int cachedViews) {
_source->updatedCachedViews = std::max(
_source->updatedCachedViews,
cachedViews);
}
void Data::prepare(const Options &options, Fn<void(Prepared)> done) const {
crl::async([source = *_source, options, done = std::move(done)] {
done(Prepare(source, options));
});
}
QString SiteNameFromUrl(const QString &url) {
const auto u = QUrl(url);
QString pretty = u.isValid() ? u.toDisplayString() : url;
const auto m = QRegularExpression(u"^[a-zA-Z0-9]+://"_q).match(pretty);
if (m.hasMatch()) pretty = pretty.mid(m.capturedLength());
int32 slash = pretty.indexOf('/');
if (slash > 0) pretty = pretty.mid(0, slash);
QStringList components = pretty.split('.', Qt::SkipEmptyParts);
if (components.size() >= 2) {
components = components.mid(components.size() - 2);
return components.at(0).at(0).toUpper()
+ components.at(0).mid(1)
+ '.'
+ components.at(1);
}
return QString();
}
bool ShowButton() {
static const auto Supported = [&] {
const auto availability = Webview::Availability();
return availability.customSchemeRequests
&& availability.customRangeRequests;
}();
return Supported;
}
void RecordShowFailure() {
FailureRecorded = true;
}
bool FailedToShow() {
return FailureRecorded;
}
} // namespace Iv

View File

@@ -0,0 +1,64 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
namespace Iv {
struct Source;
struct Options {
};
struct Prepared {
uint64 pageId = 0;
QString name;
QByteArray content;
QByteArray script;
QString url;
QString hash;
base::flat_map<QByteArray, QByteArray> embeds;
base::flat_set<QByteArray> channelIds;
bool rtl = false;
bool hasCode = false;
bool hasEmbeds = false;
};
struct Geo {
float64 lat = 0.;
float64 lon = 0.;
uint64 access = 0;
};
[[nodiscard]] QByteArray GeoPointId(Geo point);
[[nodiscard]] Geo GeoPointFromId(QByteArray data);
class Data final {
public:
Data(const MTPDwebPage &webpage, const MTPPage &page);
~Data();
[[nodiscard]] QString id() const;
[[nodiscard]] bool partial() const;
void updateCachedViews(int cachedViews);
void prepare(const Options &options, Fn<void(Prepared)> done) const;
private:
const std::unique_ptr<Source> _source;
};
[[nodiscard]] QString SiteNameFromUrl(const QString &url);
[[nodiscard]] bool ShowButton();
void RecordShowFailure();
[[nodiscard]] bool FailedToShow();
} // namespace Iv

View File

@@ -0,0 +1,27 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
namespace Ui {
class RpWindow;
} // namespace Ui
namespace Iv {
class Delegate {
public:
virtual void ivSetLastSourceWindow(not_null<QWidget*> window) = 0;
[[nodiscard]] virtual QRect ivGeometry() const = 0;
virtual void ivSaveGeometry(not_null<Ui::RpWindow*> window) = 0;
[[nodiscard]] virtual int ivZoom() const = 0;
[[nodiscard]] virtual rpl::producer<int> ivZoomValue() const = 0;
virtual void ivSetZoom(int value) = 0;
};
} // namespace Iv

View File

@@ -0,0 +1,131 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "iv/iv_delegate_impl.h"
#include "core/application.h"
#include "core/core_settings.h"
#include "mainwindow.h"
#include "window/main_window.h"
#include "window/window_controller.h"
#include "styles/style_window.h"
#include <QtGui/QGuiApplication>
#include <QtGui/QScreen>
#include <QtGui/QWindow>
namespace Iv {
namespace {
[[nodiscard]] Core::WindowPosition DefaultPosition() {
auto center = qApp->primaryScreen()->geometry().center();
const auto moncrc = [&] {
if (const auto active = Core::App().activeWindow()) {
const auto widget = active->widget();
center = widget->geometry().center();
if (const auto screen = widget->screen()) {
return Platform::ScreenNameChecksum(screen->name());
}
}
return Core::App().settings().windowPosition().moncrc;
}();
return {
.moncrc = moncrc,
.scale = cScale(),
.x = (center.x() - st::ivWidthDefault / 2),
.y = (center.y() - st::ivHeightDefault / 2),
.w = st::ivWidthDefault,
.h = st::ivHeightDefault,
};
}
} // namespace
void DelegateImpl::ivSetLastSourceWindow(not_null<QWidget*> window) {
_lastSourceWindow = window;
}
QRect DelegateImpl::ivGeometry() const {
const auto found = _lastSourceWindow
? Core::App().findWindow(_lastSourceWindow)
: nullptr;
const auto saved = Core::App().settings().ivPosition();
const auto adjusted = Core::AdjustToScale(saved, u"IV"_q);
const auto initial = DefaultPosition();
auto result = initial.rect();
if (const auto window = found ? found : Core::App().activeWindow()) {
result = window->widget()->countInitialGeometry(
adjusted,
initial,
{ st::ivWidthMin, st::ivHeightMin });
}
return result;
}
void DelegateImpl::ivSaveGeometry(not_null<Ui::RpWindow*> window) {
if (!window->windowHandle()) {
return;
}
const auto state = window->windowHandle()->windowState();
if (state == Qt::WindowMinimized) {
return;
}
const auto &savedPosition = Core::App().settings().ivPosition();
auto realPosition = savedPosition;
if (state == Qt::WindowMaximized) {
realPosition.maximized = 1;
realPosition.moncrc = 0;
DEBUG_LOG(("IV Pos: Saving maximized position."));
} else {
auto r = window->body()->mapToGlobal(window->body()->rect());
realPosition.x = r.x();
realPosition.y = r.y();
realPosition.w = r.width();
realPosition.h = r.height();
realPosition.scale = cScale();
realPosition.maximized = 0;
realPosition.moncrc = 0;
DEBUG_LOG(("IV Pos: "
"Saving non-maximized position: %1, %2, %3, %4"
).arg(realPosition.x
).arg(realPosition.y
).arg(realPosition.w
).arg(realPosition.h));
}
realPosition = Window::PositionWithScreen(
realPosition,
window,
{ st::ivWidthMin, st::ivHeightMin });
if (realPosition.w >= st::ivWidthMin
&& realPosition.h >= st::ivHeightMin
&& realPosition != savedPosition) {
DEBUG_LOG(("IV Pos: "
"Writing: %1, %2, %3, %4 (scale %5%, maximized %6)")
.arg(realPosition.x)
.arg(realPosition.y)
.arg(realPosition.w)
.arg(realPosition.h)
.arg(realPosition.scale)
.arg(Logs::b(realPosition.maximized)));
Core::App().settings().setIvPosition(realPosition);
Core::App().saveSettingsDelayed();
}
}
int DelegateImpl::ivZoom() const {
return Core::App().settings().ivZoom();
}
rpl::producer<int> DelegateImpl::ivZoomValue() const {
return Core::App().settings().ivZoomValue();
}
void DelegateImpl::ivSetZoom(int value) {
Core::App().settings().setIvZoom(value);
Core::App().saveSettingsDelayed();
}
} // namespace Iv

View File

@@ -0,0 +1,31 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "iv/iv_delegate.h"
namespace Iv {
class DelegateImpl final : public Delegate {
public:
DelegateImpl() = default;
void ivSetLastSourceWindow(not_null<QWidget*> window) override;
[[nodiscard]] QRect ivGeometry() const override;
void ivSaveGeometry(not_null<Ui::RpWindow*> window) override;
[[nodiscard]] int ivZoom() const override;
[[nodiscard]] rpl::producer<int> ivZoomValue() const override;
void ivSetZoom(int value) override;
private:
QPointer<QWidget> _lastSourceWindow;
};
} // namespace Iv

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,113 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "iv/iv_delegate.h"
namespace Main {
class Session;
class SessionShow;
} // namespace Main
namespace Window {
class SessionController;
} // namespace Window
namespace Iv {
class Data;
class Shown;
class TonSite;
class Instance final {
public:
explicit Instance(not_null<Delegate*> delegate);
~Instance();
void show(
not_null<Window::SessionController*> controller,
not_null<Data*> data,
QString hash);
void show(
std::shared_ptr<Main::SessionShow> show,
not_null<Data*> data,
QString hash);
void show(
not_null<Main::Session*> session,
not_null<Data*> data,
QString hash);
void openWithIvPreferred(
not_null<Window::SessionController*> controller,
QString uri,
QVariant context = {});
void openWithIvPreferred(
not_null<Main::Session*> session,
QString uri,
QVariant context = {});
void showTonSite(
const QString &uri,
QVariant context = {});
[[nodiscard]] bool hasActiveWindow(
not_null<Main::Session*> session) const;
bool closeActive();
bool minimizeActive();
void closeAll();
[[nodiscard]] rpl::lifetime &lifetime();
private:
struct FullResult {
crl::time lastRequestedAt = 0;
WebPageData *page = nullptr;
int32 hash = 0;
};
void processOpenChannel(const QString &context);
void processJoinChannel(const QString &context);
void requestFull(not_null<Main::Session*> session, const QString &id);
void trackSession(not_null<Main::Session*> session);
WebPageData *processReceivedPage(
not_null<Main::Session*> session,
const QString &url,
const MTPmessages_WebPage &result);
const not_null<Delegate*> _delegate;
std::unique_ptr<Shown> _shown;
Main::Session *_shownSession = nullptr;
base::flat_set<not_null<Main::Session*>> _tracking;
base::flat_map<
not_null<Main::Session*>,
base::flat_set<not_null<ChannelData*>>> _joining;
base::flat_map<
not_null<Main::Session*>,
base::flat_map<QString, FullResult>> _fullRequested;
base::flat_map<
not_null<Main::Session*>,
base::flat_map<QString, WebPageData*>> _ivCache;
Main::Session *_ivRequestSession = nullptr;
QString _ivRequestUri;
mtpRequestId _ivRequestId = 0;
std::unique_ptr<TonSite> _tonSite;
rpl::lifetime _lifetime;
};
[[nodiscard]] bool PreferForUri(const QString &uri);
} // namespace Iv

View File

@@ -0,0 +1,30 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include <QtCore/QString>
#include <QtCore/QByteArray>
#include <crl/crl.h>
#include <rpl/rpl.h>
#include <vector>
#include <map>
#include <set>
#include <deque>
#include <atomic>
#include <range/v3/all.hpp>
#include "base/flat_map.h"
#include "base/flat_set.h"
#include "base/weak_qptr.h"
#include "ui/qt_object_factory.h"
#include "scheme.h"
#include "logs.h"

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,26 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
namespace Iv {
struct Options;
struct Prepared;
struct Source {
uint64 pageId = 0;
MTPPage page;
std::optional<MTPPhoto> webpagePhoto;
std::optional<MTPDocument> webpageDocument;
QString name;
int updatedCachedViews = 0;
};
[[nodiscard]] Prepared Prepare(const Source &source, const Options &options);
} // namespace Iv