mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Moved sticker randomization to class in menu item of userpic builder.
This commit is contained in:
parent
08644a9c31
commit
e6b24a49f6
2 changed files with 143 additions and 59 deletions
|
@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "base/random.h"
|
#include "base/random.h"
|
||||||
#include "base/timer.h"
|
#include "base/timer.h"
|
||||||
#include "data/data_document.h"
|
#include "data/data_document.h"
|
||||||
|
#include "data/data_document_media.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/stickers/data_custom_emoji.h"
|
#include "data/stickers/data_custom_emoji.h"
|
||||||
#include "info/userpic/info_userpic_emoji_builder.h"
|
#include "info/userpic/info_userpic_emoji_builder.h"
|
||||||
|
@ -27,6 +28,128 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include <random>
|
#include <random>
|
||||||
|
|
||||||
namespace UserpicBuilder {
|
namespace UserpicBuilder {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr auto kTimeout = crl::time(1500);
|
||||||
|
|
||||||
|
class StickerProvider final {
|
||||||
|
public:
|
||||||
|
StickerProvider(not_null<Data::Session*> owner);
|
||||||
|
|
||||||
|
void setDocuments(std::vector<DocumentId> documents);
|
||||||
|
[[nodiscard]] DocumentId documentId() const;
|
||||||
|
[[nodiscard]] auto documentChanged() const
|
||||||
|
-> rpl::producer<not_null<DocumentData*>>;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void processDocumentIndex(int documentIndex);
|
||||||
|
[[nodiscard]] DocumentData *lookupAndRememberSticker(int documentIndex);
|
||||||
|
[[nodiscard]] std::pair<DocumentData*, int> lookupSticker(
|
||||||
|
int documentIndex) const;
|
||||||
|
|
||||||
|
const not_null<Data::Session*> _owner;
|
||||||
|
|
||||||
|
int _documentIndex = 0;
|
||||||
|
std::vector<DocumentId> _shuffledDocuments;
|
||||||
|
|
||||||
|
base::Timer _timer;
|
||||||
|
|
||||||
|
rpl::event_stream<not_null<DocumentData*>> _documentChanged;
|
||||||
|
rpl::lifetime _resolvingLifetime;
|
||||||
|
rpl::lifetime _downloadFinishedLifetime;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
StickerProvider::StickerProvider(not_null<Data::Session*> owner)
|
||||||
|
: _owner(owner) {
|
||||||
|
_timer.setCallback([=] {
|
||||||
|
_documentIndex++;
|
||||||
|
if (_documentIndex >= _shuffledDocuments.size()) {
|
||||||
|
_documentIndex = 0;
|
||||||
|
}
|
||||||
|
processDocumentIndex(_documentIndex);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
DocumentId StickerProvider::documentId() const {
|
||||||
|
const auto &[document, index] = lookupSticker(_documentIndex);
|
||||||
|
return document ? document->id : DocumentId(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StickerProvider::setDocuments(std::vector<DocumentId> documents) {
|
||||||
|
if (documents.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto rd = std::random_device();
|
||||||
|
ranges::shuffle(documents, std::mt19937(rd()));
|
||||||
|
_shuffledDocuments = std::move(documents);
|
||||||
|
_documentIndex = 0;
|
||||||
|
processDocumentIndex(_documentIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto StickerProvider::documentChanged() const
|
||||||
|
-> rpl::producer<not_null<DocumentData*>> {
|
||||||
|
return _documentChanged.events();
|
||||||
|
}
|
||||||
|
|
||||||
|
void StickerProvider::processDocumentIndex(int documentIndex) {
|
||||||
|
if (const auto document = lookupAndRememberSticker(documentIndex)) {
|
||||||
|
_resolvingLifetime.destroy();
|
||||||
|
_owner->customEmojiManager().resolve(
|
||||||
|
document->id
|
||||||
|
) | rpl::start_with_next([=](not_null<DocumentData*> d) {
|
||||||
|
_resolvingLifetime.destroy();
|
||||||
|
_downloadFinishedLifetime.destroy();
|
||||||
|
|
||||||
|
const auto mediaView = d->createMediaView();
|
||||||
|
_downloadFinishedLifetime.add([=] {
|
||||||
|
[[maybe_unused]] const auto copy = mediaView;
|
||||||
|
});
|
||||||
|
mediaView->checkStickerLarge();
|
||||||
|
mediaView->goodThumbnailWanted();
|
||||||
|
rpl::single(
|
||||||
|
rpl::empty_value()
|
||||||
|
) | rpl::then(
|
||||||
|
_owner->session().downloaderTaskFinished()
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
if (mediaView->loaded()) {
|
||||||
|
_timer.callOnce(kTimeout);
|
||||||
|
_documentChanged.fire_copy(mediaView->owner());
|
||||||
|
_downloadFinishedLifetime.destroy();
|
||||||
|
}
|
||||||
|
}, _downloadFinishedLifetime);
|
||||||
|
}, _resolvingLifetime);
|
||||||
|
} else if (!_resolvingLifetime) {
|
||||||
|
_timer.callOnce(kTimeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DocumentData *StickerProvider::lookupAndRememberSticker(int documentIndex) {
|
||||||
|
const auto &[document, index] = lookupSticker(documentIndex);
|
||||||
|
if (document) {
|
||||||
|
_documentIndex = index;
|
||||||
|
}
|
||||||
|
return document;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<DocumentData*, int> StickerProvider::lookupSticker(
|
||||||
|
int documentIndex) const {
|
||||||
|
const auto size = _shuffledDocuments.size();
|
||||||
|
for (auto i = 0; i < size; i++) {
|
||||||
|
const auto unrestrictedIndex = documentIndex + i;
|
||||||
|
const auto index = (unrestrictedIndex >= size)
|
||||||
|
? (unrestrictedIndex - size)
|
||||||
|
: unrestrictedIndex;
|
||||||
|
const auto id = _shuffledDocuments[index];
|
||||||
|
const auto document = _owner->document(id);
|
||||||
|
if (document->sticker()) {
|
||||||
|
return { document, index };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { nullptr, 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
void AddEmojiBuilderAction(
|
void AddEmojiBuilderAction(
|
||||||
not_null<Window::SessionController*> controller,
|
not_null<Window::SessionController*> controller,
|
||||||
|
@ -34,35 +157,23 @@ void AddEmojiBuilderAction(
|
||||||
rpl::producer<std::vector<DocumentId>> documents,
|
rpl::producer<std::vector<DocumentId>> documents,
|
||||||
Fn<void(UserpicBuilder::Result)> &&done,
|
Fn<void(UserpicBuilder::Result)> &&done,
|
||||||
bool isForum) {
|
bool isForum) {
|
||||||
constexpr auto kTimeout = crl::time(1500);
|
|
||||||
struct State final {
|
|
||||||
State() {
|
|
||||||
colorIndex = base::RandomIndex(std::numeric_limits<int>::max());
|
|
||||||
}
|
|
||||||
void next() {
|
|
||||||
auto nextIndex = documentIndex.current() + 1;
|
|
||||||
if (nextIndex >= shuffledDocuments.size()) {
|
|
||||||
nextIndex = 0;
|
|
||||||
}
|
|
||||||
documentIndex = nextIndex;
|
|
||||||
}
|
|
||||||
void documentShown() {
|
|
||||||
if (!firstDocumentShown) {
|
|
||||||
firstDocumentShown = true;
|
|
||||||
} else {
|
|
||||||
colorIndex = base::RandomIndex(
|
|
||||||
std::numeric_limits<int>::max());
|
|
||||||
}
|
|
||||||
timer.callOnce(kTimeout);
|
|
||||||
}
|
|
||||||
rpl::variable<int> documentIndex;
|
|
||||||
rpl::variable<int> colorIndex;
|
|
||||||
std::vector<DocumentId> shuffledDocuments;
|
|
||||||
bool firstDocumentShown = false;
|
|
||||||
|
|
||||||
base::Timer timer;
|
struct State final {
|
||||||
|
State(not_null<Window::SessionController*> controller)
|
||||||
|
: manager(&controller->session().data())
|
||||||
|
, colorIndex(rpl::single(
|
||||||
|
rpl::empty_value()
|
||||||
|
) | rpl::then(
|
||||||
|
manager.documentChanged() | rpl::skip(1) | rpl::to_empty
|
||||||
|
) | rpl::map([] {
|
||||||
|
return base::RandomIndex(std::numeric_limits<int>::max());
|
||||||
|
})) {
|
||||||
|
}
|
||||||
|
|
||||||
|
StickerProvider manager;
|
||||||
|
rpl::variable<int> colorIndex;
|
||||||
};
|
};
|
||||||
const auto state = menu->lifetime().make_state<State>();
|
const auto state = menu->lifetime().make_state<State>(controller);
|
||||||
auto item = base::make_unique_q<Ui::Menu::Action>(
|
auto item = base::make_unique_q<Ui::Menu::Action>(
|
||||||
menu.get(),
|
menu.get(),
|
||||||
menu->st().menu,
|
menu->st().menu,
|
||||||
|
@ -70,10 +181,7 @@ void AddEmojiBuilderAction(
|
||||||
menu.get(),
|
menu.get(),
|
||||||
tr::lng_attach_profile_emoji(tr::now),
|
tr::lng_attach_profile_emoji(tr::now),
|
||||||
[=, done = std::move(done), docs = rpl::duplicate(documents)] {
|
[=, done = std::move(done), docs = rpl::duplicate(documents)] {
|
||||||
const auto index = state->documentIndex.current();
|
const auto id = state->manager.documentId();
|
||||||
const auto id = index < state->shuffledDocuments.size()
|
|
||||||
? state->shuffledDocuments[index]
|
|
||||||
: 0;
|
|
||||||
UserpicBuilder::ShowLayer(
|
UserpicBuilder::ShowLayer(
|
||||||
controller,
|
controller,
|
||||||
{ id, state->colorIndex.current(), docs, {}, isForum },
|
{ id, state->colorIndex.current(), docs, {}, isForum },
|
||||||
|
@ -81,29 +189,10 @@ void AddEmojiBuilderAction(
|
||||||
}),
|
}),
|
||||||
nullptr,
|
nullptr,
|
||||||
nullptr);
|
nullptr);
|
||||||
state->timer.setCallback([=] { state->next(); });
|
|
||||||
const auto icon = UserpicBuilder::CreateEmojiUserpic(
|
const auto icon = UserpicBuilder::CreateEmojiUserpic(
|
||||||
item.get(),
|
item.get(),
|
||||||
st::restoreUserpicIcon.size,
|
st::restoreUserpicIcon.size,
|
||||||
state->documentIndex.value(
|
state->manager.documentChanged(),
|
||||||
) | rpl::filter([=](int index) {
|
|
||||||
if (index >= state->shuffledDocuments.size()) {
|
|
||||||
state->next();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const auto id = state->shuffledDocuments[index];
|
|
||||||
if (!controller->session().data().document(id)->sticker()) {
|
|
||||||
state->next();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}) | rpl::map([=](int index) {
|
|
||||||
return controller->session().data().customEmojiManager().resolve(
|
|
||||||
state->shuffledDocuments[index]);
|
|
||||||
}) | rpl::flatten_latest() | rpl::map([=](not_null<DocumentData*> d) {
|
|
||||||
state->documentShown();
|
|
||||||
return d;
|
|
||||||
}),
|
|
||||||
state->colorIndex.value(),
|
state->colorIndex.value(),
|
||||||
isForum);
|
isForum);
|
||||||
icon->setAttribute(Qt::WA_TransparentForMouseEvents);
|
icon->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||||
|
@ -115,13 +204,7 @@ void AddEmojiBuilderAction(
|
||||||
rpl::duplicate(
|
rpl::duplicate(
|
||||||
documents
|
documents
|
||||||
) | rpl::start_with_next([=](std::vector<DocumentId> documents) {
|
) | rpl::start_with_next([=](std::vector<DocumentId> documents) {
|
||||||
if (documents.empty()) {
|
state->manager.setDocuments(std::move(documents));
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto rd = std::random_device();
|
|
||||||
ranges::shuffle(documents, std::mt19937(rd()));
|
|
||||||
state->shuffledDocuments = std::move(documents);
|
|
||||||
state->documentIndex.force_assign(0);
|
|
||||||
}, item->lifetime());
|
}, item->lifetime());
|
||||||
|
|
||||||
menu->addAction(std::move(item));
|
menu->addAction(std::move(item));
|
||||||
|
|
|
@ -419,7 +419,8 @@ not_null<Ui::VerticalLayout*> CreateUserpicBuilder(
|
||||||
data.isForum)),
|
data.isForum)),
|
||||||
st::userpicBuilderEmojiPreviewPadding)->entity();
|
st::userpicBuilderEmojiPreviewPadding)->entity();
|
||||||
if (const auto id = data.documentId) {
|
if (const auto id = data.documentId) {
|
||||||
if (const auto document = controller->session().data().document(id)) {
|
const auto document = controller->session().data().document(id);
|
||||||
|
if (document && document->sticker()) {
|
||||||
preview->setDocument(document);
|
preview->setDocument(document);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue