mirror of
https://github.com/real-zony/ZonyLrcToolsX.git
synced 2025-07-01 04:00:42 +00:00
refactor: Removed avalonia code.
This commit is contained in:
parent
9ab9cd50e2
commit
7732ab52d3
@ -13,8 +13,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZonyLrcTools.Tests", "tests
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZonyLrcTools.Common", "src\ZonyLrcTools.Common\ZonyLrcTools.Common.csproj", "{9B42E4CA-61AA-4798-8D2B-2D8A7035EB67}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZonyLrcTools.Desktop", "src\ZonyLrcTools.Desktop\ZonyLrcTools.Desktop.csproj", "{DC92902B-4303-4E43-AFB3-3F93FD3986AD}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -33,10 +31,6 @@ Global
|
||||
{9B42E4CA-61AA-4798-8D2B-2D8A7035EB67}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9B42E4CA-61AA-4798-8D2B-2D8A7035EB67}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9B42E4CA-61AA-4798-8D2B-2D8A7035EB67}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{DC92902B-4303-4E43-AFB3-3F93FD3986AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{DC92902B-4303-4E43-AFB3-3F93FD3986AD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DC92902B-4303-4E43-AFB3-3F93FD3986AD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{DC92902B-4303-4E43-AFB3-3F93FD3986AD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@ -48,6 +42,5 @@ Global
|
||||
{55D74323-ABFA-4A73-A3BF-F3E8D5DE6DE8} = {C29FB05C-54B1-4020-94D2-87E192EB2F98}
|
||||
{FFBD3200-568F-455B-8390-5E76C51D522C} = {AF8ADB2F-E46C-4DEE-8316-652D9FE1A69B}
|
||||
{9B42E4CA-61AA-4798-8D2B-2D8A7035EB67} = {C29FB05C-54B1-4020-94D2-87E192EB2F98}
|
||||
{DC92902B-4303-4E43-AFB3-3F93FD3986AD} = {C29FB05C-54B1-4020-94D2-87E192EB2F98}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
@ -1,35 +0,0 @@
|
||||
<Application xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
x:Class="ZonyLrcTools.Desktop.App"
|
||||
xmlns:local="using:ZonyLrcTools.Desktop"
|
||||
xmlns:styling="clr-namespace:FluentAvalonia.Styling;assembly=FluentAvalonia"
|
||||
RequestedThemeVariant="Default"
|
||||
xmlns:ic="using:FluentIcons.Avalonia.Fluent">
|
||||
<!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. -->
|
||||
|
||||
<Application.DataTemplates>
|
||||
<local:ViewLocator />
|
||||
</Application.DataTemplates>
|
||||
|
||||
<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>
|
||||
</ResourceDictionary>
|
||||
</Application.Resources>
|
||||
|
||||
<Application.Styles>
|
||||
<FluentTheme />
|
||||
<styling:FluentAvaloniaTheme />
|
||||
<Style Selector="TextBlock">
|
||||
<Setter Property="FontFamily" Value="{StaticResource GlobalFontFamily}" />
|
||||
</Style>
|
||||
<StyleInclude Source="/Controls/DownloadStatusControl.axaml" />
|
||||
</Application.Styles>
|
||||
</Application>
|
@ -1,67 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls.ApplicationLifetimes;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
using YamlDotNet.Core;
|
||||
using YamlDotNet.Serialization;
|
||||
using YamlDotNet.Serialization.NamingConventions;
|
||||
using ZonyLrcTools.Common.Configuration;
|
||||
using ZonyLrcTools.Common.Infrastructure.DependencyInject;
|
||||
using ZonyLrcTools.Common.Infrastructure.Network;
|
||||
using ZonyLrcTools.Desktop.ViewModels;
|
||||
using ZonyLrcTools.Desktop.Views;
|
||||
|
||||
namespace ZonyLrcTools.Desktop;
|
||||
|
||||
public class App : Application
|
||||
{
|
||||
public new static App Current => (App)Application.Current!;
|
||||
public IServiceProvider Services { get; } = ConfigureServices();
|
||||
|
||||
public IOptions<GlobalOptions> GlobalOptions => Services.GetRequiredService<IOptions<GlobalOptions>>();
|
||||
|
||||
private Lazy<ISerializer> _yamlSerializer = new(() => new SerializerBuilder()
|
||||
.WithNamingConvention(CamelCaseNamingConvention.Instance)
|
||||
.WithDefaultScalarStyle(ScalarStyle.DoubleQuoted)
|
||||
.Build());
|
||||
|
||||
private static IServiceProvider ConfigureServices()
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
|
||||
services.BeginAutoDependencyInject<Program>();
|
||||
services.BeginAutoDependencyInject<IWarpHttpClient>();
|
||||
services.ConfigureConfiguration();
|
||||
services.ConfigureToolService();
|
||||
|
||||
return services.BuildServiceProvider();
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
|
||||
public override void OnFrameworkInitializationCompleted()
|
||||
{
|
||||
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
{
|
||||
desktop.MainWindow = new MainWindow
|
||||
{
|
||||
DataContext = new HomeViewModel(),
|
||||
};
|
||||
}
|
||||
|
||||
base.OnFrameworkInitializationCompleted();
|
||||
}
|
||||
|
||||
public void UpdateConfiguration()
|
||||
{
|
||||
var configPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "config.yaml");
|
||||
var yamlString = _yamlSerializer.Value.Serialize(GlobalOptions.Value);
|
||||
File.WriteAllText(configPath, yamlString);
|
||||
}
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 172 KiB |
Binary file not shown.
Before Width: | Height: | Size: 142 KiB |
@ -1,92 +0,0 @@
|
||||
<Styles xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:ZonyLrcTools.Desktop.Controls"
|
||||
xmlns:fluent="using:FluentIcons.Avalonia.Fluent">
|
||||
|
||||
<Design.PreviewWith>
|
||||
<controls:DownloadStatusControl Status="Completed" />
|
||||
</Design.PreviewWith>
|
||||
|
||||
<Style Selector="controls|DownloadStatusControl">
|
||||
<!-- Set Defaults -->
|
||||
<Setter Property="Template">
|
||||
<ControlTemplate>
|
||||
<StackPanel Orientation="Horizontal" Spacing="5">
|
||||
<Border Name="IconContainer" Width="20" Height="20">
|
||||
<fluent:SymbolIcon Name="StatusIcon" Symbol="{TemplateBinding Symbol}" />
|
||||
</Border>
|
||||
<TextBlock Text="{TemplateBinding Text}" VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
</ControlTemplate>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style Selector="controls|DownloadStatusControl[Status=NotStarted]">
|
||||
<Setter Property="Symbol" Value="QuestionCircle" />
|
||||
<Setter Property="Text" Value="未下载" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="controls|DownloadStatusControl[Status=Completed]">
|
||||
<Setter Property="Symbol" Value="CheckmarkCircle" />
|
||||
<Setter Property="Text" Value="已完成" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="controls|DownloadStatusControl[Status=Failed]">
|
||||
<Setter Property="Symbol" Value="DismissCircle" />
|
||||
<Setter Property="Text" Value="失败" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="controls|DownloadStatusControl[Status=Completed] /template/ Border#IconContainer">
|
||||
<Style.Animations>
|
||||
<Animation Duration="0:0:0.5">
|
||||
<KeyFrame Cue="0%">
|
||||
<Setter Property="RotateTransform.Angle" Value="0"/>
|
||||
<Setter Property="ScaleTransform.ScaleX" Value="1"/>
|
||||
<Setter Property="ScaleTransform.ScaleY" Value="1"/>
|
||||
</KeyFrame>
|
||||
<KeyFrame Cue="50%">
|
||||
<Setter Property="RotateTransform.Angle" Value="180"/>
|
||||
<Setter Property="ScaleTransform.ScaleX" Value="1.2"/>
|
||||
<Setter Property="ScaleTransform.ScaleY" Value="1.2"/>
|
||||
</KeyFrame>
|
||||
<KeyFrame Cue="100%">
|
||||
<Setter Property="RotateTransform.Angle" Value="360"/>
|
||||
<Setter Property="ScaleTransform.ScaleX" Value="1"/>
|
||||
<Setter Property="ScaleTransform.ScaleY" Value="1"/>
|
||||
</KeyFrame>
|
||||
</Animation>
|
||||
</Style.Animations>
|
||||
</Style>
|
||||
|
||||
<Style Selector="controls|DownloadStatusControl[Status=Failed] /template/ Border#IconContainer">
|
||||
<Style.Animations>
|
||||
<Animation Duration="0:0:0.5" IterationCount="3">
|
||||
<KeyFrame Cue="0%">
|
||||
<Setter Property="TranslateTransform.X" Value="0"/>
|
||||
</KeyFrame>
|
||||
<KeyFrame Cue="25%">
|
||||
<Setter Property="TranslateTransform.X" Value="-2"/>
|
||||
</KeyFrame>
|
||||
<KeyFrame Cue="50%">
|
||||
<Setter Property="TranslateTransform.X" Value="0"/>
|
||||
</KeyFrame>
|
||||
<KeyFrame Cue="75%">
|
||||
<Setter Property="TranslateTransform.X" Value="2"/>
|
||||
</KeyFrame>
|
||||
<KeyFrame Cue="100%">
|
||||
<Setter Property="TranslateTransform.X" Value="0"/>
|
||||
</KeyFrame>
|
||||
</Animation>
|
||||
</Style.Animations>
|
||||
</Style>
|
||||
|
||||
<Style Selector="controls|DownloadStatusControl /template/ Border#IconContainer">
|
||||
<Setter Property="RenderTransform">
|
||||
<TransformGroup>
|
||||
<RotateTransform/>
|
||||
<ScaleTransform/>
|
||||
<TranslateTransform/>
|
||||
</TransformGroup>
|
||||
</Setter>
|
||||
</Style>
|
||||
</Styles>
|
@ -1,36 +0,0 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using FluentIcons.Common;
|
||||
using ZonyLrcTools.Desktop.ViewModels;
|
||||
|
||||
namespace ZonyLrcTools.Desktop.Controls;
|
||||
|
||||
public class DownloadStatusControl : TemplatedControl
|
||||
{
|
||||
public static readonly StyledProperty<DownloadStatus> StatusProperty =
|
||||
AvaloniaProperty.Register<DownloadStatusControl, DownloadStatus>(nameof(Status));
|
||||
|
||||
public static readonly StyledProperty<Symbol> SymbolProperty =
|
||||
AvaloniaProperty.Register<DownloadStatusControl, Symbol>(nameof(Symbol));
|
||||
|
||||
public static readonly StyledProperty<string> TextProperty =
|
||||
AvaloniaProperty.Register<DownloadStatusControl, string>(nameof(Text));
|
||||
|
||||
public DownloadStatus Status
|
||||
{
|
||||
get => GetValue(StatusProperty);
|
||||
set => SetValue(StatusProperty, value);
|
||||
}
|
||||
|
||||
public Symbol Symbol
|
||||
{
|
||||
get => GetValue(SymbolProperty);
|
||||
set => SetValue(SymbolProperty, value);
|
||||
}
|
||||
|
||||
public string Text
|
||||
{
|
||||
get => GetValue(TextProperty);
|
||||
set => SetValue(TextProperty, value);
|
||||
}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
|
||||
<ReactiveUI />
|
||||
</Weavers>
|
@ -1,33 +0,0 @@
|
||||
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)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
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;
|
||||
}
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:viewModels="clr-namespace:ZonyLrcTools.Desktop.ViewModels"
|
||||
xmlns:controls="clr-namespace:ZonyLrcTools.Desktop.Controls"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="ZonyLrcTools.Desktop.Pages.HomePage"
|
||||
x:DataType="viewModels:HomeViewModel">
|
||||
|
||||
<DockPanel>
|
||||
<StackPanel DockPanel.Dock="Bottom" Margin="10">
|
||||
<TextBlock Text="下载进度:" Margin="0,0,0,5" />
|
||||
<ProgressBar Value="{Binding DownloadProgress}" Maximum="{Binding MaxProgress}" Height="20" />
|
||||
</StackPanel>
|
||||
|
||||
<DataGrid AutoGenerateColumns="False"
|
||||
IsReadOnly="True"
|
||||
GridLinesVisibility="All"
|
||||
BorderThickness="1"
|
||||
BorderBrush="Gray"
|
||||
ItemsSource="{Binding Songs}">
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Header="歌曲名称" Binding="{Binding SongName}" Width="*" />
|
||||
<DataGridTextColumn Header="歌手名称" Binding="{Binding ArtistName}" Width="*" />
|
||||
<DataGridTextColumn Header="文件路径" Binding="{Binding FilePath}" Width="2*" />
|
||||
<DataGridTemplateColumn Header="下载状态" Width="1*">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<controls:DownloadStatusControl Status="{Binding DownloadStatus}" />
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
</DataGrid.Columns>
|
||||
|
||||
<DataGrid.Styles>
|
||||
<Style Selector="DataGridColumnHeader">
|
||||
<Setter Property="Background" Value="{DynamicResource ControlFillColorDefault}" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource TextFillColorPrimary}" />
|
||||
<Setter Property="FontWeight" Value="SemiBold" />
|
||||
<Setter Property="Padding" Value="12,8,12,8" />
|
||||
<Setter Property="VerticalContentAlignment" Value="Center" />
|
||||
</Style>
|
||||
<Style Selector="DataGridCell">
|
||||
<Setter Property="Padding" Value="12,8" />
|
||||
</Style>
|
||||
</DataGrid.Styles>
|
||||
</DataGrid>
|
||||
</DockPanel>
|
||||
</UserControl>
|
@ -1,24 +0,0 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using ZonyLrcTools.Desktop.ViewModels;
|
||||
|
||||
namespace ZonyLrcTools.Desktop.Pages;
|
||||
|
||||
public partial class HomePage : UserControl
|
||||
{
|
||||
public HomePage()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
|
||||
{
|
||||
base.OnAttachedToVisualTree(e);
|
||||
|
||||
if (DataContext is HomeViewModel vm)
|
||||
{
|
||||
vm.MaxProgress = 100;
|
||||
vm.DownloadProgress = 0;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,190 +0,0 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="ZonyLrcTools.Desktop.Pages.SettingsPage"
|
||||
xmlns:ui="using:FluentAvalonia.UI.Controls"
|
||||
xmlns:settings="clr-namespace:ZonyLrcTools.Desktop.ViewModels.Settings"
|
||||
x:DataType="settings:SettingsViewModel">
|
||||
|
||||
<UserControl.Resources>
|
||||
<settings:NullToDefaultValueConverter x:Key="NullToDefaultValueConverter" />
|
||||
</UserControl.Resources>
|
||||
|
||||
<ScrollViewer>
|
||||
<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 Text="ZonyLrcToolsX" />
|
||||
<TextBlock Foreground="{DynamicResource TextFillColorSecondaryBrush}"
|
||||
Text="{Binding Version, StringFormat='Version {0}'}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<TextBlock Margin="0,20,0,0"
|
||||
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="换行符">
|
||||
<ui:SettingsExpanderItem.Footer>
|
||||
<ComboBox ItemsSource="{Binding Config.LineBreakOptions}"
|
||||
SelectedItem="{Binding Config.SelectedLineBreak}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Name}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
</ui:SettingsExpanderItem.Footer>
|
||||
</ui:SettingsExpanderItem>
|
||||
|
||||
<ui:SettingsExpanderItem Content="启用翻译歌词">
|
||||
<ui:SettingsExpanderItem.Footer>
|
||||
<ToggleSwitch IsChecked="{Binding Config.IsEnableTranslation}" />
|
||||
</ui:SettingsExpanderItem.Footer>
|
||||
</ui:SettingsExpanderItem>
|
||||
|
||||
<ui:SettingsExpanderItem Content="跳过已经存在的歌词文件(不覆盖)">
|
||||
<ui:SettingsExpanderItem.Footer>
|
||||
<ToggleSwitch IsChecked="{Binding Config.IsSkipExistLyricFiles}" />
|
||||
</ui:SettingsExpanderItem.Footer>
|
||||
</ui:SettingsExpanderItem>
|
||||
|
||||
<ui:SettingsExpanderItem Content="文件编码">
|
||||
<ui:SettingsExpanderItem.Footer>
|
||||
<ComboBox ItemsSource="{Binding Config.FileEncodingOptions}"
|
||||
SelectedItem="{Binding Config.SelectedFileEncoding}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Name}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
</ui:SettingsExpanderItem.Footer>
|
||||
</ui:SettingsExpanderItem>
|
||||
|
||||
<ui:SettingsExpanderItem Content="只输出翻译歌词">
|
||||
<ui:SettingsExpanderItem.Footer>
|
||||
<ToggleSwitch IsChecked="{Binding Config.IsOnlyOutputTranslation}" />
|
||||
</ui:SettingsExpanderItem.Footer>
|
||||
</ui:SettingsExpanderItem>
|
||||
</ui:SettingsExpander>
|
||||
|
||||
<!-- 歌词下载器配置 -->
|
||||
<ui:SettingsExpander Header="歌词下载器设置" Description="配置每个单独的歌词下载器参数" IconSource="{StaticResource DownloadIcon}">
|
||||
<ItemsRepeater ItemsSource="{Binding LyricsProviders}">
|
||||
<ItemsRepeater.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<ui:SettingsExpander Margin="0,0,0,10">
|
||||
<ui:SettingsExpander.Header>
|
||||
<TextBlock Text="{Binding Name}" />
|
||||
</ui:SettingsExpander.Header>
|
||||
|
||||
<ui:SettingsExpanderItem Content="下载器优先级">
|
||||
<ui:SettingsExpanderItem.Footer>
|
||||
<NumericUpDown Value="{Binding Priority, Converter={StaticResource NullToDefaultValueConverter}}" Minimum="-1" Maximum="100" Increment="1" />
|
||||
</ui:SettingsExpanderItem.Footer>
|
||||
</ui:SettingsExpanderItem>
|
||||
|
||||
<ui:SettingsExpanderItem Content="搜索深度">
|
||||
<ui:SettingsExpanderItem.Footer>
|
||||
<NumericUpDown Value="{Binding Depth, Converter={StaticResource NullToDefaultValueConverter}}" Minimum="1" Maximum="100" Increment="1" />
|
||||
</ui:SettingsExpanderItem.Footer>
|
||||
</ui:SettingsExpanderItem>
|
||||
</ui:SettingsExpander>
|
||||
</DataTemplate>
|
||||
</ItemsRepeater.ItemTemplate>
|
||||
</ItemsRepeater>
|
||||
</ui:SettingsExpander>
|
||||
|
||||
<!-- 标签设置 -->
|
||||
<ui:SettingsExpander Header="标签读取设置" Description="配置读取音乐文件标签时的一些参数" IconSource="{StaticResource TagIcon}">
|
||||
<!-- Block Word Options -->
|
||||
<ui:SettingsExpanderItem Content="是否启用屏蔽字典">
|
||||
<ui:SettingsExpanderItem.Footer>
|
||||
<ToggleSwitch IsChecked="{Binding Tag.BlockWord.IsEnable}" />
|
||||
</ui:SettingsExpanderItem.Footer>
|
||||
</ui:SettingsExpanderItem>
|
||||
|
||||
<ui:SettingsExpanderItem Content="屏蔽字典的路径:">
|
||||
<ui:SettingsExpanderItem.Footer>
|
||||
<StackPanel Orientation="Horizontal" Spacing="10">
|
||||
<TextBox Text="{Binding Tag.BlockWord.FilePath}" Width="200" />
|
||||
<Button Content="浏览" Command="{Binding BrowseBlockWordFileCommand}" CommandParameter="{Binding $parent[Window]}" />
|
||||
</StackPanel>
|
||||
</ui:SettingsExpanderItem.Footer>
|
||||
</ui:SettingsExpanderItem>
|
||||
|
||||
<ui:SettingsExpander Header="标签扫描器" Description="配置标签扫描器">
|
||||
<ItemsRepeater ItemsSource="{Binding Tag.TagInfoProviders}">
|
||||
<ItemsRepeater.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<ui:SettingsExpander Margin="0,0,0,10">
|
||||
<ui:SettingsExpander.Header>
|
||||
<TextBlock Text="{Binding Name}" />
|
||||
</ui:SettingsExpander.Header>
|
||||
|
||||
<ui:SettingsExpanderItem Content="优先级">
|
||||
<ui:SettingsExpanderItem.Footer>
|
||||
<NumericUpDown Value="{Binding Priority , Converter={StaticResource NullToDefaultValueConverter}}" Minimum="-1" Maximum="100" Increment="1" />
|
||||
</ui:SettingsExpanderItem.Footer>
|
||||
</ui:SettingsExpanderItem>
|
||||
|
||||
<ui:SettingsExpanderItem Content="扩展配置">
|
||||
<ui:SettingsExpanderItem.Footer>
|
||||
<ItemsRepeater ItemsSource="{Binding Extensions}">
|
||||
<ItemsRepeater.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid ColumnDefinitions="Auto,*" Margin="0,5">
|
||||
<TextBlock Grid.Column="0" Text="{Binding Key}" Margin="0,0,10,0" />
|
||||
<TextBox Grid.Column="1" Text="{Binding Value}" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ItemsRepeater.ItemTemplate>
|
||||
</ItemsRepeater>
|
||||
</ui:SettingsExpanderItem.Footer>
|
||||
</ui:SettingsExpanderItem>
|
||||
</ui:SettingsExpander>
|
||||
</DataTemplate>
|
||||
</ItemsRepeater.ItemTemplate>
|
||||
</ItemsRepeater>
|
||||
</ui:SettingsExpander>
|
||||
</ui:SettingsExpander>
|
||||
|
||||
<TextBlock Margin="0,20,0,0"
|
||||
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,20 +0,0 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
using ZonyLrcTools.Common.Configuration;
|
||||
using ZonyLrcTools.Desktop.Helpers;
|
||||
using ZonyLrcTools.Desktop.ViewModels.Settings;
|
||||
|
||||
namespace ZonyLrcTools.Desktop.Pages;
|
||||
|
||||
public partial class SettingsPage : UserControl
|
||||
{
|
||||
public SettingsPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContext = new SettingsViewModel(App.Current.Services.GetRequiredService<IOptions<GlobalOptions>>().Value);
|
||||
}
|
||||
|
||||
private void OnGitHubClick(object? sender, RoutedEventArgs? eventArgs) => UrlHelper.OpenLink("https://github.com/real-zony/ZonyLrcToolsX");
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
using Avalonia;
|
||||
using Avalonia.ReactiveUI;
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace ZonyLrcTools.Desktop;
|
||||
|
||||
class Program
|
||||
{
|
||||
// Initialization code. Don't use any Avalonia, third-party APIs or any
|
||||
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
|
||||
// yet and stuff might break.
|
||||
[STAThread]
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
||||
BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
|
||||
}
|
||||
|
||||
// Avalonia configuration, don't remove; also used by visual designer.
|
||||
public static AppBuilder BuildAvaloniaApp()
|
||||
=> AppBuilder.Configure<App>()
|
||||
.UsePlatformDetect()
|
||||
.WithInterFont()
|
||||
.LogToTrace()
|
||||
.UseReactiveUI();
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
using System;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Templates;
|
||||
using ZonyLrcTools.Desktop.ViewModels;
|
||||
|
||||
namespace ZonyLrcTools.Desktop;
|
||||
|
||||
public class ViewLocator : IDataTemplate
|
||||
{
|
||||
public Control Build(object data)
|
||||
{
|
||||
var name = data.GetType().FullName!.Replace("ViewModel", "View");
|
||||
var type = Type.GetType(name);
|
||||
|
||||
if (type != null)
|
||||
{
|
||||
return (Control)Activator.CreateInstance(type)!;
|
||||
}
|
||||
|
||||
return new TextBlock { Text = "Not Found: " + name };
|
||||
}
|
||||
|
||||
public bool Match(object data)
|
||||
{
|
||||
return data is ViewModelBase;
|
||||
}
|
||||
}
|
@ -1,77 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using ReactiveUI;
|
||||
using ZonyLrcTools.Common;
|
||||
|
||||
namespace ZonyLrcTools.Desktop.ViewModels;
|
||||
|
||||
public class HomeViewModel : ViewModelBase
|
||||
{
|
||||
private ObservableCollection<SongInfoViewModel> _songs = new();
|
||||
|
||||
public ObservableCollection<SongInfoViewModel> Songs
|
||||
{
|
||||
get => _songs;
|
||||
set => this.RaiseAndSetIfChanged(ref _songs, value);
|
||||
}
|
||||
|
||||
private int _downloadProgress;
|
||||
|
||||
public int DownloadProgress
|
||||
{
|
||||
get => _downloadProgress;
|
||||
set => this.RaiseAndSetIfChanged(ref _downloadProgress, value);
|
||||
}
|
||||
|
||||
private int _maxProgress;
|
||||
|
||||
public int MaxProgress
|
||||
{
|
||||
get => _maxProgress;
|
||||
set => this.RaiseAndSetIfChanged(ref _maxProgress, value);
|
||||
}
|
||||
}
|
||||
|
||||
public class SongInfoViewModel : ReactiveObject
|
||||
{
|
||||
public SongInfoViewModel(MusicInfo info)
|
||||
{
|
||||
_info = info;
|
||||
DownloadStatus = DownloadStatus.NotStarted;
|
||||
|
||||
this.WhenAnyValue(x => x.Info)
|
||||
.Subscribe(_ =>
|
||||
{
|
||||
this.RaisePropertyChanged(nameof(SongName));
|
||||
this.RaisePropertyChanged(nameof(ArtistName));
|
||||
this.RaisePropertyChanged(nameof(FilePath));
|
||||
});
|
||||
}
|
||||
|
||||
private MusicInfo _info;
|
||||
|
||||
public MusicInfo Info
|
||||
{
|
||||
get => _info;
|
||||
set => this.RaiseAndSetIfChanged(ref _info, value);
|
||||
}
|
||||
|
||||
public string SongName => Info.Name;
|
||||
public string ArtistName => Info.Artist;
|
||||
public string FilePath => Info.FilePath;
|
||||
|
||||
private DownloadStatus _downloadStatus;
|
||||
|
||||
public DownloadStatus DownloadStatus
|
||||
{
|
||||
get => _downloadStatus;
|
||||
set => this.RaiseAndSetIfChanged(ref _downloadStatus, value);
|
||||
}
|
||||
}
|
||||
|
||||
public enum DownloadStatus
|
||||
{
|
||||
NotStarted = 1,
|
||||
Completed,
|
||||
Failed
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
using ReactiveUI.Fody.Helpers;
|
||||
using ZonyLrcTools.Common.Configuration;
|
||||
|
||||
namespace ZonyLrcTools.Desktop.ViewModels.Settings;
|
||||
|
||||
public class BlockWordViewModel : ViewModelBase
|
||||
{
|
||||
public BlockWordViewModel(GlobalOptions options)
|
||||
{
|
||||
IsEnable = options.Provider.Tag.BlockWord.IsEnable;
|
||||
FilePath = options.Provider.Tag.BlockWord.FilePath;
|
||||
|
||||
SubscribeToProperty(this, x => x.IsEnable, x => options.Provider.Tag.BlockWord.IsEnable = x);
|
||||
SubscribeToProperty(this, x => x.FilePath, x => options.Provider.Tag.BlockWord.FilePath = x!);
|
||||
}
|
||||
|
||||
[Reactive] public bool IsEnable { get; set; }
|
||||
|
||||
[Reactive] public string? FilePath { get; set; }
|
||||
}
|
@ -1,75 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using ReactiveUI;
|
||||
using ReactiveUI.Fody.Helpers;
|
||||
using ZonyLrcTools.Common.Configuration;
|
||||
|
||||
namespace ZonyLrcTools.Desktop.ViewModels.Settings;
|
||||
|
||||
public class GlobalConfigurationViewModel : ViewModelBase
|
||||
{
|
||||
public GlobalConfigurationViewModel(GlobalOptions config)
|
||||
{
|
||||
var globalConfig = config.Provider.Lyric.Config;
|
||||
|
||||
InitializeLineBreakComboBoxItem(globalConfig);
|
||||
|
||||
IsOneLine = globalConfig.IsOneLine;
|
||||
IsEnableTranslation = globalConfig.IsEnableTranslation;
|
||||
IsSkipExistLyricFiles = globalConfig.IsSkipExistLyricFiles;
|
||||
IsOnlyOutputTranslation = globalConfig.IsOnlyOutputTranslation;
|
||||
|
||||
SubscribeToProperty(this, x => x.IsOneLine, x => globalConfig.IsOneLine = x);
|
||||
SubscribeToProperty(this, x => x.IsEnableTranslation, x => globalConfig.IsEnableTranslation = x);
|
||||
SubscribeToProperty(this, x => x.IsSkipExistLyricFiles, x => globalConfig.IsSkipExistLyricFiles = x);
|
||||
SubscribeToProperty(this, x => x.IsOnlyOutputTranslation, x => globalConfig.IsOnlyOutputTranslation = x);
|
||||
}
|
||||
|
||||
[Reactive] public bool IsOneLine { get; set; }
|
||||
|
||||
[Reactive] public bool IsEnableTranslation { get; set; }
|
||||
|
||||
[Reactive] public bool IsSkipExistLyricFiles { get; set; }
|
||||
|
||||
[Reactive] public bool IsOnlyOutputTranslation { get; set; }
|
||||
|
||||
private void InitializeLineBreakComboBoxItem(GlobalLyricsConfigOptions config)
|
||||
{
|
||||
LineBreakOptions =
|
||||
[
|
||||
new TextComboboxItem { Name = "Windows", Value = "\r\n" },
|
||||
new TextComboboxItem { Name = "Unix", Value = "\n" },
|
||||
new TextComboboxItem { Name = "Mac", Value = "\r" }
|
||||
];
|
||||
SelectedLineBreak = LineBreakOptions.FirstOrDefault(x => x.Value == config.LineBreak)
|
||||
?? LineBreakOptions.First();
|
||||
|
||||
FileEncodingOptions = Encoding.GetEncodings()
|
||||
.Select(x => new TextComboboxItem { Name = x.DisplayName, Value = x.Name })
|
||||
.ToList();
|
||||
FileEncodingOptions.Insert(0, new TextComboboxItem { Name = "UTF-8-BOM", Value = "utf-8-bom" });
|
||||
SelectedFileEncoding = FileEncodingOptions.FirstOrDefault(x => x.Value == config.FileEncoding)
|
||||
?? FileEncodingOptions.First();
|
||||
|
||||
this.WhenAnyValue(x => x.SelectedLineBreak)
|
||||
.Subscribe(x => config.LineBreak = x.Value);
|
||||
this.WhenAnyValue(x => x.SelectedFileEncoding)
|
||||
.Subscribe(x => config.FileEncoding = x.Value);
|
||||
}
|
||||
|
||||
public List<TextComboboxItem> LineBreakOptions { get; private set; }
|
||||
|
||||
[Reactive] public TextComboboxItem SelectedLineBreak { get; set; }
|
||||
|
||||
public List<TextComboboxItem> FileEncodingOptions { get; private set; }
|
||||
|
||||
[Reactive] public TextComboboxItem SelectedFileEncoding { get; set; }
|
||||
|
||||
public class TextComboboxItem
|
||||
{
|
||||
public string Name { get; set; } = default!;
|
||||
public string Value { get; set; } = default!;
|
||||
}
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using Avalonia.Data;
|
||||
using Avalonia.Data.Converters;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
using ReactiveUI.Fody.Helpers;
|
||||
using ZonyLrcTools.Common.Configuration;
|
||||
|
||||
namespace ZonyLrcTools.Desktop.ViewModels.Settings;
|
||||
|
||||
public class LyricsProviderViewModel : ViewModelBase
|
||||
{
|
||||
public LyricsProviderViewModel(LyricsProviderOptions options)
|
||||
{
|
||||
var globalOptions = App.Current.Services.GetRequiredService<IOptions<GlobalOptions>>().Value;
|
||||
|
||||
Name = options.Name;
|
||||
Priority = options.Priority;
|
||||
Depth = options.Depth;
|
||||
|
||||
SubscribeToProperty(this, x => x.Priority, x => globalOptions.Provider.Lyric.GetLyricProviderOption(Name).Priority = x);
|
||||
SubscribeToProperty(this, x => x.Depth, x => globalOptions.Provider.Lyric.GetLyricProviderOption(Name).Depth = x);
|
||||
}
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
[Reactive] public int Priority { get; set; }
|
||||
|
||||
[Reactive] public int Depth { get; set; }
|
||||
}
|
||||
|
||||
internal class NullToDefaultValueConverter : IValueConverter
|
||||
{
|
||||
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
{
|
||||
return value != null ? System.Convert.ToDecimal(value) : 0;
|
||||
}
|
||||
|
||||
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is decimal dValue)
|
||||
{
|
||||
return System.Convert.ToInt32(dValue);
|
||||
}
|
||||
|
||||
return BindingOperations.DoNothing;
|
||||
}
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Reactive;
|
||||
using System.Threading.Tasks;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Platform.Storage;
|
||||
using ReactiveUI;
|
||||
using ZonyLrcTools.Common.Configuration;
|
||||
|
||||
namespace ZonyLrcTools.Desktop.ViewModels.Settings;
|
||||
|
||||
public class SettingsViewModel : ViewModelBase
|
||||
{
|
||||
public SettingsViewModel(GlobalOptions globalOptions)
|
||||
{
|
||||
Config = new GlobalConfigurationViewModel(globalOptions);
|
||||
LyricsProviders = new ObservableCollection<LyricsProviderViewModel>(globalOptions.Provider.Lyric.Plugin.Select(p => new LyricsProviderViewModel(p)));
|
||||
Tag = new TagInfoViewModel(globalOptions);
|
||||
BrowseBlockWordFileCommand = ReactiveCommand.CreateFromTask<Window>(BrowseBlockWordFile);
|
||||
}
|
||||
|
||||
public static string Version => typeof(Program).Assembly.GetName().Version!.ToString();
|
||||
|
||||
public TagInfoViewModel Tag { get; }
|
||||
|
||||
public ReactiveCommand<Window, Unit> BrowseBlockWordFileCommand { get; }
|
||||
|
||||
public GlobalConfigurationViewModel Config { get; }
|
||||
|
||||
public ObservableCollection<LyricsProviderViewModel> LyricsProviders { get; }
|
||||
|
||||
private async Task BrowseBlockWordFile(Window parentWindow)
|
||||
{
|
||||
var storage = parentWindow.StorageProvider;
|
||||
if (storage.CanOpen)
|
||||
{
|
||||
var options = new FilePickerOpenOptions
|
||||
{
|
||||
AllowMultiple = false,
|
||||
FileTypeFilter = new[]
|
||||
{
|
||||
new FilePickerFileType("JSON")
|
||||
{
|
||||
Patterns = new[] { "*.json" }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var files = await storage.OpenFilePickerAsync(options);
|
||||
if (files.Count > 0)
|
||||
{
|
||||
Tag.BlockWord.FilePath = files[0].Path.LocalPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
using ReactiveUI.Fody.Helpers;
|
||||
using ZonyLrcTools.Common.Configuration;
|
||||
|
||||
namespace ZonyLrcTools.Desktop.ViewModels.Settings;
|
||||
|
||||
public class TagInfoProviderViewModel : ViewModelBase
|
||||
{
|
||||
public TagInfoProviderViewModel(TagInfoProviderOptions options)
|
||||
{
|
||||
var globalOptions = App.Current.Services.GetRequiredService<IOptions<GlobalOptions>>().Value;
|
||||
|
||||
Name = options.Name;
|
||||
Priority = options.Priority;
|
||||
Extensions = options.Extensions == null ? [] : new ObservableCollection<ObservableKeyValuePair>(options.Extensions.Select(x => new ObservableKeyValuePair(x.Key, x.Value)));
|
||||
|
||||
SubscribeToProperty(this, x => x.Priority, x => globalOptions.Provider.Tag.GetTagProviderOption(Name).Priority = x);
|
||||
SubscribeToProperty(this, x => x.Extensions, x => globalOptions.Provider.Tag.GetTagProviderOption(Name).Extensions = x.ToDictionary(pair => pair.Key, pair => pair.Value));
|
||||
}
|
||||
|
||||
public string? Name { get; set; }
|
||||
|
||||
[Reactive] public int Priority { get; set; }
|
||||
|
||||
[Reactive] public ObservableCollection<ObservableKeyValuePair> Extensions { get; set; }
|
||||
}
|
||||
|
||||
public class ObservableKeyValuePair : ViewModelBase
|
||||
{
|
||||
[Reactive] public string Key { get; set; }
|
||||
|
||||
[Reactive] public string Value { get; set; }
|
||||
|
||||
public ObservableKeyValuePair(string key, string value)
|
||||
{
|
||||
Key = key;
|
||||
Value = value;
|
||||
}
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using ZonyLrcTools.Common.Configuration;
|
||||
|
||||
namespace ZonyLrcTools.Desktop.ViewModels.Settings;
|
||||
|
||||
public class TagInfoViewModel : ViewModelBase
|
||||
{
|
||||
public TagInfoViewModel(GlobalOptions options)
|
||||
{
|
||||
BlockWord = new BlockWordViewModel(options);
|
||||
TagInfoProviders = new ObservableCollection<TagInfoProviderViewModel>(options.Provider.Tag.Plugin.Select(p => new TagInfoProviderViewModel(p)));
|
||||
}
|
||||
|
||||
public BlockWordViewModel BlockWord { get; }
|
||||
|
||||
public ObservableCollection<TagInfoProviderViewModel> TagInfoProviders { get; }
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
using System;
|
||||
using System.Linq.Expressions;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace ZonyLrcTools.Desktop.ViewModels;
|
||||
|
||||
public abstract class ViewModelBase : ReactiveObject
|
||||
{
|
||||
protected void SubscribeToProperty<TSender, TRet>(TSender sender, Expression<Func<TSender, TRet>> property, Action<TRet> updateGlobalConfigAction)
|
||||
{
|
||||
sender.WhenAnyValue(property)
|
||||
.Subscribe(x =>
|
||||
{
|
||||
updateGlobalConfigAction(x);
|
||||
App.Current.UpdateConfiguration();
|
||||
});
|
||||
}
|
||||
}
|
@ -1,74 +0,0 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:ui="using:FluentAvalonia.UI.Controls"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:fluent="clr-namespace:FluentIcons.Avalonia.Fluent;assembly=FluentIcons.Avalonia.Fluent"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="ZonyLrcTools.Desktop.Views.MainView">
|
||||
<Grid RowDefinitions="Auto,*">
|
||||
<Grid Name="TitleBarHost"
|
||||
Background="Transparent"
|
||||
ColumnDefinitions="Auto,Auto,*,Auto,0">
|
||||
<Grid.Styles>
|
||||
<Style Selector="Button.AppBarButton">
|
||||
<Setter Property="Padding" Value="8" />
|
||||
<Setter Property="BorderThickness" Value="0" />
|
||||
<Setter Property="Theme" Value="{StaticResource TransparentButton}" />
|
||||
</Style>
|
||||
</Grid.Styles>
|
||||
|
||||
<Image Width="20" Height="20" Margin="14"
|
||||
Source="/Assets/logo.ico" IsHitTestVisible="False"
|
||||
IsVisible="{Binding !#FrameView.CanGoBack}"
|
||||
RenderOptions.BitmapInterpolationMode="HighQuality" />
|
||||
|
||||
<Button Grid.Column="0" Margin="6"
|
||||
Classes="AppBarButton" Command="{Binding #FrameView.GoBack}"
|
||||
IsEnabled="{Binding #FrameView.CanGoBack}"
|
||||
IsVisible="{Binding #FrameView.CanGoBack}">
|
||||
<Button.Content>
|
||||
<fluent:SymbolIcon Symbol="ArrowLeft" />
|
||||
</Button.Content>
|
||||
<ToolTip.Tip>Back</ToolTip.Tip>
|
||||
</Button>
|
||||
|
||||
<TextBlock Grid.Column="1"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="12"
|
||||
Text="ZonyLrcToolsX" IsHitTestVisible="False" />
|
||||
|
||||
<StackPanel Grid.Column="3"
|
||||
Orientation="Horizontal" Margin="6" Spacing="6">
|
||||
<Button Name="OpenFolderButton" Classes="AppBarButton">
|
||||
<Button.Content>
|
||||
<fluent:SymbolIcon Symbol="FolderAdd" />
|
||||
</Button.Content>
|
||||
<ToolTip.Tip>扫描文件夹</ToolTip.Tip>
|
||||
</Button>
|
||||
|
||||
<Button Name="DownloadButton" Classes="AppBarButton">
|
||||
<Button.Content>
|
||||
<fluent:SymbolIcon Symbol="ArrowDownload" />
|
||||
</Button.Content>
|
||||
<ToolTip.Tip>下载歌词</ToolTip.Tip>
|
||||
</Button>
|
||||
|
||||
<Button Name="SettingsButton" Classes="AppBarButton">
|
||||
<Button.Content>
|
||||
<fluent:SymbolIcon Symbol="Settings" />
|
||||
</Button.Content>
|
||||
<ToolTip.Tip>软件设置</ToolTip.Tip>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<Border Grid.Row="1" Grid.ColumnSpan="3"
|
||||
Background="{DynamicResource LayerFillColorDefaultBrush}"
|
||||
BorderBrush="{DynamicResource CardStrokeColorDefaultBrush}"
|
||||
BorderThickness="0,1,0,0"
|
||||
CornerRadius="8 8 0 0">
|
||||
<ui:Frame Name="FrameView" />
|
||||
</Border>
|
||||
</Grid>
|
||||
</UserControl>
|
@ -1,102 +0,0 @@
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
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.Common.Lyrics;
|
||||
using ZonyLrcTools.Desktop.Pages;
|
||||
using ZonyLrcTools.Desktop.ViewModels;
|
||||
|
||||
namespace ZonyLrcTools.Desktop.Views;
|
||||
|
||||
public partial class MainView : UserControl
|
||||
{
|
||||
private Window? _window;
|
||||
|
||||
private Frame? _frameView;
|
||||
private Button? _settingsButton;
|
||||
private Button? _openFolderButton;
|
||||
private Button? _downloadButton;
|
||||
|
||||
public MainView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
|
||||
{
|
||||
base.OnAttachedToVisualTree(e);
|
||||
|
||||
_window = e.Root as Window;
|
||||
|
||||
_frameView = this.FindControl<Frame>("FrameView");
|
||||
_frameView?.Navigate(typeof(HomePage));
|
||||
|
||||
_settingsButton = this.FindControl<Button>("SettingsButton");
|
||||
if (_settingsButton != null) _settingsButton.Click += OnSettingsButtonClick;
|
||||
|
||||
_openFolderButton = this.FindControl<Button>("OpenFolderButton");
|
||||
if (_openFolderButton != null) _openFolderButton.Click += OnOpenFolderButtonClick;
|
||||
_downloadButton = this.FindControl<Button>("DownloadButton");
|
||||
if (_downloadButton != null) _downloadButton.Click += OnDownloadButtonClick;
|
||||
}
|
||||
|
||||
private async void OnDownloadButtonClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
var downloader = App.Current.Services.GetRequiredService<ILyricsDownloader>();
|
||||
if (DataContext is HomeViewModel vm)
|
||||
{
|
||||
var needDownloadMusicInfos = vm.Songs
|
||||
.Where(x => x.DownloadStatus == DownloadStatus.NotStarted)
|
||||
.Select(x => x.Info)
|
||||
.ToList();
|
||||
|
||||
vm.DownloadProgress = 0;
|
||||
vm.MaxProgress = needDownloadMusicInfos.Count;
|
||||
|
||||
await downloader.DownloadAsync(needDownloadMusicInfos, callback: info =>
|
||||
{
|
||||
var song = vm.Songs.FirstOrDefault(x => x.Info == info);
|
||||
if (song != null)
|
||||
{
|
||||
song.DownloadStatus = DownloadStatus.Completed;
|
||||
}
|
||||
|
||||
vm.DownloadProgress++;
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private async void OnOpenFolderButtonClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
var storage = _window?.StorageProvider;
|
||||
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);
|
||||
if (folders.Count == 0) return;
|
||||
var folderPath = folders[0].Path.LocalPath;
|
||||
var musicInfos = await musicInfoLoader.LoadAsync(folderPath);
|
||||
|
||||
vm.Songs.Clear();
|
||||
vm.Songs.AddRange(musicInfos.Select(x => new SongInfoViewModel(x!)));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSettingsButtonClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_frameView?.CurrentSourcePageType != typeof(SettingsPage))
|
||||
_frameView?.Navigate(typeof(SettingsPage));
|
||||
}
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
<Window xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:views="clr-namespace:ZonyLrcTools.Desktop.Views"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="ZonyLrcTools.Desktop.Views.MainWindow"
|
||||
Background="{DynamicResource AcrylicBackgroundFillColorDefaultBrush}"
|
||||
Icon="/Assets/avalonia-logo.ico"
|
||||
Title="ZonyLrcTools.Desktop">
|
||||
|
||||
<Panel>
|
||||
<views:MainView />
|
||||
</Panel>
|
||||
|
||||
</Window>
|
@ -1,13 +0,0 @@
|
||||
using Avalonia.Controls;
|
||||
using ZonyLrcTools.Desktop.ViewModels;
|
||||
|
||||
namespace ZonyLrcTools.Desktop.Views;
|
||||
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
public MainWindow()
|
||||
{
|
||||
DataContext = new HomeViewModel();
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
|
||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<AvaloniaResource Include="Assets\**"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Avalonia"/>
|
||||
<PackageReference Include="Avalonia.Desktop"/>
|
||||
<PackageReference Include="Avalonia.Themes.Fluent"/>
|
||||
<PackageReference Include="Avalonia.Fonts.Inter"/>
|
||||
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
|
||||
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics"/>
|
||||
<PackageReference Include="Avalonia.ReactiveUI"/>
|
||||
<PackageReference Include="FluentAvaloniaUI" />
|
||||
<PackageReference Include="FluentIcons.Avalonia.Fluent" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting"/>
|
||||
<PackageReference Include="ReactiveUI.Fody" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ZonyLrcTools.Common\ZonyLrcTools.Common.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="config.yaml"/>
|
||||
<Content Include="config.yaml">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -1,18 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<!-- This manifest is used on Windows only.
|
||||
Don't remove it as it might cause problems with window transparency and embeded controls.
|
||||
For more details visit https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests -->
|
||||
<assemblyIdentity version="1.0.0.0" name="ZonyLrcTools.Desktop.Desktop"/>
|
||||
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<!-- A list of the Windows versions that this application has been tested on
|
||||
and is designed to work with. Uncomment the appropriate elements
|
||||
and Windows will automatically select the most compatible environment. -->
|
||||
|
||||
<!-- Windows 10 -->
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
|
||||
</application>
|
||||
</compatibility>
|
||||
</assembly>
|
@ -1,61 +0,0 @@
|
||||
# 允许扫描的歌曲文件后缀名。
|
||||
supportFileExtensions:
|
||||
- '*.mp3'
|
||||
- '*.flac'
|
||||
- '*.wav'
|
||||
- '*.m4a'
|
||||
- '*.ogg'
|
||||
- '*.opus'
|
||||
|
||||
# 网络代理服务设置,仅支持 HTTP 代理。
|
||||
networkOptions:
|
||||
isEnable: false # 是否启用代理。
|
||||
ip: 127.0.0.1 # 代理服务 IP 地址。
|
||||
port: 4780 # 代理服务端口号。
|
||||
updateUrl: https://api.myzony.com/lrc-tools/update # 更新检查地址。
|
||||
|
||||
# 下载器的相关参数配置。
|
||||
provider:
|
||||
# 标签扫描器的相关参数配置。
|
||||
tag:
|
||||
# 支持的标签扫描器。
|
||||
plugin:
|
||||
- name: Taglib # 基于 Taglib 库的标签扫描器。
|
||||
priority: 1 # 优先级,升序排列。
|
||||
- name: FileName # 基于文件名的标签扫描器。
|
||||
priority: 2
|
||||
# 基于文件名扫描器的扩展参数。
|
||||
extensions:
|
||||
# 正则表达式,用于匹配文件名中的作者信息和歌曲信息,可根据
|
||||
# 自己的需求进行调整。
|
||||
regularExpressions: "(?'artist'.+)\\s-\\s(?'name'.+)"
|
||||
# 歌曲标签屏蔽字典替换功能。
|
||||
blockWord:
|
||||
isEnable: false # 是否启用屏蔽字典。
|
||||
filePath: 'BlockWords.json' # 屏蔽字典的路径。
|
||||
# 歌词下载器的相关参数配置。
|
||||
lyric:
|
||||
# 支持的歌词下载器。
|
||||
plugin:
|
||||
- name: NetEase # 基于网易云音乐的歌词下载器。
|
||||
priority: 1 # 优先级,升序排列,改为 -1 时禁用。
|
||||
depth: 10 # 搜索深度,值越大搜索结果越多,但搜索时间越长。
|
||||
additional:
|
||||
isEnableRomanOutput: false # 是否启用罗马音输出,本参数仅当对应歌曲有罗马音歌词时有效。
|
||||
- name: QQ # 基于 QQ 音乐的歌词下载器。
|
||||
priority: 2
|
||||
# depth: 10 # 暂时不支持。
|
||||
- name: KuGou # 基于酷狗音乐的歌词下载器。
|
||||
priority: 3
|
||||
depth: 10
|
||||
- name: KuWo # 基于酷我音乐的歌词下载器。
|
||||
priority: 4
|
||||
depth: 10
|
||||
# 歌词下载的一些共有配置参数。
|
||||
config:
|
||||
isOneLine: true # 双语歌词是否合并为一行展示。
|
||||
lineBreak: "\n" # 换行符的类型,记得使用双引号指定。
|
||||
isEnableTranslation: true # 是否启用翻译歌词。
|
||||
isOnlyOutputTranslation: false # 是否只输出翻译歌词。
|
||||
isSkipExistLyricFiles: false # 如果歌词文件已经存在,是否跳过这些文件。
|
||||
fileEncoding: 'utf-8' # 歌词文件的编码格式。
|
Loading…
x
Reference in New Issue
Block a user