Added indicator of what song is playing in all of the music-type views. Added Queue data structure to prepare for a music queue. #39 #45

This commit is contained in:
amazing-username
2019-06-15 10:49:04 -07:00
parent 277e20ef10
commit e15c2cf2ef
11 changed files with 336 additions and 40 deletions
+40 -12
View File
@@ -23,8 +23,15 @@ namespace Mear.Playback
public class MearPlayer public class MearPlayer
{ {
#region Fields #region Fields
private Queue<Song> _mearQueue = null;
private static Song _song; private static Song _song;
private static bool? _initialized = null; private static bool? _initialized = null;
private static SortedDictionary<MusicViews, bool?> _songChanged =
new SortedDictionary<MusicViews, bool?>{
{ MusicViews.Song, false },
{ MusicViews.Album, false },
{ MusicViews.Artist, false }
};
#endregion #endregion
@@ -76,8 +83,11 @@ namespace Mear.Playback
return null; return null;
} }
public static async Task<Song> ControlMusic(Song song, PlayControls control) public static async Task<Song> ControlMusic(Song song, PlayControls control)
{
if (song != null)
{ {
_song = song; _song = song;
}
switch (control) switch (control)
{ {
case PlayControls.PLAYOFFLINE: case PlayControls.PLAYOFFLINE:
@@ -113,15 +123,16 @@ namespace Mear.Playback
return null; return null;
} }
public static async Task<string> SongTitle()
{
return _song.Title;
}
public static async Task<string> ConvertToTime() public static async Task<string> ConvertToTime()
{ {
try try
{ {
var ttlSec = (int)CrossMediaManager.Current.Position.TotalSeconds; var ttlSec = (int)CrossMediaManager.Current.Position.TotalSeconds;
var cnvrt = new TimeFormat(); return TimeFormat.ConvertToSongTime(ttlSec);
var curPos = cnvrt.ConvertToSongTime(ttlSec);
return curPos;
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -161,7 +172,7 @@ namespace Mear.Playback
{ {
var songPath = song.SongPath; var songPath = song.SongPath;
await CrossMediaManager.Current.Play(songPath); PlaySong(songPath);
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -179,6 +190,10 @@ namespace Mear.Playback
_song.Downloaded = false; _song.Downloaded = false;
} }
public static async Task ResetSongChange(MusicViews type)
{
_songChanged[type] = false;
}
public static async Task SeekTo(double songProress) public static async Task SeekTo(double songProress)
{ {
double newPosition = (songProress / 100) * ((double)_song.Duration); double newPosition = (songProress / 100) * ((double)_song.Duration);
@@ -222,6 +237,10 @@ namespace Mear.Playback
{ {
return CrossMediaManager.Current.IsPlaying(); return CrossMediaManager.Current.IsPlaying();
} }
public static bool SongHasBeenChanged(MusicViews type)
{
return _songChanged[type].Value;
}
public static bool RepeatMatchedDatabase() public static bool RepeatMatchedDatabase()
{ {
var playerRepeatMode = CrossMediaManager.Current.RepeatMode; var playerRepeatMode = CrossMediaManager.Current.RepeatMode;
@@ -301,9 +320,11 @@ namespace Mear.Playback
if (_initialized == null) if (_initialized == null)
{ {
CrossMediaManager.Current.MediaItemFinished += Current_MediaItemFinished; CrossMediaManager.Current.MediaItemFinished += Current_MediaItemFinished;
//BackgroundWork();
_initialized = true; _initialized = true;
} }
_songChanged[MusicViews.Song] = true;
_songChanged[MusicViews.Album] = true;
_songChanged[MusicViews.Artist] = true;
} }
private static async Task ResumeSong() private static async Task ResumeSong()
{ {
@@ -314,7 +335,7 @@ namespace Mear.Playback
{ {
var musicCtrl = new DBMusicControlsRepository(); var musicCtrl = new DBMusicControlsRepository();
musicCtrl.UpdateRepeat(); musicCtrl.UpdateRepeat();
var repeatMode = (Repeat)musicCtrl.IsRepeatOn(); var repeatMode = musicCtrl.IsRepeatOn();
CrossMediaManager.Current.RepeatMode = RepeatUtility.RetrieveRepeatMode(repeatMode); CrossMediaManager.Current.RepeatMode = RepeatUtility.RetrieveRepeatMode(repeatMode);
} }
@@ -341,15 +362,12 @@ namespace Mear.Playback
{ {
var ctrlRepo = new DBMusicControlsRepository(); var ctrlRepo = new DBMusicControlsRepository();
var repeatMode = ctrlRepo.IsRepeatOn(); var repeatMode = ctrlRepo.IsRepeatOn();
if (CrossMediaManager.Current.IsPlaying())
{
//return;
}
switch(repeatMode) switch(repeatMode)
{ {
case Repeat.ONE: case Repeat.ONE:
CrossMediaManager.Current.SeekToStart(); CrossMediaManager.Current.SeekToStart();
//PlaySong(_song.SongPath); PlaySong(_song.SongPath);
break; break;
case Repeat.ALL: case Repeat.ALL:
// Will implment this fully later once Queues are a feature // Will implment this fully later once Queues are a feature
@@ -359,5 +377,15 @@ namespace Mear.Playback
} }
#endregion #endregion
#endregion #endregion
#region Enums
public enum MusicViews
{
Song = 0,
Album,
Artist
}
#endregion
} }
} }
+3 -6
View File
@@ -19,23 +19,20 @@ namespace Mear.Utilities
#region Methods #region Methods
public string ConvertToSongTime(int seconds) public static string ConvertToSongTime(int seconds)
{ {
var curTime = string.Empty;
var dur = seconds; var dur = seconds;
var min = TimeSpan.FromSeconds((double) dur).Minutes; var min = TimeSpan.FromSeconds((double) dur).Minutes;
var remainingSec = dur % 60; var remainingSec = dur % 60;
if (remainingSec < 10) if (remainingSec < 10)
{ {
curTime = $"{min}:0{remainingSec}"; return $"{min}:0{remainingSec}";
} }
else else
{ {
curTime = $"{min}:{remainingSec}"; return $"{min}:{remainingSec}";
} }
return curTime;
} }
#endregion #endregion
} }
+1 -1
View File
@@ -11,7 +11,7 @@
<ContentPage.BindingContext> <ContentPage.BindingContext>
<vm:AlbumViewModel /> <vm:AlbumViewModel />
</ContentPage.BindingContext> </ContentPage.BindingContext>
<StackLayout> <StackLayout x:Name="AlbumViewMainLayout" >
<SearchBar x:Name="SearchAlbum" <SearchBar x:Name="SearchAlbum"
Placeholder="Album" Placeholder="Album"
SearchCommand="{Binding SearchAlbumCommand}" SearchCommand="{Binding SearchAlbumCommand}"
+87
View File
@@ -2,11 +2,14 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Xamarin.Forms; using Xamarin.Forms;
using Xamarin.Forms.Xaml; using Xamarin.Forms.Xaml;
using Mear.Constants;
using Mear.Playback;
using Mear.ViewModels; using Mear.ViewModels;
namespace Mear.Views namespace Mear.Views
@@ -15,6 +18,9 @@ namespace Mear.Views
public partial class AlbumView : ContentPage public partial class AlbumView : ContentPage
{ {
#region Fields #region Fields
private StackLayout _playerIndicatorLayout;
private Button _controlButton;
private Label _songTitleLabel;
private AlbumViewModel _viewModel; private AlbumViewModel _viewModel;
#endregion #endregion
@@ -27,6 +33,8 @@ namespace Mear.Views
public AlbumView() public AlbumView()
{ {
InitializeComponent(); InitializeComponent();
AddPlayerIndicator();
BackgroundControl();
BindingContext = _viewModel = new AlbumViewModel(); BindingContext = _viewModel = new AlbumViewModel();
} }
@@ -34,7 +42,86 @@ namespace Mear.Views
#region Methods #region Methods
private async Task AddPlayerIndicator()
{
var mainLayout = AlbumViewMainLayout;
if (_playerIndicatorLayout == null)
{
_playerIndicatorLayout = await ConfigureSongIndicatorLayout();
}
mainLayout.Children.Add(_playerIndicatorLayout);
}
private async Task<StackLayout> ConfigureSongIndicatorLayout()
{
var indicatorLayout = new StackLayout();
indicatorLayout.Orientation = StackOrientation.Horizontal;
indicatorLayout.Padding = 5;
_controlButton = new Button();
_controlButton.Clicked += ControlButton_Clicked;
_songTitleLabel = new Label();
_songTitleLabel.HorizontalOptions = LayoutOptions.Center;
_songTitleLabel.VerticalOptions = LayoutOptions.Start;
var isSongPlayer = MearPlayer.IsPlaying();
if (isSongPlayer)
{
_controlButton.Text = "P";
_songTitleLabel.Text = await MearPlayer.SongTitle();
}
else
{
_controlButton.Text = "S";
_songTitleLabel.Text = string.Empty;
}
indicatorLayout.Children.Add(_controlButton);
indicatorLayout.Children.Add(_songTitleLabel);
return indicatorLayout;
}
#region Background
private async Task BackgroundControl()
{
try
{
new Thread(async () =>
{
while (true)
{
Device.BeginInvokeOnMainThread(async () =>
{
if (MearPlayer.SongHasBeenChanged(MearPlayer.MusicViews.Album))
{
_songTitleLabel.Text = MearPlayer.SongTitle().Result;
MearPlayer.ResetSongChange(MearPlayer.MusicViews.Album);
}
});
await Task.Delay(800);
}
}).Start();
}
catch (Exception ex)
{
var msg = ex.Message;
}
}
#endregion
#region Events #region Events
private async void ControlButton_Clicked(object sender, EventArgs e)
{
if (MearPlayer.IsPlaying())
{
MearPlayer.ControlMusic(null, PlayControls.PAUSE);
}
else
{
MearPlayer.ControlMusic(null, PlayControls.RESUME);
}
}
private void AlbumListView_ItemSelected(object sender, SelectedItemChangedEventArgs e) private void AlbumListView_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{ {
var albumItem = (sender as ListView).SelectedItem = null; var albumItem = (sender as ListView).SelectedItem = null;
+1 -1
View File
@@ -12,7 +12,7 @@
<vm:ArtistViewModel /> <vm:ArtistViewModel />
</ContentPage.BindingContext> </ContentPage.BindingContext>
<StackLayout> <StackLayout x:Name="ArtistViewMainLayout">
<SearchBar x:Name="SearchArtist" <SearchBar x:Name="SearchArtist"
Placeholder="Artist" Placeholder="Artist"
SearchCommand="{Binding SearchArtistCommand}" SearchCommand="{Binding SearchArtistCommand}"
+87
View File
@@ -2,11 +2,14 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Xamarin.Forms; using Xamarin.Forms;
using Xamarin.Forms.Xaml; using Xamarin.Forms.Xaml;
using Mear.Constants;
using Mear.Playback;
using Mear.ViewModels; using Mear.ViewModels;
namespace Mear.Views namespace Mear.Views
@@ -15,6 +18,9 @@ namespace Mear.Views
public partial class ArtistView : ContentPage public partial class ArtistView : ContentPage
{ {
#region Fields #region Fields
private StackLayout _playerIndicatorLayout;
private Button _controlButton;
private Label _songTitleLabel;
private ArtistViewModel _viewModel; private ArtistViewModel _viewModel;
#endregion #endregion
@@ -27,6 +33,8 @@ namespace Mear.Views
public ArtistView() public ArtistView()
{ {
InitializeComponent(); InitializeComponent();
AddPlayerIndicator();
BackgroundControl();
BindingContext = _viewModel = new ArtistViewModel(); BindingContext = _viewModel = new ArtistViewModel();
} }
@@ -34,7 +42,86 @@ namespace Mear.Views
#region Methods #region Methods
private async Task AddPlayerIndicator()
{
var mainLayout = ArtistViewMainLayout;
if (_playerIndicatorLayout == null)
{
_playerIndicatorLayout = await ConfigureSongIndicatorLayout();
}
mainLayout.Children.Add(_playerIndicatorLayout);
}
private async Task<StackLayout> ConfigureSongIndicatorLayout()
{
var indicatorLayout = new StackLayout();
indicatorLayout.Orientation = StackOrientation.Horizontal;
indicatorLayout.Padding = 5;
_controlButton = new Button();
_controlButton.Clicked += ControlButton_Clicked;
_songTitleLabel = new Label();
_songTitleLabel.HorizontalOptions = LayoutOptions.Center;
_songTitleLabel.VerticalOptions = LayoutOptions.Start;
var isSongPlayer = MearPlayer.IsPlaying();
if (isSongPlayer)
{
_controlButton.Text = "P";
_songTitleLabel.Text = await MearPlayer.SongTitle();
}
else
{
_controlButton.Text = "S";
_songTitleLabel.Text = string.Empty;
}
indicatorLayout.Children.Add(_controlButton);
indicatorLayout.Children.Add(_songTitleLabel);
return indicatorLayout;
}
#region Background
private async Task BackgroundControl()
{
try
{
new Thread(async () =>
{
while (true)
{
Device.BeginInvokeOnMainThread(async () =>
{
if (MearPlayer.SongHasBeenChanged(MearPlayer.MusicViews.Artist))
{
_songTitleLabel.Text = MearPlayer.SongTitle().Result;
MearPlayer.ResetSongChange(MearPlayer.MusicViews.Artist);
}
});
await Task.Delay(800);
}
}).Start();
}
catch (Exception ex)
{
var msg = ex.Message;
}
}
#endregion
#region Events #region Events
private async void ControlButton_Clicked(object sender, EventArgs e)
{
if (MearPlayer.IsPlaying())
{
MearPlayer.ControlMusic(null, PlayControls.PAUSE);
}
else
{
MearPlayer.ControlMusic(null, PlayControls.RESUME);
}
}
private void ArtistListView_ItemSelected(object sender, SelectedItemChangedEventArgs e) private void ArtistListView_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{ {
var artistItem = (sender as ListView).SelectedItem = null; var artistItem = (sender as ListView).SelectedItem = null;
+3 -7
View File
@@ -50,7 +50,7 @@ namespace Mear.Views
InitializeControls(); InitializeControls();
BackgroundSongElasping(); BackgroundSongElasping();
BackgroundSongCoverUpdate(); //BackgroundSongCoverUpdate();
//BackgroundControlInit(); //BackgroundControlInit();
InitializeOptions(); InitializeOptions();
@@ -81,7 +81,7 @@ namespace Mear.Views
return rmvOpt; return rmvOpt;
} }
private void InitializeOptions() private async void InitializeOptions()
{ {
if (!_song.Downloaded) if (!_song.Downloaded)
{ {
@@ -96,14 +96,10 @@ namespace Mear.Views
} }
private void InitializeControls() private void InitializeControls()
{ {
var songCnvrt = new TimeFormat();
var dur = _song.Duration;
var endTime = songCnvrt.ConvertToSongTime(dur.Value);
Shuffle.Text = MearPlayer.RetrieveShuffleString(); Shuffle.Text = MearPlayer.RetrieveShuffleString();
Repeat.Text = MearPlayer.RetrieveRepeatString(); Repeat.Text = MearPlayer.RetrieveRepeatString();
EndTime.Text = endTime; EndTime.Text = TimeFormat.ConvertToSongTime(_song.Duration.Value);
} }
private void RemoveSyncToolbar() private void RemoveSyncToolbar()
{ {
-1
View File
@@ -46,5 +46,4 @@
</x:Arguments> </x:Arguments>
</NavigationPage> </NavigationPage>
</TabbedPage.Children> </TabbedPage.Children>
</TabbedPage> </TabbedPage>
+17
View File
@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace Mear.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MusicViewBase : ContentPage
{
protected void AddPlayerIn(StackLayout mainLayout)
{
}
}
}
+1 -1
View File
@@ -12,7 +12,7 @@
<vm:SongViewModel /> <vm:SongViewModel />
</ContentPage.BindingContext> </ContentPage.BindingContext>
<StackLayout> <StackLayout x:Name="SongViewMainLayout" >
<SearchBar x:Name="SearchSong" <SearchBar x:Name="SearchSong"
Placeholder="Title, Artist" Placeholder="Title, Artist"
SearchCommand="{Binding SearchSongsCommand}" SearchCommand="{Binding SearchSongsCommand}"
+85
View File
@@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaManager; using MediaManager;
@@ -21,6 +22,9 @@ namespace Mear.Views
public partial class SongView : ContentPage public partial class SongView : ContentPage
{ {
#region Fields #region Fields
private StackLayout _playerIndicatorLayout;
private Button _controlButton;
private Label _songTitleLabel;
private SongViewModel _viewModel; private SongViewModel _viewModel;
#endregion #endregion
@@ -35,12 +39,65 @@ namespace Mear.Views
InitializeComponent(); InitializeComponent();
BindingContext = _viewModel = new SongViewModel(); BindingContext = _viewModel = new SongViewModel();
AddPlayerIndicator();
BackgroundControl();
} }
#endregion #endregion
#region Methods #region Methods
private async Task AddPlayerIndicator()
{
var mainLayout = SongViewMainLayout;
if (_playerIndicatorLayout == null)
{
_playerIndicatorLayout = await ConfigureSongIndicatorLayout();
}
mainLayout.Children.Add(_playerIndicatorLayout);
}
private async Task<StackLayout> ConfigureSongIndicatorLayout()
{
var indicatorLayout = new StackLayout();
indicatorLayout.Orientation = StackOrientation.Horizontal;
indicatorLayout.Padding = 5;
_controlButton = new Button();
_controlButton.Clicked += ControlButton_Clicked;
_songTitleLabel = new Label();
_songTitleLabel.HorizontalOptions = LayoutOptions.Center;
_songTitleLabel.VerticalOptions = LayoutOptions.Start;
var isSongPlayer = MearPlayer.IsPlaying();
if (isSongPlayer)
{
_controlButton.Text = "P";
_songTitleLabel.Text = await MearPlayer.SongTitle();
}
else
{
_controlButton.Text = "S";
_songTitleLabel.Text = string.Empty;
}
indicatorLayout.Children.Add(_controlButton);
indicatorLayout.Children.Add(_songTitleLabel);
return indicatorLayout;
}
#region Events #region Events
private async void ControlButton_Clicked(object sender, EventArgs e)
{
if (MearPlayer.IsPlaying())
{
MearPlayer.ControlMusic(null, PlayControls.PAUSE);
}
else
{
MearPlayer.ControlMusic(null, PlayControls.RESUME);
}
}
private async void SongListView_ItemSelected(object sender, SelectedItemChangedEventArgs e) private async void SongListView_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{ {
if (SongListView.SelectedItem == null) if (SongListView.SelectedItem == null)
@@ -90,6 +147,34 @@ namespace Mear.Views
} }
#endregion #endregion
#region Background
private async Task BackgroundControl()
{
try
{
new Thread(async () =>
{
while (true)
{
Device.BeginInvokeOnMainThread(async () =>
{
if (MearPlayer.SongHasBeenChanged(MearPlayer.MusicViews.Song))
{
_songTitleLabel.Text = MearPlayer.SongTitle().Result;
MearPlayer.ResetSongChange(MearPlayer.MusicViews.Song);
}
});
await Task.Delay(800);
}
}).Start();
}
catch (Exception ex)
{
var msg = ex.Message;
}
}
#endregion
#region Test #region Test
public void TestRemoteSong() public void TestRemoteSong()
{ {