From ad63f6d0c96184d5104055dd7bf939d64600b606 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karsten=20Ku=CC=88pper?= Date: Thu, 11 Jul 2024 11:27:14 -0400 Subject: [PATCH 1/6] show download curated playlists in downloaded content --- BMM.Core/App.cs | 1 + .../Factories/DocumentsPOFactory.cs | 13 +++--- .../TrackCollections/IPlaylistPOFactory.cs | 9 ++++ .../TrackCollections/PlaylistPOFactory.cs | 12 ++++++ .../MyContent/DownloadedContentViewModel.cs | 42 +++++++++++++++---- 5 files changed, 60 insertions(+), 17 deletions(-) create mode 100644 BMM.Core/Implementations/Factories/TrackCollections/IPlaylistPOFactory.cs create mode 100644 BMM.Core/Implementations/Factories/TrackCollections/PlaylistPOFactory.cs diff --git a/BMM.Core/App.cs b/BMM.Core/App.cs index 67d5360fb..476923ac3 100644 --- a/BMM.Core/App.cs +++ b/BMM.Core/App.cs @@ -287,6 +287,7 @@ public override void Initialize() Mvx.IoCProvider.LazyConstructAndRegisterSingleton(); Mvx.IoCProvider.LazyConstructAndRegisterSingleton(); Mvx.IoCProvider.LazyConstructAndRegisterSingleton(); + Mvx.IoCProvider.LazyConstructAndRegisterSingleton(); Mvx.IoCProvider.LazyConstructAndRegisterSingleton(); Mvx.IoCProvider.LazyConstructAndRegisterSingleton(); Mvx.IoCProvider.LazyConstructAndRegisterSingleton(); diff --git a/BMM.Core/Implementations/Factories/DocumentsPOFactory.cs b/BMM.Core/Implementations/Factories/DocumentsPOFactory.cs index 22e72a67d..0c590f4a8 100644 --- a/BMM.Core/Implementations/Factories/DocumentsPOFactory.cs +++ b/BMM.Core/Implementations/Factories/DocumentsPOFactory.cs @@ -1,4 +1,3 @@ -using System.Collections.Generic; using BMM.Api.Implementation.Models; using BMM.Core.Implementations.Factories.ContinueListening; using BMM.Core.Implementations.Factories.DiscoverSection; @@ -9,20 +8,15 @@ using BMM.Core.Implementations.Factories.YearInReview; using BMM.Core.Implementations.TrackInformation.Strategies; using BMM.Core.Models.POs.Albums; -using BMM.Core.Models.POs.Base; using BMM.Core.Models.POs.Base.Interfaces; using BMM.Core.Models.POs.BibleStudy; using BMM.Core.Models.POs.Carousels; using BMM.Core.Models.POs.Contributors; using BMM.Core.Models.POs.InfoMessages; using BMM.Core.Models.POs.Other; -using BMM.Core.Models.POs.Playlists; using BMM.Core.Models.POs.Podcasts; using BMM.Core.Models.POs.Recommendations; using BMM.Core.Models.POs.Tiles; -using BMM.Core.Models.POs.Tracks; -using BMM.Core.Models.POs.Tracks.Interfaces; -using BMM.Core.Models.POs.YearInReview; using MvvmCross.Commands; using MvvmCross.Navigation; @@ -37,6 +31,7 @@ public class DocumentsPOFactory : IDocumentsPOFactory private readonly ITilePOFactory _tilePOFactory; private readonly IYearInReviewTeaserPOFactory _yearInReviewTeaserPOFactory; private readonly IHighlightedTextTrackPOFactory _highlightedTextTrackPOFactory; + private readonly IPlaylistPOFactory _playlistPOFactory; private readonly IMvxNavigationService _mvxNavigationService; public DocumentsPOFactory( @@ -47,7 +42,8 @@ public DocumentsPOFactory( ITilePOFactory tilePOFactory, IYearInReviewTeaserPOFactory yearInReviewTeaserPOFactory, IHighlightedTextTrackPOFactory highlightedTextTrackPOFactory, - IMvxNavigationService mvxNavigationService) + IMvxNavigationService mvxNavigationService, + IPlaylistPOFactory playlistPOFactory) { _trackPOFactory = trackPOFactory; _trackCollectionPOFactory = trackCollectionPOFactory; @@ -57,6 +53,7 @@ public DocumentsPOFactory( _yearInReviewTeaserPOFactory = yearInReviewTeaserPOFactory; _highlightedTextTrackPOFactory = highlightedTextTrackPOFactory; _mvxNavigationService = mvxNavigationService; + _playlistPOFactory = playlistPOFactory; } public IEnumerable Create( @@ -108,7 +105,7 @@ public IEnumerable Create( documentsPOList.Add(_discoverSectionHeaderPOFactory.Create(discoverSectionHeader)); break; case Playlist playlist: - documentsPOList.Add(new PlaylistPO(playlist)); + documentsPOList.Add(_playlistPOFactory.Create(playlist)); break; case ListeningStreak listeningStreak: documentsPOList.Add(_listeningStreakPOFactory.Create(listeningStreak)); diff --git a/BMM.Core/Implementations/Factories/TrackCollections/IPlaylistPOFactory.cs b/BMM.Core/Implementations/Factories/TrackCollections/IPlaylistPOFactory.cs new file mode 100644 index 000000000..5bb8f41ed --- /dev/null +++ b/BMM.Core/Implementations/Factories/TrackCollections/IPlaylistPOFactory.cs @@ -0,0 +1,9 @@ +using BMM.Api.Implementation.Models; +using BMM.Core.Models.POs.Playlists; + +namespace BMM.Core.Implementations.Factories.TrackCollections; + +public interface IPlaylistPOFactory +{ + PlaylistPO Create(Playlist playlist); +} \ No newline at end of file diff --git a/BMM.Core/Implementations/Factories/TrackCollections/PlaylistPOFactory.cs b/BMM.Core/Implementations/Factories/TrackCollections/PlaylistPOFactory.cs new file mode 100644 index 000000000..eb8acb50c --- /dev/null +++ b/BMM.Core/Implementations/Factories/TrackCollections/PlaylistPOFactory.cs @@ -0,0 +1,12 @@ +using BMM.Api.Implementation.Models; +using BMM.Core.Models.POs.Playlists; + +namespace BMM.Core.Implementations.Factories.TrackCollections; + +public class PlaylistPOFactory : IPlaylistPOFactory +{ + public PlaylistPO Create(Playlist playlist) + { + return new PlaylistPO(playlist); + } +} \ No newline at end of file diff --git a/BMM.Core/ViewModels/MyContent/DownloadedContentViewModel.cs b/BMM.Core/ViewModels/MyContent/DownloadedContentViewModel.cs index a9affa331..d1dd43307 100644 --- a/BMM.Core/ViewModels/MyContent/DownloadedContentViewModel.cs +++ b/BMM.Core/ViewModels/MyContent/DownloadedContentViewModel.cs @@ -8,6 +8,7 @@ using BMM.Api.Implementation.Models; using BMM.Core.Implementations.Factories.TrackCollections; using BMM.Core.Implementations.FileStorage; +using BMM.Core.Implementations.PlaylistPersistence; using BMM.Core.Implementations.Podcasts; using BMM.Core.Implementations.TrackCollections; using BMM.Core.Models.POs.Base; @@ -24,18 +25,24 @@ namespace BMM.Core.ViewModels.MyContent public class DownloadedContentViewModel : ContentBaseViewModel { private readonly IConnection _connection; + private readonly IOfflinePlaylistStorage _playlistOfflineStorage; + private readonly IPlaylistPOFactory _playlistPOFactory; public bool IsEmpty { get; private set; } public DownloadedContentViewModel( IStorageManager storageManager, IConnection connection, - ITrackCollectionPOFactory trackCollectionPOFactory) + ITrackCollectionPOFactory trackCollectionPOFactory, + IOfflinePlaylistStorage playlistOfflineStorage, + IPlaylistPOFactory playlistPOFactory) : base( storageManager, trackCollectionPOFactory) { _connection = connection; + _playlistOfflineStorage = playlistOfflineStorage; + _playlistPOFactory = playlistPOFactory; } protected override void AttachEvents() @@ -63,7 +70,7 @@ private void DocumentsOnCollectionChanged(object sender, NotifyCollectionChanged RaisePropertyChanged(() => IsEmpty); } - private async Task> TrackCollectionContainOfflineFiles(IEnumerable allCollections, CachePolicy cachePolicy) + private async Task> TrackCollectionContainingOfflineFiles(IEnumerable allCollections, CachePolicy cachePolicy) { var offlineCollection = allCollections?.Where(tc => tc.IsAvailableOffline).ToList(); var isOnline = _connection.GetStatus() == ConnectionStatus.Online; @@ -92,19 +99,36 @@ public override async Task Load() public override async Task> LoadItems(CachePolicy policy = CachePolicy.UseCacheAndRefreshOutdated) { var allCollectionsExceptMyTracks = (await base.LoadItems(policy))?.OfType(); + var offlineTrackCollections = await TrackCollectionContainingOfflineFiles(allCollectionsExceptMyTracks, policy); + var offlinePlaylists = await BuildDownloadedCuratedPlaylists(); - var offlineTrackCollections = await TrackCollectionContainOfflineFiles(allCollectionsExceptMyTracks, policy); + var items = new List(); - var offlineTrackCollectionsPlusPinnedItems = new List(); - - offlineTrackCollectionsPlusPinnedItems.AddRange(await BuildPinnedItems()); + items.AddRange(await BuildPinnedItems()); + items.AddRange(offlinePlaylists); if (offlineTrackCollections != null) - offlineTrackCollectionsPlusPinnedItems.AddRange(offlineTrackCollections); + items.AddRange(offlineTrackCollections); - if (offlineTrackCollectionsPlusPinnedItems.Count == 0) + if (items.Count == 0) IsEmpty = true; - return offlineTrackCollectionsPlusPinnedItems; + return items; + } + + private async Task> BuildDownloadedCuratedPlaylists() + { + var documents = new List(); + IList playlists = await Client.Playlist.GetAll(CachePolicy.UseCache); + var downloadedPlaylistIds = await _playlistOfflineStorage.GetPlaylistIds(); + foreach (var playlist in playlists) + { + if (downloadedPlaylistIds.Contains(playlist.Id)) + { + documents.Add(_playlistPOFactory.Create(playlist)); + } + } + + return documents; } private async Task> BuildPinnedItems() From 54c28e62edd0dcd09585e8a6a1757cc545d5a94c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karsten=20Ku=CC=88pper?= Date: Thu, 11 Jul 2024 11:33:18 -0400 Subject: [PATCH 2/6] streamline layout of track lists & track collections on Android --- .../layout/listitem_featured_playlist.axml | 1 + .../Resources/layout/listitem_pinned_item.axml | 14 ++++++++------ .../layout/listitem_trackcollection.axml | 18 +++++++++--------- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/BMM.UI.Android/Resources/layout/listitem_featured_playlist.axml b/BMM.UI.Android/Resources/layout/listitem_featured_playlist.axml index e2d435827..b499af05c 100644 --- a/BMM.UI.Android/Resources/layout/listitem_featured_playlist.axml +++ b/BMM.UI.Android/Resources/layout/listitem_featured_playlist.axml @@ -15,6 +15,7 @@ android:gravity="center" app:cardCornerRadius="@dimen/corner_radius_mini" app:cardElevation="0dp" + android:padding="2dp" app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintBottom_toBottomOf="parent"> diff --git a/BMM.UI.Android/Resources/layout/listitem_pinned_item.axml b/BMM.UI.Android/Resources/layout/listitem_pinned_item.axml index 536267734..eee0a5d99 100644 --- a/BMM.UI.Android/Resources/layout/listitem_pinned_item.axml +++ b/BMM.UI.Android/Resources/layout/listitem_pinned_item.axml @@ -2,25 +2,26 @@ @@ -37,7 +38,9 @@ android:orientation="vertical" android:layout_centerVertical="true" android:layout_toRightOf="@+id/image_view_row_icon" - android:layout_toLeftOf="@+id/image_button_options"> + android:layout_toLeftOf="@+id/image_button_options" + android:layout_marginLeft="@dimen/element_margin_small" + android:layout_marginStart="12dp"> diff --git a/BMM.UI.Android/Resources/layout/listitem_trackcollection.axml b/BMM.UI.Android/Resources/layout/listitem_trackcollection.axml index b7a3d1fbb..b768cfefe 100644 --- a/BMM.UI.Android/Resources/layout/listitem_trackcollection.axml +++ b/BMM.UI.Android/Resources/layout/listitem_trackcollection.axml @@ -2,26 +2,25 @@ @@ -39,7 +38,9 @@ android:orientation="vertical" android:layout_centerVertical="true" android:layout_toRightOf="@+id/image_view_row_icon" - android:layout_toLeftOf="@+id/SharedPlaylistIcon"> + android:layout_toLeftOf="@+id/SharedPlaylistIcon" + android:layout_marginLeft="@dimen/element_margin_small" + android:layout_marginStart="12dp"> From 51f02421e859bc0ca97617bbfdbd8509f5ab3e54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karsten=20Ku=CC=88pper?= Date: Thu, 11 Jul 2024 11:50:34 -0400 Subject: [PATCH 3/6] fix tests --- ...MyContentTrackCollectionsViewModelTests.cs | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/BMM.Tests/BMM.Core.Test/Unit/ViewModels/MyContentTrackCollectionsViewModelTests.cs b/BMM.Tests/BMM.Core.Test/Unit/ViewModels/MyContentTrackCollectionsViewModelTests.cs index a3f45584e..015abb5fc 100644 --- a/BMM.Tests/BMM.Core.Test/Unit/ViewModels/MyContentTrackCollectionsViewModelTests.cs +++ b/BMM.Tests/BMM.Core.Test/Unit/ViewModels/MyContentTrackCollectionsViewModelTests.cs @@ -1,15 +1,12 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using BMM.Api.Abstraction; +using BMM.Api.Abstraction; using BMM.Api.Framework; using BMM.Api.Implementation.Models; using BMM.Core.Implementations.Factories.TrackCollections; using BMM.Core.Implementations.FileStorage; -using BMM.Core.Implementations.TrackCollections; +using BMM.Core.Implementations.PlaylistPersistence; using BMM.Core.Test.Unit.ViewModels.Base; using BMM.Core.ViewModels.MyContent; using Moq; -using NUnit.Framework; namespace BMM.Core.Test.Unit.ViewModels { @@ -17,11 +14,16 @@ namespace BMM.Core.Test.Unit.ViewModels public class MyContentTrackCollectionsViewModelTests : BaseViewModelTests { private readonly Mock _connectionMock = new Mock(); + private readonly Mock _playlistOfflineStorageMock = new Mock(); public override void SetUp() { base.SetUp(); _connectionMock.Setup(x => x.GetStatus()).Returns(ConnectionStatus.Online); + _playlistOfflineStorageMock.Setup(x => x.GetPlaylistIds()).ReturnsAsync(new HashSet()); + + Client.Setup(x => x.Playlist.GetAll(It.IsAny())) + .Returns(Task.FromResult>(new List())); } [Test] @@ -40,7 +42,9 @@ public async Task LoadItems_ShouldHandleNullValueAndDisplayEmptyDocumentIfConnec var newestViewModel = new DownloadedContentViewModel( new Mock().Object, _connectionMock.Object, - new Mock().Object); + new Mock().Object, + _playlistOfflineStorageMock.Object, + new PlaylistPOFactory()); newestViewModel.TextSource = TextResource.Object; // Act @@ -73,7 +77,9 @@ public async Task LoadItems_ShouldHandleNullValueAndDisplayEmptyDocumentIfConnec var newestViewModel = new DownloadedContentViewModel( mockStorage.Object, _connectionMock.Object, - new Mock().Object); + new Mock().Object, + _playlistOfflineStorageMock.Object, + new PlaylistPOFactory()); newestViewModel.TextSource = TextResource.Object; _connectionMock.Setup(x => x.GetStatus()).Returns(ConnectionStatus.Offline); From e38ed7d20b33c0f0426b8b4cb89a9b214e6b1f89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karsten=20Ku=CC=88pper?= Date: Thu, 11 Jul 2024 12:10:39 -0400 Subject: [PATCH 4/6] preserve PlaybackOrigin in PlayerVM --- BMM.Core/ViewModels/PlayerBaseViewModel.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/BMM.Core/ViewModels/PlayerBaseViewModel.cs b/BMM.Core/ViewModels/PlayerBaseViewModel.cs index 393bab773..7616f6202 100644 --- a/BMM.Core/ViewModels/PlayerBaseViewModel.cs +++ b/BMM.Core/ViewModels/PlayerBaseViewModel.cs @@ -1,6 +1,4 @@ using BMM.Core.ViewModels.Base; -using System; -using System.Threading.Tasks; using BMM.Api.Abstraction; using BMM.Api.Implementation.Models; using BMM.Core.Extensions; @@ -31,7 +29,12 @@ public class PlayerBaseViewModel : BaseViewModel public MvxCommand PlayPauseCommand { get; } public bool IsLiked => CurrentTrack?.IsLiked ?? false; - + + public override string PlaybackOriginString(int? index = null) + { + return _currentTrack.PlaybackOrigin; + } + /// /// When changing the song on Android, exo player sends few current track updates, where few of them is just null. /// From 039052b41c3201f2510c68f69ee8f8910d7d8d7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karsten=20Ku=CC=88pper?= Date: Thu, 11 Jul 2024 12:30:28 -0400 Subject: [PATCH 5/6] streamline design on iOS --- .../TableViewCell/PinnedItemTableViewCell.xib | 15 +++++++-------- .../TrackCollectionTableViewCell.xib | 16 ++++++++-------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/BMM.UI.iOS/Application/TableViewCell/PinnedItemTableViewCell.xib b/BMM.UI.iOS/Application/TableViewCell/PinnedItemTableViewCell.xib index 21f9d0d10..69519a1e6 100644 --- a/BMM.UI.iOS/Application/TableViewCell/PinnedItemTableViewCell.xib +++ b/BMM.UI.iOS/Application/TableViewCell/PinnedItemTableViewCell.xib @@ -1,9 +1,8 @@ - + - - + @@ -18,7 +17,7 @@