mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-17 22:57:11 +02:00
Added ability to disable chats filters tags from settings.
This commit is contained in:
parent
ba082081b3
commit
6baba5a7b2
6 changed files with 190 additions and 12 deletions
|
@ -2300,6 +2300,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_premium_summary_about_business" = "Upgrade your account with business features such as location, opening hours and quick replies.";
|
||||
"lng_premium_summary_subtitle_effects" = "Message Effects";
|
||||
"lng_premium_summary_about_effects" = "Add over 500 animated effects to private messages.";
|
||||
"lng_premium_summary_subtitle_filter_tags" = "Tag Your Chats";
|
||||
"lng_premium_summary_about_filter_tags" = "Display folder names for each chat in the chat list.";
|
||||
"lng_premium_summary_bottom_subtitle" = "About Telegram Premium";
|
||||
"lng_premium_summary_bottom_about" = "While the free version of Telegram already gives its users more than any other messaging application, **Telegram Premium** pushes its capabilities even further.\n\n**Telegram Premium** is a paid option, because most Premium Features require additional expenses from Telegram to third parties such as data center providers and server manufacturers. Contributions from **Telegram Premium** users allow us to cover such costs and also help Telegram stay free for everyone.";
|
||||
"lng_premium_summary_button" = "Subscribe for {cost} per month";
|
||||
|
@ -5155,6 +5157,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_filters_view_subtitle" = "Tabs view";
|
||||
"lng_filters_vertical" = "Tabs on the left";
|
||||
"lng_filters_horizontal" = "Tabs at the top";
|
||||
"lng_filters_enable_tags" = "Show Folder Tags";
|
||||
"lng_filters_enable_tags_about" = "Display folder names for each chat in the chat list.";
|
||||
"lng_filters_enable_tags_about_premium" = "Subscribe to **{link}** to display folder names for each chat in the chat list.";
|
||||
|
||||
"lng_filters_delete_sure" = "Are you sure you want to delete this folder? This will also deactivate all the invite links created to share this folder.";
|
||||
"lng_filters_link" = "Share Folder";
|
||||
|
|
|
@ -133,6 +133,8 @@ void PreloadSticker(const std::shared_ptr<Data::DocumentMedia> &media) {
|
|||
return tr::lng_premium_summary_subtitle_business();
|
||||
case PremiumFeature::Effects:
|
||||
return tr::lng_premium_summary_subtitle_effects();
|
||||
case PremiumFeature::FilterTags:
|
||||
return tr::lng_premium_summary_subtitle_filter_tags();
|
||||
|
||||
case PremiumFeature::BusinessLocation:
|
||||
return tr::lng_business_subtitle_location();
|
||||
|
@ -196,6 +198,8 @@ void PreloadSticker(const std::shared_ptr<Data::DocumentMedia> &media) {
|
|||
return tr::lng_premium_summary_about_business();
|
||||
case PremiumFeature::Effects:
|
||||
return tr::lng_premium_summary_about_effects();
|
||||
case PremiumFeature::FilterTags:
|
||||
return tr::lng_premium_summary_about_filter_tags();
|
||||
|
||||
case PremiumFeature::BusinessLocation:
|
||||
return tr::lng_business_about_location();
|
||||
|
@ -534,6 +538,7 @@ struct VideoPreviewDocument {
|
|||
case PremiumFeature::LastSeen: return "last_seen";
|
||||
case PremiumFeature::MessagePrivacy: return "message_privacy";
|
||||
case PremiumFeature::Effects: return "effects";
|
||||
case PremiumFeature::FilterTags: return "folder_tags";
|
||||
|
||||
case PremiumFeature::BusinessLocation: return "business_location";
|
||||
case PremiumFeature::BusinessHours: return "business_hours";
|
||||
|
|
|
@ -71,6 +71,7 @@ enum class PremiumFeature {
|
|||
MessagePrivacy,
|
||||
Business,
|
||||
Effects,
|
||||
FilterTags,
|
||||
|
||||
// Business features.
|
||||
BusinessLocation,
|
||||
|
|
|
@ -397,6 +397,23 @@ rpl::producer<bool> ChatFilters::tagsEnabledValue() const {
|
|||
return _tagsEnabled.value();
|
||||
}
|
||||
|
||||
void ChatFilters::requestToggleTags(bool value, Fn<void()> fail) {
|
||||
if (_toggleTagsRequestId) {
|
||||
return;
|
||||
}
|
||||
_toggleTagsRequestId = _owner->session().api().request(
|
||||
MTPmessages_ToggleDialogFilterTags(MTP_bool(value))
|
||||
).done([=](const MTPBool &result) {
|
||||
_tagsEnabled = value;
|
||||
_toggleTagsRequestId = 0;
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
const auto message = error.type();
|
||||
_toggleTagsRequestId = 0;
|
||||
LOG(("API Error: Toggle Tags - %1").arg(message));
|
||||
fail();
|
||||
}).send();
|
||||
}
|
||||
|
||||
void ChatFilters::received(const QVector<MTPDialogFilter> &list) {
|
||||
auto position = 0;
|
||||
auto changed = false;
|
||||
|
|
|
@ -188,6 +188,7 @@ public:
|
|||
|
||||
[[nodiscard]] bool tagsEnabled() const;
|
||||
[[nodiscard]] rpl::producer<bool> tagsEnabledValue() const;
|
||||
void requestToggleTags(bool value, Fn<void()> fail);
|
||||
|
||||
private:
|
||||
struct MoreChatsData {
|
||||
|
@ -217,6 +218,7 @@ private:
|
|||
mtpRequestId _loadRequestId = 0;
|
||||
mtpRequestId _saveOrderRequestId = 0;
|
||||
mtpRequestId _saveOrderAfterId = 0;
|
||||
mtpRequestId _toggleTagsRequestId = 0;
|
||||
bool _loaded = false;
|
||||
bool _reloading = false;
|
||||
|
||||
|
|
|
@ -7,34 +7,38 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#include "settings/settings_folders.h"
|
||||
|
||||
#include "apiwrap.h"
|
||||
#include "api/api_chat_filters.h" // ProcessFilterRemove.
|
||||
#include "boxes/premium_limits_box.h"
|
||||
#include "apiwrap.h"
|
||||
#include "boxes/filters/edit_filter_box.h"
|
||||
#include "boxes/premium_limits_box.h"
|
||||
#include "boxes/premium_preview_box.h"
|
||||
#include "core/application.h"
|
||||
#include "data/data_chat_filters.h"
|
||||
#include "data/data_folder.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "data/data_peer_values.h" // Data::AmPremiumValue.
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_premium_limits.h"
|
||||
#include "data/data_session.h"
|
||||
#include "history/history.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "lottie/lottie_icon.h"
|
||||
#include "main/main_session.h"
|
||||
#include "settings/settings_premium.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "ui/empty_userpic.h"
|
||||
#include "ui/filter_icons.h"
|
||||
#include "ui/layers/generic_box.h"
|
||||
#include "ui/painter.h"
|
||||
#include "ui/vertical_list.h"
|
||||
#include "ui/rect.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/ui_utility.h"
|
||||
#include "ui/vertical_list.h"
|
||||
#include "ui/widgets/box_content_divider.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "ui/widgets/fields/input_field.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
#include "ui/ui_utility.h"
|
||||
#include "window/window_controller.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "styles/style_settings.h"
|
||||
|
@ -67,6 +71,8 @@ public:
|
|||
[[nodiscard]] rpl::producer<> restoreRequests() const;
|
||||
[[nodiscard]] rpl::producer<> addRequests() const;
|
||||
|
||||
void setColorIndexProgress(float64 progress);
|
||||
|
||||
private:
|
||||
enum class State {
|
||||
Suggested,
|
||||
|
@ -96,6 +102,8 @@ private:
|
|||
Ui::Text::String _title;
|
||||
QString _status;
|
||||
Ui::FilterIcon _icon = Ui::FilterIcon();
|
||||
std::optional<uint8> _colorIndex;
|
||||
float64 _colorIndexProgress = 1.;
|
||||
|
||||
State _state = State::Normal;
|
||||
|
||||
|
@ -238,11 +246,11 @@ void FilterRowButton::setup(
|
|||
_title.setText(st::contactsNameStyle, filter.title());
|
||||
_status = status;
|
||||
_icon = Ui::ComputeFilterIcon(filter);
|
||||
_colorIndex = filter.colorIndex();
|
||||
|
||||
setState(_state, true);
|
||||
|
||||
sizeValue(
|
||||
) | rpl::start_with_next([=](QSize size) {
|
||||
sizeValue() | rpl::start_with_next([=](QSize size) {
|
||||
const auto right = st::contactsPadding.right()
|
||||
+ st::contactsCheckPosition.x();
|
||||
const auto width = size.width();
|
||||
|
@ -272,6 +280,13 @@ rpl::producer<> FilterRowButton::addRequests() const {
|
|||
return _add.clicks() | rpl::to_empty;
|
||||
}
|
||||
|
||||
void FilterRowButton::setColorIndexProgress(float64 progress) {
|
||||
_colorIndexProgress = progress;
|
||||
if (_colorIndex) {
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void FilterRowButton::paintEvent(QPaintEvent *e) {
|
||||
auto p = Painter(this);
|
||||
|
||||
|
@ -281,6 +296,19 @@ void FilterRowButton::paintEvent(QPaintEvent *e) {
|
|||
p.fillRect(e->rect(), st::windowBgOver);
|
||||
}
|
||||
RippleButton::paintRipple(p, 0, 0);
|
||||
|
||||
if (_colorIndex) {
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(Ui::EmptyUserpic::UserpicColor(*_colorIndex).color2);
|
||||
const auto w = height() / 3;
|
||||
const auto rect = QRect(
|
||||
_remove.x() - w - st::contactsCheckPosition.x(),
|
||||
(height() - w) / 2,
|
||||
w,
|
||||
w);
|
||||
auto hq = PainterHighQualityEnabler(p);
|
||||
p.drawEllipse(rect - Margins((1. - _colorIndexProgress) * w / 2));
|
||||
}
|
||||
} else if (_state == State::Removed) {
|
||||
p.setOpacity(st::stickersRowDisabledOpacity);
|
||||
}
|
||||
|
@ -335,7 +363,8 @@ void FilterRowButton::paintEvent(QPaintEvent *e) {
|
|||
|
||||
[[nodiscard]] Fn<void()> SetupFoldersContent(
|
||||
not_null<Window::SessionController*> controller,
|
||||
not_null<Ui::VerticalLayout*> container) {
|
||||
not_null<Ui::VerticalLayout*> container,
|
||||
not_null<rpl::event_stream<bool>*> tagsButtonEnabled) {
|
||||
auto &lifetime = container->lifetime();
|
||||
|
||||
const auto weak = Ui::MakeWeak(container);
|
||||
|
@ -351,6 +380,7 @@ void FilterRowButton::paintEvent(QPaintEvent *e) {
|
|||
rpl::variable<int> count;
|
||||
rpl::variable<int> suggested;
|
||||
Fn<void(const FilterRowButton*, Fn<void(Data::ChatFilter)>)> save;
|
||||
Ui::Animations::Simple tagsEnabledAnimation;
|
||||
};
|
||||
|
||||
const auto state = lifetime.make_state<State>();
|
||||
|
@ -583,6 +613,22 @@ void FilterRowButton::paintEvent(QPaintEvent *e) {
|
|||
Ui::AddSkip(aboutRows);
|
||||
Ui::AddSubsectionTitle(aboutRows, tr::lng_filters_recommended());
|
||||
|
||||
const auto setTagsProgress = [=](float64 value) {
|
||||
for (const auto &row : state->rows) {
|
||||
row.button->setColorIndexProgress(value);
|
||||
}
|
||||
};
|
||||
tagsButtonEnabled->events() | rpl::distinct_until_changed(
|
||||
) | rpl::start_with_next([=](bool value) {
|
||||
state->tagsEnabledAnimation.stop();
|
||||
state->tagsEnabledAnimation.start(
|
||||
setTagsProgress,
|
||||
value ? .0 : 1.,
|
||||
value ? 1. : .0,
|
||||
st::universalDuration);
|
||||
}, lifetime);
|
||||
setTagsProgress(session->data().chatsFilters().tagsEnabled());
|
||||
|
||||
rpl::single(rpl::empty) | rpl::then(
|
||||
session->data().chatsFilters().suggestedUpdated()
|
||||
) | rpl::map([=] {
|
||||
|
@ -844,9 +890,101 @@ void SetupTopContent(
|
|||
|
||||
}
|
||||
|
||||
void SetupTagContent(
|
||||
not_null<Window::SessionController*> controller,
|
||||
not_null<Ui::VerticalLayout*> content,
|
||||
not_null<rpl::event_stream<bool>*> tagsButtonEnabled) {
|
||||
Ui::AddDivider(content);
|
||||
Ui::AddSkip(content);
|
||||
|
||||
const auto session = &controller->session();
|
||||
|
||||
struct State final {
|
||||
rpl::event_stream<bool> tagsTurnOff;
|
||||
base::Timer requestTimer;
|
||||
Fn<void()> sendCallback;
|
||||
};
|
||||
|
||||
auto premium = Data::AmPremiumValue(session);
|
||||
const auto tagsButton = content->add(
|
||||
object_ptr<Ui::SettingsButton>(
|
||||
content,
|
||||
tr::lng_filters_enable_tags(),
|
||||
st::settingsButtonNoIconLocked));
|
||||
const auto state = tagsButton->lifetime().make_state<State>();
|
||||
tagsButton->toggleOn(rpl::merge(
|
||||
rpl::combine(
|
||||
session->data().chatsFilters().tagsEnabledValue(),
|
||||
rpl::duplicate(premium),
|
||||
rpl::mappers::_1 && rpl::mappers::_2),
|
||||
state->tagsTurnOff.events()));
|
||||
rpl::duplicate(premium) | rpl::start_with_next([=](bool value) {
|
||||
tagsButton->setToggleLocked(!value);
|
||||
}, tagsButton->lifetime());
|
||||
|
||||
const auto send = [=, weak = Ui::MakeWeak(tagsButton)](bool checked) {
|
||||
session->data().chatsFilters().requestToggleTags(checked, [=] {
|
||||
if (const auto strong = weak.data()) {
|
||||
state->tagsTurnOff.fire(!checked);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
tagsButton->toggledValue(
|
||||
) | rpl::filter([=](bool checked) {
|
||||
const auto premium = session->premium();
|
||||
if (checked && !premium) {
|
||||
ShowPremiumPreviewToBuy(controller, PremiumFeature::FilterTags);
|
||||
state->tagsTurnOff.fire(false);
|
||||
}
|
||||
if (!premium) {
|
||||
tagsButtonEnabled->fire(false);
|
||||
} else {
|
||||
tagsButtonEnabled->fire_copy(checked);
|
||||
}
|
||||
const auto proceed = premium
|
||||
&& (checked != session->data().chatsFilters().tagsEnabled());
|
||||
if (!proceed) {
|
||||
state->requestTimer.cancel();
|
||||
}
|
||||
return proceed;
|
||||
}) | rpl::start_with_next([=](bool v) {
|
||||
state->sendCallback = [=] { send(v); };
|
||||
state->requestTimer.cancel();
|
||||
state->requestTimer.setCallback([=] { send(v); });
|
||||
state->requestTimer.callOnce(500);
|
||||
}, tagsButton->lifetime());
|
||||
|
||||
tagsButton->lifetime().add([=] {
|
||||
if (state->requestTimer.isActive()) {
|
||||
if (state->sendCallback) {
|
||||
state->sendCallback();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Ui::AddSkip(content);
|
||||
const auto about = Ui::AddDividerText(
|
||||
content,
|
||||
rpl::conditional(
|
||||
rpl::duplicate(premium),
|
||||
tr::lng_filters_enable_tags_about(Ui::Text::RichLangValue),
|
||||
tr::lng_filters_enable_tags_about_premium(
|
||||
lt_link,
|
||||
tr::lng_effect_premium_link() | rpl::map([](QString t) {
|
||||
return Ui::Text::Link(std::move(t), u"internal:"_q);
|
||||
}),
|
||||
Ui::Text::RichLangValue)));
|
||||
about->setClickHandlerFilter([=](const auto &...) {
|
||||
Settings::ShowPremium(controller, u"folder_tags"_q);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void SetupView(
|
||||
not_null<Window::SessionController*> controller,
|
||||
not_null<Ui::VerticalLayout*> content) {
|
||||
not_null<Ui::VerticalLayout*> content,
|
||||
bool dividerNeeded) {
|
||||
const auto wrap = content->add(
|
||||
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
|
||||
content,
|
||||
|
@ -854,7 +992,9 @@ void SetupView(
|
|||
wrap->toggleOn(controller->enoughSpaceForFiltersValue());
|
||||
content = wrap->entity();
|
||||
|
||||
Ui::AddDivider(content);
|
||||
if (dividerNeeded) {
|
||||
Ui::AddDivider(content);
|
||||
}
|
||||
Ui::AddSkip(content);
|
||||
Ui::AddSubsectionTitle(content, tr::lng_filters_view_subtitle());
|
||||
|
||||
|
@ -904,12 +1044,20 @@ void Folders::setupContent(not_null<Window::SessionController*> controller) {
|
|||
controller->session().data().chatsFilters().requestSuggested();
|
||||
|
||||
const auto content = Ui::CreateChild<Ui::VerticalLayout>(this);
|
||||
const auto tagsButtonEnabled
|
||||
= content->lifetime().make_state<rpl::event_stream<bool>>();
|
||||
|
||||
SetupTopContent(content, _showFinished.events());
|
||||
|
||||
_save = SetupFoldersContent(controller, content);
|
||||
_save = SetupFoldersContent(controller, content, tagsButtonEnabled);
|
||||
|
||||
SetupView(controller, content);
|
||||
auto dividerNeeded = true;
|
||||
if (controller->session().premiumPossible()) {
|
||||
SetupTagContent(controller, content, tagsButtonEnabled);
|
||||
dividerNeeded = false;
|
||||
}
|
||||
|
||||
SetupView(controller, content, dividerNeeded);
|
||||
|
||||
Ui::ResizeFitChild(this, content);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue