settings_re9

This commit is contained in:
lincube
2026-03-14 23:52:26 +08:00
parent 689be7b585
commit 85b70c4a8a
20 changed files with 1190 additions and 146 deletions

View File

@@ -0,0 +1,142 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:LanMountainDesktop.ViewModels"
xmlns:mdxaml="https://github.com/whistyun/Markdown.Avalonia"
xmlns:helpers="using:LanMountainDesktop.Helpers"
xmlns:fi="using:FluentIcons.Avalonia.Fluent"
x:Class="LanMountainDesktop.Views.SettingsPages.PluginMarketDetailDrawer"
x:DataType="vm:PluginMarketDetailViewModel">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel Classes="settings-page-container"
Margin="0,0,0,8">
<Border Classes="settings-section-card">
<Grid ColumnDefinitions="Auto,*,Auto"
ColumnSpacing="14">
<Border Classes="settings-section-card-icon-host"
Width="64"
Height="64"
Padding="0"
VerticalAlignment="Center">
<Grid>
<Image IsVisible="{Binding Item.HasIcon}"
Source="{Binding Item.IconBitmap}"
Stretch="UniformToFill" />
<TextBlock IsVisible="{Binding !Item.HasIcon}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="20"
FontWeight="SemiBold"
Text="{Binding Item.IconFallbackText}" />
</Grid>
</Border>
<StackPanel Grid.Column="1"
Spacing="4"
VerticalAlignment="Center">
<TextBlock Classes="settings-card-header"
Margin="0"
Text="{Binding Item.Name}" />
<TextBlock Classes="settings-item-description"
Text="{Binding Item.DeveloperInfo}" />
</StackPanel>
<Button Grid.Column="2"
Classes="plugin-market-icon-button"
VerticalAlignment="Center"
Command="{Binding PerformPrimaryActionCommand}"
IsEnabled="{Binding Item.IsActionEnabled}"
ToolTip.Tip="{Binding Item.ActionTooltip}">
<fi:SymbolIcon Symbol="{Binding Item.ActionSymbol}" />
</Button>
</Grid>
</Border>
<Border Classes="settings-section-card">
<StackPanel Spacing="12">
<Grid ColumnDefinitions="Auto,*"
ColumnSpacing="12">
<TextBlock Classes="settings-item-label"
Text="{Binding VersionLabel}" />
<TextBlock Grid.Column="1"
Classes="settings-item-description"
Text="{Binding Item.Version}" />
</Grid>
<Grid ColumnDefinitions="Auto,*"
ColumnSpacing="12">
<TextBlock Classes="settings-item-label"
Text="{Binding PublisherLabel}" />
<TextBlock Grid.Column="1"
Classes="settings-item-description"
Text="{Binding Item.DeveloperInfo}" />
</Grid>
<Grid ColumnDefinitions="Auto,*"
ColumnSpacing="12">
<TextBlock Classes="settings-item-label"
Text="{Binding MinHostVersionLabel}" />
<TextBlock Grid.Column="1"
Classes="settings-item-description"
Text="{Binding Item.MinHostVersion}" />
</Grid>
<Grid ColumnDefinitions="Auto,*"
ColumnSpacing="12">
<TextBlock Classes="settings-item-label"
Text="{Binding ApiVersionLabel}" />
<TextBlock Grid.Column="1"
Classes="settings-item-description"
Text="{Binding Item.ApiVersion}" />
</Grid>
</StackPanel>
</Border>
<Border Classes="settings-section-card">
<StackPanel Spacing="12">
<TextBlock Classes="settings-card-header"
Margin="0"
Text="{Binding ReadmeHeader}" />
<TextBlock Classes="settings-item-description"
IsVisible="{Binding IsReadmeLoading}"
Text="{Binding ReadmeLoadingText}" />
<TextBlock Classes="settings-item-description"
IsVisible="{Binding HasReadmeError}"
Text="{Binding ReadmeError}"
TextWrapping="Wrap" />
<mdxaml:MarkdownScrollViewer IsVisible="{Binding HasReadmeContent}"
Markdown="{Binding ReadmeMarkdown}"
Engine="{x:Static helpers:PluginMarketMarkdownHelper.Engine}" />
</StackPanel>
</Border>
<Border Classes="settings-section-card">
<StackPanel Spacing="12">
<TextBlock Classes="settings-card-header"
Margin="0"
Text="{Binding DependenciesHeader}" />
<TextBlock Classes="settings-item-description"
IsVisible="{Binding !HasDependencies}"
Text="{Binding EmptyDependenciesText}"
TextWrapping="Wrap" />
<ItemsControl IsVisible="{Binding HasDependencies}"
ItemsSource="{Binding Dependencies}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Classes="settings-list-item">
<StackPanel Spacing="4">
<TextBlock Classes="settings-item-label"
Text="{Binding Id}" />
<TextBlock Classes="settings-item-description"
Text="{Binding AssemblyName}" />
<TextBlock Classes="settings-item-description"
Text="{Binding Version, StringFormat=v{0}}" />
</StackPanel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Border>
</StackPanel>
</ScrollViewer>
</UserControl>

View File

@@ -0,0 +1,18 @@
using Avalonia.Controls;
using LanMountainDesktop.ViewModels;
namespace LanMountainDesktop.Views.SettingsPages;
public partial class PluginMarketDetailDrawer : UserControl
{
public PluginMarketDetailDrawer()
{
InitializeComponent();
}
public PluginMarketDetailDrawer(PluginMarketDetailViewModel viewModel)
{
DataContext = viewModel;
InitializeComponent();
}
}

View File

@@ -0,0 +1,98 @@
<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"
xmlns:fi="using:FluentIcons.Avalonia.Fluent"
x:Class="LanMountainDesktop.Views.SettingsPages.PluginMarketSettingsPage"
x:Name="Root"
x:DataType="vm:PluginMarketSettingsPageViewModel">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel Classes="settings-page-container">
<ui:SettingsExpander Header="{Binding RefreshButtonText}"
Description="{Binding StatusMessage}">
<ui:SettingsExpander.IconSource>
<fi:SymbolIconSource Symbol="ShoppingBag" />
</ui:SettingsExpander.IconSource>
<ui:SettingsExpander.Footer>
<Grid ColumnDefinitions="*,Auto"
ColumnSpacing="12">
<TextBox Text="{Binding SearchText}"
Watermark="{Binding SearchPlaceholder}" />
<Button Grid.Column="1"
Command="{Binding RefreshCommand}"
Content="{Binding RefreshButtonText}" />
</Grid>
</ui:SettingsExpander.Footer>
</ui:SettingsExpander>
<TextBlock Classes="settings-item-description"
IsVisible="{Binding ShowEmptyState}"
Margin="0,4,0,14"
Text="{Binding EmptyStateText}"
TextWrapping="Wrap" />
<ListBox ItemsSource="{Binding FilteredPlugins}"
BorderThickness="0"
Padding="0"
Background="Transparent">
<ListBox.Styles>
<Style Selector="ListBoxItem">
<Setter Property="Padding" Value="0" />
<Setter Property="Margin" Value="0,0,0,10" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderThickness" Value="0" />
</Style>
</ListBox.Styles>
<ListBox.ItemTemplate>
<DataTemplate x:DataType="vm:PluginMarketItemViewModel">
<Border Classes="settings-list-item">
<Grid ColumnDefinitions="Auto,*,Auto"
ColumnSpacing="14">
<Border Classes="settings-section-card-icon-host"
Width="52"
Height="52"
Padding="0"
VerticalAlignment="Center">
<Grid>
<Image IsVisible="{Binding HasIcon}"
Source="{Binding IconBitmap}"
Stretch="UniformToFill" />
<TextBlock IsVisible="{Binding !HasIcon}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="18"
FontWeight="SemiBold"
Text="{Binding IconFallbackText}" />
</Grid>
</Border>
<Button Grid.Column="1"
Classes="plugin-market-row-button"
Command="{Binding #Root.DataContext.OpenDetailsCommand}"
CommandParameter="{Binding}">
<StackPanel Spacing="4"
HorizontalAlignment="Stretch">
<TextBlock Classes="settings-item-label"
Text="{Binding Name}" />
<TextBlock Classes="settings-item-description"
Text="{Binding DeveloperInfo}" />
</StackPanel>
</Button>
<Button Grid.Column="2"
Classes="plugin-market-icon-button"
VerticalAlignment="Center"
Command="{Binding #Root.DataContext.ExecutePrimaryActionCommand}"
CommandParameter="{Binding}"
IsEnabled="{Binding IsActionEnabled}"
ToolTip.Tip="{Binding ActionTooltip}">
<fi:SymbolIcon Symbol="{Binding ActionSymbol}" />
</Button>
</Grid>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</ScrollViewer>
</UserControl>

View File

@@ -0,0 +1,63 @@
using LanMountainDesktop.PluginSdk;
using LanMountainDesktop.Services;
using LanMountainDesktop.Services.PluginMarket;
using LanMountainDesktop.Services.Settings;
using LanMountainDesktop.ViewModels;
namespace LanMountainDesktop.Views.SettingsPages;
[SettingsPageInfo(
"plugin-market",
"Plugin Market",
SettingsPageCategory.PluginMarket,
IconKey = "ShoppingBag",
SortOrder = 35,
TitleLocalizationKey = "settings.plugin_market.title",
DescriptionLocalizationKey = "settings.plugin_market.subtitle")]
public partial class PluginMarketSettingsPage : SettingsPageBase
{
public PluginMarketSettingsPage()
: this(CreateDefaultViewModel())
{
}
public PluginMarketSettingsPage(PluginMarketSettingsPageViewModel viewModel)
{
ViewModel = viewModel;
ViewModel.RestartRequested += OnRestartRequested;
ViewModel.DetailsRequested += OnDetailsRequested;
DataContext = ViewModel;
InitializeComponent();
}
public PluginMarketSettingsPageViewModel ViewModel { get; }
public override async void OnNavigatedTo(object? parameter)
{
await ViewModel.InitializeAsync();
}
private static PluginMarketSettingsPageViewModel CreateDefaultViewModel()
{
var settingsFacade = HostSettingsFacadeProvider.GetOrCreate();
var localizationService = new LocalizationService();
return new PluginMarketSettingsPageViewModel(
settingsFacade,
localizationService,
new AirAppMarketIconService(),
new AirAppMarketReadmeService());
}
private void OnRestartRequested(string? reason)
{
RequestRestart(reason ?? ViewModel.RestartRequiredMessage);
}
private async void OnDetailsRequested(PluginMarketItemViewModel item)
{
var detailViewModel = ViewModel.CreateDetailViewModel(item);
var drawer = new PluginMarketDetailDrawer(detailViewModel);
OpenDrawer(drawer, detailViewModel.DrawerTitle);
await detailViewModel.InitializeAsync();
}
}

View File

@@ -9,8 +9,6 @@
x:DataType="vm:PluginsSettingsPageViewModel">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel Classes="settings-page-container">
<!-- 刷新按钮和状态 -->
<ui:SettingsExpander Header="{Binding RefreshButtonText}"
Description="{Binding StatusMessage}">
<ui:SettingsExpander.IconSource>
@@ -24,7 +22,6 @@
<Separator Classes="settings-separator" />
<!-- 已安装插件分组 -->
<controls:IconText Icon="PuzzleCube"
Text="{Binding InstalledHeader}"
Margin="0,0,0,4" />
@@ -56,37 +53,6 @@
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Separator Classes="settings-separator" />
<!-- 市场插件分组 -->
<controls:IconText Icon="ShoppingBag"
Text="{Binding MarketplaceHeader}"
Margin="0,0,0,4" />
<ItemsControl ItemsSource="{Binding MarketPlugins}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="vm:PluginMarketItemViewModel">
<ui:SettingsExpander>
<ui:SettingsExpander.IconSource>
<fi:SymbolIconSource Symbol="ShoppingBag" />
</ui:SettingsExpander.IconSource>
<ui:SettingsExpander.Header>
<StackPanel>
<TextBlock FontWeight="SemiBold" Text="{Binding Name}" />
<TextBlock Opacity="0.76" FontSize="12" Text="{Binding Description}" />
</StackPanel>
</ui:SettingsExpander.Header>
<ui:SettingsExpander.Footer>
<Button Command="{Binding #Root.DataContext.InstallPluginCommand}"
CommandParameter="{Binding}"
Content="{Binding #Root.DataContext.InstallButtonText}" />
</ui:SettingsExpander.Footer>
</ui:SettingsExpander>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</ScrollViewer>
</UserControl>

View File

@@ -638,6 +638,7 @@ public partial class SettingsWindow : Window, ISettingsPageHostContext
"Apps" => Symbol.Apps,
"GridDots" => Symbol.GridDots,
"PuzzlePiece" => Symbol.PuzzlePiece,
"ShoppingBag" => Symbol.ShoppingBag,
"Info" => Symbol.Info,
"ArrowSync" => Symbol.ArrowSync,
_ => Symbol.Settings