2021-04-11 20:54:59 -04:00

326 lines
11 KiB
C#

using System;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Linq;
using Aurora.Design.Components.NavigationMenu;
using Aurora.Design.Views.MainView;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
using Aurora.Models.Media;
using Aurora.Design.Components.MediaPlayer;
using Aurora.Services.Player;
using Autofac;
namespace Aurora.Design.Views.Main
{
public enum PlayAction
{
Play,
Pause,
Resume,
Stop
}
/// <summary>
/// Delegate for updating player metadata
/// </summary>
/// <param name="media"></param>
public delegate Task SetPlayerDelegate(BaseMedia media, PlayAction action);
public delegate bool GetIsPlayingDelegate();
public delegate void ShowModalDelegate(Type view, BaseDialogViewModel viewModel);
public delegate void HideModalDelegate();
public delegate void FinishDialogDelegate();
public delegate void SetViewDelegate(Type viewType, Type viewModelType);
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MainView : ContentPage//, IDisposable
{
private Dictionary<string, BaseViewModel> _viewModels;
private BaseViewModel _lastViewModel;
private Player _playerComponent;
private IPlayer _playerService;
private ContentPresenter _viewContent;
public MainView(IPlayer player)
{
InitializeComponent();
BindingContext = new MainViewModel();
_viewModels = new Dictionary<string, BaseViewModel>();
_playerComponent = Player;
_viewContent = (ContentPresenter)Content.FindByName("ViewContent");
_playerService = player;
MasterPage.ListView.ItemSelected += OnNavItemSelected;
Appearing += OnAppearing;
}
public void Dispose()
{
Appearing -= OnAppearing;
}
/// <summary>
/// Event handler for side bar items being selected
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnNavItemSelected(object sender, SelectedItemChangedEventArgs e)
{
var item = e.SelectedItem as NavigationItem;
if (item == null)
return;
var view = (View)Activator.CreateInstance(item.TargetType);
string viewModelName = item.TargetViewModelType.Name;
//Check if we have an instantiated viewModel
BaseViewModel vm = new BaseViewModel();
if (_viewModels.ContainsKey(viewModelName))
{
_viewModels.TryGetValue(viewModelName, out vm);
}
else
{
if (item.TargetViewModelType.IsAssignableFrom(typeof(BaseViewModel)))
{
throw new InvalidOperationException("TargetViewModel field must be of type BaseViewModel");
}
//Instantiate new view model
vm = (BaseViewModel)App.Container.Resolve(item.TargetViewModelType); //Activator.CreateInstance(item.TargetViewModelType);
_viewModels.Add(viewModelName, vm);
}
//Assign player controls to viewmodel
if(vm is BasePlayerViewModel)
{
AssignPlayerControls(vm as BasePlayerViewModel);
}
ChangeModalVisiblity(false);
vm.SetView = this.SetView;
//Activate viewmodel
vm.OnActive();
//Deactivate last viewModel
_lastViewModel.OnInactive();
//Unasign deactivating vm
if(_lastViewModel is BasePlayerViewModel)
{
UnassignPlayerControls(_lastViewModel as BasePlayerViewModel);
}
//Assign viewModel
_lastViewModel = vm;
view.BindingContext = vm;
_viewContent.Content = view;
}
/// <summary>
/// Event handler for page appearing.
/// </summary>
/// <param name="sender">The object that fired the event.</param>
/// <param name="args">The event arguments</param>
private void OnAppearing(object sender, EventArgs args)
{
//Set initial view from first item in list
ObservableCollection<NavigationGroupItem> screenList = (ObservableCollection<NavigationGroupItem>)MasterPage.ListView.ItemsSource;
//Assign viewModel
NavigationItem firstNavItem = screenList.FirstOrDefault().FirstOrDefault();
var view = (View)Activator.CreateInstance(firstNavItem.TargetType);
BaseViewModel vm = new BaseViewModel();
if (_viewModels.ContainsKey(nameof(firstNavItem.TargetViewModelType)))
{
_viewModels.TryGetValue(nameof(firstNavItem.TargetViewModelType), out vm);
}
else
{
//Instantiate new view model
vm = (BaseViewModel)App.Container.Resolve(firstNavItem.TargetViewModelType); //(BaseViewModel)Activator.CreateInstance(firstNavItem.TargetViewModelType);
_viewModels.Add(nameof(firstNavItem.TargetViewModelType), vm);
}
view.BindingContext = vm;
_lastViewModel = vm;
if(vm is BasePlayerViewModel)
{
AssignPlayerControls(vm as BasePlayerViewModel);
}
vm.SetView = this.SetView;
ChangeModalVisiblity(false);
vm.OnActive();
_viewContent.Content = view;
}
/// <summary>
/// Unassign setplayer delegate to prevent vms from changing player info when inactive
/// </summary>
/// <param name="vm"></param>
private void UnassignPlayerControls(BasePlayerViewModel vm)
{
vm.ChangePlayerState = null;
vm.IsPlaying = null;
vm.ShowModal = null;
}
/// <summary>
/// Assign main views music player controls to a view model
/// </summary>
/// <param name="vm">BaseViewModel to assign controls to</param>
private void AssignPlayerControls(BasePlayerViewModel vm)
{
_playerComponent.PlayButtonCommand = new Command(vm.OnPlayButtonCommandExecute, vm.CanPlayButtonCommandExecute);
_playerComponent.NextButtonCommand = new Command(vm.OnNextButtonExecute, vm.CanNextButtonCommandExecute);
_playerComponent.PreviousButtonCommand = new Command(vm.OnPreviousButtonExecute, vm.CanPreviousButtonCommandExecute);
vm.ChangePlayerState = ChangePlayerState;
vm.IsPlaying = () =>
{
return _playerService.PlaybackState == PlaybackState.Playing;
};
vm.ShowModal = this.ShowModal;
vm.HideModal = this.HideModal;
}
/// <summary>
/// Delegate handler for a view model controling music playback
/// </summary>
/// <param name="media"></param>
/// <param name="action"></param>
/// <returns></returns>
private async Task ChangePlayerState(BaseMedia media, PlayAction action)
{
if (media != null && media.Metadata is AudioMetadata)
{
AudioMetadata meta = (AudioMetadata)media.Metadata;
_playerComponent.ArtistName = meta.Artist;
_playerComponent.SongTitle = meta.Title;
}
switch (action)
{
case PlayAction.Pause:
{
_playerService.Pause();
_playerComponent.IsPlaying = false;
break;
}
case PlayAction.Play:
{
if (media == null)
{
break;
}
if (!_playerService.IsMediaLoaded(media))
{
await _playerService.LoadMedia(media).ConfigureAwait(true);
}
_playerService.Play();
_playerComponent.IsPlaying = true;
break;
}
case PlayAction.Resume:
{
_playerService.Play();
_playerComponent.IsPlaying = true;
break;
}
case PlayAction.Stop:
{
_playerService.Stop();
_playerComponent.IsPlaying = false;
break;
}
}
}
private void ShowModal(Type view, BaseDialogViewModel viewModel)
{
ContentPresenter modalContainer = (ContentPresenter)Modal.FindByName("ViewContent");
var vw = (View)Activator.CreateInstance(view);
vw.BindingContext = viewModel;
//Set modal container content
modalContainer.Content = vw;
//Set visibility
ChangeModalVisiblity(true);
}
private void HideModal()
{
ChangeModalVisiblity(false);
}
private void ChangeModalVisiblity(bool isVisible)
{
Modal.IsVisible = isVisible;
Content.IsVisible = !isVisible;
}
private void SetView(Type viewType, Type viewModelType)
{
BaseViewModel vm = new BaseViewModel();
if(this._viewModels.ContainsKey(viewModelType.Name))
{
this._viewModels.TryGetValue(viewModelType.Name, out vm);
}
else
{
if (viewModelType.IsAssignableFrom(typeof(BaseViewModel)))
{
throw new InvalidOperationException("TargetViewModel field must be of type BaseViewModel");
}
//Instantiate new view model
vm = (BaseViewModel)App.Container.Resolve(viewModelType); //Activator.CreateInstance(item.TargetViewModelType);
_viewModels.Add(viewModelType.Name, vm);
}
//Assign player controls to viewmodel
if(vm is BasePlayerViewModel)
{
AssignPlayerControls(vm as BasePlayerViewModel);
}
ChangeModalVisiblity(false);
//Activate viewmodel
vm.OnActive();
//Deactivate last viewModel
_lastViewModel.OnInactive();
//Unasign deactivating vm
if(_lastViewModel is BasePlayerViewModel)
{
UnassignPlayerControls(_lastViewModel as BasePlayerViewModel);
}
var view = (View)Activator.CreateInstance(viewType);
//Assign viewModel
_lastViewModel = vm;
view.BindingContext = vm;
_viewContent.Content = view;
}
}
}