mirror of
https://github.com/real-zony/ZonyLrcToolsX.git
synced 2025-07-01 12:11:13 +00:00
feat: Added a settings page.
This commit is contained in:
parent
5ccd8a7c53
commit
4f15d06e63
11
Directory.Build.props
Normal file
11
Directory.Build.props
Normal file
@ -0,0 +1,11 @@
|
||||
<Project>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<Version>5.0.0.0</Version>
|
||||
<Authors>Zony(real-zony)</Authors>
|
||||
<RepositoryUrl>https://github.com/real-zony/ZonyLrcToolsX</RepositoryUrl>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
@ -3,10 +3,6 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<OutputType>Exe</OutputType>
|
||||
<AssemblyVersion>0.0.0.1</AssemblyVersion>
|
||||
<FileVersion>0.0.0.1</FileVersion>
|
||||
<PackageVersion>0.0.0.1</PackageVersion>
|
||||
<Version>0.0.0.1</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -4,7 +4,6 @@
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Version>4.0.0.58</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -14,7 +14,20 @@
|
||||
|
||||
<Application.Resources>
|
||||
<ResourceDictionary>
|
||||
<ic:SymbolIconSource x:Key="OpenIcon" Symbol="Open" />
|
||||
<ic:SymbolIconSource x:Key="CodeIcon" Symbol="Code" />
|
||||
<ic:SymbolIconSource x:Key="ChatHelpIcon" Symbol="ChatHelp" />
|
||||
<ic:SymbolIconSource x:Key="SettingsIcon" Symbol="Settings" />
|
||||
<ic:SymbolIconSource x:Key="DownloadIcon" Symbol="ArrowDownload" />
|
||||
<ic:SymbolIconSource x:Key="TagIcon" Symbol="Tag" />
|
||||
|
||||
<FontFamily x:Key="GlobalFontFamily">Microsoft YaHei, Simsun, Arial</FontFamily>
|
||||
|
||||
<ControlTheme x:Key="FluentBodyStrongTextBlockStyle"
|
||||
BasedOn="{StaticResource BodyStrongTextBlockStyle}" TargetType="TextBlock">
|
||||
<Setter Property="LineHeight" Value="20" />
|
||||
<Setter Property="ClipToBounds" Value="False" />
|
||||
</ControlTheme>
|
||||
</ResourceDictionary>
|
||||
</Application.Resources>
|
||||
|
||||
|
@ -4,26 +4,25 @@ using Avalonia.Controls.ApplicationLifetimes;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using ZonyLrcTools.Common.Infrastructure.DependencyInject;
|
||||
using ZonyLrcTools.Common.Infrastructure.Network;
|
||||
using ZonyLrcTools.Desktop.ViewModels;
|
||||
using ZonyLrcTools.Desktop.Views;
|
||||
|
||||
namespace ZonyLrcTools.Desktop;
|
||||
|
||||
public partial class App : Application
|
||||
public class App : Application
|
||||
{
|
||||
public new static App Current => (App)Application.Current!;
|
||||
public IServiceProvider Services { get; }
|
||||
|
||||
public App()
|
||||
{
|
||||
Services = ConfigureServices();
|
||||
}
|
||||
public IServiceProvider Services { get; } = ConfigureServices();
|
||||
|
||||
private static IServiceProvider ConfigureServices()
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
|
||||
services.BeginAutoDependencyInject<Program>();
|
||||
services.BeginAutoDependencyInject<IWarpHttpClient>();
|
||||
services.ConfigureConfiguration();
|
||||
services.ConfigureToolService();
|
||||
|
||||
return services.BuildServiceProvider();
|
||||
}
|
||||
|
33
src/ZonyLrcTools.Desktop/Helpers/UrlHelper.cs
Normal file
33
src/ZonyLrcTools.Desktop/Helpers/UrlHelper.cs
Normal file
@ -0,0 +1,33 @@
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace ZonyLrcTools.Desktop.Helpers;
|
||||
|
||||
public static class UrlHelper
|
||||
{
|
||||
public static void OpenLink(string url)
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
using var process = Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = "/bin/sh",
|
||||
Arguments = $"-c \"xdg-open {url.Replace("\"", "\\\"")}\"",
|
||||
RedirectStandardOutput = true,
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true,
|
||||
WindowStyle = ProcessWindowStyle.Hidden
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
using var process = Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? url : "open",
|
||||
Arguments = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? url : "",
|
||||
CreateNoWindow = true,
|
||||
UseShellExecute = RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using ZonyLrcTools.Common.Infrastructure.DependencyInject;
|
||||
using ZonyLrcTools.Common.Infrastructure.Logging;
|
||||
|
||||
namespace ZonyLrcTools.Desktop.Infrastructure.Logging;
|
||||
|
||||
public class SerilogWarpLogger(ILogger<SerilogWarpLogger> logger) : IWarpLogger, ITransientDependency
|
||||
{
|
||||
public Task DebugAsync(string message, Exception? exception = null)
|
||||
{
|
||||
logger.LogDebug(message, exception);
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task InfoAsync(string message, Exception? exception = null)
|
||||
{
|
||||
logger.LogInformation(message, exception);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task WarnAsync(string message, Exception? exception = null)
|
||||
{
|
||||
logger.LogWarning(message, exception);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task ErrorAsync(string message, Exception? exception = null)
|
||||
{
|
||||
logger.LogError(message, exception);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
@ -5,20 +5,36 @@
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="ZonyLrcTools.Desktop.Pages.SettingsPage"
|
||||
xmlns:ui="using:FluentAvalonia.UI.Controls"
|
||||
xmlns:viewModels="clr-namespace:ZonyLrcTools.Desktop.ViewModels"
|
||||
xmlns:settings="clr-namespace:ZonyLrcTools.Desktop.ViewModels.Settings"
|
||||
x:DataType="settings:LyricsSettingsViewModel">
|
||||
<ScrollViewer>
|
||||
<StackPanel Spacing="20">
|
||||
<!-- Global Configuration -->
|
||||
<ui:SettingsExpander Header="Global Lyrics Configuration" Description="Configure global settings for lyrics">
|
||||
<ui:SettingsExpanderItem Content="Merge Bilingual Lyrics">
|
||||
<StackPanel Orientation="Vertical" Margin="24" Spacing="8">
|
||||
<Grid ColumnDefinitions="Auto,*,Auto,Auto">
|
||||
<Image Width="64" Height="64" HorizontalAlignment="Left"
|
||||
Source="/Assets/logo.ico"
|
||||
RenderOptions.BitmapInterpolationMode="HighQuality" />
|
||||
|
||||
<StackPanel Grid.Column="1"
|
||||
Margin="12,0,0,0" VerticalAlignment="Center">
|
||||
<TextBlock Theme="{StaticResource FluentSubtitleTextBlockStyle}" Text="ZonyLrcToolsX" />
|
||||
<TextBlock Theme="{StaticResource FluentBodyTextBlockStyle}"
|
||||
Foreground="{DynamicResource TextFillColorSecondaryBrush}"
|
||||
Text="{Binding Version, StringFormat='Version {0}'}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<TextBlock Margin="0,20,0,0"
|
||||
Theme="{StaticResource FluentBodyStrongTextBlockStyle}"
|
||||
Text="软件设置" />
|
||||
<!-- 全局设置 -->
|
||||
<ui:SettingsExpander Header="全局设置" Description="配置软件的全局设置" IconSource="{StaticResource SettingsIcon}">
|
||||
<ui:SettingsExpanderItem Content="是否合并歌词为一行">
|
||||
<ui:SettingsExpanderItem.Footer>
|
||||
<ToggleSwitch IsChecked="{Binding Config.IsOneLine}" />
|
||||
</ui:SettingsExpanderItem.Footer>
|
||||
</ui:SettingsExpanderItem>
|
||||
|
||||
<ui:SettingsExpanderItem Content="Line Break Format">
|
||||
<ui:SettingsExpanderItem Content="换行符">
|
||||
<ui:SettingsExpanderItem.Footer>
|
||||
<ComboBox SelectedItem="{Binding Config.LineBreak}">
|
||||
<ComboBoxItem Content="Windows" />
|
||||
@ -28,19 +44,19 @@
|
||||
</ui:SettingsExpanderItem.Footer>
|
||||
</ui:SettingsExpanderItem>
|
||||
|
||||
<ui:SettingsExpanderItem Content="Enable Translation">
|
||||
<ui:SettingsExpanderItem Content="启用翻译歌词">
|
||||
<ui:SettingsExpanderItem.Footer>
|
||||
<ToggleSwitch IsChecked="{Binding Config.IsEnableTranslation}" />
|
||||
</ui:SettingsExpanderItem.Footer>
|
||||
</ui:SettingsExpanderItem>
|
||||
|
||||
<ui:SettingsExpanderItem Content="Skip Existing Lyric Files">
|
||||
<ui:SettingsExpanderItem Content="跳过已经存在的歌词文件(不覆盖)">
|
||||
<ui:SettingsExpanderItem.Footer>
|
||||
<ToggleSwitch IsChecked="{Binding Config.IsSkipExistLyricFiles}" />
|
||||
</ui:SettingsExpanderItem.Footer>
|
||||
</ui:SettingsExpanderItem>
|
||||
|
||||
<ui:SettingsExpanderItem Content="File Encoding">
|
||||
<ui:SettingsExpanderItem Content="文件编码">
|
||||
<ui:SettingsExpanderItem.Footer>
|
||||
<ComboBox SelectedItem="{Binding Config.FileEncoding}">
|
||||
<ComboBoxItem Content="UTF-8" />
|
||||
@ -50,15 +66,15 @@
|
||||
</ui:SettingsExpanderItem.Footer>
|
||||
</ui:SettingsExpanderItem>
|
||||
|
||||
<ui:SettingsExpanderItem Content="Only Output Translation">
|
||||
<ui:SettingsExpanderItem Content="只输出翻译歌词">
|
||||
<ui:SettingsExpanderItem.Footer>
|
||||
<ToggleSwitch IsChecked="{Binding Config.IsOnlyOutputTranslation}" />
|
||||
</ui:SettingsExpanderItem.Footer>
|
||||
</ui:SettingsExpanderItem>
|
||||
</ui:SettingsExpander>
|
||||
|
||||
<!-- Plugin Configuration -->
|
||||
<ui:SettingsExpander Header="Lyrics Provider Plugins" Description="Configure settings for lyrics provider plugins">
|
||||
<!-- 歌词下载器配置 -->
|
||||
<ui:SettingsExpander Header="歌词下载器设置" Description="配置每个单独的歌词下载器参数" IconSource="{StaticResource DownloadIcon}">
|
||||
<ItemsRepeater ItemsSource="{Binding Plugin}">
|
||||
<ItemsRepeater.ItemTemplate>
|
||||
<DataTemplate>
|
||||
@ -67,13 +83,13 @@
|
||||
<TextBlock Text="{Binding Name}" />
|
||||
</ui:SettingsExpander.Header>
|
||||
|
||||
<ui:SettingsExpanderItem Content="Priority">
|
||||
<ui:SettingsExpanderItem Content="下载器优先级">
|
||||
<ui:SettingsExpanderItem.Footer>
|
||||
<NumericUpDown Value="{Binding Priority}" Minimum="-1" Maximum="100" />
|
||||
</ui:SettingsExpanderItem.Footer>
|
||||
</ui:SettingsExpanderItem>
|
||||
|
||||
<ui:SettingsExpanderItem Content="Search Depth">
|
||||
<ui:SettingsExpanderItem Content="搜索深度">
|
||||
<ui:SettingsExpanderItem.Footer>
|
||||
<NumericUpDown Value="{Binding Depth}" Minimum="1" Maximum="100" />
|
||||
</ui:SettingsExpanderItem.Footer>
|
||||
@ -84,26 +100,25 @@
|
||||
</ItemsRepeater>
|
||||
</ui:SettingsExpander>
|
||||
|
||||
<!-- Tag Info Configuration -->
|
||||
<ui:SettingsExpander Header="Tag Info Configuration" Description="Configure settings for tag information">
|
||||
<!-- 标签设置 -->
|
||||
<ui:SettingsExpander Header="标签读取设置" Description="配置读取音乐文件标签时的一些参数" IconSource="{StaticResource TagIcon}">
|
||||
<!-- Block Word Options -->
|
||||
<ui:SettingsExpanderItem Content="Enable Block Word Feature">
|
||||
<ui:SettingsExpanderItem Content="是否启用屏蔽字典">
|
||||
<ui:SettingsExpanderItem.Footer>
|
||||
<ToggleSwitch IsChecked="{Binding Tag.BlockWord.IsEnable}" />
|
||||
</ui:SettingsExpanderItem.Footer>
|
||||
</ui:SettingsExpanderItem>
|
||||
|
||||
<ui:SettingsExpanderItem Content="Block Word Dictionary File Path">
|
||||
<ui:SettingsExpanderItem Content="屏蔽字典的路径:">
|
||||
<ui:SettingsExpanderItem.Footer>
|
||||
<StackPanel Orientation="Horizontal" Spacing="10">
|
||||
<TextBox Text="{Binding Tag.BlockWord.FilePath}" Width="200" />
|
||||
<Button Content="Browse" Command="{Binding BrowseBlockWordFileCommand}" />
|
||||
<Button Content="浏览" Command="{Binding BrowseBlockWordFileCommand}" />
|
||||
</StackPanel>
|
||||
</ui:SettingsExpanderItem.Footer>
|
||||
</ui:SettingsExpanderItem>
|
||||
|
||||
<!-- Tag Info Providers -->
|
||||
<ui:SettingsExpander Header="Tag Info Providers" Description="Configure settings for tag info provider plugins">
|
||||
<ui:SettingsExpander Header="标签扫描器" Description="配置标签扫描器">
|
||||
<ItemsRepeater ItemsSource="{Binding Tag.Plugin}">
|
||||
<ItemsRepeater.ItemTemplate>
|
||||
<DataTemplate>
|
||||
@ -112,13 +127,13 @@
|
||||
<TextBlock Text="{Binding Name}" />
|
||||
</ui:SettingsExpander.Header>
|
||||
|
||||
<ui:SettingsExpanderItem Content="Priority">
|
||||
<ui:SettingsExpanderItem Content="优先级">
|
||||
<ui:SettingsExpanderItem.Footer>
|
||||
<NumericUpDown Value="{Binding Priority}" Minimum="-1" Maximum="100" />
|
||||
</ui:SettingsExpanderItem.Footer>
|
||||
</ui:SettingsExpanderItem>
|
||||
|
||||
<ui:SettingsExpanderItem Content="Extensions">
|
||||
<ui:SettingsExpanderItem Content="扩展配置">
|
||||
<ui:SettingsExpanderItem.Footer>
|
||||
<ItemsRepeater ItemsSource="{Binding Extensions}">
|
||||
<ItemsRepeater.ItemTemplate>
|
||||
@ -138,6 +153,30 @@
|
||||
</ItemsRepeater>
|
||||
</ui:SettingsExpander>
|
||||
</ui:SettingsExpander>
|
||||
|
||||
<TextBlock Margin="0,20,0,0"
|
||||
Theme="{StaticResource FluentBodyStrongTextBlockStyle}"
|
||||
Text="关于" />
|
||||
|
||||
<ui:SettingsExpander Description="获得帮助与支持信息" Header="帮助与支持"
|
||||
IconSource="{StaticResource ChatHelpIcon}">
|
||||
<ui:SettingsExpanderItem>
|
||||
<!-- QQ 群 -->
|
||||
<StackPanel Orientation="Vertical" Spacing="10">
|
||||
<TextBlock Text="QQ 群: 337656932" />
|
||||
<ui:HyperlinkButton NavigateUri="https://docs.myzony.com/">
|
||||
<StackPanel Orientation="Horizontal" Spacing="5">
|
||||
<ui:SymbolIcon Symbol="Link" />
|
||||
<TextBlock Text="使用文档" />
|
||||
</StackPanel>
|
||||
</ui:HyperlinkButton>
|
||||
</StackPanel>
|
||||
</ui:SettingsExpanderItem>
|
||||
</ui:SettingsExpander>
|
||||
|
||||
<ui:SettingsExpander ActionIconSource="{StaticResource OpenIcon}" Click="OnGitHubClick"
|
||||
Description="获取软件的源代码" Header="GitHub 仓库"
|
||||
IconSource="{StaticResource CodeIcon}" IsClickEnabled="True" />
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</UserControl>
|
@ -1,8 +1,9 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
using ZonyLrcTools.Common.Configuration;
|
||||
using ZonyLrcTools.Desktop.ViewModels;
|
||||
using ZonyLrcTools.Desktop.Helpers;
|
||||
using ZonyLrcTools.Desktop.ViewModels.Settings;
|
||||
|
||||
namespace ZonyLrcTools.Desktop.Pages;
|
||||
@ -14,4 +15,6 @@ public partial class SettingsPage : UserControl
|
||||
InitializeComponent();
|
||||
DataContext = new LyricsSettingsViewModel(App.Current.Services.GetRequiredService<IOptions<GlobalOptions>>().Value);
|
||||
}
|
||||
|
||||
private void OnGitHubClick(object? sender, RoutedEventArgs? eventArgs) => UrlHelper.OpenLink("https://github.com/real-zony/ZonyLrcToolsX");
|
||||
}
|
@ -1,11 +1,12 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using ReactiveUI;
|
||||
using ZonyLrcTools.Common;
|
||||
|
||||
namespace ZonyLrcTools.Desktop.ViewModels;
|
||||
|
||||
public class HomeViewModel : ViewModelBase
|
||||
{
|
||||
public ObservableCollection<SongInfo> Songs { get; } = [];
|
||||
public ObservableCollection<SongInfoViewModel> Songs { get; } = [];
|
||||
|
||||
private double _downloadProgress;
|
||||
|
||||
@ -16,10 +17,20 @@ public class HomeViewModel : ViewModelBase
|
||||
}
|
||||
}
|
||||
|
||||
public class SongInfo
|
||||
public class SongInfoViewModel(MusicInfo info)
|
||||
{
|
||||
public string SongName { get; set; }
|
||||
public string ArtistName { get; set; }
|
||||
public string FilePath { get; set; }
|
||||
public string DownloadStatus { get; set; }
|
||||
private MusicInfo Info { get; } = info;
|
||||
|
||||
public string SongName => Info.Name;
|
||||
public string ArtistName => Info.Artist;
|
||||
public string FilePath => Info.FilePath;
|
||||
|
||||
public DownloadStatus DownloadStatus { get; set; } = DownloadStatus.NotStarted;
|
||||
}
|
||||
|
||||
public enum DownloadStatus
|
||||
{
|
||||
NotStarted = 1,
|
||||
Completed,
|
||||
Failed
|
||||
}
|
@ -20,6 +20,8 @@ public class LyricsSettingsViewModel : ViewModelBase
|
||||
BrowseBlockWordFileCommand = ReactiveCommand.Create(BrowseBlockWordFile);
|
||||
}
|
||||
|
||||
public static string Version => typeof(Program).Assembly.GetName().Version!.ToString();
|
||||
|
||||
public TagInfoViewModel Tag { get; }
|
||||
|
||||
public ReactiveCommand<Unit, Unit> BrowseBlockWordFileCommand { get; }
|
||||
|
@ -1,9 +1,14 @@
|
||||
using System.Linq;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Platform.Storage;
|
||||
using DynamicData;
|
||||
using FluentAvalonia.UI.Controls;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using ZonyLrcTools.Common;
|
||||
using ZonyLrcTools.Desktop.Pages;
|
||||
using ZonyLrcTools.Desktop.ViewModels;
|
||||
|
||||
namespace ZonyLrcTools.Desktop.Views;
|
||||
|
||||
@ -41,14 +46,20 @@ public partial class MainView : UserControl
|
||||
private async void OnOpenFolderButtonClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
var storage = _window?.StorageProvider;
|
||||
if (storage?.CanOpen == true)
|
||||
var musicInfoLoader = App.Current.Services.GetRequiredService<IMusicInfoLoader>();
|
||||
|
||||
if (storage?.CanOpen == true && DataContext is HomeViewModel vm)
|
||||
{
|
||||
var options = new FolderPickerOpenOptions
|
||||
{
|
||||
SuggestedStartLocation = await storage.TryGetWellKnownFolderAsync(WellKnownFolder.Music)
|
||||
};
|
||||
var folders = await storage.OpenFolderPickerAsync(options);
|
||||
var folderPath = folders[0].Path;
|
||||
var folderPath = folders[0].Path.LocalPath;
|
||||
var musicInfos = await musicInfoLoader.LoadAsync(folderPath);
|
||||
|
||||
vm.Songs.Clear();
|
||||
vm.Songs.AddRange(musicInfos.Select(x => new SongInfoViewModel(x!)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Avalonia.Controls;
|
||||
using ZonyLrcTools.Desktop.ViewModels;
|
||||
|
||||
namespace ZonyLrcTools.Desktop.Views;
|
||||
|
||||
@ -6,6 +7,7 @@ public partial class MainWindow : Window
|
||||
{
|
||||
public MainWindow()
|
||||
{
|
||||
DataContext = new HomeViewModel();
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
@ -22,6 +22,7 @@
|
||||
<PackageReference Include="Avalonia.ReactiveUI"/>
|
||||
<PackageReference Include="FluentAvaloniaUI" />
|
||||
<PackageReference Include="FluentIcons.Avalonia.Fluent" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
Loading…
x
Reference in New Issue
Block a user