mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-15 13:47:05 +02:00
Allow disabling animations in folder emoji.
This commit is contained in:
parent
c810005f86
commit
06341efe0d
17 changed files with 235 additions and 73 deletions
|
@ -5346,6 +5346,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_filters_edit" = "Edit Folder";
|
||||
"lng_filters_setup_menu" = "Edit Folders";
|
||||
"lng_filters_new_name" = "Folder name";
|
||||
"lng_filters_enable_animations" = "Enable animations";
|
||||
"lng_filters_disable_animations" = "Disable animations";
|
||||
"lng_filters_add_chats" = "Add Chats";
|
||||
"lng_filters_remove_chats" = "Add Chats to Exclude";
|
||||
"lng_filters_include" = "Included chats";
|
||||
|
|
|
@ -52,7 +52,7 @@ public:
|
|||
ToggleChatsController(
|
||||
not_null<Window::SessionController*> window,
|
||||
ToggleAction action,
|
||||
TextWithEntities title,
|
||||
Data::ChatFilterTitle title,
|
||||
std::vector<not_null<PeerData*>> chats,
|
||||
std::vector<not_null<PeerData*>> additional);
|
||||
|
||||
|
@ -78,7 +78,6 @@ private:
|
|||
Ui::RpWidget *_addedBottomWidget = nullptr;
|
||||
|
||||
ToggleAction _action = ToggleAction::Adding;
|
||||
TextWithEntities _filterTitle;
|
||||
base::flat_set<not_null<PeerData*>> _checkable;
|
||||
std::vector<not_null<PeerData*>> _chats;
|
||||
std::vector<not_null<PeerData*>> _additional;
|
||||
|
@ -141,7 +140,7 @@ void InitFilterLinkHeader(
|
|||
not_null<PeerListBox*> box,
|
||||
Fn<void(int minHeight, int maxHeight, int addedTopHeight)> adjust,
|
||||
Ui::FilterLinkHeaderType type,
|
||||
TextWithEntities title,
|
||||
Data::ChatFilterTitle title,
|
||||
QString iconEmoji,
|
||||
rpl::producer<int> count,
|
||||
bool horizontalFilters) {
|
||||
|
@ -149,18 +148,20 @@ void InitFilterLinkHeader(
|
|||
Ui::LookupFilterIconByEmoji(
|
||||
iconEmoji
|
||||
).value_or(Ui::FilterIcon::Custom)).active;
|
||||
const auto isStatic = title.isStatic;
|
||||
const auto makeContext = [=](Fn<void()> repaint) {
|
||||
return Core::MarkedTextContext{
|
||||
.session = &box->peerListUiShow()->session(),
|
||||
.customEmojiRepaint = std::move(repaint),
|
||||
.customEmojiLoopLimit = isStatic ? -1 : 0,
|
||||
};
|
||||
};
|
||||
auto header = Ui::MakeFilterLinkHeader(box, {
|
||||
.type = type,
|
||||
.title = TitleText(type)(tr::now),
|
||||
.about = AboutText(type, title),
|
||||
.about = AboutText(type, title.text),
|
||||
.makeAboutContext = makeContext,
|
||||
.folderTitle = title,
|
||||
.folderTitle = title.text,
|
||||
.folderIcon = icon,
|
||||
.badge = (type == Ui::FilterLinkHeaderType::AddingChats
|
||||
? std::move(count)
|
||||
|
@ -258,12 +259,11 @@ void ImportInvite(
|
|||
ToggleChatsController::ToggleChatsController(
|
||||
not_null<Window::SessionController*> window,
|
||||
ToggleAction action,
|
||||
TextWithEntities title,
|
||||
Data::ChatFilterTitle title,
|
||||
std::vector<not_null<PeerData*>> chats,
|
||||
std::vector<not_null<PeerData*>> additional)
|
||||
: _window(window)
|
||||
, _action(action)
|
||||
, _filterTitle(title)
|
||||
, _chats(std::move(chats))
|
||||
, _additional(std::move(additional)) {
|
||||
setStyleOverrides(&st::filterLinkChatsList);
|
||||
|
@ -539,7 +539,7 @@ void ShowImportError(
|
|||
|
||||
void ShowImportToast(
|
||||
base::weak_ptr<Window::SessionController> weak,
|
||||
TextWithEntities title,
|
||||
Data::ChatFilterTitle title,
|
||||
Ui::FilterLinkHeaderType type,
|
||||
int added) {
|
||||
const auto strong = weak.get();
|
||||
|
@ -551,7 +551,7 @@ void ShowImportToast(
|
|||
? tr::lng_filters_added_title
|
||||
: tr::lng_filters_updated_title;
|
||||
auto text = Ui::Text::Wrapped(
|
||||
phrase(tr::now, lt_folder, title, Ui::Text::WithEntities),
|
||||
phrase(tr::now, lt_folder, title.text, Ui::Text::WithEntities),
|
||||
EntityType::Bold);
|
||||
if (added > 0) {
|
||||
const auto phrase = created
|
||||
|
@ -559,10 +559,12 @@ void ShowImportToast(
|
|||
: tr::lng_filters_updated_also;
|
||||
text.append('\n').append(phrase(tr::now, lt_count, added));
|
||||
}
|
||||
const auto isStatic = title.isStatic;
|
||||
const auto makeContext = [=](not_null<QWidget*> widget) {
|
||||
return Core::MarkedTextContext{
|
||||
.session = &strong->session(),
|
||||
.customEmojiRepaint = [=] { widget->update(); },
|
||||
.customEmojiLoopLimit = isStatic ? -1 : 0,
|
||||
};
|
||||
};
|
||||
strong->showToast({
|
||||
|
@ -595,7 +597,7 @@ void ProcessFilterInvite(
|
|||
base::weak_ptr<Window::SessionController> weak,
|
||||
const QString &slug,
|
||||
FilterId filterId,
|
||||
TextWithEntities title,
|
||||
Data::ChatFilterTitle title,
|
||||
QString iconEmoji,
|
||||
std::vector<not_null<PeerData*>> peers,
|
||||
std::vector<not_null<PeerData*>> already) {
|
||||
|
@ -637,16 +639,18 @@ void ProcessFilterInvite(
|
|||
|
||||
raw->setRealContentHeight(box->heightValue());
|
||||
|
||||
const auto isStatic = title.isStatic;
|
||||
const auto makeContext = [=](Fn<void()> update) {
|
||||
return Core::MarkedTextContext{
|
||||
.session = &strong->session(),
|
||||
.customEmojiRepaint = update,
|
||||
.customEmojiLoopLimit = isStatic ? -1 : 0,
|
||||
};
|
||||
};
|
||||
auto owned = Ui::FilterLinkProcessButton(
|
||||
box,
|
||||
type,
|
||||
title,
|
||||
title.text,
|
||||
makeContext,
|
||||
std::move(badge));
|
||||
|
||||
|
@ -748,7 +752,7 @@ void CheckFilterInvite(
|
|||
if (!strong) {
|
||||
return;
|
||||
}
|
||||
auto title = TextWithEntities();
|
||||
auto title = Data::ChatFilterTitle();
|
||||
auto iconEmoji = QString();
|
||||
auto filterId = FilterId();
|
||||
auto peers = std::vector<not_null<PeerData*>>();
|
||||
|
@ -767,7 +771,8 @@ void CheckFilterInvite(
|
|||
return result;
|
||||
};
|
||||
result.match([&](const MTPDchatlists_chatlistInvite &data) {
|
||||
title = ParseTextWithEntities(session, data.vtitle());
|
||||
title.text = ParseTextWithEntities(session, data.vtitle());
|
||||
title.isStatic = data.is_title_noanimate();
|
||||
iconEmoji = data.vemoticon().value_or_empty();
|
||||
peers = parseList(data.vpeers());
|
||||
}, [&](const MTPDchatlists_chatlistInviteAlready &data) {
|
||||
|
@ -832,7 +837,7 @@ void ProcessFilterUpdate(
|
|||
|
||||
void ProcessFilterRemove(
|
||||
base::weak_ptr<Window::SessionController> weak,
|
||||
TextWithEntities title,
|
||||
Data::ChatFilterTitle title,
|
||||
QString iconEmoji,
|
||||
std::vector<not_null<PeerData*>> all,
|
||||
std::vector<not_null<PeerData*>> suggest,
|
||||
|
@ -867,16 +872,18 @@ void ProcessFilterRemove(
|
|||
raw->adjust(min, max, addedTop);
|
||||
}, type, title, iconEmoji, rpl::single(0), horizontalFilters);
|
||||
|
||||
const auto isStatic = title.isStatic;
|
||||
const auto makeContext = [=](Fn<void()> update) {
|
||||
return Core::MarkedTextContext{
|
||||
.session = &strong->session(),
|
||||
.customEmojiRepaint = update,
|
||||
.customEmojiLoopLimit = isStatic ? -1 : 0,
|
||||
};
|
||||
};
|
||||
auto owned = Ui::FilterLinkProcessButton(
|
||||
box,
|
||||
type,
|
||||
title,
|
||||
title.text,
|
||||
makeContext,
|
||||
std::move(badge));
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ class SessionController;
|
|||
|
||||
namespace Data {
|
||||
class ChatFilter;
|
||||
struct ChatFilterTitle;
|
||||
} // namespace Data
|
||||
|
||||
namespace Api {
|
||||
|
@ -36,7 +37,7 @@ void ProcessFilterUpdate(
|
|||
|
||||
void ProcessFilterRemove(
|
||||
base::weak_ptr<Window::SessionController> weak,
|
||||
TextWithEntities title,
|
||||
Data::ChatFilterTitle title,
|
||||
QString iconEmoji,
|
||||
std::vector<not_null<PeerData*>> all,
|
||||
std::vector<not_null<PeerData*>> suggest,
|
||||
|
|
|
@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "boxes/filters/edit_filter_box.h"
|
||||
#include "boxes/premium_limits_box.h"
|
||||
#include "core/application.h" // primaryWindow
|
||||
#include "core/ui_integration.h"
|
||||
#include "data/data_chat_filters.h"
|
||||
#include "data/data_premium_limits.h"
|
||||
#include "data/data_session.h"
|
||||
|
@ -22,6 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/painter.h"
|
||||
#include "ui/rect.h"
|
||||
#include "ui/text/text_utilities.h" // Ui::Text::Bold
|
||||
#include "ui/toast/toast.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/menu/menu_action.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
|
@ -169,15 +171,26 @@ void ChangeFilterById(
|
|||
)).done([=, chat = history->peer->name(), name = filter.title()] {
|
||||
const auto account = not_null(&history->session().account());
|
||||
if (const auto controller = Core::App().windowFor(account)) {
|
||||
controller->showToast((add
|
||||
? tr::lng_filters_toast_add
|
||||
: tr::lng_filters_toast_remove)(
|
||||
tr::now,
|
||||
lt_chat,
|
||||
Ui::Text::Bold(chat),
|
||||
lt_folder,
|
||||
Ui::Text::Wrapped(name, EntityType::Bold),
|
||||
Ui::Text::WithEntities));
|
||||
const auto isStatic = name.isStatic;
|
||||
const auto textContext = [=](not_null<QWidget*> widget) {
|
||||
return Core::MarkedTextContext{
|
||||
.session = &history->session(),
|
||||
.customEmojiRepaint = [=] { widget->update(); },
|
||||
.customEmojiLoopLimit = isStatic ? -1 : 0,
|
||||
};
|
||||
};
|
||||
controller->showToast({
|
||||
.text = (add
|
||||
? tr::lng_filters_toast_add
|
||||
: tr::lng_filters_toast_remove)(
|
||||
tr::now,
|
||||
lt_chat,
|
||||
Ui::Text::Bold(chat),
|
||||
lt_folder,
|
||||
Ui::Text::Wrapped(name.text, EntityType::Bold),
|
||||
Ui::Text::WithEntities),
|
||||
.textContext = textContext,
|
||||
});
|
||||
}
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
LOG(("API Error: failed to %1 a dialog to a folder. %2")
|
||||
|
@ -279,7 +292,7 @@ void FillChooseFilterMenu(
|
|||
menu->st().menu,
|
||||
Ui::Menu::CreateAction(
|
||||
menu.get(), // todo filter emoji
|
||||
Ui::Text::FixAmpersandInAction(filter.title().text),
|
||||
Ui::Text::FixAmpersandInAction(filter.title().text.text),
|
||||
std::move(callback)),
|
||||
contains ? &st::mediaPlayerMenuCheck : nullptr,
|
||||
contains ? &st::mediaPlayerMenuCheck : nullptr);
|
||||
|
|
|
@ -40,6 +40,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/filter_icons.h"
|
||||
#include "ui/layers/generic_box.h"
|
||||
#include "ui/painter.h"
|
||||
#include "ui/power_saving.h"
|
||||
#include "ui/vertical_list.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/fields/input_field.h"
|
||||
|
@ -352,6 +353,8 @@ void EditFilterBox(
|
|||
rpl::variable<bool> hasLinks;
|
||||
rpl::variable<bool> chatlist;
|
||||
rpl::variable<bool> creating;
|
||||
rpl::variable<TextWithEntities> title;
|
||||
rpl::variable<bool> staticTitle;
|
||||
rpl::variable<int> colorIndex;
|
||||
};
|
||||
const auto owner = &window->session().data();
|
||||
|
@ -359,6 +362,8 @@ void EditFilterBox(
|
|||
.rules = filter,
|
||||
.chatlist = filter.chatlist(),
|
||||
.creating = filter.title().empty(),
|
||||
.title = filter.titleText(),
|
||||
.staticTitle = filter.staticTitle(),
|
||||
});
|
||||
state->colorIndex = filter.colorIndex().value_or(kNoTag);
|
||||
state->links = owner->chatsFilters().chatlistLinks(filter.id()),
|
||||
|
@ -404,7 +409,7 @@ void EditFilterBox(
|
|||
}, box->lifetime());
|
||||
|
||||
const auto content = box->verticalLayout();
|
||||
const auto current = filter.title();
|
||||
const auto current = state->title.current();
|
||||
const auto name = content->add(
|
||||
object_ptr<Ui::InputField>(
|
||||
box,
|
||||
|
@ -422,6 +427,44 @@ void EditFilterBox(
|
|||
const auto nameEditing = box->lifetime().make_state<NameEditing>(
|
||||
NameEditing{ name });
|
||||
|
||||
const auto staticTitle = Ui::CreateChild<Ui::LinkButton>(
|
||||
name,
|
||||
QString());
|
||||
staticTitle->setClickedCallback([=] {
|
||||
state->staticTitle = !state->staticTitle.current();
|
||||
});
|
||||
state->staticTitle.value() | rpl::start_with_next([=](bool value) {
|
||||
staticTitle->setText(value
|
||||
? tr::lng_filters_enable_animations(tr::now)
|
||||
: tr::lng_filters_disable_animations(tr::now));
|
||||
const auto paused = [=] {
|
||||
using namespace Window;
|
||||
return window->isGifPausedAtLeastFor(GifPauseReason::Layer);
|
||||
};
|
||||
name->setCustomTextContext([=](Fn<void()> repaint) {
|
||||
return std::any(Core::MarkedTextContext{
|
||||
.session = session,
|
||||
.customEmojiRepaint = std::move(repaint),
|
||||
.customEmojiLoopLimit = value ? -1 : 0,
|
||||
});
|
||||
}, [paused] {
|
||||
return On(PowerSaving::kEmojiChat) || paused();
|
||||
}, [paused] {
|
||||
return On(PowerSaving::kChatSpoiler) || paused();
|
||||
});
|
||||
name->update();
|
||||
}, staticTitle->lifetime());
|
||||
|
||||
rpl::combine(
|
||||
staticTitle->widthValue(),
|
||||
name->widthValue()
|
||||
) | rpl::start_with_next([=](int inner, int outer) {
|
||||
staticTitle->moveToRight(
|
||||
st::windowFilterStaticTitlePosition.x(),
|
||||
st::windowFilterStaticTitlePosition.y(),
|
||||
outer);
|
||||
}, staticTitle->lifetime());
|
||||
|
||||
state->creating.value(
|
||||
) | rpl::filter(!_1) | rpl::start_with_next([=] {
|
||||
nameEditing->custom = true;
|
||||
|
@ -432,7 +475,13 @@ void EditFilterBox(
|
|||
if (!nameEditing->settingDefault) {
|
||||
nameEditing->custom = true;
|
||||
}
|
||||
auto entered = name->getTextWithTags();
|
||||
state->title = TextWithEntities{
|
||||
std::move(entered.text),
|
||||
TextUtilities::ConvertTextTagsToEntities(entered.tags),
|
||||
};
|
||||
}, name->lifetime());
|
||||
|
||||
const auto updateDefaultTitle = [=](const Data::ChatFilter &filter) {
|
||||
if (nameEditing->custom) {
|
||||
return;
|
||||
|
@ -444,13 +493,11 @@ void EditFilterBox(
|
|||
nameEditing->settingDefault = false;
|
||||
}
|
||||
};
|
||||
const auto nameWithEntities = [=](bool upper = false) {
|
||||
const auto entered = name->getTextWithTags();
|
||||
return TextWithEntities{
|
||||
(upper ? entered.text.toUpper() : entered.text),
|
||||
TextUtilities::ConvertTextTagsToEntities(entered.tags),
|
||||
};
|
||||
};
|
||||
|
||||
state->title.value(
|
||||
) | rpl::start_with_next([=](const TextWithEntities &value) {
|
||||
staticTitle->setVisible(!value.entities.isEmpty());
|
||||
}, staticTitle->lifetime());
|
||||
|
||||
const auto outer = box->getDelegate()->outerContainer();
|
||||
CreateIconSelector(
|
||||
|
@ -595,10 +642,16 @@ void EditFilterBox(
|
|||
const auto palette = [](int i) {
|
||||
return Ui::EmptyUserpic::UserpicColor(i).color2;
|
||||
};
|
||||
name->changes() | rpl::start_with_next([=] {
|
||||
const auto upperTitle = [=] {
|
||||
auto value = state->title.current();
|
||||
value.text = value.text.toUpper();
|
||||
return value;
|
||||
};
|
||||
state->title.changes(
|
||||
) | rpl::start_with_next([=] {
|
||||
tag->context.color = palette(state->colorIndex.current())->c;
|
||||
tag->frame = Ui::ChatsFilterTag(
|
||||
nameWithEntities(true),
|
||||
upperTitle(),
|
||||
tag->context);
|
||||
preview->update();
|
||||
}, preview->lifetime());
|
||||
|
@ -615,7 +668,7 @@ void EditFilterBox(
|
|||
if (progress == 1) {
|
||||
tag->context.color = color->c;
|
||||
tag->frame = Ui::ChatsFilterTag(
|
||||
nameWithEntities(true),
|
||||
upperTitle(),
|
||||
tag->context);
|
||||
if (i == kNoTag) {
|
||||
tag->alpha = 0.;
|
||||
|
@ -641,7 +694,7 @@ void EditFilterBox(
|
|||
buttons[now]->setSelectedProgress(progress);
|
||||
tag->context.color = anim::color(c1, c2, progress);
|
||||
tag->frame = Ui::ChatsFilterTag(
|
||||
nameWithEntities(true),
|
||||
upperTitle(),
|
||||
tag->context);
|
||||
tag->alpha = anim::interpolateF(a1, a2, progress);
|
||||
preview->update();
|
||||
|
@ -689,7 +742,9 @@ void EditFilterBox(
|
|||
}
|
||||
|
||||
const auto collect = [=]() -> std::optional<Data::ChatFilter> {
|
||||
const auto title = nameWithEntities();
|
||||
auto title = state->title.current();
|
||||
const auto staticTitle = !title.entities.isEmpty()
|
||||
&& state->staticTitle.current();
|
||||
const auto rules = data->current();
|
||||
if (title.empty()) {
|
||||
name->showError();
|
||||
|
@ -708,7 +763,9 @@ void EditFilterBox(
|
|||
const auto colorIndex = (rawColorIndex >= kNoTag
|
||||
? std::nullopt
|
||||
: std::make_optional(rawColorIndex));
|
||||
return rules.withTitle(title).withColorIndex(colorIndex);
|
||||
return rules.withTitle(
|
||||
{ std::move(title), staticTitle }
|
||||
).withColorIndex(colorIndex);
|
||||
};
|
||||
|
||||
Ui::AddSubsectionTitle(
|
||||
|
|
|
@ -151,7 +151,10 @@ ExceptionRow::ExceptionRow(
|
|||
if (!filters.empty()) {
|
||||
filters.append(u", "_q);
|
||||
}
|
||||
filters.append(filter.title());
|
||||
auto title = filter.title();
|
||||
filters.append(title.isStatic
|
||||
? Data::ForceCustomEmojiStatic(std::move(title.text))
|
||||
: std::move(title.text));
|
||||
}
|
||||
}
|
||||
if (!filters.empty()) {
|
||||
|
|
|
@ -483,7 +483,7 @@ private:
|
|||
const not_null<Window::SessionController*> _window;
|
||||
InviteLinkData _data;
|
||||
|
||||
TextWithEntities _filterTitle;
|
||||
Data::ChatFilterTitle _filterTitle;
|
||||
base::flat_set<not_null<History*>> _filterChats;
|
||||
base::flat_map<not_null<PeerData*>, QString> _denied;
|
||||
rpl::variable<base::flat_set<not_null<PeerData*>>> _selected;
|
||||
|
@ -536,10 +536,12 @@ void LinkController::addHeader(not_null<Ui::VerticalLayout*> container) {
|
|||
}, verticalLayout->lifetime());
|
||||
verticalLayout->add(std::move(icon.widget));
|
||||
|
||||
const auto isStatic = _filterTitle.isStatic;
|
||||
const auto makeContext = [=](Fn<void()> update) {
|
||||
return Core::MarkedTextContext{
|
||||
.session = &_window->session(),
|
||||
.customEmojiRepaint = update,
|
||||
.customEmojiLoopLimit = isStatic ? -1 : 0,
|
||||
};
|
||||
};
|
||||
verticalLayout->add(
|
||||
|
@ -552,7 +554,7 @@ void LinkController::addHeader(not_null<Ui::VerticalLayout*> container) {
|
|||
: tr::lng_filters_link_share_about(
|
||||
lt_folder,
|
||||
rpl::single(Ui::Text::Wrapped(
|
||||
_filterTitle,
|
||||
_filterTitle.text,
|
||||
EntityType::Bold)),
|
||||
Ui::Text::WithEntities)),
|
||||
st::settingsFilterDividerLabel,
|
||||
|
|
|
@ -286,6 +286,9 @@ std::unique_ptr<Ui::Text::CustomEmoji> UiIntegration::createCustomEmoji(
|
|||
return std::make_unique<Ui::Text::LimitedLoopsEmoji>(
|
||||
std::move(result),
|
||||
my->customEmojiLoopLimit);
|
||||
} else if (my->customEmojiLoopLimit) {
|
||||
return std::make_unique<Ui::Text::FirstFrameEmoji>(
|
||||
std::move(result));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -40,9 +40,22 @@ constexpr auto kLoadExceptionsPerRequest = 100;
|
|||
|
||||
} // namespace
|
||||
|
||||
TextWithEntities ForceCustomEmojiStatic(TextWithEntities text) {
|
||||
for (auto &entity : text.entities) {
|
||||
if (entity.type() == EntityType::CustomEmoji) {
|
||||
entity = EntityInText(
|
||||
EntityType::CustomEmoji,
|
||||
entity.offset(),
|
||||
entity.length(),
|
||||
u"force-static:"_q + entity.data());
|
||||
}
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
ChatFilter::ChatFilter(
|
||||
FilterId id,
|
||||
TextWithEntities title,
|
||||
ChatFilterTitle title,
|
||||
QString iconEmoji,
|
||||
std::optional<uint8> colorIndex,
|
||||
Flags flags,
|
||||
|
@ -50,13 +63,15 @@ ChatFilter::ChatFilter(
|
|||
std::vector<not_null<History*>> pinned,
|
||||
base::flat_set<not_null<History*>> never)
|
||||
: _id(id)
|
||||
, _title(std::move(title))
|
||||
, _title(std::move(title.text))
|
||||
, _iconEmoji(std::move(iconEmoji))
|
||||
, _colorIndex(colorIndex)
|
||||
, _always(std::move(always))
|
||||
, _pinned(std::move(pinned))
|
||||
, _never(std::move(never))
|
||||
, _flags(flags) {
|
||||
, _flags(title.isStatic
|
||||
? (flags | Flag::StaticTitle)
|
||||
: (flags & ~Flag::StaticTitle)) {
|
||||
}
|
||||
|
||||
ChatFilter ChatFilter::FromTL(
|
||||
|
@ -70,7 +85,8 @@ ChatFilter ChatFilter::FromTL(
|
|||
| (data.is_bots() ? Flag::Bots : Flag(0))
|
||||
| (data.is_exclude_muted() ? Flag::NoMuted : Flag(0))
|
||||
| (data.is_exclude_read() ? Flag::NoRead : Flag(0))
|
||||
| (data.is_exclude_archived() ? Flag::NoArchived : Flag(0));
|
||||
| (data.is_exclude_archived() ? Flag::NoArchived : Flag(0))
|
||||
| (data.is_title_noanimate() ? Flag::StaticTitle : Flag(0));
|
||||
auto &&to_histories = ranges::views::transform([&](
|
||||
const MTPInputPeer &input) {
|
||||
const auto peer = Data::PeerFromInputMTP(owner, input);
|
||||
|
@ -96,7 +112,10 @@ ChatFilter ChatFilter::FromTL(
|
|||
};
|
||||
return ChatFilter(
|
||||
data.vid().v,
|
||||
Api::ParseTextWithEntities(&owner->session(), data.vtitle()),
|
||||
{
|
||||
Api::ParseTextWithEntities(&owner->session(), data.vtitle()),
|
||||
data.is_title_noanimate(),
|
||||
},
|
||||
qs(data.vemoticon().value_or_empty()),
|
||||
data.vcolor()
|
||||
? std::make_optional(data.vcolor()->v)
|
||||
|
@ -105,7 +124,7 @@ ChatFilter ChatFilter::FromTL(
|
|||
std::move(list),
|
||||
std::move(pinned),
|
||||
{ never.begin(), never.end() });
|
||||
}, [](const MTPDdialogFilterDefault &d) {
|
||||
}, [](const MTPDdialogFilterDefault &) {
|
||||
return ChatFilter();
|
||||
}, [&](const MTPDdialogFilterChatlist &data) {
|
||||
auto &&to_histories = ranges::views::transform([&](
|
||||
|
@ -144,13 +163,17 @@ ChatFilter ChatFilter::FromTL(
|
|||
};
|
||||
return ChatFilter(
|
||||
data.vid().v,
|
||||
Api::ParseTextWithEntities(&owner->session(), data.vtitle()),
|
||||
{
|
||||
Api::ParseTextWithEntities(&owner->session(), data.vtitle()),
|
||||
data.is_title_noanimate(),
|
||||
},
|
||||
qs(data.vemoticon().value_or_empty()),
|
||||
data.vcolor()
|
||||
? std::make_optional(data.vcolor()->v)
|
||||
: std::nullopt,
|
||||
(Flag::Chatlist
|
||||
| (data.is_has_my_invites() ? Flag::HasMyLinks : Flag())),
|
||||
| (data.is_has_my_invites() ? Flag::HasMyLinks : Flag())
|
||||
| (data.is_title_noanimate() ? Flag::StaticTitle : Flag(0))),
|
||||
std::move(list),
|
||||
std::move(pinned),
|
||||
{});
|
||||
|
@ -163,9 +186,14 @@ ChatFilter ChatFilter::withId(FilterId id) const {
|
|||
return result;
|
||||
}
|
||||
|
||||
ChatFilter ChatFilter::withTitle(TextWithEntities title) const {
|
||||
ChatFilter ChatFilter::withTitle(ChatFilterTitle title) const {
|
||||
auto result = *this;
|
||||
result._title = std::move(title);
|
||||
result._title = std::move(title.text);
|
||||
if (title.isStatic) {
|
||||
result._flags |= Flag::StaticTitle;
|
||||
} else {
|
||||
result._flags &= ~Flag::StaticTitle;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -219,7 +247,8 @@ MTPDialogFilter ChatFilter::tl(FilterId replaceId) const {
|
|||
if (_flags & Flag::Chatlist) {
|
||||
using TLFlag = MTPDdialogFilterChatlist::Flag;
|
||||
const auto flags = TLFlag::f_emoticon
|
||||
| (_colorIndex ? TLFlag::f_color : TLFlag(0));
|
||||
| (_colorIndex ? TLFlag::f_color : TLFlag(0))
|
||||
| (staticTitle() ? TLFlag::f_title_noanimate : TLFlag(0));
|
||||
return MTP_dialogFilterChatlist(
|
||||
MTP_flags(flags),
|
||||
MTP_int(replaceId ? replaceId : _id),
|
||||
|
@ -232,6 +261,7 @@ MTPDialogFilter ChatFilter::tl(FilterId replaceId) const {
|
|||
using TLFlag = MTPDdialogFilter::Flag;
|
||||
const auto flags = TLFlag::f_emoticon
|
||||
| (_colorIndex ? TLFlag::f_color : TLFlag(0))
|
||||
| (staticTitle() ? TLFlag::f_title_noanimate : TLFlag(0))
|
||||
| ((_flags & Flag::Contacts) ? TLFlag::f_contacts : TLFlag(0))
|
||||
| ((_flags & Flag::NonContacts) ? TLFlag::f_non_contacts : TLFlag(0))
|
||||
| ((_flags & Flag::Groups) ? TLFlag::f_groups : TLFlag(0))
|
||||
|
@ -262,10 +292,14 @@ FilterId ChatFilter::id() const {
|
|||
return _id;
|
||||
}
|
||||
|
||||
TextWithEntities ChatFilter::title() const {
|
||||
const TextWithEntities &ChatFilter::titleText() const {
|
||||
return _title;
|
||||
}
|
||||
|
||||
ChatFilterTitle ChatFilter::title() const {
|
||||
return { _title, !!(_flags & Flag::StaticTitle) };
|
||||
}
|
||||
|
||||
QString ChatFilter::iconEmoji() const {
|
||||
return _iconEmoji;
|
||||
}
|
||||
|
@ -278,6 +312,10 @@ ChatFilter::Flags ChatFilter::flags() const {
|
|||
return _flags;
|
||||
}
|
||||
|
||||
bool ChatFilter::staticTitle() const {
|
||||
return _flags & Flag::StaticTitle;
|
||||
}
|
||||
|
||||
bool ChatFilter::chatlist() const {
|
||||
return _flags & Flag::Chatlist;
|
||||
}
|
||||
|
@ -669,7 +707,8 @@ bool ChatFilters::applyChange(ChatFilter &filter, ChatFilter &&updated) {
|
|||
|| (filter.hasMyLinks() != updated.hasMyLinks());
|
||||
const auto listUpdated = rulesChanged
|
||||
|| pinnedChanged
|
||||
|| (filter.title() != updated.title())
|
||||
|| (filter.titleText() != updated.titleText())
|
||||
|| (filter.staticTitle() != updated.staticTitle())
|
||||
|| (filter.iconEmoji() != updated.iconEmoji());
|
||||
const auto colorChanged = filter.colorIndex() != updated.colorIndex();
|
||||
const auto colorExistenceChanged = (!filter.colorIndex())
|
||||
|
|
|
@ -25,6 +25,17 @@ namespace Data {
|
|||
|
||||
class Session;
|
||||
|
||||
struct ChatFilterTitle {
|
||||
TextWithEntities text;
|
||||
bool isStatic = false;
|
||||
|
||||
[[nodiscard]] bool empty() const {
|
||||
return text.empty();
|
||||
}
|
||||
};
|
||||
|
||||
[[nodiscard]] TextWithEntities ForceCustomEmojiStatic(TextWithEntities text);
|
||||
|
||||
class ChatFilter final {
|
||||
public:
|
||||
enum class Flag : ushort {
|
||||
|
@ -40,9 +51,10 @@ public:
|
|||
|
||||
Chatlist = (1 << 8),
|
||||
HasMyLinks = (1 << 9),
|
||||
StaticTitle = (1 << 10),
|
||||
|
||||
NewChats = (1 << 10), // Telegram Business exceptions.
|
||||
ExistingChats = (1 << 11),
|
||||
NewChats = (1 << 11), // Telegram Business exceptions.
|
||||
ExistingChats = (1 << 12),
|
||||
};
|
||||
friend constexpr inline bool is_flag_type(Flag) { return true; };
|
||||
using Flags = base::flags<Flag>;
|
||||
|
@ -50,7 +62,7 @@ public:
|
|||
ChatFilter() = default;
|
||||
ChatFilter(
|
||||
FilterId id,
|
||||
TextWithEntities title,
|
||||
ChatFilterTitle title,
|
||||
QString iconEmoji,
|
||||
std::optional<uint8> colorIndex,
|
||||
Flags flags,
|
||||
|
@ -59,7 +71,7 @@ public:
|
|||
base::flat_set<not_null<History*>> never);
|
||||
|
||||
[[nodiscard]] ChatFilter withId(FilterId id) const;
|
||||
[[nodiscard]] ChatFilter withTitle(TextWithEntities title) const;
|
||||
[[nodiscard]] ChatFilter withTitle(ChatFilterTitle title) const;
|
||||
[[nodiscard]] ChatFilter withColorIndex(std::optional<uint8>) const;
|
||||
[[nodiscard]] ChatFilter withChatlist(
|
||||
bool chatlist,
|
||||
|
@ -72,10 +84,12 @@ public:
|
|||
[[nodiscard]] MTPDialogFilter tl(FilterId replaceId = 0) const;
|
||||
|
||||
[[nodiscard]] FilterId id() const;
|
||||
[[nodiscard]] TextWithEntities title() const;
|
||||
[[nodiscard]] ChatFilterTitle title() const;
|
||||
[[nodiscard]] const TextWithEntities &titleText() const;
|
||||
[[nodiscard]] QString iconEmoji() const;
|
||||
[[nodiscard]] std::optional<uint8> colorIndex() const;
|
||||
[[nodiscard]] Flags flags() const;
|
||||
[[nodiscard]] bool staticTitle() const;
|
||||
[[nodiscard]] bool chatlist() const;
|
||||
[[nodiscard]] bool hasMyLinks() const;
|
||||
[[nodiscard]] const base::flat_set<not_null<History*>> &always() const;
|
||||
|
@ -99,7 +113,7 @@ private:
|
|||
};
|
||||
|
||||
inline bool operator==(const ChatFilter &a, const ChatFilter &b) {
|
||||
return (a.title() == b.title())
|
||||
return (a.titleText() == b.titleText())
|
||||
&& (a.iconEmoji() == b.iconEmoji())
|
||||
&& (a.colorIndex() == b.colorIndex())
|
||||
&& (a.flags() == b.flags())
|
||||
|
|
|
@ -113,6 +113,10 @@ private:
|
|||
return u"scaled-custom:"_q;
|
||||
}
|
||||
|
||||
[[nodiscard]] QString ForceStaticPrefix() {
|
||||
return u"force-static:"_q;
|
||||
}
|
||||
|
||||
[[nodiscard]] QString InternalPadding(QMargins value) {
|
||||
return value.isNull() ? QString() : QString(",%1,%2,%3,%4"
|
||||
).arg(value.left()
|
||||
|
@ -554,6 +558,10 @@ std::unique_ptr<Ui::Text::CustomEmoji> CustomEmojiManager::create(
|
|||
const auto original = data.mid(ScaledCustomPrefix().size());
|
||||
return Ui::MakeScaledCustomEmoji(
|
||||
create(original, std::move(update), SizeTag::Large));
|
||||
} else if (data.startsWith(ForceStaticPrefix())) {
|
||||
const auto original = data.mid(ForceStaticPrefix().size());
|
||||
return std::make_unique<Ui::Text::FirstFrameEmoji>(
|
||||
create(original, std::move(update), tag, sizeOverride));
|
||||
} else if (data.startsWith(InternalPrefix())) {
|
||||
return internal(data);
|
||||
} else if (data.startsWith(UserpicEmojiPrefix())) {
|
||||
|
|
|
@ -4181,7 +4181,7 @@ QImage *InnerWidget::cacheChatsFilterTag(
|
|||
auto roundedText = TextWithEntities();
|
||||
auto colorIndex = -1;
|
||||
if (filter.id()) {
|
||||
roundedText = filter.title();
|
||||
roundedText = filter.title().text;
|
||||
roundedText.text = roundedText.text.toUpper();
|
||||
if (filter.colorIndex()) {
|
||||
colorIndex = *(filter.colorIndex());
|
||||
|
|
|
@ -194,13 +194,15 @@ void FilterRowButton::updateData(
|
|||
bool ignoreCount) {
|
||||
Expects(_session != nullptr);
|
||||
|
||||
const auto title = filter.title();
|
||||
_title.setMarkedText(
|
||||
st::contactsNameStyle,
|
||||
filter.title(),
|
||||
title.text,
|
||||
kMarkupTextOptions,
|
||||
Core::MarkedTextContext{
|
||||
.session = _session,
|
||||
.customEmojiRepaint = [=] { update(); },
|
||||
.customEmojiLoopLimit = title.isStatic ? -1 : 0,
|
||||
});
|
||||
_icon = Ui::ComputeFilterIcon(filter);
|
||||
_colorIndex = filter.colorIndex();
|
||||
|
|
|
@ -151,9 +151,10 @@ void ShowFiltersListMenu(
|
|||
|
||||
for (auto i = 0; i < list.size(); ++i) {
|
||||
const auto &filter = list[i];
|
||||
auto text = filter.title().empty()
|
||||
auto title = filter.title();
|
||||
auto text = title.text.empty()
|
||||
? tr::lng_filters_all_short(tr::now)
|
||||
: filter.title().text; // todo filter emoji
|
||||
: title.text.text; // todo filter emoji
|
||||
|
||||
const auto action = state->menu->addAction(std::move(text), [=] {
|
||||
if (i != active) {
|
||||
|
@ -340,9 +341,12 @@ not_null<Ui::RpWidget*> AddChatFiltersTabsStrip(
|
|||
ranges::views::all(
|
||||
list
|
||||
) | ranges::views::transform([](const Data::ChatFilter &filter) {
|
||||
return filter.title().empty()
|
||||
auto title = filter.title();
|
||||
return title.text.empty()
|
||||
? TextWithEntities{ tr::lng_filters_all_short(tr::now) }
|
||||
: filter.title();
|
||||
: title.isStatic
|
||||
? Data::ForceCustomEmojiStatic(title.text)
|
||||
: title.text;
|
||||
}) | ranges::to_vector, context, paused);
|
||||
if (!sectionsChanged) {
|
||||
return;
|
||||
|
|
|
@ -285,8 +285,9 @@ windowFilterSmallRemoveRight: 10px;
|
|||
windowFilterNameInput: InputField(defaultInputField) {
|
||||
textMargins: margins(0px, 26px, 36px, 4px);
|
||||
}
|
||||
windowFilterStaticTitlePosition: point(0px, 5px);
|
||||
windowFilterIconToggleSize: size(36px, 36px);
|
||||
windowFilterIconTogglePosition: point(-4px, 12px);
|
||||
windowFilterIconTogglePosition: point(-4px, 18px);
|
||||
windwoFilterIconPanelPosition: point(-2px, -1px);
|
||||
windowFilterIconSingle: size(44px, 42px);
|
||||
windowFilterIconPadding: margins(10px, 36px, 10px, 8px);
|
||||
|
|
|
@ -218,7 +218,7 @@ void FiltersMenu::setupList() {
|
|||
_setup = prepareButton(
|
||||
_container,
|
||||
-1,
|
||||
TextWithEntities{ tr::lng_filters_setup(tr::now) },
|
||||
{ TextWithEntities{ tr::lng_filters_setup(tr::now) } },
|
||||
Ui::FilterIcon::Edit);
|
||||
_reorder = std::make_unique<Ui::VerticalLayoutReorder>(_list, &_scroll);
|
||||
|
||||
|
@ -249,13 +249,15 @@ base::unique_qptr<Ui::SideBarButton> FiltersMenu::prepareAll() {
|
|||
base::unique_qptr<Ui::SideBarButton> FiltersMenu::prepareButton(
|
||||
not_null<Ui::VerticalLayout*> container,
|
||||
FilterId id,
|
||||
TextWithEntities title,
|
||||
Data::ChatFilterTitle title,
|
||||
Ui::FilterIcon icon,
|
||||
bool toBeginning) {
|
||||
const auto isStatic = title.isStatic;
|
||||
const auto makeContext = [=](Fn<void()> update) {
|
||||
return Core::MarkedTextContext{
|
||||
.session = &_session->session(),
|
||||
.customEmojiRepaint = std::move(update),
|
||||
.customEmojiLoopLimit = isStatic ? -1 : 0,
|
||||
};
|
||||
};
|
||||
const auto paused = [=] {
|
||||
|
@ -264,7 +266,7 @@ base::unique_qptr<Ui::SideBarButton> FiltersMenu::prepareButton(
|
|||
};
|
||||
auto prepared = object_ptr<Ui::SideBarButton>(
|
||||
container,
|
||||
id ? title : TextWithEntities{ tr::lng_filters_all(tr::now) },
|
||||
id ? title.text : TextWithEntities{ tr::lng_filters_all(tr::now) },
|
||||
st::windowFiltersButton,
|
||||
makeContext,
|
||||
paused);
|
||||
|
|
|
@ -13,6 +13,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/widgets/side_bar_button.h"
|
||||
#include "ui/widgets/scroll_area.h"
|
||||
|
||||
namespace Data {
|
||||
struct ChatFilterTitle;
|
||||
} // namespace Data
|
||||
|
||||
namespace Ui {
|
||||
class VerticalLayout;
|
||||
class VerticalLayoutReorder;
|
||||
|
@ -44,7 +48,7 @@ private:
|
|||
[[nodiscard]] base::unique_qptr<Ui::SideBarButton> prepareButton(
|
||||
not_null<Ui::VerticalLayout*> container,
|
||||
FilterId id,
|
||||
TextWithEntities title,
|
||||
Data::ChatFilterTitle title,
|
||||
Ui::FilterIcon icon,
|
||||
bool toBeginning = false);
|
||||
void setupMainMenuIcon();
|
||||
|
|
Loading…
Add table
Reference in a new issue