mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-16 06:07:06 +02:00
Use StickersListFooter for GIFs section.
This commit is contained in:
parent
d51d1939b0
commit
ffb2c5093d
7 changed files with 177 additions and 93 deletions
|
@ -353,8 +353,6 @@ gifsSearchField: defaultMultiSelectSearchField;
|
|||
gifsSearchFieldPosition: point(42px, 7px);
|
||||
gifsSearchCancel: defaultMultiSelectSearchCancel;
|
||||
gifsSearchCancelPosition: point(1px, 1px);
|
||||
gifsSearchIcon: boxFieldSearchIcon;
|
||||
gifsSearchIconPosition: point(6px, 7px);
|
||||
|
||||
emojiSuggestionsDropdown: InnerDropdown(defaultInnerDropdown) {
|
||||
scrollMargin: margins(0px, emojiColorsPadding, 0px, emojiColorsPadding);
|
||||
|
|
|
@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "api/api_toggling_media.h" // Api::ToggleSavedGif
|
||||
#include "base/const_string.h"
|
||||
#include "base/qt/qt_key_modifiers.h"
|
||||
#include "chat_helpers/stickers_list_footer.h"
|
||||
#include "data/data_photo.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_emoji_statuses.h"
|
||||
|
@ -83,94 +84,6 @@ void AddGifAction(
|
|||
}, saved ? &st::menuIconDelete : &st::menuIconGif);
|
||||
}
|
||||
|
||||
class GifsListWidget::Footer : public TabbedSelector::InnerFooter {
|
||||
public:
|
||||
Footer(not_null<GifsListWidget*> parent);
|
||||
|
||||
void stealFocus();
|
||||
void returnFocus();
|
||||
void setLoading(bool loading) {
|
||||
_cancel->setLoadingAnimation(loading);
|
||||
}
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
|
||||
void processPanelHideFinished() override;
|
||||
|
||||
private:
|
||||
not_null<GifsListWidget*> _pan;
|
||||
|
||||
object_ptr<Ui::InputField> _field;
|
||||
object_ptr<Ui::CrossButton> _cancel;
|
||||
|
||||
QPointer<QWidget> _focusTakenFrom;
|
||||
|
||||
};
|
||||
|
||||
GifsListWidget::Footer::Footer(not_null<GifsListWidget*> parent)
|
||||
: InnerFooter(parent, st::defaultEmojiPan)
|
||||
, _pan(parent)
|
||||
, _field(this, st::gifsSearchField, tr::lng_gifs_search())
|
||||
, _cancel(this, st::gifsSearchCancel) {
|
||||
connect(_field, &Ui::InputField::submitted, [=] {
|
||||
_pan->sendInlineRequest();
|
||||
});
|
||||
connect(_field, &Ui::InputField::cancelled, [=] {
|
||||
if (_field->getLastText().isEmpty()) {
|
||||
_pan->cancelled();
|
||||
} else {
|
||||
_field->setText(QString());
|
||||
}
|
||||
});
|
||||
connect(_field, &Ui::InputField::changed, [=] {
|
||||
_cancel->toggle(
|
||||
!_field->getLastText().isEmpty(),
|
||||
anim::type::normal);
|
||||
_pan->searchForGifs(_field->getLastText());
|
||||
});
|
||||
_cancel->setClickedCallback([=] {
|
||||
_field->setText(QString());
|
||||
});
|
||||
}
|
||||
|
||||
void GifsListWidget::Footer::stealFocus() {
|
||||
if (!_focusTakenFrom) {
|
||||
_focusTakenFrom = QApplication::focusWidget();
|
||||
}
|
||||
_field->setFocus();
|
||||
}
|
||||
|
||||
void GifsListWidget::Footer::returnFocus() {
|
||||
if (_focusTakenFrom) {
|
||||
if (_field->hasFocus()) {
|
||||
_focusTakenFrom->setFocus();
|
||||
}
|
||||
_focusTakenFrom = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void GifsListWidget::Footer::paintEvent(QPaintEvent *e) {
|
||||
Painter p(this);
|
||||
st::gifsSearchIcon.paint(p, st::gifsSearchIconPosition.x(), st::gifsSearchIconPosition.y(), width());
|
||||
}
|
||||
|
||||
void GifsListWidget::Footer::resizeEvent(QResizeEvent *e) {
|
||||
auto fieldWidth = width()
|
||||
- st::gifsSearchFieldPosition.x()
|
||||
- st::gifsSearchCancelPosition.x()
|
||||
- st::gifsSearchCancel.width;
|
||||
_field->resizeToWidth(fieldWidth);
|
||||
_field->moveToLeft(st::gifsSearchFieldPosition.x(), st::gifsSearchFieldPosition.y());
|
||||
_cancel->moveToRight(st::gifsSearchCancelPosition.x(), st::gifsSearchCancelPosition.y());
|
||||
}
|
||||
|
||||
void GifsListWidget::Footer::processPanelHideFinished() {
|
||||
// Preserve panel state through visibility toggles.
|
||||
//_field->setText(QString());
|
||||
}
|
||||
|
||||
GifsListWidget::GifsListWidget(
|
||||
QWidget *parent,
|
||||
not_null<Window::SessionController*> controller,
|
||||
|
@ -241,8 +154,89 @@ auto GifsListWidget::inlineResultChosen() const
|
|||
object_ptr<TabbedSelector::InnerFooter> GifsListWidget::createFooter() {
|
||||
Expects(_footer == nullptr);
|
||||
|
||||
auto result = object_ptr<Footer>(this);
|
||||
using FooterDescriptor = StickersListFooter::Descriptor;
|
||||
auto result = object_ptr<StickersListFooter>(FooterDescriptor{
|
||||
.session = &session(),
|
||||
.paused = pausedMethod(),
|
||||
.parent = this,
|
||||
.st = &st(),
|
||||
});
|
||||
_footer = result;
|
||||
|
||||
GifSectionsValue(
|
||||
&session()
|
||||
) | rpl::start_with_next([=](std::vector<GifSection> &&list) {
|
||||
_sections = std::move(list);
|
||||
refreshIcons();
|
||||
}, _footer->lifetime());
|
||||
|
||||
_footer->setChosen(
|
||||
) | rpl::start_with_next([=](uint64 setId) {
|
||||
_chosenSetId = setId;
|
||||
refreshIcons();
|
||||
const auto i = ranges::find(_sections, setId, [](GifSection value) {
|
||||
return value.document->id;
|
||||
});
|
||||
if (i != end(_sections)) {
|
||||
searchForGifs(i->emoji->text());
|
||||
}
|
||||
}, _footer->lifetime());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void GifsListWidget::refreshIcons() {
|
||||
if (_footer) {
|
||||
_footer->refreshIcons(
|
||||
fillIcons(),
|
||||
_chosenSetId,
|
||||
nullptr,
|
||||
ValidateIconAnimations::None);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<StickerIcon> GifsListWidget::fillIcons() {
|
||||
auto result = std::vector<StickerIcon>();
|
||||
result.reserve(_sections.size() + 1);
|
||||
result.emplace_back(Data::Stickers::RecentSetId);
|
||||
for (const auto §ion : _sections) {
|
||||
const auto s = section.document;
|
||||
const auto id = s->id;
|
||||
const auto availw = st::stickerIconWidth - 2 * st::stickerIconPadding;
|
||||
const auto availh = st().footer - 2 * st::stickerIconPadding;
|
||||
const auto size = s->hasThumbnail()
|
||||
? QSize(
|
||||
s->thumbnailLocation().width(),
|
||||
s->thumbnailLocation().height())
|
||||
: QSize();
|
||||
auto thumbw = size.width(), thumbh = size.height(), pixw = 1, pixh = 1;
|
||||
if (availw * thumbh > availh * thumbw) {
|
||||
pixh = availh;
|
||||
pixw = (pixh * thumbw) / thumbh;
|
||||
} else {
|
||||
pixw = availw;
|
||||
pixh = thumbw ? ((pixw * thumbh) / thumbw) : 1;
|
||||
}
|
||||
if (pixw < 1) pixw = 1;
|
||||
if (pixh < 1) pixh = 1;
|
||||
const auto owner = &s->owner();
|
||||
const auto already = _fakeSets.find(id);
|
||||
const auto set = (already != end(_fakeSets))
|
||||
? already
|
||||
: _fakeSets.emplace(
|
||||
id,
|
||||
std::make_unique<Data::StickersSet>(
|
||||
owner,
|
||||
id,
|
||||
0,
|
||||
0,
|
||||
QString(),
|
||||
QString(),
|
||||
0,
|
||||
Data::StickersSetFlag::Special,
|
||||
0)).first;
|
||||
result.emplace_back(set->second.get(), s, pixw, pixh);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -546,10 +540,16 @@ TabbedSelector::InnerFooter *GifsListWidget::getFooter() const {
|
|||
void GifsListWidget::processHideFinished() {
|
||||
clearSelection();
|
||||
clearHeavyData();
|
||||
if (_footer) {
|
||||
_footer->clearHeavyData();
|
||||
}
|
||||
}
|
||||
|
||||
void GifsListWidget::processPanelHideFinished() {
|
||||
clearHeavyData();
|
||||
if (_footer) {
|
||||
_footer->clearHeavyData();
|
||||
}
|
||||
}
|
||||
|
||||
void GifsListWidget::clearHeavyData() {
|
||||
|
@ -813,6 +813,8 @@ void GifsListWidget::setupSearch() {
|
|||
});
|
||||
_search->queryValue(
|
||||
) | rpl::start_with_next([=](std::vector<QString> &&query) {
|
||||
_chosenSetId = Data::Stickers::RecentSetId;
|
||||
refreshIcons();
|
||||
searchForGifs(ranges::accumulate(query, QString(), [](
|
||||
QString a,
|
||||
QString b) {
|
||||
|
|
|
@ -39,6 +39,10 @@ namespace SendMenu {
|
|||
enum class Type;
|
||||
} // namespace SendMenu
|
||||
|
||||
namespace Data {
|
||||
class StickersSet;
|
||||
} // namespace Data
|
||||
|
||||
namespace ChatHelpers {
|
||||
|
||||
void AddGifAction(
|
||||
|
@ -46,6 +50,10 @@ void AddGifAction(
|
|||
Window::SessionController *controller,
|
||||
not_null<DocumentData*> document);
|
||||
|
||||
class StickersListFooter;
|
||||
struct StickerIcon;
|
||||
struct GifSection;
|
||||
|
||||
class GifsListWidget
|
||||
: public TabbedSelector::Inner
|
||||
, public InlineBots::Layout::Context {
|
||||
|
@ -109,7 +117,6 @@ private:
|
|||
Inlines,
|
||||
Gifs,
|
||||
};
|
||||
class Footer;
|
||||
|
||||
using InlineResult = InlineBots::Result;
|
||||
using InlineResults = std::vector<std::unique_ptr<InlineResult>>;
|
||||
|
@ -134,6 +141,8 @@ private:
|
|||
|
||||
void updateSelected();
|
||||
void paintInlineItems(Painter &p, QRect clip);
|
||||
void refreshIcons();
|
||||
[[nodiscard]] std::vector<StickerIcon> fillIcons();
|
||||
|
||||
void updateInlineItems();
|
||||
void repaintItems(crl::time now = 0);
|
||||
|
@ -171,7 +180,10 @@ private:
|
|||
not_null<InlineResult*>,
|
||||
std::unique_ptr<LayoutItem>> _inlineLayouts;
|
||||
|
||||
Footer *_footer = nullptr;
|
||||
StickersListFooter *_footer = nullptr;
|
||||
std::vector<GifSection> _sections;
|
||||
base::flat_map<uint64, std::unique_ptr<Data::StickersSet>> _fakeSets;
|
||||
uint64 _chosenSetId = 0;
|
||||
|
||||
Mosaic::Layout::MosaicLayout<LayoutItem> _mosaic;
|
||||
|
||||
|
|
|
@ -384,6 +384,7 @@ void EmojiPack::applySet(const MTPDmessages_stickerSet &data) {
|
|||
for (const auto &[emoji, document] : was) {
|
||||
refreshItems(emoji);
|
||||
}
|
||||
_refreshed.fire({});
|
||||
}
|
||||
|
||||
void EmojiPack::applyAnimationsSet(const MTPDmessages_stickerSet &data) {
|
||||
|
|
|
@ -87,6 +87,9 @@ public:
|
|||
[[nodiscard]] int animationsVersion() const {
|
||||
return _animationsVersion;
|
||||
}
|
||||
[[nodiscard]] rpl::producer<> refreshed() const {
|
||||
return _refreshed.events();
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unique_ptr<Lottie::SinglePlayer> effectPlayer(
|
||||
not_null<DocumentData*> document,
|
||||
|
@ -135,6 +138,8 @@ private:
|
|||
not_null<DocumentData*>,
|
||||
std::weak_ptr<Lottie::FrameProvider>> _sharedProviders;
|
||||
|
||||
rpl::event_stream<> _refreshed;
|
||||
|
||||
rpl::lifetime _lifetime;
|
||||
|
||||
};
|
||||
|
|
|
@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#include "chat_helpers/stickers_list_footer.h"
|
||||
|
||||
#include "chat_helpers/stickers_emoji_pack.h"
|
||||
#include "chat_helpers/stickers_lottie.h"
|
||||
#include "data/stickers/data_stickers_set.h"
|
||||
#include "data/stickers/data_stickers.h"
|
||||
|
@ -16,6 +17,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_session.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_document_media.h"
|
||||
#include "main/main_account.h"
|
||||
#include "main/main_app_config.h"
|
||||
#include "main/main_session.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "lottie/lottie_single_player.h"
|
||||
|
@ -90,6 +93,58 @@ std::optional<EmojiSection> SetIdEmojiSection(uint64 id) {
|
|||
: std::optional<EmojiSection>();
|
||||
}
|
||||
|
||||
[[nodiscard]] std::vector<QString> GifSearchEmojiFallback() {
|
||||
return {
|
||||
u"\xf0\x9f\x91\x8d"_q,
|
||||
u"\xf0\x9f\x98\x98"_q,
|
||||
u"\xf0\x9f\x98\x8d"_q,
|
||||
u"\xf0\x9f\x98\xa1"_q,
|
||||
u"\xf0\x9f\xa5\xb3"_q,
|
||||
u"\xf0\x9f\x98\x82"_q,
|
||||
u"\xf0\x9f\x98\xae"_q,
|
||||
u"\xf0\x9f\x99\x84"_q,
|
||||
u"\xf0\x9f\x98\x8e"_q,
|
||||
u"\xf0\x9f\x91\x8e"_q,
|
||||
};
|
||||
}
|
||||
|
||||
rpl::producer<std::vector<GifSection>> GifSectionsValue(
|
||||
not_null<Main::Session*> session) {
|
||||
const auto config = &session->account().appConfig();
|
||||
return rpl::single(
|
||||
rpl::empty_value()
|
||||
) | rpl::then(
|
||||
config->refreshed()
|
||||
) | rpl::map([=] {
|
||||
return config->get<std::vector<QString>>(
|
||||
u"gif_search_emojies"_q,
|
||||
GifSearchEmojiFallback());
|
||||
}) | rpl::distinct_until_changed(
|
||||
) | rpl::map([=](const std::vector<QString> &emoji) {
|
||||
const auto list = ranges::views::all(
|
||||
emoji
|
||||
) | ranges::views::transform([](const QString &val) {
|
||||
return Ui::Emoji::Find(val);
|
||||
}) | ranges::views::filter([](EmojiPtr emoji) {
|
||||
return emoji != nullptr;
|
||||
}) | ranges::to_vector;
|
||||
|
||||
const auto pack = &session->emojiStickersPack();
|
||||
return rpl::single(
|
||||
rpl::empty_value()
|
||||
) | rpl::then(
|
||||
pack->refreshed()
|
||||
) | rpl::map([=, list = std::move(list)] {
|
||||
return list | ranges::views::transform([&](EmojiPtr emoji) {
|
||||
const auto document = pack->stickerForEmoji(emoji).document;
|
||||
return GifSection{ document, emoji };
|
||||
}) | ranges::views::filter([](GifSection section) {
|
||||
return (section.document != nullptr);
|
||||
}) | ranges::to_vector;
|
||||
}) | rpl::distinct_until_changed();
|
||||
}) | rpl::flatten_latest();
|
||||
}
|
||||
|
||||
StickerIcon::StickerIcon(uint64 setId) : setId(setId) {
|
||||
}
|
||||
|
||||
|
|
|
@ -52,6 +52,17 @@ enum class ValidateIconAnimations {
|
|||
[[nodiscard]] uint64 SearchEmojiSectionSetId();
|
||||
[[nodiscard]] std::optional<Ui::Emoji::Section> SetIdEmojiSection(uint64 id);
|
||||
|
||||
struct GifSection {
|
||||
DocumentData *document = nullptr;
|
||||
EmojiPtr emoji;
|
||||
|
||||
friend inline constexpr auto operator<=>(
|
||||
GifSection,
|
||||
GifSection) = default;
|
||||
};
|
||||
[[nodiscard]] rpl::producer<std::vector<GifSection>> GifSectionsValue(
|
||||
not_null<Main::Session*> session);
|
||||
|
||||
struct StickerIcon {
|
||||
explicit StickerIcon(uint64 setId);
|
||||
StickerIcon(
|
||||
|
|
Loading…
Add table
Reference in a new issue