diff --git a/.github/workflows/snap.yml b/.github/workflows/snap.yml
index 4191aced9..c2e5dbafe 100644
--- a/.github/workflows/snap.yml
+++ b/.github/workflows/snap.yml
@@ -61,7 +61,7 @@ jobs:
sudo snap run lxd waitready
- name: Free up some disk space.
- uses: jlumbroso/free-disk-space@76866dbe54312617f00798d1762df7f43def6e5c
+ uses: jlumbroso/free-disk-space@f68fdb76e2ea636224182cfb7377ff9a1708f9b8
- name: Telegram Desktop snap build.
run: sg lxd -c 'snap run snapcraft -v'
diff --git a/Telegram/Resources/uwp/AppX/AppxManifest.xml b/Telegram/Resources/uwp/AppX/AppxManifest.xml
index f5ee77da9..a64e3b239 100644
--- a/Telegram/Resources/uwp/AppX/AppxManifest.xml
+++ b/Telegram/Resources/uwp/AppX/AppxManifest.xml
@@ -10,7 +10,7 @@
+ Version="4.10.2.0" />
Telegram Desktop
Telegram Messenger LLP
diff --git a/Telegram/Resources/winrc/Telegram.rc b/Telegram/Resources/winrc/Telegram.rc
index 64f248acc..3c262b4b3 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 4,10,1,0
- PRODUCTVERSION 4,10,1,0
+ FILEVERSION 4,10,2,0
+ PRODUCTVERSION 4,10,2,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -62,10 +62,10 @@ BEGIN
BEGIN
VALUE "CompanyName", "Radolyn Labs"
VALUE "FileDescription", "AyuGram Desktop"
- VALUE "FileVersion", "4.10.1.0"
+ VALUE "FileVersion", "4.10.2.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2023"
VALUE "ProductName", "AyuGram Desktop"
- VALUE "ProductVersion", "4.10.1.0"
+ VALUE "ProductVersion", "4.10.2.0"
END
END
BLOCK "VarFileInfo"
diff --git a/Telegram/Resources/winrc/Updater.rc b/Telegram/Resources/winrc/Updater.rc
index 1d26f8846..760e5f1b7 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 4,10,1,0
- PRODUCTVERSION 4,10,1,0
+ FILEVERSION 4,10,2,0
+ PRODUCTVERSION 4,10,2,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -53,10 +53,10 @@ BEGIN
BEGIN
VALUE "CompanyName", "Radolyn Labs"
VALUE "FileDescription", "AyuGram Desktop Updater"
- VALUE "FileVersion", "4.10.1.0"
+ VALUE "FileVersion", "4.10.2.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2023"
VALUE "ProductName", "AyuGram Desktop"
- VALUE "ProductVersion", "4.10.1.0"
+ VALUE "ProductVersion", "4.10.2.0"
END
END
BLOCK "VarFileInfo"
diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp
index 5b95559f5..3c3270595 100644
--- a/Telegram/SourceFiles/apiwrap.cpp
+++ b/Telegram/SourceFiles/apiwrap.cpp
@@ -2450,7 +2450,13 @@ void ApiWrap::refreshFileReference(
};
v::match(origin.data, [&](Data::FileOriginMessage data) {
if (const auto item = _session->data().message(data)) {
- if (item->isScheduled()) {
+ const auto media = item->media();
+ const auto storyId = media ? media->storyId() : FullStoryId();
+ if (storyId) {
+ request(MTPstories_GetStoriesByID(
+ _session->data().peer(storyId.peer)->input,
+ MTP_vector(1, MTP_int(storyId.story))));
+ } else if (item->isScheduled()) {
const auto &scheduled = _session->data().scheduledMessages();
const auto realId = scheduled.lookupId(item);
request(MTPmessages_GetScheduledMessages(
diff --git a/Telegram/SourceFiles/core/version.h b/Telegram/SourceFiles/core/version.h
index 65c0b2aa8..ea54c2b39 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 = 4010001;
-constexpr auto AppVersionStr = "4.10.1";
+constexpr auto AppVersion = 4010002;
+constexpr auto AppVersionStr = "4.10.2";
constexpr auto AppBetaVersion = false;
constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION;
diff --git a/Telegram/SourceFiles/data/data_stories.cpp b/Telegram/SourceFiles/data/data_stories.cpp
index e9474d26a..d33412478 100644
--- a/Telegram/SourceFiles/data/data_stories.cpp
+++ b/Telegram/SourceFiles/data/data_stories.cpp
@@ -1230,7 +1230,7 @@ void Stories::toggleHidden(
const auto name = peer->shortName();
const auto guard = gsl::finally([&] {
- if (show) {
+ if (show && !justRemove) {
const auto phrase = hidden
? tr::lng_stories_hidden_to_contacts
: tr::lng_stories_shown_in_chats;
diff --git a/Telegram/SourceFiles/data/data_story.cpp b/Telegram/SourceFiles/data/data_story.cpp
index 237c3323d..13c453e06 100644
--- a/Telegram/SourceFiles/data/data_story.cpp
+++ b/Telegram/SourceFiles/data/data_story.cpp
@@ -43,6 +43,19 @@ using UpdateFlag = StoryUpdate::Flag;
};
}
+[[nodiscard]] TextWithEntities StripLinks(TextWithEntities text) {
+ const auto link = [&](const EntityInText &entity) {
+ return (entity.type() == EntityType::CustomUrl)
+ || (entity.type() == EntityType::Url)
+ || (entity.type() == EntityType::Mention)
+ || (entity.type() == EntityType::Hashtag);
+ };
+ text.entities.erase(
+ ranges::remove_if(text.entities, link),
+ text.entities.end());
+ return text;
+}
+
[[nodiscard]] auto ParseLocation(const MTPMediaArea &area)
-> std::optional {
auto result = std::optional();
@@ -586,6 +599,11 @@ void Story::applyFields(
&owner().session(),
data.ventities().value_or_empty()),
};
+ if (const auto user = _peer->asUser()) {
+ if (!user->isVerified() && !user->isPremium()) {
+ caption = StripLinks(std::move(caption));
+ }
+ }
auto counts = ViewsCounts();
auto viewsKnown = _views.known;
if (const auto info = data.vviews()) {
diff --git a/Telegram/SourceFiles/dialogs/dialogs_row.cpp b/Telegram/SourceFiles/dialogs/dialogs_row.cpp
index c937f10f2..a6459bbc4 100644
--- a/Telegram/SourceFiles/dialogs/dialogs_row.cpp
+++ b/Telegram/SourceFiles/dialogs/dialogs_row.cpp
@@ -444,10 +444,12 @@ void Row::paintUserpic(
const auto cornerBadgeShown = !_cornerBadgeUserpic
? _cornerBadgeShown
: !_cornerBadgeUserpic->layersManager.isDisplayedNone();
- const auto storiesUser = peer ? peer->asUser() : nullptr;
+ const auto storiesPeer = peer
+ ? ((peer->isUser() || peer->isBroadcast()) ? peer : nullptr)
+ : nullptr;
const auto storiesFolder = peer ? nullptr : _id.folder();
- const auto storiesHas = storiesUser
- ? storiesUser->hasActiveStories()
+ const auto storiesHas = storiesPeer
+ ? storiesPeer->hasActiveStories()
: storiesFolder
? storiesFolder->storiesCount()
: false;
@@ -467,8 +469,8 @@ void Row::paintUserpic(
const auto frameSide = (2 * framePadding + context.st->photoSize)
* ratio;
const auto frameSize = QSize(frameSide, frameSide);
- const auto storiesSource = (storiesHas && storiesUser)
- ? storiesUser->owner().stories().source(storiesUser->id)
+ const auto storiesSource = (storiesHas && storiesPeer)
+ ? storiesPeer->owner().stories().source(storiesPeer->id)
: nullptr;
const auto storiesCountReal = storiesSource
? int(storiesSource->ids.size())
@@ -481,7 +483,7 @@ void Row::paintUserpic(
? storiesSource->unreadCount()
: storiesFolder
? storiesFolder->storiesUnreadCount()
- : (storiesUser && storiesUser->hasUnreadStories())
+ : (storiesPeer && storiesPeer->hasUnreadStories())
? 1
: 0;
const auto limit = Ui::kOutlineSegmentsMax;
diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp
index 62b98a007..0bc3d256d 100644
--- a/Telegram/SourceFiles/history/history_inner_widget.cpp
+++ b/Telegram/SourceFiles/history/history_inner_widget.cpp
@@ -2336,8 +2336,9 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
const auto item = _dragStateItem;
const auto itemId = item ? item->fullId() : FullMsgId();
if (isUponSelected > 0) {
+ const auto selectedText = getSelectedText();
if (!hasCopyRestrictionForSelected()
- && !getSelectedText().empty()) {
+ && !selectedText.empty()) {
_menu->addAction(
(isUponSelected > 1
? tr::lng_context_copy_selected_items(tr::now)
@@ -2345,11 +2346,12 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
[=] { copySelectedText(); },
&st::menuIconCopy);
}
- if (!Ui::SkipTranslate(getSelectedText().rich)) {
+ if (item && !Ui::SkipTranslate(selectedText.rich)) {
+ const auto peer = item->history()->peer;
_menu->addAction(tr::lng_context_translate_selected({}), [=] {
_controller->show(Box(
Ui::TranslateBox,
- item->history()->peer,
+ peer,
MsgId(),
getSelectedText().rich,
hasCopyRestrictionForSelected()));
@@ -2452,7 +2454,7 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
[=] { copySelectedText(); },
&st::menuIconCopy);
}
- if (!Ui::SkipTranslate(selectedText.rich)) {
+ if (item && !Ui::SkipTranslate(selectedText.rich)) {
const auto peer = item->history()->peer;
_menu->addAction(tr::lng_context_translate_selected({}), [=] {
_controller->show(Box(
diff --git a/Telegram/SourceFiles/mtproto/scheme/api.tl b/Telegram/SourceFiles/mtproto/scheme/api.tl
index 93ee43704..8a386d988 100644
--- a/Telegram/SourceFiles/mtproto/scheme/api.tl
+++ b/Telegram/SourceFiles/mtproto/scheme/api.tl
@@ -1564,7 +1564,7 @@ peerStories#9a35e999 flags:# peer:Peer max_read_id:flags.0?int stories:Vector users:Vector = stories.PeerStories;
-stories.boostsStatus#66ea1fef flags:# my_boost:flags.2?true level:int current_level_boosts:int boosts:int next_level_boosts:flags.0?int premium_audience:flags.1?StatsPercentValue = stories.BoostsStatus;
+stories.boostsStatus#e5c1aa5c flags:# my_boost:flags.2?true level:int current_level_boosts:int boosts:int next_level_boosts:flags.0?int premium_audience:flags.1?StatsPercentValue boost_url:string = stories.BoostsStatus;
stories.canApplyBoostOk#c3173587 = stories.CanApplyBoostResult;
stories.canApplyBoostReplace#712c4655 current_boost:Peer chats:Vector = stories.CanApplyBoostResult;
@@ -1573,6 +1573,8 @@ booster#e9e6380 user_id:long expires:int = Booster;
stories.boostersList#f3dd3d1d flags:# count:int boosters:Vector next_offset:flags.0?string users:Vector = stories.BoostersList;
+messages.webPage#fd5e12bd webpage:WebPage chats:Vector users:Vector = messages.WebPage;
+
---functions---
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
@@ -1801,7 +1803,7 @@ messages.setInlineGameScore#15ad9f64 flags:# edit_message:flags.0?true force:fla
messages.getGameHighScores#e822649d peer:InputPeer id:int user_id:InputUser = messages.HighScores;
messages.getInlineGameHighScores#f635e1b id:InputBotInlineMessageID user_id:InputUser = messages.HighScores;
messages.getCommonChats#e40ca104 user_id:InputUser max_id:long limit:int = messages.Chats;
-messages.getWebPage#32ca8f91 url:string hash:int = WebPage;
+messages.getWebPage#8d9692a3 url:string hash:int = messages.WebPage;
messages.toggleDialogPin#a731e257 flags:# pinned:flags.0?true peer:InputDialogPeer = Bool;
messages.reorderPinnedDialogs#3b1adf37 flags:# force:flags.0?true folder_id:int order:Vector = Bool;
messages.getPinnedDialogs#d6b94df2 folder_id:int = messages.PeerDialogs;
diff --git a/Telegram/SourceFiles/mtproto/scheme/layer.tl b/Telegram/SourceFiles/mtproto/scheme/layer.tl
index dcdebd9f5..7a644419f 100644
--- a/Telegram/SourceFiles/mtproto/scheme/layer.tl
+++ b/Telegram/SourceFiles/mtproto/scheme/layer.tl
@@ -1 +1 @@
-// LAYER 164
+// LAYER 165
diff --git a/Telegram/SourceFiles/settings/settings_premium.cpp b/Telegram/SourceFiles/settings/settings_premium.cpp
index 58420b719..612b0c35e 100644
--- a/Telegram/SourceFiles/settings/settings_premium.cpp
+++ b/Telegram/SourceFiles/settings/settings_premium.cpp
@@ -33,10 +33,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "settings/settings_premium.h"
#include "ui/abstract_button.h"
#include "ui/basic_click_handlers.h"
-#include "ui/color_contrast.h"
#include "ui/effects/gradient.h"
#include "ui/effects/premium_graphics.h"
#include "ui/effects/premium_stars_colored.h"
+#include "ui/effects/premium_top_bar.h"
#include "ui/layers/generic_box.h"
#include "ui/text/format_values.h"
#include "ui/text/text_utilities.h"
@@ -71,41 +71,6 @@ namespace {
using SectionCustomTopBarData = Info::Settings::SectionCustomTopBarData;
-constexpr auto kBodyAnimationPart = 0.90;
-constexpr auto kTitleAdditionalScale = 0.15;
-constexpr auto kMinAcceptableContrast = 4.5; // 1.14;
-
-[[nodiscard]] QString Svg() {
- return u":/gui/icons/settings/star.svg"_q;
-}
-
-[[nodiscard]] QByteArray ColorizedSvg() {
- auto f = QFile(Svg());
- if (!f.open(QIODevice::ReadOnly)) {
- return QByteArray();
- }
- auto content = qs(f.readAll());
- auto stops = [] {
- auto s = QString();
- for (const auto &stop : Ui::Premium::ButtonGradientStops()) {
- s += QString("")
- .arg(QString::number(stop.first), stop.second.name());
- }
- return s;
- }();
- const auto color = QString("%5")
- .arg(0)
- .arg(1)
- .arg(1)
- .arg(0)
- .arg(std::move(stops));
- content.replace(u"gradientPlaceholder"_q, color);
- content.replace(u"#fff"_q, u"url(#Gradient2)"_q);
- f.close();
- return content.toUtf8();
-}
-
[[nodiscard]] Data::SubscriptionOptions SubscriptionOptionsForRows(
Data::SubscriptionOptions result) {
for (auto &option : result) {
@@ -416,85 +381,6 @@ void SendScreenAccept(not_null controller) {
MTP_jsonNull());
}
-class TopBarAbstract : public Ui::RpWidget {
-public:
- using Ui::RpWidget::RpWidget;
-
- void setRoundEdges(bool value);
-
- virtual void setPaused(bool paused) = 0;
- virtual void setTextPosition(int x, int y) = 0;
-
- [[nodiscard]] virtual rpl::producer additionalHeight() const = 0;
-
-protected:
- void paintEdges(QPainter &p, const QBrush &brush) const;
- void paintEdges(QPainter &p) const;
-
- [[nodiscard]] QRectF starRect(
- float64 topProgress,
- float64 sizeProgress) const;
-
- [[nodiscard]] bool isDark() const;
- void computeIsDark();
-
-private:
- bool _roundEdges = true;
- bool _isDark = false;
-
-};
-
-void TopBarAbstract::setRoundEdges(bool value) {
- _roundEdges = value;
- update();
-}
-
-void TopBarAbstract::paintEdges(QPainter &p, const QBrush &brush) const {
- const auto r = rect();
- if (_roundEdges) {
- PainterHighQualityEnabler hq(p);
- const auto radius = st::boxRadius;
- p.setPen(Qt::NoPen);
- p.setBrush(brush);
- p.drawRoundedRect(
- r + QMargins{ 0, 0, 0, radius + 1 },
- radius,
- radius);
- } else {
- p.fillRect(r, brush);
- }
-}
-
-void TopBarAbstract::paintEdges(QPainter &p) const {
- paintEdges(p, st::boxBg);
- if (isDark()) {
- paintEdges(p, st::shadowFg);
- paintEdges(p, st::shadowFg);
- }
-}
-
-QRectF TopBarAbstract::starRect(
- float64 topProgress,
- float64 sizeProgress) const {
- const auto starSize = st::settingsPremiumStarSize * sizeProgress;
- return QRectF(
- QPointF(
- (width() - starSize.width()) / 2,
- st::settingsPremiumStarTopSkip * topProgress),
- starSize);
-};
-
-bool TopBarAbstract::isDark() const {
- return _isDark;
-}
-
-void TopBarAbstract::computeIsDark() {
- const auto contrast = Ui::CountContrast(
- st::boxBg->c,
- st::premiumButtonFg->c);
- _isDark = (contrast > kMinAcceptableContrast);
-}
-
class EmojiStatusTopBar final {
public:
EmojiStatusTopBar(
@@ -587,7 +473,7 @@ void EmojiStatusTopBar::paint(QPainter &p) {
}
}
-class TopBarUser final : public TopBarAbstract {
+class TopBarUser final : public Ui::Premium::TopBarAbstract {
public:
TopBarUser(
not_null parent,
@@ -678,38 +564,8 @@ TopBarUser::TopBarUser(
HistoryView::Sticker::EmojiSize());
_imageStar = QImage();
} else {
- auto svg = QSvgRenderer(Svg());
-
- const auto size = _starRect.size().toSize();
- auto frame = QImage(
- size * style::DevicePixelRatio(),
- QImage::Format_ARGB32_Premultiplied);
- frame.setDevicePixelRatio(style::DevicePixelRatio());
-
- auto mask = frame;
- mask.fill(Qt::transparent);
- {
- auto p = QPainter(&mask);
- auto gradient = QLinearGradient(
- 0,
- size.height(),
- size.width(),
- 0);
- gradient.setStops(Ui::Premium::ButtonGradientStops());
- p.setPen(Qt::NoPen);
- p.setBrush(gradient);
- p.drawRect(0, 0, size.width(), size.height());
- }
- frame.fill(Qt::transparent);
- {
- auto q = QPainter(&frame);
- svg.render(&q, QRect(QPoint(), size));
- q.setCompositionMode(QPainter::CompositionMode_SourceIn);
- q.drawImage(0, 0, mask);
- }
- _imageStar = std::move(frame);
-
_emojiStatus = nullptr;
+ _imageStar = Ui::Premium::GenerateStarForLightTopBar(_starRect);
}
updateTitle(document, { name }, controller);
@@ -929,194 +785,6 @@ void TopBarUser::resizeEvent(QResizeEvent *e) {
}
}
-class TopBar final : public TopBarAbstract {
-public:
- TopBar(
- not_null parent,
- not_null controller,
- rpl::producer title,
- rpl::producer about);
-
- void setPaused(bool paused) override;
- void setTextPosition(int x, int y) override;
-
- rpl::producer additionalHeight() const override;
-
-protected:
- void paintEvent(QPaintEvent *e) override;
- void resizeEvent(QResizeEvent *e) override;
-
-private:
- const style::font &_titleFont;
- const style::margins &_titlePadding;
- object_ptr _about;
- Ui::Premium::ColoredMiniStars _ministars;
- QSvgRenderer _star;
-
- struct {
- float64 top = 0.;
- float64 body = 0.;
- float64 title = 0.;
- float64 scaleTitle = 0.;
- } _progress;
-
- QRectF _starRect;
-
- QPoint _titlePosition;
- QPainterPath _titlePath;
-
-};
-
-TopBar::TopBar(
- not_null parent,
- not_null controller,
- rpl::producer title,
- rpl::producer about)
-: TopBarAbstract(parent)
-, _titleFont(st::boxTitle.style.font)
-, _titlePadding(st::settingsPremiumTitlePadding)
-, _about(this, std::move(about), st::settingsPremiumAbout)
-, _ministars(this) {
- std::move(
- title
- ) | rpl::start_with_next([=](QString text) {
- _titlePath = QPainterPath();
- _titlePath.addText(0, _titleFont->ascent, _titleFont, text);
- update();
- }, lifetime());
-
- _about->setClickHandlerFilter([=](
- const ClickHandlerPtr &handler,
- Qt::MouseButton button) {
- ActivateClickHandler(_about, handler, {
- button,
- QVariant::fromValue(ClickHandlerContext{
- .sessionWindow = base::make_weak(controller),
- .botStartAutoSubmit = true,
- })
- });
- return false;
- });
-
- rpl::single() | rpl::then(
- style::PaletteChanged()
- ) | rpl::start_with_next([=] {
- TopBarAbstract::computeIsDark();
-
- if (!TopBarAbstract::isDark()) {
- _star.load(Svg());
- _ministars.setColorOverride(st::premiumButtonFg->c);
- } else {
- _star.load(ColorizedSvg());
- _ministars.setColorOverride(std::nullopt);
- }
- auto event = QResizeEvent(size(), size());
- resizeEvent(&event);
- }, lifetime());
-}
-
-void TopBar::setPaused(bool paused) {
- _ministars.setPaused(paused);
-}
-
-void TopBar::setTextPosition(int x, int y) {
- _titlePosition = { x, y };
-}
-
-rpl::producer TopBar::additionalHeight() const {
- return _about->heightValue(
- ) | rpl::map([l = st::settingsPremiumAbout.style.lineHeight](int height) {
- return std::max(height - l * 2, 0);
- });
-}
-
-void TopBar::resizeEvent(QResizeEvent *e) {
- const auto progress = (e->size().height() - minimumHeight())
- / float64(maximumHeight() - minimumHeight());
- _progress.top = 1. -
- std::clamp(
- (1. - progress) / kBodyAnimationPart,
- 0.,
- 1.);
- _progress.body = _progress.top;
- _progress.title = 1. - progress;
- _progress.scaleTitle = 1. + kTitleAdditionalScale * progress;
-
- _ministars.setCenter(starRect(_progress.top, 1.).toRect());
-
- _starRect = starRect(_progress.top, _progress.body);
-
- const auto &padding = st::boxRowPadding;
- const auto availableWidth = width() - padding.left() - padding.right();
- const auto titleTop = _starRect.top()
- + _starRect.height()
- + _titlePadding.top();
- const auto titlePathRect = _titlePath.boundingRect();
- const auto aboutTop = titleTop
- + titlePathRect.height()
- + _titlePadding.bottom();
- _about->resizeToWidth(availableWidth);
- _about->moveToLeft(padding.left(), aboutTop);
- _about->setOpacity(_progress.body);
-
- Ui::RpWidget::resizeEvent(e);
-}
-
-void TopBar::paintEvent(QPaintEvent *e) {
- auto p = QPainter(this);
-
- p.fillRect(e->rect(), Qt::transparent);
-
- const auto r = rect();
-
- if (!TopBarAbstract::isDark()) {
- const auto gradientPointTop = r.height() / 3. * 2.;
- auto gradient = QLinearGradient(
- QPointF(0, gradientPointTop),
- QPointF(r.width(), r.height() - gradientPointTop));
- gradient.setStops(Ui::Premium::ButtonGradientStops());
-
- TopBarAbstract::paintEdges(p, gradient);
- } else {
- TopBarAbstract::paintEdges(p);
- }
-
- p.setOpacity(_progress.body);
- p.translate(_starRect.center());
- p.scale(_progress.body, _progress.body);
- p.translate(-_starRect.center());
- if (_progress.top) {
- _ministars.paint(p);
- }
- p.resetTransform();
-
- _star.render(&p, _starRect);
-
- p.setPen(st::premiumButtonFg);
-
- const auto titlePathRect = _titlePath.boundingRect();
-
- // Title.
- PainterHighQualityEnabler hq(p);
- p.setOpacity(1.);
- p.setFont(_titleFont);
- const auto fullStarRect = starRect(1., 1.);
- const auto fullTitleTop = fullStarRect.top()
- + fullStarRect.height()
- + _titlePadding.top();
- p.translate(
- anim::interpolate(
- (width() - titlePathRect.width()) / 2,
- _titlePosition.x(),
- _progress.title),
- anim::interpolate(fullTitleTop, _titlePosition.y(), _progress.title));
-
- p.translate(titlePathRect.center());
- p.scale(_progress.scaleTitle, _progress.scaleTitle);
- p.translate(-titlePathRect.center());
- p.fillPath(_titlePath, st::premiumButtonFg);
-}
-
class Premium : public Section {
public:
Premium(
@@ -1499,7 +1167,7 @@ QPointer Premium::createPinnedToTop(
return nullptr;
}();
- const auto content = [&]() -> TopBarAbstract* {
+ const auto content = [&]() -> Ui::Premium::TopBarAbstract* {
if (peerWithPremium) {
return Ui::CreateChild(
parent.get(),
@@ -1507,9 +1175,16 @@ QPointer Premium::createPinnedToTop(
peerWithPremium,
_showFinished.events());
}
- return Ui::CreateChild(
+ const auto weak = base::make_weak(_controller);
+ const auto clickContextOther = [=] {
+ return QVariant::fromValue(ClickHandlerContext{
+ .sessionWindow = weak,
+ .botStartAutoSubmit = true,
+ });
+ };
+ return Ui::CreateChild(
parent.get(),
- _controller,
+ clickContextOther,
std::move(title),
std::move(about));
}();
diff --git a/Telegram/SourceFiles/ui/effects/premium_top_bar.cpp b/Telegram/SourceFiles/ui/effects/premium_top_bar.cpp
new file mode 100644
index 000000000..309db7a6a
--- /dev/null
+++ b/Telegram/SourceFiles/ui/effects/premium_top_bar.cpp
@@ -0,0 +1,317 @@
+/*
+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 "ui/effects/premium_top_bar.h"
+
+#include "ui/color_contrast.h"
+#include "ui/painter.h"
+#include "ui/effects/premium_graphics.h"
+#include "ui/widgets/labels.h"
+#include "ui/wrap/fade_wrap.h"
+#include "styles/style_layers.h"
+#include "styles/style_settings.h"
+
+#include
+
+namespace Ui::Premium {
+namespace {
+
+constexpr auto kBodyAnimationPart = 0.90;
+constexpr auto kTitleAdditionalScale = 0.15;
+constexpr auto kMinAcceptableContrast = 4.5; // 1.14;
+
+} // namespace
+
+QString Svg() {
+ return u":/gui/icons/settings/star.svg"_q;
+}
+
+QByteArray ColorizedSvg() {
+ auto f = QFile(Svg());
+ if (!f.open(QIODevice::ReadOnly)) {
+ return QByteArray();
+ }
+ auto content = QString::fromUtf8(f.readAll());
+ auto stops = [] {
+ auto s = QString();
+ for (const auto &stop : Ui::Premium::ButtonGradientStops()) {
+ s += QString("")
+ .arg(QString::number(stop.first), stop.second.name());
+ }
+ return s;
+ }();
+ const auto color = QString("%5")
+ .arg(0)
+ .arg(1)
+ .arg(1)
+ .arg(0)
+ .arg(std::move(stops));
+ content.replace(u"gradientPlaceholder"_q, color);
+ content.replace(u"#fff"_q, u"url(#Gradient2)"_q);
+ f.close();
+ return content.toUtf8();
+}
+
+QImage GenerateStarForLightTopBar(QRectF rect) {
+ auto svg = QSvgRenderer(Ui::Premium::Svg());
+
+ const auto size = rect.size().toSize();
+ auto frame = QImage(
+ size * style::DevicePixelRatio(),
+ QImage::Format_ARGB32_Premultiplied);
+ frame.setDevicePixelRatio(style::DevicePixelRatio());
+
+ auto mask = frame;
+ mask.fill(Qt::transparent);
+ {
+ auto p = QPainter(&mask);
+ auto gradient = QLinearGradient(
+ 0,
+ size.height(),
+ size.width(),
+ 0);
+ gradient.setStops(Ui::Premium::ButtonGradientStops());
+ p.setPen(Qt::NoPen);
+ p.setBrush(gradient);
+ p.drawRect(0, 0, size.width(), size.height());
+ }
+ frame.fill(Qt::transparent);
+ {
+ auto q = QPainter(&frame);
+ svg.render(&q, QRect(QPoint(), size));
+ q.setCompositionMode(QPainter::CompositionMode_SourceIn);
+ q.drawImage(0, 0, mask);
+ }
+ return frame;
+}
+
+void TopBarAbstract::setRoundEdges(bool value) {
+ _roundEdges = value;
+ update();
+}
+
+void TopBarAbstract::paintEdges(QPainter &p, const QBrush &brush) const {
+ const auto r = rect();
+ if (_roundEdges) {
+ PainterHighQualityEnabler hq(p);
+ const auto radius = st::boxRadius;
+ p.setPen(Qt::NoPen);
+ p.setBrush(brush);
+ p.drawRoundedRect(
+ r + QMargins{ 0, 0, 0, radius + 1 },
+ radius,
+ radius);
+ } else {
+ p.fillRect(r, brush);
+ }
+}
+
+void TopBarAbstract::paintEdges(QPainter &p) const {
+ paintEdges(p, st::boxBg);
+ if (isDark()) {
+ paintEdges(p, st::shadowFg);
+ paintEdges(p, st::shadowFg);
+ }
+}
+
+QRectF TopBarAbstract::starRect(
+ float64 topProgress,
+ float64 sizeProgress) const {
+ const auto starSize = st::settingsPremiumStarSize * sizeProgress;
+ return QRectF(
+ QPointF(
+ (width() - starSize.width()) / 2,
+ st::settingsPremiumStarTopSkip * topProgress),
+ starSize);
+};
+
+bool TopBarAbstract::isDark() const {
+ return _isDark;
+}
+
+void TopBarAbstract::computeIsDark() {
+ const auto contrast = CountContrast(
+ st::boxBg->c,
+ st::premiumButtonFg->c);
+ _isDark = (contrast > kMinAcceptableContrast);
+}
+
+TopBar::TopBar(
+ not_null parent,
+ Fn clickContextOther,
+ rpl::producer title,
+ rpl::producer about,
+ bool light)
+: TopBarAbstract(parent)
+, _light(light)
+, _titleFont(st::boxTitle.style.font)
+, _titlePadding(st::settingsPremiumTitlePadding)
+, _about(
+ this,
+ std::move(about),
+ _light ? st::settingsPremiumUserAbout : st::settingsPremiumAbout)
+, _ministars(this) {
+ std::move(
+ title
+ ) | rpl::start_with_next([=](QString text) {
+ _titlePath = QPainterPath();
+ _titlePath.addText(0, _titleFont->ascent, _titleFont, text);
+ update();
+ }, lifetime());
+
+ if (clickContextOther) {
+ _about->setClickHandlerFilter([=](
+ const ClickHandlerPtr &handler,
+ Qt::MouseButton button) {
+ ActivateClickHandler(_about, handler, {
+ button,
+ clickContextOther()
+ });
+ return false;
+ });
+ }
+
+ rpl::single() | rpl::then(
+ style::PaletteChanged()
+ ) | rpl::start_with_next([=] {
+ TopBarAbstract::computeIsDark();
+
+ if (!_light && !TopBarAbstract::isDark()) {
+ _star.load(Svg());
+ _ministars.setColorOverride(st::premiumButtonFg->c);
+ } else {
+ _star.load(ColorizedSvg());
+ _ministars.setColorOverride(std::nullopt);
+ }
+ auto event = QResizeEvent(size(), size());
+ resizeEvent(&event);
+ }, lifetime());
+
+ if (_light) {
+ const auto smallTopShadow = CreateChild(this);
+ smallTopShadow->setDuration(st::fadeWrapDuration);
+ sizeValue(
+ ) | rpl::start_with_next([=](QSize size) {
+ smallTopShadow->resizeToWidth(size.width());
+ smallTopShadow->moveToLeft(
+ 0,
+ height() - smallTopShadow->height());
+ const auto shown = (minimumHeight() * 2 > size.height());
+ smallTopShadow->toggle(shown, anim::type::normal);
+ }, lifetime());
+ }
+}
+
+TopBar::~TopBar() = default;
+
+void TopBar::setPaused(bool paused) {
+ _ministars.setPaused(paused);
+}
+
+void TopBar::setTextPosition(int x, int y) {
+ _titlePosition = { x, y };
+}
+
+rpl::producer TopBar::additionalHeight() const {
+ return _about->heightValue(
+ ) | rpl::map([l = st::settingsPremiumAbout.style.lineHeight](int height) {
+ return std::max(height - l * 2, 0);
+ });
+}
+
+void TopBar::resizeEvent(QResizeEvent *e) {
+ const auto progress = (e->size().height() - minimumHeight())
+ / float64(maximumHeight() - minimumHeight());
+ _progress.top = 1. -
+ std::clamp(
+ (1. - progress) / kBodyAnimationPart,
+ 0.,
+ 1.);
+ _progress.body = _progress.top;
+ _progress.title = 1. - progress;
+ _progress.scaleTitle = 1. + kTitleAdditionalScale * progress;
+
+ _ministars.setCenter(starRect(_progress.top, 1.).toRect());
+
+ _starRect = starRect(_progress.top, _progress.body);
+
+ const auto &padding = st::boxRowPadding;
+ const auto availableWidth = width() - padding.left() - padding.right();
+ const auto titleTop = _starRect.top()
+ + _starRect.height()
+ + _titlePadding.top();
+ const auto titlePathRect = _titlePath.boundingRect();
+ const auto aboutTop = titleTop
+ + titlePathRect.height()
+ + _titlePadding.bottom();
+ _about->resizeToWidth(availableWidth);
+ _about->moveToLeft(padding.left(), aboutTop);
+ _about->setOpacity(_progress.body);
+
+ RpWidget::resizeEvent(e);
+}
+
+void TopBar::paintEvent(QPaintEvent *e) {
+ auto p = QPainter(this);
+
+ p.fillRect(e->rect(), Qt::transparent);
+
+ const auto r = rect();
+
+ if (!_light && !TopBarAbstract::isDark()) {
+ const auto gradientPointTop = r.height() / 3. * 2.;
+ auto gradient = QLinearGradient(
+ QPointF(0, gradientPointTop),
+ QPointF(r.width(), r.height() - gradientPointTop));
+ gradient.setStops(ButtonGradientStops());
+
+ TopBarAbstract::paintEdges(p, gradient);
+ } else {
+ TopBarAbstract::paintEdges(p);
+ }
+
+ p.setOpacity(_progress.body);
+ p.translate(_starRect.center());
+ p.scale(_progress.body, _progress.body);
+ p.translate(-_starRect.center());
+ if (_progress.top) {
+ _ministars.paint(p);
+ }
+ p.resetTransform();
+
+ _star.render(&p, _starRect);
+
+ const auto color = _light
+ ? st::settingsPremiumUserTitle.textFg
+ : st::premiumButtonFg;
+ p.setPen(color);
+
+ const auto titlePathRect = _titlePath.boundingRect();
+
+ // Title.
+ PainterHighQualityEnabler hq(p);
+ p.setOpacity(1.);
+ p.setFont(_titleFont);
+ const auto fullStarRect = starRect(1., 1.);
+ const auto fullTitleTop = fullStarRect.top()
+ + fullStarRect.height()
+ + _titlePadding.top();
+ p.translate(
+ anim::interpolate(
+ (width() - titlePathRect.width()) / 2,
+ _titlePosition.x(),
+ _progress.title),
+ anim::interpolate(fullTitleTop, _titlePosition.y(), _progress.title));
+
+ p.translate(titlePathRect.center());
+ p.scale(_progress.scaleTitle, _progress.scaleTitle);
+ p.translate(-titlePathRect.center());
+ p.fillPath(_titlePath, color);
+}
+
+} // namespace Ui::Premium
diff --git a/Telegram/SourceFiles/ui/effects/premium_top_bar.h b/Telegram/SourceFiles/ui/effects/premium_top_bar.h
new file mode 100644
index 000000000..0cef38dc5
--- /dev/null
+++ b/Telegram/SourceFiles/ui/effects/premium_top_bar.h
@@ -0,0 +1,93 @@
+/*
+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/object_ptr.h"
+#include "ui/rp_widget.h"
+#include "ui/effects/premium_stars_colored.h"
+
+namespace Ui {
+class FlatLabel;
+} // namespace Ui
+
+namespace Ui::Premium {
+
+[[nodiscard]] QString Svg();
+[[nodiscard]] QByteArray ColorizedSvg();
+[[nodiscard]] QImage GenerateStarForLightTopBar(QRectF rect);
+
+class TopBarAbstract : public RpWidget {
+public:
+ using RpWidget::RpWidget;
+
+ void setRoundEdges(bool value);
+
+ virtual void setPaused(bool paused) = 0;
+ virtual void setTextPosition(int x, int y) = 0;
+
+ [[nodiscard]] virtual rpl::producer additionalHeight() const = 0;
+
+protected:
+ void paintEdges(QPainter &p, const QBrush &brush) const;
+ void paintEdges(QPainter &p) const;
+
+ [[nodiscard]] QRectF starRect(
+ float64 topProgress,
+ float64 sizeProgress) const;
+
+ [[nodiscard]] bool isDark() const;
+ void computeIsDark();
+
+private:
+ bool _roundEdges = true;
+ bool _isDark = false;
+
+};
+
+class TopBar final : public TopBarAbstract {
+public:
+ TopBar(
+ not_null parent,
+ Fn clickContextOther,
+ rpl::producer title,
+ rpl::producer about,
+ bool light = false);
+ ~TopBar();
+
+ void setPaused(bool paused) override;
+ void setTextPosition(int x, int y) override;
+
+ rpl::producer additionalHeight() const override;
+
+protected:
+ void paintEvent(QPaintEvent *e) override;
+ void resizeEvent(QResizeEvent *e) override;
+
+private:
+ const bool _light = false;
+ const style::font &_titleFont;
+ const style::margins &_titlePadding;
+ object_ptr _about;
+ ColoredMiniStars _ministars;
+ QSvgRenderer _star;
+
+ struct {
+ float64 top = 0.;
+ float64 body = 0.;
+ float64 title = 0.;
+ float64 scaleTitle = 0.;
+ } _progress;
+
+ QRectF _starRect;
+
+ QPoint _titlePosition;
+ QPainterPath _titlePath;
+
+};
+
+} // namespace Ui::Premium
diff --git a/Telegram/build/docker/centos_env/Dockerfile b/Telegram/build/docker/centos_env/Dockerfile
index c6cc7117f..1a92eb135 100644
--- a/Telegram/build/docker/centos_env/Dockerfile
+++ b/Telegram/build/docker/centos_env/Dockerfile
@@ -211,7 +211,7 @@ FROM builder AS libvpx
RUN git init libvpx \
&& cd libvpx \
&& git remote add origin {{ GIT }}/webmproject/libvpx.git \
- && git fetch --depth=1 origin e1c124f8965f166d3e9ca26c9215ebc3ec3a1d72 \
+ && git fetch --depth=1 origin 51057f4ba894e13f9bba278905bacf6aaaecd992 \
&& git reset --hard FETCH_HEAD \
&& CFLAGS="$CFLAGS -fno-lto" CXXFLAGS="$CXXFLAGS -fno-lto" ./configure \
--disable-examples \
diff --git a/Telegram/build/prepare/prepare.py b/Telegram/build/prepare/prepare.py
index 1e5aa170d..33ae63dc3 100644
--- a/Telegram/build/prepare/prepare.py
+++ b/Telegram/build/prepare/prepare.py
@@ -837,7 +837,7 @@ stage('libvpx', """
git clone https://github.com/webmproject/libvpx.git
depends:patches/libvpx/*.patch
cd libvpx
- git checkout e1c124f89
+ git checkout 51057f4ba8
win:
for /r %%i in (..\\patches\\libvpx\\*) do git apply %%i
diff --git a/Telegram/build/version b/Telegram/build/version
index 29156e692..aa5d6c6c7 100644
--- a/Telegram/build/version
+++ b/Telegram/build/version
@@ -1,7 +1,7 @@
-AppVersion 4010001
+AppVersion 4010002
AppVersionStrMajor 4.10
-AppVersionStrSmall 4.10.1
-AppVersionStr 4.10.1
+AppVersionStrSmall 4.10.2
+AppVersionStr 4.10.2
BetaChannel 0
AlphaVersion 0
-AppVersionOriginal 4.10.1
+AppVersionOriginal 4.10.2
diff --git a/Telegram/cmake/td_ui.cmake b/Telegram/cmake/td_ui.cmake
index 3a5a539ba..8f0e06312 100644
--- a/Telegram/cmake/td_ui.cmake
+++ b/Telegram/cmake/td_ui.cmake
@@ -282,6 +282,8 @@ PRIVATE
ui/effects/premium_stars.h
ui/effects/premium_stars_colored.cpp
ui/effects/premium_stars_colored.h
+ ui/effects/premium_top_bar.cpp
+ ui/effects/premium_top_bar.h
ui/effects/round_checkbox.cpp
ui/effects/round_checkbox.h
ui/effects/scroll_content_shadow.cpp
diff --git a/Telegram/lib_base b/Telegram/lib_base
index d67a11776..cb8e07fa7 160000
--- a/Telegram/lib_base
+++ b/Telegram/lib_base
@@ -1 +1 @@
-Subproject commit d67a11776ad720a718bae026b78ddd150f13fac5
+Subproject commit cb8e07fa7febcff1dbdbac7bdb0ac46e4eda5c8e
diff --git a/changelog.txt b/changelog.txt
index d94ce148b..821c95794 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,3 +1,7 @@
+4.10.2 (28.09.23)
+
+- Bug fixes and other minor improvements.
+
4.10.1 (23.09.23)
- Rebuild macOS version with Xcode 14.0.1.
diff --git a/cmake b/cmake
index 218a34d9b..b1b0e95b0 160000
--- a/cmake
+++ b/cmake
@@ -1 +1 @@
-Subproject commit 218a34d9b5e3267b86a938b48bd74c045455bd3c
+Subproject commit b1b0e95b091f298c87cb9ec4458f426574221ca4