diff --git a/Source/LibationAvalonia/App.axaml.cs b/Source/LibationAvalonia/App.axaml.cs index a064ac39..f02085c6 100644 --- a/Source/LibationAvalonia/App.axaml.cs +++ b/Source/LibationAvalonia/App.axaml.cs @@ -6,6 +6,11 @@ using LibationFileManager; using LibationAvalonia.Views; using System; using Avalonia.Platform; +using LibationAvalonia.Dialogs; +using System.Threading.Tasks; +using System.Collections.Generic; +using System.IO; +using ApplicationServices; namespace LibationAvalonia { @@ -31,6 +36,9 @@ namespace LibationAvalonia AssetLoader = AvaloniaLocator.Current.GetService(); } + public static Task> LibraryTask; + public static bool SetupRequired; + public override void OnFrameworkInitializationCompleted() { LoadStyles(); @@ -41,16 +49,140 @@ namespace LibationAvalonia if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { - var mainWindow = new MainWindow(); - desktop.MainWindow = mainWindow; - mainWindow.RestoreSizeAndLocation(Configuration.Instance); - mainWindow.OnLoad(); + if (SetupRequired) + { + var config = Configuration.Instance; + + var defaultLibationFilesDir = Configuration.UserProfile; + + // check for existing settings in default location + var defaultSettingsFile = Path.Combine(defaultLibationFilesDir, "Settings.json"); + if (Configuration.SettingsFileIsValid(defaultSettingsFile)) + config.SetLibationFiles(defaultLibationFilesDir); + + if (config.LibationSettingsAreValid) + return; + + var setupDialog = new SetupDialog { Config = config }; + setupDialog.Closing += Setup_Closing; + + desktop.MainWindow = setupDialog; + } + else + ShowMainWindow(desktop); } base.OnFrameworkInitializationCompleted(); } - private void LoadStyles() + private void Setup_Closing(object sender, System.ComponentModel.CancelEventArgs e) + { + var setupDialog = sender as SetupDialog; + var desktop = ApplicationLifetime as IClassicDesktopStyleApplicationLifetime; + + try + { + // all returns should be preceded by either: + // - if config.LibationSettingsAreValid + // - error message, Exit() + + if ((!setupDialog.IsNewUser + && !setupDialog.IsReturningUser) || + !RunInstall(setupDialog)) + { + CancelInstallation(); + return; + } + + + // most migrations go in here + AppScaffolding.LibationScaffolding.RunPostConfigMigrations(setupDialog.Config); + + MessageBox.VerboseLoggingWarning_ShowIfTrue(); + +#if !DEBUG + checkForUpdate(); +#endif + // logging is init'd here + AppScaffolding.LibationScaffolding.RunPostMigrationScaffolding(setupDialog.Config); + + } + catch (Exception ex) + { + var title = "Fatal error, pre-logging"; + var body = "An unrecoverable error occurred. Since this error happened before logging could be initialized, this error can not be written to the log file."; + try + { + MessageBox.ShowAdminAlert(null, body, title, ex); + } + catch + { + MessageBox.Show($"{body}\r\n\r\n{ex.Message}\r\n\r\n{ex.StackTrace}", title, MessageBoxButtons.OK, MessageBoxIcon.Error); + } + return; + } + + LibraryTask = Task.Run(() => DbContexts.GetLibrary_Flat_NoTracking(includeParents: true)); + AudibleUtilities.AudibleApiStorage.EnsureAccountsSettingsFileExists(); + ShowMainWindow(desktop); + } + + private static bool RunInstall(SetupDialog setupDialog) + { + var config = setupDialog.Config; + + if (setupDialog.IsNewUser) + { + config.SetLibationFiles(Configuration.UserProfile); + } + else if (setupDialog.IsReturningUser) + { + + var libationFilesDialog = new LibationFilesDialog(); + + if (libationFilesDialog.ShowDialogSynchronously(setupDialog) != DialogResult.OK) + return false; + + config.SetLibationFiles(libationFilesDialog.SelectedDirectory); + if (config.LibationSettingsAreValid) + return true; + + // path did not result in valid settings + var continueResult = MessageBox.Show( + $"No valid settings were found at this location.\r\nWould you like to create a new install settings in this folder?\r\n\r\n{libationFilesDialog.SelectedDirectory}", + "New install?", + MessageBoxButtons.YesNo, + MessageBoxIcon.Question); + + if (continueResult != DialogResult.Yes) + return false; + } + + // INIT DEFAULT SETTINGS + // if 'new user' was clicked, or if 'returning user' chose new install: show basic settings dialog + config.Books ??= Path.Combine(Configuration.UserProfile, "Books"); + + return new SettingsDialog().ShowDialogSynchronously(setupDialog) == DialogResult.OK + && config.LibationSettingsAreValid; + } + + static void CancelInstallation() + { + MessageBox.Show("Initial set up cancelled.", "Cancelled", MessageBoxButtons.OK, MessageBoxIcon.Warning); + Environment.Exit(0); + } + + private static void ShowMainWindow(IClassicDesktopStyleApplicationLifetime desktop) + { + var mainWindow = new MainWindow(); + desktop.MainWindow = mainWindow; + mainWindow.RestoreSizeAndLocation(Configuration.Instance); + mainWindow.OnLoad(); + mainWindow.OnLibraryLoaded(LibraryTask.GetAwaiter().GetResult()); + mainWindow.Show(); + } + + private static void LoadStyles() { ProcessQueueBookFailedBrush = AvaloniaUtils.GetBrushFromResources("ProcessQueueBookFailedBrush"); ProcessQueueBookCompletedBrush = AvaloniaUtils.GetBrushFromResources("ProcessQueueBookCompletedBrush"); diff --git a/Source/LibationAvalonia/AppBasic.axaml b/Source/LibationAvalonia/AppBasic.axaml new file mode 100644 index 00000000..910f2a87 --- /dev/null +++ b/Source/LibationAvalonia/AppBasic.axaml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/Source/LibationAvalonia/AppBasic.axaml.cs b/Source/LibationAvalonia/AppBasic.axaml.cs new file mode 100644 index 00000000..e3a82116 --- /dev/null +++ b/Source/LibationAvalonia/AppBasic.axaml.cs @@ -0,0 +1,28 @@ +using Avalonia; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Markup.Xaml; +using Avalonia.Controls; +using LibationAvalonia.Dialogs; + +namespace LibationAvalonia +{ + public class AppBasic : Application + { + public override void Initialize() + { + AvaloniaXamlLoader.Load(this); + } + public Window MainWindow { get; set; } + + public override void OnFrameworkInitializationCompleted() + { + if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + { + desktop.MainWindow = new SetupDialog(); + } + + base.OnFrameworkInitializationCompleted(); + } + + } +} \ No newline at end of file diff --git a/Source/LibationAvalonia/Dialogs/DialogWindow.cs b/Source/LibationAvalonia/Dialogs/DialogWindow.cs index f6d86c90..f30e9c47 100644 --- a/Source/LibationAvalonia/Dialogs/DialogWindow.cs +++ b/Source/LibationAvalonia/Dialogs/DialogWindow.cs @@ -8,6 +8,7 @@ namespace LibationAvalonia.Dialogs { public abstract class DialogWindow : Window { + public bool SaveAndRestorePosition { get; set; } = true; public Control ControlToFocusOnShow { get; set; } public DialogWindow() { @@ -21,16 +22,22 @@ namespace LibationAvalonia.Dialogs this.AttachDevTools(); #endif } + public DialogWindow(bool saveAndRestorePosition) : this() + { + SaveAndRestorePosition = saveAndRestorePosition; + } private void DialogWindow_Initialized(object sender, EventArgs e) { this.WindowStartupLocation = WindowStartupLocation.CenterOwner; - this.RestoreSizeAndLocation(Configuration.Instance); + if (SaveAndRestorePosition) + this.RestoreSizeAndLocation(Configuration.Instance); } private void DialogWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e) { - this.SaveSizeAndLocation(Configuration.Instance); + if (SaveAndRestorePosition) + this.SaveSizeAndLocation(Configuration.Instance); } private void DialogWindow_Opened(object sender, EventArgs e) diff --git a/Source/LibationAvalonia/Dialogs/LibationFilesDialog.axaml b/Source/LibationAvalonia/Dialogs/LibationFilesDialog.axaml index 9f0e5c94..0ddabd5e 100644 --- a/Source/LibationAvalonia/Dialogs/LibationFilesDialog.axaml +++ b/Source/LibationAvalonia/Dialogs/LibationFilesDialog.axaml @@ -17,6 +17,7 @@ Grid.Row="0" Margin="5" Directory="{Binding Directory, Mode=TwoWay}" + SubDirectory="" KnownDirectories="{Binding KnownDirectories}" /> + + + + diff --git a/Source/LibationAvalonia/Dialogs/SetupDialog.axaml.cs b/Source/LibationAvalonia/Dialogs/SetupDialog.axaml.cs new file mode 100644 index 00000000..4733c449 --- /dev/null +++ b/Source/LibationAvalonia/Dialogs/SetupDialog.axaml.cs @@ -0,0 +1,39 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; +using LibationFileManager; + +namespace LibationAvalonia.Dialogs +{ + public partial class SetupDialog : Window + { + public bool IsNewUser { get;private set; } + public bool IsReturningUser { get;private set; } + public Configuration Config { get; init; } + public SetupDialog() + { + InitializeComponent(); + +#if DEBUG + this.AttachDevTools(); +#endif + } + + public void NewUser_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e) + { + IsNewUser = true; + Close(DialogResult.OK); + } + + public void ReturningUser_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e) + { + IsReturningUser = true; + Close(DialogResult.OK); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } + } +} diff --git a/Source/LibationAvalonia/FormSaveExtension.cs b/Source/LibationAvalonia/FormSaveExtension.cs index 42f37128..6365b9ae 100644 --- a/Source/LibationAvalonia/FormSaveExtension.cs +++ b/Source/LibationAvalonia/FormSaveExtension.cs @@ -12,7 +12,7 @@ namespace LibationAvalonia static readonly WindowIcon WindowIcon; static FormSaveExtension() { - if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop && desktop.MainWindow is not null) WindowIcon = desktop.MainWindow.Icon; else WindowIcon = null; diff --git a/Source/LibationAvalonia/LibationAvalonia.csproj b/Source/LibationAvalonia/LibationAvalonia.csproj index 9ef599fb..50090c9e 100644 --- a/Source/LibationAvalonia/LibationAvalonia.csproj +++ b/Source/LibationAvalonia/LibationAvalonia.csproj @@ -80,6 +80,9 @@ + + AppBasic.axaml + ProcessBookControl.axaml diff --git a/Source/LibationAvalonia/MessageBox.cs b/Source/LibationAvalonia/MessageBox.cs index 81749201..0ad54af9 100644 --- a/Source/LibationAvalonia/MessageBox.cs +++ b/Source/LibationAvalonia/MessageBox.cs @@ -62,8 +62,8 @@ namespace LibationAvalonia public static DialogResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton) => ShowCoreAsync(null, text, caption, buttons, icon, defaultButton); -public static DialogResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon) - => ShowCoreAsync(null, text, caption, buttons, icon, MessageBoxDefaultButton.Button1); +public static DialogResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, bool saveAndRestorePosition = true) + => ShowCoreAsync(null, text, caption, buttons, icon, MessageBoxDefaultButton.Button1, saveAndRestorePosition); public static DialogResult Show(string text, string caption, MessageBoxButtons buttons) => ShowCoreAsync(null, text, caption, buttons, MessageBoxIcon.None, MessageBoxDefaultButton.Button1); public static DialogResult Show(string text, string caption) @@ -148,9 +148,9 @@ Libation. } - private static DialogResult ShowCoreAsync(Window owner, string message, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton) + private static DialogResult ShowCoreAsync(Window owner, string message, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, bool saveAndRestorePosition = true) { - var dialog = new MessageBoxWindow(); + var dialog = new MessageBoxWindow(saveAndRestorePosition); dialog.HideMinMaxBtns(); diff --git a/Source/LibationAvalonia/Program.cs b/Source/LibationAvalonia/Program.cs index 00b80f30..b5cf1d10 100644 --- a/Source/LibationAvalonia/Program.cs +++ b/Source/LibationAvalonia/Program.cs @@ -18,24 +18,33 @@ namespace LibationAvalonia static async Task Main() { + //***********************************************// + // // + // do not use Configuration before this line // + // // + //***********************************************// + // Migrations which must occur before configuration is loaded for the first time. Usually ones which alter the Configuration + var config = AppScaffolding.LibationScaffolding.RunPreConfigMigrations(); + + App.SetupRequired = !config.LibationSettingsAreValid; + //Start as much work in parallel as possible. - var runDbMigrationsTask = Task.Run(() => RunDbMigrations()); var classicLifetimeTask = Task.Run(() => new ClassicDesktopStyleApplicationLifetime()); var appBuilderTask = Task.Run(BuildAvaloniaApp); - if (!await runDbMigrationsTask) - return; - var dbLibraryTask = Task.Run(() => DbContexts.GetLibrary_Flat_NoTracking(includeParents: true)); + if (!App.SetupRequired) + { + if (!RunDbMigrations(config)) + return; + + App.LibraryTask = Task.Run(() => DbContexts.GetLibrary_Flat_NoTracking(includeParents: true)); + } + + (await appBuilderTask).SetupWithLifetime(await classicLifetimeTask); - var form1 = (Views.MainWindow)classicLifetimeTask.Result.MainWindow; - - form1.OnLibraryLoaded(await dbLibraryTask); - - var assets = AvaloniaLocator.Current.GetService(); - classicLifetimeTask.Result.Start(null); } @@ -44,20 +53,15 @@ namespace LibationAvalonia .UsePlatformDetect() .LogToTrace() .UseReactiveUI(); + public static AppBuilder BuildAvaloniaAppBasic() + => AppBuilder.Configure() + .UsePlatformDetect() + .LogToTrace(); - private static bool RunDbMigrations() + public static bool RunDbMigrations(Configuration config) { try { - //***********************************************// - // // - // do not use Configuration before this line // - // // - //***********************************************// - // Migrations which must occur before configuration is loaded for the first time. Usually ones which alter the Configuration - var config = AppScaffolding.LibationScaffolding.RunPreConfigMigrations(); - AudibleUtilities.AudibleApiStorage.EnsureAccountsSettingsFileExists(); - // most migrations go in here AppScaffolding.LibationScaffolding.RunPostConfigMigrations(config); AppScaffolding.LibationScaffolding.RunPostMigrationScaffolding(config); diff --git a/Source/LibationAvalonia/Properties/PublishProfiles/FolderProfile.pubxml b/Source/LibationAvalonia/Properties/PublishProfiles/FolderProfile.pubxml index 32cb4d79..510fb21c 100644 --- a/Source/LibationAvalonia/Properties/PublishProfiles/FolderProfile.pubxml +++ b/Source/LibationAvalonia/Properties/PublishProfiles/FolderProfile.pubxml @@ -6,7 +6,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121. Release Any CPU - ..\bin\Release\publish\linux-x64\ + ..\bin\publish\linux-x64\ FileSystem net6.0 linux-x64 diff --git a/Source/LibationFileManager/Configuration.cs b/Source/LibationFileManager/Configuration.cs index a86343c0..a3cb7ad3 100644 --- a/Source/LibationFileManager/Configuration.cs +++ b/Source/LibationFileManager/Configuration.cs @@ -345,7 +345,7 @@ namespace LibationFileManager #endregion #region known directories - public static string AppDir_Relative => $@".\{LIBATION_FILES_KEY}"; + public static string AppDir_Relative => $@".{Path.PathSeparator}{LIBATION_FILES_KEY}"; public static string AppDir_Absolute => Path.GetFullPath(Path.Combine(Path.GetDirectoryName(Exe.FileLocationOnDisk), LIBATION_FILES_KEY)); public static string MyDocs => Path.GetFullPath(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "Libation")); public static string WinTemp => Path.GetFullPath(Path.Combine(Path.GetTempPath(), "Libation")); @@ -522,8 +522,6 @@ namespace LibationFileManager public void SetLibationFiles(string directory) { - libationFilesPathCache = null; - // ensure exists if (!File.Exists(APPSETTINGS_JSON)) { @@ -532,6 +530,8 @@ namespace LibationFileManager System.Threading.Thread.Sleep(100); } + libationFilesPathCache = null; + var startingContents = File.ReadAllText(APPSETTINGS_JSON); var jObj = JObject.Parse(startingContents); diff --git a/Source/LibationWinForms/Program.cs b/Source/LibationWinForms/Program.cs index 2af09639..29d49a92 100644 --- a/Source/LibationWinForms/Program.cs +++ b/Source/LibationWinForms/Program.cs @@ -1,14 +1,12 @@ using System; +using System.Collections.Generic; using System.IO; using System.Linq; -using System.Threading.Tasks; using System.Windows.Forms; -using ApplicationServices; -using Avalonia; -using Avalonia.Controls.ApplicationLifetimes; -using Avalonia.ReactiveUI; +using Dinah.Core; using LibationFileManager; using LibationWinForms.Dialogs; +using Serilog; namespace LibationWinForms { @@ -20,98 +18,6 @@ namespace LibationWinForms [STAThread] static void Main() - { - var sw = System.Diagnostics.Stopwatch.StartNew(); - var config = LoadLibationConfig(); - - if (config is null) return; - - - var bmp = System.Drawing.SystemIcons.Error.ToBitmap(); - - /* - Results below compare startup times when parallelizing startup tasks vs when - running everything sequentially, from the entry point until after the call to - OnLoadedLibrary() returns. Tests were run on a ReadyToRun enabled release build. - - The first run is substantially slower than all subsequent runs for both serial - and parallel. This is most likely due to file system caching speeding up - subsequent runs, and it's significant because in the wild, most runs are "cold" - and will not benefit from caching. - - All times are in milliseconds. - - Run Parallel Serial - 1 2837 5835 - 2 1566 2774 - 3 1562 2316 - 4 1642 2388 - 5 1596 2391 - 6 1591 2358 - 7 1492 2363 - 8 1542 2335 - 9 1600 2418 - 10 1564 2359 - 11 1567 2379 - - Min 1492 2316 - Q1 1562 2358 - Med 1567 2379 - Q3 1600 2418 - Max 2837 5835 - */ - - void Form1_Load(object sender, EventArgs e) - { - sw.Stop(); - //MessageBox.Show(sw.ElapsedMilliseconds.ToString()); - } - - //For debug purposes, always run AvaloniaUI. - if (config.GetNonString("BetaOptIn")) - { - //Start as much work in parallel as possible. - var runDbMigrationsTask = Task.Run(() => RunDbMigrations(config)); - var classicLifetimeTask = Task.Run(() => new ClassicDesktopStyleApplicationLifetime()); - var appBuilderTask = Task.Run(BuildAvaloniaApp); - - if (!runDbMigrationsTask.GetAwaiter().GetResult()) - return; - - var runOtherMigrationsTask = Task.Run(() => RunOtherMigrations(config)); - var dbLibraryTask = Task.Run(() => DbContexts.GetLibrary_Flat_NoTracking(includeParents: true)); - - appBuilderTask.GetAwaiter().GetResult().SetupWithLifetime(classicLifetimeTask.GetAwaiter().GetResult()); - - if (!runOtherMigrationsTask.GetAwaiter().GetResult()) - return; - - var form1 = (AvaloniaUI.Views.MainWindow)classicLifetimeTask.Result.MainWindow; - form1.Opened += Form1_Load; - - form1.OnLibraryLoaded(dbLibraryTask.GetAwaiter().GetResult()); - - classicLifetimeTask.Result.Start(null); - } - else - { - if (!RunDbMigrations(config) || !RunOtherMigrations(config)) - return; - - var form1 = new Form1(); - form1.Shown += Form1_Load; - - System.Windows.Forms.Application.Run(form1); - } - } - - public static AppBuilder BuildAvaloniaApp() - => AppBuilder.Configure() - .UsePlatformDetect() - .LogToTrace() - .UseReactiveUI(); - - private static Configuration LoadLibationConfig() { try { @@ -120,7 +26,7 @@ namespace LibationWinForms //AllocConsole(); // run as early as possible. see notes in postLoggingGlobalExceptionHandling - System.Windows.Forms.Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException); + Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException); ApplicationConfiguration.Initialize(); @@ -131,40 +37,13 @@ namespace LibationWinForms //***********************************************// // Migrations which must occur before configuration is loaded for the first time. Usually ones which alter the Configuration var config = AppScaffolding.LibationScaffolding.RunPreConfigMigrations(); - AudibleUtilities.AudibleApiStorage.EnsureAccountsSettingsFileExists(); - return config; - } - catch (Exception ex) - { - DisplayStartupErrorMessage(ex); - return null; - } - } - - private static bool RunDbMigrations(Configuration config) - { - try - { // do this as soon as possible (post-config) RunInstaller(config); // most migrations go in here - AppScaffolding.LibationScaffolding.RunPostConfigMigrations(config); + AppScaffolding.LibationScaffolding.RunPostConfigMigrations(config); - return true; - } - catch (Exception ex) - { - DisplayStartupErrorMessage(ex); - return false; - } - } - - private static bool RunOtherMigrations(Configuration config) - { - try - { // migrations which require Forms or are long-running RunWindowsOnlyMigrations(config); @@ -175,36 +54,26 @@ namespace LibationWinForms #endif // logging is init'd here AppScaffolding.LibationScaffolding.RunPostMigrationScaffolding(config); - - // global exception handling (ShowAdminAlert) attempts to use logging. only call it after logging has been init'd -#if WINDOWS7_0_OR_GREATER - postLoggingGlobalExceptionHandling(); -#endif - - return true; } catch (Exception ex) { - DisplayStartupErrorMessage(ex); - return false; + var title = "Fatal error, pre-logging"; + var body = "An unrecoverable error occurred. Since this error happened before logging could be initialized, this error can not be written to the log file."; + try + { + MessageBoxLib.ShowAdminAlert(null, body, title, ex); + } + catch + { + MessageBox.Show($"{body}\r\n\r\n{ex.Message}\r\n\r\n{ex.StackTrace}", title, MessageBoxButtons.OK, MessageBoxIcon.Error); + } + return; } - } + // global exception handling (ShowAdminAlert) attempts to use logging. only call it after logging has been init'd + postLoggingGlobalExceptionHandling(); - private static void DisplayStartupErrorMessage(Exception ex) - { - var title = "Fatal error, pre-logging"; - var body = "An unrecoverable error occurred. Since this error happened before logging could be initialized, this error can not be written to the log file."; -#if WINDOWS7_0_OR_GREATER - try - { - MessageBoxLib.ShowAdminAlert(null, body, title, ex); - } - catch - { - MessageBox.Show($"{body}\r\n\r\n{ex.Message}\r\n\r\n{ex.StackTrace}", title, MessageBoxButtons.OK, MessageBoxIcon.Error); - } -#endif + Application.Run(new Form1()); } private static void RunInstaller(Configuration config) @@ -229,7 +98,7 @@ namespace LibationWinForms static void CancelInstallation() { MessageBox.Show("Initial set up cancelled.", "Cancelled", MessageBoxButtons.OK, MessageBoxIcon.Warning); - System.Windows.Forms.Application.Exit(); + Application.Exit(); Environment.Exit(0); } @@ -301,23 +170,19 @@ namespace LibationWinForms try { - upgradeProperties = AppScaffolding.LibationScaffolding.GetLatestRelease(); + upgradeProperties = AppScaffolding.LibationScaffolding.GetLatestRelease(); if (upgradeProperties is null) return; } catch (Exception ex) { -#if WINDOWS7_0_OR_GREATER MessageBoxLib.ShowAdminAlert(null, "Error checking for update", "Error checking for update", ex); -#endif return; } if (upgradeProperties.ZipUrl is null) { -#if WINDOWS7_0_OR_GREATER MessageBox.Show(upgradeProperties.HtmlUrl, "New version available"); -#endif return; } @@ -330,10 +195,10 @@ namespace LibationWinForms AppDomain.CurrentDomain.UnhandledException += (_, e) => MessageBoxLib.ShowAdminAlert(null, "Libation has crashed due to an unhandled error.", "Application crash!", (Exception)e.ExceptionObject); // these 2 lines makes it graceful. sync (eg in main form's ctor) and thread exceptions will still crash us, but event (sync, void async, Task async) will not - System.Windows.Forms.Application.ThreadException += (_, e) => MessageBoxLib.ShowAdminAlert(null, "Libation has encountered an unexpected error.", "Unexpected error", e.Exception); + Application.ThreadException += (_, e) => MessageBoxLib.ShowAdminAlert(null, "Libation has encountered an unexpected error.", "Unexpected error", e.Exception); // move to beginning of execution. crashes app if this is called post-RunInstaller: System.InvalidOperationException: 'Thread exception mode cannot be changed once any Controls are created on the thread.' //// I never found a case where including made a difference. I think this enum is default and including it will override app user config file //Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException); } } -} +} \ No newline at end of file