Browse Source

Add notifications settings subpage

pull/438/head
Ionite 10 months ago
parent
commit
8a4eaae59f
No known key found for this signature in database
  1. 3
      StabilityMatrix.Avalonia/DesignData/DesignData.cs
  2. 18
      StabilityMatrix.Avalonia/Languages/Resources.Designer.cs
  3. 6
      StabilityMatrix.Avalonia/Languages/Resources.resx
  4. 31
      StabilityMatrix.Avalonia/ViewModels/Settings/NotificationSettingsItem.cs
  5. 51
      StabilityMatrix.Avalonia/ViewModels/Settings/NotificationSettingsViewModel.cs
  6. 3
      StabilityMatrix.Avalonia/ViewModels/SettingsViewModel.cs
  7. 19
      StabilityMatrix.Avalonia/Views/Settings/MainSettingsPage.axaml
  8. 61
      StabilityMatrix.Avalonia/Views/Settings/NotificationSettingsPage.axaml
  9. 13
      StabilityMatrix.Avalonia/Views/Settings/NotificationSettingsPage.axaml.cs
  10. 36
      StabilityMatrix.Core/Models/Settings/NotificationKey.cs
  11. 15
      StabilityMatrix.Core/Models/Settings/NotificationOption.cs
  12. 2
      StabilityMatrix.Core/Models/Settings/Settings.cs

3
StabilityMatrix.Avalonia/DesignData/DesignData.cs

@ -530,6 +530,9 @@ public static class DesignData
public static AccountSettingsViewModel AccountSettingsViewModel => public static AccountSettingsViewModel AccountSettingsViewModel =>
Services.GetRequiredService<AccountSettingsViewModel>(); Services.GetRequiredService<AccountSettingsViewModel>();
public static NotificationSettingsViewModel NotificationSettingsViewModel =>
Services.GetRequiredService<NotificationSettingsViewModel>();
public static UpdateSettingsViewModel UpdateSettingsViewModel public static UpdateSettingsViewModel UpdateSettingsViewModel
{ {
get get

18
StabilityMatrix.Avalonia/Languages/Resources.Designer.cs generated

@ -1643,6 +1643,24 @@ namespace StabilityMatrix.Avalonia.Languages {
} }
} }
/// <summary>
/// Looks up a localized string similar to .
/// </summary>
public static string Label_NotificationOption_None {
get {
return ResourceManager.GetString("Label_NotificationOption_None", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Notifications.
/// </summary>
public static string Label_Notifications {
get {
return ResourceManager.GetString("Label_Notifications", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to {0} images selected. /// Looks up a localized string similar to {0} images selected.
/// </summary> /// </summary>

6
StabilityMatrix.Avalonia/Languages/Resources.resx

@ -942,4 +942,10 @@
<data name="Action_CopyDetails" xml:space="preserve"> <data name="Action_CopyDetails" xml:space="preserve">
<value>Copy Details</value> <value>Copy Details</value>
</data> </data>
<data name="Label_Notifications" xml:space="preserve">
<value>Notifications</value>
</data>
<data name="Label_NotificationOption_None" xml:space="preserve">
<value />
</data>
</root> </root>

31
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<NotificationOption> AvailableOptions => Enum.GetValues<NotificationOption>();
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;
});
}
}

51
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<NotificationSettingsItem> items = [];
public override void OnLoaded()
{
base.OnLoaded();
Items = GetItems().OrderBy(item => item.Key).ToImmutableArray();
}
private IEnumerable<NotificationSettingsItem> 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
};
}
}
}

3
StabilityMatrix.Avalonia/ViewModels/SettingsViewModel.cs

@ -36,7 +36,8 @@ public partial class SettingsViewModel : PageViewModelBase
vmFactory.Get<MainSettingsViewModel>(), vmFactory.Get<MainSettingsViewModel>(),
vmFactory.Get<InferenceSettingsViewModel>(), vmFactory.Get<InferenceSettingsViewModel>(),
vmFactory.Get<AccountSettingsViewModel>(), vmFactory.Get<AccountSettingsViewModel>(),
vmFactory.Get<UpdateSettingsViewModel>() vmFactory.Get<UpdateSettingsViewModel>(),
vmFactory.Get<NotificationSettingsViewModel>()
}; };
CurrentPagePath.AddRange(SubPages); CurrentPagePath.AddRange(SubPages);

19
StabilityMatrix.Avalonia/Views/Settings/MainSettingsPage.axaml

@ -117,7 +117,7 @@
</Grid> </Grid>
<!-- General --> <!-- General -->
<sg:SpacedGrid RowDefinitions="Auto,*,*" RowSpacing="4"> <sg:SpacedGrid RowDefinitions="Auto,*,*,*" RowSpacing="4">
<TextBlock <TextBlock
Margin="0,0,0,4" Margin="0,0,0,4"
FontWeight="Medium" FontWeight="Medium"
@ -138,7 +138,22 @@
Symbol="AppGeneric" /> Symbol="AppGeneric" />
</ui:SettingsExpander.IconSource> </ui:SettingsExpander.IconSource>
</ui:SettingsExpander> </ui:SettingsExpander>
<ui:SettingsExpander Grid.Row="2" <!-- Link to Notifications Sub-Settings -->
<ui:SettingsExpander
Grid.Row="2"
Margin="8,0"
ActionIconSource="ChevronRight"
Command="{Binding NavigateToSubPageCommand}"
CommandParameter="{x:Type vmSettings:NotificationSettingsViewModel}"
Header="{x:Static lang:Resources.Label_Notifications}"
IsClickEnabled="True">
<ui:SettingsExpander.IconSource>
<fluentIcons:SymbolIconSource
FontSize="10"
Symbol="Alert" />
</ui:SettingsExpander.IconSource>
</ui:SettingsExpander>
<ui:SettingsExpander Grid.Row="3"
Header="{x:Static lang:Resources.Label_HolidayMode}"> Header="{x:Static lang:Resources.Label_HolidayMode}">
<ui:SettingsExpander.IconSource> <ui:SettingsExpander.IconSource>
<fluentIcons:SymbolIconSource <fluentIcons:SymbolIconSource

61
StabilityMatrix.Avalonia/Views/Settings/NotificationSettingsPage.axaml

@ -0,0 +1,61 @@
<controls:UserControlBase
x:Class="StabilityMatrix.Avalonia.Views.Settings.NotificationSettingsPage"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:StabilityMatrix.Avalonia.Controls"
xmlns:converters="clr-namespace:StabilityMatrix.Avalonia.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:fluentIcons="clr-namespace:FluentIcons.Avalonia.Fluent;assembly=FluentIcons.Avalonia.Fluent"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:mocks="clr-namespace:StabilityMatrix.Avalonia.DesignData"
xmlns:models="clr-namespace:StabilityMatrix.Core.Models.Settings;assembly=StabilityMatrix.Core"
xmlns:sg="clr-namespace:SpacedGridControl.Avalonia;assembly=SpacedGridControl.Avalonia"
xmlns:ui="using:FluentAvalonia.UI.Controls"
xmlns:vmSettings="clr-namespace:StabilityMatrix.Avalonia.ViewModels.Settings"
d:DataContext="{x:Static mocks:DesignData.NotificationSettingsViewModel}"
d:DesignHeight="450"
d:DesignWidth="800"
x:DataType="vmSettings:NotificationSettingsViewModel"
mc:Ignorable="d">
<controls:UserControlBase.Resources>
<DataTemplate x:Key="ItemTemplate" DataType="vmSettings:NotificationSettingsItem">
<controls:Card Padding="16">
<Grid ColumnDefinitions="*,Auto">
<StackPanel VerticalAlignment="Center">
<TextBlock Text="{Binding Key.DisplayName}" />
</StackPanel>
<controls:BetterComboBox
Grid.Column="1"
ItemsSource="{x:Static vmSettings:NotificationSettingsItem.AvailableOptions}"
SelectedItem="{Binding Option}">
<controls:BetterComboBox.ItemTemplate>
<DataTemplate x:DataType="models:NotificationOption">
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} - {1}">
<Binding Converter="{x:Static converters:EnumAttributeConverters.DisplayName}" />
<Binding Converter="{x:Static converters:EnumAttributeConverters.DisplayDescription}" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
</controls:BetterComboBox.ItemTemplate>
<controls:BetterComboBox.SelectionBoxItemTemplate>
<DataTemplate x:DataType="models:NotificationOption">
<TextBlock Text="{Binding Converter={x:Static converters:EnumAttributeConverters.DisplayName}}" />
</DataTemplate>
</controls:BetterComboBox.SelectionBoxItemTemplate>
</controls:BetterComboBox>
</Grid>
</controls:Card>
</DataTemplate>
</controls:UserControlBase.Resources>
<ScrollViewer Padding="16" VerticalScrollBarVisibility="Auto">
<ItemsControl ItemTemplate="{StaticResource ItemTemplate}" ItemsSource="{Binding Items}" />
</ScrollViewer>
</controls:UserControlBase>

13
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();
}
}

36
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;
/// <summary>
/// Notification Names
/// </summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
[JsonConverter(typeof(StringJsonConverter<NotificationKey>))]
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<string, NotificationKey> All { get; } = GetValues<NotificationKey>();
/// <inheritdoc />
public override string ToString() => base.ToString();
}

15
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
}

2
StabilityMatrix.Core/Models/Settings/Settings.cs

@ -109,6 +109,8 @@ public class Settings
public HashSet<TeachingTip> SeenTeachingTips { get; set; } = new(); public HashSet<TeachingTip> SeenTeachingTips { get; set; } = new();
public Dictionary<NotificationKey, NotificationOption> NotificationOptions { get; set; } = new();
public List<string> SelectedBaseModels { get; set; } = public List<string> SelectedBaseModels { get; set; } =
Enum.GetValues<CivitBaseModelType>() Enum.GetValues<CivitBaseModelType>()
.Where(x => x != CivitBaseModelType.All) .Where(x => x != CivitBaseModelType.All)

Loading…
Cancel
Save