using System; using System.ComponentModel; using System.IO; using Avalonia; using Avalonia.Controls; using Avalonia.Markup.Xaml; using Avalonia.Media.Imaging; using Avalonia.Platform; using Avalonia.Threading; using RedBookPlayer.GUI.ViewModels; namespace RedBookPlayer.GUI { public class PlayerView : UserControl { /// /// Read-only access to the view model /// public PlayerViewModel PlayerViewModel => DataContext as PlayerViewModel; /// /// Set of images representing the digits for the UI /// private Image[] _digits; /// /// Initialize the UI based on the default theme /// public PlayerView() : this(null, null) { } /// /// Initialize the UI based on the default theme with an existing view model /// /// XAML data representing the theme, null for default /// Existing PlayerViewModel to load in instead of creating a new one public PlayerView(PlayerViewModel playerViewModel) : this(null, playerViewModel) { } /// /// Initialize the UI based on the currently selected theme /// /// XAML data representing the theme, null for default /// Existing PlayerViewModel to load in instead of creating a new one public PlayerView(string xaml, PlayerViewModel playerViewModel) { if(playerViewModel != null) DataContext = playerViewModel; else DataContext = new PlayerViewModel(); PlayerViewModel.PropertyChanged += PlayerViewModelStateChanged; LoadTheme(xaml); InitializeDigits(); } #region Helpers /// /// Update the view model with new settings /// public void UpdateViewModel() { PlayerViewModel.SetLoadDataTracks(App.Settings.PlayDataTracks); PlayerViewModel.SetLoadHiddenTracks(App.Settings.PlayHiddenTracks); } /// /// Load the png image for a given character based on the theme /// /// Character to load the image for /// Bitmap representing the loaded image private Bitmap GetBitmap(char character) { try { if(App.Settings.SelectedTheme == "default") { IAssetLoader assets = AvaloniaLocator.Current.GetService(); return new Bitmap(assets.Open(new Uri($"avares://RedBookPlayer/Assets/{character}.png"))); } else { string themeDirectory = $"{Directory.GetCurrentDirectory()}/themes/{App.Settings.SelectedTheme}"; using FileStream stream = File.Open($"{themeDirectory}/{character}.png", FileMode.Open); return new Bitmap(stream); } } catch { return null; } } /// /// Initialize the displayed digits array /// private void InitializeDigits() { _digits = new Image[] { this.FindControl("TrackDigit1"), this.FindControl("TrackDigit2"), this.FindControl("IndexDigit1"), this.FindControl("IndexDigit2"), this.FindControl("TimeDigit1"), this.FindControl("TimeDigit2"), this.FindControl("TimeDigit3"), this.FindControl("TimeDigit4"), this.FindControl("TimeDigit5"), this.FindControl("TimeDigit6"), this.FindControl("TotalTracksDigit1"), this.FindControl("TotalTracksDigit2"), this.FindControl("TotalIndexesDigit1"), this.FindControl("TotalIndexesDigit2"), this.FindControl("TotalTimeDigit1"), this.FindControl("TotalTimeDigit2"), this.FindControl("TotalTimeDigit3"), this.FindControl("TotalTimeDigit4"), this.FindControl("TotalTimeDigit5"), this.FindControl("TotalTimeDigit6"), }; } /// /// Load the theme from a XAML, if possible /// /// XAML data representing the theme, null for default private void LoadTheme(string xaml) { try { if(xaml != null) new AvaloniaXamlLoader().Load(xaml, null, this); else AvaloniaXamlLoader.Load(this); } catch { AvaloniaXamlLoader.Load(this); } } /// /// Update the UI from the view-model /// private void PlayerViewModelStateChanged(object sender, PropertyChangedEventArgs e) { Dispatcher.UIThread.InvokeAsync(() => { string digitString = PlayerViewModel?.GenerateDigitString() ?? string.Empty.PadLeft(20, '-'); for(int i = 0; i < _digits.Length; i++) { Bitmap digitImage = GetBitmap(digitString[i]); if(_digits[i] != null && digitImage != null) _digits[i].Source = digitImage; } }); } #endregion } }