settings_re4

This commit is contained in:
lincube
2026-03-13 22:20:12 +08:00
parent 3b3f060f33
commit 5fdaa2539b
89 changed files with 5778 additions and 192 deletions

View File

@@ -0,0 +1,80 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:LanMountainDesktop.ViewModels"
xmlns:controls="using:LanMountainDesktop.Controls"
xmlns:ui="using:FluentAvalonia.UI.Controls"
x:Class="LanMountainDesktop.Views.SettingsPages.AboutSettingsPage"
x:DataType="vm:AboutSettingsPageViewModel">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel Classes="settings-page-container">
<TextBlock Classes="settings-section-title"
Text="{Binding PageTitle}" />
<TextBlock Classes="settings-section-description"
Text="{Binding PageDescription}" />
<controls:SettingsSectionCard IconKey="Info"
Title="{Binding AppInfoHeader}">
<controls:SettingsSectionCard.CardContent>
<StackPanel Spacing="14">
<StackPanel Classes="settings-item">
<TextBlock Classes="settings-item-label"
Text="{Binding VersionLabel}" />
<TextBlock Opacity="0.82"
Text="{Binding VersionText}" />
</StackPanel>
<StackPanel Classes="settings-item">
<TextBlock Classes="settings-item-label"
Text="{Binding RenderBackendLabel}" />
<TextBlock Opacity="0.82"
Text="{Binding RenderBackendText}" />
</StackPanel>
</StackPanel>
</controls:SettingsSectionCard.CardContent>
</controls:SettingsSectionCard>
<ui:SettingsExpander Classes="settings-expander-card"
Header="{Binding UpdateHeader}"
IsExpanded="True">
<StackPanel Spacing="12">
<controls:SettingsOptionCard IconKey="ArrowSync"
Title="{Binding AutoCheckUpdatesLabel}">
<controls:SettingsOptionCard.ActionContent>
<ToggleSwitch IsChecked="{Binding AutoCheckUpdates}" />
</controls:SettingsOptionCard.ActionContent>
</controls:SettingsOptionCard>
<controls:SettingsOptionCard IconKey="ArrowSync"
Title="{Binding IncludePrereleaseUpdatesLabel}">
<controls:SettingsOptionCard.ActionContent>
<ToggleSwitch IsChecked="{Binding IncludePrereleaseUpdates}" />
</controls:SettingsOptionCard.ActionContent>
</controls:SettingsOptionCard>
<controls:SettingsOptionCard IconKey="ArrowSync"
Title="{Binding UpdateChannelLabel}">
<controls:SettingsOptionCard.DetailsContent>
<ComboBox ItemsSource="{Binding UpdateChannels}"
SelectedItem="{Binding SelectedUpdateChannel}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="vm:SelectionOption">
<TextBlock Text="{Binding Label}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</controls:SettingsOptionCard.DetailsContent>
</controls:SettingsOptionCard>
<StackPanel Orientation="Horizontal"
Spacing="12">
<Button Command="{Binding CheckForUpdatesCommand}"
Content="{Binding CheckForUpdatesButtonText}" />
<TextBlock VerticalAlignment="Center"
Opacity="0.76"
Text="{Binding UpdateStatus}" />
</StackPanel>
</StackPanel>
</ui:SettingsExpander>
</StackPanel>
</ScrollViewer>
</UserControl>

View File

@@ -0,0 +1,30 @@
using LanMountainDesktop.PluginSdk;
using LanMountainDesktop.Services.Settings;
using LanMountainDesktop.ViewModels;
namespace LanMountainDesktop.Views.SettingsPages;
[SettingsPageInfo(
"about",
"About",
SettingsPageCategory.About,
IconKey = "Info",
SortOrder = 40,
TitleLocalizationKey = "settings.about.title",
DescriptionLocalizationKey = "settings.about.description")]
public partial class AboutSettingsPage : SettingsPageBase
{
public AboutSettingsPage()
: this(new AboutSettingsPageViewModel(HostSettingsFacadeProvider.GetOrCreate()))
{
}
public AboutSettingsPage(AboutSettingsPageViewModel viewModel)
{
ViewModel = viewModel;
DataContext = ViewModel;
InitializeComponent();
}
public AboutSettingsPageViewModel ViewModel { get; }
}

View File

@@ -0,0 +1,97 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:LanMountainDesktop.ViewModels"
xmlns:controls="using:LanMountainDesktop.Controls"
x:Class="LanMountainDesktop.Views.SettingsPages.AppearanceSettingsPage"
x:DataType="vm:AppearanceSettingsPageViewModel">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel Classes="settings-page-container">
<TextBlock Classes="settings-section-title"
Text="{Binding PageTitle}" />
<TextBlock Classes="settings-section-description"
Text="{Binding PageDescription}" />
<controls:SettingsOptionCard IconKey="DesignIdeas"
Title="{Binding NightModeLabel}">
<controls:SettingsOptionCard.ActionContent>
<ToggleSwitch IsChecked="{Binding IsNightMode}" />
</controls:SettingsOptionCard.ActionContent>
</controls:SettingsOptionCard>
<controls:SettingsOptionCard IconKey="DesignIdeas"
Title="{Binding UseSystemChromeLabel}">
<controls:SettingsOptionCard.ActionContent>
<ToggleSwitch IsChecked="{Binding UseSystemChrome}" />
</controls:SettingsOptionCard.ActionContent>
</controls:SettingsOptionCard>
<controls:SettingsOptionCard IconKey="DesignIdeas"
Title="{Binding ThemeColorLabel}">
<controls:SettingsOptionCard.DetailsContent>
<TextBox Watermark="#AABBCC"
Text="{Binding ThemeColor}" />
</controls:SettingsOptionCard.DetailsContent>
</controls:SettingsOptionCard>
<controls:SettingsSectionCard IconKey="DesignIdeas"
Title="{Binding WallpaperHeader}">
<controls:SettingsSectionCard.CardContent>
<StackPanel Spacing="14">
<StackPanel Classes="settings-item">
<TextBlock Classes="settings-item-label"
Text="{Binding WallpaperPathLabel}" />
<TextBox IsReadOnly="True"
Text="{Binding WallpaperPath}" />
</StackPanel>
<StackPanel Classes="settings-item">
<TextBlock Classes="settings-item-label"
Text="{Binding WallpaperPlacementLabel}" />
<ComboBox ItemsSource="{Binding WallpaperPlacements}"
SelectedItem="{Binding SelectedWallpaperPlacement}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="vm:SelectionOption">
<TextBlock Text="{Binding Label}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
<Button HorizontalAlignment="Left"
Click="OnBrowseWallpaperClick"
Content="{Binding ImportWallpaperButtonText}" />
</StackPanel>
</controls:SettingsSectionCard.CardContent>
</controls:SettingsSectionCard>
<controls:SettingsSectionCard IconKey="DesignIdeas"
Title="{Binding ClockHeader}"
Description="{Binding ClockDescription}">
<controls:SettingsSectionCard.CardContent>
<StackPanel Spacing="14">
<controls:SettingsOptionCard IconKey="DesignIdeas"
Title="{Binding ClockHeader}">
<controls:SettingsOptionCard.ActionContent>
<ToggleSwitch IsChecked="{Binding ShowClock}" />
</controls:SettingsOptionCard.ActionContent>
</controls:SettingsOptionCard>
<controls:SettingsOptionCard IconKey="DesignIdeas"
Title="{Binding ClockFormatLabel}">
<controls:SettingsOptionCard.DetailsContent>
<ComboBox ItemsSource="{Binding ClockFormats}"
SelectedItem="{Binding SelectedClockFormat}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="vm:SelectionOption">
<TextBlock Text="{Binding Label}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</controls:SettingsOptionCard.DetailsContent>
</controls:SettingsOptionCard>
</StackPanel>
</controls:SettingsSectionCard.CardContent>
</controls:SettingsSectionCard>
</StackPanel>
</ScrollViewer>
</UserControl>

View File

@@ -0,0 +1,54 @@
using Avalonia.Controls;
using Avalonia.Platform.Storage;
using LanMountainDesktop.PluginSdk;
using LanMountainDesktop.Services.Settings;
using LanMountainDesktop.ViewModels;
using System.Linq;
namespace LanMountainDesktop.Views.SettingsPages;
[SettingsPageInfo(
"appearance",
"Appearance",
SettingsPageCategory.Appearance,
IconKey = "DesignIdeas",
SortOrder = 10,
TitleLocalizationKey = "settings.appearance.title",
DescriptionLocalizationKey = "settings.appearance.description")]
public partial class AppearanceSettingsPage : SettingsPageBase
{
public AppearanceSettingsPage()
: this(new AppearanceSettingsPageViewModel(HostSettingsFacadeProvider.GetOrCreate()))
{
}
public AppearanceSettingsPage(AppearanceSettingsPageViewModel viewModel)
{
ViewModel = viewModel;
DataContext = ViewModel;
InitializeComponent();
}
public AppearanceSettingsPageViewModel ViewModel { get; }
private async void OnBrowseWallpaperClick(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
{
if (TopLevel.GetTopLevel(this)?.StorageProvider is not { } storageProvider)
{
return;
}
var files = await storageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
{
Title = ViewModel.FilePickerTitle,
AllowMultiple = false
});
var file = files.FirstOrDefault();
var localPath = file?.TryGetLocalPath();
if (!string.IsNullOrWhiteSpace(localPath))
{
await ViewModel.ImportWallpaperAsync(localPath);
}
}
}

View File

@@ -0,0 +1,50 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:LanMountainDesktop.ViewModels"
xmlns:ui="using:FluentAvalonia.UI.Controls"
x:Class="LanMountainDesktop.Views.SettingsPages.ComponentsSettingsPage"
x:DataType="vm:ComponentsSettingsPageViewModel">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel Classes="settings-page-container">
<TextBlock Classes="settings-section-title"
Text="{Binding PageTitle}" />
<TextBlock Classes="settings-section-description"
Text="{Binding PageDescription}" />
<ui:SettingsExpander Classes="settings-expander-card"
Header="{Binding GridHeader}"
IsExpanded="True">
<StackPanel Spacing="14">
<StackPanel Classes="settings-item">
<TextBlock Classes="settings-item-label"
Text="{Binding ShortSideCellsLabel}" />
<NumericUpDown Minimum="6"
Maximum="96"
Value="{Binding ShortSideCells}" />
</StackPanel>
<StackPanel Classes="settings-item">
<TextBlock Classes="settings-item-label"
Text="{Binding EdgeInsetPercentLabel}" />
<NumericUpDown Minimum="0"
Maximum="30"
Value="{Binding EdgeInsetPercent}" />
</StackPanel>
<StackPanel Classes="settings-item">
<TextBlock Classes="settings-item-label"
Text="{Binding SpacingPresetLabel}" />
<ComboBox ItemsSource="{Binding SpacingPresets}"
SelectedItem="{Binding SelectedSpacingPreset}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="vm:SelectionOption">
<TextBlock Text="{Binding Label}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
</StackPanel>
</ui:SettingsExpander>
</StackPanel>
</ScrollViewer>
</UserControl>

View File

@@ -0,0 +1,30 @@
using LanMountainDesktop.PluginSdk;
using LanMountainDesktop.Services.Settings;
using LanMountainDesktop.ViewModels;
namespace LanMountainDesktop.Views.SettingsPages;
[SettingsPageInfo(
"components",
"Components",
SettingsPageCategory.Components,
IconKey = "GridDots",
SortOrder = 20,
TitleLocalizationKey = "settings.components.title",
DescriptionLocalizationKey = "settings.components.description")]
public partial class ComponentsSettingsPage : SettingsPageBase
{
public ComponentsSettingsPage()
: this(new ComponentsSettingsPageViewModel(HostSettingsFacadeProvider.GetOrCreate()))
{
}
public ComponentsSettingsPage(ComponentsSettingsPageViewModel viewModel)
{
ViewModel = viewModel;
DataContext = ViewModel;
InitializeComponent();
}
public ComponentsSettingsPageViewModel ViewModel { get; }
}

View File

@@ -0,0 +1,87 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:LanMountainDesktop.ViewModels"
xmlns:controls="using:LanMountainDesktop.Controls"
xmlns:ui="using:FluentAvalonia.UI.Controls"
x:Class="LanMountainDesktop.Views.SettingsPages.GeneralSettingsPage"
x:DataType="vm:GeneralSettingsPageViewModel">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel Classes="settings-page-container">
<TextBlock Classes="settings-section-title"
Text="{Binding PageTitle}" />
<TextBlock Classes="settings-section-description"
Text="{Binding PageDescription}" />
<controls:SettingsOptionCard IconKey="Settings"
Title="{Binding LanguageHeader}">
<controls:SettingsOptionCard.DetailsContent>
<ComboBox MinWidth="240"
ItemsSource="{Binding Languages}"
SelectedItem="{Binding SelectedLanguage}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="vm:SelectionOption">
<TextBlock Text="{Binding Label}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</controls:SettingsOptionCard.DetailsContent>
</controls:SettingsOptionCard>
<controls:SettingsOptionCard IconKey="Settings"
Title="{Binding TimeZoneHeader}"
Description="{Binding TimeZoneDescription}">
<controls:SettingsOptionCard.DetailsContent>
<ComboBox MinWidth="280"
ItemsSource="{Binding TimeZones}"
SelectedItem="{Binding SelectedTimeZone}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="vm:TimeZoneOption">
<TextBlock Text="{Binding Label}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</controls:SettingsOptionCard.DetailsContent>
</controls:SettingsOptionCard>
<controls:SettingsSectionCard IconKey="Info"
Title="{Binding PreviewHeader}">
<controls:SettingsSectionCard.CardContent>
<Grid ColumnDefinitions="Auto,*"
ColumnSpacing="16"
RowDefinitions="Auto,Auto"
RowSpacing="12">
<TextBlock FontWeight="SemiBold"
Text="{Binding PreviewTimeLabel}" />
<TextBlock Grid.Column="1"
Opacity="0.82"
Text="{Binding PreviewTimeText}" />
<TextBlock Grid.Row="1"
FontWeight="SemiBold"
Text="{Binding PreviewDateLabel}" />
<TextBlock Grid.Row="1"
Grid.Column="1"
Opacity="0.82"
Text="{Binding PreviewDateText}" />
</Grid>
</controls:SettingsSectionCard.CardContent>
</controls:SettingsSectionCard>
<ui:SettingsExpander Classes="settings-expander-card"
Header="{Binding RuntimeHeader}"
Description="{Binding RuntimeDescription}"
IsExpanded="True">
<ui:SettingsExpander.Footer>
<ComboBox MinWidth="240"
ItemsSource="{Binding RenderModes}"
SelectedItem="{Binding SelectedRenderMode}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="vm:SelectionOption">
<TextBlock Text="{Binding Label}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</ui:SettingsExpander.Footer>
</ui:SettingsExpander>
</StackPanel>
</ScrollViewer>
</UserControl>

View File

@@ -0,0 +1,36 @@
using LanMountainDesktop.PluginSdk;
using LanMountainDesktop.Services.Settings;
using LanMountainDesktop.ViewModels;
namespace LanMountainDesktop.Views.SettingsPages;
[SettingsPageInfo(
"general",
"General",
SettingsPageCategory.General,
IconKey = "Settings",
SortOrder = 0,
TitleLocalizationKey = "settings.general.title",
DescriptionLocalizationKey = "settings.general.description")]
public partial class GeneralSettingsPage : SettingsPageBase
{
public GeneralSettingsPage()
: this(new GeneralSettingsPageViewModel(HostSettingsFacadeProvider.GetOrCreate()))
{
}
public GeneralSettingsPage(GeneralSettingsPageViewModel viewModel)
{
ViewModel = viewModel;
ViewModel.RestartRequested += OnRestartRequested;
DataContext = ViewModel;
InitializeComponent();
}
public GeneralSettingsPageViewModel ViewModel { get; }
private void OnRestartRequested()
{
RequestRestart(ViewModel.RenderModeRestartMessage);
}
}

View File

@@ -0,0 +1,18 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:LanMountainDesktop.ViewModels"
x:Class="LanMountainDesktop.Views.SettingsPages.GeneratedPluginSettingsPage"
x:DataType="vm:PluginGeneratedSettingsPageViewModel">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel Classes="settings-page-container">
<TextBlock Classes="settings-section-title"
Text="{Binding Title}" />
<TextBlock x:Name="DescriptionTextBlock"
Classes="settings-section-description"
Text="{Binding Description}" />
<StackPanel x:Name="DynamicOptionsHost"
Spacing="0" />
</StackPanel>
</ScrollViewer>
</UserControl>

View File

@@ -0,0 +1,226 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Avalonia.Controls;
using LanMountainDesktop.Controls;
using LanMountainDesktop.PluginSdk;
using LanMountainDesktop.Services.Settings;
using LanMountainDesktop.ViewModels;
namespace LanMountainDesktop.Views.SettingsPages;
public partial class GeneratedPluginSettingsPage : SettingsPageBase
{
public GeneratedPluginSettingsPage()
: this(
new PluginGeneratedSettingsPageViewModel(
HostSettingsFacadeProvider.GetOrCreate().Settings,
string.Empty,
new PluginSettingsSectionRegistration("_preview", "preview", []),
new PluginLocalizer(AppContext.BaseDirectory, "en-US")))
{
}
public GeneratedPluginSettingsPage(PluginGeneratedSettingsPageViewModel viewModel)
{
ViewModel = viewModel;
DataContext = ViewModel;
InitializeComponent();
if (DescriptionTextBlock is not null)
{
DescriptionTextBlock.IsVisible = !string.IsNullOrWhiteSpace(ViewModel.Description);
}
BuildDynamicOptions();
}
public PluginGeneratedSettingsPageViewModel ViewModel { get; }
private void BuildDynamicOptions()
{
if (DynamicOptionsHost is null)
{
return;
}
DynamicOptionsHost.Children.Clear();
foreach (var option in ViewModel.Section.Options)
{
DynamicOptionsHost.Children.Add(CreateOptionControl(option));
}
}
private Control CreateOptionControl(SettingsOptionDefinition option)
{
var title = ViewModel.Localizer.GetString(option.TitleLocalizationKey, option.TitleLocalizationKey);
var description = string.IsNullOrWhiteSpace(option.DescriptionLocalizationKey)
? null
: ViewModel.Localizer.GetString(option.DescriptionLocalizationKey, option.DescriptionLocalizationKey);
var card = new SettingsOptionCard
{
IconKey = "Settings",
Title = title,
Description = description
};
switch (option.OptionType)
{
case SettingsOptionType.Toggle:
card.ActionContent = CreateToggle(option);
break;
case SettingsOptionType.Number:
card.DetailsContent = CreateNumber(option);
break;
case SettingsOptionType.Select:
card.DetailsContent = CreateSelect(option);
break;
case SettingsOptionType.Path:
card.DetailsContent = CreateText(option, "Path");
break;
case SettingsOptionType.List:
card.DetailsContent = CreateText(option, "Comma-separated values");
break;
default:
card.DetailsContent = CreateText(option, null);
break;
}
return card;
}
private Control CreateToggle(SettingsOptionDefinition option)
{
var toggleSwitch = new ToggleSwitch
{
IsChecked = ViewModel.SettingsService.GetValue<bool?>(
SettingsScope.Plugin,
option.Key,
ViewModel.PluginId,
sectionId: ViewModel.Section.Id) ?? (option.DefaultValue as bool? ?? false)
};
toggleSwitch.IsCheckedChanged += (_, _) =>
{
ViewModel.SettingsService.SetValue(
SettingsScope.Plugin,
option.Key,
toggleSwitch.IsChecked == true,
ViewModel.PluginId,
sectionId: ViewModel.Section.Id,
changedKeys: [option.Key]);
};
return toggleSwitch;
}
private Control CreateNumber(SettingsOptionDefinition option)
{
var currentValue = ViewModel.SettingsService.GetValue<double?>(
SettingsScope.Plugin,
option.Key,
ViewModel.PluginId,
sectionId: ViewModel.Section.Id);
var numeric = new NumericUpDown
{
Minimum = (decimal)(option.Minimum ?? 0d),
Maximum = (decimal)(option.Maximum ?? 9999d),
Value = (decimal)(currentValue ?? Convert.ToDouble(option.DefaultValue ?? 0d))
};
numeric.ValueChanged += (_, _) =>
{
ViewModel.SettingsService.SetValue(
SettingsScope.Plugin,
option.Key,
(double)(numeric.Value ?? 0m),
ViewModel.PluginId,
sectionId: ViewModel.Section.Id,
changedKeys: [option.Key]);
};
return numeric;
}
private Control CreateSelect(SettingsOptionDefinition option)
{
var choices = option.Choices
.Select(choice => new SelectionOption(
choice.Value,
ViewModel.Localizer.GetString(choice.TitleLocalizationKey, choice.TitleLocalizationKey)))
.ToArray();
var comboBox = new ComboBox
{
ItemsSource = choices
};
var currentValue = ViewModel.SettingsService.GetValue<string>(
SettingsScope.Plugin,
option.Key,
ViewModel.PluginId,
sectionId: ViewModel.Section.Id);
comboBox.SelectedItem = choices.FirstOrDefault(choice =>
string.Equals(choice.Value, currentValue ?? option.DefaultValue?.ToString(), StringComparison.OrdinalIgnoreCase));
comboBox.SelectionChanged += (_, _) =>
{
if (comboBox.SelectedItem is not SelectionOption selected)
{
return;
}
ViewModel.SettingsService.SetValue(
SettingsScope.Plugin,
option.Key,
selected.Value,
ViewModel.PluginId,
sectionId: ViewModel.Section.Id,
changedKeys: [option.Key]);
};
return comboBox;
}
private Control CreateText(SettingsOptionDefinition option, string? watermark)
{
var currentValue = option.OptionType == SettingsOptionType.List
? string.Join(
", ",
ViewModel.SettingsService.GetValue<IReadOnlyList<string>>(
SettingsScope.Plugin,
option.Key,
ViewModel.PluginId,
sectionId: ViewModel.Section.Id) ?? (option.DefaultValue as IReadOnlyList<string> ?? []))
: ViewModel.SettingsService.GetValue<string>(
SettingsScope.Plugin,
option.Key,
ViewModel.PluginId,
sectionId: ViewModel.Section.Id) ?? option.DefaultValue?.ToString() ?? string.Empty;
var textBox = new TextBox
{
Watermark = watermark,
Text = currentValue
};
textBox.LostFocus += (_, _) =>
{
object value = option.OptionType == SettingsOptionType.List
? textBox.Text?
.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
.ToArray() ?? []
: textBox.Text ?? string.Empty;
ViewModel.SettingsService.SetValue(
SettingsScope.Plugin,
option.Key,
value,
ViewModel.PluginId,
sectionId: ViewModel.Section.Id,
changedKeys: [option.Key]);
};
return textBox;
}
}

View File

@@ -0,0 +1,87 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:LanMountainDesktop.ViewModels"
x:Class="LanMountainDesktop.Views.SettingsPages.PluginsSettingsPage"
x:Name="Root"
x:DataType="vm:PluginsSettingsPageViewModel">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel Classes="settings-page-container">
<TextBlock Classes="settings-section-title"
Text="{Binding PageTitle}" />
<TextBlock Classes="settings-section-description"
Text="{Binding PageDescription}" />
<StackPanel Orientation="Horizontal"
Spacing="12"
Margin="0,0,0,18">
<Button Command="{Binding RefreshCommand}"
Content="{Binding RefreshButtonText}" />
<TextBlock VerticalAlignment="Center"
Opacity="0.76"
Text="{Binding StatusMessage}" />
</StackPanel>
<TextBlock Classes="settings-subsection-title"
Text="{Binding InstalledHeader}" />
<ItemsControl ItemsSource="{Binding InstalledPlugins}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="vm:InstalledPluginItemViewModel">
<Border Classes="settings-list-item">
<Grid Classes="settings-list-actions"
ColumnDefinitions="*,Auto,Auto">
<StackPanel>
<TextBlock FontWeight="SemiBold"
Text="{Binding Name}" />
<TextBlock Opacity="0.76"
FontSize="12"
Text="{Binding Description}" />
<TextBlock Opacity="0.58"
FontSize="11"
Text="{Binding Version}" />
</StackPanel>
<ToggleSwitch Grid.Column="1"
IsChecked="{Binding IsEnabled}"
Command="{Binding #Root.DataContext.TogglePluginCommand}"
CommandParameter="{Binding}" />
<Button Grid.Column="2"
Command="{Binding #Root.DataContext.DeletePluginCommand}"
CommandParameter="{Binding}"
Content="{Binding #Root.DataContext.DeleteButtonText}" />
</Grid>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<TextBlock Classes="settings-subsection-title"
Text="{Binding MarketplaceHeader}" />
<ItemsControl ItemsSource="{Binding MarketPlugins}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="vm:PluginMarketItemViewModel">
<Border Classes="settings-list-item">
<Grid Classes="settings-list-actions"
ColumnDefinitions="*,Auto">
<StackPanel>
<TextBlock FontWeight="SemiBold"
Text="{Binding Name}" />
<TextBlock Opacity="0.76"
FontSize="12"
Text="{Binding Description}" />
<TextBlock Opacity="0.58"
FontSize="11"
Text="{Binding Version}" />
</StackPanel>
<Button Grid.Column="1"
Command="{Binding #Root.DataContext.InstallPluginCommand}"
CommandParameter="{Binding}"
Content="{Binding #Root.DataContext.InstallButtonText}" />
</Grid>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</ScrollViewer>
</UserControl>

View File

@@ -0,0 +1,41 @@
using LanMountainDesktop.PluginSdk;
using LanMountainDesktop.Services.Settings;
using LanMountainDesktop.ViewModels;
namespace LanMountainDesktop.Views.SettingsPages;
[SettingsPageInfo(
"plugins",
"Plugins",
SettingsPageCategory.Plugins,
IconKey = "PuzzlePiece",
SortOrder = 30,
TitleLocalizationKey = "settings.plugins.title",
DescriptionLocalizationKey = "settings.plugins.description")]
public partial class PluginsSettingsPage : SettingsPageBase
{
public PluginsSettingsPage()
: this(new PluginsSettingsPageViewModel(HostSettingsFacadeProvider.GetOrCreate()))
{
}
public PluginsSettingsPage(PluginsSettingsPageViewModel viewModel)
{
ViewModel = viewModel;
ViewModel.RestartRequested += OnRestartRequested;
DataContext = ViewModel;
InitializeComponent();
}
public PluginsSettingsPageViewModel ViewModel { get; }
public override async void OnNavigatedTo(object? parameter)
{
await ViewModel.InitializeAsync();
}
private void OnRestartRequested()
{
RequestRestart(ViewModel.RestartRequiredMessage);
}
}