using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reactive; using System.Text.Json; using System.Text.Json.Serialization; using Avalonia.Input; using ReactiveUI; using RedBookPlayer.Models; namespace RedBookPlayer.GUI.ViewModels { public class SettingsViewModel : ReactiveObject { #region Player Settings /// /// List of all data playback values /// [JsonIgnore] public List DataPlaybackValues => GenerateDataPlaybackList(); /// /// List of all disc handling values /// [JsonIgnore] public List DiscHandlingValues => GenerateDiscHandlingList(); /// /// List of all repeat mode values /// [JsonIgnore] public List RepeatModeValues => GenerateRepeatModeList(); /// /// List of all session handling values /// [JsonIgnore] public List SessionHandlingValues => GenerateSessionHandlingList(); /// /// List of all themes /// [JsonIgnore] public List ThemeValues => GenerateThemeList(); /// /// Indicates if discs should start playing on load /// public bool AutoPlay { get; set; } = false; /// /// Indicates the number of discs to allow loading and changing /// public int NumberOfDiscs { get; set; } = 1; /// /// Indicates how to deal with multiple discs /// public DiscHandling DiscHandling { get; set; } = DiscHandling.SingleDisc; /// /// Indicates if an index change can trigger a track change /// public bool IndexButtonChangeTrack { get; set; } = false; /// /// Indicates if hidden tracks should be played /// /// /// Hidden tracks can be one of the following: /// - TrackSequence == 0 /// - Larget pregap of track 1 (> 150 sectors) /// public bool PlayHiddenTracks { get; set; } = false; /// /// Generate a TOC if the disc is missing one /// public bool GenerateMissingTOC { get; set; } = true; /// /// Indicates how to deal with data tracks /// public DataPlayback DataPlayback { get; set; } = DataPlayback.Skip; /// /// Indicates how to repeat tracks /// public RepeatMode RepeatMode { get; set; } = RepeatMode.All; /// /// Indicates how to handle tracks on different sessions /// public SessionHandling SessionHandling { get; set; } = SessionHandling.FirstSessionOnly; /// /// Indicates the default playback volume /// public int Volume { get => _volume; private set { int tempValue; if(value > 100) tempValue = 100; else if(value < 0) tempValue = 0; else tempValue = value; this.RaiseAndSetIfChanged(ref _volume, tempValue); } } /// /// Indicates the currently selected theme /// public string SelectedTheme { get; set; } = "Default"; #endregion #region Key Mappings /// /// List of all keyboard keys /// [JsonIgnore] public List KeyboardList => GenerateKeyList(); /// /// Key assigned to open settings /// public Key OpenSettingsKey { get; set; } = Key.F1; /// /// Key assigned to load a new image /// public Key LoadImageKey { get; set; } = Key.F2; /// /// Key assigned to save the current track or all tracks /// public Key SaveTrackKey { get; set; } = Key.S; /// /// Key assigned to toggle play and pause /// public Key TogglePlaybackKey { get; set; } = Key.Space; /// /// Key assigned to stop playback /// public Key StopPlaybackKey { get; set; } = Key.Escape; /// /// Key assigned to eject the disc /// public Key EjectKey { get; set; } = Key.OemTilde; /// /// Key assigned to move to the next disc /// public Key NextDiscKey { get; set; } = Key.PageUp; /// /// Key assigned to move to the previous disc /// public Key PreviousDiscKey { get; set; } = Key.PageDown; /// /// Key assigned to move to the next track /// public Key NextTrackKey { get; set; } = Key.Right; /// /// Key assigned to move to the previous track /// public Key PreviousTrackKey { get; set; } = Key.Left; /// /// Key assigned to shuffling the track list /// public Key ShuffleTracksKey { get; set; } = Key.R; /// /// Key assigned to move to the next index /// public Key NextIndexKey { get; set; } = Key.OemCloseBrackets; /// /// Key assigned to move to the previous index /// public Key PreviousIndexKey { get; set; } = Key.OemOpenBrackets; /// /// Key assigned to fast forward playback /// public Key FastForwardPlaybackKey { get; set; } = Key.OemPeriod; /// /// Key assigned to rewind playback /// public Key RewindPlaybackKey { get; set; } = Key.OemComma; /// /// Key assigned to raise volume /// public Key VolumeUpKey { get; set; } = Key.Add; /// /// Key assigned to lower volume /// public Key VolumeDownKey { get; set; } = Key.Subtract; /// /// Key assigned to toggle mute /// public Key ToggleMuteKey { get; set; } = Key.M; /// /// Key assigned to toggle de-emphasis /// public Key ToggleDeEmphasisKey { get; set; } = Key.E; #endregion #region Commands /// /// Command for applying settings /// public ReactiveCommand ApplySettingsCommand { get; } #endregion /// /// Path to the settings file /// private string _filePath; /// /// Internal value for the volume /// private int _volume = 100; public SettingsViewModel() : this(null) { } public SettingsViewModel(string filePath) { _filePath = filePath; ApplySettingsCommand = ReactiveCommand.Create(ExecuteApplySettings); } /// /// Load settings from a file /// /// Path to the settings JSON file /// Settings derived from the input file, if possible public static SettingsViewModel Load(string filePath) { if(File.Exists(filePath)) { try { SettingsViewModel settings = JsonSerializer.Deserialize(File.ReadAllText(filePath)); settings._filePath = filePath; return settings; } catch(JsonException) { Console.WriteLine("Couldn't parse settings, reverting to default"); return new SettingsViewModel(filePath); } } return new SettingsViewModel(filePath); } /// /// Apply settings from the UI /// public void ExecuteApplySettings() { if(!string.IsNullOrWhiteSpace(SelectedTheme)) App.PlayerView?.ViewModel?.ApplyTheme(SelectedTheme); var options = new JsonSerializerOptions { WriteIndented = true }; string json = JsonSerializer.Serialize(this, options); File.WriteAllText(_filePath, json); } #region Generation /// /// Generate the list of DataPlayback values /// private List GenerateDataPlaybackList() => Enum.GetValues(typeof(DataPlayback)).Cast().ToList(); /// /// Generate the list of DiscHandling values /// private List GenerateDiscHandlingList() => Enum.GetValues(typeof(DiscHandling)).Cast().ToList(); /// /// Generate the list of Key values /// private List GenerateKeyList() => Enum.GetValues(typeof(Key)).Cast().ToList(); /// /// Generate the list of RepeatMode values /// private List GenerateRepeatModeList() => Enum.GetValues(typeof(RepeatMode)).Cast().ToList(); /// /// Generate the list of SessionHandling values /// private List GenerateSessionHandlingList() => Enum.GetValues(typeof(SessionHandling)).Cast().ToList(); /// /// Generate the list of valid themes /// private List GenerateThemeList() { // Create a list of all found themes List items = new List(); // Ensure the theme directory exists if(!Directory.Exists("themes/")) Directory.CreateDirectory("themes/"); // Add all theme directories if they're valid foreach(string dir in Directory.EnumerateDirectories("themes/")) { string themeName = dir.Split('/')[1]; if(!File.Exists($"themes/{themeName}/view.xaml")) continue; items.Add(themeName); } return items; } #endregion } }