diff --git a/StabilityMatrix.Avalonia/DesignData/DesignData.cs b/StabilityMatrix.Avalonia/DesignData/DesignData.cs index 15784042..dadc8bc3 100644 --- a/StabilityMatrix.Avalonia/DesignData/DesignData.cs +++ b/StabilityMatrix.Avalonia/DesignData/DesignData.cs @@ -530,6 +530,9 @@ public static class DesignData public static AccountSettingsViewModel AccountSettingsViewModel => Services.GetRequiredService(); + public static NotificationSettingsViewModel NotificationSettingsViewModel => + Services.GetRequiredService(); + public static UpdateSettingsViewModel UpdateSettingsViewModel { get diff --git a/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs b/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs index 132fdfbc..df9f2091 100644 --- a/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs +++ b/StabilityMatrix.Avalonia/Languages/Resources.Designer.cs @@ -1643,6 +1643,24 @@ namespace StabilityMatrix.Avalonia.Languages { } } + /// + /// Looks up a localized string similar to . + /// + public static string Label_NotificationOption_None { + get { + return ResourceManager.GetString("Label_NotificationOption_None", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Notifications. + /// + public static string Label_Notifications { + get { + return ResourceManager.GetString("Label_Notifications", resourceCulture); + } + } + /// /// Looks up a localized string similar to {0} images selected. /// diff --git a/StabilityMatrix.Avalonia/Languages/Resources.resx b/StabilityMatrix.Avalonia/Languages/Resources.resx index f731e8b0..f992fa02 100644 --- a/StabilityMatrix.Avalonia/Languages/Resources.resx +++ b/StabilityMatrix.Avalonia/Languages/Resources.resx @@ -942,4 +942,10 @@ Copy Details + + Notifications + + + + diff --git a/StabilityMatrix.Avalonia/ViewModels/Settings/NotificationSettingsItem.cs b/StabilityMatrix.Avalonia/ViewModels/Settings/NotificationSettingsItem.cs new file mode 100644 index 00000000..7dd03712 --- /dev/null +++ b/StabilityMatrix.Avalonia/ViewModels/Settings/NotificationSettingsItem.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using CommunityToolkit.Mvvm.ComponentModel; +using StabilityMatrix.Core.Attributes; +using StabilityMatrix.Core.Models.Settings; +using StabilityMatrix.Core.Services; + +namespace StabilityMatrix.Avalonia.ViewModels.Settings; + +[Transient] +[ManagedService] +public partial class NotificationSettingsItem(ISettingsManager settingsManager) : ObservableObject +{ + public NotificationKey? Key { get; set; } + + [ObservableProperty] + private NotificationOption? option; + + public static IEnumerable AvailableOptions => Enum.GetValues(); + + partial void OnOptionChanged(NotificationOption? oldValue, NotificationOption? newValue) + { + if (Key is null || oldValue is null || newValue is null) + return; + + settingsManager.Transaction(settings => + { + settings.NotificationOptions[Key] = newValue.Value; + }); + } +} diff --git a/StabilityMatrix.Avalonia/ViewModels/Settings/NotificationSettingsViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Settings/NotificationSettingsViewModel.cs new file mode 100644 index 00000000..1390e95f --- /dev/null +++ b/StabilityMatrix.Avalonia/ViewModels/Settings/NotificationSettingsViewModel.cs @@ -0,0 +1,51 @@ +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using CommunityToolkit.Mvvm.ComponentModel; +using FluentAvalonia.UI.Controls; +using StabilityMatrix.Avalonia.ViewModels.Base; +using StabilityMatrix.Avalonia.Views.Settings; +using StabilityMatrix.Core.Attributes; +using StabilityMatrix.Core.Models.Settings; +using StabilityMatrix.Core.Services; + +namespace StabilityMatrix.Avalonia.ViewModels.Settings; + +[View(typeof(NotificationSettingsPage))] +[Singleton] +[ManagedService] +public partial class NotificationSettingsViewModel(ISettingsManager settingsManager) : PageViewModelBase +{ + public override string Title => "Notifications"; + public override IconSource IconSource => new SymbolIconSource { Symbol = Symbol.Alert }; + + [ObservableProperty] + private IReadOnlyList items = []; + + public override void OnLoaded() + { + base.OnLoaded(); + + Items = GetItems().OrderBy(item => item.Key).ToImmutableArray(); + } + + private IEnumerable GetItems() + { + var settingsOptions = settingsManager.Settings.NotificationOptions; + + foreach (var notificationKey in NotificationKey.All.Values) + { + // If in settings, include settings value, otherwise default + if (!settingsOptions.TryGetValue(notificationKey, out var option)) + { + option = notificationKey.DefaultOption; + } + + yield return new NotificationSettingsItem(settingsManager) + { + Key = notificationKey, + Option = option + }; + } + } +} diff --git a/StabilityMatrix.Avalonia/ViewModels/SettingsViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/SettingsViewModel.cs index f1245814..e79ef3c3 100644 --- a/StabilityMatrix.Avalonia/ViewModels/SettingsViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/SettingsViewModel.cs @@ -36,7 +36,8 @@ public partial class SettingsViewModel : PageViewModelBase vmFactory.Get(), vmFactory.Get(), vmFactory.Get(), - vmFactory.Get() + vmFactory.Get(), + vmFactory.Get() }; CurrentPagePath.AddRange(SubPages); diff --git a/StabilityMatrix.Avalonia/Views/Settings/MainSettingsPage.axaml b/StabilityMatrix.Avalonia/Views/Settings/MainSettingsPage.axaml index ad190b15..369c3f9a 100644 --- a/StabilityMatrix.Avalonia/Views/Settings/MainSettingsPage.axaml +++ b/StabilityMatrix.Avalonia/Views/Settings/MainSettingsPage.axaml @@ -117,7 +117,7 @@ - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/StabilityMatrix.Avalonia/Views/Settings/NotificationSettingsPage.axaml.cs b/StabilityMatrix.Avalonia/Views/Settings/NotificationSettingsPage.axaml.cs new file mode 100644 index 00000000..dc2cc15d --- /dev/null +++ b/StabilityMatrix.Avalonia/Views/Settings/NotificationSettingsPage.axaml.cs @@ -0,0 +1,13 @@ +using StabilityMatrix.Avalonia.Controls; +using StabilityMatrix.Core.Attributes; + +namespace StabilityMatrix.Avalonia.Views.Settings; + +[Singleton] +public partial class NotificationSettingsPage : UserControlBase +{ + public NotificationSettingsPage() + { + InitializeComponent(); + } +} diff --git a/StabilityMatrix.Core/Models/Settings/NotificationKey.cs b/StabilityMatrix.Core/Models/Settings/NotificationKey.cs new file mode 100644 index 00000000..a8a93cf8 --- /dev/null +++ b/StabilityMatrix.Core/Models/Settings/NotificationKey.cs @@ -0,0 +1,36 @@ +using System.Diagnostics.CodeAnalysis; +using System.Text.Json.Serialization; +using StabilityMatrix.Core.Converters.Json; + +namespace StabilityMatrix.Core.Models.Settings; + +/// +/// Notification Names +/// +[SuppressMessage("ReSharper", "InconsistentNaming")] +[JsonConverter(typeof(StringJsonConverter))] +public record NotificationKey(string Value) : StringValue(Value) +{ + public NotificationOption DefaultOption { get; init; } + + public string? DisplayName { get; init; } + + public static NotificationKey Inference_PromptCompleted => + new("Inference_PromptCompleted") + { + DefaultOption = NotificationOption.NativePush, + DisplayName = "Inference Prompt Completed" + }; + + public static NotificationKey Download_Completed => + new("Download_Completed") + { + DefaultOption = NotificationOption.NativePush, + DisplayName = "Download Completed" + }; + + public static Dictionary All { get; } = GetValues(); + + /// + public override string ToString() => base.ToString(); +} diff --git a/StabilityMatrix.Core/Models/Settings/NotificationOption.cs b/StabilityMatrix.Core/Models/Settings/NotificationOption.cs new file mode 100644 index 00000000..261f3d10 --- /dev/null +++ b/StabilityMatrix.Core/Models/Settings/NotificationOption.cs @@ -0,0 +1,15 @@ +using System.ComponentModel.DataAnnotations; + +namespace StabilityMatrix.Core.Models.Settings; + +public enum NotificationOption +{ + [Display(Name = "None", Description = "No notification")] + None, + + [Display(Name = "In-App", Description = "Show a toast in the app")] + AppToast, + + [Display(Name = "Desktop", Description = "Native desktop push notification")] + NativePush +} diff --git a/StabilityMatrix.Core/Models/Settings/Settings.cs b/StabilityMatrix.Core/Models/Settings/Settings.cs index 9626acef..9dc0a5db 100644 --- a/StabilityMatrix.Core/Models/Settings/Settings.cs +++ b/StabilityMatrix.Core/Models/Settings/Settings.cs @@ -109,6 +109,8 @@ public class Settings public HashSet SeenTeachingTips { get; set; } = new(); + public Dictionary NotificationOptions { get; set; } = new(); + public List SelectedBaseModels { get; set; } = Enum.GetValues() .Where(x => x != CivitBaseModelType.All)