From 8c3fa14a75760735215e8cc70302f5ee645e0614 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 28 Nov 2023 18:29:29 +0400 Subject: [PATCH] Allow setting background for both sides. --- Telegram/Resources/icons/chat/mini_lock.png | Bin 0 -> 266 bytes .../Resources/icons/chat/mini_lock@2x.png | Bin 0 -> 358 bytes .../Resources/icons/chat/mini_lock@3x.png | Bin 0 -> 489 bytes Telegram/Resources/langs/lang.strings | 2 + .../boxes/background_preview_box.cpp | 137 ++++++++++++++++-- .../boxes/background_preview_box.h | 9 +- Telegram/SourceFiles/boxes/boxes.style | 21 +++ .../media/history_view_similar_channels.cpp | 11 +- Telegram/SourceFiles/info/info.style | 10 +- .../info_similar_channels_widget.cpp | 7 +- .../SourceFiles/settings/settings_premium.cpp | 55 +++++++ .../SourceFiles/settings/settings_premium.h | 12 ++ Telegram/SourceFiles/ui/chat/chat.style | 4 +- 13 files changed, 245 insertions(+), 23 deletions(-) create mode 100644 Telegram/Resources/icons/chat/mini_lock.png create mode 100644 Telegram/Resources/icons/chat/mini_lock@2x.png create mode 100644 Telegram/Resources/icons/chat/mini_lock@3x.png diff --git a/Telegram/Resources/icons/chat/mini_lock.png b/Telegram/Resources/icons/chat/mini_lock.png new file mode 100644 index 0000000000000000000000000000000000000000..a81e9beb5ec25e5408f953e407048574badf0332 GIT binary patch literal 266 zcmeAS@N?(olHy`uVBq!ia0vp^JRr=$1SD^YpWXnZ7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TW!7X8|*U4N@q~^D7oem3X>1hDbUIrd`` zhR33^&;4Ah;_xRXj5G{V!$T z7`}c67_6&|oECN7tEVvb zx(}yGlY!I4kYGix;f3sy-QXneQ{@}sA#pUXO@geCwv0C&p( literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/chat/mini_lock@3x.png b/Telegram/Resources/icons/chat/mini_lock@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..2fd8ee86a64f4af86d4e9f3a97266a5e38dfccec GIT binary patch literal 489 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1SIp4_|F3=#^NA%Cx&(BWL^R}E~ycoX}-P; zT0k}j17mw80}DtA5K93u0|WB{Mh0de%?J`(zyz07S-^~7gA{7SoYA4F`Jyqg?9GqdoyH@O^Uc4%tad+KazTEp2lXC~$7 zS-MSl^=?(xF3G&@uVbWtOqaeeW!bh|YYwK%X7U+J&QCt@+Yb6VNpEUeBinN z!$O(Pm6@~l2s%xYZ)-e1|IiUZf8X18;##(-Tz=r(=3=>FnM8v4r={%?Yi~Mp|9rB1 zMwjc(b>5bV5I=RKdAy3$J9*pR3B#mja<<_U_4RjMM#H{SRg(dx32Rrz~u{TAW$ zUF(v6G2e=L8Y{YQcaP7G-?kMeqw^nM?TP<;`p5Y-h4a#{DjpHKnBseRg;}-Zr`v}L z=aj}Ctv8Hkl@z-AJ-Mc1^{QFRI?Zj91RSidc7EM+VQXV~&I9Q;jWeBm*I4j@g4xs6 K&t;ucLK6VN9ll5a literal 0 HcmV?d00001 diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index f35d705113..faefa64bf3 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -839,6 +839,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_background_dimming" = "Background dimming"; "lng_background_sure_reset_default" = "Are you sure you want to reset the wallpaper?"; "lng_background_reset_default" = "Reset"; +"lng_background_apply_me" = "Apply for me"; +"lng_background_apply_both" = "Apply for me and {user}"; "lng_download_path_ask" = "Ask download path for each file"; "lng_download_path" = "Download path"; diff --git a/Telegram/SourceFiles/boxes/background_preview_box.cpp b/Telegram/SourceFiles/boxes/background_preview_box.cpp index e0f99a7a1a..09cd207812 100644 --- a/Telegram/SourceFiles/boxes/background_preview_box.cpp +++ b/Telegram/SourceFiles/boxes/background_preview_box.cpp @@ -7,6 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "boxes/background_preview_box.h" +#include "base/unixtime.h" +#include "boxes/premium_preview_box.h" #include "lang/lang_keys.h" #include "mainwidget.h" #include "window/themes/window_theme.h" @@ -18,6 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/image/image.h" #include "ui/widgets/checkbox.h" #include "ui/widgets/continuous_sliders.h" +#include "ui/wrap/fade_wrap.h" #include "ui/wrap/slide_wrap.h" #include "ui/painter.h" #include "ui/vertical_list.h" @@ -34,12 +37,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_document_media.h" #include "data/data_document_resolver.h" #include "data/data_file_origin.h" -#include "base/unixtime.h" -#include "boxes/background_preview_box.h" -#include "window/window_session_controller.h" -#include "window/themes/window_themes_embedded.h" +#include "data/data_peer_values.h" +#include "settings/settings_premium.h" #include "storage/file_upload.h" #include "storage/localimageloader.h" +#include "window/window_session_controller.h" +#include "window/themes/window_themes_embedded.h" #include "styles/style_chat.h" #include "styles/style_layers.h" #include "styles/style_boxes.h" @@ -509,6 +512,10 @@ void BackgroundPreviewBox::recreateBlurCheckbox() { }, _blur->lifetime()); _blur->setDisabled(_paper.document() && _full.isNull()); + + if (_forBothOverlay) { + _forBothOverlay->raise(); + } } void BackgroundPreviewBox::apply() { @@ -519,7 +526,7 @@ void BackgroundPreviewBox::apply() { } } -void BackgroundPreviewBox::uploadForPeer() { +void BackgroundPreviewBox::uploadForPeer(bool both) { Expects(_forPeer != nullptr); if (_uploadId) { @@ -578,7 +585,7 @@ void BackgroundPreviewBox::uploadForPeer() { "Got wallPaperNoFile after account.UploadWallPaper.")); }); if (const auto paper = Data::WallPaper::Create(session, result)) { - setExistingForPeer(*paper); + setExistingForPeer(*paper, both); } }).send(); }, _uploadLifetime); @@ -587,7 +594,9 @@ void BackgroundPreviewBox::uploadForPeer() { _radial.start(_uploadProgress); } -void BackgroundPreviewBox::setExistingForPeer(const Data::WallPaper &paper) { +void BackgroundPreviewBox::setExistingForPeer( + const Data::WallPaper &paper, + bool both) { Expects(_forPeer != nullptr); if (const auto already = _forPeer->wallPaper()) { @@ -601,6 +610,7 @@ void BackgroundPreviewBox::setExistingForPeer(const Data::WallPaper &paper) { api->request(MTPmessages_SetChatWallPaper( MTP_flags((_fromMessageId ? Flag::f_id : Flag()) | (_fromMessageId ? Flag() : Flag::f_wallpaper) + | (both ? Flag::f_for_both : Flag()) | Flag::f_settings), _forPeer->input, paper.mtpInput(&_controller->session()), @@ -617,10 +627,117 @@ void BackgroundPreviewBox::setExistingForPeer(const Data::WallPaper &paper) { void BackgroundPreviewBox::applyForPeer() { Expects(_forPeer != nullptr); - if (Data::IsCustomWallPaper(_paper)) { - uploadForPeer(); + if (!Data::IsCustomWallPaper(_paper)) { + if (const auto already = _forPeer->wallPaper()) { + if (already->equals(_paper)) { + _controller->finishChatThemeEdit(_forPeer); + return; + } + } + } + + if (!_fromMessageId && _forPeer->session().premiumPossible()) { + if (_forBothOverlay) { + return; + } + const auto size = this->size() * style::DevicePixelRatio(); + const auto bg = Images::DitherImage( + Images::BlurLargeImage( + Ui::GrabWidgetToImage(this).scaled( + size / style::ConvertScale(4), + Qt::IgnoreAspectRatio, + Qt::SmoothTransformation), + 24).scaled( + size, + Qt::IgnoreAspectRatio, + Qt::SmoothTransformation)); + + _forBothOverlay = std::make_unique>( + this, + object_ptr(this)); + const auto overlay = _forBothOverlay->entity(); + + sizeValue() | rpl::start_with_next([=](QSize size) { + _forBothOverlay->setGeometry({ QPoint(), size }); + overlay->setGeometry({ QPoint(), size }); + }, _forBothOverlay->lifetime()); + + overlay->paintRequest( + ) | rpl::start_with_next([=](QRect clip) { + auto p = QPainter(overlay); + p.drawImage(0, 0, bg); + p.fillRect(clip, QColor(0, 0, 0, 64)); + }, overlay->lifetime()); + + using namespace Ui; + const auto forMe = CreateChild( + overlay, + tr::lng_background_apply_me(), + st::backgroundConfirm); + forMe->setClickedCallback([=] { + applyForPeer(false); + }); + using namespace rpl::mappers; + const auto forBoth = ::Settings::CreateLockedButton( + overlay, + tr::lng_background_apply_both( + lt_user, + rpl::single(_forPeer->shortName())), + st::backgroundConfirm, + Data::AmPremiumValue(&_forPeer->session()) | rpl::map(!_1)); + forBoth->setClickedCallback([=] { + if (_forPeer->session().premium()) { + applyForPeer(true); + } else { + ShowPremiumPreviewBox( + _controller->uiShow(), + PremiumPreview::AnimatedEmoji); + } + }); + const auto cancel = CreateChild( + overlay, + tr::lng_cancel(), + st::backgroundConfirmCancel); + cancel->setClickedCallback([=] { + const auto raw = _forBothOverlay.release(); + raw->shownValue() | rpl::filter( + !rpl::mappers::_1 + ) | rpl::take(1) | rpl::start_with_next(crl::guard(raw, [=] { + delete raw; + }), 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::start_with_next([=](QSize size) { + const auto padding = st::backgroundConfirmPadding; + const auto width = size.width() + - padding.left() + - padding.right(); + const auto height = cancel->height(); + auto top = size.height() - padding.bottom() - height; + cancel->setGeometry(padding.left(), top, width, height); + top -= height + padding.top(); + forBoth->setGeometry(padding.left(), top, width, height); + top -= height + padding.top(); + forMe->setGeometry(padding.left(), top, width, height); + }, _forBothOverlay->lifetime()); + + _forBothOverlay->hide(anim::type::instant); + _forBothOverlay->show(anim::type::normal); } else { - setExistingForPeer(_paper); + applyForPeer(false); + } +} + +void BackgroundPreviewBox::applyForPeer(bool both) { + if (Data::IsCustomWallPaper(_paper)) { + uploadForPeer(both); + } else { + setExistingForPeer(_paper, both); } } diff --git a/Telegram/SourceFiles/boxes/background_preview_box.h b/Telegram/SourceFiles/boxes/background_preview_box.h index 2916cd7768..8c1bd43462 100644 --- a/Telegram/SourceFiles/boxes/background_preview_box.h +++ b/Telegram/SourceFiles/boxes/background_preview_box.h @@ -29,6 +29,8 @@ class ChatStyle; class MediaSlider; template class SlideWrap; +template +class FadeWrap; } // namespace Ui struct BackgroundPreviewArgs { @@ -66,9 +68,10 @@ private: void apply(); void applyForPeer(); + void applyForPeer(bool both); void applyForEveryone(); - void uploadForPeer(); - void setExistingForPeer(const Data::WallPaper &paper); + void uploadForPeer(bool both); + void setExistingForPeer(const Data::WallPaper &paper, bool both); void share(); void radialAnimationCallback(crl::time now); QRect radialRect() const; @@ -131,6 +134,8 @@ private: float64 _uploadProgress = 0.; rpl::lifetime _uploadLifetime; + std::unique_ptr> _forBothOverlay; + rpl::variable _paletteServiceBg; rpl::lifetime _serviceBgLifetime; diff --git a/Telegram/SourceFiles/boxes/boxes.style b/Telegram/SourceFiles/boxes/boxes.style index 62eb6dc6be..f43708f48a 100644 --- a/Telegram/SourceFiles/boxes/boxes.style +++ b/Telegram/SourceFiles/boxes/boxes.style @@ -753,7 +753,28 @@ backgroundCheck: ServiceCheck { color: msgServiceFg; duration: 200; } +backgroundConfirmPadding: margins(24px, 16px, 24px, 16px); +backgroundConfirm: RoundButton(defaultActiveButton) { + height: 44px; + textTop: 12px; + font: font(13px semibold); +} +backgroundConfirmCancel: RoundButton(backgroundConfirm) { + textFg: mediaviewSaveMsgFg; + textFgOver: mediaviewSaveMsgFg; + numbersTextFg: mediaviewSaveMsgFg; + numbersTextFgOver: mediaviewSaveMsgFg; + textBg: shadowFg; + textBgOver: shadowFg; + height: 44px; + textTop: 12px; + font: font(13px semibold); + + ripple: RippleAnimation(defaultRippleAnimation) { + color: shadowFg; + } +} urlAuthCheckbox: Checkbox(defaultBoxCheckbox) { width: 240px; } diff --git a/Telegram/SourceFiles/history/view/media/history_view_similar_channels.cpp b/Telegram/SourceFiles/history/view/media/history_view_similar_channels.cpp index 2ab07ee667..3081fa8232 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_similar_channels.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_similar_channels.cpp @@ -406,6 +406,11 @@ void SimilarChannels::validateCounterBg(const Channel &channel) const { channel.counterRect = badge.marginsAdded( st::chatSimilarBadgePadding); + constexpr auto kMinSaturation = 0; + constexpr auto kMaxSaturation = 96; + constexpr auto kMinLightness = 160; + constexpr auto kMaxLightness = 208; + const auto width = channel.counterRect.width(); const auto height = channel.counterRect.height(); const auto ratio = style::DevicePixelRatio(); @@ -413,16 +418,12 @@ void SimilarChannels::validateCounterBg(const Channel &channel) const { channel.counterRect.size() * ratio, QImage::Format_ARGB32_Premultiplied); auto color = channel.more - ? st::windowBgRipple->c + ? QColor(kMinLightness, kMinLightness, kMinLightness) : Ui::CountAverageColor( channel.thumbnail->image(photo).copy( QRect(photo / 3, photo / 3, photo / 3, photo / 3))); const auto hsl = color.toHsl(); - constexpr auto kMinSaturation = 0; - constexpr auto kMaxSaturation = 96; - constexpr auto kMinLightness = 160; - constexpr auto kMaxLightness = 208; if (!base::in_range(hsl.saturation(), kMinSaturation, kMaxSaturation) || !base::in_range(hsl.lightness(), kMinLightness, kMaxLightness)) { color = QColor::fromHsl( diff --git a/Telegram/SourceFiles/info/info.style b/Telegram/SourceFiles/info/info.style index 0c74019649..2be1c96501 100644 --- a/Telegram/SourceFiles/info/info.style +++ b/Telegram/SourceFiles/info/info.style @@ -956,7 +956,15 @@ permissionsExpandIcon: icon{{ "info/edit/expand_arrow_small", windowBoldFg }}; similarChannelsLockOverlap: 58px; similarChannelsLockFade: 58px; -similarChannelsLock: defaultActiveButton; +similarChannelsLock: RoundButton(defaultActiveButton) { + height: 44px; + textTop: 12px; + font: font(13px semibold); +} +similarChannelsLockLabel: FlatLabel(defaultFlatLabel) { + textFg: premiumButtonFg; + style: semiboldTextStyle; +} similarChannelsLockPadding: margins(12px, 12px, 12px, 12px); similarChannelsLockAbout: FlatLabel(defaultFlatLabel) { textFg: windowSubTextFg; diff --git a/Telegram/SourceFiles/info/similar_channels/info_similar_channels_widget.cpp b/Telegram/SourceFiles/info/similar_channels/info_similar_channels_widget.cpp index 049ea9fddf..14474faf93 100644 --- a/Telegram/SourceFiles/info/similar_channels/info_similar_channels_widget.cpp +++ b/Telegram/SourceFiles/info/similar_channels/info_similar_channels_widget.cpp @@ -144,15 +144,16 @@ void ListController::setupUnlock() { _unlock = Ui::CreateChild(_content); _unlock->show(); - const auto button = Ui::CreateChild( + const auto button = ::Settings::CreateLockedButton( _unlock, tr::lng_similar_channels_show_more(), - st::similarChannelsLock); - button->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); + st::similarChannelsLock, + rpl::single(true)); button->setClickedCallback([=] { const auto window = _controller->parentController(); ::Settings::ShowPremium(window, u"similar_channels"_q); }); + const auto upto = Data::PremiumLimits( &_channel->session()).similarChannelsPremium(); const auto about = Ui::CreateChild( diff --git a/Telegram/SourceFiles/settings/settings_premium.cpp b/Telegram/SourceFiles/settings/settings_premium.cpp index 9d979bdbd2..3ffb3de338 100644 --- a/Telegram/SourceFiles/settings/settings_premium.cpp +++ b/Telegram/SourceFiles/settings/settings_premium.cpp @@ -56,6 +56,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/unixtime.h" #include "apiwrap.h" #include "api/api_premium.h" +#include "styles/style_chat_helpers.h" #include "styles/style_premium.h" #include "styles/style_info.h" #include "styles/style_layers.h" @@ -1497,6 +1498,60 @@ void ShowPremiumPromoToast( }); } +not_null CreateLockedButton( + not_null parent, + rpl::producer text, + const style::RoundButton &st, + rpl::producer locked) { + const auto result = Ui::CreateChild( + parent.get(), + rpl::single(QString()), + st); + + const auto labelSt = result->lifetime().make_state( + st::defaultFlatLabel); + labelSt->style.font = st.font; + labelSt->textFg = st.textFg; + + const auto label = Ui::CreateChild( + result, + std::move(text), + *labelSt); + label->setAttribute(Qt::WA_TransparentForMouseEvents); + + const auto icon = Ui::CreateChild(result); + icon->setAttribute(Qt::WA_TransparentForMouseEvents); + icon->resize(st::stickersPremiumLock.size()); + icon->paintRequest() | rpl::start_with_next([=] { + auto p = QPainter(icon); + st::stickersPremiumLock.paint(p, 0, 0, icon->width()); + }, icon->lifetime()); + + rpl::combine( + result->widthValue(), + label->widthValue(), + std::move(locked) + ) | rpl::start_with_next([=](int outer, int inner, bool locked) { + if (locked) { + icon->show(); + inner += icon->width(); + label->move( + (outer - inner) / 2 + icon->width(), + st::similarChannelsLock.textTop); + icon->move( + (outer - inner) / 2, + st::similarChannelsLock.textTop); + } else { + icon->hide(); + label->move( + (outer - inner) / 2, + st::similarChannelsLock.textTop); + } + }, result->lifetime()); + + return result; +} + not_null CreateSubscribeButton( SubscribeButtonArgs &&args) { Expects(args.show || args.controller); diff --git a/Telegram/SourceFiles/settings/settings_premium.h b/Telegram/SourceFiles/settings/settings_premium.h index 6bc1775fdf..44d9c8ea4c 100644 --- a/Telegram/SourceFiles/settings/settings_premium.h +++ b/Telegram/SourceFiles/settings/settings_premium.h @@ -11,12 +11,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL enum class PremiumPreview; +namespace style { +struct RoundButton; +} // namespace style + namespace ChatHelpers { class Show; } // namespace ChatHelpers namespace Ui { class RpWidget; +class RoundButton; class GradientButton; } // namespace Ui @@ -66,6 +71,13 @@ struct SubscribeButtonArgs final { std::shared_ptr show; }; + +[[nodiscard]] not_null CreateLockedButton( + not_null parent, + rpl::producer text, + const style::RoundButton &st, + rpl::producer locked); + [[nodiscard]] not_null CreateSubscribeButton( SubscribeButtonArgs &&args); diff --git a/Telegram/SourceFiles/ui/chat/chat.style b/Telegram/SourceFiles/ui/chat/chat.style index 2fef5dfa09..875ba5f2c2 100644 --- a/Telegram/SourceFiles/ui/chat/chat.style +++ b/Telegram/SourceFiles/ui/chat/chat.style @@ -991,8 +991,8 @@ chatSimilarBadgePadding: margins(2px, 0px, 3px, 1px); chatSimilarBadgeTop: 43px; chatSimilarBadgeIcon: icon{{ "chat/mini_subscribers", premiumButtonFg }}; chatSimilarBadgeIconPosition: point(0px, 1px); -chatSimilarLockedIcon: icon{{ "emoji/premium_lock", premiumButtonFg }}; -chatSimilarLockedIconPosition: point(0px, -1px); +chatSimilarLockedIcon: icon{{ "chat/mini_lock", premiumButtonFg }}; +chatSimilarLockedIconPosition: point(0px, 1px); chatSimilarBadgeFont: font(10px bold); chatSimilarNameTop: 59px; chatSimilarName: TextStyle(defaultTextStyle) {