mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-16 06:07:06 +02:00
Support topic icon display in topic profile.
This commit is contained in:
parent
fcc4503791
commit
df5602d203
26 changed files with 317 additions and 119 deletions
|
@ -2003,9 +2003,8 @@ void ApiWrap::applyAffectedMessages(
|
|||
}
|
||||
|
||||
void ApiWrap::saveCurrentDraftToCloud() {
|
||||
Core::App().saveCurrentDraftsToHistories();
|
||||
|
||||
for (const auto &controller : _session->windows()) {
|
||||
controller->materializeLocalDrafts();
|
||||
if (const auto thread = controller->activeChatCurrent().thread()) {
|
||||
const auto history = thread->owningHistory();
|
||||
_session->local().writeDrafts(history);
|
||||
|
@ -2028,10 +2027,8 @@ void ApiWrap::saveDraftsToCloud() {
|
|||
if (!thread) {
|
||||
i = _draftsSaveRequestIds.erase(i);
|
||||
continue;
|
||||
}
|
||||
auto &requestId = i->second;
|
||||
++i;
|
||||
if (requestId) {
|
||||
} else if (i->second) {
|
||||
++i;
|
||||
continue; // sent already
|
||||
}
|
||||
|
||||
|
@ -2055,9 +2052,9 @@ void ApiWrap::saveDraftsToCloud() {
|
|||
}
|
||||
if (cloudDraft->msgId) {
|
||||
flags |= MTPmessages_SaveDraft::Flag::f_reply_to_msg_id;
|
||||
if (cloudDraft->topicRootId) {
|
||||
flags |= MTPmessages_SaveDraft::Flag::f_top_msg_id;
|
||||
}
|
||||
}
|
||||
if (cloudDraft->topicRootId) {
|
||||
flags |= MTPmessages_SaveDraft::Flag::f_top_msg_id;
|
||||
}
|
||||
if (!textWithTags.tags.isEmpty()) {
|
||||
flags |= MTPmessages_SaveDraft::Flag::f_entities;
|
||||
|
@ -2111,6 +2108,7 @@ void ApiWrap::saveDraftsToCloud() {
|
|||
}).send();
|
||||
|
||||
i->second = cloudDraft->saveRequestId;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ namespace ChatHelpers {
|
|||
|
||||
enum class StickerLottieSize : uint8 {
|
||||
MessageHistory,
|
||||
StickerSet,
|
||||
StickerSet, // In Emoji used for forum topic profile cover icons.
|
||||
StickersPanel,
|
||||
StickersFooter,
|
||||
SetsListThumbnail,
|
||||
|
|
|
@ -1144,14 +1144,6 @@ bool Application::hasActiveWindow(not_null<Main::Session*> session) const {
|
|||
return false;
|
||||
}
|
||||
|
||||
void Application::saveCurrentDraftsToHistories() {
|
||||
if (!_primaryWindow) {
|
||||
return;
|
||||
} else if (const auto controller = _primaryWindow->sessionController()) {
|
||||
controller->content()->saveFieldToHistoryLocalDraft();
|
||||
}
|
||||
}
|
||||
|
||||
Window::Controller *Application::primaryWindow() const {
|
||||
return _primaryWindow.get();
|
||||
}
|
||||
|
|
|
@ -152,7 +152,6 @@ public:
|
|||
|
||||
// Windows interface.
|
||||
bool hasActiveWindow(not_null<Main::Session*> session) const;
|
||||
void saveCurrentDraftsToHistories();
|
||||
[[nodiscard]] Window::Controller *primaryWindow() const;
|
||||
[[nodiscard]] Window::Controller *activeWindow() const;
|
||||
[[nodiscard]] Window::Controller *separateWindowForPeer(
|
||||
|
|
|
@ -151,10 +151,11 @@ struct TopicUpdate {
|
|||
UnreadReactions = (1U << 3),
|
||||
Notifications = (1U << 4),
|
||||
Title = (1U << 5),
|
||||
Icon = (1U << 6),
|
||||
CloudDraft = (1U << 7),
|
||||
IconId = (1U << 6),
|
||||
ColorId = (1U << 7),
|
||||
CloudDraft = (1U << 8),
|
||||
|
||||
LastUsedBit = (1U << 7),
|
||||
LastUsedBit = (1U << 8),
|
||||
};
|
||||
using Flags = base::flags<Flag>;
|
||||
friend inline constexpr auto is_flag_type(Flag) { return true; }
|
||||
|
|
|
@ -492,7 +492,7 @@ void ForumTopic::applyIconId(DocumentId iconId) {
|
|||
_defaultIcon = QImage();
|
||||
}
|
||||
updateChatListEntry();
|
||||
session().changes().topicUpdated(this, UpdateFlag::Icon);
|
||||
session().changes().topicUpdated(this, UpdateFlag::IconId);
|
||||
}
|
||||
|
||||
int32 ForumTopic::colorId() const {
|
||||
|
@ -500,7 +500,10 @@ int32 ForumTopic::colorId() const {
|
|||
}
|
||||
|
||||
void ForumTopic::applyColorId(int32 colorId) {
|
||||
_colorId = colorId;
|
||||
if (_colorId != colorId) {
|
||||
_colorId = colorId;
|
||||
session().changes().topicUpdated(this, UpdateFlag::ColorId);
|
||||
}
|
||||
}
|
||||
|
||||
void ForumTopic::applyItemAdded(not_null<HistoryItem*> item) {
|
||||
|
|
|
@ -39,6 +39,22 @@ constexpr auto kUnsubscribeUpdatesDelay = 3 * crl::time(1000);
|
|||
|
||||
using SizeTag = CustomEmojiManager::SizeTag;
|
||||
|
||||
class CallbackListener final : public CustomEmojiManager::Listener {
|
||||
public:
|
||||
explicit CallbackListener(Fn<void(not_null<DocumentData*>)> callback)
|
||||
: _callback(std::move(callback)) {
|
||||
Expects(_callback != nullptr);
|
||||
}
|
||||
|
||||
private:
|
||||
void customEmojiResolveDone(not_null<DocumentData*> document) {
|
||||
_callback(document);
|
||||
}
|
||||
|
||||
Fn<void(not_null<DocumentData*>)> _callback;
|
||||
|
||||
};
|
||||
|
||||
[[nodiscard]] ChatHelpers::StickerLottieSize LottieSizeFromTag(SizeTag tag) {
|
||||
// NB! onlyCustomEmoji dimensions caching uses last ::EmojiInteraction-s.
|
||||
using LottieSize = ChatHelpers::StickerLottieSize;
|
||||
|
@ -546,6 +562,28 @@ void CustomEmojiManager::unregisterListener(not_null<Listener*> listener) {
|
|||
}
|
||||
}
|
||||
|
||||
rpl::producer<not_null<DocumentData*>> CustomEmojiManager::resolve(
|
||||
DocumentId documentId) {
|
||||
return [=](auto consumer) {
|
||||
auto result = rpl::lifetime();
|
||||
const auto put = [=](not_null<DocumentData*> document) {
|
||||
if (!document->sticker()) {
|
||||
return false;
|
||||
}
|
||||
consumer.put_next_copy(document);
|
||||
return true;
|
||||
};
|
||||
if (!put(owner().document(documentId))) {
|
||||
const auto listener = new CallbackListener(put);
|
||||
result.add([=] {
|
||||
unregisterListener(listener);
|
||||
delete listener;
|
||||
});
|
||||
}
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
std::unique_ptr<Ui::CustomEmoji::Loader> CustomEmojiManager::createLoader(
|
||||
not_null<DocumentData*> document,
|
||||
SizeTag tag,
|
||||
|
|
|
@ -65,6 +65,9 @@ public:
|
|||
void resolve(DocumentId documentId, not_null<Listener*> listener);
|
||||
void unregisterListener(not_null<Listener*> listener);
|
||||
|
||||
[[nodiscard]] rpl::producer<not_null<DocumentData*>> resolve(
|
||||
DocumentId documentId);
|
||||
|
||||
[[nodiscard]] std::unique_ptr<Ui::CustomEmoji::Loader> createLoader(
|
||||
not_null<DocumentData*> document,
|
||||
SizeTag tag,
|
||||
|
|
|
@ -35,6 +35,11 @@ largeForumTopicIcon: ForumTopicIcon {
|
|||
font: font(bold 13px);
|
||||
textTop: 3px;
|
||||
}
|
||||
infoForumTopicIcon: ForumTopicIcon {
|
||||
size: 32px;
|
||||
font: font(bold 15px);
|
||||
textTop: 4px;
|
||||
}
|
||||
|
||||
dialogsUnreadFont: font(12px bold);
|
||||
dialogsUnreadHeight: 19px;
|
||||
|
|
|
@ -182,9 +182,9 @@ constexpr auto kSkipRepaintWhileScrollMs = 100;
|
|||
constexpr auto kShowMembersDropdownTimeoutMs = 300;
|
||||
constexpr auto kDisplayEditTimeWarningMs = 300 * 1000;
|
||||
constexpr auto kFullDayInMs = 86400 * 1000;
|
||||
constexpr auto kSaveDraftTimeout = 1000;
|
||||
constexpr auto kSaveDraftAnywayTimeout = 5000;
|
||||
constexpr auto kSaveCloudDraftIdleTimeout = 14000;
|
||||
constexpr auto kSaveDraftTimeout = crl::time(1000);
|
||||
constexpr auto kSaveDraftAnywayTimeout = 5 * crl::time(1000);
|
||||
constexpr auto kSaveCloudDraftIdleTimeout = 14 * crl::time(1000);
|
||||
constexpr auto kRefreshSlowmodeLabelTimeout = crl::time(200);
|
||||
constexpr auto kCommonModifiers = 0
|
||||
| Qt::ShiftModifier
|
||||
|
@ -865,6 +865,11 @@ HistoryWidget::HistoryWidget(
|
|||
}, lifetime());
|
||||
}
|
||||
|
||||
controller->materializeLocalDraftsRequests(
|
||||
) | rpl::start_with_next([=] {
|
||||
saveFieldToHistoryLocalDraft();
|
||||
}, lifetime());
|
||||
|
||||
setupScheduledToggle();
|
||||
setupSendAsToggle();
|
||||
orderWidgets();
|
||||
|
|
|
@ -227,7 +227,6 @@ public:
|
|||
void clearSupportPreloadRequest();
|
||||
void clearDelayedShowAtRequest();
|
||||
void clearDelayedShowAt();
|
||||
void saveFieldToHistoryLocalDraft();
|
||||
|
||||
void toggleChooseChatTheme(not_null<PeerData*> peer);
|
||||
[[nodiscard]] Ui::ChatTheme *customChatTheme() const;
|
||||
|
@ -355,6 +354,7 @@ private:
|
|||
void checkFieldAutocomplete();
|
||||
void showMembersDropdown();
|
||||
void windowIsVisibleChanged();
|
||||
void saveFieldToHistoryLocalDraft();
|
||||
|
||||
// Checks if we are too close to the top or to the bottom
|
||||
// in the scroll area and preloads history if needed.
|
||||
|
|
|
@ -68,6 +68,7 @@ namespace {
|
|||
|
||||
constexpr auto kSaveDraftTimeout = crl::time(1000);
|
||||
constexpr auto kSaveDraftAnywayTimeout = 5 * crl::time(1000);
|
||||
constexpr auto kSaveCloudDraftIdleTimeout = 14 * crl::time(1000);
|
||||
constexpr auto kMouseEvents = {
|
||||
QEvent::MouseMove,
|
||||
QEvent::MouseButtonPress,
|
||||
|
@ -870,7 +871,8 @@ ComposeControls::ComposeControls(
|
|||
st::historySendSize.height()))
|
||||
, _sendMenuType(sendMenuType)
|
||||
, _unavailableEmojiPasted(unavailableEmojiPasted)
|
||||
, _saveDraftTimer([=] { saveDraft(); }) {
|
||||
, _saveDraftTimer([=] { saveDraft(); })
|
||||
, _saveCloudDraftTimer([=] { saveCloudDraft(); }) {
|
||||
init();
|
||||
}
|
||||
|
||||
|
@ -1341,6 +1343,11 @@ void ComposeControls::init() {
|
|||
}, _wrap->lifetime());
|
||||
}
|
||||
|
||||
_window->materializeLocalDraftsRequests(
|
||||
) | rpl::start_with_next([=] {
|
||||
saveFieldToHistoryLocalDraft();
|
||||
}, _wrap->lifetime());
|
||||
|
||||
orderControls();
|
||||
}
|
||||
|
||||
|
@ -1660,6 +1667,7 @@ void ComposeControls::fieldChanged() {
|
|||
}
|
||||
});
|
||||
|
||||
_saveCloudDraftTimer.cancel();
|
||||
if (!(_textUpdateEvents & TextUpdateEvent::SaveDraft)) {
|
||||
return;
|
||||
}
|
||||
|
@ -1709,6 +1717,10 @@ void ComposeControls::saveDraft(bool delayed) {
|
|||
writeDrafts();
|
||||
}
|
||||
|
||||
void ComposeControls::saveCloudDraft() {
|
||||
session().api().saveCurrentDraftToCloud();
|
||||
}
|
||||
|
||||
void ComposeControls::writeDraftTexts() {
|
||||
Expects(_history != nullptr);
|
||||
|
||||
|
@ -1773,9 +1785,15 @@ void ComposeControls::writeDrafts() {
|
|||
}
|
||||
_saveDraftText = false;
|
||||
|
||||
//if (!isEditingMessage() && !_inlineBot) {
|
||||
// _saveCloudDraftTimer.callOnce(kSaveCloudDraftIdleTimeout);
|
||||
//}
|
||||
if (!isEditingMessage() && !_inlineBot) {
|
||||
_saveCloudDraftTimer.callOnce(kSaveCloudDraftIdleTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
void ComposeControls::applyCloudDraft() {
|
||||
if (!isEditingMessage()) {
|
||||
applyDraft(Ui::InputField::HistoryAction::NewEntry);
|
||||
}
|
||||
}
|
||||
|
||||
void ComposeControls::applyDraft(FieldHistoryAction fieldHistoryAction) {
|
||||
|
|
|
@ -179,6 +179,7 @@ public:
|
|||
[[nodiscard]] bool isLockPresent() const;
|
||||
[[nodiscard]] bool isRecording() const;
|
||||
|
||||
void applyCloudDraft();
|
||||
void applyDraft(
|
||||
FieldHistoryAction fieldHistoryAction = FieldHistoryAction::Clear);
|
||||
|
||||
|
@ -265,6 +266,7 @@ private:
|
|||
[[nodiscard]] Data::DraftKey draftKeyCurrent() const;
|
||||
void saveDraft(bool delayed = false);
|
||||
void saveDraftDelayed();
|
||||
void saveCloudDraft();
|
||||
|
||||
void writeDrafts();
|
||||
void writeDraftTexts();
|
||||
|
@ -334,6 +336,7 @@ private:
|
|||
crl::time _saveDraftStart = 0;
|
||||
bool _saveDraftText = false;
|
||||
base::Timer _saveDraftTimer;
|
||||
base::Timer _saveCloudDraftTimer;
|
||||
|
||||
UserData *_inlineBot = nullptr;
|
||||
QString _inlineBotUsername;
|
||||
|
|
|
@ -44,22 +44,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
namespace HistoryView {
|
||||
namespace {
|
||||
|
||||
class Listener final : public Data::CustomEmojiManager::Listener {
|
||||
public:
|
||||
explicit Listener(Fn<void(not_null<DocumentData*>)> check)
|
||||
: _check(std::move(check)) {
|
||||
}
|
||||
|
||||
void customEmojiResolveDone(
|
||||
not_null<DocumentData*> document) override {
|
||||
_check(document);
|
||||
}
|
||||
|
||||
private:
|
||||
Fn<void(not_null<DocumentData*>)> _check;
|
||||
|
||||
};
|
||||
|
||||
[[nodiscard]] bool BarCurrentlyHidden(not_null<PeerData*> peer) {
|
||||
const auto settings = peer->settings();
|
||||
if (!settings) {
|
||||
|
@ -83,43 +67,29 @@ private:
|
|||
[[nodiscard]] rpl::producer<TextWithEntities> ResolveIsCustom(
|
||||
not_null<Data::Session*> owner,
|
||||
DocumentId id) {
|
||||
return [=](auto consumer) {
|
||||
const auto document = owner->document(id);
|
||||
const auto manager = &owner->customEmojiManager();
|
||||
const auto check = [=](not_null<DocumentData*> document) {
|
||||
if (const auto sticker = document->sticker()) {
|
||||
const auto setId = manager->coloredSetId();
|
||||
const auto text = (setId == sticker->set.id)
|
||||
? QString()
|
||||
: sticker->alt;
|
||||
if (text.isEmpty()) {
|
||||
consumer.put_next({});
|
||||
} else {
|
||||
consumer.put_next({
|
||||
.text = text,
|
||||
.entities = { EntityInText(
|
||||
EntityType::CustomEmoji,
|
||||
0,
|
||||
text.size(),
|
||||
Data::SerializeCustomEmojiId(document)) },
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
auto lifetime = rpl::lifetime();
|
||||
if (!check(document)) {
|
||||
const auto manager = &owner->customEmojiManager();
|
||||
const auto listener = new Listener(check);
|
||||
lifetime.add([=] {
|
||||
manager->unregisterListener(listener);
|
||||
delete listener;
|
||||
});
|
||||
manager->resolve(id, listener);
|
||||
return owner->customEmojiManager().resolve(
|
||||
id
|
||||
) | rpl::map([=](not_null<DocumentData*> document) {
|
||||
const auto sticker = document->sticker();
|
||||
Assert(sticker != nullptr);
|
||||
|
||||
const auto &manager = document->owner().customEmojiManager();
|
||||
const auto setId = manager.coloredSetId();
|
||||
const auto text = (setId == sticker->set.id)
|
||||
? QString()
|
||||
: sticker->alt;
|
||||
if (text.isEmpty()) {
|
||||
return TextWithEntities();
|
||||
}
|
||||
return lifetime;
|
||||
};
|
||||
return TextWithEntities{
|
||||
.text = text,
|
||||
.entities = { EntityInText(
|
||||
EntityType::CustomEmoji,
|
||||
0,
|
||||
text.size(),
|
||||
Data::SerializeCustomEmojiId(document)) },
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
[[nodiscard]] rpl::producer<TextWithEntities> PeerCustomStatus(
|
||||
|
|
|
@ -359,6 +359,7 @@ RepliesWidget::~RepliesWidget() {
|
|||
_history->owner().sendActionManager().repliesPainterRemoved(
|
||||
_history,
|
||||
_rootId);
|
||||
session().api().saveCurrentDraftToCloud();
|
||||
controller()->sendingAnimation().clear();
|
||||
}
|
||||
|
||||
|
@ -461,13 +462,19 @@ void RepliesWidget::setupTopicViewer() {
|
|||
void RepliesWidget::subscribeToTopic() {
|
||||
Expects(_topic != nullptr);
|
||||
|
||||
using TopicUpdateFlag = Data::TopicUpdate::Flag;
|
||||
using Flag = Data::TopicUpdate::Flag;
|
||||
session().changes().topicUpdates(
|
||||
_topic,
|
||||
(TopicUpdateFlag::UnreadMentions
|
||||
| TopicUpdateFlag::UnreadReactions)
|
||||
(Flag::UnreadMentions
|
||||
| Flag::UnreadReactions
|
||||
| Flag::CloudDraft)
|
||||
) | rpl::start_with_next([=](const Data::TopicUpdate &update) {
|
||||
_cornerButtons.updateUnreadThingsVisibility();
|
||||
if (update.flags & (Flag::UnreadMentions | Flag::UnreadReactions)) {
|
||||
_cornerButtons.updateUnreadThingsVisibility();
|
||||
}
|
||||
if (update.flags & Flag::CloudDraft) {
|
||||
_composeControls->applyCloudDraft();
|
||||
}
|
||||
}, _topicLifetime);
|
||||
|
||||
_topic->destroyed(
|
||||
|
|
|
@ -7,6 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#include "history/view/media/history_view_sticker_player.h"
|
||||
|
||||
#include "core/file_location.h"
|
||||
|
||||
namespace HistoryView {
|
||||
namespace {
|
||||
|
||||
|
@ -114,4 +116,46 @@ bool WebmPlayer::markFrameShown() {
|
|||
return _reader->moveToNextFrame();
|
||||
}
|
||||
|
||||
StaticStickerPlayer::StaticStickerPlayer(
|
||||
const Core::FileLocation &location,
|
||||
const QByteArray &data,
|
||||
QSize size)
|
||||
: _frame(Images::Read({
|
||||
.path = location.name(),
|
||||
.content = data,
|
||||
.forceOpaque = true,
|
||||
}).image) {
|
||||
if (!_frame.isNull()) {
|
||||
size = _frame.size().scaled(size, Qt::KeepAspectRatio);
|
||||
const auto ratio = style::DevicePixelRatio();
|
||||
_frame = Images::Prepare(std::move(_frame), size * ratio, {});
|
||||
_frame.setDevicePixelRatio(ratio);
|
||||
}
|
||||
}
|
||||
|
||||
void StaticStickerPlayer::setRepaintCallback(Fn<void()> callback) {
|
||||
callback();
|
||||
}
|
||||
|
||||
bool StaticStickerPlayer::ready() {
|
||||
return true;
|
||||
}
|
||||
|
||||
int StaticStickerPlayer::framesCount() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
StaticStickerPlayer::FrameInfo StaticStickerPlayer::frame(
|
||||
QSize size,
|
||||
QColor colored,
|
||||
bool mirrorHorizontal,
|
||||
crl::time now,
|
||||
bool paused) {
|
||||
return { _frame };
|
||||
}
|
||||
|
||||
bool StaticStickerPlayer::markFrameShown() {
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace HistoryView
|
||||
|
|
|
@ -66,4 +66,27 @@ private:
|
|||
|
||||
};
|
||||
|
||||
class StaticStickerPlayer final : public StickerPlayer {
|
||||
public:
|
||||
StaticStickerPlayer(
|
||||
const Core::FileLocation &location,
|
||||
const QByteArray &data,
|
||||
QSize size);
|
||||
|
||||
void setRepaintCallback(Fn<void()> callback) override;
|
||||
bool ready() override;
|
||||
int framesCount() override;
|
||||
FrameInfo frame(
|
||||
QSize size,
|
||||
QColor colored,
|
||||
bool mirrorHorizontal,
|
||||
crl::time now,
|
||||
bool paused) override;
|
||||
bool markFrameShown() override;
|
||||
|
||||
private:
|
||||
QImage _frame;
|
||||
|
||||
};
|
||||
|
||||
} // namespace HistoryView
|
||||
|
|
|
@ -315,6 +315,11 @@ infoProfileMegagroupCover: InfoProfileCover(infoProfileCover) {
|
|||
}
|
||||
infoTopicCover: InfoProfileCover(infoProfileMegagroupCover) {
|
||||
height: 77px;
|
||||
photo: UserpicButton(defaultUserpicButton) {
|
||||
size: size(36px, 36px);
|
||||
}
|
||||
photoLeft: 22px;
|
||||
photoTop: 18px;
|
||||
nameLeft: 79px;
|
||||
nameTop: 14px;
|
||||
statusLeft: 79px;
|
||||
|
|
|
@ -11,6 +11,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_channel.h"
|
||||
#include "data/data_chat.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_document_media.h"
|
||||
#include "data/data_changes.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_forum_topic.h"
|
||||
|
@ -19,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "info/profile/info_profile_badge.h"
|
||||
#include "info/profile/info_profile_emoji_status_panel.h"
|
||||
#include "info/info_controller.h"
|
||||
#include "history/view/media/history_view_sticker_player.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
|
@ -27,10 +30,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "window/window_session_controller.h"
|
||||
#include "main/main_session.h"
|
||||
#include "settings/settings_premium.h"
|
||||
#include "chat_helpers/stickers_lottie.h"
|
||||
#include "apiwrap.h"
|
||||
#include "api/api_peer_photo.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_info.h"
|
||||
#include "styles/style_dialogs.h"
|
||||
|
||||
namespace Info::Profile {
|
||||
namespace {
|
||||
|
@ -185,32 +190,90 @@ Cover::Cover(
|
|||
}
|
||||
}
|
||||
|
||||
void Cover::setupIcon(not_null<Data::ForumTopic*> topic) {
|
||||
const auto tag = Data::CustomEmojiManager::SizeTag::Large;
|
||||
void Cover::setupIconPlayer(not_null<Data::ForumTopic*> topic) {
|
||||
IconIdValue(
|
||||
topic
|
||||
) | rpl::start_with_next([=](DocumentId id) {
|
||||
_icon = id
|
||||
? topic->owner().customEmojiManager().create(
|
||||
id,
|
||||
[=] { _iconView->update(); },
|
||||
tag)
|
||||
: nullptr;
|
||||
) | rpl::map([=](DocumentId id) {
|
||||
return topic->owner().customEmojiManager().resolve(id);
|
||||
}) | rpl::flatten_latest(
|
||||
) | rpl::map([=](not_null<DocumentData*> document) {
|
||||
const auto media = document->createMediaView();
|
||||
media->checkStickerLarge();
|
||||
media->goodThumbnailWanted();
|
||||
|
||||
return rpl::single() | rpl::then(
|
||||
document->owner().session().downloaderTaskFinished()
|
||||
) | rpl::filter([=] {
|
||||
return media->loaded();
|
||||
}) | rpl::take(1) | rpl::map([=] {
|
||||
auto result = std::shared_ptr<StickerPlayer>();
|
||||
const auto sticker = document->sticker();
|
||||
if (sticker->isLottie()) {
|
||||
result = std::make_shared<HistoryView::LottiePlayer>(
|
||||
ChatHelpers::LottiePlayerFromDocument(
|
||||
media.get(),
|
||||
ChatHelpers::StickerLottieSize::StickerSet,
|
||||
_st.photo.size,
|
||||
Lottie::Quality::High));
|
||||
} else if (sticker->isWebm()) {
|
||||
result = std::make_shared<HistoryView::WebmPlayer>(
|
||||
media->owner()->location(),
|
||||
media->bytes(),
|
||||
_st.photo.size);
|
||||
} else {
|
||||
result = std::make_shared<HistoryView::StaticStickerPlayer>(
|
||||
media->owner()->location(),
|
||||
media->bytes(),
|
||||
_st.photo.size);
|
||||
}
|
||||
result->setRepaintCallback([=] { _iconView->update(); });
|
||||
return result;
|
||||
});
|
||||
}) | rpl::flatten_latest(
|
||||
) | rpl::start_with_next([=](std::shared_ptr<StickerPlayer> player) {
|
||||
_iconPlayer = std::move(player);
|
||||
}, lifetime());
|
||||
const auto size = Data::FrameSizeFromTag(tag);
|
||||
_iconView->resize(size, size);
|
||||
}
|
||||
|
||||
void Cover::setupIconImage(not_null<Data::ForumTopic*> topic) {
|
||||
rpl::combine(
|
||||
TitleValue(topic),
|
||||
ColorIdValue(topic)
|
||||
) | rpl::map([=](const QString &title, int32 colorId) {
|
||||
using namespace Data;
|
||||
return ForumTopicIconFrame(colorId, title, st::infoForumTopicIcon);
|
||||
}) | rpl::start_with_next([=](QImage &&image) {
|
||||
_iconImage = std::move(image);
|
||||
_iconView->update();
|
||||
}, lifetime());
|
||||
}
|
||||
|
||||
void Cover::setupIcon(not_null<Data::ForumTopic*> topic) {
|
||||
setupIconPlayer(topic);
|
||||
setupIconImage(topic);
|
||||
|
||||
_iconView->resize(_st.photo.size);
|
||||
_iconView->paintRequest(
|
||||
) | rpl::start_with_next([=] {
|
||||
auto p = QPainter(_iconView.data());
|
||||
if (_icon) {
|
||||
_icon->paint(p, {
|
||||
.preview = st::windowBgOver->c,
|
||||
.now = crl::now(),
|
||||
.paused = _controller->isGifPausedAtLeastFor(
|
||||
Window::GifPauseReason::Layer),
|
||||
});
|
||||
} else {
|
||||
|
||||
const auto paint = [&](const QImage &image) {
|
||||
const auto size = image.size() / image.devicePixelRatio();
|
||||
p.drawImage(
|
||||
(_st.photo.size.width() - size.width()) / 2,
|
||||
(_st.photo.size.height() - size.height()) / 2,
|
||||
image);
|
||||
};
|
||||
if (_iconPlayer && _iconPlayer->ready()) {
|
||||
paint(_iconPlayer->frame(
|
||||
_st.photo.size,
|
||||
QColor(0, 0, 0, 0),
|
||||
false,
|
||||
crl::now(),
|
||||
_controller->isGifPausedAtLeastFor(
|
||||
Window::GifPauseReason::Layer)).image);
|
||||
_iconPlayer->markFrameShown();
|
||||
} else if (!topic->iconId() && !_iconImage.isNull()) {
|
||||
paint(_iconImage);
|
||||
}
|
||||
}, _iconView->lifetime());
|
||||
}
|
||||
|
|
|
@ -21,9 +21,9 @@ template <typename Widget>
|
|||
class SlideWrap;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Ui::Text {
|
||||
struct CustomEmojiColored;
|
||||
} // namespace Ui::Text
|
||||
namespace HistoryView {
|
||||
class StickerPlayer;
|
||||
} // namespace HistoryView
|
||||
|
||||
namespace Data {
|
||||
class ForumTopic;
|
||||
|
@ -67,6 +67,8 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
using StickerPlayer = HistoryView::StickerPlayer;
|
||||
|
||||
Cover(
|
||||
QWidget *parent,
|
||||
not_null<PeerData*> peer,
|
||||
|
@ -75,6 +77,8 @@ private:
|
|||
rpl::producer<QString> title);
|
||||
|
||||
void setupIcon(not_null<Data::ForumTopic*> topic);
|
||||
void setupIconPlayer(not_null<Data::ForumTopic*> topic);
|
||||
void setupIconImage(not_null<Data::ForumTopic*> topic);
|
||||
void setupChildGeometry();
|
||||
void initViewers(rpl::producer<QString> title);
|
||||
void refreshStatusText();
|
||||
|
@ -92,7 +96,8 @@ private:
|
|||
|
||||
object_ptr<Ui::UserpicButton> _userpic;
|
||||
object_ptr<Ui::RpWidget> _iconView;
|
||||
std::unique_ptr<Ui::Text::CustomEmoji> _icon;
|
||||
std::shared_ptr<StickerPlayer> _iconPlayer;
|
||||
QImage _iconImage;
|
||||
object_ptr<Ui::FlatLabel> _name = { nullptr };
|
||||
object_ptr<Ui::FlatLabel> _status = { nullptr };
|
||||
//object_ptr<CoverDropArea> _dropArea = { nullptr };
|
||||
|
|
|
@ -104,10 +104,17 @@ rpl::producer<QString> TitleValue(not_null<Data::ForumTopic*> topic) {
|
|||
rpl::producer<DocumentId> IconIdValue(not_null<Data::ForumTopic*> topic) {
|
||||
return topic->session().changes().topicFlagsValue(
|
||||
topic,
|
||||
Data::TopicUpdate::Flag::Icon
|
||||
Data::TopicUpdate::Flag::IconId
|
||||
) | rpl::map([=] { return topic->iconId(); });
|
||||
}
|
||||
|
||||
rpl::producer<int32> ColorIdValue(not_null<Data::ForumTopic*> topic) {
|
||||
return topic->session().changes().topicFlagsValue(
|
||||
topic,
|
||||
Data::TopicUpdate::Flag::ColorId
|
||||
) | rpl::map([=] { return topic->colorId(); });
|
||||
}
|
||||
|
||||
rpl::producer<TextWithEntities> PhoneValue(not_null<UserData*> user) {
|
||||
return rpl::merge(
|
||||
Countries::Instance().updated(),
|
||||
|
|
|
@ -49,6 +49,8 @@ rpl::producer<not_null<PeerData*>> MigratedOrMeValue(
|
|||
not_null<Data::ForumTopic*> topic);
|
||||
[[nodiscard]] rpl::producer<DocumentId> IconIdValue(
|
||||
not_null<Data::ForumTopic*> topic);
|
||||
[[nodiscard]] rpl::producer<int32> ColorIdValue(
|
||||
not_null<Data::ForumTopic*> topic);
|
||||
[[nodiscard]] rpl::producer<TextWithEntities> PhoneValue(
|
||||
not_null<UserData*> user);
|
||||
[[nodiscard]] rpl::producer<TextWithEntities> PhoneOrHiddenValue(
|
||||
|
|
|
@ -2727,10 +2727,6 @@ bool MainWidget::doWeMarkAsRead() const {
|
|||
return isActive() && !_mainSection;
|
||||
}
|
||||
|
||||
void MainWidget::saveFieldToHistoryLocalDraft() {
|
||||
_history->saveFieldToHistoryLocalDraft();
|
||||
}
|
||||
|
||||
bool MainWidget::isOneColumn() const {
|
||||
return _controller->adaptive().isOneColumn();
|
||||
}
|
||||
|
|
|
@ -169,8 +169,6 @@ public:
|
|||
bool isActive() const;
|
||||
[[nodiscard]] bool doWeMarkAsRead() const;
|
||||
|
||||
void saveFieldToHistoryLocalDraft();
|
||||
|
||||
void showForwardLayer(Data::ForwardDraft &&draft);
|
||||
void showSendPathsLayer();
|
||||
void shareUrlLayer(const QString &url, const QString &text);
|
||||
|
|
|
@ -1119,6 +1119,14 @@ void SessionController::floatPlayerAreaUpdated() {
|
|||
}
|
||||
}
|
||||
|
||||
void SessionController::materializeLocalDrafts() {
|
||||
_materializeLocalDraftsRequests.fire({});
|
||||
}
|
||||
|
||||
rpl::producer<> SessionController::materializeLocalDraftsRequests() const {
|
||||
return _materializeLocalDraftsRequests.events();
|
||||
}
|
||||
|
||||
int SessionController::dialogsSmallColumnWidth() const {
|
||||
return st::defaultDialogRow.padding.left()
|
||||
+ st::defaultDialogRow.photoSize
|
||||
|
|
|
@ -378,6 +378,9 @@ public:
|
|||
bool isGifPausedAtLeastFor(GifPauseReason reason) const;
|
||||
void floatPlayerAreaUpdated();
|
||||
|
||||
void materializeLocalDrafts();
|
||||
[[nodiscard]] rpl::producer<> materializeLocalDraftsRequests() const;
|
||||
|
||||
struct ColumnLayout {
|
||||
int bodyWidth = 0;
|
||||
int dialogsWidth = 0;
|
||||
|
@ -629,6 +632,8 @@ private:
|
|||
|
||||
QString _premiumRef;
|
||||
|
||||
rpl::event_stream<> _materializeLocalDraftsRequests;
|
||||
|
||||
rpl::lifetime _lifetime;
|
||||
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue