diff --git a/Knossos.NET/AppStyles.axaml b/Knossos.NET/AppStyles.axaml index ea5c8076..758a8213 100644 --- a/Knossos.NET/AppStyles.axaml +++ b/Knossos.NET/AppStyles.axaml @@ -69,10 +69,16 @@ + + + + M2 4.5C2 4.22386 2.22386 4 2.5 4H17.5C17.7761 4 18 4.22386 18 4.5C18 4.77614 17.7761 5 17.5 5H2.5C2.22386 5 2 4.77614 2 4.5Z M2 9.5C2 9.22386 2.22386 9 2.5 9H17.5C17.7761 9 18 9.22386 18 9.5C18 9.77614 17.7761 10 17.5 10H2.5C2.22386 10 2 9.77614 2 9.5Z M2.5 14C2.22386 14 2 14.2239 2 14.5C2 14.7761 2.22386 15 2.5 15H17.5C17.7761 15 18 14.7761 18 14.5C18 14.2239 17.7761 14 17.5 14H2.5Z + + #18191A - #422626 + #2d2d2d #131414 #257200 diff --git a/Knossos.NET/Assets/fs2_res/kn_banner.png b/Knossos.NET/Assets/fs2_res/kn_banner.png index 70d10132..6d818313 100644 Binary files a/Knossos.NET/Assets/fs2_res/kn_banner.png and b/Knossos.NET/Assets/fs2_res/kn_banner.png differ diff --git a/Knossos.NET/Assets/fs2_res/kn_screen_0.jpg b/Knossos.NET/Assets/fs2_res/kn_screen_0.jpg index 07ea3bae..71893723 100644 Binary files a/Knossos.NET/Assets/fs2_res/kn_screen_0.jpg and b/Knossos.NET/Assets/fs2_res/kn_screen_0.jpg differ diff --git a/Knossos.NET/Assets/fs2_res/kn_screen_1.jpg b/Knossos.NET/Assets/fs2_res/kn_screen_1.jpg index 695ec25e..ee3e26c9 100644 Binary files a/Knossos.NET/Assets/fs2_res/kn_screen_1.jpg and b/Knossos.NET/Assets/fs2_res/kn_screen_1.jpg differ diff --git a/Knossos.NET/Assets/fs2_res/kn_screen_10.jpg b/Knossos.NET/Assets/fs2_res/kn_screen_10.jpg index 7e08247d..5bca972a 100644 Binary files a/Knossos.NET/Assets/fs2_res/kn_screen_10.jpg and b/Knossos.NET/Assets/fs2_res/kn_screen_10.jpg differ diff --git a/Knossos.NET/Assets/fs2_res/kn_screen_11.jpg b/Knossos.NET/Assets/fs2_res/kn_screen_11.jpg index 0f4529ac..9e2e7cda 100644 Binary files a/Knossos.NET/Assets/fs2_res/kn_screen_11.jpg and b/Knossos.NET/Assets/fs2_res/kn_screen_11.jpg differ diff --git a/Knossos.NET/Assets/fs2_res/kn_screen_2.jpg b/Knossos.NET/Assets/fs2_res/kn_screen_2.jpg index 025448fa..d4ab79c2 100644 Binary files a/Knossos.NET/Assets/fs2_res/kn_screen_2.jpg and b/Knossos.NET/Assets/fs2_res/kn_screen_2.jpg differ diff --git a/Knossos.NET/Assets/fs2_res/kn_screen_3.jpg b/Knossos.NET/Assets/fs2_res/kn_screen_3.jpg index c4a1e9cf..76a4398a 100644 Binary files a/Knossos.NET/Assets/fs2_res/kn_screen_3.jpg and b/Knossos.NET/Assets/fs2_res/kn_screen_3.jpg differ diff --git a/Knossos.NET/Assets/fs2_res/kn_screen_4.jpg b/Knossos.NET/Assets/fs2_res/kn_screen_4.jpg index f19fdcd0..f6636718 100644 Binary files a/Knossos.NET/Assets/fs2_res/kn_screen_4.jpg and b/Knossos.NET/Assets/fs2_res/kn_screen_4.jpg differ diff --git a/Knossos.NET/Assets/fs2_res/kn_screen_5.jpg b/Knossos.NET/Assets/fs2_res/kn_screen_5.jpg index b175a628..1be98d32 100644 Binary files a/Knossos.NET/Assets/fs2_res/kn_screen_5.jpg and b/Knossos.NET/Assets/fs2_res/kn_screen_5.jpg differ diff --git a/Knossos.NET/Assets/fs2_res/kn_screen_6.jpg b/Knossos.NET/Assets/fs2_res/kn_screen_6.jpg index 82300221..3097ff62 100644 Binary files a/Knossos.NET/Assets/fs2_res/kn_screen_6.jpg and b/Knossos.NET/Assets/fs2_res/kn_screen_6.jpg differ diff --git a/Knossos.NET/Assets/fs2_res/kn_screen_7.jpg b/Knossos.NET/Assets/fs2_res/kn_screen_7.jpg index 01562e49..d0cf452b 100644 Binary files a/Knossos.NET/Assets/fs2_res/kn_screen_7.jpg and b/Knossos.NET/Assets/fs2_res/kn_screen_7.jpg differ diff --git a/Knossos.NET/Assets/fs2_res/kn_screen_8.jpg b/Knossos.NET/Assets/fs2_res/kn_screen_8.jpg index 89b08944..956cf260 100644 Binary files a/Knossos.NET/Assets/fs2_res/kn_screen_8.jpg and b/Knossos.NET/Assets/fs2_res/kn_screen_8.jpg differ diff --git a/Knossos.NET/Assets/fs2_res/kn_screen_9.jpg b/Knossos.NET/Assets/fs2_res/kn_screen_9.jpg index 0649a20d..eb58414a 100644 Binary files a/Knossos.NET/Assets/fs2_res/kn_screen_9.jpg and b/Knossos.NET/Assets/fs2_res/kn_screen_9.jpg differ diff --git a/Knossos.NET/Assets/fs2_res/kn_tile.png b/Knossos.NET/Assets/fs2_res/kn_tile.png index 7eaf9a4d..8d0c8934 100644 Binary files a/Knossos.NET/Assets/fs2_res/kn_tile.png and b/Knossos.NET/Assets/fs2_res/kn_tile.png differ diff --git a/Knossos.NET/Assets/general/NebulaDefault.png b/Knossos.NET/Assets/general/NebulaDefault.png index 54c47dd3..637651c5 100644 Binary files a/Knossos.NET/Assets/general/NebulaDefault.png and b/Knossos.NET/Assets/general/NebulaDefault.png differ diff --git a/Knossos.NET/Assets/general/clean.png b/Knossos.NET/Assets/general/clean.png new file mode 100644 index 00000000..e2846951 Binary files /dev/null and b/Knossos.NET/Assets/general/clean.png differ diff --git a/Knossos.NET/Assets/general/custom-config-icon.png b/Knossos.NET/Assets/general/custom-config-icon.png index f3f51235..b3f78199 100644 Binary files a/Knossos.NET/Assets/general/custom-config-icon.png and b/Knossos.NET/Assets/general/custom-config-icon.png differ diff --git a/Knossos.NET/Assets/general/discordicon.png b/Knossos.NET/Assets/general/discordicon.png index d13716b9..85c58e06 100644 Binary files a/Knossos.NET/Assets/general/discordicon.png and b/Knossos.NET/Assets/general/discordicon.png differ diff --git a/Knossos.NET/Assets/general/fred.png b/Knossos.NET/Assets/general/fred.png index f8f955d7..19c5dbff 100644 Binary files a/Knossos.NET/Assets/general/fred.png and b/Knossos.NET/Assets/general/fred.png differ diff --git a/Knossos.NET/Assets/general/fsolua.png b/Knossos.NET/Assets/general/fsolua.png index 11c044bb..35fbc1a1 100644 Binary files a/Knossos.NET/Assets/general/fsolua.png and b/Knossos.NET/Assets/general/fsolua.png differ diff --git a/Knossos.NET/Assets/general/github.png b/Knossos.NET/Assets/general/github.png index f4d53221..00154be8 100644 Binary files a/Knossos.NET/Assets/general/github.png and b/Knossos.NET/Assets/general/github.png differ diff --git a/Knossos.NET/Assets/general/loading.png b/Knossos.NET/Assets/general/loading.png index 9286bc5d..445690d5 100644 Binary files a/Knossos.NET/Assets/general/loading.png and b/Knossos.NET/Assets/general/loading.png differ diff --git a/Knossos.NET/Assets/general/menu_community.png b/Knossos.NET/Assets/general/menu_community.png new file mode 100644 index 00000000..77e88554 Binary files /dev/null and b/Knossos.NET/Assets/general/menu_community.png differ diff --git a/Knossos.NET/Assets/general/menu_debug.png b/Knossos.NET/Assets/general/menu_debug.png new file mode 100644 index 00000000..4fae816b Binary files /dev/null and b/Knossos.NET/Assets/general/menu_debug.png differ diff --git a/Knossos.NET/Assets/general/menu_develop.png b/Knossos.NET/Assets/general/menu_develop.png new file mode 100644 index 00000000..e77c51a8 Binary files /dev/null and b/Knossos.NET/Assets/general/menu_develop.png differ diff --git a/Knossos.NET/Assets/general/menu_engine.png b/Knossos.NET/Assets/general/menu_engine.png new file mode 100644 index 00000000..d8bec145 Binary files /dev/null and b/Knossos.NET/Assets/general/menu_engine.png differ diff --git a/Knossos.NET/Assets/general/menu_explore.png b/Knossos.NET/Assets/general/menu_explore.png new file mode 100644 index 00000000..85806958 Binary files /dev/null and b/Knossos.NET/Assets/general/menu_explore.png differ diff --git a/Knossos.NET/Assets/general/menu_multiplayer.png b/Knossos.NET/Assets/general/menu_multiplayer.png new file mode 100644 index 00000000..7103d8f1 Binary files /dev/null and b/Knossos.NET/Assets/general/menu_multiplayer.png differ diff --git a/Knossos.NET/Assets/general/menu_play.png b/Knossos.NET/Assets/general/menu_play.png new file mode 100644 index 00000000..79ddf471 Binary files /dev/null and b/Knossos.NET/Assets/general/menu_play.png differ diff --git a/Knossos.NET/Assets/general/menu_settings.png b/Knossos.NET/Assets/general/menu_settings.png new file mode 100644 index 00000000..f33e3135 Binary files /dev/null and b/Knossos.NET/Assets/general/menu_settings.png differ diff --git a/Knossos.NET/Assets/general/play-button.png b/Knossos.NET/Assets/general/play-button.png index d5cfb016..a29938ac 100644 Binary files a/Knossos.NET/Assets/general/play-button.png and b/Knossos.NET/Assets/general/play-button.png differ diff --git a/Knossos.NET/Assets/general/questionmark.png b/Knossos.NET/Assets/general/questionmark.png index cba02b01..66dcd945 100644 Binary files a/Knossos.NET/Assets/general/questionmark.png and b/Knossos.NET/Assets/general/questionmark.png differ diff --git a/Knossos.NET/Assets/general/refresh.png b/Knossos.NET/Assets/general/refresh.png index 894d2b17..014a7a91 100644 Binary files a/Knossos.NET/Assets/general/refresh.png and b/Knossos.NET/Assets/general/refresh.png differ diff --git a/Knossos.NET/Assets/general/restart.png b/Knossos.NET/Assets/general/restart.png index 1e4d00aa..4735dbe0 100644 Binary files a/Knossos.NET/Assets/general/restart.png and b/Knossos.NET/Assets/general/restart.png differ diff --git a/Knossos.NET/Assets/general/resume.png b/Knossos.NET/Assets/general/resume.png index 103ca9f9..a8436927 100644 Binary files a/Knossos.NET/Assets/general/resume.png and b/Knossos.NET/Assets/general/resume.png differ diff --git a/Knossos.NET/Assets/general/screenshot.png b/Knossos.NET/Assets/general/screenshot.png index 62a3e2ff..3cae4563 100644 Binary files a/Knossos.NET/Assets/general/screenshot.png and b/Knossos.NET/Assets/general/screenshot.png differ diff --git a/Knossos.NET/Assets/general/sort-icon.png b/Knossos.NET/Assets/general/sort-icon.png index a8f4d5e9..fdaa9e58 100644 Binary files a/Knossos.NET/Assets/general/sort-icon.png and b/Knossos.NET/Assets/general/sort-icon.png differ diff --git a/Knossos.NET/Assets/general/x.png b/Knossos.NET/Assets/general/x.png index 1c2281c0..391604f2 100644 Binary files a/Knossos.NET/Assets/general/x.png and b/Knossos.NET/Assets/general/x.png differ diff --git a/Knossos.NET/Classes/Knossos.cs b/Knossos.NET/Classes/Knossos.cs index b43dc33f..f64d5d85 100644 --- a/Knossos.NET/Classes/Knossos.cs +++ b/Knossos.NET/Classes/Knossos.cs @@ -72,10 +72,7 @@ public static async void StartUp(bool isQuickLaunch, bool forceUpdate) //Load knossos config globalSettings.Load(); - - if (MainWindowViewModel.Instance != null){ - MainWindowViewModel.Instance.applySettingsToList(); - } + MainWindowViewModel.Instance?.ApplySettings(); //Print Decompressor Type diff --git a/Knossos.NET/Converters/BitmapAssetValueConverter.cs b/Knossos.NET/Converters/BitmapAssetValueConverter.cs new file mode 100644 index 00000000..216cabe5 --- /dev/null +++ b/Knossos.NET/Converters/BitmapAssetValueConverter.cs @@ -0,0 +1,45 @@ +using Avalonia.Data.Converters; +using System; +using System.Globalization; +using Avalonia.Platform; +using System.Reflection; +using Avalonia.Media.Imaging; + +namespace Knossos.NET.Converters +{ + public class BitmapAssetValueConverter : IValueConverter + { + public static BitmapAssetValueConverter Instance { get; } = new(); + + public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + { + if (value == null) return null; + + if (value is not string rawUri || !targetType.IsAssignableFrom(typeof(Bitmap))) + { + throw new NotSupportedException(); + } + + Uri uri; + + if (rawUri.StartsWith("avares://")) + { + uri = new Uri(rawUri); + } + else + { + var assemblyName = Assembly.GetEntryAssembly()?.GetName().Name; + uri = new Uri($"avares://{assemblyName}/{rawUri.TrimStart('/')}"); + } + + var asset = AssetLoader.Open(uri); + + return new Bitmap(asset); + } + + public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/Knossos.NET/Models/GlobalSettings.cs b/Knossos.NET/Models/GlobalSettings.cs index 0ba510d3..33ad9309 100644 --- a/Knossos.NET/Models/GlobalSettings.cs +++ b/Knossos.NET/Models/GlobalSettings.cs @@ -121,6 +121,58 @@ public AutoUpdateFsoBuilds(bool stable = false, bool rc = false, bool nightly = [JsonPropertyName("warn_new_settings_system")] public bool warnNewSettingsSystem { get; set; } = true; + /* + * Settings that can wait to be saved at app close so we dont have to call save() all the time + * use JsonIgnore, private and '_' for the actual variable name + */ + [JsonIgnore] + private bool pendingChangesOnAppClose { get; set; } = false; + + [JsonIgnore] + private bool _mainMenuOpen = true; + [JsonPropertyName("main_menu_open")] + public bool mainMenuOpen + { + get { return _mainMenuOpen; } + set { if ( _mainMenuOpen != value ) { _mainMenuOpen = value; pendingChangesOnAppClose = true; } } + } + + [JsonIgnore] + private bool _hideBuildRC = true; + [JsonPropertyName("hide_build_rc")] + public bool hideBuildRC + { + get { return _hideBuildRC; } + set { if (_hideBuildRC != value) { _hideBuildRC = value; pendingChangesOnAppClose = true; } } + } + + [JsonIgnore] + private bool _hideBuildCustom = true; + [JsonPropertyName("hide_build_custom")] + public bool hideBuildCustom + { + get { return _hideBuildCustom; } + set { if (_hideBuildCustom != value) { _hideBuildCustom = value; pendingChangesOnAppClose = true; } } + } + + [JsonIgnore] + private bool _hideBuildNightly = true; + [JsonPropertyName("hide_build_nightly")] + public bool hideBuildNightly + { + get { return _hideBuildNightly; } + set { if (_hideBuildNightly != value) { _hideBuildNightly = value; pendingChangesOnAppClose = true; } } + } + + [JsonIgnore] + private MainWindowViewModel.SortType _sortType = MainWindowViewModel.SortType.name; + [JsonPropertyName("last_sort_type"), JsonConverter(typeof(JsonStringEnumConverter))] + public MainWindowViewModel.SortType sortType + { + get { return _sortType; } + set { if (_sortType != value) { _sortType = value; pendingChangesOnAppClose = true; } } + } + /* FSO Settings that use the fs2_open.ini are json ignored */ /* Video Settings */ @@ -210,15 +262,6 @@ public AutoUpdateFsoBuilds(bool stable = false, bool rc = false, bool nightly = [JsonIgnore] public string pxoPassword { get; set; } = ""; - [JsonPropertyName("hide_build_rc")] - public bool hideBuildRC { get; set; } = true; - [JsonPropertyName("hide_build_custom")] - public bool hideBuildCustom { get; set; } = false; - [JsonPropertyName("hide_build_nightly")] - public bool hideBuildNightly { get; set; } = true; - [JsonPropertyName("last_sort_type"), JsonConverter(typeof(JsonStringEnumConverter))] - public MainWindowViewModel.SortType sortType { get; set; } = MainWindowViewModel.SortType.name; - /* Developer Settings */ [JsonPropertyName("no_system_cmd")] public bool noSystemCMD { get; set; } = false; @@ -232,6 +275,18 @@ public AutoUpdateFsoBuilds(bool stable = false, bool rc = false, bool nightly = [JsonIgnore] private FileSystemWatcher? iniWatcher = null; + /// + /// Call this when the app is closing to save settings if we have pending changes + /// Note: this only applies to Knossos setting and not anything saved on the fs2_open.ini + /// + public void SaveSettingsOnAppClose() + { + if(pendingChangesOnAppClose) + { + Save(false); + } + } + /// /// When the User is on the settings tab we must watch the fs2_open.ini for external changes /// This is the initial call that must be called once, then we start or stop raising of events @@ -265,8 +320,13 @@ private void OnIniChanged(object sender, FileSystemEventArgs e) /// public void EnableIniWatch() { - if(iniWatcher != null) + if (iniWatcher != null) iniWatcher.EnableRaisingEvents = true; + else + { + StartWatchingDirectory(); + EnableIniWatch(); + } } /// @@ -294,12 +354,6 @@ private void ReadFS2IniValues() var data = parser.ReadFile(KnUtils.GetFSODataFolderPath() + Path.DirectorySeparatorChar + "fs2_open.ini"); data.Configuration.AssigmentSpacer = string.Empty; - if(iniWatcher == null) - { - StartWatchingDirectory(); - } - - //LEGACY ENTRIES, mostly read only by fso /* Default Section */ var resoItem = data["Default"]["VideocardFs2open"]; @@ -611,12 +665,13 @@ public void Load() envVars = tempSettings.envVars; showDevOptions = tempSettings.showDevOptions; warnNewSettingsSystem = tempSettings.warnNewSettingsSystem; - - if (MainWindowViewModel.Instance != null) - MainWindowViewModel.Instance.sharedSortType = tempSettings.sortType; + mainMenuOpen = tempSettings.mainMenuOpen; + sortType = tempSettings.sortType; ReadFS2IniValues(); Log.Add(Log.LogSeverity.Information, "GlobalSettings.Load()", "Global settings have been loaded"); + + pendingChangesOnAppClose = false; } } @@ -833,6 +888,7 @@ public void Save(bool writeIni = true) var json = JsonSerializer.Serialize(this, options); File.WriteAllText(KnUtils.GetKnossosDataFolderPath() + Path.DirectorySeparatorChar + "settings.json", json, new UTF8Encoding(false)); Log.Add(Log.LogSeverity.Information, "GlobalSettings.Save()", "Global settings have been saved."); + pendingChangesOnAppClose = false; } catch (Exception ex) { diff --git a/Knossos.NET/ViewModels/DebugViewModel.cs b/Knossos.NET/ViewModels/DebugViewModel.cs new file mode 100644 index 00000000..3fa401c1 --- /dev/null +++ b/Knossos.NET/ViewModels/DebugViewModel.cs @@ -0,0 +1,180 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using Knossos.NET.Models; +using Knossos.NET.Views; +using System; +using System.Diagnostics; +using System.IO; +namespace Knossos.NET.ViewModels +{ + public partial class DebugViewModel : ViewModelBase + { + [ObservableProperty] + internal string uiConsoleOutput = string.Empty; + + /// + /// Write a string to UI console on debug tab + /// + /// + public void WriteToUIConsole(string message) + { + UiConsoleOutput += "\n" + message; + } + + /* Debug Section */ + internal void OpenLog() + { + if (File.Exists(KnUtils.GetKnossosDataFolderPath() + Path.DirectorySeparatorChar + "Knossos.log")) + { + try + { + var cmd = new Process(); + cmd.StartInfo.FileName = KnUtils.GetKnossosDataFolderPath() + Path.DirectorySeparatorChar + "Knossos.log"; + cmd.StartInfo.UseShellExecute = true; + cmd.Start(); + cmd.Dispose(); + } + catch (Exception ex) + { + Log.Add(Log.LogSeverity.Error, "MainWindowViewModel.ReloadLog", ex); + } + } + else + { + if (MainWindow.instance != null) + MessageBox.Show(MainWindow.instance, "Log File " + KnUtils.GetKnossosDataFolderPath() + Path.DirectorySeparatorChar + "Knossos.log not found.", "File not found", MessageBox.MessageBoxButtons.OK); + } + } + + internal void OpenSettings() + { + if (File.Exists(KnUtils.GetKnossosDataFolderPath() + Path.DirectorySeparatorChar + "settings.json")) + { + try + { + var cmd = new Process(); + cmd.StartInfo.FileName = KnUtils.GetKnossosDataFolderPath() + Path.DirectorySeparatorChar + "settings.json"; + cmd.StartInfo.UseShellExecute = true; + cmd.Start(); + cmd.Dispose(); + } + catch (Exception ex) + { + Log.Add(Log.LogSeverity.Error, "MainWindowViewModel.ReloadLog", ex); + } + } + else + { + if (MainWindow.instance != null) + MessageBox.Show(MainWindow.instance, "Log File " + KnUtils.GetKnossosDataFolderPath() + Path.DirectorySeparatorChar + "settings.json not found.", "File not found", MessageBox.MessageBoxButtons.OK); + } + } + + internal void OpenFS2Log() + { + if (File.Exists(KnUtils.GetFSODataFolderPath() + Path.DirectorySeparatorChar + "data" + Path.DirectorySeparatorChar + "fs2_open.log")) + { + try + { + var cmd = new Process(); + cmd.StartInfo.FileName = KnUtils.GetFSODataFolderPath() + Path.DirectorySeparatorChar + "data" + Path.DirectorySeparatorChar + "fs2_open.log"; + cmd.StartInfo.UseShellExecute = true; + cmd.Start(); + cmd.Dispose(); + } + catch (Exception ex) + { + Log.Add(Log.LogSeverity.Error, "MainWindowViewModel.ReloadFS2Log", ex); + } + } + else + { + if (MainWindow.instance != null) + MessageBox.Show(MainWindow.instance, "Log File " + KnUtils.GetFSODataFolderPath() + Path.DirectorySeparatorChar + "data" + Path.DirectorySeparatorChar + "fs2_open.log not found.", "File not found", MessageBox.MessageBoxButtons.OK); + } + } + + internal void OpenFS2Ini() + { + if (File.Exists(KnUtils.GetFSODataFolderPath() + Path.DirectorySeparatorChar + "fs2_open.ini")) + { + try + { + var cmd = new Process(); + cmd.StartInfo.FileName = KnUtils.GetFSODataFolderPath() + Path.DirectorySeparatorChar + "fs2_open.ini"; + cmd.StartInfo.UseShellExecute = true; + cmd.Start(); + cmd.Dispose(); + } + catch (Exception ex) + { + Log.Add(Log.LogSeverity.Error, "MainWindowViewModel.ReloadFS2ini", ex); + } + } + else + { + if (MainWindow.instance != null) + MessageBox.Show(MainWindow.instance, "Log File " + KnUtils.GetFSODataFolderPath() + Path.DirectorySeparatorChar + "fs2_open.ini not found.", "File not found", MessageBox.MessageBoxButtons.OK); + } + } + + internal async void UploadFS2Log() + { + if (File.Exists(KnUtils.GetFSODataFolderPath() + Path.DirectorySeparatorChar + "data" + Path.DirectorySeparatorChar + "fs2_open.log")) + { + try + { + var logString = File.ReadAllText(KnUtils.GetFSODataFolderPath() + Path.DirectorySeparatorChar + "data" + Path.DirectorySeparatorChar + "fs2_open.log", System.Text.Encoding.UTF8); + if (logString.Trim() != string.Empty) + { + var status = await Nebula.UploadLog(logString); + if (!status) + { + if (MainWindow.instance != null) + await MessageBox.Show(MainWindow.instance, "An error has ocurred while uploading the log file, check the log below.", "Upload log error", MessageBox.MessageBoxButtons.OK); + } + } + else + { + if (MainWindow.instance != null) + await MessageBox.Show(MainWindow.instance, "The log file is empty.", "Error", MessageBox.MessageBoxButtons.OK); + } + } + catch (Exception ex) + { + Log.Add(Log.LogSeverity.Error, "MainWindowViewModel.UploadFS2Log", ex); + } + } + else + { + if (MainWindow.instance != null) + await MessageBox.Show(MainWindow.instance, "Log File " + KnUtils.GetFSODataFolderPath() + Path.DirectorySeparatorChar + "data" + Path.DirectorySeparatorChar + "fs2_open.log not found.", "File not found", MessageBox.MessageBoxButtons.OK); + } + } + internal async void UploadKnossosConsole() + { + try + { + var status = await Nebula.UploadLog(UiConsoleOutput); + if (!status) + { + if (MainWindow.instance != null) + await MessageBox.Show(MainWindow.instance, "An error has ocurred while uploading the console output, check the log below.", "Upload error", MessageBox.MessageBoxButtons.OK); + } + } + catch (Exception ex) + { + Log.Add(Log.LogSeverity.Error, "MainWindowViewModel.UploadKnossosConsole", ex); + } + } + + /// + /// Open Debug Filter Dialog + /// + internal async void OpenDebugFilterView() + { + var dialog = new Views.DebugFiltersView(); + dialog.DataContext = new DebugFiltersViewModel(); + await dialog.ShowDialog(MainWindow.instance!); + } + } +} diff --git a/Knossos.NET/ViewModels/GlobalSettingsViewModel.cs b/Knossos.NET/ViewModels/GlobalSettingsViewModel.cs index c6ab6d4c..eedb3009 100644 --- a/Knossos.NET/ViewModels/GlobalSettingsViewModel.cs +++ b/Knossos.NET/ViewModels/GlobalSettingsViewModel.cs @@ -19,6 +19,8 @@ namespace Knossos.NET.ViewModels /// public partial class GlobalSettingsViewModel : ViewModelBase { + private bool UnCommitedChanges = false; + /* Limiters definition */ private const long speedUnlimited = 0; private const long speedHalfMB = 850000; @@ -33,14 +35,7 @@ public partial class GlobalSettingsViewModel : ViewModelBase private const long speed9MB = 155000000; private const long speed10MB = 170000000; - [ObservableProperty] - internal bool blCfNebula = false; - [ObservableProperty] - internal bool blDlNebula = false; - [ObservableProperty] - internal bool blAigaion = false; - [ObservableProperty] - internal bool blTalos = false; + /* For display only */ [ObservableProperty] internal bool flagDataLoaded = false; @@ -48,17 +43,9 @@ public partial class GlobalSettingsViewModel : ViewModelBase internal bool enable16BitColor = false; [ObservableProperty] internal bool windowsOS = false; - - /* Knossos */ [ObservableProperty] internal string imgCacheSize = "0 MB"; [ObservableProperty] - internal string basePath = string.Empty; - [ObservableProperty] - internal bool enableLogFile = true; - [ObservableProperty] - internal int logLevel = 1; - [ObservableProperty] internal bool fs2RootPack = false; [ObservableProperty] internal string numberOfMods = string.Empty; @@ -72,132 +59,448 @@ public partial class GlobalSettingsViewModel : ViewModelBase internal bool isAVX = false; [ObservableProperty] internal bool isAVX2 = false; + + /* Knossos Settings */ + [ObservableProperty] - internal bool forceSSE2 = false; - [ObservableProperty] - internal int maxConcurrentSubtasks = 3; - [ObservableProperty] - internal long maxDownloadSpeedIndex = 0; - [ObservableProperty] - internal CompressionSettings modCompression = CompressionSettings.Manual; - [ObservableProperty] - internal int compressionMaxParallelism = 2; - [ObservableProperty] - internal bool checkUpdates = true; - [ObservableProperty] - internal bool autoUpdate = false; - [ObservableProperty] - internal bool deleteUploadedFiles = true; - [ObservableProperty] - internal bool updateNightly = false; - [ObservableProperty] - internal bool updateStable = false; - [ObservableProperty] - internal bool updateRC = false; - [ObservableProperty] - internal bool deleteOlder = false; - [ObservableProperty] - internal bool showDevOptions = false; + internal string basePath = string.Empty; //When this is changed settings are saved immediately. + + private bool blCfNebula = false; + internal bool BlCfNebula + { + get { return blCfNebula; } + set { if (blCfNebula != value) { this.SetProperty(ref blCfNebula, value); UnCommitedChanges = true; } } + } + + private bool blDlNebula = false; + internal bool BlDlNebula + { + get { return blDlNebula; } + set { if (blDlNebula != value) { this.SetProperty(ref blDlNebula, value); UnCommitedChanges = true; } } + } + + private bool blAigaion = false; + internal bool BlAigaion + { + get { return blAigaion; } + set { if (blAigaion != value) { this.SetProperty(ref blAigaion, value); UnCommitedChanges = true; } } + } + + private bool blTalos = false; + internal bool BlTalos + { + get { return blTalos; } + set { if (blTalos != value) { this.SetProperty(ref blTalos, value); UnCommitedChanges = true; } } + } + + private bool enableLogFile = true; + internal bool EnableLogFile + { + get { return enableLogFile; } + set { if (enableLogFile != value) { this.SetProperty(ref enableLogFile, value); UnCommitedChanges = true; } } + } + + private int logLevel = 1; + internal int LogLevel + { + get { return logLevel; } + set { if (logLevel != value) { this.SetProperty(ref logLevel, value); UnCommitedChanges = true; } } + } + + private bool forceSSE2 = false; + internal bool ForceSSE2 + { + get { return forceSSE2; } + set { if (forceSSE2 != value) { this.SetProperty(ref forceSSE2, value); UnCommitedChanges = true; } } + } + + private int maxConcurrentSubtasks = 3; + internal int MaxConcurrentSubtasks + { + get { return maxConcurrentSubtasks; } + set { if (maxConcurrentSubtasks != value) { this.SetProperty(ref maxConcurrentSubtasks, value); UnCommitedChanges = true; } } + } + + private long maxDownloadSpeedIndex = 0; + internal long MaxDownloadSpeedIndex + { + get { return maxDownloadSpeedIndex; } + set { if (maxDownloadSpeedIndex != value) { this.SetProperty(ref maxDownloadSpeedIndex, value); UnCommitedChanges = true; } } + } + + private CompressionSettings modCompression = CompressionSettings.Manual; + internal CompressionSettings ModCompression + { + get { return modCompression; } + set { if (modCompression != value) { this.SetProperty(ref modCompression, value); UnCommitedChanges = true; } } + } + + private int compressionMaxParallelism = 2; + internal int CompressionMaxParallelism + { + get { return compressionMaxParallelism; } + set { if (compressionMaxParallelism != value) { this.SetProperty(ref compressionMaxParallelism, value); UnCommitedChanges = true; } } + } + + private bool checkUpdates = true; + internal bool CheckUpdates + { + get { return checkUpdates; } + set { if (checkUpdates != value) { this.SetProperty(ref checkUpdates, value); UnCommitedChanges = true; } } + } + + private bool autoUpdate = false; + internal bool AutoUpdate + { + get { return autoUpdate; } + set { if (autoUpdate != value) { this.SetProperty(ref autoUpdate, value); UnCommitedChanges = true; } } + } + + private bool deleteUploadedFiles = true; + internal bool DeleteUploadedFiles + { + get { return deleteUploadedFiles; } + set { if (deleteUploadedFiles != value) { this.SetProperty(ref deleteUploadedFiles, value); UnCommitedChanges = true; } } + } + + private bool updateNightly = false; + internal bool UpdateNightly + { + get { return updateNightly; } + set { if (updateNightly != value) { this.SetProperty(ref updateNightly, value); UnCommitedChanges = true; } } + } + + private bool updateStable = false; + internal bool UpdateStable + { + get { return updateStable; } + set { if (updateStable != value) { this.SetProperty(ref updateStable, value); UnCommitedChanges = true; } } + } + + private bool updateRC = false; + internal bool UpdateRC + { + get { return updateRC; } + set { if (updateRC != value) { this.SetProperty(ref updateRC, value); UnCommitedChanges = true; } } + } + + private bool deleteOlder = false; + internal bool DeleteOlder + { + get { return deleteOlder; } + set { if (deleteOlder != value) { this.SetProperty(ref deleteOlder, value); UnCommitedChanges = true; } } + } + + private bool showDevOptions = false; + internal bool ShowDevOptions + { + get { return showDevOptions; } + set { if (showDevOptions != value) { this.SetProperty(ref showDevOptions, value); UnCommitedChanges = true; } } + } /*VIDEO*/ - [ObservableProperty] - internal int bitsSelectedIndex = 0; - [ObservableProperty] - internal int resolutionSelectedIndex = 0; - [ObservableProperty] - internal int textureSelectedIndex = 0; + private int bitsSelectedIndex = 0; + internal int BitsSelectedIndex + { + get { return bitsSelectedIndex; } + set { if (bitsSelectedIndex != value) { this.SetProperty(ref bitsSelectedIndex, value); UnCommitedChanges = true; } } + } + + private int resolutionSelectedIndex = 0; + internal int ResolutionSelectedIndex + { + get { return resolutionSelectedIndex; } + set { if (resolutionSelectedIndex != value) { this.SetProperty(ref resolutionSelectedIndex, value); UnCommitedChanges = true; } } + } + + private int textureSelectedIndex = 0; + internal int TextureSelectedIndex + { + get { return textureSelectedIndex; } + set { if (textureSelectedIndex != value) { this.SetProperty(ref textureSelectedIndex, value); UnCommitedChanges = true; } } + } + internal ObservableCollection ResolutionItems { get; set; } = new ObservableCollection(); - [ObservableProperty] - internal int shadowQualitySelectedIndex = 0; - [ObservableProperty] - internal int aaSelectedIndex = 5; - [ObservableProperty] - internal int msaaSelectedIndex = 0; - [ObservableProperty] - internal bool enableSoftParticles = true; - [ObservableProperty] - internal bool enableDeferredLighting = true; - [ObservableProperty] - internal int windowMode = 2; - [ObservableProperty] - internal bool vsync = true; - [ObservableProperty] - internal bool postProcess = true; - [ObservableProperty] - internal bool noFpsCapping = false; - [ObservableProperty] - internal bool showFps = false; + + private int shadowQualitySelectedIndex = 0; + internal int ShadowQualitySelectedIndex + { + get { return shadowQualitySelectedIndex; } + set { if (shadowQualitySelectedIndex != value) { this.SetProperty(ref shadowQualitySelectedIndex, value); UnCommitedChanges = true; } } + } + + private int aaSelectedIndex = 5; + internal int AaSelectedIndex + { + get { return aaSelectedIndex; } + set { if (aaSelectedIndex != value) { this.SetProperty(ref aaSelectedIndex, value); UnCommitedChanges = true; } } + } + + private int msaaSelectedIndex = 0; + internal int MsaaSelectedIndex + { + get { return msaaSelectedIndex; } + set { if (msaaSelectedIndex != value) { this.SetProperty(ref msaaSelectedIndex, value); UnCommitedChanges = true; } } + } + + private bool enableSoftParticles = true; + internal bool EnableSoftParticles + { + get { return enableSoftParticles; } + set { if (enableSoftParticles != value) { this.SetProperty(ref enableSoftParticles, value); UnCommitedChanges = true; } } + } + + private bool enableDeferredLighting = true; + internal bool EnableDeferredLighting + { + get { return enableDeferredLighting; } + set { if (enableDeferredLighting != value) { this.SetProperty(ref enableDeferredLighting, value); UnCommitedChanges = true; } } + } + + private int windowMode = 2; + internal int WindowMode + { + get { return windowMode; } + set { if (windowMode != value) { this.SetProperty(ref windowMode, value); UnCommitedChanges = true; } } + } + + private bool vsync = true; + internal bool Vsync + { + get { return vsync; } + set { if (vsync != value) { this.SetProperty(ref vsync, value); UnCommitedChanges = true; } } + } + + private bool postProcess = true; + internal bool PostProcess + { + get { return postProcess; } + set { if (postProcess != value) { this.SetProperty(ref postProcess, value); UnCommitedChanges = true; } } + } + + private bool noFpsCapping = false; + internal bool NoFpsCapping + { + get { return noFpsCapping; } + set { if (noFpsCapping != value) { this.SetProperty(ref noFpsCapping, value); UnCommitedChanges = true; } } + } + + private bool showFps = false; + internal bool ShowFps + { + get { return showFps; } + set { if (showFps != value) { this.SetProperty(ref showFps, value); UnCommitedChanges = true; } } + } /*AUDIO*/ - [ObservableProperty] - internal int playbackSelectedIndex = 0; + private int playbackSelectedIndex = 0; + internal int PlaybackSelectedIndex + { + get { return playbackSelectedIndex; } + set { if (playbackSelectedIndex != value) { this.SetProperty(ref playbackSelectedIndex, value); UnCommitedChanges = true; } } + } + internal ObservableCollection PlaybackItems { get; set; } = new ObservableCollection(); - [ObservableProperty] - internal int captureSelectedIndex = 0; + + private int captureSelectedIndex = 0; + internal int CaptureSelectedIndex + { + get { return captureSelectedIndex; } + set { if (captureSelectedIndex != value) { this.SetProperty(ref captureSelectedIndex, value); UnCommitedChanges = true; } } + } + internal ObservableCollection CaptureItems { get; set; } = new ObservableCollection(); - [ObservableProperty] - internal int sampleRateSelectedIndex = 0; - [ObservableProperty] - internal bool enableEFX = false; - [ObservableProperty] - internal bool disableAudio = false; - [ObservableProperty] - internal bool disableMusic = false; - [ObservableProperty] - internal bool enableTTS = true; - [ObservableProperty] - internal int voiceSelectedIndex = 0; + + private int sampleRateSelectedIndex = 0; + internal int SampleRateSelectedIndex + { + get { return sampleRateSelectedIndex; } + set { if (sampleRateSelectedIndex != value) { this.SetProperty(ref sampleRateSelectedIndex, value); UnCommitedChanges = true; } } + } + + private bool enableEFX = false; + internal bool EnableEFX + { + get { return enableEFX; } + set { if (enableEFX != value) { this.SetProperty(ref enableEFX, value); UnCommitedChanges = true; } } + } + + private bool disableAudio = false; + internal bool DisableAudio + { + get { return disableAudio; } + set { if (disableAudio != value) { this.SetProperty(ref disableAudio, value); UnCommitedChanges = true; } } + } + + private bool disableMusic = false; + internal bool DisableMusic + { + get { return disableMusic; } + set { if (disableMusic != value) { this.SetProperty(ref disableMusic, value); UnCommitedChanges = true; } } + } + + private bool enableTTS = true; + internal bool EnableTTS + { + get { return enableTTS; } + set { if (enableTTS != value) { this.SetProperty(ref enableTTS, value); UnCommitedChanges = true; } } + } + + private int voiceSelectedIndex = 0; + internal int VoiceSelectedIndex + { + get { return voiceSelectedIndex; } + set { if (voiceSelectedIndex != value) { this.SetProperty(ref voiceSelectedIndex, value); UnCommitedChanges = true; } } + } + internal ObservableCollection VoiceItems { get; set; } = new ObservableCollection(); - [ObservableProperty] - internal bool ttsTechroom = true; - [ObservableProperty] - internal bool ttsBriefings = true; - [ObservableProperty] - internal bool ttsIngame = true; - [ObservableProperty] - internal bool ttsMulti = true; - [ObservableProperty] - internal bool ttsDescription = true; - [ObservableProperty] - internal int ttsVolume = 100; - [ObservableProperty] - internal bool playingTTS = false; + + private bool ttsTechroom = true; + internal bool TtsTechroom + { + get { return ttsTechroom; } + set { if (ttsTechroom != value) { this.SetProperty(ref ttsTechroom, value); UnCommitedChanges = true; } } + } + + private bool ttsBriefings = true; + internal bool TtsBriefings + { + get { return ttsBriefings; } + set { if (ttsBriefings != value) { this.SetProperty(ref ttsBriefings, value); UnCommitedChanges = true; } } + } + + private bool ttsIngame = true; + internal bool TtsIngame + { + get { return ttsIngame; } + set { if (ttsIngame != value) { this.SetProperty(ref ttsIngame, value); UnCommitedChanges = true; } } + } + + private bool ttsMulti = true; + internal bool TtsMulti + { + get { return ttsMulti; } + set { if (ttsMulti != value) { this.SetProperty(ref ttsMulti, value); UnCommitedChanges = true; } } + } + + private bool ttsDescription = true; + internal bool TtsDescription + { + get { return ttsDescription; } + set { if (ttsDescription != value) { this.SetProperty(ref ttsDescription, value); UnCommitedChanges = true; } } + } + + private int ttsVolume = 100; + internal int TtsVolume + { + get { return ttsVolume; } + set { if (ttsVolume != value) { this.SetProperty(ref ttsVolume, value); UnCommitedChanges = true; } } + } + + private bool playingTTS = false; + internal bool PlayingTTS + { + get { return playingTTS; } + set { if (playingTTS != value) { this.SetProperty(ref playingTTS, value); UnCommitedChanges = true; } } + } /*JOYSTICK*/ internal ObservableCollection Joystick1Items { get; set; } = new ObservableCollection(); internal ObservableCollection Joystick2Items { get; set; } = new ObservableCollection(); internal ObservableCollection Joystick3Items { get; set; } = new ObservableCollection(); internal ObservableCollection Joystick4Items { get; set; } = new ObservableCollection(); - [ObservableProperty] - internal int joy1SelectedIndex = -1; - [ObservableProperty] - internal int joy2SelectedIndex = -1; - [ObservableProperty] - internal int joy3SelectedIndex = -1; - [ObservableProperty] - internal int joy4SelectedIndex = -1; + + private int joy1SelectedIndex = -1; + internal int Joy1SelectedIndex + { + get { return joy1SelectedIndex; } + set { if (joy1SelectedIndex != value) { this.SetProperty(ref joy1SelectedIndex, value); UnCommitedChanges = true; } } + } + + private int joy2SelectedIndex = -1; + internal int Joy2SelectedIndex + { + get { return joy2SelectedIndex; } + set { if (joy2SelectedIndex != value) { this.SetProperty(ref joy2SelectedIndex, value); UnCommitedChanges = true; } } + } + + private int joy3SelectedIndex = -1; + internal int Joy3SelectedIndex + { + get { return joy3SelectedIndex; } + set { if (joy3SelectedIndex != value) { this.SetProperty(ref joy3SelectedIndex, value); UnCommitedChanges = true; } } + } + + private int joy4SelectedIndex = -1; + internal int Joy4SelectedIndex + { + get { return joy4SelectedIndex; } + set { if (joy4SelectedIndex != value) { this.SetProperty(ref joy4SelectedIndex, value); UnCommitedChanges = true; } } + } + /* MOD / FS2 */ - internal string globalCmd = string.Empty; - [ObservableProperty] - internal int fs2LangSelectedIndex = 0; - [ObservableProperty] - internal uint multiPort = 7808; - [ObservableProperty] - internal uint mouseSensitivity = 5; - [ObservableProperty] - internal uint joystickSensitivity = 9; - [ObservableProperty] - internal uint joystickDeadZone = 10; - + + + private int fs2LangSelectedIndex = 0; + internal int Fs2LangSelectedIndex + { + get { return fs2LangSelectedIndex; } + set { if (fs2LangSelectedIndex != value) { this.SetProperty(ref fs2LangSelectedIndex, value); UnCommitedChanges = true; } } + } + + private uint multiPort = 7808; + internal uint MultiPort + { + get { return multiPort; } + set { if (multiPort != value) { this.SetProperty(ref multiPort, value); UnCommitedChanges = true; } } + } + + private uint mouseSensitivity = 5; + internal uint MouseSensitivity + { + get { return mouseSensitivity; } + set { if (mouseSensitivity != value) { this.SetProperty(ref mouseSensitivity, value); UnCommitedChanges = true; } } + } + + private uint joystickSensitivity = 9; + internal uint JoystickSensitivity + { + get { return joystickSensitivity; } + set { if (joystickSensitivity != value) { this.SetProperty(ref joystickSensitivity, value); UnCommitedChanges = true; } } + } + + private uint joystickDeadZone = 10; + internal uint JoystickDeadZone + { + get { return joystickDeadZone; } + set { if (joystickDeadZone != value) { this.SetProperty(ref joystickDeadZone, value); UnCommitedChanges = true; } } + } + + /* DEVELOPER */ - [ObservableProperty] - internal bool noSystemCMD = false; - [ObservableProperty] - internal string prefixCMD = string.Empty; - [ObservableProperty] - internal string envVars = string.Empty; + private bool noSystemCMD = false; + internal bool NoSystemCMD + { + get { return noSystemCMD; } + set { if (noSystemCMD != value) { this.SetProperty(ref noSystemCMD, value); UnCommitedChanges = true; } } + } + + private string prefixCMD = string.Empty; + internal string PrefixCMD + { + get { return prefixCMD; } + set { if (prefixCMD != value) { this.SetProperty(ref prefixCMD, value); UnCommitedChanges = true; } } + } + private string envVars = string.Empty; + internal string EnvVars + { + get { return envVars; } + set { if (envVars != value) { this.SetProperty(ref envVars, value); UnCommitedChanges = true; } } + } + + internal string globalCmd = string.Empty; // In order to have hidden dev options, we need a setter for globalCMD public string GlobalCmd { @@ -213,6 +516,7 @@ public string GlobalCmd } SetProperty(ref globalCmd, value.Replace("freespace2.com", "")); + UnCommitedChanges = true; } } @@ -220,6 +524,18 @@ public GlobalSettingsViewModel() { } + /// + /// Check if the settings where changed from the ones in the GlobalSettings instance compared to the ones here + /// If they did change update data stored in GlobalSettings and save file + /// + public void CommitPendingChanges() + { + if(UnCommitedChanges) + { + SaveCommand(); + } + } + /// /// Loads data from the GlobalSettings.cs class into this one to display it in the UI /// Also loads flag data from a FSO build, if one is installed @@ -285,6 +601,10 @@ public void LoadData() default: MaxDownloadSpeedIndex = 0; break; } + BlDlNebula = false; + BlCfNebula = false; + BlAigaion = false; + BlTalos = false; if (Knossos.globalSettings.mirrorBlacklist != null) { if (Knossos.globalSettings.mirrorBlacklist.Contains("dl.fsnebula.org")) @@ -716,6 +1036,8 @@ public void LoadData() //Multi Port MultiPort = Knossos.globalSettings.multiPort; + + UnCommitedChanges = false; } private FlagsJsonV1? GetFlagData() @@ -1043,6 +1365,7 @@ internal void SaveCommand() Knossos.globalSettings.multiPort = MultiPort; Knossos.globalSettings.Save(); + UnCommitedChanges = false; } /// diff --git a/Knossos.NET/ViewModels/ModListViewModel.cs b/Knossos.NET/ViewModels/ModListViewModel.cs index 300a6733..5b8d8f18 100644 --- a/Knossos.NET/ViewModels/ModListViewModel.cs +++ b/Knossos.NET/ViewModels/ModListViewModel.cs @@ -134,6 +134,10 @@ internal void ChangeSort(object sort) if (newSort != sortType) { + if (MainWindowViewModel.Instance != null && newSort != MainWindowViewModel.SortType.unsorted && MainWindowViewModel.Instance.sharedSortType != newSort ) + { + MainWindowViewModel.Instance.sharedSortType = newSort; + } LoadingAnimation.Animate = 1; Sorting = true; Dispatcher.UIThread.Invoke( () => diff --git a/Knossos.NET/ViewModels/NebulaModListViewModel.cs b/Knossos.NET/ViewModels/NebulaModListViewModel.cs index 4f862208..10313e6e 100644 --- a/Knossos.NET/ViewModels/NebulaModListViewModel.cs +++ b/Knossos.NET/ViewModels/NebulaModListViewModel.cs @@ -283,6 +283,10 @@ internal void ChangeSort(object sort) if (newSort != sortType) { + if (MainWindowViewModel.Instance != null && newSort != MainWindowViewModel.SortType.unsorted && MainWindowViewModel.Instance.sharedSortType != newSort) + { + MainWindowViewModel.Instance.sharedSortType = newSort; + } if (sortType != MainWindowViewModel.SortType.unsorted) { sorting = true; diff --git a/Knossos.NET/ViewModels/TaskViewModel.cs b/Knossos.NET/ViewModels/TaskViewModel.cs index bcd7725c..b5b2dd3b 100644 --- a/Knossos.NET/ViewModels/TaskViewModel.cs +++ b/Knossos.NET/ViewModels/TaskViewModel.cs @@ -28,9 +28,6 @@ public partial class TaskViewModel : ViewModelBase /// internal Queue taskQueue { get; set; } = new Queue(); - [ObservableProperty] - public bool showTaskList = false; - public TaskViewModel() { Instance = this; @@ -224,39 +221,6 @@ public string GetRunningTaskString() } } - /// - /// Hide the task panel - /// - public void HideCommand() - { - Dispatcher.UIThread.Invoke(() => - { - ShowTaskList = false; - }); - } - - /// - /// Show the task panel - /// - public void ShowCommand() - { - Dispatcher.UIThread.Invoke(() => - { - ShowTaskList = true; - }); - } - - /// - /// Toggle task panel visibility - /// - public void ToggleCommand() - { - Dispatcher.UIThread.Invoke(() => - { - ShowTaskList = !ShowTaskList; - }); - } - /// /// Return number of tasks in list /// diff --git a/Knossos.NET/ViewModels/Templates/FsoBuildPickerViewModel.cs b/Knossos.NET/ViewModels/Templates/FsoBuildPickerViewModel.cs index a89a4cce..96709ce6 100644 --- a/Knossos.NET/ViewModels/Templates/FsoBuildPickerViewModel.cs +++ b/Knossos.NET/ViewModels/Templates/FsoBuildPickerViewModel.cs @@ -32,7 +32,6 @@ internal bool HideRC { this.SetProperty(ref hideRC, value); Knossos.globalSettings.hideBuildRC = value; - Knossos.globalSettings.Save(false); BuildItems.ForEach(buildItem => { if(buildItem.Tag != null && buildItem.Tag?.ToString() == "rc") buildItem.IsVisible = !value; @@ -53,7 +52,6 @@ internal bool HideCustom if (hideCustom != value) { Knossos.globalSettings.hideBuildCustom = value; - Knossos.globalSettings.Save(false); this.SetProperty(ref hideCustom, value); BuildItems.ForEach(buildItem => { if (buildItem.Tag != null && buildItem.Tag?.ToString() == "custom") @@ -76,7 +74,6 @@ internal bool HideNightly { this.SetProperty(ref hideNightly, value); Knossos.globalSettings.hideBuildNightly = value; - Knossos.globalSettings.Save(false); BuildItems.ForEach(buildItem => { if (buildItem.Tag != null && buildItem.Tag?.ToString() == "nightly") buildItem.IsVisible = !value; diff --git a/Knossos.NET/ViewModels/Templates/TaskInfoButtonViewModel.cs b/Knossos.NET/ViewModels/Templates/TaskInfoButtonViewModel.cs index 82474d4d..d348c784 100644 --- a/Knossos.NET/ViewModels/Templates/TaskInfoButtonViewModel.cs +++ b/Knossos.NET/ViewModels/Templates/TaskInfoButtonViewModel.cs @@ -34,11 +34,6 @@ public TaskInfoButtonViewModel(TaskViewModel taskViewModel) timer.Start(); } - internal void ToggleTaskView() - { - TaskViewModel?.ToggleCommand(); - } - private void Update(object? _, System.Timers.ElapsedEventArgs __) { if(TaskViewModel != null) diff --git a/Knossos.NET/ViewModels/Windows/MainWindowViewModel.cs b/Knossos.NET/ViewModels/Windows/MainWindowViewModel.cs index 916136de..33b4a843 100644 --- a/Knossos.NET/ViewModels/Windows/MainWindowViewModel.cs +++ b/Knossos.NET/ViewModels/Windows/MainWindowViewModel.cs @@ -4,12 +4,15 @@ using System; using System.Threading.Tasks; using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.Linq; +using System.Collections.ObjectModel; +using Avalonia.Threading; namespace Knossos.NET.ViewModels { + public record MainViewMenuItem(ViewModelBase vm, string? iconRoute, string label, string tooltip); + /// /// Main Windows View Mode /// Everything starts here @@ -39,9 +42,19 @@ public partial class MainWindowViewModel : ViewModelBase [ObservableProperty] internal CommunityViewModel communityView = new CommunityViewModel(); [ObservableProperty] - internal string uiConsoleOutput = string.Empty; + internal DebugViewModel debugView = new DebugViewModel(); [ObservableProperty] internal TaskInfoButtonViewModel? taskInfoButton; + [ObservableProperty] + internal bool isMenuOpen = true; + [ObservableProperty] + internal ObservableCollection? menuItems; + [ObservableProperty] + private MainViewMenuItem? selectedMenuItem; + [ObservableProperty] + internal ViewModelBase? currentViewModel; + + internal string sharedSearch = string.Empty; @@ -56,79 +69,18 @@ public enum SortType unsorted } - internal SortType sharedSortType = SortType.name; - internal int tabIndex = 0; - internal int TabIndex + private SortType _sortType = SortType.name; //do not use directly + internal SortType sharedSortType { - get => tabIndex; + get { return _sortType; } set { - /* Execute code when user changes tab */ - if (value != tabIndex) + if (_sortType != value) { - // Things to do on tab exit - if (tabIndex == 0) //Exiting the Play tab. - { - sharedSearch = InstalledModsView.Search; - - // Change and save to the new sort type. - if (sharedSortType != InstalledModsView.sortType && InstalledModsView.sortType != SortType.unsorted) - { - sharedSortType = InstalledModsView.sortType; - Knossos.globalSettings.Save(false); - } - } - if (tabIndex == 1) //Exiting the Nebula tab. - { - sharedSearch = NebulaModsView.Search; - - if (sharedSortType != NebulaModsView.sortType && NebulaModsView.sortType != SortType.unsorted) - { - sharedSortType = NebulaModsView.sortType; - Knossos.globalSettings.Save(false); - } - } - - // Things to do on tab entrance - this.SetProperty(ref tabIndex, value); - if (tabIndex == 0) //Play Tab - { - InstalledModsView.Search = sharedSearch; - InstalledModsView.ChangeSort(sharedSortType); - } - if (tabIndex == 1) //Nebula Mods - { - NebulaModsView.OpenTab(sharedSearch, sharedSortType); - } - if (tabIndex == 3) //Dev Tab - { - DeveloperModsViewModel.Instance?.MaybeChangeSorting(); - DeveloperModView.UpdateBuildInstallButtons(); - } - if (tabIndex == 4) //Community Tab - { - Task.Run(async()=>{await CommunityView.LoadFAQRepo();}); - } - if (tabIndex == 5) //PXO - { - PxoViewModel.Instance!.InitialLoad(); - } - if (tabIndex == 6) //Settings - { - Knossos.globalSettings.Load(); - GlobalSettingsView.LoadData(); - Knossos.globalSettings.EnableIniWatch(); - GlobalSettingsView.UpdateImgCacheSize(); - } - else - { - Knossos.globalSettings.DisableIniWatch(); - } - if (tabIndex == 7) // Debug - { -// LoadDebugRepo - } - + //change sort and update globalsettings value + //to be saved at app close + this.SetProperty(ref _sortType, value); + Knossos.globalSettings.sortType = value; } } } @@ -151,9 +103,92 @@ public MainWindowViewModel() forceUpdate = true; } } + FillMenuItemsNormalMode(1); Knossos.StartUp(isQuickLaunch, forceUpdate); } + public void FillMenuItemsNormalMode(int defaultSelectedIndex) + { + Dispatcher.UIThread.Invoke(new Action(() => { + MenuItems = new ObservableCollection{ + new MainViewMenuItem(TaskView, null, "Tasks", "Overview of current running tasks"), + new MainViewMenuItem(InstalledModsView, "avares://Knossos.NET/Assets/general/menu_play.png", "Play", "View and run installed Freepsace Open games and modifications"), + new MainViewMenuItem(NebulaModsView, "avares://Knossos.NET/Assets/general/menu_explore.png", "Explore", "Search and install Freespace Open games and modifications"), + new MainViewMenuItem(FsoBuildsView, "avares://Knossos.NET/Assets/general/menu_engine.png", "Engine", "Download new Freespace Open engine builds"), + new MainViewMenuItem(DeveloperModView, "avares://Knossos.NET/Assets/general/menu_develop.png", "Develop", "Develop new games and modifications for the Freespace Open Engine"), + new MainViewMenuItem(CommunityView, "avares://Knossos.NET/Assets/general/menu_community.png", "Community", "FAQs and Community Resources"), + new MainViewMenuItem(PxoView, "avares://Knossos.NET/Assets/general/menu_multiplayer.png", "Multiplayer", "View multiplayer games using PXO servers"), + new MainViewMenuItem(GlobalSettingsView, "avares://Knossos.NET/Assets/general/menu_settings.png", "Settings", "Change global Freespace Open and Knossos.NET settings"), + new MainViewMenuItem(DebugView, "avares://Knossos.NET/Assets/general/menu_debug.png", "Debug", "Debug info") + }; + if (MenuItems != null && MenuItems.Count() - 1 > defaultSelectedIndex) + { + SelectedMenuItem = MenuItems[defaultSelectedIndex]; + } + })); + } + + /// + /// When the user clicks a sidebar menu item this code is called + /// + /// + partial void OnSelectedMenuItemChanged(MainViewMenuItem? value) + { + if (value != null) + { + // Things to do on tab exit + if (CurrentViewModel == InstalledModsView) //Exiting the Play tab. + { + sharedSearch = InstalledModsView.Search; + } + if (CurrentViewModel == NebulaModsView) //Exiting the Nebula tab. + { + sharedSearch = NebulaModsView.Search; + } + if(CurrentViewModel == GlobalSettingsView) //Exiting the settings view + { + GlobalSettingsView.CommitPendingChanges(); + } + + CurrentViewModel = value.vm; + + //Run code when entering a new view + if (CurrentViewModel == InstalledModsView) //Play Tab + { + InstalledModsView.Search = sharedSearch; + InstalledModsView.ChangeSort(sharedSortType); + } + if (CurrentViewModel == NebulaModsView) //Nebula Mods + { + NebulaModsView.OpenTab(sharedSearch, sharedSortType); + } + if (CurrentViewModel == DeveloperModView) //Dev Tab + { + DeveloperModsViewModel.Instance?.MaybeChangeSorting(); + DeveloperModView.UpdateBuildInstallButtons(); + } + if (CurrentViewModel == CommunityView) //Community Tab + { + Task.Run(async () => { await CommunityView.LoadFAQRepo(); }); + } + if (CurrentViewModel == PxoView) //PXO + { + PxoViewModel.Instance!.InitialLoad(); + } + if (CurrentViewModel == GlobalSettingsView) //Settings + { + Knossos.globalSettings.Load(); + GlobalSettingsView.LoadData(); + //Knossos.globalSettings.EnableIniWatch(); + GlobalSettingsView.UpdateImgCacheSize(); + } + else + { + //Knossos.globalSettings.DisableIniWatch(); + } + } + } + /* External Commands */ /// /// Add mod to DevMod tab @@ -272,183 +307,28 @@ public void GlobalSettingsLoadData() GlobalSettingsView.LoadData(); } - /// - /// Write a string to UI console on debug tab - /// - /// - public void WriteToUIConsole(string message) + internal void ApplySettings() { - UiConsoleOutput += "\n"+ message; + Dispatcher.UIThread.Invoke(() => { + IsMenuOpen = Knossos.globalSettings.mainMenuOpen; + sharedSortType = Knossos.globalSettings.sortType; + InstalledModsView?.ChangeSort(sharedSortType); + NebulaModsView.sortType = sharedSortType; + }); } - /* Debug Section */ - internal void OpenLog() - { - if (File.Exists(KnUtils.GetKnossosDataFolderPath() + Path.DirectorySeparatorChar + "Knossos.log")) - { - try - { - var cmd = new Process(); - cmd.StartInfo.FileName = KnUtils.GetKnossosDataFolderPath() + Path.DirectorySeparatorChar + "Knossos.log"; - cmd.StartInfo.UseShellExecute = true; - cmd.Start(); - cmd.Dispose(); - } - catch (Exception ex) - { - Log.Add(Log.LogSeverity.Error, "MainWindowViewModel.ReloadLog",ex); - } - } - else - { - if(MainWindow.instance != null) - MessageBox.Show(MainWindow.instance, "Log File " + KnUtils.GetKnossosDataFolderPath() + Path.DirectorySeparatorChar + "Knossos.log not found.","File not found",MessageBox.MessageBoxButtons.OK); - } - } - - internal void OpenSettings() - { - if (File.Exists(KnUtils.GetKnossosDataFolderPath() + Path.DirectorySeparatorChar + "settings.json")) - { - try - { - var cmd = new Process(); - cmd.StartInfo.FileName = KnUtils.GetKnossosDataFolderPath() + Path.DirectorySeparatorChar +"settings.json"; - cmd.StartInfo.UseShellExecute = true; - cmd.Start(); - cmd.Dispose(); - } - catch (Exception ex) - { - Log.Add(Log.LogSeverity.Error, "MainWindowViewModel.ReloadLog", ex); - } - } - else - { - if (MainWindow.instance != null) - MessageBox.Show(MainWindow.instance, "Log File " + KnUtils.GetKnossosDataFolderPath() + Path.DirectorySeparatorChar + "settings.json not found.", "File not found", MessageBox.MessageBoxButtons.OK); - } - } - - internal void OpenFS2Log() - { - if (File.Exists(KnUtils.GetFSODataFolderPath() + Path.DirectorySeparatorChar + "data" + Path.DirectorySeparatorChar + "fs2_open.log")) - { - try - { - var cmd = new Process(); - cmd.StartInfo.FileName = KnUtils.GetFSODataFolderPath() + Path.DirectorySeparatorChar + "data"+ Path.DirectorySeparatorChar + "fs2_open.log"; - cmd.StartInfo.UseShellExecute = true; - cmd.Start(); - cmd.Dispose(); - } - catch (Exception ex) - { - Log.Add(Log.LogSeverity.Error, "MainWindowViewModel.ReloadFS2Log", ex); - } - } - else - { - if (MainWindow.instance != null) - MessageBox.Show(MainWindow.instance, "Log File " + KnUtils.GetFSODataFolderPath() + Path.DirectorySeparatorChar+ "data"+ Path.DirectorySeparatorChar+"fs2_open.log not found.", "File not found", MessageBox.MessageBoxButtons.OK); - } - } - - internal void OpenFS2Ini() - { - if (File.Exists(KnUtils.GetFSODataFolderPath() + Path.DirectorySeparatorChar+ "fs2_open.ini")) - { - try - { - var cmd = new Process(); - cmd.StartInfo.FileName = KnUtils.GetFSODataFolderPath() + Path.DirectorySeparatorChar + "fs2_open.ini"; - cmd.StartInfo.UseShellExecute = true; - cmd.Start(); - cmd.Dispose(); - } - catch (Exception ex) - { - Log.Add(Log.LogSeverity.Error, "MainWindowViewModel.ReloadFS2ini", ex); - } - } - else - { - if (MainWindow.instance != null) - MessageBox.Show(MainWindow.instance, "Log File " + KnUtils.GetFSODataFolderPath() + Path.DirectorySeparatorChar + "fs2_open.ini not found.", "File not found", MessageBox.MessageBoxButtons.OK); - } - } - - internal async void UploadFS2Log() - { - if (File.Exists(KnUtils.GetFSODataFolderPath() + Path.DirectorySeparatorChar + "data" + Path.DirectorySeparatorChar + "fs2_open.log")) - { - try - { - var logString = File.ReadAllText(KnUtils.GetFSODataFolderPath() + Path.DirectorySeparatorChar + "data" + Path.DirectorySeparatorChar + "fs2_open.log",System.Text.Encoding.UTF8); - if(logString.Trim() != string.Empty) - { - var status = await Nebula.UploadLog(logString); - if(!status) - { - if (MainWindow.instance != null) - await MessageBox.Show(MainWindow.instance, "An error has ocurred while uploading the log file, check the log below.", "Upload log error", MessageBox.MessageBoxButtons.OK); - } - } - else - { - if (MainWindow.instance != null) - await MessageBox.Show(MainWindow.instance, "The log file is empty.", "Error", MessageBox.MessageBoxButtons.OK); - } - } - catch (Exception ex) - { - Log.Add(Log.LogSeverity.Error, "MainWindowViewModel.UploadFS2Log", ex); - } - } - else - { - if (MainWindow.instance != null) - await MessageBox.Show(MainWindow.instance, "Log File " + KnUtils.GetFSODataFolderPath() + Path.DirectorySeparatorChar + "data" + Path.DirectorySeparatorChar + "fs2_open.log not found.", "File not found", MessageBox.MessageBoxButtons.OK); - } - } - internal async void UploadKnossosConsole() - { - try - { - var status = await Nebula.UploadLog(UiConsoleOutput); - if (!status) - { - if (MainWindow.instance != null) - await MessageBox.Show(MainWindow.instance, "An error has ocurred while uploading the console output, check the log below.", "Upload error", MessageBox.MessageBoxButtons.OK); - } - } - catch (Exception ex) - { - Log.Add(Log.LogSeverity.Error, "MainWindowViewModel.UploadKnossosConsole", ex); - } + public void UpdateBuildInstallButtons(){ + DeveloperModView?.UpdateBuildNames(LatestStable, LatestNightly); + QuickSetupViewModel.Instance?.UpdateBuildName(LatestStable); } /// - /// Open Debug Filter Dialog + /// Write a string to UI console on debug tab /// - internal async void OpenDebugFilterView() - { - var dialog = new Views.DebugFiltersView(); - dialog.DataContext = new DebugFiltersViewModel(); - await dialog.ShowDialog(MainWindow.instance!); - } - - internal void applySettingsToList() + /// + public void WriteToUIConsole(string message) { - if (InstalledModsView != null) - { - InstalledModsView.ChangeSort(sharedSortType); - } - } - - public void UpdateBuildInstallButtons(){ - DeveloperModView?.UpdateBuildNames(LatestStable, LatestNightly); - QuickSetupViewModel.Instance?.UpdateBuildName(LatestStable); + DebugView.WriteToUIConsole(message); } /// @@ -465,5 +345,11 @@ internal void OpenScreenshotsFolder() Log.Add(Log.LogSeverity.Error, "MainWindowViewModel.OpenScreenshotsFolder", ex); } } + + internal void TriggerMenuCommand() + { + IsMenuOpen = !IsMenuOpen; + Knossos.globalSettings.mainMenuOpen = IsMenuOpen; + } } } diff --git a/Knossos.NET/ViewModels/Windows/ModSettingsViewModel.cs b/Knossos.NET/ViewModels/Windows/ModSettingsViewModel.cs index 803e9333..7b591b0c 100644 --- a/Knossos.NET/ViewModels/Windows/ModSettingsViewModel.cs +++ b/Knossos.NET/ViewModels/Windows/ModSettingsViewModel.cs @@ -315,7 +315,6 @@ internal void SaveSettingsCommand() modJson.modSettings.ignoreGlobalCmd = IgnoreGlobalCmd; modJson.modSettings.Save(); - Knossos.globalSettings.Save(false); if(modCardViewModel != null) { modCardViewModel.CheckDependencyActiveVersion(); diff --git a/Knossos.NET/Views/DebugView.axaml b/Knossos.NET/Views/DebugView.axaml new file mode 100644 index 00000000..052cd511 --- /dev/null +++ b/Knossos.NET/Views/DebugView.axaml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/Knossos.NET/Views/DebugView.axaml.cs b/Knossos.NET/Views/DebugView.axaml.cs new file mode 100644 index 00000000..ac1b6996 --- /dev/null +++ b/Knossos.NET/Views/DebugView.axaml.cs @@ -0,0 +1,13 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace Knossos.NET.Views; + +public partial class DebugView : UserControl +{ + public DebugView() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/Knossos.NET/Views/GlobalSettingsView.axaml b/Knossos.NET/Views/GlobalSettingsView.axaml index d1201081..b81ebca2 100644 --- a/Knossos.NET/Views/GlobalSettingsView.axaml +++ b/Knossos.NET/Views/GlobalSettingsView.axaml @@ -2,7 +2,7 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="2000" + mc:Ignorable="d" d:DesignWidth="1000" d:DesignHeight="2500" x:Class="Knossos.NET.Views.GlobalSettingsView" xmlns:v="using:Knossos.NET.Views" xmlns:vm="using:Knossos.NET.ViewModels" @@ -13,17 +13,11 @@ - - - - - - - - - Please navigate to another tab before playing, as this tab constantly scans for option file changes. - - + + + + + @@ -64,12 +58,12 @@ - - + + - - + + @@ -79,8 +73,8 @@ Delete older versions - - + + @@ -128,8 +122,8 @@ - - + + @@ -210,34 +204,34 @@ - - + + - - + + - - + + - - + + - - + + - - + + @@ -271,23 +265,23 @@ - - + + - - + + - - + + - - + + Voice @@ -417,8 +411,8 @@ - - + + diff --git a/Knossos.NET/Views/ModListView.axaml b/Knossos.NET/Views/ModListView.axaml index 37c4c689..fd2da1fd 100644 --- a/Knossos.NET/Views/ModListView.axaml +++ b/Knossos.NET/Views/ModListView.axaml @@ -16,7 +16,7 @@ - + - + diff --git a/Knossos.NET/Views/TaskView.axaml b/Knossos.NET/Views/TaskView.axaml index 9eca170f..c33d3e0d 100644 --- a/Knossos.NET/Views/TaskView.axaml +++ b/Knossos.NET/Views/TaskView.axaml @@ -2,7 +2,7 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - mc:Ignorable="d" d:DesignWidth="350" d:DesignHeight="450" + mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="600" x:Class="Knossos.NET.Views.TaskView" xmlns:v="using:Knossos.NET.Views" xmlns:vm="using:Knossos.NET.ViewModels" @@ -13,16 +13,13 @@ - - - - - - - - - - + + + + + diff --git a/Knossos.NET/Views/Templates/TaskInfoButtonView.axaml b/Knossos.NET/Views/Templates/TaskInfoButtonView.axaml index bcf96fe2..0ad27ccc 100644 --- a/Knossos.NET/Views/Templates/TaskInfoButtonView.axaml +++ b/Knossos.NET/Views/Templates/TaskInfoButtonView.axaml @@ -9,11 +9,11 @@ xmlns:vm="using:Knossos.NET.ViewModels" x:DataType="vm:TaskInfoButtonViewModel"> - + diff --git a/Knossos.NET/Views/Templates/TaskItemView.axaml b/Knossos.NET/Views/Templates/TaskItemView.axaml index 5e106b48..72b53755 100644 --- a/Knossos.NET/Views/Templates/TaskItemView.axaml +++ b/Knossos.NET/Views/Templates/TaskItemView.axaml @@ -20,7 +20,7 @@ - + @@ -32,7 +32,7 @@ - + - + - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - + + + + + + + diff --git a/Knossos.NET/Views/Windows/MainWindow.axaml.cs b/Knossos.NET/Views/Windows/MainWindow.axaml.cs index be5acedb..cd6da281 100644 --- a/Knossos.NET/Views/Windows/MainWindow.axaml.cs +++ b/Knossos.NET/Views/Windows/MainWindow.axaml.cs @@ -1,22 +1,38 @@ using Avalonia.Controls; -using System.ComponentModel; -using System.Threading.Tasks; +using Avalonia.Threading; +using Knossos.NET.ViewModels; namespace Knossos.NET.Views { public partial class MainWindow : Window { public static MainWindow? instance; + private static bool canClose = false; + public MainWindow() { instance = this; InitializeComponent(); - this.Closing += MainWindow_StopTTS; } - private void MainWindow_StopTTS(object? sender, CancelEventArgs e) + protected override async void OnClosing(WindowClosingEventArgs e) { - Knossos.Tts(string.Empty); + //Intercept closing, do stuff, then re-call close + if (!canClose) + { + e.Cancel = true; + + await Dispatcher.UIThread.InvokeAsync(() => { + Knossos.Tts(string.Empty); + MainWindowViewModel.Instance?.GlobalSettingsView.CommitPendingChanges(); + Knossos.globalSettings.SaveSettingsOnAppClose(); + canClose = true; + }); + + if (canClose) + this.Close(); + } + base.OnClosing(e); } } } diff --git a/Knossos.NET/Views/Windows/ModSettingsView.axaml b/Knossos.NET/Views/Windows/ModSettingsView.axaml index 76e52ffc..5274e9f4 100644 --- a/Knossos.NET/Views/Windows/ModSettingsView.axaml +++ b/Knossos.NET/Views/Windows/ModSettingsView.axaml @@ -19,12 +19,8 @@ - - - - - - + + @@ -63,6 +59,9 @@ + + + diff --git a/Knossos.NET/Views/Windows/ModSettingsView.axaml.cs b/Knossos.NET/Views/Windows/ModSettingsView.axaml.cs index dad50c67..1d019d58 100644 --- a/Knossos.NET/Views/Windows/ModSettingsView.axaml.cs +++ b/Knossos.NET/Views/Windows/ModSettingsView.axaml.cs @@ -1,12 +1,42 @@ using Avalonia.Controls; +using Avalonia.Threading; +using Knossos.NET.ViewModels; +using System.Threading.Tasks; namespace Knossos.NET.Views { public partial class ModSettingsView : Window { + private bool canClose = false; + public ModSettingsView() { InitializeComponent(); } + + protected override async void OnClosing(WindowClosingEventArgs e) + { + //Intercept closing, do stuff, then re-call close + if (DataContext != null) + { + var vm = DataContext as ModSettingsViewModel; + if (vm != null) + { + if (!canClose) + { + e.Cancel = true; + + await Dispatcher.UIThread.InvokeAsync(() => { + vm.SaveSettingsCommand(); + canClose = true; + }); + + if (canClose) + this.Close(); + } + } + } + base.OnClosing(e); + } } }