diff --git a/Telegram/SourceFiles/data/data_saved_music.cpp b/Telegram/SourceFiles/data/data_saved_music.cpp index d7c4d88afa..273e876101 100644 --- a/Telegram/SourceFiles/data/data_saved_music.cpp +++ b/Telegram/SourceFiles/data/data_saved_music.cpp @@ -9,10 +9,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "api/api_hash.h" #include "apiwrap.h" +#include "base/unixtime.h" #include "data/data_document.h" #include "data/data_peer.h" #include "data/data_session.h" #include "data/data_user.h" +#include "history/history.h" #include "main/main_session.h" #include "ui/ui_utility.h" @@ -21,19 +23,52 @@ namespace { constexpr auto kPerPage = 50; +[[nodiscard]] not_null ItemDocument( + not_null item) { + return item->media()->document(); +} + } // namespace SavedMusic::SavedMusic(not_null owner) : _owner(owner) { } +SavedMusic::~SavedMusic() { + Expects(_entries.empty()); +} + +void SavedMusic::clear() { + base::take(_entries); +} + bool SavedMusic::Supported(PeerId peerId) { return peerId && peerIsUser(peerId); } +not_null SavedMusic::musicIdToMsg( + PeerId peerId, + Entry &entry, + not_null id) { + const auto i = entry.musicIdToMsg.find(id); + if (i != end(entry.musicIdToMsg)) { + return i->second.get(); + } else if (!entry.history) { + entry.history = _owner->history(peerId); + } + return entry.musicIdToMsg.emplace(id, entry.history->makeMessage({ + .id = entry.history->nextNonHistoryEntryId(), + .flags = (MessageFlag::FakeHistoryItem + | MessageFlag::HasFromId + | MessageFlag::SavedMusicItem), + .from = entry.history->peer->id, + .date = base::unixtime::now(), + }, id, TextWithEntities())).first->second.get(); +} + bool SavedMusic::has(not_null document) const { const auto entry = lookupEntry(_owner->session().userPeerId()); - return entry && ranges::contains(entry->list, document); + return entry && ranges::contains(entry->list, document, ItemDocument); } void SavedMusic::save(not_null document) { @@ -42,10 +77,11 @@ void SavedMusic::save(not_null document) { if (entry.list.empty() && !entry.loaded) { loadMore(peerId); } - if (ranges::contains(entry.list, document)) { + if (ranges::contains(entry.list, document, ItemDocument)) { return; } - entry.list.insert(begin(entry.list), document); + const auto item = musicIdToMsg(peerId, entry, document); + entry.list.insert(begin(entry.list), item); if (entry.total >= 0) { ++entry.total; } @@ -60,13 +96,15 @@ void SavedMusic::save(not_null document) { void SavedMusic::remove(not_null document) { const auto peerId = _owner->session().userPeerId(); auto &entry = _entries[peerId]; - const auto i = ranges::remove(entry.list, document); - if (const auto removed = int(end(entry.list) - i)) { - entry.list.erase(i, end(entry.list)); - if (entry.total >= 0) { - entry.total = std::max(entry.total - removed, 0); + const auto i = ranges::find(entry.list, document, ItemDocument); + if (i != end(entry.list)) { + entry.musicIdFromMsgId.remove((*i)->id); + entry.list.erase(i); + if (entry.total > 0) { + entry.total = std::max(entry.total - 1, 0); } } + entry.musicIdToMsg.remove(document); _owner->session().api().request(MTPaccount_SaveMusic( MTP_flags(MTPaccount_SaveMusic::Flag::f_unsave), document->mtpInput(), @@ -87,7 +125,7 @@ void SavedMusic::apply(not_null user, const MTPDocument *last) { return; } const auto document = _owner->processDocument(*last); - const auto i = ranges::find(entry.list, document); + const auto i = ranges::find(entry.list, document, ItemDocument); if (i != end(entry.list)) { if (i == begin(entry.list)) { return; @@ -97,7 +135,9 @@ void SavedMusic::apply(not_null user, const MTPDocument *last) { loadMore(peerId, true); return; } - entry.list.insert(begin(entry.list), document); + entry.list.insert( + begin(entry.list), + musicIdToMsg(peerId, entry, document)); _changed.fire_copy(peerId); if (entry.loaded) { loadMore(peerId, true); @@ -120,9 +160,9 @@ int SavedMusic::count(PeerId peerId) const { return entry ? std::max(entry->total, 0) : 0; } -const std::vector> &SavedMusic::list( +const std::vector> &SavedMusic::list( PeerId peerId) const { - static const auto empty = std::vector>(); + static const auto empty = std::vector>(); if (!Supported(peerId)) { return empty; } @@ -171,8 +211,9 @@ void SavedMusic::loadMore(PeerId peerId, bool reload) { } for (const auto &item : list) { const auto document = _owner->processDocument(item); - if (!ranges::contains(entry.list, document)) { - entry.list.push_back(document); + if (!ranges::contains(entry.list, document, ItemDocument)) { + entry.list.push_back( + musicIdToMsg(peerId, entry, document)); } } entry.loaded = list.empty() || (count == entry.list.size()); @@ -189,6 +230,7 @@ void SavedMusic::loadMore(PeerId peerId, bool reload) { uint64 SavedMusic::firstPageHash(const Entry &entry) const { return Api::CountHash(entry.list + | ranges::views::transform(ItemDocument) | ranges::views::transform(&DocumentData::id) | ranges::views::take(kPerPage)); } @@ -215,7 +257,7 @@ const SavedMusic::Entry *SavedMusic::lookupEntry(PeerId peerId) const { rpl::producer SavedMusicList( not_null peer, - DocumentData *aroundId, + HistoryItem *aroundId, int limit) { if (!peer->isUser()) { return rpl::single(SavedMusicSlice({}, 0, 0, 0)); @@ -253,7 +295,7 @@ rpl::producer SavedMusicList( } const auto takeBefore = std::min(hasBefore, limit); const auto takeAfter = std::min(hasAfter, limit); - auto ids = std::vector>(); + auto ids = std::vector>(); ids.reserve(takeBefore + takeAfter); for (auto j = i - takeBefore; j != i + takeAfter; ++j) { ids.push_back(*j); diff --git a/Telegram/SourceFiles/data/data_saved_music.h b/Telegram/SourceFiles/data/data_saved_music.h index 3b4c0563f0..fe31a5d788 100644 --- a/Telegram/SourceFiles/data/data_saved_music.h +++ b/Telegram/SourceFiles/data/data_saved_music.h @@ -9,6 +9,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_abstract_sparse_ids.h" +#include "history/history_item.h" + class PeerData; namespace Data { @@ -18,12 +20,13 @@ class Session; class SavedMusic final { public: explicit SavedMusic(not_null owner); + ~SavedMusic(); [[nodiscard]] static bool Supported(PeerId peerId); [[nodiscard]] bool countKnown(PeerId peerId) const; [[nodiscard]] int count(PeerId peerId) const; - [[nodiscard]] const std::vector> &list( + [[nodiscard]] const std::vector> &list( PeerId peerId) const; void loadMore(PeerId peerId); @@ -35,9 +38,16 @@ public: void apply(not_null user, const MTPDocument *last); + void clear(); + private: + using OwnedItem = std::unique_ptr; + struct Entry { - std::vector> list; + base::flat_map> musicIdFromMsgId; + base::flat_map, OwnedItem> musicIdToMsg; + std::vector> list; + History *history = nullptr; mtpRequestId requestId = 0; int total = -1; bool loaded = false; @@ -48,6 +58,10 @@ private: [[nodiscard]] Entry *lookupEntry(PeerId peerId); [[nodiscard]] const Entry *lookupEntry(PeerId peerId) const; [[nodiscard]] uint64 firstPageHash(const Entry &entry) const; + [[nodiscard]] not_null musicIdToMsg( + PeerId peerId, + Entry &entry, + not_null id); const not_null _owner; @@ -57,11 +71,11 @@ private: }; using SavedMusicSlice = AbstractSparseIds< - std::vector>>; + std::vector>>; [[nodiscard]] rpl::producer SavedMusicList( not_null peer, - DocumentData *aroundId, + HistoryItem *aroundId, int limit); } // namespace Data diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index a7009dfb68..367e0c54c1 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -409,6 +409,7 @@ void Session::clear() { channel->setFlags(channel->flags() & ~(ChannelDataFlag::Forum | ChannelDataFlag::MonoforumAdmin)); } + _savedMusic->clear(); _savedMessages->clear(); _sendActionManager->clear(); diff --git a/Telegram/SourceFiles/data/data_shared_media.cpp b/Telegram/SourceFiles/data/data_shared_media.cpp index 5e0c3735d2..3ee5f54785 100644 --- a/Telegram/SourceFiles/data/data_shared_media.cpp +++ b/Telegram/SourceFiles/data/data_shared_media.cpp @@ -7,18 +7,18 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "data/data_shared_media.h" -#include -#include "main/main_session.h" #include "apiwrap.h" -#include "storage/storage_facade.h" -#include "history/history.h" -#include "history/history_item.h" +#include "core/crash_reports.h" #include "data/components/scheduled_messages.h" #include "data/data_document.h" #include "data/data_media_types.h" #include "data/data_photo.h" +#include "data/data_saved_music.h" #include "data/data_session.h" -#include "core/crash_reports.h" +#include "history/history.h" +#include "history/history_item.h" +#include "main/main_session.h" +#include "storage/storage_facade.h" namespace { @@ -233,6 +233,39 @@ rpl::producer SharedScheduledMediaViewer( }); } +rpl::producer SavedMusicMediaViewer( + not_null session, + SharedMediaMergedKey key, + int limitBefore, + int limitAfter) { + Expects((key.mergedKey.universalId != 0) + || (limitBefore == 0 && limitAfter == 0)); + + const auto peerId = key.mergedKey.peerId; + const auto item = key.mergedKey.universalId + ? session->data().message(peerId, key.mergedKey.universalId) + : nullptr; + + return Data::SavedMusicList( + session->data().peer(peerId), + item, + std::max(limitBefore, limitAfter) + ) | rpl::map([=](const Data::SavedMusicSlice &slice) { + auto list = std::vector(); + list.reserve(slice.size()); + for (auto i = 0, count = int(slice.size()); i != count; ++i) { + list.push_back(slice[i]->id); + } + return SparseIdsMergedSlice( + key.mergedKey, + SparseUnsortedIdsSlice( + std::move(list), + slice.fullCount(), + slice.skippedBefore(), + slice.skippedAfter())); + }); +} + rpl::producer SharedMediaMergedViewer( not_null session, SharedMediaMergedKey key, @@ -490,6 +523,19 @@ rpl::producer SharedMediaWithLastViewer( std::move(update), std::nullopt)); }); + } else if (key.topicRootId == SharedMediaWithLastSlice::kSavedMusicTopicId) { + return SavedMusicMediaViewer( + session, + std::move(viewerKey), + limitBefore, + limitAfter + ) | rpl::start_with_next([=](SparseIdsMergedSlice &&update) { + consumer.put_next(SharedMediaWithLastSlice( + session, + key, + std::move(update), + std::nullopt)); + }); } return rpl::combine( SharedMediaMergedViewer( diff --git a/Telegram/SourceFiles/data/data_shared_media.h b/Telegram/SourceFiles/data/data_shared_media.h index 8f53b4026c..cb01f14f46 100644 --- a/Telegram/SourceFiles/data/data_shared_media.h +++ b/Telegram/SourceFiles/data/data_shared_media.h @@ -52,6 +52,12 @@ rpl::producer SharedScheduledMediaViewer( int limitBefore, int limitAfter); +rpl::producer SavedMusicMediaViewer( + not_null session, + SharedMediaMergedKey key, + int limitBefore, + int limitAfter); + rpl::producer SharedMediaMergedViewer( not_null session, SharedMediaMergedKey key, @@ -70,6 +76,8 @@ public: static constexpr auto kScheduledTopicId = SparseIdsMergedSlice::kScheduledTopicId; + static constexpr auto kSavedMusicTopicId + = SparseIdsMergedSlice::kSavedMusicTopicId; struct Key { Key( PeerId peerId, diff --git a/Telegram/SourceFiles/data/data_sparse_ids.h b/Telegram/SourceFiles/data/data_sparse_ids.h index 3328ee5a40..10dbe9037e 100644 --- a/Telegram/SourceFiles/data/data_sparse_ids.h +++ b/Telegram/SourceFiles/data/data_sparse_ids.h @@ -28,6 +28,7 @@ class SparseIdsMergedSlice { public: using UniversalMsgId = MsgId; static constexpr MsgId kScheduledTopicId = ScheduledMaxMsgId; + static constexpr MsgId kSavedMusicTopicId = ScheduledMaxMsgId + 1; struct Key { Key( diff --git a/Telegram/SourceFiles/data/data_types.h b/Telegram/SourceFiles/data/data_types.h index ebc6958c41..e2850df79a 100644 --- a/Telegram/SourceFiles/data/data_types.h +++ b/Telegram/SourceFiles/data/data_types.h @@ -358,6 +358,7 @@ enum class MessageFlag : uint64 { TonPaidSuggested = (1ULL << 53), StoryInProfile = (1ULL << 54), + SavedMusicItem = (1ULL << 55), }; inline constexpr bool is_flag_type(MessageFlag) { return true; } using MessageFlags = base::flags; diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index ae2f738165..5207443627 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -1831,6 +1831,10 @@ bool HistoryItem::isUserpicSuggestion() const { return (_flags & MessageFlag::IsUserpicSuggestion); } +bool HistoryItem::isSavedMusicItem() const { + return (_flags & MessageFlag::SavedMusicItem); +} + BusinessShortcutId HistoryItem::shortcutId() const { return _shortcutId; } diff --git a/Telegram/SourceFiles/history/history_item.h b/Telegram/SourceFiles/history/history_item.h index 1f65b0c6a8..743112461b 100644 --- a/Telegram/SourceFiles/history/history_item.h +++ b/Telegram/SourceFiles/history/history_item.h @@ -192,6 +192,7 @@ public: [[nodiscard]] bool canLookupMessageAuthor() const; [[nodiscard]] bool skipNotification() const; [[nodiscard]] bool isUserpicSuggestion() const; + [[nodiscard]] bool isSavedMusicItem() const; [[nodiscard]] BusinessShortcutId shortcutId() const; [[nodiscard]] bool isBusinessShortcut() const; void setRealShortcutId(BusinessShortcutId id); diff --git a/Telegram/SourceFiles/info/profile/info_profile_cover.cpp b/Telegram/SourceFiles/info/profile/info_profile_cover.cpp index 280d6d6d51..96b0b3320e 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_cover.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_cover.cpp @@ -835,7 +835,9 @@ void Cover::setupSavedMusic() { 1 ) | rpl::map([=](const Data::SavedMusicSlice &data) { return data.size() ? data[0].get() : nullptr; - }) | rpl::start_with_next([=](DocumentData *document) { + }) | rpl::start_with_next([=](HistoryItem *item) { + const auto media = item ? item->media() : nullptr; + const auto document = media ? media->document() : nullptr; if (!document) { _musicButton = nullptr; resize(width(), _st.height); @@ -845,6 +847,7 @@ void Cover::setupSavedMusic() { this, DocumentMusicButtonData(document), [=] { _controller->showSection(MakeMusic(_peer)); }); + _musicButton->show(); widthValue( ) | rpl::start_with_next([=](int newWidth) { diff --git a/Telegram/SourceFiles/info/saved/info_saved_music_provider.cpp b/Telegram/SourceFiles/info/saved/info_saved_music_provider.cpp index 99fe45ba40..04510fc78c 100644 --- a/Telegram/SourceFiles/info/saved/info_saved_music_provider.cpp +++ b/Telegram/SourceFiles/info/saved/info_saved_music_provider.cpp @@ -81,31 +81,6 @@ bool MusicProvider::sectionHasFloatingHeader() { return false; } -not_null MusicProvider::musicIdFromMsgId(MsgId itemId) const { - const auto i = _musicIdFromMsgId.find(itemId); - Assert(i != end(_musicIdFromMsgId)); - - return i->second; -} - -not_null MusicProvider::musicIdToMsg( - not_null id) const { - const auto i = _musicIdToMsg.find(id); - if (i != end(_musicIdToMsg)) { - return i->second.get(); - } - return _musicIdToMsg.emplace(id, _history->makeMessage({ - .id = _history->nextNonHistoryEntryId(), - .flags = (MessageFlag::FakeHistoryItem | MessageFlag::HasFromId), - .from = _peer->id, - .date = base::unixtime::now(), - }, id, TextWithEntities())).first->second.get(); -} - -MsgId MusicProvider::musicIdToMsgId(not_null id) const { - return musicIdToMsg(id)->id; -} - QString MusicProvider::sectionTitle(not_null item) { return QString(); } @@ -161,18 +136,18 @@ void MusicProvider::checkPreload( / minItemHeight; const auto preloadAroundItem = [&](not_null layout) { auto preloadRequired = false; - const auto id = musicIdFromMsgId(layout->getItem()->id); + const auto item = layout->getItem(); if (!preloadRequired) { preloadRequired = (_idsLimit < preloadIdsLimitMin); } if (!preloadRequired) { - auto delta = _slice.distance(_aroundId, id); + auto delta = _slice.distance(_aroundId, item); Assert(delta != std::nullopt); preloadRequired = (qAbs(*delta) >= minIdDelta); } if (preloadRequired) { _idsLimit = preloadIdsLimit; - _aroundId = id; + _aroundId = item; refreshViewer(); } }; @@ -200,7 +175,7 @@ void MusicProvider::refreshViewer() { } _slice = std::move(slice); - auto nearestId = (DocumentData*)nullptr; + auto nearestId = (HistoryItem*)nullptr; for (auto i = 0; i != _slice.size(); ++i) { if (_slice[i] == aroundId) { nearestId = aroundId; @@ -227,8 +202,8 @@ std::vector MusicProvider::fillSections( auto section = ListSection(Type::MusicFile, sectionDelegate()); auto count = _slice.size(); for (auto i = 0; i != count; ++i) { - const auto musicId = _slice[i]; - if (const auto layout = getLayout(musicId, delegate)) { + const auto item = _slice[i]; + if (const auto layout = getLayout(item, delegate)) { if (!section.addItem(layout)) { section.finishSection(); result.push_back(std::move(section)); @@ -280,13 +255,13 @@ bool MusicProvider::isAfter( } BaseLayout *MusicProvider::getLayout( - not_null id, + not_null item, not_null delegate) { - auto it = _layouts.find(id); + auto it = _layouts.find(item); if (it == _layouts.end()) { - if (auto layout = createLayout(id, delegate)) { + if (auto layout = createLayout(item, delegate)) { layout->initDimensions(); - it = _layouts.emplace(id, std::move(layout)).first; + it = _layouts.emplace(item, std::move(layout)).first; } else { return nullptr; } @@ -296,36 +271,22 @@ BaseLayout *MusicProvider::getLayout( } std::unique_ptr MusicProvider::createLayout( - not_null id, + not_null item, not_null delegate) { - const auto item = musicIdToMsg(id); - if (!item) { - return nullptr; - } - const auto getPhoto = [&]() -> PhotoData* { - if (const auto media = item->media()) { - return media->photo(); - } - return nullptr; - }; - const auto getFile = [&]() -> DocumentData* { - if (const auto media = item->media()) { - return media->document(); - } - return nullptr; - }; - const auto peer = item->history()->peer; using namespace Overview::Layout; const auto options = MediaOptions{ }; - if (const auto file = getFile()) { - return std::make_unique( - delegate, - item, - DocumentFields{ file }, - st::overviewFileLayout); + + if (const auto media = item->media()) { + if (const auto file = media->document()) { + return std::make_unique( + delegate, + item, + DocumentFields{ file }, + st::overviewFileLayout); + } } return nullptr; } @@ -334,11 +295,8 @@ ListItemSelectionData MusicProvider::computeSelectionData( not_null item, TextSelection selection) { auto result = ListItemSelectionData(selection); - const auto id = item->id; - if (!_musicIdFromMsgId.contains(id)) { - return result; - } AssertIsDebug(); + //const auto id = item->id; //const auto peer = item->history()->peer; //const auto channel = peer->asChannel(); //const auto maybeStory = peer->owner().stories().lookup( @@ -372,8 +330,7 @@ void MusicProvider::applyDragSelection( } } for (auto &layoutItem : _layouts) { - const auto musicId = layoutItem.first; - const auto item = musicIdToMsg(musicId); + const auto item = layoutItem.first; if (item->id <= fromId && item->id > tillId) { ChangeItemSelection( selected, @@ -400,7 +357,7 @@ int64 MusicProvider::scrollTopStatePosition(not_null item) { } HistoryItem *MusicProvider::scrollTopStateItem(ListScrollTopState state) { - if (state.item && _slice.indexOf(musicIdFromMsgId(state.item->id))) { + if (state.item && _slice.indexOf(state.item)) { return state.item; //} else if (const auto id = _slice.nearest(state.position)) { // const auto full = FullMsgId(_peer->id, StoryIdToMsgId(*id)); @@ -409,7 +366,7 @@ HistoryItem *MusicProvider::scrollTopStateItem(ListScrollTopState state) { // } } - auto nearestId = (DocumentData*)nullptr; AssertIsDebug(); + auto nearestId = (HistoryItem*)nullptr; AssertIsDebug(); //for (auto i = 0; i != _slice.size(); ++i) { // if (!nearestId // || std::abs(*nearestId - state.position) @@ -418,7 +375,7 @@ HistoryItem *MusicProvider::scrollTopStateItem(ListScrollTopState state) { // } //} if (nearestId) { - const auto full = FullMsgId(_peer->id, musicIdToMsgId(nearestId)); + const auto full = nearestId->fullId(); if (const auto item = _controller->session().data().message(full)) { return item; } diff --git a/Telegram/SourceFiles/info/saved/info_saved_music_provider.h b/Telegram/SourceFiles/info/saved/info_saved_music_provider.h index 483d6e6a0e..77e4e33d0f 100644 --- a/Telegram/SourceFiles/info/saved/info_saved_music_provider.h +++ b/Telegram/SourceFiles/info/saved/info_saved_music_provider.h @@ -90,14 +90,6 @@ public: private: static constexpr auto kMinimalIdsLimit = 16; - using OwnedItem = std::unique_ptr; - - [[nodiscard]] not_null musicIdFromMsgId( - MsgId itemId) const; - [[nodiscard]] not_null musicIdToMsg( - not_null id) const; - [[nodiscard]] MsgId musicIdToMsgId(not_null id) const; - bool sectionHasFloatingHeader() override; QString sectionTitle(not_null item) override; bool sectionItemBelongsHere( @@ -108,29 +100,25 @@ private: void clearStaleLayouts(); void clear(); - [[nodiscard]] HistoryItem *ensureItem(not_null id); [[nodiscard]] Media::BaseLayout *getLayout( - not_null id, + not_null item, not_null delegate); [[nodiscard]] std::unique_ptr createLayout( - not_null musicId, + not_null item, not_null delegate); const not_null _controller; const not_null _peer; const not_null _history; - DocumentData *_aroundId = nullptr; + HistoryItem *_aroundId = nullptr; int _idsLimit = kMinimalIdsLimit; Data::SavedMusicSlice _slice; - std::unordered_map, Media::CachedItem> _layouts; + std::unordered_map, Media::CachedItem> _layouts; rpl::event_stream> _layoutRemoved; rpl::event_stream<> _refreshed; - mutable base::flat_map> _musicIdFromMsgId; - mutable base::flat_map, OwnedItem> _musicIdToMsg; - bool _started = false; rpl::lifetime _lifetime; diff --git a/Telegram/SourceFiles/info/saved/info_saved_music_widget.cpp b/Telegram/SourceFiles/info/saved/info_saved_music_widget.cpp index 762e252aed..458d71b2e3 100644 --- a/Telegram/SourceFiles/info/saved/info_saved_music_widget.cpp +++ b/Telegram/SourceFiles/info/saved/info_saved_music_widget.cpp @@ -323,9 +323,7 @@ void MusicWidget::selectionAction(SelectionAction action) { } rpl::producer MusicWidget::title() { - //const auto peer = controller()->key().musicPeer(); - AssertIsDebug(); - return rpl::single(u"muzlo"_q); + return tr::lng_media_type_songs(); } std::shared_ptr MakeMusic(not_null peer) { diff --git a/Telegram/SourceFiles/media/player/media_player_instance.cpp b/Telegram/SourceFiles/media/player/media_player_instance.cpp index c73c34e5ef..51e30ce824 100644 --- a/Telegram/SourceFiles/media/player/media_player_instance.cpp +++ b/Telegram/SourceFiles/media/player/media_player_instance.cpp @@ -88,6 +88,7 @@ struct Instance::ShuffleData { PeerId monoforumPeerId = 0; History *migrated = nullptr; bool scheduled = false; + bool savedMusic = false; int indexInPlayedIds = 0; bool allLoaded = false; rpl::lifetime nextSliceLifetime; @@ -387,6 +388,8 @@ void Instance::validatePlaylist(not_null data) { const auto sharedMediaViewer = (key->topicRootId == SparseIdsMergedSlice::kScheduledTopicId) ? SharedScheduledMediaViewer + : (key->topicRootId == SparseIdsMergedSlice::kSavedMusicTopicId) + ? SavedMusicMediaViewer : SharedMediaMergedViewer; sharedMediaViewer( &data->history->session(), @@ -413,7 +416,10 @@ auto Instance::playlistKey(not_null data) const return {}; } const auto item = data->history->owner().message(contextId); - if (!item || (!item->isRegular() && !item->isScheduled())) { + if (!item + || (!item->isRegular() + && !item->isScheduled() + && !item->isSavedMusicItem())) { return {}; } @@ -424,6 +430,8 @@ auto Instance::playlistKey(not_null data) const data->history->peer->id, (item->isScheduled() ? SparseIdsMergedSlice::kScheduledTopicId + : item->isSavedMusicItem() + ? SparseIdsMergedSlice::kSavedMusicTopicId : data->topicRootId), data->monoforumPeerId, data->migrated ? data->migrated->peer->id : 0, @@ -908,14 +916,18 @@ void Instance::validateShuffleData(not_null data) { const auto key = playlistKey(data); const auto scheduled = key && (key->topicRootId == SparseIdsMergedSlice::kScheduledTopicId); + const auto savedMusic = key + && (key->topicRootId == SparseIdsMergedSlice::kSavedMusicTopicId); if (raw->history != data->history || raw->topicRootId != data->topicRootId || raw->monoforumPeerId != data->monoforumPeerId || raw->migrated != data->migrated - || raw->scheduled != scheduled) { + || raw->scheduled != scheduled + || raw->savedMusic != savedMusic) { raw->history = data->history; raw->migrated = data->migrated; raw->scheduled = scheduled; + raw->savedMusic = savedMusic; raw->nextSliceLifetime.destroy(); raw->allLoaded = false; raw->playlist.clear(); diff --git a/Telegram/SourceFiles/media/player/media_player_panel.cpp b/Telegram/SourceFiles/media/player/media_player_panel.cpp index 9da485b116..73c9556d44 100644 --- a/Telegram/SourceFiles/media/player/media_player_panel.cpp +++ b/Telegram/SourceFiles/media/player/media_player_panel.cpp @@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "media/player/media_player_instance.h" #include "info/media/info_media_list_widget.h" +#include "info/saved/info_saved_music_widget.h" #include "history/history.h" #include "history/history_item.h" #include "data/data_session.h" @@ -227,6 +228,7 @@ void Panel::ensureCreated() { void Panel::refreshList() { const auto current = instance()->current(AudioMsgId::Type::Song); const auto contextId = current.contextId(); + auto savedMusicItem = false; const auto peer = [&]() -> PeerData* { if (const auto document = current.audio()) { if (&document->session() != &session()) { @@ -241,9 +243,12 @@ void Panel::refreshList() { const auto document = media ? media->document() : nullptr; if (!document || !document->isSharedMediaMusic() - || (!item->isRegular() && !item->isScheduled())) { + || (!item->isRegular() + && !item->isScheduled() + && !item->isSavedMusicItem())) { return nullptr; } + savedMusicItem = item->isSavedMusicItem(); const auto result = item->history()->peer; if (const auto migrated = result->migrateTo()) { return migrated; @@ -251,13 +256,19 @@ void Panel::refreshList() { return result; }(); const auto migrated = peer ? peer->migrateFrom() : nullptr; - if (_listPeer != peer || _listMigratedPeer != migrated) { + const auto listPeer = savedMusicItem ? nullptr : peer; + const auto listMusicPeer = savedMusicItem ? peer : nullptr; + const auto listMigratedPeer = savedMusicItem ? nullptr : migrated; + if (_listPeer != listPeer + || _listMusicPeer != listMusicPeer + || _listMigratedPeer != listMigratedPeer) { _scroll->takeWidget().destroy(); - _listPeer = _listMigratedPeer = nullptr; + _listPeer = _listMusicPeer = _listMigratedPeer = nullptr; } - if (peer && !_listPeer) { - _listPeer = peer; - _listMigratedPeer = migrated; + if ((listPeer && !_listPeer) || (listMusicPeer && !_listMusicPeer)) { + _listPeer = listPeer; + _listMusicPeer = listMusicPeer; + _listMigratedPeer = listMigratedPeer; auto list = object_ptr(this, infoController()); const auto weak = _scroll->setOwnedWidget(std::move(list)); @@ -292,10 +303,14 @@ void Panel::refreshList() { weak->setVisibleTopBottom(top, bottom); }, weak->lifetime()); - auto memento = Info::Media::Memento( + auto musicMemento = Info::Saved::MusicMemento(peer); + auto mediaMemento = Info::Media::Memento( peer, migratedPeerId(), - section().mediaType()); + (listMusicPeer + ? Storage::SharedMediaType::MusicFile + : section().mediaType())); + auto &memento = listMusicPeer ? musicMemento.media() : mediaMemento; memento.setAroundId(contextId); memento.setIdsLimit(kPlaylistIdsLimit); memento.setScrollTopItem({ contextId, peer->session().uniqueId() }); @@ -308,12 +323,14 @@ void Panel::performDestroy() { if (!_scroll->widget()) return; _scroll->takeWidget().destroy(); - _listPeer = _listMigratedPeer = nullptr; + _listPeer = _listMusicPeer = _listMigratedPeer = nullptr; _refreshListLifetime.destroy(); } Info::Key Panel::key() const { - return Info::Key(_listPeer); + return _listMusicPeer + ? Info::Key(Info::Saved::MusicTag{ _listMusicPeer }) + : Info::Key(_listPeer); } PeerData *Panel::migrated() const { @@ -321,7 +338,9 @@ PeerData *Panel::migrated() const { } Info::Section Panel::section() const { - return Info::Section(Info::Section::MediaType::MusicFile); + return _listMusicPeer + ? Info::Section(Info::Section::Type::SavedMusic) + : Info::Section(Info::Section::MediaType::MusicFile); } void Panel::startShow() { diff --git a/Telegram/SourceFiles/media/player/media_player_panel.h b/Telegram/SourceFiles/media/player/media_player_panel.h index 9123834cee..c46b499c3a 100644 --- a/Telegram/SourceFiles/media/player/media_player_panel.h +++ b/Telegram/SourceFiles/media/player/media_player_panel.h @@ -101,6 +101,7 @@ private: rpl::lifetime _refreshListLifetime; PeerData *_listPeer = nullptr; + PeerData *_listMusicPeer = nullptr; PeerData *_listMigratedPeer = nullptr; };