From 32d92be9900d3c328c017e57382849f940380f52 Mon Sep 17 00:00:00 2001 From: Difegue Date: Thu, 2 Sep 2021 19:57:36 +0200 Subject: [PATCH 01/15] Use more Segoe UI Variable --- Sources/Stylophone/Views/Playback/OverlayView.xaml | 6 ++++-- Sources/Stylophone/Views/Playback/PlaybackView.xaml | 10 +++++++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/Sources/Stylophone/Views/Playback/OverlayView.xaml b/Sources/Stylophone/Views/Playback/OverlayView.xaml index 8777ee37..197e9525 100644 --- a/Sources/Stylophone/Views/Playback/OverlayView.xaml +++ b/Sources/Stylophone/Views/Playback/OverlayView.xaml @@ -60,7 +60,8 @@ x:Name="compactTrackName" Margin="24,0,46,4" FontSize="18" - FontWeight="Bold" + FontFamily="Segoe UI Variable Display" + FontWeight="SemiBold" MaxLines="2" Text="{x:Bind PlaybackViewModel.CurrentTrack.Name, Mode=OneWay}" TextTrimming="CharacterEllipsis" @@ -71,7 +72,8 @@ x:Name="compactTrackArtist" Margin="24,0,46,8" FontSize="14" - FontWeight="Bold" + FontFamily="Segoe UI Variable Display" + FontWeight="SemiBold" Opacity="0.6" Text="{x:Bind PlaybackViewModel.CurrentTrack.File.Artist, Mode=OneWay}" TextTrimming="CharacterEllipsis" diff --git a/Sources/Stylophone/Views/Playback/PlaybackView.xaml b/Sources/Stylophone/Views/Playback/PlaybackView.xaml index 17e71261..22418df0 100644 --- a/Sources/Stylophone/Views/Playback/PlaybackView.xaml +++ b/Sources/Stylophone/Views/Playback/PlaybackView.xaml @@ -87,8 +87,8 @@ Margin="0,12,0,0"> @@ -136,6 +139,7 @@ x:Name="UpNextTitle" MaxWidth="256" Margin="{StaticResource XSmallLeftMargin}" + FontFamily="Segoe UI Variable Display" Opacity="0.6" Style="{ThemeResource BaseTextBlockStyle}" Text="{x:Bind PlaybackViewModel.NextTrack.Name, Mode=OneWay}" From a6019f75b9afcb99ea2a2b03e1ecb7d24113e3c4 Mon Sep 17 00:00:00 2001 From: Difegue Date: Thu, 2 Sep 2021 19:57:58 +0200 Subject: [PATCH 02/15] Fix bugs reported by AppCenter --- .../ViewModels/Bases/PlaybackViewModelBase.cs | 2 +- .../ViewModels/PlaylistViewModel.cs | 61 ++++++++++--------- Sources/Stylophone/Package.appxmanifest | 2 +- Sources/Stylophone/Package.tt | 2 +- 4 files changed, 35 insertions(+), 32 deletions(-) diff --git a/Sources/Stylophone.Common/ViewModels/Bases/PlaybackViewModelBase.cs b/Sources/Stylophone.Common/ViewModels/Bases/PlaybackViewModelBase.cs index cad067f9..fc64f249 100644 --- a/Sources/Stylophone.Common/ViewModels/Bases/PlaybackViewModelBase.cs +++ b/Sources/Stylophone.Common/ViewModels/Bases/PlaybackViewModelBase.cs @@ -669,7 +669,7 @@ private void AddToPlaylist(EventArgs obj) _notificationService.ShowInAppNotification(Resources.NotificationNoTrackPlaying); } - CurrentTrack.AddToPlayListCommand.Execute(CurrentTrack.File); + CurrentTrack?.AddToPlayListCommand.Execute(CurrentTrack.File); } private ICommand _showAlbumCommand; diff --git a/Sources/Stylophone.Common/ViewModels/PlaylistViewModel.cs b/Sources/Stylophone.Common/ViewModels/PlaylistViewModel.cs index 274599d8..0b949fef 100644 --- a/Sources/Stylophone.Common/ViewModels/PlaylistViewModel.cs +++ b/Sources/Stylophone.Common/ViewModels/PlaylistViewModel.cs @@ -267,37 +267,40 @@ public async Task LoadDataAsync(string playlistName) PlaylistInfo = $"{Source.Count} Tracks, Total Time: {Miscellaneous.ToReadableString(t)}"; - await Task.Run(async () => + if (Source.Count > 0) { - // Get album art for three albums to display in the playlist view - Random r = new Random(); - var distinctAlbums = Source.GroupBy(tr => tr.File.Album).Select(tr => tr.First()).OrderBy((item) => r.Next()).ToList(); - - if (distinctAlbums.Count > 1) - { - var art = await _albumArtService.GetAlbumArtAsync(distinctAlbums[0].File, true); - PlaylistArt = art != null ? art.ArtBitmap : PlaylistArt; - - DominantColor = (art?.DominantColor?.Color).GetValueOrDefault(); - IsLight = (!art?.DominantColor?.IsDark).GetValueOrDefault(); - } - - if (distinctAlbums.Count > 2) + await Task.Run(async () => { - var art = await _albumArtService.GetAlbumArtAsync(distinctAlbums[1].File, false); - PlaylistArt2 = art != null ? art.ArtBitmap : PlaylistArt2; - } - else PlaylistArt2 = PlaylistArt; - - if (distinctAlbums.Count > 3) - { - var art = await _albumArtService.GetAlbumArtAsync(distinctAlbums[2].File, false); - PlaylistArt3 = art != null ? art.ArtBitmap : PlaylistArt3; - } - else PlaylistArt3 = PlaylistArt2; - - ArtLoaded = true; - }); + // Get album art for three albums to display in the playlist view + Random r = new Random(); + var distinctAlbums = Source.GroupBy(tr => tr.File.Album).Select(tr => tr.First()).OrderBy((item) => r.Next()).ToList(); + + if (distinctAlbums.Count > 1) + { + var art = await _albumArtService.GetAlbumArtAsync(distinctAlbums[0].File, true); + PlaylistArt = art != null ? art.ArtBitmap : PlaylistArt; + + DominantColor = (art?.DominantColor?.Color).GetValueOrDefault(); + IsLight = (!art?.DominantColor?.IsDark).GetValueOrDefault(); + } + + if (distinctAlbums.Count > 2) + { + var art = await _albumArtService.GetAlbumArtAsync(distinctAlbums[1].File, false); + PlaylistArt2 = art != null ? art.ArtBitmap : PlaylistArt2; + } + else PlaylistArt2 = PlaylistArt; + + if (distinctAlbums.Count > 3) + { + var art = await _albumArtService.GetAlbumArtAsync(distinctAlbums[2].File, false); + PlaylistArt3 = art != null ? art.ArtBitmap : PlaylistArt3; + } + else PlaylistArt3 = PlaylistArt2; + + ArtLoaded = true; + }); + } } private async void Source_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) diff --git a/Sources/Stylophone/Package.appxmanifest b/Sources/Stylophone/Package.appxmanifest index e7c01844..d4ee0377 100644 --- a/Sources/Stylophone/Package.appxmanifest +++ b/Sources/Stylophone/Package.appxmanifest @@ -12,7 +12,7 @@ + Version="2.0.4.0" /> diff --git a/Sources/Stylophone/Package.tt b/Sources/Stylophone/Package.tt index f4d38056..7a1fabd8 100644 --- a/Sources/Stylophone/Package.tt +++ b/Sources/Stylophone/Package.tt @@ -2,7 +2,7 @@ <#@ output extension=".appxmanifest" #> <#@ parameter type="System.String" name="BuildConfiguration" #> <# - string version = "2.0.3.0"; + string version = "2.0.4.0"; // Get configuration name at Build time string configName = Host.ResolveParameterValue("-", "-", "BuildConfiguration"); From 40bcdc0ceef0a6dc640c7f67ca83bc36bcc0d7db Mon Sep 17 00:00:00 2001 From: Difegue Date: Thu, 9 Sep 2021 18:21:19 +0200 Subject: [PATCH 03/15] Fix a potential crash with server info string (Seen through App Center) --- Sources/Stylophone.Common/ViewModels/SettingsViewModel.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Sources/Stylophone.Common/ViewModels/SettingsViewModel.cs b/Sources/Stylophone.Common/ViewModels/SettingsViewModel.cs index 28b9c89a..e4bc7a5c 100644 --- a/Sources/Stylophone.Common/ViewModels/SettingsViewModel.cs +++ b/Sources/Stylophone.Common/ViewModels/SettingsViewModel.cs @@ -303,12 +303,15 @@ private async Task UpdateServerVersionAsync() // Build info string var outputs = await _mpdService.SafelySendCommandAsync(new OutputsCommand()); + var songs = response.ContainsKey("songs") ? response["songs"] : "??"; + var albums = response.ContainsKey("albums") ? response["albums"] : "??"; + if (outputs != null) { var outputString = outputs.Select(o => o.Plugin).Aggregate((s, s2) => $"{s}, {s2}"); ServerInfo = $"MPD Protocol {_mpdService.Version}\n" + - $"{response["songs"]} Songs, {response["albums"]} Albums\n" + + $"{songs} Songs, {albums} Albums\n" + $"Database last updated {lastUpdatedDb}\n" + $"Outputs available: {outputString}"; @@ -320,7 +323,7 @@ private async Task UpdateServerVersionAsync() else { ServerInfo = $"MPD Protocol {_mpdService.Version}\n" + - $"{response["songs"]} Songs, {response["albums"]} Albums\n" + + $"{songs} Songs, {albums} Albums\n" + $"Database last updated {lastUpdatedDb}"; } From 32d6745a65ac4a714b19f18ead759beafb3bc0e5 Mon Sep 17 00:00:00 2001 From: Difegue Date: Thu, 9 Sep 2021 18:58:44 +0200 Subject: [PATCH 04/15] Switch Local Playback to use LibVLCSharp Should make the stuff actually work on Xbox now. --- .../Interfaces/IInteropService.cs | 4 --- .../Stylophone.Common.csproj | 1 + .../ViewModels/LocalPlaybackViewModel.cs | 29 +++++++++++++--- Sources/Stylophone/App.xaml.cs | 3 ++ Sources/Stylophone/Services/DialogService.cs | 2 +- Sources/Stylophone/Services/InteropService.cs | 33 ++----------------- Sources/Stylophone/Stylophone.csproj | 3 ++ 7 files changed, 35 insertions(+), 40 deletions(-) diff --git a/Sources/Stylophone.Common/Interfaces/IInteropService.cs b/Sources/Stylophone.Common/Interfaces/IInteropService.cs index 6e493f1e..8842a0a9 100644 --- a/Sources/Stylophone.Common/Interfaces/IInteropService.cs +++ b/Sources/Stylophone.Common/Interfaces/IInteropService.cs @@ -34,10 +34,6 @@ public interface IInteropService Version GetAppVersion(); Task SetThemeAsync(Theme param); - void PlayStream(Uri streamUri); - void StopStream(); - void SetStreamVolume(double volume); - string GetIcon(PlaybackIcon volumeFull); Task OpenStoreReviewUrlAsync(); diff --git a/Sources/Stylophone.Common/Stylophone.Common.csproj b/Sources/Stylophone.Common/Stylophone.Common.csproj index 1d1f5146..84059803 100644 --- a/Sources/Stylophone.Common/Stylophone.Common.csproj +++ b/Sources/Stylophone.Common/Stylophone.Common.csproj @@ -6,6 +6,7 @@ + diff --git a/Sources/Stylophone.Common/ViewModels/LocalPlaybackViewModel.cs b/Sources/Stylophone.Common/ViewModels/LocalPlaybackViewModel.cs index 4687e55d..b628b720 100644 --- a/Sources/Stylophone.Common/ViewModels/LocalPlaybackViewModel.cs +++ b/Sources/Stylophone.Common/ViewModels/LocalPlaybackViewModel.cs @@ -1,4 +1,5 @@ using System; +using LibVLCSharp.Shared; using Stylophone.Common.Interfaces; using Stylophone.Common.Services; using Stylophone.Localization.Strings; @@ -12,6 +13,8 @@ public class LocalPlaybackViewModel : ViewModelBase private SettingsViewModel _settingsVm; private MPDConnectionService _mpdService; + private LibVLC _vlcCore; + private MediaPlayer _mediaPlayer; private string _serverHost; public LocalPlaybackViewModel(SettingsViewModel settingsVm, MPDConnectionService mpdService, IInteropService interopService, INotificationService notificationService, IDispatcherService dispatcherService): base(dispatcherService) @@ -47,12 +50,23 @@ private set { Set(ref _isEnabled, value); - if (!value) + if (value) + { + if (_vlcCore == null) + _vlcCore = new LibVLC(); + + _mediaPlayer?.Dispose(); + _mediaPlayer = new MediaPlayer(_vlcCore); + } + else { // Reset IsPlaying = false; Volume = 0; _previousVolume = 10; + + _vlcCore?.Dispose(); + _vlcCore = null; } } @@ -80,7 +94,8 @@ public double Volume if (!IsPlaying && value != 0) IsPlaying = true; - _interopService.SetStreamVolume(value); + if (_mediaPlayer != null) + _mediaPlayer.Volume = (int)value; if ((int)value == 0) { @@ -140,13 +155,17 @@ private void UpdatePlayback() { if (IsPlaying && _serverHost != null && _mpdService.IsConnected) { - var urlString = "http://" + _serverHost + ":8000/mpd.ogg"; + var urlString = "http://" + _serverHost + ":8000"; var streamUrl = new Uri(urlString); - _interopService.PlayStream(streamUrl); + var media = new Media(_vlcCore, streamUrl); + + _mediaPlayer.Volume = (int)_volume; + _mediaPlayer.Media = media; + _mediaPlayer.Play(); } else { - _interopService.StopStream(); + _mediaPlayer?.Stop(); } } catch (Exception e) diff --git a/Sources/Stylophone/App.xaml.cs b/Sources/Stylophone/App.xaml.cs index bcdc8470..aebffdca 100644 --- a/Sources/Stylophone/App.xaml.cs +++ b/Sources/Stylophone/App.xaml.cs @@ -63,6 +63,8 @@ protected override async void OnLaunched(LaunchActivatedEventArgs args) // Analytics SystemInformation.Instance.TrackAppUse(args); +#if DEBUG +#else var enableAnalytics = Ioc.Default.GetRequiredService().GetValue(nameof(SettingsViewModel.EnableAnalytics), true); if (enableAnalytics) { @@ -70,6 +72,7 @@ protected override async void OnLaunched(LaunchActivatedEventArgs args) AppCenter.Start("f2193544-6a38-42f6-92bd-69964bc3a0e8", typeof(Analytics), typeof(Crashes)); } +#endif var viewTitleBar = ApplicationView.GetForCurrentView().TitleBar; viewTitleBar.ButtonBackgroundColor = Colors.Transparent; diff --git a/Sources/Stylophone/Services/DialogService.cs b/Sources/Stylophone/Services/DialogService.cs index f67bfc74..fd78844b 100644 --- a/Sources/Stylophone/Services/DialogService.cs +++ b/Sources/Stylophone/Services/DialogService.cs @@ -51,7 +51,7 @@ public async Task ShowFirstRunDialogIfAppropriateAsync() { await _dispatcherService.ExecuteOnUIThreadAsync(async () => { - if (SystemInformation.Instance.IsFirstRun || SystemInformation.Instance.IsAppUpdated && !shown) + if (SystemInformation.Instance.IsFirstRun && !shown) { shown = true; var dialog = new FirstRunDialog(); diff --git a/Sources/Stylophone/Services/InteropService.cs b/Sources/Stylophone/Services/InteropService.cs index ef6b9357..3f381b23 100644 --- a/Sources/Stylophone/Services/InteropService.cs +++ b/Sources/Stylophone/Services/InteropService.cs @@ -12,9 +12,6 @@ using Stylophone.Common.ViewModels; using System.IO; using Windows.ApplicationModel; -using Windows.Media.Core; -using Windows.Media.Playback; -using Windows.Services.Store; using Microsoft.Toolkit.Uwp.Helpers; namespace Stylophone.Services @@ -23,7 +20,6 @@ public class InteropService : IInteropService { private ApplicationTheme _appTheme; private SystemMediaControlsService _smtcService; - private MediaPlayer _mediaPlayer; public InteropService(SystemMediaControlsService smtcService) { @@ -112,15 +108,15 @@ private void UpdateTitleBar(ElementTheme theme) switch (theme) { case ElementTheme.Default: - color = ((Color)Application.Current.Resources["SystemBaseHighColor"]); + color = (Color)Application.Current.Resources["SystemBaseHighColor"]; break; case ElementTheme.Light: if (_appTheme == ApplicationTheme.Light) { color = ((Color)Application.Current.Resources["SystemBaseHighColor"]); } - else { color = ((Color)Application.Current.Resources["SystemAltHighColor"]); } + else { color = (Color)Application.Current.Resources["SystemAltHighColor"]; } break; case ElementTheme.Dark: if (_appTheme == ApplicationTheme.Light) { color = ((Color)Application.Current.Resources["SystemAltHighColor"]); } - else { color = ((Color)Application.Current.Resources["SystemBaseHighColor"]); } + else { color = (Color)Application.Current.Resources["SystemBaseHighColor"]; } break; default: break; @@ -158,29 +154,6 @@ public string GetIcon(PlaybackIcon icon) _ => "?", }; } - public void PlayStream(Uri streamUri) - { - if (_mediaPlayer == null) - { - _mediaPlayer = new MediaPlayer(); - _mediaPlayer.RealTimePlayback = true; - _mediaPlayer.CommandManager.IsEnabled = false; // Disable SMTC integration, as we use it to control the MPD server instead - } - - _mediaPlayer.Source = MediaSource.CreateFromUri(streamUri); - _mediaPlayer.Play(); - } - - public void StopStream() - { - _mediaPlayer?.Pause(); - } - - public void SetStreamVolume(double volume) - { - if (_mediaPlayer != null) - _mediaPlayer.Volume = volume / 100; - } public async Task OpenStoreReviewUrlAsync() { diff --git a/Sources/Stylophone/Stylophone.csproj b/Sources/Stylophone/Stylophone.csproj index dfe11b68..4d34568a 100644 --- a/Sources/Stylophone/Stylophone.csproj +++ b/Sources/Stylophone/Stylophone.csproj @@ -172,6 +172,9 @@ 2.80.2 + + 3.3.1 + 1.1.0 From 4230fea5535007041bff24206d88bc68b3637b1e Mon Sep 17 00:00:00 2001 From: Difegue Date: Thu, 9 Sep 2021 19:19:03 +0200 Subject: [PATCH 05/15] Bring back Local Playback on iOS as well VLC works about a thousand times better than AVPlayer, huh --- .../Stylophone.iOS/Services/InteropService.cs | 25 ---------- Sources/Stylophone.iOS/Stylophone.iOS.csproj | 3 ++ .../ViewControllers/SettingsViewController.cs | 5 +- .../SettingsViewController.designer.cs | 18 +++++-- .../Stylophone.iOS/Views/Settings.storyboard | 49 ++++++++++++++++--- 5 files changed, 61 insertions(+), 39 deletions(-) diff --git a/Sources/Stylophone.iOS/Services/InteropService.cs b/Sources/Stylophone.iOS/Services/InteropService.cs index 4e4dd98e..6a6dc94c 100644 --- a/Sources/Stylophone.iOS/Services/InteropService.cs +++ b/Sources/Stylophone.iOS/Services/InteropService.cs @@ -7,13 +7,11 @@ using UIKit; using SkiaSharp.Views.iOS; using Foundation; -using AVFoundation; namespace Stylophone.iOS.Services { public class InteropService: IInteropService { - private AVPlayer _mediaPlayer; public InteropService( ) { @@ -86,29 +84,6 @@ public string GetIcon(PlaybackIcon icon) }; } - public void PlayStream(Uri streamUri) - { - if (_mediaPlayer == null || _mediaPlayer.Status == AVPlayerStatus.Failed) - _mediaPlayer = new AVPlayer(); - - var playerItem = new AVPlayerItem(new NSUrl(streamUri.AbsoluteUri)); - _mediaPlayer.ReplaceCurrentItemWithPlayerItem(playerItem); - - _mediaPlayer.AutomaticallyWaitsToMinimizeStalling = false; - _mediaPlayer.Play(); - } - - public void StopStream() - { - _mediaPlayer?.Pause(); - } - - public void SetStreamVolume(double volume) - { - if (_mediaPlayer != null) - _mediaPlayer.Volume = (float)volume / 100; - } - public Task OpenStoreReviewUrlAsync() { try diff --git a/Sources/Stylophone.iOS/Stylophone.iOS.csproj b/Sources/Stylophone.iOS/Stylophone.iOS.csproj index 9044db2e..d72aedb1 100644 --- a/Sources/Stylophone.iOS/Stylophone.iOS.csproj +++ b/Sources/Stylophone.iOS/Stylophone.iOS.csproj @@ -225,6 +225,9 @@ 1.0.0 + + 3.3.10 + diff --git a/Sources/Stylophone.iOS/ViewControllers/SettingsViewController.cs b/Sources/Stylophone.iOS/ViewControllers/SettingsViewController.cs index a28bfacc..af440f04 100644 --- a/Sources/Stylophone.iOS/ViewControllers/SettingsViewController.cs +++ b/Sources/Stylophone.iOS/ViewControllers/SettingsViewController.cs @@ -48,6 +48,7 @@ public override string TitleForFooter(UITableView tableView, nint section) { return (int)section switch { + 0 => Resources.SettingsLocalPlaybackText, 1 => Resources.SettingsClearCacheDescription, 2 => Resources.SettingsApplyOnRestart, _ => "", @@ -76,8 +77,8 @@ public override void ViewDidLoad() Binder.Bind(ServerConnectionSuccess, "hidden", nameof(ViewModel.IsServerValid), valueTransformer: negateBoolTransformer); - //Binder.Bind(LocalPlaybackToggle, "enabled", nameof(ViewModel.IsStreamingAvailable)); - //Binder.Bind(LocalPlaybackToggle, "on", nameof(ViewModel.IsLocalPlaybackEnabled), true); + Binder.Bind(LocalPlaybackToggle, "enabled", nameof(ViewModel.IsStreamingAvailable)); + Binder.Bind(LocalPlaybackToggle, "on", nameof(ViewModel.IsLocalPlaybackEnabled), true); Binder.Bind(AnalyticsToggle, "on", nameof(ViewModel.EnableAnalytics), true); Binder.Bind(VersionLabel, "text", nameof(ViewModel.VersionDescription)); diff --git a/Sources/Stylophone.iOS/ViewControllers/SettingsViewController.designer.cs b/Sources/Stylophone.iOS/ViewControllers/SettingsViewController.designer.cs index 0d82b9ce..e5e068b1 100644 --- a/Sources/Stylophone.iOS/ViewControllers/SettingsViewController.designer.cs +++ b/Sources/Stylophone.iOS/ViewControllers/SettingsViewController.designer.cs @@ -21,6 +21,9 @@ partial class SettingsViewController [Outlet] UIKit.UIButton GithubButton { get; set; } + [Outlet] + UIKit.UISwitch LocalPlaybackToggle { get; set; } + [Outlet] UIKit.UIButton RateButton { get; set; } @@ -106,16 +109,16 @@ void ReleaseDesignerOutlets () ServerInfoLabel = null; } - if (ServerPortField != null) { - ServerPortField.Dispose (); - ServerPortField = null; - } - if (ServerPasswordField != null) { ServerPasswordField.Dispose (); ServerPasswordField = null; } + if (ServerPortField != null) { + ServerPortField.Dispose (); + ServerPortField = null; + } + if (UpdateDatabaseButton != null) { UpdateDatabaseButton.Dispose (); UpdateDatabaseButton = null; @@ -125,6 +128,11 @@ void ReleaseDesignerOutlets () VersionLabel.Dispose (); VersionLabel = null; } + + if (LocalPlaybackToggle != null) { + LocalPlaybackToggle.Dispose (); + LocalPlaybackToggle = null; + } } } } diff --git a/Sources/Stylophone.iOS/Views/Settings.storyboard b/Sources/Stylophone.iOS/Views/Settings.storyboard index 41a4a58a..d2223334 100644 --- a/Sources/Stylophone.iOS/Views/Settings.storyboard +++ b/Sources/Stylophone.iOS/Views/Settings.storyboard @@ -16,7 +16,7 @@ - + @@ -188,12 +188,46 @@ + + + + + + + + + + + + + + + + + + + + + + + - + @@ -211,7 +245,7 @@ - + @@ -233,7 +267,7 @@ - + @@ -269,7 +303,7 @@ - + @@ -321,7 +355,7 @@ - + @@ -340,7 +374,7 @@ - + @@ -370,6 +404,7 @@ + From f7e8aa84cc159b80a210a810b8613d0595fe93fe Mon Sep 17 00:00:00 2001 From: Difegue Date: Thu, 9 Sep 2021 19:32:30 +0200 Subject: [PATCH 06/15] Add a section in iOS Settings --- .../ViewControllers/SettingsViewController.cs | 13 ++++++------ .../Stylophone.iOS/Views/Settings.storyboard | 20 +++++++++++-------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/Sources/Stylophone.iOS/ViewControllers/SettingsViewController.cs b/Sources/Stylophone.iOS/ViewControllers/SettingsViewController.cs index af440f04..394c528a 100644 --- a/Sources/Stylophone.iOS/ViewControllers/SettingsViewController.cs +++ b/Sources/Stylophone.iOS/ViewControllers/SettingsViewController.cs @@ -37,9 +37,10 @@ public override string TitleForHeader(UITableView tableView, nint section) return (int)section switch { 0 => Resources.SettingsServer, - 1 => Resources.SettingsDatabase, - 2 => Resources.SettingsAnalytics, - 3 => Resources.SettingsAbout, + 1 => Resources.SettingsLocalPlaybackHeader, + 2 => Resources.SettingsDatabase, + 3 => Resources.SettingsAnalytics, + 4 => Resources.SettingsAbout, _ => "", }; } @@ -48,9 +49,9 @@ public override string TitleForFooter(UITableView tableView, nint section) { return (int)section switch { - 0 => Resources.SettingsLocalPlaybackText, - 1 => Resources.SettingsClearCacheDescription, - 2 => Resources.SettingsApplyOnRestart, + 1 => Resources.SettingsLocalPlaybackText, + 2 => Resources.SettingsClearCacheDescription, + 3 => Resources.SettingsApplyOnRestart, _ => "", }; } diff --git a/Sources/Stylophone.iOS/Views/Settings.storyboard b/Sources/Stylophone.iOS/Views/Settings.storyboard index d2223334..031bb41a 100644 --- a/Sources/Stylophone.iOS/Views/Settings.storyboard +++ b/Sources/Stylophone.iOS/Views/Settings.storyboard @@ -16,7 +16,7 @@ - + @@ -188,8 +188,12 @@ + + + + - + @@ -227,7 +231,7 @@ - + @@ -245,7 +249,7 @@ - + @@ -267,7 +271,7 @@ - + @@ -303,7 +307,7 @@ - + @@ -355,7 +359,7 @@ - + @@ -374,7 +378,7 @@ - + From e4bdd53ec7acc5806c2eb58fa6a37ac520ea9656 Mon Sep 17 00:00:00 2001 From: Difegue Date: Fri, 10 Sep 2021 00:12:26 +0200 Subject: [PATCH 07/15] Small fixes + Use binding for albumart in Album view --- .../ViewModels/PlaylistViewModel.cs | 1 + Sources/Stylophone.iOS/AppDelegate.cs | 3 ++ .../Helpers/TrackTableViewDataSource.cs | 16 +++++++++- .../AlbumDetailViewController.cs | 32 ++++++------------- .../Views/AlbumDetail.storyboard | 2 -- 5 files changed, 29 insertions(+), 25 deletions(-) diff --git a/Sources/Stylophone.Common/ViewModels/PlaylistViewModel.cs b/Sources/Stylophone.Common/ViewModels/PlaylistViewModel.cs index 0b949fef..42eeb1fc 100644 --- a/Sources/Stylophone.Common/ViewModels/PlaylistViewModel.cs +++ b/Sources/Stylophone.Common/ViewModels/PlaylistViewModel.cs @@ -240,6 +240,7 @@ public async Task LoadDataAsync(string playlistName) { var placeholder = await _interop.GetPlaceholderImageAsync(); + ArtLoaded = false; PlaylistArt = placeholder; PlaylistArt2 = placeholder; PlaylistArt3 = placeholder; diff --git a/Sources/Stylophone.iOS/AppDelegate.cs b/Sources/Stylophone.iOS/AppDelegate.cs index 494c7e2b..ac0da911 100644 --- a/Sources/Stylophone.iOS/AppDelegate.cs +++ b/Sources/Stylophone.iOS/AppDelegate.cs @@ -86,6 +86,8 @@ await Ioc.Default.GetRequiredService().ExecuteOnUIThreadAsyn await Ioc.Default.GetRequiredService().ShowRateAppDialogIfAppropriateAsync(); }); +#if DEBUG +#else // Analytics var enableAnalytics = storageService.GetValue(nameof(SettingsViewModel.EnableAnalytics), true); if (enableAnalytics) @@ -94,6 +96,7 @@ await Ioc.Default.GetRequiredService().ExecuteOnUIThreadAsyn AppCenter.Start("90b62f5a-2448-4ef1-81ca-3fb807a5b126", typeof(Analytics), typeof(Crashes)); } +#endif } // UISceneSession Lifecycle diff --git a/Sources/Stylophone.iOS/Helpers/TrackTableViewDataSource.cs b/Sources/Stylophone.iOS/Helpers/TrackTableViewDataSource.cs index a41f839d..0fd759a7 100644 --- a/Sources/Stylophone.iOS/Helpers/TrackTableViewDataSource.cs +++ b/Sources/Stylophone.iOS/Helpers/TrackTableViewDataSource.cs @@ -27,6 +27,15 @@ public TrackTableViewDataSource(IntPtr handle) : base(handle) { } + /// + /// Create a UITableViewDataSource/UITableViewDelegate for a given source of TrackViewModels. + /// + /// The tableView hosting this source/delegate + /// The source TrackViewModels + /// A factory for row context menus + /// A factory for row swipe actions + /// Whether you can select multiple rows + /// Optional scrollHandler public TrackTableViewDataSource(UITableView tableView, ObservableCollection source, Func contextMenuFactory, Func swipeActionFactory, bool canSelectRows = false, Action scrollHandler = null) @@ -37,7 +46,8 @@ public TrackTableViewDataSource(UITableView tableView, ObservableCollection UIApplication.SharedApplication.InvokeOnMainThread( + () => UpdateUITableView(s,e)); _tableView.AllowsMultipleSelection = canSelectRows; } @@ -84,6 +94,10 @@ public nint RowsInSection(UITableView tableView, nint section) public UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath) { var cell = tableView.DequeueReusableCell("trackCell") as TrackViewCell; + + if (_sourceCollection.Count < indexPath.Row) + return cell; // Safety check + var trackViewModel = _sourceCollection[indexPath.Row]; cell.Configure(indexPath.Row, trackViewModel); diff --git a/Sources/Stylophone.iOS/ViewControllers/AlbumDetailViewController.cs b/Sources/Stylophone.iOS/ViewControllers/AlbumDetailViewController.cs index e35f2ce4..472f269e 100644 --- a/Sources/Stylophone.iOS/ViewControllers/AlbumDetailViewController.cs +++ b/Sources/Stylophone.iOS/ViewControllers/AlbumDetailViewController.cs @@ -12,6 +12,7 @@ using CoreGraphics; using SkiaSharp.Views.iOS; using System.ComponentModel; +using SkiaSharp; namespace Stylophone.iOS.ViewControllers { @@ -78,15 +79,8 @@ void IPreparableViewController.Prepare(object parameter) { TableView.ScrollRectToVisible(new CGRect(0, 0, 1, 1), false); - if (ViewModel.Item != null) - ViewModel.Item.PropertyChanged -= UpdateAlbumArt; - var album = parameter as AlbumViewModel; ViewModel.Initialize(album); - ViewModel.Item.PropertyChanged += UpdateAlbumArt; - - if (ViewModel.Item.AlbumArtLoaded) - SetAlbumArt(); // Reset label texts AlbumArtists.Text = "..."; @@ -109,6 +103,15 @@ void IPreparableViewController.Prepare(object parameter) _settingsBtn = CreateSettingsButton(); + var imageConverter = NSValueTransformer.GetValueTransformer(nameof(SkiaToUIImageValueTransformer)); + var colorConverter = NSValueTransformer.GetValueTransformer(nameof(SkiaToUIColorValueTransformer)); + + _albumBinder.Bind(AlbumArt, "image", nameof(album.AlbumArt), valueTransformer: imageConverter); + _albumBinder.Bind(BackgroundArt, "image", nameof(album.AlbumArt), valueTransformer: imageConverter); + _albumBinder.Bind(PlayButton, "backgroundColor", nameof(album.DominantColor), valueTransformer: colorConverter); + _albumBinder.Bind(AddToQueueButton, "backgroundColor", nameof(album.DominantColor), valueTransformer: colorConverter); + _albumBinder.Bind(PlaylistButton, "backgroundColor", nameof(album.DominantColor), valueTransformer: colorConverter); + // Add radius to AlbumArt AlbumArt.Layer.CornerRadius = 8; AlbumArt.Layer.MasksToBounds = true; @@ -119,21 +122,6 @@ void IPreparableViewController.Prepare(object parameter) ArtContainer.Layer.ShadowRadius = 4; } - private void UpdateAlbumArt(object sender, PropertyChangedEventArgs e) - { - if (e.PropertyName == nameof(ViewModel.Item.AlbumArt)) - SetAlbumArt(); - } - - private void SetAlbumArt() - { - AlbumArt.Image = ViewModel.Item.AlbumArt.ToUIImage(); - BackgroundArt.Image = ViewModel.Item.AlbumArt.ToUIImage(); - PlayButton.BackgroundColor = ViewModel.Item.DominantColor.ToUIColor(); - AddToQueueButton.BackgroundColor = ViewModel.Item.DominantColor.ToUIColor(); - PlaylistButton.BackgroundColor = ViewModel.Item.DominantColor.ToUIColor(); - } - private UIMenu GetRowContextMenu(NSIndexPath indexPath) { // The common commands take a list of objects diff --git a/Sources/Stylophone.iOS/Views/AlbumDetail.storyboard b/Sources/Stylophone.iOS/Views/AlbumDetail.storyboard index e76cf41c..a7d0acb4 100644 --- a/Sources/Stylophone.iOS/Views/AlbumDetail.storyboard +++ b/Sources/Stylophone.iOS/Views/AlbumDetail.storyboard @@ -335,14 +335,12 @@ - - From 94f1a5dfd02dbc122aaba241fbde8c635f091816 Mon Sep 17 00:00:00 2001 From: Difegue Date: Fri, 10 Sep 2021 00:16:02 +0200 Subject: [PATCH 08/15] Add Playlist view --- .../Helpers/TrackTableViewDataSource.cs | 2 +- .../Services/NavigationService.cs | 2 +- Sources/Stylophone.iOS/Stylophone.iOS.csproj | 5 + .../ViewControllers/PlaylistViewController.cs | 176 ++++++++ .../PlaylistViewController.designer.cs | 106 +++++ .../Stylophone.iOS/Views/Playlist.storyboard | 386 ++++++++++++++++++ 6 files changed, 675 insertions(+), 2 deletions(-) create mode 100644 Sources/Stylophone.iOS/ViewControllers/PlaylistViewController.cs create mode 100644 Sources/Stylophone.iOS/ViewControllers/PlaylistViewController.designer.cs create mode 100644 Sources/Stylophone.iOS/Views/Playlist.storyboard diff --git a/Sources/Stylophone.iOS/Helpers/TrackTableViewDataSource.cs b/Sources/Stylophone.iOS/Helpers/TrackTableViewDataSource.cs index 0fd759a7..d0a8de7f 100644 --- a/Sources/Stylophone.iOS/Helpers/TrackTableViewDataSource.cs +++ b/Sources/Stylophone.iOS/Helpers/TrackTableViewDataSource.cs @@ -95,7 +95,7 @@ public UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath) { var cell = tableView.DequeueReusableCell("trackCell") as TrackViewCell; - if (_sourceCollection.Count < indexPath.Row) + if (_sourceCollection.Count <= indexPath.Row) return cell; // Safety check var trackViewModel = _sourceCollection[indexPath.Row]; diff --git a/Sources/Stylophone.iOS/Services/NavigationService.cs b/Sources/Stylophone.iOS/Services/NavigationService.cs index a28683eb..91c00bd0 100644 --- a/Sources/Stylophone.iOS/Services/NavigationService.cs +++ b/Sources/Stylophone.iOS/Services/NavigationService.cs @@ -20,7 +20,7 @@ public class NavigationService : NavigationServiceBase { typeof(PlaybackViewModelBase), UIStoryboard.FromName("NowPlaying", null) }, { typeof(SearchResultsViewModel), UIStoryboard.FromName("SearchResults", null) }, { typeof(FoldersViewModel), UIStoryboard.FromName("Folders", null) }, - //{ typeof(PlaylistViewModel), typeof(PlaylistPage) }, + { typeof(PlaylistViewModel), UIStoryboard.FromName("Playlist", null) }, { typeof(LibraryViewModel), UIStoryboard.FromName("Library", null) } }; diff --git a/Sources/Stylophone.iOS/Stylophone.iOS.csproj b/Sources/Stylophone.iOS/Stylophone.iOS.csproj index d72aedb1..b48956d5 100644 --- a/Sources/Stylophone.iOS/Stylophone.iOS.csproj +++ b/Sources/Stylophone.iOS/Stylophone.iOS.csproj @@ -142,6 +142,10 @@ + + + PlaylistViewController.cs + @@ -156,6 +160,7 @@ + false diff --git a/Sources/Stylophone.iOS/ViewControllers/PlaylistViewController.cs b/Sources/Stylophone.iOS/ViewControllers/PlaylistViewController.cs new file mode 100644 index 00000000..520eaab4 --- /dev/null +++ b/Sources/Stylophone.iOS/ViewControllers/PlaylistViewController.cs @@ -0,0 +1,176 @@ +// This file has been autogenerated from a class added in the UI designer. + +using System; + +using Strings = Stylophone.Localization.Strings.Resources; +using Stylophone.Common.ViewModels; +using Stylophone.iOS.Helpers; +using UIKit; +using Microsoft.Toolkit.Mvvm.DependencyInjection; +using CoreGraphics; +using System.Linq; +using Foundation; +using System.Collections.Generic; +using System.ComponentModel; +using SkiaSharp.Views.iOS; +using System.Threading.Tasks; +using SkiaSharp; +using Stylophone.iOS.Services; + +namespace Stylophone.iOS.ViewControllers +{ + public partial class PlaylistViewController : UITableViewController, IViewController + { + public PlaylistViewController(IntPtr handle) : base(handle) + { + } + + public PlaylistViewModel ViewModel => Ioc.Default.GetRequiredService(); + public PropertyBinder Binder => new(ViewModel); + + private PropertyBinder _albumBinder; + private UIBarButtonItem _settingsBtn; + + void IPreparableViewController.Prepare(object parameter) + { + TableView.ScrollRectToVisible(new CGRect(0, 0, 1, 1), false); + + // Reset label texts + PlaylistArtists.Text = "..."; + + Task.Run(async () => + { + try + { + await ViewModel.LoadDataAsync(parameter as string); + } + catch (Exception e) + { + Ioc.Default.GetRequiredService().ShowErrorNotification(e); + } + }); + } + + public override void AwakeFromNib() + { + base.AwakeFromNib(); + TraitCollectionDidChange(null); + NavigationItem.LargeTitleDisplayMode = UINavigationItemLargeTitleDisplayMode.Never; + + _settingsBtn = CreateSettingsButton(); + + var trackDataSource = new TrackTableViewDataSource(TableView, ViewModel.Source, GetRowContextMenu, GetRowSwipeActions, true, OnScroll); + TableView.DataSource = trackDataSource; + TableView.Delegate = trackDataSource; + + Binder.Bind(EmptyView, "hidden", nameof(ViewModel.IsSourceEmpty), + valueTransformer: NSValueTransformer.GetValueTransformer(nameof(ReverseBoolValueTransformer))); + Binder.Bind(PlaylistInfo, "text", nameof(ViewModel.PlaylistInfo)); + + Binder.Bind(PlaylistTitle, "text", nameof(ViewModel.Name)); + Binder.Bind(PlaylistArtists, "text", nameof(ViewModel.Artists)); + Binder.Bind(AlbumArtLoadingIndicator, "animating", nameof(ViewModel.ArtLoaded), + valueTransformer: NSValueTransformer.GetValueTransformer(nameof(ReverseBoolValueTransformer))); + + Binder.BindButton(PlayButton, Strings.ContextMenuPlay, ViewModel.PlayPlaylistCommand); + PlayButton.Layer.CornerRadius = 8; + Binder.BindButton(AddToQueueButton, Strings.ContextMenuAddToQueue, ViewModel.LoadPlaylistCommand); + AddToQueueButton.Layer.CornerRadius = 8; + Binder.BindButton(DeleteButton, Strings.ContextMenuDeletePlaylist, ViewModel.RemovePlaylistCommand); + DeleteButton.Layer.CornerRadius = 8; + + var imageConverter = NSValueTransformer.GetValueTransformer(nameof(SkiaToUIImageValueTransformer)); + var colorConverter = NSValueTransformer.GetValueTransformer(nameof(SkiaToUIColorValueTransformer)); + + Binder.Bind(AlbumArt, "image", nameof(ViewModel.PlaylistArt), valueTransformer: imageConverter); + Binder.Bind(BackgroundArt, "image", nameof(ViewModel.PlaylistArt), valueTransformer: imageConverter); + Binder.Bind(PlayButton, "backgroundColor", nameof(ViewModel.DominantColor), valueTransformer: colorConverter); + Binder.Bind(AddToQueueButton, "backgroundColor", nameof(ViewModel.DominantColor), valueTransformer: colorConverter); + + // Add radius to AlbumArt + AlbumArt.Layer.CornerRadius = 8; + AlbumArt.Layer.MasksToBounds = true; + + ArtContainer.Layer.ShadowColor = UIColor.Black.CGColor; + ArtContainer.Layer.ShadowOpacity = 0.5F; + ArtContainer.Layer.ShadowOffset = new CGSize(0, 0); + ArtContainer.Layer.ShadowRadius = 4; + } + + private void OnScroll(UIScrollView scrollView) + { + if (scrollView.ContentOffset.Y > 192) + { + Title = ViewModel?.Name; + NavigationItem.RightBarButtonItem = _settingsBtn; + } + else + { + Title = ""; + NavigationItem.RightBarButtonItem = null; + } + } + + public override void TraitCollectionDidChange(UITraitCollection previousTraitCollection) + { + base.TraitCollectionDidChange(previousTraitCollection); + + var headerView = TableView.TableHeaderView; + CGRect newFrame = headerView.Frame; + if (TraitCollection.VerticalSizeClass == UIUserInterfaceSizeClass.Compact) + { + newFrame.Height = 242; + } + else + { + newFrame.Height = 296; + } + headerView.Frame = newFrame; + TableView.TableHeaderView = headerView; + } + + private UIMenu GetRowContextMenu(NSIndexPath indexPath) + { + // The common commands take a list of objects + var trackList = new List(); + + if (TableView.IndexPathsForSelectedRows == null) + { + trackList.Add(ViewModel?.Source[indexPath.Row]); + } + else + { + trackList = TableView.IndexPathsForSelectedRows.Select(indexPath => ViewModel?.Source[indexPath.Row]) + .ToList(); + } + + var queueAction = Binder.GetCommandAction(Strings.ContextMenuAddToQueue, "plus", ViewModel.AddToQueueCommand, trackList); + var albumAction = Binder.GetCommandAction(Strings.ContextMenuViewAlbum, "opticaldisc", ViewModel.ViewAlbumCommand, trackList); + var removeAction = Binder.GetCommandAction(Strings.ContextMenuRemoveFromPlaylist, "minus", ViewModel.RemoveTrackFromPlaylistCommand, trackList); + + return UIMenu.Create(new[] { queueAction, albumAction, removeAction }); + } + + private UISwipeActionsConfiguration GetRowSwipeActions(NSIndexPath indexPath, bool isLeadingSwipe) + { + // The common commands take a list of objects + var trackList = new List(); + trackList.Add(ViewModel?.Source[indexPath.Row]); + + var action = isLeadingSwipe ? Binder.GetContextualAction(UIContextualActionStyle.Normal, Strings.ContextMenuAddToQueue, ViewModel.AddToQueueCommand, trackList) + : Binder.GetContextualAction(UIContextualActionStyle.Destructive, Strings.ContextMenuRemoveFromPlaylist, ViewModel.RemoveTrackFromPlaylistCommand, trackList); + + return UISwipeActionsConfiguration.FromActions(new[] { action }); + } + + private UIBarButtonItem CreateSettingsButton() + { + var playAlbumAction = Binder.GetCommandAction(Strings.ContextMenuPlay, "play", ViewModel.PlayPlaylistCommand); + var addAlbumAction = Binder.GetCommandAction(Strings.ContextMenuAddToQueue, "plus", ViewModel.LoadPlaylistCommand); + var deletePlaylistAction = Binder.GetCommandAction(Strings.ContextMenuDeletePlaylist, "trash", ViewModel.RemovePlaylistCommand); + + var barButtonMenu = UIMenu.Create(new[] { playAlbumAction, addAlbumAction, deletePlaylistAction }); + return new UIBarButtonItem(UIImage.GetSystemImage("ellipsis.circle"), barButtonMenu); + } + } +} diff --git a/Sources/Stylophone.iOS/ViewControllers/PlaylistViewController.designer.cs b/Sources/Stylophone.iOS/ViewControllers/PlaylistViewController.designer.cs new file mode 100644 index 00000000..c0b23211 --- /dev/null +++ b/Sources/Stylophone.iOS/ViewControllers/PlaylistViewController.designer.cs @@ -0,0 +1,106 @@ +// WARNING +// +// This file has been generated automatically by Visual Studio to store outlets and +// actions made in the UI designer. If it is removed, they will be lost. +// Manual changes to this file may not be handled correctly. +// +using Foundation; +using System.CodeDom.Compiler; + +namespace Stylophone.iOS.ViewControllers +{ + [Register ("PlaylistViewController")] + partial class PlaylistViewController + { + [Outlet] + UIKit.UIButton AddToQueueButton { get; set; } + + [Outlet] + UIKit.UIImageView AlbumArt { get; set; } + + [Outlet] + UIKit.UIActivityIndicatorView AlbumArtLoadingIndicator { get; set; } + + [Outlet] + UIKit.UIView ArtContainer { get; set; } + + [Outlet] + UIKit.UIImageView BackgroundArt { get; set; } + + [Outlet] + UIKit.UIButton DeleteButton { get; set; } + + [Outlet] + UIKit.UIView EmptyView { get; set; } + + [Outlet] + UIKit.UIButton PlayButton { get; set; } + + [Outlet] + UIKit.UILabel PlaylistArtists { get; set; } + + [Outlet] + UIKit.UILabel PlaylistInfo { get; set; } + + [Outlet] + UIKit.UILabel PlaylistTitle { get; set; } + + void ReleaseDesignerOutlets () + { + if (AddToQueueButton != null) { + AddToQueueButton.Dispose (); + AddToQueueButton = null; + } + + if (AlbumArt != null) { + AlbumArt.Dispose (); + AlbumArt = null; + } + + if (AlbumArtLoadingIndicator != null) { + AlbumArtLoadingIndicator.Dispose (); + AlbumArtLoadingIndicator = null; + } + + if (ArtContainer != null) { + ArtContainer.Dispose (); + ArtContainer = null; + } + + if (BackgroundArt != null) { + BackgroundArt.Dispose (); + BackgroundArt = null; + } + + if (DeleteButton != null) { + DeleteButton.Dispose (); + DeleteButton = null; + } + + if (PlayButton != null) { + PlayButton.Dispose (); + PlayButton = null; + } + + if (EmptyView != null) { + EmptyView.Dispose (); + EmptyView = null; + } + + if (PlaylistTitle != null) { + PlaylistTitle.Dispose (); + PlaylistTitle = null; + } + + if (PlaylistInfo != null) { + PlaylistInfo.Dispose (); + PlaylistInfo = null; + } + + if (PlaylistArtists != null) { + PlaylistArtists.Dispose (); + PlaylistArtists = null; + } + } + } +} diff --git a/Sources/Stylophone.iOS/Views/Playlist.storyboard b/Sources/Stylophone.iOS/Views/Playlist.storyboard new file mode 100644 index 00000000..acdfc616 --- /dev/null +++ b/Sources/Stylophone.iOS/Views/Playlist.storyboard @@ -0,0 +1,386 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 1305f40bb1ce63d1a6756b18643be2bbbce2773c Mon Sep 17 00:00:00 2001 From: Difegue Date: Sat, 18 Sep 2021 19:17:27 +0200 Subject: [PATCH 09/15] Clean up local playback --- .../ViewModels/LocalPlaybackViewModel.cs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/Sources/Stylophone.Common/ViewModels/LocalPlaybackViewModel.cs b/Sources/Stylophone.Common/ViewModels/LocalPlaybackViewModel.cs index b628b720..75f22ca0 100644 --- a/Sources/Stylophone.Common/ViewModels/LocalPlaybackViewModel.cs +++ b/Sources/Stylophone.Common/ViewModels/LocalPlaybackViewModel.cs @@ -82,8 +82,8 @@ public string VolumeIcon private set => Set(ref _volumeIcon, value); } - private double _volume = 0; - public double Volume + private int _volume = 0; + public int Volume { get => _volume; set @@ -95,9 +95,9 @@ public double Volume IsPlaying = true; if (_mediaPlayer != null) - _mediaPlayer.Volume = (int)value; + _mediaPlayer.Volume = value; - if ((int)value == 0) + if (value == 0) { VolumeIcon = _interopService.GetIcon(PlaybackIcon.VolumeMute); } @@ -131,7 +131,7 @@ private set } } - private double _previousVolume = 10; + private int _previousVolume = 25; /// /// Toggle if we should mute /// @@ -159,9 +159,10 @@ private void UpdatePlayback() var streamUrl = new Uri(urlString); var media = new Media(_vlcCore, streamUrl); - _mediaPlayer.Volume = (int)_volume; - _mediaPlayer.Media = media; - _mediaPlayer.Play(); + _mediaPlayer.Play(media); + + // This set won't work on UWP, see https://code.videolan.org/videolan/LibVLCSharp/-/issues/423 + _mediaPlayer.Volume = _volume; } else { From c338eb9c98cf476b122ddc5ac42b3e250e6db444 Mon Sep 17 00:00:00 2001 From: Difegue Date: Sat, 18 Sep 2021 19:17:35 +0200 Subject: [PATCH 10/15] Bump version and nuget packages --- Sources/Stylophone.Common/Stylophone.Common.csproj | 10 +++++----- Sources/Stylophone/Package.appxmanifest | 2 +- Sources/Stylophone/Package.tt | 2 +- Sources/Stylophone/Stylophone.csproj | 6 +++--- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Sources/Stylophone.Common/Stylophone.Common.csproj b/Sources/Stylophone.Common/Stylophone.Common.csproj index 84059803..f5c7ebf0 100644 --- a/Sources/Stylophone.Common/Stylophone.Common.csproj +++ b/Sources/Stylophone.Common/Stylophone.Common.csproj @@ -5,13 +5,13 @@ - + - - + + - - + + diff --git a/Sources/Stylophone/Package.appxmanifest b/Sources/Stylophone/Package.appxmanifest index d4ee0377..ca4bc761 100644 --- a/Sources/Stylophone/Package.appxmanifest +++ b/Sources/Stylophone/Package.appxmanifest @@ -12,7 +12,7 @@ + Version="2.1.0.0" /> diff --git a/Sources/Stylophone/Package.tt b/Sources/Stylophone/Package.tt index 7a1fabd8..0180c870 100644 --- a/Sources/Stylophone/Package.tt +++ b/Sources/Stylophone/Package.tt @@ -2,7 +2,7 @@ <#@ output extension=".appxmanifest" #> <#@ parameter type="System.String" name="BuildConfiguration" #> <# - string version = "2.0.4.0"; + string version = "2.1.0.0"; // Get configuration name at Build time string configName = Host.ResolveParameterValue("-", "-", "BuildConfiguration"); diff --git a/Sources/Stylophone/Stylophone.csproj b/Sources/Stylophone/Stylophone.csproj index 4d34568a..3592de8a 100644 --- a/Sources/Stylophone/Stylophone.csproj +++ b/Sources/Stylophone/Stylophone.csproj @@ -143,7 +143,7 @@ 4.3.0 - 5.0.1 + 5.0.2 6.2.12 @@ -164,13 +164,13 @@ 7.0.2 - 2.6.2 + 2.7.0 2.0.1 - 2.80.2 + 2.80.3 3.3.1 From ccd796754dca97fa026d28d474171c0e8da805a2 Mon Sep 17 00:00:00 2001 From: Difegue Date: Sat, 18 Sep 2021 21:41:53 +0200 Subject: [PATCH 11/15] (#26) Add a toggle to disable album art loading --- .../Services/AlbumArtService.cs | 7 ++++++ .../ViewModels/SettingsViewModel.cs | 19 +++++++++++++-- .../Strings/Resources.Designer.cs | 21 ++++++++++++++-- .../Strings/Resources.en-US.resx | 9 +++++-- .../Strings/Resources.fr-FR.resx | 9 +++++-- .../Strings/Resources.resx | 9 +++++-- Sources/Stylophone/Views/SettingsPage.xaml | 24 ++++++++++++++++--- 7 files changed, 85 insertions(+), 13 deletions(-) diff --git a/Sources/Stylophone.Common/Services/AlbumArtService.cs b/Sources/Stylophone.Common/Services/AlbumArtService.cs index 53e7ff70..707848e9 100644 --- a/Sources/Stylophone.Common/Services/AlbumArtService.cs +++ b/Sources/Stylophone.Common/Services/AlbumArtService.cs @@ -1,4 +1,5 @@ using ColorThiefDotNet; +using Microsoft.Toolkit.Mvvm.DependencyInjection; using MpcNET.Commands.Database; using MpcNET.Types; using SkiaSharp; @@ -135,6 +136,12 @@ private async Task GetAlbumBitmap(IMpdFile f, CancellationToken token if (await IsAlbumArtCachedAsync(f)) return await LoadImageFromFile(fileName); + // No cache, check if remote fetching is enabled before going further + var isAlbumArtFetchingEnabled = _applicationStorageService.GetValue(nameof(SettingsViewModel.IsAlbumArtFetchingEnabled), true); + + if (!isAlbumArtFetchingEnabled) + return null; + // Get albumart from MPD List data = new List(); try diff --git a/Sources/Stylophone.Common/ViewModels/SettingsViewModel.cs b/Sources/Stylophone.Common/ViewModels/SettingsViewModel.cs index e4bc7a5c..bea744f4 100644 --- a/Sources/Stylophone.Common/ViewModels/SettingsViewModel.cs +++ b/Sources/Stylophone.Common/ViewModels/SettingsViewModel.cs @@ -123,6 +123,20 @@ public bool IsCompactSizing } } + private bool _albumArtEnabled; + public bool IsAlbumArtFetchingEnabled + { + get { return _albumArtEnabled; } + set + { + if (value != _albumArtEnabled) + { + _applicationStorageService.SetValue(nameof(IsAlbumArtFetchingEnabled), value); + } + Set(ref _albumArtEnabled, value); + } + } + private bool _enableAnalytics; public bool EnableAnalytics { @@ -240,8 +254,9 @@ public async Task EnsureInstanceInitializedAsync() _serverHost = _applicationStorageService.GetValue(nameof(ServerHost)); _serverHost = _serverHost?.Replace("\"", ""); // TODO: This is a quickfix for 1.x updates - _serverPort = _applicationStorageService.GetValue(nameof(ServerPort), 6600); - _enableAnalytics = _applicationStorageService.GetValue(nameof(EnableAnalytics), true); + _serverPort = _applicationStorageService.GetValue(nameof(ServerPort), 6600); + _enableAnalytics = _applicationStorageService.GetValue(nameof(EnableAnalytics), true); + _albumArtEnabled = _applicationStorageService.GetValue(nameof(IsAlbumArtFetchingEnabled), true); _localPlaybackEnabled = _applicationStorageService.GetValue(nameof(IsLocalPlaybackEnabled)); Enum.TryParse(_applicationStorageService.GetValue(nameof(ElementTheme)), out _elementTheme); diff --git a/Sources/Stylophone.Localization/Strings/Resources.Designer.cs b/Sources/Stylophone.Localization/Strings/Resources.Designer.cs index fe23c072..3f01b99a 100644 --- a/Sources/Stylophone.Localization/Strings/Resources.Designer.cs +++ b/Sources/Stylophone.Localization/Strings/Resources.Designer.cs @@ -848,6 +848,24 @@ public static string SettingsAboutText { } } + /// + /// Recherche une chaîne localisée semblable à Download Album Art from the MPD Server. + /// + public static string SettingsAlbumArt { + get { + return ResourceManager.GetString("SettingsAlbumArt", resourceCulture); + } + } + + /// + /// Recherche une chaîne localisée semblable à Stylophone stores album art locally to avoid overloading your MPD Server.. + /// + public static string SettingsAlbumArtText { + get { + return ResourceManager.GetString("SettingsAlbumArtText", resourceCulture); + } + } + /// /// Recherche une chaîne localisée semblable à Analytics. /// @@ -885,8 +903,7 @@ public static string SettingsClearCache { } /// - /// Recherche une chaîne localisée semblable à Stylophone stores album art locally to avoid overloading your MPD Server. - ///If you want to clear the album art cache, click this button.. + /// Recherche une chaîne localisée semblable à Clear the local album art cache. /// public static string SettingsClearCacheDescription { get { diff --git a/Sources/Stylophone.Localization/Strings/Resources.en-US.resx b/Sources/Stylophone.Localization/Strings/Resources.en-US.resx index 4faa4d46..3acf4197 100644 --- a/Sources/Stylophone.Localization/Strings/Resources.en-US.resx +++ b/Sources/Stylophone.Localization/Strings/Resources.en-US.resx @@ -249,8 +249,7 @@ Clear Cache - Stylophone stores album art locally to avoid overloading your MPD Server. -If you want to clear the album art cache, click this button. + Clear the local album art cache Personalization @@ -485,4 +484,10 @@ Enabling this option will show a second volume slider to control local volume. David Bowie is credited with playing the Stylophone on his 1969 debut hit song "Space Oddity" and also for his 2002 album Heathen track titled "Slip Away," as well as on the song "Heathen (The Rays)". + + Download Album Art from the MPD Server + + + Stylophone stores album art locally to avoid overloading your MPD Server. + \ No newline at end of file diff --git a/Sources/Stylophone.Localization/Strings/Resources.fr-FR.resx b/Sources/Stylophone.Localization/Strings/Resources.fr-FR.resx index af699af4..c37d0136 100644 --- a/Sources/Stylophone.Localization/Strings/Resources.fr-FR.resx +++ b/Sources/Stylophone.Localization/Strings/Resources.fr-FR.resx @@ -248,8 +248,7 @@ Vider le cache - Stylophone stocke les pochettes d'album sur votre ordinateur pour éviter de surcharger votre serveur MPD. -Pour nettoyer ce cache de pochettes, cliquez sur ce bouton. + Nettoyer le cache de pochettes local Personnalisation @@ -484,4 +483,10 @@ L'activation de cette option affichera un second slider pour contrôler le volum David Bowie is credited with playing the Stylophone on his 1969 debut hit song "Space Oddity" and also for his 2002 album Heathen track titled "Slip Away," as well as on the song "Heathen (The Rays)". + + Récupérer les pochettes d'album depuis le serveur MPD + + + Stylophone stocke les pochettes d'album sur votre ordinateur pour éviter de surcharger votre serveur MPD. + \ No newline at end of file diff --git a/Sources/Stylophone.Localization/Strings/Resources.resx b/Sources/Stylophone.Localization/Strings/Resources.resx index ceabdd41..d6b710b2 100644 --- a/Sources/Stylophone.Localization/Strings/Resources.resx +++ b/Sources/Stylophone.Localization/Strings/Resources.resx @@ -249,8 +249,7 @@ Clear Cache - Stylophone stores album art locally to avoid overloading your MPD Server. -If you want to clear the album art cache, click this button. + Clear the local album art cache Personalization @@ -485,4 +484,10 @@ Enabling this option will show a second volume slider to control local volume. David Bowie is credited with playing the Stylophone on his 1969 debut hit song "Space Oddity" and also for his 2002 album Heathen track titled "Slip Away," as well as on the song "Heathen (The Rays)". + + Download Album Art from the MPD Server + + + Stylophone stores album art locally to avoid overloading your MPD Server. + \ No newline at end of file diff --git a/Sources/Stylophone/Views/SettingsPage.xaml b/Sources/Stylophone/Views/SettingsPage.xaml index 3518793f..18763aa2 100644 --- a/Sources/Stylophone/Views/SettingsPage.xaml +++ b/Sources/Stylophone/Views/SettingsPage.xaml @@ -34,6 +34,7 @@ + @@ -142,11 +143,28 @@ IsEnabled="{x:Bind ViewModel.IsServerValid, Mode=OneWay}" /> - + - + -