mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-18 15:17:07 +02:00
Initial starref setup section implementation.
This commit is contained in:
parent
a6bfd35f1a
commit
1e15764bb9
17 changed files with 896 additions and 21 deletions
Telegram
|
@ -918,6 +918,8 @@ PRIVATE
|
|||
info/bot/earn/info_bot_earn_list.h
|
||||
info/bot/earn/info_bot_earn_widget.cpp
|
||||
info/bot/earn/info_bot_earn_widget.h
|
||||
info/bot/starref/info_bot_starref_widget.cpp
|
||||
info/bot/starref/info_bot_starref_widget.h
|
||||
info/channel_statistics/boosts/create_giveaway_box.cpp
|
||||
info/channel_statistics/boosts/create_giveaway_box.h
|
||||
info/channel_statistics/boosts/giveaway/giveaway_list_controllers.cpp
|
||||
|
|
BIN
Telegram/Resources/art/affiliate_logo.png
Normal file
BIN
Telegram/Resources/art/affiliate_logo.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 78 KiB |
|
@ -4,6 +4,7 @@
|
|||
<file alias="art/bg_thumbnail.png">../../art/bg_thumbnail.png</file>
|
||||
<file alias="art/bg_initial.jpg">../../art/bg_initial.jpg</file>
|
||||
<file alias="art/business_logo.png">../../art/business_logo.png</file>
|
||||
<file alias="art/affiliate_logo.png">../../art/affiliate_logo.png</file>
|
||||
<file alias="art/logo_256.png">../../art/logo_256.png</file>
|
||||
<file alias="art/logo_256_no_margin.png">../../art/logo_256_no_margin.png</file>
|
||||
<file alias="art/themeimage.jpg">../../art/themeimage.jpg</file>
|
||||
|
|
|
@ -46,6 +46,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_user.h"
|
||||
#include "history/admin_log/history_admin_log_section.h"
|
||||
#include "info/bot/earn/info_bot_earn_widget.h"
|
||||
#include "info/bot/starref/info_bot_starref_widget.h"
|
||||
#include "info/channel_statistics/boosts/info_boosts_widget.h"
|
||||
#include "info/channel_statistics/earn/earn_format.h"
|
||||
#include "info/channel_statistics/earn/earn_icons.h"
|
||||
|
@ -358,6 +359,7 @@ private:
|
|||
void fillBotUsernamesButton();
|
||||
void fillBotCurrencyButton();
|
||||
void fillBotCreditsButton();
|
||||
void fillBotAffiliateProgram();
|
||||
void fillBotEditIntroButton();
|
||||
void fillBotEditCommandsButton();
|
||||
void fillBotEditSettingsButton();
|
||||
|
@ -1181,6 +1183,7 @@ void Controller::fillManageSection() {
|
|||
fillBotUsernamesButton();
|
||||
fillBotCurrencyButton();
|
||||
fillBotCreditsButton();
|
||||
fillBotAffiliateProgram();
|
||||
fillBotEditIntroButton();
|
||||
fillBotEditCommandsButton();
|
||||
fillBotEditSettingsButton();
|
||||
|
@ -1711,6 +1714,31 @@ void Controller::fillBotCreditsButton() {
|
|||
|
||||
}
|
||||
|
||||
void Controller::fillBotAffiliateProgram() {
|
||||
Expects(_isBot);
|
||||
|
||||
const auto user = _peer->asUser();
|
||||
auto label = user->session().changes().peerFlagsValue(
|
||||
user,
|
||||
Data::PeerUpdate::Flag::StarRefProgram
|
||||
) | rpl::map([=] {
|
||||
const auto commission = user->botInfo
|
||||
? user->botInfo->starRefProgram.commission
|
||||
: 0;
|
||||
return commission
|
||||
? u"%1%"_q.arg(commission)
|
||||
: tr::lng_manage_peer_bot_star_ref_off(tr::now);
|
||||
});
|
||||
AddButtonWithCount(
|
||||
_controls.buttonsLayout,
|
||||
tr::lng_manage_peer_bot_star_ref(),
|
||||
std::move(label),
|
||||
[controller = _navigation->parentController(), user] {
|
||||
controller->showSection(Info::BotStarRef::Make(user));
|
||||
},
|
||||
{ &st::menuIconSharing });
|
||||
}
|
||||
|
||||
void Controller::fillBotEditIntroButton() {
|
||||
Expects(_isBot);
|
||||
|
||||
|
|
|
@ -92,27 +92,28 @@ struct PeerUpdate {
|
|||
BusinessDetails = (1ULL << 30),
|
||||
Birthday = (1ULL << 31),
|
||||
PersonalChannel = (1ULL << 32),
|
||||
StarRefProgram = (1ULL << 33),
|
||||
|
||||
// For chats and channels
|
||||
InviteLinks = (1ULL << 33),
|
||||
Members = (1ULL << 34),
|
||||
Admins = (1ULL << 35),
|
||||
BannedUsers = (1ULL << 36),
|
||||
Rights = (1ULL << 37),
|
||||
PendingRequests = (1ULL << 38),
|
||||
Reactions = (1ULL << 39),
|
||||
InviteLinks = (1ULL << 34),
|
||||
Members = (1ULL << 35),
|
||||
Admins = (1ULL << 36),
|
||||
BannedUsers = (1ULL << 37),
|
||||
Rights = (1ULL << 38),
|
||||
PendingRequests = (1ULL << 39),
|
||||
Reactions = (1ULL << 40),
|
||||
|
||||
// For channels
|
||||
ChannelAmIn = (1ULL << 40),
|
||||
StickersSet = (1ULL << 41),
|
||||
EmojiSet = (1ULL << 42),
|
||||
ChannelLinkedChat = (1ULL << 43),
|
||||
ChannelLocation = (1ULL << 44),
|
||||
Slowmode = (1ULL << 45),
|
||||
GroupCall = (1ULL << 46),
|
||||
ChannelAmIn = (1ULL << 41),
|
||||
StickersSet = (1ULL << 42),
|
||||
EmojiSet = (1ULL << 43),
|
||||
ChannelLinkedChat = (1ULL << 44),
|
||||
ChannelLocation = (1ULL << 45),
|
||||
Slowmode = (1ULL << 46),
|
||||
GroupCall = (1ULL << 47),
|
||||
|
||||
// For iteration
|
||||
LastUsedBit = (1ULL << 46),
|
||||
LastUsedBit = (1ULL << 47),
|
||||
};
|
||||
using Flags = base::flags<Flag>;
|
||||
friend inline constexpr auto is_flag_type(Flag) { return true; }
|
||||
|
|
|
@ -600,6 +600,20 @@ void ApplyUserUpdate(not_null<UserData*> user, const MTPDuserFull &update) {
|
|||
}
|
||||
if (const auto info = user->botInfo.get()) {
|
||||
info->canManageEmojiStatus = update.is_bot_can_manage_emoji_status();
|
||||
auto starRefProgram = StarRefProgram();
|
||||
if (const auto program = update.vstarref_program()) {
|
||||
const auto &data = program->data();
|
||||
starRefProgram.commission = data.vcommission_permille().v;
|
||||
starRefProgram.durationMonths
|
||||
= data.vduration_months().value_or_empty();
|
||||
starRefProgram.endDate = data.vend_date().value_or_empty();
|
||||
}
|
||||
if (info->starRefProgram != starRefProgram) {
|
||||
info->starRefProgram = starRefProgram;
|
||||
user->session().changes().peerUpdated(
|
||||
user,
|
||||
Data::PeerUpdate::Flag::StarRefProgram);
|
||||
}
|
||||
}
|
||||
if (const auto pinned = update.vpinned_msg_id()) {
|
||||
SetTopPinnedMessageId(user, pinned->v);
|
||||
|
|
|
@ -19,6 +19,16 @@ struct BotCommand;
|
|||
struct BusinessDetails;
|
||||
} // namespace Data
|
||||
|
||||
struct StarRefProgram {
|
||||
TimeId endDate = 0;
|
||||
ushort commission = 0;
|
||||
uint8 durationMonths = 0;
|
||||
|
||||
friend inline constexpr bool operator==(
|
||||
StarRefProgram,
|
||||
StarRefProgram) = default;
|
||||
};
|
||||
|
||||
struct BotInfo {
|
||||
BotInfo();
|
||||
|
||||
|
@ -44,6 +54,8 @@ struct BotInfo {
|
|||
ChatAdminRights groupAdminRights;
|
||||
ChatAdminRights channelAdminRights;
|
||||
|
||||
StarRefProgram starRefProgram;
|
||||
|
||||
int version = 0;
|
||||
int descriptionVersion = 0;
|
||||
int activeUsers = 0;
|
||||
|
|
|
@ -0,0 +1,681 @@
|
|||
/*
|
||||
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 "info/bot/starref/info_bot_starref_widget.h"
|
||||
|
||||
#include "apiwrap.h"
|
||||
#include "base/timer_rpl.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "core/click_handler_types.h"
|
||||
#include "data/data_user.h"
|
||||
#include "info/profile/info_profile_icon.h"
|
||||
#include "info/info_controller.h"
|
||||
#include "info/info_memento.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_session.h"
|
||||
#include "settings/settings_common.h"
|
||||
#include "ui/effects/premium_top_bar.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/continuous_sliders.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/wrap/fade_wrap.h"
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
#include "ui/ui_utility.h"
|
||||
#include "ui/vertical_list.h"
|
||||
#include "styles/style_info.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_menu_icons.h"
|
||||
#include "styles/style_premium.h"
|
||||
#include "styles/style_settings.h"
|
||||
|
||||
namespace Info::BotStarRef {
|
||||
namespace {
|
||||
|
||||
constexpr auto kDurationForeverValue = 999;
|
||||
constexpr auto kCommissionDefault = 20;
|
||||
constexpr auto kDurationDefault = 12;
|
||||
|
||||
} // namespace
|
||||
|
||||
struct State {
|
||||
not_null<UserData*> user;
|
||||
StarRefProgram program;
|
||||
bool exists = false;
|
||||
};
|
||||
|
||||
class InnerWidget final : public Ui::RpWidget {
|
||||
public:
|
||||
InnerWidget(QWidget *parent, not_null<Controller*> controller);
|
||||
|
||||
[[nodiscard]] not_null<PeerData*> peer() const;
|
||||
[[nodiscard]] not_null<State*> state();
|
||||
|
||||
void showFinished();
|
||||
void setInnerFocus();
|
||||
|
||||
void saveState(not_null<Memento*> memento);
|
||||
void restoreState(not_null<Memento*> memento);
|
||||
|
||||
private:
|
||||
void prepare();
|
||||
void setupInfo();
|
||||
void setupCommission();
|
||||
void setupDuration();
|
||||
void setupViewExisting();
|
||||
void setupEnd();
|
||||
|
||||
[[nodiscard]] object_ptr<Ui::RpWidget> infoRow(
|
||||
rpl::producer<QString> title,
|
||||
rpl::producer<QString> text,
|
||||
not_null<const style::icon*> icon);
|
||||
|
||||
const not_null<Controller*> _controller;
|
||||
State _state;
|
||||
const not_null<Ui::VerticalLayout*> _container;
|
||||
|
||||
};
|
||||
|
||||
[[nodiscard]] int ValueForCommission(const State &state) {
|
||||
return state.program.commission
|
||||
? state.program.commission
|
||||
: kCommissionDefault;
|
||||
}
|
||||
|
||||
[[nodiscard]] int ValueForDurationMonths(const State &state) {
|
||||
return state.program.durationMonths
|
||||
? state.program.durationMonths
|
||||
: state.exists
|
||||
? kDurationForeverValue
|
||||
: kDurationDefault;
|
||||
}
|
||||
|
||||
[[nodiscard]] State StateForPeer(not_null<PeerData*> peer) {
|
||||
const auto user = peer->asUser();
|
||||
const auto program = user->botInfo->starRefProgram;
|
||||
return State{
|
||||
.user = user,
|
||||
.program = program,
|
||||
.exists = (program.commission > 0),
|
||||
};
|
||||
}
|
||||
|
||||
InnerWidget::InnerWidget(QWidget *parent, not_null<Controller*> controller)
|
||||
: RpWidget(parent)
|
||||
, _controller(controller)
|
||||
, _state(StateForPeer(_controller->key().starrefPeer()))
|
||||
, _container(Ui::CreateChild<Ui::VerticalLayout>(this)) {
|
||||
prepare();
|
||||
}
|
||||
|
||||
not_null<State*> InnerWidget::state() {
|
||||
return &_state;
|
||||
}
|
||||
|
||||
void InnerWidget::prepare() {
|
||||
Ui::ResizeFitChild(this, _container);
|
||||
|
||||
setupInfo();
|
||||
Ui::AddSkip(_container);
|
||||
Ui::AddDivider(_container);
|
||||
setupCommission();
|
||||
setupDuration();
|
||||
Ui::AddSkip(_container);
|
||||
setupViewExisting();
|
||||
Ui::AddSkip(_container);
|
||||
Ui::AddDivider(_container);
|
||||
Ui::AddSkip(_container);
|
||||
setupEnd();
|
||||
}
|
||||
|
||||
void InnerWidget::setupInfo() {
|
||||
AddSkip(_container, st::defaultVerticalListSkip * 2);
|
||||
|
||||
_container->add(infoRow(
|
||||
tr::lng_star_ref_share_title(),
|
||||
tr::lng_star_ref_share_about(),
|
||||
&st::menuIconPremium));
|
||||
|
||||
_container->add(infoRow(
|
||||
tr::lng_star_ref_launch_title(),
|
||||
tr::lng_star_ref_launch_about(),
|
||||
&st::menuIconChannel));
|
||||
|
||||
_container->add(infoRow(
|
||||
tr::lng_star_ref_let_title(),
|
||||
tr::lng_star_ref_let_about(),
|
||||
&st::menuIconStarRefLink));
|
||||
}
|
||||
|
||||
void InnerWidget::setupCommission() {
|
||||
Ui::AddSkip(_container);
|
||||
Ui::AddSubsectionTitle(_container, tr::lng_star_ref_commission_title());
|
||||
|
||||
auto values = std::vector<int>();
|
||||
for (auto i = 1; i != 91; ++i) {
|
||||
values.push_back(i);
|
||||
}
|
||||
const auto valuesCount = int(values.size());
|
||||
|
||||
auto sliderWithLabel = ::Settings::MakeSliderWithLabel(
|
||||
_container,
|
||||
st::settingsScale,
|
||||
st::settingsScaleLabel,
|
||||
st::normalFont->spacew * 2,
|
||||
st::settingsScaleLabel.style.font->width("90%"),
|
||||
true);
|
||||
_container->add(
|
||||
std::move(sliderWithLabel.widget),
|
||||
st::settingsBigScalePadding);
|
||||
const auto slider = sliderWithLabel.slider;
|
||||
const auto label = sliderWithLabel.label;
|
||||
|
||||
const auto updateLabel = [=](int value) {
|
||||
const auto labelText = QString::number(value) + '%';
|
||||
label->setText(labelText);
|
||||
};
|
||||
const auto commission = ValueForCommission(_state);
|
||||
const auto setCommission = [=](int value) {
|
||||
_state.program.commission = value;
|
||||
updateLabel(value);
|
||||
};
|
||||
updateLabel(commission);
|
||||
|
||||
slider->setPseudoDiscrete(
|
||||
valuesCount,
|
||||
[=](int index) { return values[index]; },
|
||||
commission,
|
||||
setCommission,
|
||||
setCommission);
|
||||
|
||||
Ui::AddSkip(_container);
|
||||
Ui::AddDividerText(_container, tr::lng_star_ref_commission_about());
|
||||
}
|
||||
|
||||
void InnerWidget::setupDuration() {
|
||||
Ui::AddSkip(_container);
|
||||
Ui::AddSubsectionTitle(_container, tr::lng_star_ref_duration_title());
|
||||
|
||||
auto values = std::vector<int>{ 1, 3, 6, 12, 24, 36, 999 };
|
||||
const auto valuesCount = int(values.size());
|
||||
|
||||
auto sliderWithLabel = ::Settings::MakeSliderWithLabel(
|
||||
_container,
|
||||
st::settingsScale,
|
||||
st::settingsScaleLabel,
|
||||
st::normalFont->spacew * 2,
|
||||
st::settingsScaleLabel.style.font->width("3y"),
|
||||
true);
|
||||
_container->add(
|
||||
std::move(sliderWithLabel.widget),
|
||||
st::settingsBigScalePadding);
|
||||
const auto slider = sliderWithLabel.slider;
|
||||
const auto label = sliderWithLabel.label;
|
||||
|
||||
const auto updateLabel = [=](int value) {
|
||||
const auto labelText = (value < 12)
|
||||
? (QString::number(value) + 'm')
|
||||
: (value < 999)
|
||||
? (QString::number(value / 12) + 'y')
|
||||
: u"inf"_q;
|
||||
label->setText(labelText);
|
||||
};
|
||||
const auto durationMonths = ValueForDurationMonths(_state);
|
||||
const auto setDurationMonths = [=](int value) {
|
||||
_state.program.durationMonths = (value == kDurationForeverValue)
|
||||
? 0
|
||||
: value;
|
||||
updateLabel(durationMonths);
|
||||
};
|
||||
updateLabel(durationMonths);
|
||||
|
||||
slider->setPseudoDiscrete(
|
||||
valuesCount,
|
||||
[=](int index) { return values[index]; },
|
||||
durationMonths,
|
||||
setDurationMonths,
|
||||
setDurationMonths);
|
||||
|
||||
Ui::AddSkip(_container);
|
||||
Ui::AddDividerText(_container, tr::lng_star_ref_duration_about());
|
||||
}
|
||||
|
||||
void InnerWidget::setupViewExisting() {
|
||||
const auto &stLabel = st::defaultFlatLabel;
|
||||
const auto iconSize = st::settingsPremiumIconDouble.size();
|
||||
const auto &titlePadding = st::settingsPremiumRowTitlePadding;
|
||||
const auto &descriptionPadding = st::settingsPremiumRowAboutPadding;
|
||||
|
||||
const auto content = _container;
|
||||
const auto labelAscent = stLabel.style.font->ascent;
|
||||
const auto button = Ui::CreateChild<Ui::SettingsButton>(
|
||||
content.get(),
|
||||
rpl::single(QString()));
|
||||
|
||||
const auto label = content->add(
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
content,
|
||||
tr::lng_star_ref_existing_title() | Ui::Text::ToBold(),
|
||||
stLabel),
|
||||
titlePadding);
|
||||
label->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
const auto description = content->add(
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
content,
|
||||
tr::lng_star_ref_existing_about(),
|
||||
st::boxDividerLabel),
|
||||
descriptionPadding);
|
||||
description->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
|
||||
const auto dummy = Ui::CreateChild<Ui::AbstractButton>(content.get());
|
||||
dummy->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
|
||||
content->sizeValue(
|
||||
) | rpl::start_with_next([=](const QSize &s) {
|
||||
dummy->resize(s.width(), iconSize.height());
|
||||
}, dummy->lifetime());
|
||||
|
||||
label->geometryValue(
|
||||
) | rpl::start_with_next([=](const QRect &r) {
|
||||
dummy->moveToLeft(0, r.y() + (r.height() - labelAscent));
|
||||
}, dummy->lifetime());
|
||||
|
||||
::Settings::AddButtonIcon(dummy, st::settingsButton, {
|
||||
.icon = &st::settingsPremiumIconStar,
|
||||
.backgroundBrush = st::premiumIconBg3,
|
||||
});
|
||||
|
||||
rpl::combine(
|
||||
content->widthValue(),
|
||||
label->heightValue(),
|
||||
description->heightValue()
|
||||
) | rpl::start_with_next([=,
|
||||
topPadding = titlePadding,
|
||||
bottomPadding = descriptionPadding](
|
||||
int width,
|
||||
int topHeight,
|
||||
int bottomHeight) {
|
||||
button->resize(
|
||||
width,
|
||||
topPadding.top()
|
||||
+ topHeight
|
||||
+ topPadding.bottom()
|
||||
+ bottomPadding.top()
|
||||
+ bottomHeight
|
||||
+ bottomPadding.bottom());
|
||||
}, button->lifetime());
|
||||
label->topValue(
|
||||
) | rpl::start_with_next([=, padding = titlePadding.top()](int top) {
|
||||
button->moveToLeft(0, top - padding);
|
||||
}, button->lifetime());
|
||||
const auto arrow = Ui::CreateChild<Ui::IconButton>(
|
||||
button,
|
||||
st::backButton);
|
||||
arrow->setIconOverride(
|
||||
&st::settingsPremiumArrow,
|
||||
&st::settingsPremiumArrowOver);
|
||||
arrow->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
button->sizeValue(
|
||||
) | rpl::start_with_next([=](const QSize &s) {
|
||||
const auto &point = st::settingsPremiumArrowShift;
|
||||
arrow->moveToRight(
|
||||
-point.x(),
|
||||
point.y() + (s.height() - arrow->height()) / 2);
|
||||
}, arrow->lifetime());
|
||||
|
||||
button->setClickedCallback([=] {
|
||||
_controller->showToast(u"List or smth.."_q);
|
||||
});
|
||||
}
|
||||
|
||||
void InnerWidget::setupEnd() {
|
||||
if (!_state.exists) {
|
||||
return;
|
||||
}
|
||||
const auto end = _container->add(object_ptr<Ui::SettingsButton>(
|
||||
_container,
|
||||
tr::lng_star_ref_end(),
|
||||
st::settingsAttentionButton));
|
||||
end->setClickedCallback([=] {
|
||||
using Flag = MTPbots_UpdateStarRefProgram::Flag;
|
||||
const auto user = _state.user;
|
||||
const auto weak = Ui::MakeWeak(this);
|
||||
user->session().api().request(MTPbots_UpdateStarRefProgram(
|
||||
MTP_flags(0),
|
||||
user->inputUser,
|
||||
MTP_int(0),
|
||||
MTP_int(0)
|
||||
)).done([=] {
|
||||
user->botInfo->starRefProgram.commission = 0;
|
||||
user->botInfo->starRefProgram.durationMonths = 0;
|
||||
user->updateFullForced();
|
||||
if (weak) {
|
||||
_controller->showToast("Removed!");
|
||||
_controller->showBackFromStack();
|
||||
}
|
||||
}).fail(crl::guard(weak, [=] {
|
||||
_controller->showToast("Remove failed!");
|
||||
})).send();
|
||||
});
|
||||
}
|
||||
|
||||
object_ptr<Ui::RpWidget> InnerWidget::infoRow(
|
||||
rpl::producer<QString> title,
|
||||
rpl::producer<QString> text,
|
||||
not_null<const style::icon*> icon) {
|
||||
auto result = object_ptr<Ui::VerticalLayout>(_container);
|
||||
const auto raw = result.data();
|
||||
|
||||
raw->add(
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
raw,
|
||||
std::move(title) | Ui::Text::ToBold(),
|
||||
st::defaultFlatLabel),
|
||||
st::settingsPremiumRowTitlePadding);
|
||||
raw->add(
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
raw,
|
||||
std::move(text),
|
||||
st::boxDividerLabel),
|
||||
st::settingsPremiumRowAboutPadding);
|
||||
object_ptr<Info::Profile::FloatingIcon>(
|
||||
raw,
|
||||
*icon,
|
||||
st::starrefInfoIconPosition);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
not_null<PeerData*> InnerWidget::peer() const {
|
||||
return _controller->key().starrefPeer();
|
||||
}
|
||||
|
||||
void InnerWidget::showFinished() {
|
||||
|
||||
}
|
||||
|
||||
void InnerWidget::setInnerFocus() {
|
||||
setFocus();
|
||||
}
|
||||
|
||||
void InnerWidget::saveState(not_null<Memento*> memento) {
|
||||
|
||||
}
|
||||
|
||||
void InnerWidget::restoreState(not_null<Memento*> memento) {
|
||||
|
||||
}
|
||||
|
||||
Memento::Memento(not_null<Controller*> controller)
|
||||
: ContentMemento(Tag(controller->starrefPeer())) {
|
||||
}
|
||||
|
||||
Memento::Memento(not_null<PeerData*> peer)
|
||||
: ContentMemento(Tag(peer)) {
|
||||
}
|
||||
|
||||
Memento::~Memento() = default;
|
||||
|
||||
Section Memento::section() const {
|
||||
return Section(Section::Type::BotStarRef);
|
||||
}
|
||||
|
||||
object_ptr<ContentWidget> Memento::createWidget(
|
||||
QWidget *parent,
|
||||
not_null<Controller*> controller,
|
||||
const QRect &geometry) {
|
||||
auto result = object_ptr<Widget>(parent, controller);
|
||||
result->setInternalState(geometry, this);
|
||||
return result;
|
||||
}
|
||||
|
||||
Widget::Widget(
|
||||
QWidget *parent,
|
||||
not_null<Controller*> controller)
|
||||
: ContentWidget(parent, controller)
|
||||
, _inner(setInnerWidget(object_ptr<InnerWidget>(this, controller)))
|
||||
, _state(_inner->state()) {
|
||||
_top = setupTop();
|
||||
_bottom = setupBottom();
|
||||
}
|
||||
|
||||
not_null<PeerData*> Widget::peer() const {
|
||||
return _inner->peer();
|
||||
}
|
||||
|
||||
bool Widget::showInternal(not_null<ContentMemento*> memento) {
|
||||
return (memento->starrefPeer() == peer());
|
||||
}
|
||||
|
||||
rpl::producer<QString> Widget::title() {
|
||||
return tr::lng_star_ref_title();
|
||||
}
|
||||
|
||||
void Widget::setInternalState(
|
||||
const QRect &geometry,
|
||||
not_null<Memento*> memento) {
|
||||
setGeometry(geometry);
|
||||
Ui::SendPendingMoveResizeEvents(this);
|
||||
restoreState(memento);
|
||||
}
|
||||
|
||||
rpl::producer<bool> Widget::desiredShadowVisibility() const {
|
||||
return rpl::single<bool>(true);
|
||||
}
|
||||
|
||||
void Widget::showFinished() {
|
||||
_inner->showFinished();
|
||||
}
|
||||
|
||||
void Widget::setInnerFocus() {
|
||||
_inner->setInnerFocus();
|
||||
}
|
||||
|
||||
void Widget::enableBackButton() {
|
||||
_backEnabled = true;
|
||||
}
|
||||
|
||||
std::shared_ptr<ContentMemento> Widget::doCreateMemento() {
|
||||
auto result = std::make_shared<Memento>(controller());
|
||||
saveState(result.get());
|
||||
return result;
|
||||
}
|
||||
|
||||
void Widget::saveState(not_null<Memento*> memento) {
|
||||
memento->setScrollTop(scrollTopSave());
|
||||
_inner->saveState(memento);
|
||||
}
|
||||
|
||||
void Widget::restoreState(not_null<Memento*> memento) {
|
||||
_inner->restoreState(memento);
|
||||
scrollTopRestore(memento->scrollTop());
|
||||
}
|
||||
|
||||
std::unique_ptr<Ui::Premium::TopBarAbstract> Widget::setupTop() {
|
||||
auto title = tr::lng_star_ref_title();
|
||||
auto about = tr::lng_star_ref_about() | Ui::Text::ToWithEntities();
|
||||
|
||||
const auto controller = this->controller();
|
||||
const auto weak = base::make_weak(controller->parentController());
|
||||
const auto clickContextOther = [=] {
|
||||
return QVariant::fromValue(ClickHandlerContext{
|
||||
.sessionWindow = weak,
|
||||
.botStartAutoSubmit = true,
|
||||
});
|
||||
};
|
||||
auto result = std::make_unique<Ui::Premium::TopBar>(
|
||||
this,
|
||||
st::userPremiumCover,
|
||||
Ui::Premium::TopBarDescriptor{
|
||||
.clickContextOther = clickContextOther,
|
||||
.logo = u"affiliate"_q,
|
||||
.title = std::move(title),
|
||||
.about = std::move(about),
|
||||
.light = true,
|
||||
});
|
||||
const auto raw = result.get();
|
||||
|
||||
controller->wrapValue(
|
||||
) | rpl::start_with_next([=](Info::Wrap wrap) {
|
||||
raw->setRoundEdges(wrap == Info::Wrap::Layer);
|
||||
}, raw->lifetime());
|
||||
|
||||
const auto calculateMaximumHeight = [=] {
|
||||
return st::settingsPremiumTopHeight;
|
||||
};
|
||||
|
||||
raw->setMaximumHeight(st::settingsPremiumTopHeight);
|
||||
raw->setMinimumHeight(st::settingsPremiumTopHeight);
|
||||
|
||||
raw->resize(width(), raw->maximumHeight());
|
||||
|
||||
setPaintPadding({ 0, st::settingsPremiumTopHeight, 0, 0 });
|
||||
|
||||
controller->wrapValue(
|
||||
) | rpl::start_with_next([=](Info::Wrap wrap) {
|
||||
const auto isLayer = (wrap == Info::Wrap::Layer);
|
||||
_back = base::make_unique_q<Ui::FadeWrap<Ui::IconButton>>(
|
||||
raw,
|
||||
object_ptr<Ui::IconButton>(
|
||||
raw,
|
||||
(isLayer
|
||||
? st::infoLayerTopBar.back
|
||||
: st::infoTopBar.back)),
|
||||
st::infoTopBarScale);
|
||||
_back->setDuration(0);
|
||||
_back->toggleOn(isLayer
|
||||
? _backEnabled.value() | rpl::type_erased()
|
||||
: rpl::single(true));
|
||||
_back->entity()->addClickHandler([=] {
|
||||
controller->showBackFromStack();
|
||||
});
|
||||
_back->toggledValue(
|
||||
) | rpl::start_with_next([=](bool toggled) {
|
||||
const auto &st = isLayer ? st::infoLayerTopBar : st::infoTopBar;
|
||||
raw->setTextPosition(
|
||||
toggled ? st.back.width : st.titlePosition.x(),
|
||||
st.titlePosition.y());
|
||||
}, _back->lifetime());
|
||||
|
||||
if (!isLayer) {
|
||||
_close = nullptr;
|
||||
} else {
|
||||
_close = base::make_unique_q<Ui::IconButton>(
|
||||
raw,
|
||||
st::settingsPremiumTopBarClose);
|
||||
_close->addClickHandler([=] {
|
||||
controller->parentController()->hideLayer();
|
||||
controller->parentController()->hideSpecialLayer();
|
||||
});
|
||||
raw->widthValue(
|
||||
) | rpl::start_with_next([=] {
|
||||
_close->moveToRight(0, 0);
|
||||
}, _close->lifetime());
|
||||
}
|
||||
}, raw->lifetime());
|
||||
|
||||
raw->move(0, 0);
|
||||
widthValue() | rpl::start_with_next([=](int width) {
|
||||
raw->resizeToWidth(width);
|
||||
setScrollTopSkip(raw->height());
|
||||
}, raw->lifetime());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::unique_ptr<Ui::RpWidget> Widget::setupBottom() {
|
||||
auto result = std::make_unique<Ui::VerticalLayout>(this);
|
||||
const auto raw = result.get();
|
||||
|
||||
auto text = base::timer_each(100) | rpl::map([=] {
|
||||
const auto till = _state->user->botInfo->starRefProgram.endDate;
|
||||
const auto now = base::unixtime::now();
|
||||
const auto left = (till > now) ? (till - now) : 0;
|
||||
return left
|
||||
? tr::lng_star_ref_start_disabled(
|
||||
tr::now,
|
||||
lt_time,
|
||||
QString::number(left))
|
||||
: _state->exists
|
||||
? tr::lng_star_ref_update(tr::now)
|
||||
: tr::lng_star_ref_start(tr::now);
|
||||
});
|
||||
const auto save = raw->add(
|
||||
object_ptr<Ui::RoundButton>(
|
||||
raw,
|
||||
rpl::duplicate(text),
|
||||
st::defaultActiveButton),
|
||||
st::starrefButtonMargin);
|
||||
std::move(text) | rpl::start_with_next([=] {
|
||||
save->resizeToWidth(raw->width()
|
||||
- st::starrefButtonMargin.left()
|
||||
- st::starrefButtonMargin.right());
|
||||
}, save->lifetime());
|
||||
save->setTextTransform(Ui::RoundButton::TextTransform::NoTransform);
|
||||
const auto &margins = st::defaultBoxDividerLabelPadding;
|
||||
raw->add(
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
raw,
|
||||
(_state->exists
|
||||
? tr::lng_star_ref_update_info
|
||||
: tr::lng_star_ref_start_info)(
|
||||
lt_terms,
|
||||
tr::lng_star_ref_button_link() | Ui::Text::ToLink(),
|
||||
Ui::Text::WithEntities),
|
||||
st::boxDividerLabel),
|
||||
QMargins(margins.left(), 0, margins.right(), 0));
|
||||
save->setClickedCallback([=] {
|
||||
using Flag = MTPbots_UpdateStarRefProgram::Flag;
|
||||
const auto weak = Ui::MakeWeak(this);
|
||||
const auto user = _state->user;
|
||||
auto program = StarRefProgram{
|
||||
.commission = _state->program.commission,
|
||||
.durationMonths = _state->program.durationMonths,
|
||||
};
|
||||
user->session().api().request(MTPbots_UpdateStarRefProgram(
|
||||
MTP_flags((program.commission > 0 && program.durationMonths > 0)
|
||||
? Flag::f_duration_months
|
||||
: Flag()),
|
||||
user->inputUser,
|
||||
MTP_int(program.commission),
|
||||
MTP_int(program.durationMonths)
|
||||
)).done([=] {
|
||||
user->botInfo->starRefProgram.commission = program.commission;
|
||||
user->botInfo->starRefProgram.durationMonths
|
||||
= program.durationMonths;
|
||||
if (weak) {
|
||||
controller()->showBackFromStack();
|
||||
}
|
||||
}).fail(crl::guard(weak, [=] {
|
||||
controller()->showToast("Failed!");
|
||||
})).send();
|
||||
});
|
||||
|
||||
widthValue() | rpl::start_with_next([=](int width) {
|
||||
raw->resizeToWidth(width);
|
||||
}, raw->lifetime());
|
||||
|
||||
rpl::combine(
|
||||
raw->heightValue(),
|
||||
heightValue()
|
||||
) | rpl::start_with_next([=](int height, int fullHeight) {
|
||||
setScrollBottomSkip(height);
|
||||
raw->move(0, fullHeight - height);
|
||||
}, raw->lifetime());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::shared_ptr<Info::Memento> Make(not_null<PeerData*> peer) {
|
||||
return std::make_shared<Info::Memento>(
|
||||
std::vector<std::shared_ptr<ContentMemento>>(
|
||||
1,
|
||||
std::make_shared<Memento>(peer)));
|
||||
}
|
||||
|
||||
} // namespace Info::BotStarRef
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
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 "info/info_content_widget.h"
|
||||
|
||||
namespace Ui::Premium {
|
||||
class TopBarAbstract;
|
||||
} // namespace Ui::Premium
|
||||
|
||||
namespace Ui {
|
||||
template <typename Widget>
|
||||
class FadeWrap;
|
||||
class IconButton;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Info::BotStarRef {
|
||||
|
||||
struct State;
|
||||
class InnerWidget;
|
||||
|
||||
class Memento final : public ContentMemento {
|
||||
public:
|
||||
Memento(not_null<Controller*> controller);
|
||||
Memento(not_null<PeerData*> peer);
|
||||
~Memento();
|
||||
|
||||
object_ptr<ContentWidget> createWidget(
|
||||
QWidget *parent,
|
||||
not_null<Controller*> controller,
|
||||
const QRect &geometry) override;
|
||||
|
||||
Section section() const override;
|
||||
|
||||
};
|
||||
|
||||
class Widget final : public ContentWidget {
|
||||
public:
|
||||
Widget(QWidget *parent, not_null<Controller*> controller);
|
||||
|
||||
bool showInternal(not_null<ContentMemento*> memento) override;
|
||||
rpl::producer<QString> title() override;
|
||||
rpl::producer<bool> desiredShadowVisibility() const override;
|
||||
void showFinished() override;
|
||||
void setInnerFocus() override;
|
||||
void enableBackButton() override;
|
||||
|
||||
[[nodiscard]] not_null<PeerData*> peer() const;
|
||||
|
||||
void setInternalState(
|
||||
const QRect &geometry,
|
||||
not_null<Memento*> memento);
|
||||
|
||||
private:
|
||||
void saveState(not_null<Memento*> memento);
|
||||
void restoreState(not_null<Memento*> memento);
|
||||
|
||||
[[nodiscard]] std::unique_ptr<Ui::Premium::TopBarAbstract> setupTop();
|
||||
[[nodiscard]] std::unique_ptr<Ui::RpWidget> setupBottom();
|
||||
|
||||
std::shared_ptr<ContentMemento> doCreateMemento() override;
|
||||
|
||||
const not_null<InnerWidget*> _inner;
|
||||
const not_null<State*> _state;
|
||||
|
||||
std::unique_ptr<Ui::Premium::TopBarAbstract> _top;
|
||||
base::unique_qptr<Ui::FadeWrap<Ui::IconButton>> _back;
|
||||
base::unique_qptr<Ui::IconButton> _close;
|
||||
rpl::variable<bool> _backEnabled;
|
||||
|
||||
std::unique_ptr<Ui::RpWidget> _bottom;
|
||||
|
||||
};
|
||||
|
||||
[[nodiscard]] std::shared_ptr<Info::Memento> Make(not_null<PeerData*> peer);
|
||||
|
||||
} // namespace Info::BotStarRef
|
|
@ -1144,3 +1144,6 @@ infoHoursOuter: RoundButton(defaultActiveButton) {
|
|||
}
|
||||
infoHoursOuterMargin: margins(8px, 4px, 8px, 4px);
|
||||
infoHoursDaySkip: 6px;
|
||||
|
||||
starrefInfoIconPosition: point(16px, 8px);
|
||||
starrefButtonMargin: margins(12px, 12px, 12px, 12px);
|
||||
|
|
|
@ -374,10 +374,12 @@ Key ContentMemento::key() const {
|
|||
return Key(poll, pollContextId());
|
||||
} else if (const auto self = settingsSelf()) {
|
||||
return Settings::Tag{ self };
|
||||
} else if (const auto peer = storiesPeer()) {
|
||||
return Stories::Tag{ peer, storiesTab() };
|
||||
} else if (const auto peer = statisticsTag().peer) {
|
||||
} else if (const auto stories = storiesPeer()) {
|
||||
return Stories::Tag{ stories, storiesTab() };
|
||||
} else if (statisticsTag().peer) {
|
||||
return statisticsTag();
|
||||
} else if (const auto starref = starrefPeer()) {
|
||||
return BotStarRef::Tag(starref);
|
||||
} else if (const auto who = reactionsWhoReadIds()) {
|
||||
return Key(who, _reactionsSelected, _pollReactionsContextId);
|
||||
} else {
|
||||
|
@ -420,6 +422,10 @@ ContentMemento::ContentMemento(Statistics::Tag statistics)
|
|||
: _statisticsTag(statistics) {
|
||||
}
|
||||
|
||||
ContentMemento::ContentMemento(BotStarRef::Tag starref)
|
||||
: _starrefPeer(starref.peer) {
|
||||
}
|
||||
|
||||
ContentMemento::ContentMemento(
|
||||
std::shared_ptr<Api::WhoReadList> whoReadIds,
|
||||
FullMsgId contextId,
|
||||
|
|
|
@ -52,6 +52,10 @@ namespace Info::Statistics {
|
|||
struct Tag;
|
||||
} // namespace Info::Statistics
|
||||
|
||||
namespace Info::BotStarRef {
|
||||
struct Tag;
|
||||
} // namespace Info::BotStarRef
|
||||
|
||||
namespace Info {
|
||||
|
||||
class ContentMemento;
|
||||
|
@ -191,6 +195,7 @@ public:
|
|||
explicit ContentMemento(Downloads::Tag downloads);
|
||||
explicit ContentMemento(Stories::Tag stories);
|
||||
explicit ContentMemento(Statistics::Tag statistics);
|
||||
explicit ContentMemento(BotStarRef::Tag starref);
|
||||
ContentMemento(not_null<PollData*> poll, FullMsgId contextId)
|
||||
: _poll(poll)
|
||||
, _pollReactionsContextId(contextId) {
|
||||
|
@ -226,6 +231,9 @@ public:
|
|||
Statistics::Tag statisticsTag() const {
|
||||
return _statisticsTag;
|
||||
}
|
||||
PeerData *starrefPeer() const {
|
||||
return _starrefPeer;
|
||||
}
|
||||
PollData *poll() const {
|
||||
return _poll;
|
||||
}
|
||||
|
@ -280,6 +288,7 @@ private:
|
|||
PeerData * const _storiesPeer = nullptr;
|
||||
Stories::Tab _storiesTab = {};
|
||||
Statistics::Tag _statisticsTag;
|
||||
PeerData * const _starrefPeer = nullptr;
|
||||
PollData * const _poll = nullptr;
|
||||
std::shared_ptr<Api::WhoReadList> _reactionsWhoReadIds;
|
||||
Data::ReactionId _reactionsSelected;
|
||||
|
|
|
@ -46,6 +46,9 @@ Key::Key(Stories::Tag stories) : _value(stories) {
|
|||
Key::Key(Statistics::Tag statistics) : _value(statistics) {
|
||||
}
|
||||
|
||||
Key::Key(BotStarRef::Tag starref) : _value(starref) {
|
||||
}
|
||||
|
||||
Key::Key(not_null<PollData*> poll, FullMsgId contextId)
|
||||
: _value(PollKey{ poll, contextId }) {
|
||||
}
|
||||
|
@ -106,6 +109,13 @@ Statistics::Tag Key::statisticsTag() const {
|
|||
return Statistics::Tag();
|
||||
}
|
||||
|
||||
PeerData *Key::starrefPeer() const {
|
||||
if (const auto tag = std::get_if<BotStarRef::Tag>(&_value)) {
|
||||
return tag->peer;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PollData *Key::poll() const {
|
||||
if (const auto data = std::get_if<PollKey>(&_value)) {
|
||||
return data->poll;
|
||||
|
@ -319,7 +329,8 @@ bool Controller::validateMementoPeer(
|
|||
&& memento->migratedPeerId() == migratedPeerId()
|
||||
&& memento->settingsSelf() == settingsSelf()
|
||||
&& memento->storiesPeer() == storiesPeer()
|
||||
&& memento->statisticsTag().peer == statisticsTag().peer;
|
||||
&& memento->statisticsTag().peer == statisticsTag().peer
|
||||
&& memento->starrefPeer() == starrefPeer();
|
||||
}
|
||||
|
||||
void Controller::setSection(not_null<ContentMemento*> memento) {
|
||||
|
|
|
@ -61,6 +61,17 @@ struct Tag {
|
|||
|
||||
} // namespace Info::Stories
|
||||
|
||||
namespace Info::BotStarRef {
|
||||
|
||||
struct Tag {
|
||||
explicit Tag(not_null<PeerData*> peer) : peer(peer) {
|
||||
}
|
||||
|
||||
not_null<PeerData*> peer;
|
||||
};
|
||||
|
||||
} // namespace Info::BotStarRef
|
||||
|
||||
namespace Info {
|
||||
|
||||
class Key {
|
||||
|
@ -71,6 +82,7 @@ public:
|
|||
Key(Downloads::Tag downloads);
|
||||
Key(Stories::Tag stories);
|
||||
Key(Statistics::Tag statistics);
|
||||
Key(BotStarRef::Tag starref);
|
||||
Key(not_null<PollData*> poll, FullMsgId contextId);
|
||||
Key(
|
||||
std::shared_ptr<Api::WhoReadList> whoReadIds,
|
||||
|
@ -84,6 +96,7 @@ public:
|
|||
PeerData *storiesPeer() const;
|
||||
Stories::Tab storiesTab() const;
|
||||
Statistics::Tag statisticsTag() const;
|
||||
PeerData *starrefPeer() const;
|
||||
PollData *poll() const;
|
||||
FullMsgId pollContextId() const;
|
||||
std::shared_ptr<Api::WhoReadList> reactionsWhoReadIds() const;
|
||||
|
@ -107,6 +120,7 @@ private:
|
|||
Downloads::Tag,
|
||||
Stories::Tag,
|
||||
Statistics::Tag,
|
||||
BotStarRef::Tag,
|
||||
PollKey,
|
||||
ReactionsKey> _value;
|
||||
|
||||
|
@ -134,6 +148,7 @@ public:
|
|||
Stories,
|
||||
PollResults,
|
||||
Statistics,
|
||||
BotStarRef,
|
||||
Boosts,
|
||||
ChannelEarn,
|
||||
BotEarn,
|
||||
|
@ -202,6 +217,9 @@ public:
|
|||
[[nodiscard]] Statistics::Tag statisticsTag() const {
|
||||
return key().statisticsTag();
|
||||
}
|
||||
[[nodiscard]] PeerData *starrefPeer() const {
|
||||
return key().starrefPeer();
|
||||
}
|
||||
[[nodiscard]] PollData *poll() const;
|
||||
[[nodiscard]] FullMsgId pollContextId() const {
|
||||
return key().pollContextId();
|
||||
|
|
|
@ -64,8 +64,9 @@ const style::InfoTopBar &TopBarStyle(Wrap wrap) {
|
|||
|
||||
[[nodiscard]] bool HasCustomTopBar(not_null<const Controller*> controller) {
|
||||
const auto section = controller->section();
|
||||
return (section.type() == Section::Type::Settings)
|
||||
&& section.settingsType()->hasCustomTopBar();
|
||||
return (section.type() == Section::Type::BotStarRef)
|
||||
|| ((section.type() == Section::Type::Settings)
|
||||
&& section.settingsType()->hasCustomTopBar());
|
||||
}
|
||||
|
||||
[[nodiscard]] Fn<Ui::StringWithNumbers(int)> SelectedTitleForMedia(
|
||||
|
|
|
@ -138,6 +138,10 @@ TopBar::TopBar(
|
|||
_dollar = ScaleTo(QImage(u":/gui/art/business_logo.png"_q));
|
||||
_ministars.setColorOverride(
|
||||
QGradientStops{{ 0, st::premiumButtonFg->c }});
|
||||
} else if (_logo == u"affiliate"_q) {
|
||||
_dollar = ScaleTo(QImage(u":/gui/art/affiliate_logo.png"_q));
|
||||
_ministars.setColorOverride(
|
||||
QGradientStops{{ 0, st::premiumButtonFg->c }});
|
||||
} else if (!_light && !TopBarAbstract::isDark()) {
|
||||
_star.load(Svg());
|
||||
_ministars.setColorOverride(
|
||||
|
|
|
@ -42,6 +42,7 @@ menuIconRemove: icon {{ "menu/remove", menuIconColor }};
|
|||
menuIconRetractVote: icon {{ "menu/retract_vote", menuIconColor }};
|
||||
menuIconPermissions: icon {{ "menu/permissions", menuIconColor }};
|
||||
menuIconShare: icon {{ "menu/share", menuIconColor }};
|
||||
menuIconSharing: icon {{ "menu/share2", menuIconColor }};
|
||||
menuIconArchive: icon {{ "menu/archive", menuIconColor }};
|
||||
menuIconUnarchive: icon {{ "menu/unarchive", menuIconColor }};
|
||||
menuIconMarkRead: icon {{ "menu/read", menuIconColor }};
|
||||
|
@ -161,6 +162,7 @@ menuIconAppleWatch: icon {{ "menu/passcode_watch", menuIconColor }};
|
|||
menuIconSystemPwd: menuIconPermissions;
|
||||
menuIconPlayerFullScreen: icon {{ "player/player_fullscreen", menuIconColor }};
|
||||
menuIconPlayerWindowed: icon {{ "player/player_minimize", menuIconColor }};
|
||||
menuIconStarRefLink: icon{{ "settings/premium/features/feature_links2", menuIconColor }};
|
||||
|
||||
menuIconTTLAny: icon {{ "menu/auto_delete_plain", menuIconColor }};
|
||||
menuIconTTLAnyTextPosition: point(11px, 22px);
|
||||
|
|
Loading…
Add table
Reference in a new issue