diff --git a/Emerald/App.xaml.cs b/Emerald/App.xaml.cs
index 16414ea8..d643e6a3 100644
--- a/Emerald/App.xaml.cs
+++ b/Emerald/App.xaml.cs
@@ -5,42 +5,55 @@
using Uno.UI.HotDesign;
using Microsoft.Extensions.DependencyInjection;
using Emerald.CoreX.Store.Modrinth;
+using System.Diagnostics;
+using System;
+using Emerald.Helpers;
namespace Emerald;
public partial class App : Application
{
+ private Helpers.Settings.SettingsSystem SS;
///
/// Initializes the singleton application object. This is the first line of authored code
/// executed, and as such is the logical equivalent of main() or WinMain().
///
public App()
{
- this.InitializeComponent();
+ this.InitializeComponent();
+
+ // Register exception handlers
+
+ this.UnhandledException += App_UnhandledException;
+ AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
+ TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
}
+
public Window? MainWindow { get; private set; }
protected IHost? Host { get; private set; }
- public void ConfigureServices(IServiceCollection services)
+ private void ConfigureServices(IServiceCollection services)
{
-
+ //Stores
services.AddTransient(provider => new ModStore(typeof(ModStore).Log()));
services.AddTransient(provider => new PluginStore(typeof(PluginStore).Log()));
services.AddTransient(provider => new ResourcePackStore(typeof(ResourcePackStore).Log()));
services.AddTransient(provider => new ResourcePackStore(typeof(ShaderStore).Log()));
services.AddTransient(provider => new ModpackStore(typeof(ModpackStore).Log()));
-
+
+ //Settings
+ services.AddSingleton();
+
+
}
- protected override void OnLaunched(LaunchActivatedEventArgs args)
+ protected override async void OnLaunched(LaunchActivatedEventArgs args)
{
-
var logPath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"Emerald",
"logs",
"app_.log");
-
var builder = this.CreateBuilder(args)
.Configure(host => host
#if DEBUG
@@ -54,7 +67,7 @@ protected override void OnLaunched(LaunchActivatedEventArgs args)
.WriteTo.File(logPath,
rollingInterval: RollingInterval.Day,
retainedFileCountLimit: 7,
- outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}.{Method}) {Message}{NewLine}{Exception}"))
+ outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}) {Message}{NewLine}{Exception}"))
.ConfigureServices((context, services) =>
{
@@ -71,8 +84,9 @@ protected override void OnLaunched(LaunchActivatedEventArgs args)
Host = builder.Build();
//Help me.
- ServiceLocator.SetLocatorProvider(() => new Emerald.Helpers.Services.ServiceProviderLocator(Host!.Services));
+ ServiceLocator.SetLocatorProvider(() => new Emerald.Services.ServiceProviderLocator(Host!.Services));
+ SS = ServiceLocator.Current.GetInstance();
this.Log().LogInformation("New Instance was created. Logs are being saved at: {logPath}",logPath);
// Do not repeat app initialization when the Window already has content,
@@ -82,6 +96,9 @@ protected override void OnLaunched(LaunchActivatedEventArgs args)
// Create a Frame to act as the navigation context and navigate to the first page
rootFrame = new Frame();
+ //load settings,
+ SS.LoadData();
+
// Place the frame in the current Window
MainWindow.Content = rootFrame;
}
@@ -95,10 +112,102 @@ protected override void OnLaunched(LaunchActivatedEventArgs args)
}
// Ensure the current window is active
MainWindow.Activate();
+
+ MainWindow.Closed += MainWindow_Closed;
+ }
+
+ private void MainWindow_Closed(object sender, WindowEventArgs args)
+ {
+ //save settings,
+ SS.SaveData();
}
///
/// Gets the current instance in use
///
public new static App Current => (App)Application.Current;
+
+ #region UnhandledExceptions
+ private void App_UnhandledException(object sender, Microsoft.UI.Xaml.UnhandledExceptionEventArgs e)
+ {
+ var logPath = Path.Combine(
+ Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
+ "Emerald");
+ e.Handled = true;
+ LogUnhandledException(e.Exception, "UI UnhandledException");
+ ShowPlatformErrorDialog($"An unexpected error occurred. The application needs to be closed.\n see logs at {logPath} for more details");
+ }
+
+ private void CurrentDomain_UnhandledException(object sender, System.UnhandledExceptionEventArgs e)
+ {
+ var logPath = Path.Combine(
+ Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
+ "Emerald");
+ LogUnhandledException((Exception)e.ExceptionObject, "AppDomain UnhandledException");
+ ShowPlatformErrorDialog($"A critical error occurred. The application needs to be closed.\n see logs at {logPath} for more details");
+ }
+
+ private void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
+ {
+ var logPath = Path.Combine(
+ Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
+ "Emerald");
+ e.SetObserved();
+ LogUnhandledException(e.Exception, "Task UnobservedException");
+ ShowPlatformErrorDialog($"A unobserved error occurred. The application needs to be closed.\n see logs at {logPath} for more details");
+ }
+
+ private void LogUnhandledException(Exception exception, string source)
+ {
+ try
+ {
+ this.Log().LogCritical(exception,
+ "Unhandled exception ({Source}). Platform: {Platform}",
+ source,
+ DirectResoucres.Platform
+ );
+
+ // Save to crash file (platform-specific path)
+ var crashPath = Path.Combine(
+#if WINDOWS
+ Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
+#else
+ Environment.GetFolderPath(Environment.SpecialFolder.Personal),
+#endif
+ "Emerald",
+ "crashes",
+ $"crash_{DateTime.Now:yyyyMMdd_HHmmss}.txt"
+ );
+
+ Directory.CreateDirectory(Path.GetDirectoryName(crashPath));
+ File.WriteAllText(crashPath, $"""
+ Exception Details:
+ Time: {DateTime.Now}
+ Platform: {DirectResoucres.Platform}
+ Type: {exception.GetType().FullName}
+ Message: {exception.Message}
+ Stack Trace: {exception.StackTrace}
+ """);
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"Failed to log unhandled exception: {ex.Message}");
+ }
+ }
+
+ private async void ShowPlatformErrorDialog(string message)
+ {
+ try
+ {
+ await MessageBox.Show("AppCrash".Localize(), message, Helpers.Enums.MessageBoxButtons.Ok);
+ Application.Current.Exit();
+
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"Error: {message}");
+ }
+ Process.GetCurrentProcess().Kill();
+ }
+ #endregion
}
diff --git a/Emerald/DirectResources.cs b/Emerald/DirectResources.cs
index f72ac03c..240d3162 100644
--- a/Emerald/DirectResources.cs
+++ b/Emerald/DirectResources.cs
@@ -18,6 +18,21 @@ public static int MinRAM
public static string SettingsAPIVersion
=> "1.3";
+ public static string Platform
+ {
+ get
+ {
+#if WINDOWS
+ return "Windows";
+#elif MACCATALYST
+ return "OSX";
+#elif DESKTOP
+ return "Skia";
+#else
+ return "Unknown";
+#endif
+ }
+ }
public static string BuildType
{
get
diff --git a/Emerald/Emerald.csproj b/Emerald/Emerald.csproj
index 9372b37a..59731572 100644
--- a/Emerald/Emerald.csproj
+++ b/Emerald/Emerald.csproj
@@ -54,6 +54,7 @@
+
@@ -98,4 +99,12 @@
+
+
+
+
+
+
+
+
diff --git a/Emerald/Helpers/Enums/MessageBox.cs b/Emerald/Helpers/Enums/MessageBox.cs
new file mode 100644
index 00000000..5a5b58a6
--- /dev/null
+++ b/Emerald/Helpers/Enums/MessageBox.cs
@@ -0,0 +1,22 @@
+namespace Emerald.Helpers.Enums;
+
+public enum MessageBoxResults
+{
+ Ok,
+ Cancel,
+ Yes,
+ No,
+ CustomResult1,
+ CustomResult2,
+ OpenFailed
+}
+
+public enum MessageBoxButtons
+{
+ Ok,
+ OkCancel,
+ YesNo,
+ YesNoCancel,
+ Custom,
+ CustomWithCancel
+}
diff --git a/Emerald/Helpers/Extensions.cs b/Emerald/Helpers/Extensions.cs
index 736b98e6..fdf846c5 100644
--- a/Emerald/Helpers/Extensions.cs
+++ b/Emerald/Helpers/Extensions.cs
@@ -1,3 +1,4 @@
+using CommonServiceLocator;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.Windows.ApplicationModel.Resources;
@@ -78,7 +79,7 @@ public static ContentDialog ToContentDialog(this UIElement content, string title
Content = content,
Padding = new(12)
} : content,
- RequestedTheme = (ElementTheme)Settings.SettingsSystem.Settings.App.Appearance.Theme
+ RequestedTheme = (ElementTheme)ServiceLocator.Current.GetInstance< Helpers.Settings.SettingsSystem>().Settings.App.Appearance.Theme
};
App.Current.Log().LogInformation("Created ContentDialog with title: {title}", title);
return dialog;
diff --git a/Emerald/Helpers/MessageBox.cs b/Emerald/Helpers/MessageBox.cs
new file mode 100644
index 00000000..7b1010c6
--- /dev/null
+++ b/Emerald/Helpers/MessageBox.cs
@@ -0,0 +1,193 @@
+using CommonServiceLocator;
+using Emerald.Helpers;
+using Emerald.Helpers.Enums;
+using Microsoft.UI;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Media;
+using System;
+using System.Threading.Tasks;
+
+namespace Emerald.Helpers;
+
+///
+/// A as a MessageBox...
+/// Copied From the Emerald.UWP
+///
+public partial class MessageBox : ContentDialog
+{
+ public MessageBoxResults Result { get; set; } = MessageBoxResults.Cancel;
+
+ public MessageBox(string title, string caption, MessageBoxButtons buttons, string cusbtn1 = null, string cusbtn2 = null)
+ {
+ Style = Application.Current.Resources["DefaultContentDialogStyle"] as Style;
+ Title = title;
+ Content = new TextBlock { Text = caption };
+
+ if (buttons == MessageBoxButtons.Ok)
+ {
+ PrimaryButtonText = "";
+ SecondaryButtonText = "OK".Localize();
+ DefaultButton = ContentDialogButton.None;
+ }
+ else if (buttons == MessageBoxButtons.OkCancel)
+ {
+ PrimaryButtonText = "OK".Localize();
+ SecondaryButtonText = "Cancel".Localize();
+ DefaultButton = ContentDialogButton.Primary;
+ }
+ else if (buttons == MessageBoxButtons.YesNoCancel)
+ {
+ PrimaryButtonText = "Yes".Localize();
+ SecondaryButtonText = "No".Localize();
+ CloseButtonText = "Cancel".Localize();
+ DefaultButton = ContentDialogButton.Primary;
+ }
+ else if (buttons == MessageBoxButtons.YesNo)
+ {
+ PrimaryButtonText = "Yes".Localize();
+ SecondaryButtonText = "No".Localize();
+ DefaultButton = ContentDialogButton.Primary;
+ }
+ else if (buttons == MessageBoxButtons.Custom)
+ {
+ if (!string.IsNullOrEmpty(cusbtn1))
+ {
+ PrimaryButtonText = cusbtn1;
+ }
+ if (!string.IsNullOrEmpty(cusbtn2))
+ {
+ SecondaryButtonText = cusbtn2;
+ }
+ if (string.IsNullOrEmpty(cusbtn2) && string.IsNullOrEmpty(cusbtn1))
+ {
+ PrimaryButtonText = "Yes".Localize();
+ SecondaryButtonText = "No".Localize();
+ DefaultButton = ContentDialogButton.Primary;
+ }
+ }
+ else if (buttons == MessageBoxButtons.CustomWithCancel)
+ {
+ if (!string.IsNullOrEmpty(cusbtn1))
+ {
+ PrimaryButtonText = cusbtn1;
+ }
+ if (!string.IsNullOrEmpty(cusbtn2))
+ {
+ SecondaryButtonText = cusbtn2;
+ }
+ if (string.IsNullOrEmpty(cusbtn2) && string.IsNullOrEmpty(cusbtn1))
+ {
+ DefaultButton = ContentDialogButton.Primary;
+ PrimaryButtonText = "Yes".Localize();
+ SecondaryButtonText = "No".Localize();
+ }
+
+ CloseButtonText = "Cancel".Localize();
+ }
+
+ PrimaryButtonClick += ContentDialog_PrimaryButtonClick;
+ SecondaryButtonClick += ContentDialog_SecondaryButtonClick;
+ }
+
+ private void ContentDialog_PrimaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args)
+ {
+ if (sender.PrimaryButtonText == "OK".Localize())
+ {
+ Result = MessageBoxResults.Ok;
+ }
+ else if (sender.PrimaryButtonText == "Yes".Localize())
+ {
+ Result = MessageBoxResults.Yes;
+ }
+ else
+ {
+ Result = MessageBoxResults.CustomResult1;
+ }
+ }
+
+ private void ContentDialog_SecondaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args)
+ {
+ if (sender.SecondaryButtonText == "OK".Localize())
+ {
+ Result = MessageBoxResults.Ok;
+ }
+ else if (sender.SecondaryButtonText == "Cancel".Localize())
+ {
+ Result = MessageBoxResults.Cancel;
+ }
+ else if (sender.SecondaryButtonText == "No".Localize())
+ {
+ Result = MessageBoxResults.No;
+ }
+ else
+ {
+ Result = MessageBoxResults.CustomResult2;
+ }
+ }
+
+ public static async Task Show(string title, string caption, MessageBoxButtons buttons, string customResult1 = null, string customResult2 = null, bool waitUntilOpens = true)
+ {
+ var theme = ServiceLocator.IsLocationProviderSet ?
+ (ElementTheme)ServiceLocator.Current.GetInstance().Settings.App.Appearance.Theme :
+ ElementTheme.Default;
+ var d = new MessageBox(title, caption, buttons, customResult1, customResult2)
+ {
+ XamlRoot = App.Current.MainWindow.Content.XamlRoot,
+ RequestedTheme = theme
+ };
+
+ if (waitUntilOpens)
+ {
+ bool notOpen = true;
+ while (notOpen)
+ {
+ try
+ {
+ await d.ShowAsync();
+ notOpen = false;
+ }
+ catch (NullReferenceException) // XamlRoot can be null
+ {
+ notOpen = false;
+ return MessageBoxResults.OpenFailed;
+ }
+ }
+ return d.Result;
+ }
+
+ try
+ {
+ await d.ShowAsync();
+ }
+ catch
+ {
+ return MessageBoxResults.OpenFailed;
+ }
+
+ return d.Result;
+ }
+
+ public static async Task Show(string text)
+ {
+ var theme = ServiceLocator.IsLocationProviderSet ?
+ (ElementTheme)ServiceLocator.Current.GetInstance().Settings.App.Appearance.Theme :
+ ElementTheme.Default;
+ var d = new MessageBox("Information".Localize(), text, MessageBoxButtons.Ok)
+ {
+ XamlRoot = App.Current.MainWindow.Content.XamlRoot,
+ RequestedTheme = theme
+ };
+
+ try
+ {
+ await d.ShowAsync();
+ }
+ catch
+ {
+ return MessageBoxResults.OpenFailed;
+ }
+
+ return d.Result;
+ }
+}
diff --git a/Emerald/Helpers/Settings/JSON.cs b/Emerald/Helpers/Settings/JSON.cs
index c1859a55..7370ba61 100644
--- a/Emerald/Helpers/Settings/JSON.cs
+++ b/Emerald/Helpers/Settings/JSON.cs
@@ -13,7 +13,7 @@ namespace Emerald.Helpers.Settings.JSON;
public class JSON : Models.Model
{
public string Serialize()
- => JsonSerializer.Serialize(this, new JsonSerializerOptions { WriteIndented = true });
+ => JsonSerializer.Serialize(this);
}
public class SettingsBackup : JSON
@@ -58,7 +58,7 @@ public class Settings : JSON
}
};
- // public string APIVersion { get; set; } = DirectResoucres.SettingsAPIVersion;
+ public string APIVersion { get; set; } = DirectResoucres.SettingsAPIVersion;
public DateTime LastSaved { get; set; } = DateTime.Now;
public Minecraft Minecraft { get; set; } = new();
diff --git a/Emerald/Helpers/Settings/SettingsSystem.cs b/Emerald/Helpers/Settings/SettingsSystem.cs
index 5a25b55a..4d4ac25a 100644
--- a/Emerald/Helpers/Settings/SettingsSystem.cs
+++ b/Emerald/Helpers/Settings/SettingsSystem.cs
@@ -1,4 +1,5 @@
using Emerald.Helpers.Settings.JSON;
+using Microsoft.Extensions.Logging;
using System.Text.Json;
using System;
using System.Collections.Generic;
@@ -7,105 +8,142 @@
using Windows.Storage;
namespace Emerald.Helpers.Settings;
-
-public static class SettingsSystem
+public class SettingsSystem
{
- public static JSON.Settings Settings { get; private set; } = JSON.Settings.CreateNew();
- public static Account[] Accounts { get; set; }
-
- public static event EventHandler? APINoMatch;
-// public static T GetSerializedFromSettings(string key, T def)
-// {
-// string json;
-// try
-// {
-// json = ApplicationData.Current.RoamingSettings.Values[key] as string;
-// return JsonSerializer.Deserialize(json);
-// }
-// catch
-// {
-// json = JsonSerializer.Serialize(def);
-// ApplicationData.Current.RoamingSettings.Values[key] = json;
-// return def;
-// }
-// }
-// public static void LoadData()
-// {
-// Settings = GetSerializedFromSettings("Settings", JSON.Settings.CreateNew());
-// Accounts = GetSerializedFromSettings("Accounts", Array.Empty());
-
-// if (Settings.APIVersion != DirectResoucres.SettingsAPIVersion)
-// {
-// APINoMatch?.Invoke(null, ApplicationData.Current.RoamingSettings.Values["Settings"] as string);
-// ApplicationData.Current.RoamingSettings.Values["Settings"] = JSON.Settings.CreateNew().Serialize();
-// Settings = JsonSerializer.Deserialize(ApplicationData.Current.RoamingSettings.Values["Settings"] as string);
-// }
-// }
-
-// public static async Task CreateBackup(string system)
-// {
-// string json = await FileIO.ReadTextAsync(await ApplicationData.Current.LocalFolder.CreateFileAsync("backups.json", CreationCollisionOption.OpenIfExists));
-// var l = json.IsNullEmptyOrWhiteSpace() ? new Backups() : JsonSerializer.Deserialize(json);
-
-// var bl = l.AllBackups == null ? new List() : l.AllBackups.ToList();
-// bl.Add(new SettingsBackup() { Time = DateTime.Now, Backup = system });
-// l.AllBackups = bl.ToArray();
-// json = l.Serialize();
-
-// await FileIO.WriteTextAsync(await ApplicationData.Current.LocalFolder.CreateFileAsync("backups.json", CreationCollisionOption.OpenIfExists), json);
-// }
-
-// public static async Task DeleteBackup(int Index)
-// {
-// string json = await FileIO.ReadTextAsync(await ApplicationData.Current.LocalFolder.CreateFileAsync("backups.json", CreationCollisionOption.OpenIfExists));
-// var l = json.IsNullEmptyOrWhiteSpace() ? new Backups() : JsonSerializer.Deserialize(json);
-
-// var bl = l.AllBackups == null ? new List() : l.AllBackups.ToList();
-// bl.RemoveAt(Index);
-// l.AllBackups = bl.ToArray();
-// json = l.Serialize();
-
-// await FileIO.WriteTextAsync(await ApplicationData.Current.LocalFolder.CreateFileAsync("backups.json", CreationCollisionOption.OpenIfExists), json);
-// }
-
-// public static async Task DeleteBackup(DateTime time)
-// {
-// string json = await FileIO.ReadTextAsync(await ApplicationData.Current.LocalFolder.CreateFileAsync("backups.json", CreationCollisionOption.OpenIfExists));
-// var l = json.IsNullEmptyOrWhiteSpace() ? new Backups() : JsonSerializer.Deserialize(json);
-
-// var bl = l.AllBackups == null ? new List() : l.AllBackups.ToList();
-// bl.Remove(x => x.Time == time);
-// l.AllBackups = bl.ToArray();
-// json = l.Serialize();
-
-// await FileIO.WriteTextAsync(await ApplicationData.Current.LocalFolder.CreateFileAsync("backups.json", CreationCollisionOption.OpenIfExists), json);
-// }
-// public static async Task RenameBackup(DateTime time, string name)
-// {
-// string json = await FileIO.ReadTextAsync(await ApplicationData.Current.LocalFolder.CreateFileAsync("backups.json", CreationCollisionOption.OpenIfExists));
-// var l = json.IsNullEmptyOrWhiteSpace() ? new Backups() : JsonSerializer.Deserialize(json);
-
-// var bl = l.AllBackups == null ? new List() : l.AllBackups.ToList();
-// bl.FirstOrDefault(x => x.Time == time).Name = name;
-// l.AllBackups = bl.ToArray();
-// json = l.Serialize();
-
-// await FileIO.WriteTextAsync(await ApplicationData.Current.LocalFolder.CreateFileAsync("backups.json", CreationCollisionOption.OpenIfExists), json);
-// }
-
-// public static async Task> GetBackups()
-// {
-// string json = await FileIO.ReadTextAsync(await ApplicationData.Current.LocalFolder.CreateFileAsync("backups.json", CreationCollisionOption.OpenIfExists));
-// var l = json.IsNullEmptyOrWhiteSpace() ? new Backups() : JsonSerializer.Deserialize(json);
-
-// return l.AllBackups == null ? new List() : l.AllBackups.ToList();
-// }
-
-// public static void SaveData()
-// {
-// Settings.LastSaved = DateTime.Now;
-// ApplicationData.Current.RoamingSettings.Values["Settings"] = Settings.Serialize();
-// ApplicationData.Current.RoamingSettings.Values["Accounts"] = JsonSerializer.Serialize(Accounts);
-// }
-//}
+ private readonly ILogger _logger;
+
+ public JSON.Settings Settings { get; private set; }
+ public Account[] Accounts { get; set; }
+
+ public event EventHandler? APINoMatch;
+
+ public SettingsSystem(ILogger logger)
+ {
+ _logger = logger;
+ }
+
+ public T GetSerializedFromSettings(string key, T def)
+ {
+ try
+ {
+ string json = ApplicationData.Current.LocalSettings.Values[key] as string;
+ if (!string.IsNullOrWhiteSpace(json))
+ {
+ return JsonSerializer.Deserialize(json);
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Error deserializing key '{Key}' from settings", key);
+ }
+
+ // Save default value if deserialization fails or key is missing
+ try
+ {
+ string json = JsonSerializer.Serialize(def);
+ ApplicationData.Current.LocalSettings.Values[key] = json;
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Error serializing default value for key '{Key}'", key);
+ }
+
+ return def;
+ }
+
+ public void LoadData()
+ {
+ try
+ {
+ _logger.LogInformation("Loading settings and accounts.");
+ Settings = GetSerializedFromSettings("Settings", JSON.Settings.CreateNew());
+ Accounts = GetSerializedFromSettings("Accounts", Array.Empty());
+
+ if (Settings.APIVersion != DirectResoucres.SettingsAPIVersion)
+ {
+ _logger.LogWarning("API version mismatch. Triggering APINoMatch event.");
+ APINoMatch?.Invoke(this, ApplicationData.Current.LocalSettings.Values["Settings"] as string);
+ ApplicationData.Current.LocalSettings.Values["Settings"] = JSON.Settings.CreateNew().Serialize();
+ Settings = JsonSerializer.Deserialize(ApplicationData.Current.LocalSettings.Values["Settings"] as string);
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Error loading settings data.");
+ }
+ }
+
+ public async Task CreateBackup(string system)
+ {
+ try
+ {
+ string json = await FileIO.ReadTextAsync(await ApplicationData.Current.LocalFolder.CreateFileAsync("backups.json", CreationCollisionOption.OpenIfExists));
+ var backups = string.IsNullOrWhiteSpace(json) ? new Backups() : JsonSerializer.Deserialize(json);
+
+ backups.AllBackups ??= Array.Empty();
+ backups.AllBackups = backups.AllBackups.Append(new SettingsBackup { Time = DateTime.Now, Backup = system }).ToArray();
+
+ json = backups.Serialize();
+ await FileIO.WriteTextAsync(await ApplicationData.Current.LocalFolder.CreateFileAsync("backups.json", CreationCollisionOption.OpenIfExists), json);
+
+ _logger.LogInformation("Backup created successfully.");
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Error creating backup.");
+ }
+ }
+
+ public async Task DeleteBackup(int index)
+ {
+ try
+ {
+ string json = await FileIO.ReadTextAsync(await ApplicationData.Current.LocalFolder.CreateFileAsync("backups.json", CreationCollisionOption.OpenIfExists));
+ var backups = string.IsNullOrWhiteSpace(json) ? new Backups() : JsonSerializer.Deserialize(json);
+
+ backups.AllBackups?.ToList().RemoveAt(index);
+ json = backups.Serialize();
+
+ await FileIO.WriteTextAsync(await ApplicationData.Current.LocalFolder.CreateFileAsync("backups.json", CreationCollisionOption.OpenIfExists), json);
+
+ _logger.LogInformation("Backup at index {Index} deleted successfully.", index);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Error deleting backup at index {Index}.", index);
+ }
+ }
+
+ public async Task> GetBackups()
+ {
+ try
+ {
+ string json = await FileIO.ReadTextAsync(await ApplicationData.Current.LocalFolder.CreateFileAsync("backups.json", CreationCollisionOption.OpenIfExists));
+ var backups = string.IsNullOrWhiteSpace(json) ? new Backups() : JsonSerializer.Deserialize(json);
+
+ _logger.LogInformation("Backups retrieved successfully.");
+ return backups.AllBackups?.ToList() ?? [];
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Error retrieving backups.");
+ return [];
+ }
+ }
+
+ public void SaveData()
+ {
+ try
+ {
+ Settings.LastSaved = DateTime.Now;
+ ApplicationData.Current.LocalSettings.Values["Settings"] = JsonSerializer.Serialize(Settings);
+ ApplicationData.Current.LocalSettings.Values["Accounts"] = JsonSerializer.Serialize(Accounts);
+
+ _logger.LogInformation("Settings and accounts saved successfully.");
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Error saving data.");
+ }
+ }
}
diff --git a/Emerald/MainPage.xaml b/Emerald/MainPage.xaml
index c8a3de96..ad12e865 100644
--- a/Emerald/MainPage.xaml
+++ b/Emerald/MainPage.xaml
@@ -5,7 +5,6 @@
xmlns:utu="using:Uno.Toolkit.UI"
xmlns:models="using:Emerald.Models"
xmlns:uc="using:Emerald.UserControls"
- xmlns:SS="using:Emerald.Helpers.Settings"
xmlns:conv="using:Emerald.Helpers.Converters"
xmlns:helpers="using:Emerald.Helpers">
@@ -90,20 +89,20 @@
VerticalAlignment="Top"
Content="{x:Bind InfoBadge}" />
();
this.InitializeComponent();
this.Loaded += MainPage_Loaded;
NavView.ItemInvoked += MainNavigationView_ItemInvoked;
diff --git a/Emerald/Models/SquareNavigationViewItem.cs b/Emerald/Models/SquareNavigationViewItem.cs
index 3f9f2ac5..bc2ea821 100644
--- a/Emerald/Models/SquareNavigationViewItem.cs
+++ b/Emerald/Models/SquareNavigationViewItem.cs
@@ -1,12 +1,15 @@
using System.ComponentModel;
+using CommonServiceLocator;
using CommunityToolkit.Mvvm.ComponentModel;
namespace Emerald.Models;
public partial class SquareNavigationViewItem : Model
{
+ public Helpers.Settings.SettingsSystem SS { get; private set; }
public SquareNavigationViewItem()
{
+ SS = ServiceLocator.Current.GetInstance();
PropertyChanged += (_, e) =>
{
if (e.PropertyName == nameof(IsSelected) || e.PropertyName == nameof(ShowFontIcons))
diff --git a/Emerald/Package.appxmanifest b/Emerald/Package.appxmanifest
index 29558f1d..e9c7863f 100644
--- a/Emerald/Package.appxmanifest
+++ b/Emerald/Package.appxmanifest
@@ -7,13 +7,13 @@
IgnorableNamespaces="uap rescap">
Emerald
- Emerald
+ Riverside Valley
@@ -33,6 +33,7 @@
DisplayName="Emerald"
Description="Emerald">
+
diff --git a/Emerald/Helpers/Services/ServiceProviderLocator.cs b/Emerald/Services/ServiceProviderLocator.cs
similarity index 97%
rename from Emerald/Helpers/Services/ServiceProviderLocator.cs
rename to Emerald/Services/ServiceProviderLocator.cs
index c0207531..d722e87c 100644
--- a/Emerald/Helpers/Services/ServiceProviderLocator.cs
+++ b/Emerald/Services/ServiceProviderLocator.cs
@@ -5,7 +5,7 @@
using System.Threading.Tasks;
using CommonServiceLocator;
-namespace Emerald.Helpers.Services;
+namespace Emerald.Services;
//Bruh I can't get uno services to work. help me.
diff --git a/Emerald/Strings/en/Resources.resw b/Emerald/Strings/en/Resources.resw
index abd56c45..c3f94326 100644
--- a/Emerald/Strings/en/Resources.resw
+++ b/Emerald/Strings/en/Resources.resw
@@ -760,4 +760,7 @@
Tint opacity
+
+ Emerald Got Crashed!
+
\ No newline at end of file
diff --git a/Emerald/UserControls/ArgumentsListView.xaml.cs b/Emerald/UserControls/ArgumentsListView.xaml.cs
index 6ac337f1..a0c6fb8c 100644
--- a/Emerald/UserControls/ArgumentsListView.xaml.cs
+++ b/Emerald/UserControls/ArgumentsListView.xaml.cs
@@ -13,8 +13,8 @@
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Navigation;
using System.Collections.ObjectModel;
-using SS = Emerald.Helpers.Settings.SettingsSystem;
using Emerald.Models;
+using CommonServiceLocator;
namespace Emerald.UserControls;
@@ -23,8 +23,10 @@ namespace Emerald.UserControls;
public sealed partial class ArgumentsListView : UserControl
{
private int count = 0;
+ private readonly Helpers.Settings.SettingsSystem SS;
public ArgumentsListView()
{
+ SS = ServiceLocator.Current.GetInstance();
InitializeComponent();
view.ItemsSource = Source;
UpdateSource();
diff --git a/Emerald/Views/Settings/AppearancePage.xaml b/Emerald/Views/Settings/AppearancePage.xaml
index e366b7d7..ccb5f53b 100644
--- a/Emerald/Views/Settings/AppearancePage.xaml
+++ b/Emerald/Views/Settings/AppearancePage.xaml
@@ -1,7 +1,7 @@
+ mc:Ignorable="d" xmlns:Main="using:Emerald" xmlns:helpers="using:Emerald.Helpers"
+ DataContext="{x:Bind SS.Settings}" xmlns:cn="using:CommunityToolkit.WinUI.Controls" xmlns:uc="using:Emerald.UserControls" xmlns:windowsui="using:Windows.UI">
();
if (SS.Settings.App.Appearance.MicaTintColor == (int)Helpers.Settings.Enums.MicaTintColor.CustomColor)
{
diff --git a/Emerald/Views/Settings/GeneralPage.xaml b/Emerald/Views/Settings/GeneralPage.xaml
index c998ca54..a5ea6f81 100644
--- a/Emerald/Views/Settings/GeneralPage.xaml
+++ b/Emerald/Views/Settings/GeneralPage.xaml
@@ -1,7 +1,7 @@
+ mc:Ignorable="d" xmlns:Main="using:Emerald" xmlns:helpers="using:Emerald.Helpers"
+ DataContext="{x:Bind SS.Settings}" xmlns:cn="using:CommunityToolkit.WinUI.Controls" xmlns:uc="using:Emerald.UserControls">
diff --git a/Emerald/Views/Settings/GeneralPage.xaml.cs b/Emerald/Views/Settings/GeneralPage.xaml.cs
index a8569390..985067c6 100644
--- a/Emerald/Views/Settings/GeneralPage.xaml.cs
+++ b/Emerald/Views/Settings/GeneralPage.xaml.cs
@@ -4,6 +4,7 @@
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using CmlLib.Core;
+using CommonServiceLocator;
using CommunityToolkit.WinUI.Controls;
using Emerald.Helpers;
using Microsoft.UI.Xaml;
@@ -26,8 +27,10 @@ namespace Emerald.Views.Settings;
///
public sealed partial class GeneralPage : Page
{
+ private readonly Helpers.Settings.SettingsSystem SS;
public GeneralPage()
{
+ SS = ServiceLocator.Current.GetInstance();
this.InitializeComponent();
}
private async void btnChangeMPath_Click(object sender, RoutedEventArgs e)
diff --git a/Emerald/Views/Settings/SettingsPage.xaml.cs b/Emerald/Views/Settings/SettingsPage.xaml.cs
index 30caab1a..a430d373 100644
--- a/Emerald/Views/Settings/SettingsPage.xaml.cs
+++ b/Emerald/Views/Settings/SettingsPage.xaml.cs
@@ -26,7 +26,7 @@ private void Navigate(NavigationViewItem itm)
NavigateOnce(typeof(AppearancePage));
break;
case "About":
- NavigateOnce(typeof(SettingsPage));
+ throw new NotImplementedException();
break;
default:
NavigateOnce(typeof(GeneralPage));
diff --git a/Emerald/Views/Store/ModrinthStorePage.xaml b/Emerald/Views/Store/ModrinthStorePage.xaml
new file mode 100644
index 00000000..84654cc6
--- /dev/null
+++ b/Emerald/Views/Store/ModrinthStorePage.xaml
@@ -0,0 +1,130 @@
+
+
+
+
diff --git a/Emerald/Views/Store/ModrinthStorePage.xaml.cs b/Emerald/Views/Store/ModrinthStorePage.xaml.cs
new file mode 100644
index 00000000..64aa4367
--- /dev/null
+++ b/Emerald/Views/Store/ModrinthStorePage.xaml.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices.WindowsRuntime;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Controls.Primitives;
+using Microsoft.UI.Xaml.Data;
+using Microsoft.UI.Xaml.Input;
+using Microsoft.UI.Xaml.Media;
+using Microsoft.UI.Xaml.Navigation;
+using Windows.Foundation;
+using Windows.Foundation.Collections;
+
+// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238
+
+namespace Emerald.Views.Store;
+///
+/// An empty page that can be used on its own or navigated to within a Frame.
+///
+public sealed partial class ModrinthStorePage : Page
+{
+ public ModrinthStorePage()
+ {
+ this.InitializeComponent();
+ }
+}