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