mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-18 15:17:07 +02:00
Allow setting channel wallpaper.
This commit is contained in:
parent
941126ad69
commit
fd64718502
10 changed files with 420 additions and 164 deletions
Telegram
|
@ -591,6 +591,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_settings_section_background" = "Chat background";
|
||||
"lng_settings_bg_from_gallery" = "Choose from gallery";
|
||||
"lng_settings_bg_from_file" = "Choose from file";
|
||||
"lng_settings_bg_remove" = "Remove wallpaper";
|
||||
"lng_settings_bg_theme_edit" = "Edit theme";
|
||||
"lng_settings_bg_theme_create" = "Create new theme";
|
||||
"lng_settings_bg_cloud_themes" = "Custom themes";
|
||||
|
@ -838,6 +839,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_background_blur" = "Blurred";
|
||||
"lng_background_sure_delete" = "Are you sure you want to delete this background?";
|
||||
"lng_background_other_info" = "{user} will be able to apply this wallpaper";
|
||||
"lng_background_other_channel" = "All subscribers will see this wallpaper";
|
||||
"lng_background_apply1" = "Apply the wallpaper in this chat.";
|
||||
"lng_background_apply2" = "Enjoy the view.";
|
||||
"lng_background_apply_button" = "Apply For This Chat";
|
||||
|
@ -846,6 +848,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_background_reset_default" = "Reset";
|
||||
"lng_background_apply_me" = "Apply for me";
|
||||
"lng_background_apply_both" = "Apply for me and {user}";
|
||||
"lng_background_apply_channel" = "Apply For Channel";
|
||||
|
||||
"lng_download_path_ask" = "Ask download path for each file";
|
||||
"lng_download_path" = "Download path";
|
||||
|
|
|
@ -129,6 +129,8 @@ private:
|
|||
int row) const;
|
||||
void validatePaperThumbnail(const Paper &paper) const;
|
||||
|
||||
[[nodiscard]] bool forChannel() const;
|
||||
|
||||
const not_null<Main::Session*> _session;
|
||||
PeerData * const _forPeer = nullptr;
|
||||
|
||||
|
@ -176,6 +178,23 @@ void BackgroundBox::prepare() {
|
|||
st::infoIconMediaPhoto,
|
||||
st::infoSharedMediaButtonIconPosition);
|
||||
|
||||
if (forChannel() && _forPeer->wallPaper()) {
|
||||
const auto remove = container->add(object_ptr<Ui::SettingsButton>(
|
||||
container,
|
||||
tr::lng_settings_bg_remove(),
|
||||
st::infoBlockButton));
|
||||
object_ptr<Info::Profile::FloatingIcon>(
|
||||
remove,
|
||||
st::infoIconDeleteRed,
|
||||
st::infoSharedMediaButtonIconPosition);
|
||||
|
||||
remove->setClickedCallback([=] {
|
||||
if (const auto resolved = _inner->resolveResetCustomPaper()) {
|
||||
chosen(*resolved);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
button->setClickedCallback([=] {
|
||||
chooseFromFile();
|
||||
});
|
||||
|
@ -290,6 +309,23 @@ void BackgroundBox::chosen(const Data::WallPaper &paper) {
|
|||
closeBox();
|
||||
}
|
||||
return;
|
||||
} else if (forChannel()) {
|
||||
if (_forPeer->wallPaper() && _forPeer->wallPaper()->equals(paper)) {
|
||||
closeBox();
|
||||
return;
|
||||
}
|
||||
const auto &themes = _forPeer->owner().cloudThemes();
|
||||
for (const auto &theme : themes.chatThemes()) {
|
||||
for (const auto &[type, themed] : theme.settings) {
|
||||
if (themed.paper && themed.paper->equals(paper)) {
|
||||
_controller->show(Box<BackgroundPreviewBox>(
|
||||
_controller,
|
||||
Data::WallPaper::FromEmojiId(theme.emoticon),
|
||||
BackgroundPreviewArgs{ _forPeer }));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_controller->show(Box<BackgroundPreviewBox>(
|
||||
_controller,
|
||||
|
@ -316,6 +352,10 @@ void BackgroundBox::resetForPeer() {
|
|||
}
|
||||
}
|
||||
|
||||
bool BackgroundBox::forChannel() const {
|
||||
return _forPeer && _forPeer->isChannel();
|
||||
}
|
||||
|
||||
void BackgroundBox::removePaper(const Data::WallPaper &paper) {
|
||||
const auto session = &_controller->session();
|
||||
const auto remove = [=, weak = Ui::MakeWeak(this)](Fn<void()> &&close) {
|
||||
|
@ -345,9 +385,16 @@ BackgroundBox::Inner::Inner(
|
|||
, _session(session)
|
||||
, _forPeer(forPeer)
|
||||
, _api(&_session->mtp())
|
||||
, _check(std::make_unique<Ui::RoundCheckbox>(st::overviewCheck, [=] { update(); })) {
|
||||
, _check(
|
||||
std::make_unique<Ui::RoundCheckbox>(
|
||||
st::overviewCheck,
|
||||
[=] { update(); })) {
|
||||
_check->setChecked(true, anim::type::instant);
|
||||
resize(st::boxWideWidth, 2 * (st::backgroundSize.height() + st::backgroundPadding) + st::backgroundPadding);
|
||||
resize(
|
||||
st::boxWideWidth,
|
||||
(2 * (st::backgroundSize.height() + st::backgroundPadding)
|
||||
+ st::backgroundPadding));
|
||||
|
||||
Window::Theme::IsNightModeValue(
|
||||
) | rpl::start_with_next([=] {
|
||||
updatePapers();
|
||||
|
@ -364,21 +411,31 @@ BackgroundBox::Inner::Inner(
|
|||
_check->invalidateCache();
|
||||
}, lifetime());
|
||||
|
||||
using Update = Window::Theme::BackgroundUpdate;
|
||||
Window::Theme::Background()->updates(
|
||||
) | rpl::start_with_next([=](const Update &update) {
|
||||
if (update.type == Update::Type::New) {
|
||||
sortPapers();
|
||||
requestPapers();
|
||||
this->update();
|
||||
}
|
||||
}, lifetime());
|
||||
|
||||
if (forChannel()) {
|
||||
_session->data().cloudThemes().chatThemesUpdated(
|
||||
) | rpl::start_with_next([=] {
|
||||
updatePapers();
|
||||
}, lifetime());
|
||||
} else {
|
||||
using Update = Window::Theme::BackgroundUpdate;
|
||||
Window::Theme::Background()->updates(
|
||||
) | rpl::start_with_next([=](const Update &update) {
|
||||
if (update.type == Update::Type::New) {
|
||||
sortPapers();
|
||||
requestPapers();
|
||||
this->update();
|
||||
}
|
||||
}, lifetime());
|
||||
}
|
||||
|
||||
setMouseTracking(true);
|
||||
}
|
||||
|
||||
void BackgroundBox::Inner::requestPapers() {
|
||||
if (forChannel()) {
|
||||
_session->data().cloudThemes().refreshChatThemes();
|
||||
return;
|
||||
}
|
||||
_api.request(MTPaccount_GetWallPapers(
|
||||
MTP_long(_session->data().wallpapersHash())
|
||||
)).done([=](const MTPaccount_WallPapers &result) {
|
||||
|
@ -395,7 +452,7 @@ auto BackgroundBox::Inner::resolveResetCustomPaper() const
|
|||
}
|
||||
const auto nonCustom = Window::Theme::Background()->paper();
|
||||
const auto themeEmoji = _forPeer->themeEmoji();
|
||||
if (themeEmoji.isEmpty()) {
|
||||
if (forChannel() || themeEmoji.isEmpty()) {
|
||||
return nonCustom;
|
||||
}
|
||||
const auto &themes = _forPeer->owner().cloudThemes();
|
||||
|
@ -443,6 +500,8 @@ void BackgroundBox::Inner::pushCustomPapers() {
|
|||
}
|
||||
|
||||
void BackgroundBox::Inner::sortPapers() {
|
||||
Expects(!forChannel());
|
||||
|
||||
const auto currentCustom = _forPeer ? _forPeer->wallPaper() : nullptr;
|
||||
_currentId = currentCustom
|
||||
? currentCustom->id()
|
||||
|
@ -472,23 +531,60 @@ void BackgroundBox::Inner::sortPapers() {
|
|||
}
|
||||
|
||||
void BackgroundBox::Inner::updatePapers() {
|
||||
if (_session->data().wallpapers().empty()) {
|
||||
return;
|
||||
if (forChannel()) {
|
||||
if (_session->data().cloudThemes().chatThemes().empty()) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (_session->data().wallpapers().empty()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
_over = _overDown = Selection();
|
||||
|
||||
_papers = _session->data().wallpapers(
|
||||
) | ranges::views::filter([&](const Data::WallPaper &paper) {
|
||||
return (!paper.isPattern() || !paper.backgroundColors().empty())
|
||||
&& (!_forPeer
|
||||
|| (!Data::IsDefaultWallPaper(paper)
|
||||
&& (Data::IsCloudWallPaper(paper)
|
||||
|| Data::IsCustomWallPaper(paper))));
|
||||
}) | ranges::views::transform([](const Data::WallPaper &paper) {
|
||||
return Paper{ paper };
|
||||
}) | ranges::to_vector;
|
||||
pushCustomPapers();
|
||||
sortPapers();
|
||||
const auto was = base::take(_papers);
|
||||
if (forChannel()) {
|
||||
const auto now = _forPeer->wallPaper();
|
||||
const auto &list = _session->data().cloudThemes().chatThemes();
|
||||
if (list.empty()) {
|
||||
return;
|
||||
}
|
||||
using Type = Data::CloudThemeType;
|
||||
const auto type = Window::Theme::IsNightMode()
|
||||
? Type::Dark
|
||||
: Type::Light;
|
||||
_papers.reserve(list.size() + 1);
|
||||
const auto nowEmojiId = now ? now->emojiId() : QString();
|
||||
if (!now || !now->emojiId().isEmpty()) {
|
||||
_papers.push_back({ Window::Theme::Background()->paper() });
|
||||
_currentId = _papers.back().data.id();
|
||||
} else {
|
||||
_papers.push_back({ *now });
|
||||
_currentId = now->id();
|
||||
}
|
||||
for (const auto &theme : list) {
|
||||
const auto i = theme.settings.find(type);
|
||||
if (i != end(theme.settings) && i->second.paper) {
|
||||
_papers.push_back({ *i->second.paper });
|
||||
if (nowEmojiId == theme.emoticon) {
|
||||
_currentId = _papers.back().data.id();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_papers = _session->data().wallpapers(
|
||||
) | ranges::views::filter([&](const Data::WallPaper &paper) {
|
||||
return (!paper.isPattern() || !paper.backgroundColors().empty())
|
||||
&& (!_forPeer
|
||||
|| (!Data::IsDefaultWallPaper(paper)
|
||||
&& (Data::IsCloudWallPaper(paper)
|
||||
|| Data::IsCustomWallPaper(paper))));
|
||||
}) | ranges::views::transform([](const Data::WallPaper &paper) {
|
||||
return Paper{ paper };
|
||||
}) | ranges::to_vector;
|
||||
pushCustomPapers();
|
||||
sortPapers();
|
||||
}
|
||||
resizeToContentAndPreload();
|
||||
}
|
||||
|
||||
|
@ -587,6 +683,10 @@ void BackgroundBox::Inner::validatePaperThumbnail(
|
|||
paper.thumbnail.setDevicePixelRatio(cRetinaFactor());
|
||||
}
|
||||
|
||||
bool BackgroundBox::Inner::forChannel() const {
|
||||
return _forPeer && _forPeer->isChannel();
|
||||
}
|
||||
|
||||
void BackgroundBox::Inner::paintPaper(
|
||||
QPainter &p,
|
||||
const Paper &paper,
|
||||
|
@ -604,7 +704,8 @@ void BackgroundBox::Inner::paintPaper(
|
|||
const auto checkLeft = x + st::backgroundSize.width() - st::overviewCheckSkip - st::overviewCheck.size;
|
||||
const auto checkTop = y + st::backgroundSize.height() - st::overviewCheckSkip - st::overviewCheck.size;
|
||||
_check->paint(p, checkLeft, checkTop, width());
|
||||
} else if (Data::IsCloudWallPaper(paper.data)
|
||||
} else if (!forChannel()
|
||||
&& Data::IsCloudWallPaper(paper.data)
|
||||
&& !Data::IsDefaultWallPaper(paper.data)
|
||||
&& !Data::IsLegacy2DefaultWallPaper(paper.data)
|
||||
&& !Data::IsLegacy3DefaultWallPaper(paper.data)
|
||||
|
@ -642,7 +743,8 @@ void BackgroundBox::Inner::mouseMoveEvent(QMouseEvent *e) {
|
|||
- st::stickerPanDeleteIconBg.width();
|
||||
const auto deleteBottom = row * (height + skip) + skip
|
||||
+ st::stickerPanDeleteIconBg.height();
|
||||
const auto inDelete = (x >= deleteLeft)
|
||||
const auto inDelete = !forChannel()
|
||||
&& (x >= deleteLeft)
|
||||
&& (y < deleteBottom)
|
||||
&& Data::IsCloudWallPaper(data)
|
||||
&& !Data::IsDefaultWallPaper(data)
|
||||
|
|
|
@ -38,6 +38,7 @@ private:
|
|||
const Data::WallPaper &paper) const;
|
||||
void removePaper(const Data::WallPaper &paper);
|
||||
void resetForPeer();
|
||||
[[nodiscard]] bool forChannel() const;
|
||||
|
||||
void chooseFromFile();
|
||||
|
||||
|
|
|
@ -8,11 +8,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "boxes/background_preview_box.h"
|
||||
|
||||
#include "base/unixtime.h"
|
||||
#include "boxes/peers/edit_peer_color_box.h"
|
||||
#include "boxes/premium_preview_box.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "mainwidget.h"
|
||||
#include "window/themes/window_theme.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "ui/boxes/boost_box.h"
|
||||
#include "ui/controls/chat_service_checkbox.h"
|
||||
#include "ui/chat/chat_theme.h"
|
||||
#include "ui/chat/chat_style.h"
|
||||
|
@ -29,6 +31,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "history/history_item.h"
|
||||
#include "history/history_item_helpers.h"
|
||||
#include "history/view/history_view_message.h"
|
||||
#include "main/main_account.h"
|
||||
#include "main/main_app_config.h"
|
||||
#include "main/main_session.h"
|
||||
#include "apiwrap.h"
|
||||
#include "data/data_session.h"
|
||||
|
@ -159,6 +163,25 @@ constexpr auto kDefaultDimming = 50;
|
|||
return result;
|
||||
}
|
||||
|
||||
[[nodiscard]] Data::WallPaper Resolve(
|
||||
not_null<Main::Session*> session,
|
||||
const Data::WallPaper &paper,
|
||||
bool dark) {
|
||||
if (paper.emojiId().isEmpty()) {
|
||||
return paper;
|
||||
}
|
||||
const auto &themes = session->data().cloudThemes();
|
||||
if (const auto theme = themes.themeForEmoji(paper.emojiId())) {
|
||||
using Type = Data::CloudThemeType;
|
||||
const auto type = dark ? Type::Dark : Type::Light;
|
||||
const auto i = theme->settings.find(type);
|
||||
if (i != end(theme->settings) && i->second.paper) {
|
||||
return *i->second.paper;
|
||||
}
|
||||
}
|
||||
return paper;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
struct BackgroundPreviewBox::OverridenStyle {
|
||||
|
@ -196,15 +219,17 @@ BackgroundPreviewBox::BackgroundPreviewBox(
|
|||
? tr::lng_background_apply2(tr::now)
|
||||
: tr::lng_background_text2(tr::now)),
|
||||
true))
|
||||
, _paper(paper)
|
||||
, _paperEmojiId(paper.emojiId())
|
||||
, _paper(
|
||||
Resolve(&controller->session(), paper, Window::Theme::IsNightMode()))
|
||||
, _media(_paper.document() ? _paper.document()->createMediaView() : nullptr)
|
||||
, _radial([=](crl::time now) { radialAnimationCallback(now); })
|
||||
, _appNightMode(Window::Theme::IsNightModeValue())
|
||||
, _boxDarkMode(_appNightMode.current())
|
||||
, _dimmingIntensity(std::clamp(paper.patternIntensity(), 0, 100))
|
||||
, _dimmingIntensity(std::clamp(_paper.patternIntensity(), 0, 100))
|
||||
, _dimmed(_forPeer
|
||||
&& (paper.document() || paper.localThumbnail())
|
||||
&& !paper.isPattern()) {
|
||||
&& (_paper.document() || _paper.localThumbnail())
|
||||
&& !_paper.isPattern()) {
|
||||
if (_media) {
|
||||
_media->thumbnailWanted(_paper.fileOrigin());
|
||||
}
|
||||
|
@ -244,7 +269,36 @@ BackgroundPreviewBox::BackgroundPreviewBox(
|
|||
|
||||
BackgroundPreviewBox::~BackgroundPreviewBox() = default;
|
||||
|
||||
void BackgroundPreviewBox::recreate(bool dark) {
|
||||
_paper = Resolve(
|
||||
&_controller->session(),
|
||||
Data::WallPaper::FromEmojiId(_paperEmojiId),
|
||||
dark);
|
||||
_media = _paper.document()
|
||||
? _paper.document()->createMediaView()
|
||||
: nullptr;
|
||||
if (_media) {
|
||||
_media->thumbnailWanted(_paper.fileOrigin());
|
||||
}
|
||||
_full = QImage();
|
||||
_generated = _scaled = _blurred = _fadeOutThumbnail = QPixmap();
|
||||
_generating = {};
|
||||
generateBackground();
|
||||
_paper.loadDocument();
|
||||
if (const auto document = _paper.document()) {
|
||||
if (document->loading()) {
|
||||
_radial.start(_media->progress());
|
||||
}
|
||||
}
|
||||
checkLoadedDocument();
|
||||
updateServiceBg(_paper.backgroundColors());
|
||||
update();
|
||||
}
|
||||
|
||||
void BackgroundPreviewBox::applyDarkMode(bool dark) {
|
||||
if (!_paperEmojiId.isEmpty()) {
|
||||
recreate(dark);
|
||||
}
|
||||
const auto equals = (dark == Window::Theme::IsNightMode());
|
||||
const auto &palette = (dark ? _darkPalette : _lightPalette);
|
||||
if (!equals && !palette) {
|
||||
|
@ -410,6 +464,10 @@ auto BackgroundPreviewBox::prepareOverridenStyle(bool dark)
|
|||
return result;
|
||||
}
|
||||
|
||||
bool BackgroundPreviewBox::forChannel() const {
|
||||
return _forPeer && _forPeer->isChannel();
|
||||
}
|
||||
|
||||
void BackgroundPreviewBox::generateBackground() {
|
||||
if (_paper.backgroundColors().empty()) {
|
||||
return;
|
||||
|
@ -435,7 +493,9 @@ void BackgroundPreviewBox::resetTitle() {
|
|||
|
||||
void BackgroundPreviewBox::rebuildButtons(bool dark) {
|
||||
clearButtons();
|
||||
addButton(_forPeer
|
||||
addButton(forChannel()
|
||||
? tr::lng_background_apply_channel()
|
||||
: _forPeer
|
||||
? tr::lng_background_apply_button()
|
||||
: tr::lng_settings_apply(), [=] { apply(); });
|
||||
addButton(tr::lng_cancel(), [=] { closeBox(); });
|
||||
|
@ -624,6 +684,36 @@ void BackgroundPreviewBox::setExistingForPeer(
|
|||
_controller->finishChatThemeEdit(_forPeer);
|
||||
}
|
||||
|
||||
void BackgroundPreviewBox::checkLevelForChannel() {
|
||||
Expects(forChannel());
|
||||
|
||||
const auto show = _controller->uiShow();
|
||||
_forPeerLevelCheck = true;
|
||||
const auto weak = Ui::MakeWeak(this);
|
||||
CheckBoostLevel(show, _forPeer, [=](int level) {
|
||||
if (!weak) {
|
||||
return std::optional<Ui::AskBoostReason>();
|
||||
}
|
||||
const auto appConfig = &_forPeer->session().account().appConfig();
|
||||
const auto defaultRequired = appConfig->get<int>(
|
||||
"channel_wallpaper_level_min",
|
||||
9);
|
||||
const auto customRequired = appConfig->get<int>(
|
||||
"channel_custom_wallpaper_level_min",
|
||||
10);
|
||||
const auto required = _paperEmojiId.isEmpty()
|
||||
? customRequired
|
||||
: defaultRequired;
|
||||
if (level >= required) {
|
||||
applyForPeer(false);
|
||||
return std::optional<Ui::AskBoostReason>();
|
||||
}
|
||||
return std::make_optional(Ui::AskBoostReason{
|
||||
Ui::AskBoostWallpaper{ required }
|
||||
});
|
||||
}, [=] { _forPeerLevelCheck = false; });
|
||||
}
|
||||
|
||||
void BackgroundPreviewBox::applyForPeer() {
|
||||
Expects(_forPeer != nullptr);
|
||||
|
||||
|
@ -636,105 +726,110 @@ void BackgroundPreviewBox::applyForPeer() {
|
|||
}
|
||||
}
|
||||
|
||||
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<Ui::FadeWrap<>>(
|
||||
this,
|
||||
object_ptr<Ui::RpWidget>(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<RoundButton>(
|
||||
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::Wallpapers);
|
||||
}
|
||||
});
|
||||
const auto cancel = CreateChild<RoundButton>(
|
||||
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 {
|
||||
if (forChannel()) {
|
||||
checkLevelForChannel();
|
||||
return;
|
||||
} else if (_fromMessageId || !_forPeer->session().premiumPossible()) {
|
||||
applyForPeer(false);
|
||||
return;
|
||||
} else 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<Ui::FadeWrap<>>(
|
||||
this,
|
||||
object_ptr<Ui::RpWidget>(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<RoundButton>(
|
||||
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::Wallpapers);
|
||||
}
|
||||
});
|
||||
const auto cancel = CreateChild<RoundButton>(
|
||||
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);
|
||||
}
|
||||
|
||||
void BackgroundPreviewBox::applyForPeer(bool both) {
|
||||
if (Data::IsCustomWallPaper(_paper)) {
|
||||
using namespace Data;
|
||||
if (forChannel() && !_paperEmojiId.isEmpty()) {
|
||||
setExistingForPeer(WallPaper::FromEmojiId(_paperEmojiId), both);
|
||||
} else if (IsCustomWallPaper(_paper)) {
|
||||
uploadForPeer(both);
|
||||
} else {
|
||||
setExistingForPeer(_paper, both);
|
||||
|
@ -855,7 +950,7 @@ int BackgroundPreviewBox::textsTop() const {
|
|||
- st::historyPaddingBottom
|
||||
- (_service ? _service->height() : 0)
|
||||
- _text1->height()
|
||||
- _text2->height();
|
||||
- (forChannel() ? _text2->height() : 0);
|
||||
}
|
||||
|
||||
QRect BackgroundPreviewBox::radialRect() const {
|
||||
|
@ -885,10 +980,11 @@ void BackgroundPreviewBox::paintTexts(Painter &p, crl::time ms) {
|
|||
context.outbg = _text1->hasOutLayout();
|
||||
_text1->draw(p, context);
|
||||
p.translate(0, height1);
|
||||
|
||||
context.outbg = _text2->hasOutLayout();
|
||||
_text2->draw(p, context);
|
||||
p.translate(0, height2);
|
||||
if (!forChannel()) {
|
||||
context.outbg = _text2->hasOutLayout();
|
||||
_text2->draw(p, context);
|
||||
p.translate(0, height2);
|
||||
}
|
||||
}
|
||||
|
||||
void BackgroundPreviewBox::radialAnimationCallback(crl::time now) {
|
||||
|
@ -988,7 +1084,9 @@ void BackgroundPreviewBox::updateServiceBg(const std::vector<QColor> &bg) {
|
|||
_service = GenerateServiceItem(
|
||||
delegate(),
|
||||
_serviceHistory,
|
||||
((_forPeer && !_fromMessageId)
|
||||
(forChannel()
|
||||
? tr::lng_background_other_channel(tr::now)
|
||||
: (_forPeer && !_fromMessageId)
|
||||
? tr::lng_background_other_info(
|
||||
tr::now,
|
||||
lt_user,
|
||||
|
|
|
@ -94,18 +94,24 @@ private:
|
|||
void applyDarkMode(bool dark);
|
||||
[[nodiscard]] OverridenStyle prepareOverridenStyle(bool dark);
|
||||
|
||||
[[nodiscard]] bool forChannel() const;
|
||||
void checkLevelForChannel();
|
||||
|
||||
void recreate(bool dark);
|
||||
void resetTitle();
|
||||
void rebuildButtons(bool dark);
|
||||
void createDimmingSlider(bool dark);
|
||||
|
||||
const not_null<Window::SessionController*> _controller;
|
||||
PeerData * const _forPeer = nullptr;
|
||||
bool _forPeerLevelCheck = false;
|
||||
FullMsgId _fromMessageId;
|
||||
std::unique_ptr<Ui::ChatStyle> _chatStyle;
|
||||
const not_null<History*> _serviceHistory;
|
||||
AdminLog::OwnedItem _service;
|
||||
AdminLog::OwnedItem _text1;
|
||||
AdminLog::OwnedItem _text2;
|
||||
QString _paperEmojiId;
|
||||
Data::WallPaper _paper;
|
||||
std::shared_ptr<Data::DocumentMedia> _media;
|
||||
QImage _full;
|
||||
|
|
|
@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "api/api_peer_photo.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "boxes/peers/replace_boost_box.h"
|
||||
#include "boxes/background_box.h"
|
||||
#include "chat_helpers/compose/compose_show.h"
|
||||
#include "data/data_changes.h"
|
||||
#include "data/data_channel.h"
|
||||
|
@ -524,13 +525,7 @@ void Apply(
|
|||
Set(show, peer, values);
|
||||
close();
|
||||
} else {
|
||||
session->api().request(MTPpremium_GetBoostsStatus(
|
||||
peer->input
|
||||
)).done([=](const MTPpremium_BoostsStatus &result) {
|
||||
const auto &data = result.data();
|
||||
if (const auto channel = peer->asChannel()) {
|
||||
channel->updateLevelHint(data.vlevel().v);
|
||||
}
|
||||
CheckBoostLevel(show, peer, [=](int level) {
|
||||
const auto peerColors = &peer->session().api().peerColors();
|
||||
const auto colorRequired = peerColors->requiredLevelFor(
|
||||
peer->id,
|
||||
|
@ -551,38 +546,21 @@ void Apply(
|
|||
iconRequired,
|
||||
statusRequired,
|
||||
});
|
||||
const auto current = data.vlevel().v;
|
||||
if (current >= required) {
|
||||
if (level >= required) {
|
||||
Set(show, peer, values);
|
||||
close();
|
||||
return;
|
||||
return std::optional<Ui::AskBoostReason>();
|
||||
}
|
||||
const auto openStatistics = [=] {
|
||||
if (const auto controller = show->resolveWindow(
|
||||
ChatHelpers::WindowUsage::PremiumPromo)) {
|
||||
controller->showSection(Info::Boosts::Make(peer));
|
||||
}
|
||||
};
|
||||
auto counters = ParseBoostCounters(result);
|
||||
counters.mine = 0; // Don't show current level as just-reached.
|
||||
const auto reason = [&]() -> Ui::AskBoostReason {
|
||||
if (current < statusRequired) {
|
||||
if (level < statusRequired) {
|
||||
return { Ui::AskBoostEmojiStatus{ statusRequired } };
|
||||
} else if (current < iconRequired) {
|
||||
} else if (level < iconRequired) {
|
||||
return { Ui::AskBoostChannelColor{ iconRequired } };
|
||||
}
|
||||
return { Ui::AskBoostChannelColor{ colorRequired } };
|
||||
}();
|
||||
show->show(Box(Ui::AskBoostBox, Ui::AskBoostBoxData{
|
||||
.link = qs(data.vboost_url()),
|
||||
.boost = counters,
|
||||
.reason = reason,
|
||||
}, openStatistics, nullptr));
|
||||
cancel();
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
show->showToast(error.type());
|
||||
cancel();
|
||||
}).send();
|
||||
return std::make_optional(reason);
|
||||
}, cancel);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -978,6 +956,23 @@ void EditPeerColorBox(
|
|||
: tr::lng_settings_color_emoji_about_channel());
|
||||
|
||||
if (const auto channel = peer->asChannel()) {
|
||||
Ui::AddSkip(container, st::settingsColorSampleSkip);
|
||||
container->add(object_ptr<Ui::SettingsButton>(
|
||||
container,
|
||||
tr::lng_edit_channel_wallpaper(),
|
||||
st::settingsButtonNoIcon)
|
||||
)->setClickedCallback([=] {
|
||||
const auto usage = ChatHelpers::WindowUsage::PremiumPromo;
|
||||
if (const auto strong = show->resolveWindow(usage)) {
|
||||
show->show(Box<BackgroundBox>(strong, channel));
|
||||
}
|
||||
});
|
||||
|
||||
Ui::AddSkip(container, st::settingsColorSampleSkip);
|
||||
Ui::AddDividerText(
|
||||
container,
|
||||
tr::lng_edit_channel_wallpaper_about());
|
||||
|
||||
// Preload exceptions list.
|
||||
const auto peerPhoto = &channel->session().api().peerPhoto();
|
||||
[[maybe_unused]] auto list = peerPhoto->emojiListValue(
|
||||
|
@ -1110,3 +1105,39 @@ void AddPeerColorButton(
|
|||
show->show(Box(EditPeerColorBox, show, peer, style, theme));
|
||||
});
|
||||
}
|
||||
|
||||
void CheckBoostLevel(
|
||||
std::shared_ptr<ChatHelpers::Show> show,
|
||||
not_null<PeerData*> peer,
|
||||
Fn<std::optional<Ui::AskBoostReason>(int level)> askMore,
|
||||
Fn<void()> cancel) {
|
||||
peer->session().api().request(MTPpremium_GetBoostsStatus(
|
||||
peer->input
|
||||
)).done([=](const MTPpremium_BoostsStatus &result) {
|
||||
const auto &data = result.data();
|
||||
if (const auto channel = peer->asChannel()) {
|
||||
channel->updateLevelHint(data.vlevel().v);
|
||||
}
|
||||
const auto reason = askMore(data.vlevel().v);
|
||||
if (!reason) {
|
||||
return;
|
||||
}
|
||||
const auto openStatistics = [=] {
|
||||
if (const auto controller = show->resolveWindow(
|
||||
ChatHelpers::WindowUsage::PremiumPromo)) {
|
||||
controller->showSection(Info::Boosts::Make(peer));
|
||||
}
|
||||
};
|
||||
auto counters = ParseBoostCounters(result);
|
||||
counters.mine = 0; // Don't show current level as just-reached.
|
||||
show->show(Box(Ui::AskBoostBox, Ui::AskBoostBoxData{
|
||||
.link = qs(data.vboost_url()),
|
||||
.boost = counters,
|
||||
.reason = *reason,
|
||||
}, openStatistics, nullptr));
|
||||
cancel();
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
show->showToast(error.type());
|
||||
cancel();
|
||||
}).send();
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ class GenericBox;
|
|||
class ChatStyle;
|
||||
class ChatTheme;
|
||||
class VerticalLayout;
|
||||
struct AskBoostReason;
|
||||
} // namespace Ui
|
||||
|
||||
void EditPeerColorBox(
|
||||
|
@ -29,3 +30,9 @@ void AddPeerColorButton(
|
|||
not_null<Ui::VerticalLayout*> container,
|
||||
std::shared_ptr<ChatHelpers::Show> show,
|
||||
not_null<PeerData*> peer);
|
||||
|
||||
void CheckBoostLevel(
|
||||
std::shared_ptr<ChatHelpers::Show> show,
|
||||
not_null<PeerData*> peer,
|
||||
Fn<std::optional<Ui::AskBoostReason>(int level)> askMore,
|
||||
Fn<void()> cancel);
|
||||
|
|
|
@ -698,6 +698,12 @@ std::optional<WallPaper> WallPaper::FromColorsSlug(const QString &slug) {
|
|||
return result;
|
||||
}
|
||||
|
||||
WallPaper WallPaper::FromEmojiId(const QString &emojiId) {
|
||||
auto result = WallPaper(0);
|
||||
result._emojiId = emojiId;
|
||||
return result;
|
||||
}
|
||||
|
||||
WallPaper WallPaper::ConstructDefault() {
|
||||
auto result = WallPaper(
|
||||
kDefaultBackground
|
||||
|
|
|
@ -103,6 +103,7 @@ public:
|
|||
qint32 legacyId);
|
||||
[[nodiscard]] static std::optional<WallPaper> FromColorsSlug(
|
||||
const QString &slug);
|
||||
[[nodiscard]] static WallPaper FromEmojiId(const QString &emojiId);
|
||||
[[nodiscard]] static WallPaper ConstructDefault();
|
||||
|
||||
private:
|
||||
|
|
|
@ -404,6 +404,7 @@ infoIconMediaStoriesRecent: icon {{ "info/info_stories_recent", infoIconFg }};
|
|||
infoIconShare: icon {{ "info/info_share", infoIconFg }};
|
||||
infoIconEdit: icon {{ "info/info_edit", infoIconFg }};
|
||||
infoIconDelete: icon {{ "info/info_delete", infoIconFg }};
|
||||
infoIconDeleteRed: icon {{ "info/info_delete", attentionButtonFg }};
|
||||
infoIconReport: icon {{ "info/info_report", attentionButtonFg }};
|
||||
infoIconLeave: icon {{ "info/info_leave", infoIconFg }};
|
||||
infoIconBlock: icon {{ "info/info_block", attentionButtonFg }};
|
||||
|
|
Loading…
Add table
Reference in a new issue