diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 5a3711ca4..5a7af54b8 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -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; } } diff --git a/Telegram/SourceFiles/chat_helpers/stickers_lottie.h b/Telegram/SourceFiles/chat_helpers/stickers_lottie.h index 37d499842..d1581374f 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_lottie.h +++ b/Telegram/SourceFiles/chat_helpers/stickers_lottie.h @@ -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, diff --git a/Telegram/SourceFiles/core/application.cpp b/Telegram/SourceFiles/core/application.cpp index 4d9d29216..7b97c31e5 100644 --- a/Telegram/SourceFiles/core/application.cpp +++ b/Telegram/SourceFiles/core/application.cpp @@ -1144,14 +1144,6 @@ bool Application::hasActiveWindow(not_null 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(); } diff --git a/Telegram/SourceFiles/core/application.h b/Telegram/SourceFiles/core/application.h index d05906372..b984ccfa4 100644 --- a/Telegram/SourceFiles/core/application.h +++ b/Telegram/SourceFiles/core/application.h @@ -152,7 +152,6 @@ public: // Windows interface. bool hasActiveWindow(not_null session) const; - void saveCurrentDraftsToHistories(); [[nodiscard]] Window::Controller *primaryWindow() const; [[nodiscard]] Window::Controller *activeWindow() const; [[nodiscard]] Window::Controller *separateWindowForPeer( diff --git a/Telegram/SourceFiles/data/data_changes.h b/Telegram/SourceFiles/data/data_changes.h index 4c8b71a30..de90e9bf8 100644 --- a/Telegram/SourceFiles/data/data_changes.h +++ b/Telegram/SourceFiles/data/data_changes.h @@ -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; friend inline constexpr auto is_flag_type(Flag) { return true; } diff --git a/Telegram/SourceFiles/data/data_forum_topic.cpp b/Telegram/SourceFiles/data/data_forum_topic.cpp index 4ef0754dc..d1e7ffc8b 100644 --- a/Telegram/SourceFiles/data/data_forum_topic.cpp +++ b/Telegram/SourceFiles/data/data_forum_topic.cpp @@ -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 item) { diff --git a/Telegram/SourceFiles/data/stickers/data_custom_emoji.cpp b/Telegram/SourceFiles/data/stickers/data_custom_emoji.cpp index 4dc8fbb6f..b90c29028 100644 --- a/Telegram/SourceFiles/data/stickers/data_custom_emoji.cpp +++ b/Telegram/SourceFiles/data/stickers/data_custom_emoji.cpp @@ -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)> callback) + : _callback(std::move(callback)) { + Expects(_callback != nullptr); + } + +private: + void customEmojiResolveDone(not_null document) { + _callback(document); + } + + Fn)> _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) { } } +rpl::producer> CustomEmojiManager::resolve( + DocumentId documentId) { + return [=](auto consumer) { + auto result = rpl::lifetime(); + const auto put = [=](not_null 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 CustomEmojiManager::createLoader( not_null document, SizeTag tag, diff --git a/Telegram/SourceFiles/data/stickers/data_custom_emoji.h b/Telegram/SourceFiles/data/stickers/data_custom_emoji.h index 5cd8de902..53df8fb25 100644 --- a/Telegram/SourceFiles/data/stickers/data_custom_emoji.h +++ b/Telegram/SourceFiles/data/stickers/data_custom_emoji.h @@ -65,6 +65,9 @@ public: void resolve(DocumentId documentId, not_null listener); void unregisterListener(not_null listener); + [[nodiscard]] rpl::producer> resolve( + DocumentId documentId); + [[nodiscard]] std::unique_ptr createLoader( not_null document, SizeTag tag, diff --git a/Telegram/SourceFiles/dialogs/dialogs.style b/Telegram/SourceFiles/dialogs/dialogs.style index 009c36892..df0c4dbf1 100644 --- a/Telegram/SourceFiles/dialogs/dialogs.style +++ b/Telegram/SourceFiles/dialogs/dialogs.style @@ -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; diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 4c43c5903..3cb580dc7 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -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(); diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h index 625bb1f0d..f76b6e42f 100644 --- a/Telegram/SourceFiles/history/history_widget.h +++ b/Telegram/SourceFiles/history/history_widget.h @@ -227,7 +227,6 @@ public: void clearSupportPreloadRequest(); void clearDelayedShowAtRequest(); void clearDelayedShowAt(); - void saveFieldToHistoryLocalDraft(); void toggleChooseChatTheme(not_null 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. diff --git a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp index b0ac36507..ca3ed55a9 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp @@ -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) { diff --git a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h index aea7c0d0d..a37652048 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h @@ -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; diff --git a/Telegram/SourceFiles/history/view/history_view_contact_status.cpp b/Telegram/SourceFiles/history/view/history_view_contact_status.cpp index ddb3b4ae3..f10c4daf4 100644 --- a/Telegram/SourceFiles/history/view/history_view_contact_status.cpp +++ b/Telegram/SourceFiles/history/view/history_view_contact_status.cpp @@ -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)> check) - : _check(std::move(check)) { - } - - void customEmojiResolveDone( - not_null document) override { - _check(document); - } - -private: - Fn)> _check; - -}; - [[nodiscard]] bool BarCurrentlyHidden(not_null peer) { const auto settings = peer->settings(); if (!settings) { @@ -83,43 +67,29 @@ private: [[nodiscard]] rpl::producer ResolveIsCustom( not_null owner, DocumentId id) { - return [=](auto consumer) { - const auto document = owner->document(id); - const auto manager = &owner->customEmojiManager(); - const auto check = [=](not_null 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 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 PeerCustomStatus( diff --git a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp index 7c7e97f27..0eb3d0164 100644 --- a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp @@ -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( diff --git a/Telegram/SourceFiles/history/view/media/history_view_sticker_player.cpp b/Telegram/SourceFiles/history/view/media/history_view_sticker_player.cpp index f82565ec4..c79950c87 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_sticker_player.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_sticker_player.cpp @@ -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 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 diff --git a/Telegram/SourceFiles/history/view/media/history_view_sticker_player.h b/Telegram/SourceFiles/history/view/media/history_view_sticker_player.h index 176a84f35..9d5ef7ce1 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_sticker_player.h +++ b/Telegram/SourceFiles/history/view/media/history_view_sticker_player.h @@ -66,4 +66,27 @@ private: }; +class StaticStickerPlayer final : public StickerPlayer { +public: + StaticStickerPlayer( + const Core::FileLocation &location, + const QByteArray &data, + QSize size); + + void setRepaintCallback(Fn 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 diff --git a/Telegram/SourceFiles/info/info.style b/Telegram/SourceFiles/info/info.style index 365b6b26c..fdc047c75 100644 --- a/Telegram/SourceFiles/info/info.style +++ b/Telegram/SourceFiles/info/info.style @@ -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; diff --git a/Telegram/SourceFiles/info/profile/info_profile_cover.cpp b/Telegram/SourceFiles/info/profile/info_profile_cover.cpp index 01b0d9d5a..24279dd19 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_cover.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_cover.cpp @@ -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 topic) { - const auto tag = Data::CustomEmojiManager::SizeTag::Large; +void Cover::setupIconPlayer(not_null 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 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(); + const auto sticker = document->sticker(); + if (sticker->isLottie()) { + result = std::make_shared( + ChatHelpers::LottiePlayerFromDocument( + media.get(), + ChatHelpers::StickerLottieSize::StickerSet, + _st.photo.size, + Lottie::Quality::High)); + } else if (sticker->isWebm()) { + result = std::make_shared( + media->owner()->location(), + media->bytes(), + _st.photo.size); + } else { + result = std::make_shared( + media->owner()->location(), + media->bytes(), + _st.photo.size); + } + result->setRepaintCallback([=] { _iconView->update(); }); + return result; + }); + }) | rpl::flatten_latest( + ) | rpl::start_with_next([=](std::shared_ptr player) { + _iconPlayer = std::move(player); }, lifetime()); - const auto size = Data::FrameSizeFromTag(tag); - _iconView->resize(size, size); +} + +void Cover::setupIconImage(not_null 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 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()); } diff --git a/Telegram/SourceFiles/info/profile/info_profile_cover.h b/Telegram/SourceFiles/info/profile/info_profile_cover.h index 71080fa1d..739744231 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_cover.h +++ b/Telegram/SourceFiles/info/profile/info_profile_cover.h @@ -21,9 +21,9 @@ template 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 peer, @@ -75,6 +77,8 @@ private: rpl::producer title); void setupIcon(not_null topic); + void setupIconPlayer(not_null topic); + void setupIconImage(not_null topic); void setupChildGeometry(); void initViewers(rpl::producer title); void refreshStatusText(); @@ -92,7 +96,8 @@ private: object_ptr _userpic; object_ptr _iconView; - std::unique_ptr _icon; + std::shared_ptr _iconPlayer; + QImage _iconImage; object_ptr _name = { nullptr }; object_ptr _status = { nullptr }; //object_ptr _dropArea = { nullptr }; diff --git a/Telegram/SourceFiles/info/profile/info_profile_values.cpp b/Telegram/SourceFiles/info/profile/info_profile_values.cpp index 19451cf03..66b76bfbb 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_values.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_values.cpp @@ -104,10 +104,17 @@ rpl::producer TitleValue(not_null topic) { rpl::producer IconIdValue(not_null topic) { return topic->session().changes().topicFlagsValue( topic, - Data::TopicUpdate::Flag::Icon + Data::TopicUpdate::Flag::IconId ) | rpl::map([=] { return topic->iconId(); }); } +rpl::producer ColorIdValue(not_null topic) { + return topic->session().changes().topicFlagsValue( + topic, + Data::TopicUpdate::Flag::ColorId + ) | rpl::map([=] { return topic->colorId(); }); +} + rpl::producer PhoneValue(not_null user) { return rpl::merge( Countries::Instance().updated(), diff --git a/Telegram/SourceFiles/info/profile/info_profile_values.h b/Telegram/SourceFiles/info/profile/info_profile_values.h index 9291c99c2..3b4cc19e3 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_values.h +++ b/Telegram/SourceFiles/info/profile/info_profile_values.h @@ -49,6 +49,8 @@ rpl::producer> MigratedOrMeValue( not_null topic); [[nodiscard]] rpl::producer IconIdValue( not_null topic); +[[nodiscard]] rpl::producer ColorIdValue( + not_null topic); [[nodiscard]] rpl::producer PhoneValue( not_null user); [[nodiscard]] rpl::producer PhoneOrHiddenValue( diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index abbcf0201..4b2f23f37 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -2727,10 +2727,6 @@ bool MainWidget::doWeMarkAsRead() const { return isActive() && !_mainSection; } -void MainWidget::saveFieldToHistoryLocalDraft() { - _history->saveFieldToHistoryLocalDraft(); -} - bool MainWidget::isOneColumn() const { return _controller->adaptive().isOneColumn(); } diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index 88a24119d..94cb3ed77 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -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); diff --git a/Telegram/SourceFiles/window/window_session_controller.cpp b/Telegram/SourceFiles/window/window_session_controller.cpp index 94a1aed67..1e7af0c39 100644 --- a/Telegram/SourceFiles/window/window_session_controller.cpp +++ b/Telegram/SourceFiles/window/window_session_controller.cpp @@ -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 diff --git a/Telegram/SourceFiles/window/window_session_controller.h b/Telegram/SourceFiles/window/window_session_controller.h index 02a74419b..8eb6997a5 100644 --- a/Telegram/SourceFiles/window/window_session_controller.h +++ b/Telegram/SourceFiles/window/window_session_controller.h @@ -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; };