mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-15 13:47:05 +02:00
Start animating emoji in filter titles.
This commit is contained in:
parent
6cfbccd955
commit
d874829b06
16 changed files with 363 additions and 144 deletions
|
@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "boxes/filters/edit_filter_links.h" // FilterChatStatusText
|
||||
#include "core/application.h"
|
||||
#include "core/core_settings.h"
|
||||
#include "core/ui_integration.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_chat.h"
|
||||
#include "data/data_chat_filters.h"
|
||||
|
@ -26,6 +27,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/boxes/confirm_box.h"
|
||||
#include "ui/controls/filter_link_header.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/toast/toast.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/filter_icons.h"
|
||||
#include "ui/vertical_list.h"
|
||||
|
@ -105,7 +107,7 @@ private:
|
|||
Unexpected("Ui::FilterLinkHeaderType in TitleText.");
|
||||
}
|
||||
|
||||
[[nodiscard]] TextWithEntities AboutText( // todo filter emoji
|
||||
[[nodiscard]] TextWithEntities AboutText(
|
||||
Ui::FilterLinkHeaderType type,
|
||||
TextWithEntities title) {
|
||||
using Type = Ui::FilterLinkHeaderType;
|
||||
|
@ -147,10 +149,17 @@ void InitFilterLinkHeader(
|
|||
Ui::LookupFilterIconByEmoji(
|
||||
iconEmoji
|
||||
).value_or(Ui::FilterIcon::Custom)).active;
|
||||
const auto makeContext = [=](Fn<void()> repaint) {
|
||||
return Core::MarkedTextContext{
|
||||
.session = &box->peerListUiShow()->session(),
|
||||
.customEmojiRepaint = std::move(repaint),
|
||||
};
|
||||
};
|
||||
auto header = Ui::MakeFilterLinkHeader(box, {
|
||||
.type = type,
|
||||
.title = TitleText(type)(tr::now),
|
||||
.about = AboutText(type, title),
|
||||
.makeAboutContext = makeContext,
|
||||
.folderTitle = title,
|
||||
.folderIcon = icon,
|
||||
.badge = (type == Ui::FilterLinkHeaderType::AddingChats
|
||||
|
@ -541,7 +550,7 @@ void ShowImportToast(
|
|||
const auto phrase = created
|
||||
? tr::lng_filters_added_title
|
||||
: tr::lng_filters_updated_title;
|
||||
auto text = Ui::Text::Wrapped( // todo filter emoji
|
||||
auto text = Ui::Text::Wrapped(
|
||||
phrase(tr::now, lt_folder, title, Ui::Text::WithEntities),
|
||||
EntityType::Bold);
|
||||
if (added > 0) {
|
||||
|
@ -550,7 +559,16 @@ void ShowImportToast(
|
|||
: tr::lng_filters_updated_also;
|
||||
text.append('\n').append(phrase(tr::now, lt_count, added));
|
||||
}
|
||||
strong->showToast(std::move(text));
|
||||
const auto makeContext = [=](not_null<QWidget*> widget) {
|
||||
return Core::MarkedTextContext{
|
||||
.session = &strong->session(),
|
||||
.customEmojiRepaint = [=] { widget->update(); },
|
||||
};
|
||||
};
|
||||
strong->showToast({
|
||||
.text = std::move(text),
|
||||
.textContext = makeContext,
|
||||
});
|
||||
}
|
||||
|
||||
void HandleEnterInBox(not_null<Ui::BoxContent*> box) {
|
||||
|
@ -619,10 +637,17 @@ void ProcessFilterInvite(
|
|||
|
||||
raw->setRealContentHeight(box->heightValue());
|
||||
|
||||
const auto makeContext = [=](Fn<void()> update) {
|
||||
return Core::MarkedTextContext{
|
||||
.session = &strong->session(),
|
||||
.customEmojiRepaint = update,
|
||||
};
|
||||
};
|
||||
auto owned = Ui::FilterLinkProcessButton(
|
||||
box,
|
||||
type,
|
||||
title,
|
||||
makeContext,
|
||||
std::move(badge));
|
||||
|
||||
const auto button = owned.data();
|
||||
|
@ -842,10 +867,17 @@ void ProcessFilterRemove(
|
|||
raw->adjust(min, max, addedTop);
|
||||
}, type, title, iconEmoji, rpl::single(0), horizontalFilters);
|
||||
|
||||
const auto makeContext = [=](Fn<void()> update) {
|
||||
return Core::MarkedTextContext{
|
||||
.session = &strong->session(),
|
||||
.customEmojiRepaint = update,
|
||||
};
|
||||
};
|
||||
auto owned = Ui::FilterLinkProcessButton(
|
||||
box,
|
||||
type,
|
||||
title,
|
||||
makeContext,
|
||||
std::move(badge));
|
||||
|
||||
const auto button = owned.data();
|
||||
|
|
|
@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "boxes/premium_limits_box.h"
|
||||
#include "boxes/premium_preview_box.h"
|
||||
#include "chat_helpers/emoji_suggestions_widget.h"
|
||||
#include "chat_helpers/message_field.h"
|
||||
#include "core/application.h"
|
||||
#include "core/core_settings.h"
|
||||
#include "data/data_channel.h"
|
||||
|
@ -394,28 +395,28 @@ void EditFilterBox(
|
|||
tr::lng_filters_edit()));
|
||||
box->setCloseByOutsideClick(false);
|
||||
|
||||
const auto session = &window->session();
|
||||
Data::AmPremiumValue(
|
||||
&window->session()
|
||||
session
|
||||
) | rpl::start_with_next([=] {
|
||||
box->closeBox();
|
||||
}, box->lifetime());
|
||||
|
||||
const auto content = box->verticalLayout();
|
||||
const auto current = filter.title();
|
||||
const auto name = content->add(
|
||||
object_ptr<Ui::InputField>(
|
||||
box,
|
||||
st::windowFilterNameInput,
|
||||
tr::lng_filters_new_name(),
|
||||
filter.title().text), // todo filter emoji
|
||||
Ui::InputField::Mode::SingleLine,
|
||||
tr::lng_filters_new_name()),
|
||||
st::markdownLinkFieldPadding);
|
||||
InitMessageFieldHandlers(window, name, ChatHelpers::PauseReason::Layer);
|
||||
name->setTextWithTags({
|
||||
current.text,
|
||||
TextUtilities::ConvertEntitiesToTextTags(current.entities),
|
||||
}, Ui::InputField::HistoryAction::Clear);
|
||||
name->setMaxLength(kMaxFilterTitleLength);
|
||||
name->setInstantReplaces(Ui::InstantReplaces::Default());
|
||||
name->setInstantReplacesEnabled(
|
||||
Core::App().settings().replaceEmojiValue());
|
||||
Ui::Emoji::SuggestionsController::Init(
|
||||
box->getDelegate()->outerContainer(),
|
||||
name,
|
||||
&window->session());
|
||||
|
||||
const auto nameEditing = box->lifetime().make_state<NameEditing>(
|
||||
NameEditing{ name });
|
||||
|
@ -672,8 +673,11 @@ void EditFilterBox(
|
|||
}
|
||||
|
||||
const auto collect = [=]() -> std::optional<Data::ChatFilter> {
|
||||
// todo filter emoji
|
||||
const auto title = TextWithEntities{ name->getLastText().trimmed() };
|
||||
const auto entered = name->getTextWithTags();
|
||||
const auto title = TextWithEntities{
|
||||
entered.text,
|
||||
TextUtilities::ConvertTextTagsToEntities(entered.tags),
|
||||
};
|
||||
const auto rules = data->current();
|
||||
if (title.empty()) {
|
||||
name->showError();
|
||||
|
|
|
@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#include "boxes/filters/edit_filter_chats_list.h"
|
||||
|
||||
#include "core/ui_integration.h"
|
||||
#include "data/data_chat_filters.h"
|
||||
#include "data/data_premium_limits.h"
|
||||
#include "data/data_session.h"
|
||||
|
@ -63,13 +64,27 @@ private:
|
|||
|
||||
class ExceptionRow final : public ChatsListBoxController::Row {
|
||||
public:
|
||||
explicit ExceptionRow(not_null<History*> history);
|
||||
ExceptionRow(
|
||||
not_null<History*> history,
|
||||
not_null<PeerListDelegate*> delegate);
|
||||
|
||||
QString generateName() override;
|
||||
QString generateShortName() override;
|
||||
PaintRoundImageCallback generatePaintUserpicCallback(
|
||||
bool forceRound) override;
|
||||
|
||||
void paintStatusText(
|
||||
Painter &p,
|
||||
const style::PeerListItem &st,
|
||||
int x,
|
||||
int y,
|
||||
int availableWidth,
|
||||
int outerWidth,
|
||||
bool selected) override;
|
||||
|
||||
private:
|
||||
Ui::Text::String _filtersText;
|
||||
|
||||
};
|
||||
|
||||
class TypeController final : public PeerListController {
|
||||
|
@ -126,15 +141,29 @@ Flag TypeRow::flag() const {
|
|||
return static_cast<Flag>(id() & 0xFFFF);
|
||||
}
|
||||
|
||||
ExceptionRow::ExceptionRow(not_null<History*> history) : Row(history) {
|
||||
auto filters = QStringList();
|
||||
ExceptionRow::ExceptionRow(
|
||||
not_null<History*> history,
|
||||
not_null<PeerListDelegate*> delegate)
|
||||
: Row(history) {
|
||||
auto filters = TextWithEntities();
|
||||
for (const auto &filter : history->owner().chatsFilters().list()) {
|
||||
if (filter.contains(history) && filter.id()) {
|
||||
filters << filter.title().text; // todo filter emoji
|
||||
if (!filters.empty()) {
|
||||
filters.append(u", "_q);
|
||||
}
|
||||
filters.append(filter.title());
|
||||
}
|
||||
}
|
||||
if (!filters.isEmpty()) {
|
||||
setCustomStatus(filters.join(", "));
|
||||
if (!filters.empty()) {
|
||||
const auto repaint = [=] { delegate->peerListUpdateRow(this); };
|
||||
_filtersText.setMarkedText(
|
||||
st::defaultTextStyle,
|
||||
filters,
|
||||
kMarkupTextOptions,
|
||||
Core::MarkedTextContext{
|
||||
.session = &history->session(),
|
||||
.customEmojiRepaint = repaint,
|
||||
});
|
||||
} else if (peer()->isSelf()) {
|
||||
setCustomStatus(tr::lng_saved_forward_here(tr::now));
|
||||
}
|
||||
|
@ -176,6 +205,37 @@ PaintRoundImageCallback ExceptionRow::generatePaintUserpicCallback(
|
|||
};
|
||||
}
|
||||
|
||||
void ExceptionRow::paintStatusText(
|
||||
Painter &p,
|
||||
const style::PeerListItem &st,
|
||||
int x,
|
||||
int y,
|
||||
int availableWidth,
|
||||
int outerWidth,
|
||||
bool selected) {
|
||||
if (_filtersText.isEmpty()) {
|
||||
Row::paintStatusText(
|
||||
p,
|
||||
st,
|
||||
x,
|
||||
y,
|
||||
availableWidth,
|
||||
outerWidth,
|
||||
selected);
|
||||
} else {
|
||||
p.setPen(selected ? st.statusFgOver : st.statusFg);
|
||||
_filtersText.draw(p, {
|
||||
.position = { x, y },
|
||||
.outerWidth = outerWidth,
|
||||
.availableWidth = availableWidth,
|
||||
.palette = &st::defaultTextPalette,
|
||||
.now = crl::now(),
|
||||
.pausedEmoji = false,
|
||||
.elisionLines = 1,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
TypeController::TypeController(
|
||||
not_null<Main::Session*> session,
|
||||
Flags options,
|
||||
|
@ -418,7 +478,7 @@ void EditFilterChatsListController::prepareViewHook() {
|
|||
const auto rows = std::make_unique<std::optional<ExceptionRow>[]>(count);
|
||||
auto i = 0;
|
||||
for (const auto &history : _peers) {
|
||||
rows[i++].emplace(history);
|
||||
rows[i++].emplace(history, delegate());
|
||||
}
|
||||
auto pointers = std::vector<ExceptionRow*>();
|
||||
pointers.reserve(count);
|
||||
|
@ -499,7 +559,7 @@ auto EditFilterChatsListController::createRow(not_null<History*> history)
|
|||
return nullptr;
|
||||
}
|
||||
return history->inChatList()
|
||||
? std::make_unique<ExceptionRow>(history)
|
||||
? std::make_unique<ExceptionRow>(history, delegate())
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "boxes/peers/edit_peer_invite_link.h" // InviteLinkQrBox.
|
||||
#include "boxes/peer_list_box.h"
|
||||
#include "boxes/premium_limits_box.h"
|
||||
#include "core/ui_integration.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_chat.h"
|
||||
#include "data/data_chat_filters.h"
|
||||
|
@ -535,6 +536,12 @@ void LinkController::addHeader(not_null<Ui::VerticalLayout*> container) {
|
|||
}, verticalLayout->lifetime());
|
||||
verticalLayout->add(std::move(icon.widget));
|
||||
|
||||
const auto makeContext = [=](Fn<void()> update) {
|
||||
return Core::MarkedTextContext{
|
||||
.session = &_window->session(),
|
||||
.customEmojiRepaint = update,
|
||||
};
|
||||
};
|
||||
verticalLayout->add(
|
||||
object_ptr<Ui::CenterWrap<>>(
|
||||
verticalLayout,
|
||||
|
@ -543,12 +550,14 @@ void LinkController::addHeader(not_null<Ui::VerticalLayout*> container) {
|
|||
(_data.url.isEmpty()
|
||||
? tr::lng_filters_link_no_about(Ui::Text::WithEntities)
|
||||
: tr::lng_filters_link_share_about(
|
||||
lt_folder, // todo filter emoji
|
||||
lt_folder,
|
||||
rpl::single(Ui::Text::Wrapped(
|
||||
_filterTitle,
|
||||
EntityType::Bold)),
|
||||
Ui::Text::WithEntities)),
|
||||
st::settingsFilterDividerLabel)),
|
||||
st::settingsFilterDividerLabel,
|
||||
st::defaultPopupMenu,
|
||||
makeContext)),
|
||||
st::filterLinkDividerLabelPadding);
|
||||
|
||||
verticalLayout->geometryValue(
|
||||
|
|
|
@ -356,7 +356,8 @@ void ShareBox::prepare() {
|
|||
[this](FilterId id) {
|
||||
_inner->applyChatFilter(id);
|
||||
scrollToY(0);
|
||||
});
|
||||
},
|
||||
Window::GifPauseReason::Layer);
|
||||
chatsFilters->lower();
|
||||
chatsFilters->heightValue() | rpl::start_with_next([this](int h) {
|
||||
updateScrollSkips();
|
||||
|
|
|
@ -1345,6 +1345,7 @@ void Widget::toggleFiltersMenu(bool enabled) {
|
|||
controller()->setActiveChatsFilter(id);
|
||||
}
|
||||
},
|
||||
Window::GifPauseReason::Any,
|
||||
controller(),
|
||||
true);
|
||||
raw->show();
|
||||
|
|
|
@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "boxes/premium_limits_box.h"
|
||||
#include "boxes/premium_preview_box.h"
|
||||
#include "core/application.h"
|
||||
#include "core/ui_integration.h"
|
||||
#include "data/data_chat_filters.h"
|
||||
#include "data/data_folder.h"
|
||||
#include "data/data_peer.h"
|
||||
|
@ -57,14 +58,13 @@ public:
|
|||
FilterRowButton(
|
||||
not_null<QWidget*> parent,
|
||||
not_null<Main::Session*> session,
|
||||
const Data::ChatFilter &filter);
|
||||
FilterRowButton(
|
||||
not_null<QWidget*> parent,
|
||||
const Data::ChatFilter &filter,
|
||||
const QString &description);
|
||||
const QString &description = {});
|
||||
|
||||
void setRemoved(bool removed);
|
||||
void updateData(const Data::ChatFilter &filter);
|
||||
void updateData(
|
||||
const Data::ChatFilter &filter,
|
||||
bool ignoreCount = false);
|
||||
void updateCount(const Data::ChatFilter &filter);
|
||||
|
||||
[[nodiscard]] rpl::producer<> removeRequests() const;
|
||||
|
@ -80,20 +80,13 @@ private:
|
|||
Normal,
|
||||
};
|
||||
|
||||
FilterRowButton(
|
||||
not_null<QWidget*> parent,
|
||||
Main::Session *session,
|
||||
const Data::ChatFilter &filter,
|
||||
const QString &description,
|
||||
State state);
|
||||
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
void setup(const Data::ChatFilter &filter, const QString &status);
|
||||
void setState(State state, bool force = false);
|
||||
void updateButtonsVisibility();
|
||||
|
||||
Main::Session *_session = nullptr;
|
||||
const not_null<Main::Session*> _session;
|
||||
|
||||
Ui::IconButton _remove;
|
||||
Ui::RoundButton _restore;
|
||||
|
@ -177,50 +170,43 @@ struct FilterRow {
|
|||
FilterRowButton::FilterRowButton(
|
||||
not_null<QWidget*> parent,
|
||||
not_null<Main::Session*> session,
|
||||
const Data::ChatFilter &filter)
|
||||
: FilterRowButton(
|
||||
parent,
|
||||
session,
|
||||
filter,
|
||||
ComputeCountString(session, filter),
|
||||
State::Normal) {
|
||||
}
|
||||
|
||||
FilterRowButton::FilterRowButton(
|
||||
not_null<QWidget*> parent,
|
||||
const Data::ChatFilter &filter,
|
||||
const QString &description)
|
||||
: FilterRowButton(parent, nullptr, filter, description, State::Suggested) {
|
||||
}
|
||||
|
||||
FilterRowButton::FilterRowButton(
|
||||
not_null<QWidget*> parent,
|
||||
Main::Session *session,
|
||||
const Data::ChatFilter &filter,
|
||||
const QString &status,
|
||||
State state)
|
||||
: RippleButton(parent, st::defaultRippleAnimation)
|
||||
, _session(session)
|
||||
, _remove(this, st::filtersRemove)
|
||||
, _restore(this, tr::lng_filters_restore(), st::stickersUndoRemove)
|
||||
, _add(this, tr::lng_filters_recommended_add(), st::stickersTrendingAdd)
|
||||
, _state(state) {
|
||||
, _state(description.isEmpty() ? State::Normal : State::Suggested) {
|
||||
_restore.setTextTransform(Ui::RoundButton::TextTransform::NoTransform);
|
||||
_add.setTextTransform(Ui::RoundButton::TextTransform::NoTransform);
|
||||
setup(filter, status);
|
||||
setup(filter, description.isEmpty()
|
||||
? ComputeCountString(session, filter)
|
||||
: description);
|
||||
}
|
||||
|
||||
void FilterRowButton::setRemoved(bool removed) {
|
||||
setState(removed ? State::Removed : State::Normal);
|
||||
}
|
||||
|
||||
void FilterRowButton::updateData(const Data::ChatFilter &filter) {
|
||||
void FilterRowButton::updateData(
|
||||
const Data::ChatFilter &filter,
|
||||
bool ignoreCount) {
|
||||
Expects(_session != nullptr);
|
||||
// todo filter emoji
|
||||
_title.setText(st::contactsNameStyle, filter.title().text);
|
||||
|
||||
_title.setMarkedText(
|
||||
st::contactsNameStyle,
|
||||
filter.title(),
|
||||
kMarkupTextOptions,
|
||||
Core::MarkedTextContext{
|
||||
.session = _session,
|
||||
.customEmojiRepaint = [=] { update(); },
|
||||
});
|
||||
_icon = Ui::ComputeFilterIcon(filter);
|
||||
_colorIndex = filter.colorIndex();
|
||||
updateCount(filter);
|
||||
if (!ignoreCount) {
|
||||
updateCount(filter);
|
||||
}
|
||||
}
|
||||
|
||||
void FilterRowButton::updateCount(const Data::ChatFilter &filter) {
|
||||
|
@ -243,12 +229,9 @@ void FilterRowButton::setup(
|
|||
const Data::ChatFilter &filter,
|
||||
const QString &status) {
|
||||
resize(width(), st::defaultPeerListItem.height);
|
||||
// todo filter emoji
|
||||
_title.setText(st::contactsNameStyle, filter.title().text);
|
||||
_status = status;
|
||||
_icon = Ui::ComputeFilterIcon(filter);
|
||||
_colorIndex = filter.colorIndex();
|
||||
|
||||
_status = status;
|
||||
updateData(filter, true);
|
||||
setState(_state, true);
|
||||
|
||||
sizeValue() | rpl::start_with_next([=](QSize size) {
|
||||
|
@ -648,6 +631,7 @@ void FilterRowButton::paintEvent(QPaintEvent *e) {
|
|||
state->suggested = state->suggested.current() + 1;
|
||||
const auto button = aboutRows->add(object_ptr<FilterRowButton>(
|
||||
aboutRows,
|
||||
session,
|
||||
filter,
|
||||
suggestion.description));
|
||||
button->addRequests(
|
||||
|
|
|
@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
#include "lang/lang_keys.h"
|
||||
#include "ui/image/image_prepare.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/painter.h"
|
||||
#include "ui/rp_widget.h"
|
||||
#include "ui/ui_utility.h"
|
||||
|
@ -28,6 +29,11 @@ namespace {
|
|||
constexpr auto kBodyAnimationPart = 0.90;
|
||||
constexpr auto kTitleAdditionalScale = 0.05;
|
||||
|
||||
struct PreviewState {
|
||||
Fn<QImage()> frame;
|
||||
rpl::lifetime lifetime;
|
||||
};
|
||||
|
||||
class Widget final : public RpWidget {
|
||||
public:
|
||||
Widget(
|
||||
|
@ -61,7 +67,7 @@ private:
|
|||
} _progress;
|
||||
|
||||
rpl::variable<int> _badge;
|
||||
QImage _preview;
|
||||
PreviewState _preview;
|
||||
QRectF _previewRect;
|
||||
|
||||
QString _titleText;
|
||||
|
@ -71,6 +77,7 @@ private:
|
|||
QPainterPath _titlePath;
|
||||
|
||||
TextWithEntities _folderTitle;
|
||||
Fn<std::any(Fn<void()>)> _makeContext;
|
||||
not_null<const style::icon*> _folderIcon;
|
||||
bool _horizontalFilters = false;
|
||||
|
||||
|
@ -80,55 +87,94 @@ private:
|
|||
|
||||
};
|
||||
|
||||
[[nodiscard]] QImage GeneratePreview(
|
||||
[[nodiscard]] PreviewState GeneratePreview(
|
||||
not_null<Ui::RpWidget*> parent,
|
||||
const TextWithEntities &title,
|
||||
Fn<std::any(Fn<void()>)> makeContext,
|
||||
int badge) {
|
||||
using Tabs = Ui::ChatsFiltersTabs;
|
||||
auto owned = parent->lifetime().make_state<base::unique_qptr<Tabs>>(
|
||||
base::make_unique_q<Tabs>(parent, st::dialogsSearchTabs));
|
||||
const auto raw = owned->get();
|
||||
auto preview = PreviewState();
|
||||
|
||||
struct State {
|
||||
State(not_null<Ui::RpWidget*> parent)
|
||||
: tabs(parent, st::dialogsSearchTabs) {
|
||||
}
|
||||
|
||||
Tabs tabs;
|
||||
QImage cache;
|
||||
bool dirty = true;
|
||||
};
|
||||
const auto state = preview.lifetime.make_state<State>(parent);
|
||||
preview.frame = [=] {
|
||||
if (state->dirty) {
|
||||
const auto raw = &state->tabs;
|
||||
state->cache.fill(st::windowBg->c);
|
||||
|
||||
auto p = QPainter(&state->cache);
|
||||
Ui::RenderWidget(p, raw, QPoint(), raw->rect());
|
||||
|
||||
const auto &r = st::defaultEmojiSuggestions.fadeRight;
|
||||
const auto &l = st::defaultEmojiSuggestions.fadeLeft;
|
||||
const auto padding = st::filterLinkSubsectionTitlePadding.top();
|
||||
const auto w = raw->width();
|
||||
const auto h = raw->height();
|
||||
r.fill(p, QRect(w - r.width() - padding, 0, r.width(), h));
|
||||
l.fill(p, QRect(padding, 0, l.width(), h));
|
||||
p.fillRect(0, 0, padding, h, st::windowBg);
|
||||
p.fillRect(w - padding, 0, padding, raw->height(), st::windowBg);
|
||||
}
|
||||
return state->cache;
|
||||
};
|
||||
const auto raw = &state->tabs;
|
||||
const auto repaint = [=] {
|
||||
state->dirty = true;
|
||||
};
|
||||
raw->setSections({
|
||||
tr::lng_filters_name_people(tr::now),
|
||||
title.text, // todo filter emoji
|
||||
tr::lng_filters_name_unread(tr::now),
|
||||
});
|
||||
TextWithEntities{ tr::lng_filters_name_people(tr::now) },
|
||||
title,
|
||||
TextWithEntities{ tr::lng_filters_name_unread(tr::now) },
|
||||
}, makeContext(repaint));
|
||||
raw->fitWidthToSections();
|
||||
raw->setActiveSectionFast(1);
|
||||
raw->stopAnimation();
|
||||
|
||||
auto result = QImage(
|
||||
auto &result = state->cache;
|
||||
result = QImage(
|
||||
raw->size() * style::DevicePixelRatio(),
|
||||
QImage::Format_ARGB32_Premultiplied);
|
||||
result.setDevicePixelRatio(style::DevicePixelRatio());
|
||||
result.fill(st::windowBg->c);
|
||||
{
|
||||
auto p = QPainter(&result);
|
||||
Ui::RenderWidget(p, raw, QPoint(), raw->rect());
|
||||
raw->hide();
|
||||
|
||||
const auto &r = st::defaultEmojiSuggestions.fadeRight;
|
||||
const auto &l = st::defaultEmojiSuggestions.fadeLeft;
|
||||
const auto padding = st::filterLinkSubsectionTitlePadding.top();
|
||||
const auto w = raw->width();
|
||||
const auto h = raw->height();
|
||||
r.fill(p, QRect(w - r.width() - padding, 0, r.width(), h));
|
||||
l.fill(p, QRect(padding, 0, l.width(), h));
|
||||
p.fillRect(0, 0, padding, h, st::windowBg);
|
||||
p.fillRect(w - padding, 0, padding, raw->height(), st::windowBg);
|
||||
}
|
||||
owned->reset();
|
||||
return result;
|
||||
style::PaletteChanged(
|
||||
) | rpl::start_with_next(repaint, preview.lifetime);
|
||||
|
||||
return preview;
|
||||
}
|
||||
|
||||
[[nodiscard]] QImage GeneratePreview(
|
||||
[[nodiscard]] PreviewState GeneratePreview(
|
||||
const TextWithEntities &title,
|
||||
Fn<std::any(Fn<void()>)> makeContext,
|
||||
not_null<const style::icon*> icon,
|
||||
int badge) {
|
||||
auto preview = PreviewState();
|
||||
|
||||
struct State {
|
||||
QImage bg;
|
||||
QImage composed;
|
||||
Ui::Text::String string;
|
||||
bool dirty = true;
|
||||
};
|
||||
const auto state = preview.lifetime.make_state<State>();
|
||||
const auto repaint = [=] {
|
||||
state->dirty = true;
|
||||
};
|
||||
|
||||
const auto size = st::filterLinkPreview;
|
||||
const auto ratio = style::DevicePixelRatio();
|
||||
const auto radius = st::filterLinkPreviewRadius;
|
||||
const auto full = QSize(size, size) * ratio;
|
||||
auto result = QImage(full, QImage::Format_ARGB32_Premultiplied);
|
||||
auto &result = state->bg;
|
||||
result = QImage(full, QImage::Format_ARGB32_Premultiplied);
|
||||
result.setDevicePixelRatio(ratio);
|
||||
result.fill(st::windowBg->c);
|
||||
|
||||
|
@ -149,16 +195,19 @@ private:
|
|||
const auto myIconTop = st::filterLinkPreviewMyBottom - iconHeight;
|
||||
icon->paint(p, iconLeft, myIconTop, size);
|
||||
|
||||
const auto paintName = [&](const QString &text, int top) {
|
||||
auto string = Ui::Text::String(
|
||||
st.style,
|
||||
const auto fillName = [=](const TextWithEntities &text) {
|
||||
state->string = Ui::Text::String(
|
||||
st::windowFiltersButton.style,
|
||||
text,
|
||||
kDefaultTextOptions,
|
||||
available);
|
||||
string.draw(p, {
|
||||
kMarkupTextOptions,
|
||||
available,
|
||||
makeContext(repaint));
|
||||
};
|
||||
const auto paintName = [=](QPainter &p, int top) {
|
||||
state->string.draw(p, {
|
||||
.position = QPoint(
|
||||
std::max(
|
||||
(column - string.maxWidth()) / 2,
|
||||
(column - state->string.maxWidth()) / 2,
|
||||
skip),
|
||||
top),
|
||||
.outerWidth = available,
|
||||
|
@ -169,9 +218,9 @@ private:
|
|||
};
|
||||
p.setFont(st.style.font);
|
||||
p.setPen(st.textFg);
|
||||
paintName(tr::lng_filters_all(tr::now), st::filterLinkPreviewAllTop);
|
||||
p.setPen(st.textFgActive);
|
||||
paintName(title.text, st::filterLinkPreviewMyTop); // todo filter emoji
|
||||
fillName({ tr::lng_filters_all(tr::now) });
|
||||
paintName(p, st::filterLinkPreviewAllTop);
|
||||
fillName(title);
|
||||
|
||||
auto hq = PainterHighQualityEnabler(p);
|
||||
|
||||
|
@ -226,7 +275,19 @@ private:
|
|||
p.drawRoundedRect(0, 0, size, size, radius, radius);
|
||||
p.end();
|
||||
|
||||
return Images::Round(std::move(result), Images::CornersMask(radius));
|
||||
result = Images::Round(std::move(result), Images::CornersMask(radius));
|
||||
|
||||
preview.frame = [=] {
|
||||
if (state->dirty) {
|
||||
state->composed = state->bg;
|
||||
auto p = QPainter(&state->composed);
|
||||
p.setPen(st.textFgActive);
|
||||
paintName(p, st::filterLinkPreviewMyTop);
|
||||
}
|
||||
return state->composed;
|
||||
};
|
||||
|
||||
return preview;
|
||||
}
|
||||
|
||||
Widget::Widget(
|
||||
|
@ -236,7 +297,9 @@ Widget::Widget(
|
|||
, _about(CreateChild<FlatLabel>(
|
||||
this,
|
||||
rpl::single(descriptor.about.value()),
|
||||
st::filterLinkAbout))
|
||||
st::filterLinkAbout,
|
||||
st::defaultPopupMenu,
|
||||
descriptor.makeAboutContext))
|
||||
, _close(CreateChild<IconButton>(this, st::boxTitleClose))
|
||||
, _aboutPadding(st::boxRowPadding)
|
||||
, _badge(std::move(descriptor.badge))
|
||||
|
@ -244,19 +307,15 @@ Widget::Widget(
|
|||
, _titleFont(st::boxTitle.style.font)
|
||||
, _titlePadding(st::filterLinkTitlePadding)
|
||||
, _folderTitle(descriptor.folderTitle)
|
||||
, _makeContext(descriptor.makeAboutContext)
|
||||
, _folderIcon(descriptor.folderIcon)
|
||||
, _horizontalFilters(descriptor.horizontalFilters) {
|
||||
setMinimumHeight(st::boxTitleHeight);
|
||||
refreshTitleText();
|
||||
setTitlePosition(st::boxTitlePosition.x(), st::boxTitlePosition.y());
|
||||
|
||||
style::PaletteChanged(
|
||||
) | rpl::start_with_next([this] {
|
||||
_preview = QImage();
|
||||
}, lifetime());
|
||||
|
||||
_badge.changes() | rpl::start_with_next([this] {
|
||||
_preview = QImage();
|
||||
_preview = PreviewState();
|
||||
update();
|
||||
}, lifetime());
|
||||
}
|
||||
|
@ -332,8 +391,9 @@ QRectF Widget::previewRect(
|
|||
float64 topProgress,
|
||||
float64 sizeProgress) const {
|
||||
if (_horizontalFilters) {
|
||||
const auto size = (_preview.size() / style::DevicePixelRatio())
|
||||
* sizeProgress;
|
||||
const auto size = (_preview.frame
|
||||
? (_preview.frame().size() / style::DevicePixelRatio())
|
||||
: QSize()) * sizeProgress;
|
||||
return QRectF(
|
||||
(width() - size.width()) / 2.,
|
||||
st::filterLinkPreviewTop * 1.5 * topProgress,
|
||||
|
@ -355,16 +415,27 @@ void Widget::paintEvent(QPaintEvent *e) {
|
|||
p.setOpacity(_progress.body);
|
||||
if (_progress.top) {
|
||||
auto hq = PainterHighQualityEnabler(p);
|
||||
if (_preview.isNull()) {
|
||||
if (!_preview.frame) {
|
||||
const auto badge = _badge.current();
|
||||
const auto makeContext = [=](Fn<void()> repaint) {
|
||||
return _makeContext([=] { repaint(); update(); });
|
||||
};
|
||||
if (_horizontalFilters) {
|
||||
_preview = GeneratePreview(this, _folderTitle, badge);
|
||||
_preview = GeneratePreview(
|
||||
this,
|
||||
_folderTitle,
|
||||
makeContext,
|
||||
badge);
|
||||
Widget::resizeEvent(nullptr);
|
||||
} else {
|
||||
_preview = GeneratePreview(_folderTitle, _folderIcon, badge);
|
||||
_preview = GeneratePreview(
|
||||
_folderTitle,
|
||||
makeContext,
|
||||
_folderIcon,
|
||||
badge);
|
||||
}
|
||||
}
|
||||
p.drawImage(_previewRect, _preview);
|
||||
p.drawImage(_previewRect, _preview.frame());
|
||||
}
|
||||
p.resetTransform();
|
||||
|
||||
|
@ -415,13 +486,14 @@ object_ptr<RoundButton> FilterLinkProcessButton(
|
|||
not_null<QWidget*> parent,
|
||||
FilterLinkHeaderType type,
|
||||
TextWithEntities title,
|
||||
Fn<std::any(Fn<void()>)> makeContext,
|
||||
rpl::producer<int> badge) {
|
||||
const auto st = &st::filterInviteBox.button;
|
||||
const auto badgeSt = &st::filterInviteButtonBadgeStyle;
|
||||
auto result = object_ptr<RoundButton>(parent, rpl::single(u""_q), *st);
|
||||
|
||||
struct Data {
|
||||
QString text;
|
||||
TextWithEntities text;
|
||||
QString badge;
|
||||
};
|
||||
auto data = std::move(
|
||||
|
@ -429,32 +501,41 @@ object_ptr<RoundButton> FilterLinkProcessButton(
|
|||
) | rpl::map([=](int count) {
|
||||
const auto badge = count ? QString::number(count) : QString();
|
||||
const auto with = [&](QString badge) {
|
||||
return rpl::map([=](QString text) {
|
||||
return rpl::map([=](TextWithEntities text) {
|
||||
return Data{ text, badge };
|
||||
});
|
||||
};
|
||||
switch (type) {
|
||||
case FilterLinkHeaderType::AddingFilter:
|
||||
return badge.isEmpty()
|
||||
? tr::lng_filters_by_link_add_no() | with(QString())
|
||||
? tr::lng_filters_by_link_add_no(
|
||||
Ui::Text::WithEntities
|
||||
) | with(QString())
|
||||
: tr::lng_filters_by_link_add_button(
|
||||
lt_folder,
|
||||
rpl::single(title.text) // todo filter emoji
|
||||
rpl::single(title),
|
||||
Ui::Text::WithEntities
|
||||
) | with(badge);
|
||||
case FilterLinkHeaderType::AddingChats:
|
||||
return badge.isEmpty()
|
||||
? tr::lng_filters_by_link_join_no() | with(QString())
|
||||
? tr::lng_filters_by_link_join_no(
|
||||
Ui::Text::WithEntities
|
||||
) | with(QString())
|
||||
: tr::lng_filters_by_link_and_join_button(
|
||||
lt_count,
|
||||
rpl::single(float64(count))) | with(badge);
|
||||
rpl::single(float64(count)),
|
||||
Ui::Text::WithEntities) | with(badge);
|
||||
case FilterLinkHeaderType::AllAdded:
|
||||
return tr::lng_box_ok() | with(QString());
|
||||
return tr::lng_box_ok(Ui::Text::WithEntities) | with(QString());
|
||||
case FilterLinkHeaderType::Removing:
|
||||
return badge.isEmpty()
|
||||
? tr::lng_filters_by_link_remove_button() | with(QString())
|
||||
? tr::lng_filters_by_link_remove_button(
|
||||
Ui::Text::WithEntities
|
||||
) | with(QString())
|
||||
: tr::lng_filters_by_link_and_quit_button(
|
||||
lt_count,
|
||||
rpl::single(float64(count))) | with(badge);
|
||||
rpl::single(float64(count)),
|
||||
Ui::Text::WithEntities) | with(badge);
|
||||
}
|
||||
Unexpected("Type in FilterLinkProcessButton.");
|
||||
}) | rpl::flatten_latest();
|
||||
|
@ -520,7 +601,11 @@ object_ptr<RoundButton> FilterLinkProcessButton(
|
|||
}, label->lifetime());
|
||||
|
||||
std::move(data) | rpl::start_with_next([=](Data data) {
|
||||
label->text.setText(st::filterInviteButtonStyle, data.text);
|
||||
label->text.setMarkedText(
|
||||
st::filterInviteButtonStyle,
|
||||
data.text,
|
||||
kMarkupTextOptions,
|
||||
makeContext([=] { label->update(); }));
|
||||
label->badge.setText(st::filterInviteButtonBadgeStyle, data.badge);
|
||||
label->update();
|
||||
}, label->lifetime());
|
||||
|
|
|
@ -26,6 +26,7 @@ struct FilterLinkHeaderDescriptor {
|
|||
base::required<FilterLinkHeaderType> type;
|
||||
base::required<QString> title;
|
||||
base::required<TextWithEntities> about;
|
||||
Fn<std::any(Fn<void()>)> makeAboutContext;
|
||||
base::required<TextWithEntities> folderTitle;
|
||||
not_null<const style::icon*> folderIcon;
|
||||
rpl::producer<int> badge;
|
||||
|
@ -46,6 +47,7 @@ struct FilterLinkHeader {
|
|||
not_null<QWidget*> parent,
|
||||
FilterLinkHeaderType type,
|
||||
TextWithEntities title,
|
||||
Fn<std::any(Fn<void()>)> makeContext,
|
||||
rpl::producer<int> badge);
|
||||
|
||||
} // namespace Ui
|
||||
|
|
|
@ -46,22 +46,25 @@ ChatsFiltersTabs::ChatsFiltersTabs(
|
|||
}
|
||||
|
||||
bool ChatsFiltersTabs::setSectionsAndCheckChanged(
|
||||
std::vector<QString> &§ions) {
|
||||
std::vector<TextWithEntities> &§ions,
|
||||
const std::any &context,
|
||||
Fn<bool()> paused) {
|
||||
const auto &was = sectionsRef();
|
||||
const auto changed = [&] {
|
||||
if (was.size() != sections.size()) {
|
||||
return true;
|
||||
}
|
||||
for (auto i = 0; i < sections.size(); i++) {
|
||||
if (was[i].label.toString() != sections[i]) {
|
||||
if (was[i].label.toTextWithEntities() != sections[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}();
|
||||
if (changed) {
|
||||
Ui::DiscreteSlider::setSections(std::move(sections));
|
||||
Ui::DiscreteSlider::setSections(std::move(sections), context);
|
||||
}
|
||||
_emojiPaused = std::move(paused);
|
||||
return changed;
|
||||
}
|
||||
|
||||
|
@ -171,6 +174,7 @@ void ChatsFiltersTabs::paintEvent(QPaintEvent *e) {
|
|||
const auto clip = e->rect();
|
||||
const auto range = getCurrentActiveRange();
|
||||
const auto activeIndex = activeSection();
|
||||
const auto now = crl::now();
|
||||
|
||||
auto index = 0;
|
||||
auto raisedIndex = -1;
|
||||
|
@ -225,6 +229,8 @@ void ChatsFiltersTabs::paintEvent(QPaintEvent *e) {
|
|||
.position = QPoint(labelLeft, _st.labelTop),
|
||||
.outerWidth = width(),
|
||||
.availableWidth = section.label.maxWidth(),
|
||||
.now = now,
|
||||
.pausedEmoji = _emojiPaused && _emojiPaused(),
|
||||
});
|
||||
{
|
||||
const auto it = _unreadCounts.find(index);
|
||||
|
|
|
@ -27,7 +27,10 @@ public:
|
|||
not_null<Ui::RpWidget*> parent,
|
||||
const style::SettingsSlider &st);
|
||||
|
||||
bool setSectionsAndCheckChanged(std::vector<QString> &§ions);
|
||||
bool setSectionsAndCheckChanged(
|
||||
std::vector<TextWithEntities> &§ions,
|
||||
const std::any &context,
|
||||
Fn<bool()> paused);
|
||||
|
||||
void fitWidthToSections() override;
|
||||
void setUnreadCount(int index, int unreadCount, bool muted);
|
||||
|
@ -84,6 +87,7 @@ private:
|
|||
std::optional<Ui::RoundRect> _bar;
|
||||
std::optional<Ui::RoundRect> _barActive;
|
||||
std::optional<QImage> _lockCache;
|
||||
Fn<bool()> _emojiPaused;
|
||||
|
||||
int _reordering = 0;
|
||||
|
||||
|
|
|
@ -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"
|
||||
#include "core/ui_integration.h"
|
||||
#include "data/data_chat_filters.h"
|
||||
#include "data/data_peer_values.h" // Data::AmPremiumValue.
|
||||
#include "data/data_premium_limits.h"
|
||||
|
@ -20,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "lang/lang_keys.h"
|
||||
#include "main/main_session.h"
|
||||
#include "settings/settings_folders.h"
|
||||
#include "ui/power_saving.h"
|
||||
#include "ui/ui_utility.h"
|
||||
#include "ui/widgets/chat_filters_tabs_slider_reorder.h"
|
||||
#include "ui/widgets/menu/menu_add_action_callback_factory.h"
|
||||
|
@ -177,6 +179,7 @@ not_null<Ui::RpWidget*> AddChatFiltersTabsStrip(
|
|||
not_null<Ui::RpWidget*> parent,
|
||||
not_null<Main::Session*> session,
|
||||
Fn<void(FilterId)> choose,
|
||||
ChatHelpers::PauseReason pauseLevel,
|
||||
Window::SessionController *controller,
|
||||
bool trackActiveFilterAndUnreadAndReorder) {
|
||||
|
||||
|
@ -325,14 +328,22 @@ not_null<Ui::RpWidget*> AddChatFiltersTabsStrip(
|
|||
if ((list.size() <= 1 && !slider->width()) || state->ignoreRefresh) {
|
||||
return;
|
||||
}
|
||||
const auto context = Core::MarkedTextContext{
|
||||
.session = session,
|
||||
.customEmojiRepaint = [=] { slider->update(); },
|
||||
};
|
||||
const auto paused = [=] {
|
||||
return On(PowerSaving::kEmojiChat)
|
||||
|| controller->isGifPausedAtLeastFor(pauseLevel);
|
||||
};
|
||||
const auto sectionsChanged = slider->setSectionsAndCheckChanged(
|
||||
ranges::views::all(
|
||||
list
|
||||
) | ranges::views::transform([](const Data::ChatFilter &filter) {
|
||||
return filter.title().empty()
|
||||
? tr::lng_filters_all_short(tr::now)
|
||||
: filter.title().text; // todo filter emoji
|
||||
}) | ranges::to_vector);
|
||||
? TextWithEntities{ tr::lng_filters_all_short(tr::now) }
|
||||
: filter.title();
|
||||
}) | ranges::to_vector, context, paused);
|
||||
if (!sectionsChanged) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
namespace ChatHelpers {
|
||||
enum class PauseReason;
|
||||
} // namespace ChatHelpers
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
@ -25,6 +29,7 @@ not_null<Ui::RpWidget*> AddChatFiltersTabsStrip(
|
|||
not_null<Ui::RpWidget*> parent,
|
||||
not_null<Main::Session*> session,
|
||||
Fn<void(FilterId)> choose,
|
||||
ChatHelpers::PauseReason pauseLevel,
|
||||
Window::SessionController *controller = nullptr,
|
||||
bool trackActiveFilterAndUnreadAndReorder = false);
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "window/window_main_menu.h"
|
||||
#include "window/window_peer_menu.h"
|
||||
#include "main/main_session.h"
|
||||
#include "core/ui_integration.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_chat_filters.h"
|
||||
#include "data/data_user.h"
|
||||
|
@ -26,6 +27,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/widgets/menu/menu_add_action_callback_factory.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "ui/power_saving.h"
|
||||
#include "ui/ui_utility.h"
|
||||
#include "boxes/filters/edit_filter_box.h"
|
||||
#include "boxes/premium_limits_box.h"
|
||||
|
@ -46,7 +48,7 @@ FiltersMenu::FiltersMenu(
|
|||
: _session(session)
|
||||
, _parent(parent)
|
||||
, _outer(_parent)
|
||||
, _menu(&_outer, QString(), st::windowFiltersMainMenu)
|
||||
, _menu(&_outer, TextWithEntities(), st::windowFiltersMainMenu)
|
||||
, _scroll(&_outer)
|
||||
, _container(
|
||||
_scroll.setOwnedWidget(
|
||||
|
@ -250,10 +252,22 @@ base::unique_qptr<Ui::SideBarButton> FiltersMenu::prepareButton(
|
|||
TextWithEntities title,
|
||||
Ui::FilterIcon icon,
|
||||
bool toBeginning) {
|
||||
const auto makeContext = [=](Fn<void()> update) {
|
||||
return Core::MarkedTextContext{
|
||||
.session = &_session->session(),
|
||||
.customEmojiRepaint = std::move(update),
|
||||
};
|
||||
};
|
||||
const auto paused = [=] {
|
||||
return On(PowerSaving::kEmojiChat)
|
||||
|| _session->isGifPausedAtLeastFor(Window::GifPauseReason::Any);
|
||||
};
|
||||
auto prepared = object_ptr<Ui::SideBarButton>(
|
||||
container,
|
||||
id ? title.text : tr::lng_filters_all(tr::now), // todo filter emoji
|
||||
st::windowFiltersButton);
|
||||
id ? title : TextWithEntities{ tr::lng_filters_all(tr::now) },
|
||||
st::windowFiltersButton,
|
||||
makeContext,
|
||||
paused);
|
||||
auto added = toBeginning
|
||||
? container->insert(0, std::move(prepared))
|
||||
: container->add(std::move(prepared));
|
||||
|
|
|
@ -2241,7 +2241,8 @@ QPointer<Ui::BoxContent> ShowForwardMessagesBox(
|
|||
[=](FilterId id) {
|
||||
*lastFilterId = id;
|
||||
applyFilter(box, id);
|
||||
});
|
||||
},
|
||||
Window::GifPauseReason::Layer);
|
||||
chatsFilters->lower();
|
||||
rpl::combine(
|
||||
chatsFilters->heightValue(),
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit ab8d8fcfd265f94b2a63f94a0f1796b907818b74
|
||||
Subproject commit b063197b5d05de96754894630e45c8b3f95ade62
|
Loading…
Add table
Reference in a new issue