mirror of
https://github.com/jayfunc/BetterLyrics.git
synced 2026-01-13 03:34:55 +08:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e194dfaa70 | ||
|
|
bfc877f924 | ||
|
|
af55446004 | ||
|
|
faf8acf669 | ||
|
|
5b79a54117 | ||
|
|
4ef55f6ece | ||
|
|
0593f9aa3f | ||
|
|
b09a6494ff |
@@ -12,7 +12,7 @@
|
||||
<Identity
|
||||
Name="37412.BetterLyrics"
|
||||
Publisher="CN=E1428B0E-DC1D-4EA4-ACB1-4556569D5BA9"
|
||||
Version="1.0.45.0" />
|
||||
Version="1.0.48.0" />
|
||||
|
||||
<mp:PhoneIdentity PhoneProductId="ca4a4830-fc19-40d9-b823-53e2bff3d816" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
|
||||
|
||||
|
||||
@@ -297,6 +297,17 @@
|
||||
<Setter Property="Padding" Value="0" />
|
||||
</Style>
|
||||
|
||||
<Style
|
||||
x:Key="SettingsScrollViewerStyle"
|
||||
BasedOn="{StaticResource DefaultScrollViewerStyle}"
|
||||
TargetType="ScrollViewer">
|
||||
<Setter Property="Padding" Value="36,0" />
|
||||
</Style>
|
||||
|
||||
<Style x:Key="SettingsGridStyle" TargetType="Grid">
|
||||
<Setter Property="Padding" Value="0,0,0,36" />
|
||||
</Style>
|
||||
|
||||
<StaticResource x:Key="ToggleButtonBackgroundChecked" ResourceKey="TextFillColorPrimaryBrush" />
|
||||
<StaticResource x:Key="ToggleButtonBackgroundCheckedPointerOver" ResourceKey="TextFillColorPrimaryBrush" />
|
||||
<StaticResource x:Key="ToggleButtonBackgroundCheckedPressed" ResourceKey="TextFillColorPrimaryBrush" />
|
||||
|
||||
@@ -12,7 +12,6 @@ using BetterLyrics.WinUI3.Services.SettingsService;
|
||||
using BetterLyrics.WinUI3.Services.TranslateService;
|
||||
using BetterLyrics.WinUI3.ViewModels;
|
||||
using BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel;
|
||||
using BetterLyrics.WinUI3.ViewModels.SettingsPageViewModel;
|
||||
using BetterLyrics.WinUI3.Views;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
@@ -118,6 +117,12 @@ namespace BetterLyrics.WinUI3
|
||||
.AddSingleton<ITranslateService, TranslateService>()
|
||||
.AddSingleton<ILastFMService, LastFMService>()
|
||||
// ViewModels
|
||||
.AddSingleton<AppSettingsControlViewModel>()
|
||||
.AddSingleton<LyricsBackgroundSettingsControlViewModel>()
|
||||
.AddSingleton<AlbumArtLayoutSettingsControlViewModel>()
|
||||
.AddSingleton<PlaybackSettingsControlViewModel>()
|
||||
.AddSingleton<MediaSettingsControlViewModel>()
|
||||
.AddSingleton<AllLyricsSettingsControlViewModel>()
|
||||
.AddSingleton<LyricsWindowViewModel>()
|
||||
.AddSingleton<SettingsWindowViewModel>()
|
||||
.AddSingleton<SystemTrayViewModel>()
|
||||
|
||||
@@ -22,6 +22,14 @@
|
||||
<ItemGroup>
|
||||
<None Remove="Assets\Segoe Fluent Icons.ttf" />
|
||||
<None Remove="Assets\Wiki82.profile.xml" />
|
||||
<None Remove="Controls\AlbumArtLayoutSettingsControl.xaml" />
|
||||
<None Remove="Controls\AllLyricsSettingsControl.xaml" />
|
||||
<None Remove="Controls\AppSettingsControl.xaml" />
|
||||
<None Remove="Controls\ExtendedSlider.xaml" />
|
||||
<None Remove="Controls\LyricsBavkgroundSettingsControl.xaml" />
|
||||
<None Remove="Controls\LyricsSettingsControl.xaml" />
|
||||
<None Remove="Controls\MediaSettingsControl.xaml" />
|
||||
<None Remove="Controls\PlaybackSettingsControl.xaml" />
|
||||
<None Remove="Controls\SystemTray.xaml" />
|
||||
<None Remove="Views\MusicGalleryPage.xaml" />
|
||||
<None Remove="Views\MusicGalleryWindow.xaml" />
|
||||
@@ -177,6 +185,46 @@
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\ExtendedSlider.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\AllLyricsSettingsControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\LyricsSettingsControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\MediaSettingsControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\PlaybackSettingsControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\AlbumArtLayoutSettingsControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\LyricsBavkgroundSettingsControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\AppSettingsControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Views\MusicGalleryWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
|
||||
@@ -5,5 +5,6 @@ namespace BetterLyrics.WinUI3.Constants
|
||||
public const string ApiKey = "Your api key here";
|
||||
public const string SharedSecret = "Your shared secret here";
|
||||
public const string UnAuthUrl = "https://www.last.fm/settings/applications";
|
||||
public const string SessionKeyCredentialKey = "LastFMSessionKey";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<UserControl
|
||||
x:Class="BetterLyrics.WinUI3.Controls.AlbumArtLayoutSettingsControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:CommunityToolkit.WinUI.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:BetterLyrics.WinUI3.Controls"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid>
|
||||
<ScrollViewer Style="{StaticResource SettingsScrollViewerStyle}">
|
||||
<Grid Style="{StaticResource SettingsGridStyle}">
|
||||
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
|
||||
|
||||
<TextBlock x:Uid="SettingsPageAlbumArt" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageAlbumRadius" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<local:ExtendedSlider
|
||||
Default="12"
|
||||
Frequency="1"
|
||||
Maximum="100"
|
||||
Minimum="0"
|
||||
Unit="%"
|
||||
Value="{x:Bind ViewModel.AppSettings.AlbumArtLayoutSettings.CoverImageRadius, Mode=TwoWay}" />
|
||||
</controls:SettingsCard>
|
||||
|
||||
<TextBlock x:Uid="SettingsPageSongInfo" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageSongInfoAlignment" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ComboBox SelectedIndex="{x:Bind ViewModel.AppSettings.AlbumArtLayoutSettings.SongInfoAlignmentType, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||
<ComboBoxItem x:Uid="SettingsPageSongInfoLeft" />
|
||||
<ComboBoxItem x:Uid="SettingsPageSongInfoCenter" />
|
||||
<ComboBoxItem x:Uid="SettingsPageSongInfoRight" />
|
||||
</ComboBox>
|
||||
</controls:SettingsCard>
|
||||
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,32 @@
|
||||
using BetterLyrics.WinUI3.ViewModels;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Controls.Primitives;
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
using Microsoft.UI.Xaml.Input;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
using Windows.Foundation;
|
||||
using Windows.Foundation.Collections;
|
||||
|
||||
// To learn more about WinUI, the WinUI project structure,
|
||||
// and more about our project templates, see: http://aka.ms/winui-project-info.
|
||||
|
||||
namespace BetterLyrics.WinUI3.Controls
|
||||
{
|
||||
public sealed partial class AlbumArtLayoutSettingsControl : UserControl
|
||||
{
|
||||
public AlbumArtLayoutSettingsControlViewModel ViewModel => (AlbumArtLayoutSettingsControlViewModel)DataContext;
|
||||
public AlbumArtLayoutSettingsControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContext = Ioc.Default.GetRequiredService<AlbumArtLayoutSettingsControlViewModel>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<UserControl
|
||||
x:Class="BetterLyrics.WinUI3.Controls.AllLyricsSettingsControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:CommunityToolkit.WinUI.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:BetterLyrics.WinUI3.Controls"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:uc="using:BetterLyrics.WinUI3.Controls"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid>
|
||||
<controls:SwitchPresenter Margin="0,72,0,0" Value="{Binding SelectedItem.Tag, ElementName=LyricsSettingsSegmentedControl}">
|
||||
<controls:Case Value="Standard">
|
||||
<uc:LyricsSettingsControl LyricsEffectSettings="{x:Bind ViewModel.AppSettings.StandardLyricsEffectSettings, Mode=OneWay}" LyricsStyleSettings="{x:Bind ViewModel.AppSettings.StandardLyricsStyleSettings, Mode=OneWay}" />
|
||||
</controls:Case>
|
||||
<controls:Case Value="Desktop">
|
||||
<uc:LyricsSettingsControl LyricsEffectSettings="{x:Bind ViewModel.AppSettings.DesktopLyricsEffectSettings, Mode=OneWay}" LyricsStyleSettings="{x:Bind ViewModel.AppSettings.DesktopLyricsStyleSettings, Mode=OneWay}" />
|
||||
</controls:Case>
|
||||
<controls:Case Value="Dock">
|
||||
<uc:LyricsSettingsControl LyricsEffectSettings="{x:Bind ViewModel.AppSettings.DockLyricsEffectSettings, Mode=OneWay}" LyricsStyleSettings="{x:Bind ViewModel.AppSettings.DockLyricsStyleSettings, Mode=OneWay}" />
|
||||
</controls:Case>
|
||||
</controls:SwitchPresenter>
|
||||
<controls:Segmented
|
||||
x:Name="LyricsSettingsSegmentedControl"
|
||||
Margin="36,36,36,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Top"
|
||||
SelectedIndex="0">
|
||||
<controls:SegmentedItem x:Uid="AllLyricsSettingsControlStandard" Tag="Standard" />
|
||||
<controls:SegmentedItem x:Uid="AllLyricsSettingsControlDesktop" Tag="Desktop" />
|
||||
<controls:SegmentedItem x:Uid="AllLyricsSettingsControlDock" Tag="Dock" />
|
||||
</controls:Segmented>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,32 @@
|
||||
using BetterLyrics.WinUI3.ViewModels;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Controls.Primitives;
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
using Microsoft.UI.Xaml.Input;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
using Windows.Foundation;
|
||||
using Windows.Foundation.Collections;
|
||||
|
||||
// To learn more about WinUI, the WinUI project structure,
|
||||
// and more about our project templates, see: http://aka.ms/winui-project-info.
|
||||
|
||||
namespace BetterLyrics.WinUI3.Controls
|
||||
{
|
||||
public sealed partial class AllLyricsSettingsControl : UserControl
|
||||
{
|
||||
public AllLyricsSettingsControlViewModel ViewModel => (AllLyricsSettingsControlViewModel)DataContext;
|
||||
public AllLyricsSettingsControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContext = Ioc.Default.GetRequiredService<AllLyricsSettingsControlViewModel>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<UserControl
|
||||
x:Class="BetterLyrics.WinUI3.Controls.AppSettingsControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:CommunityToolkit.WinUI.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:BetterLyrics.WinUI3.Controls"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid>
|
||||
<ScrollViewer Style="{StaticResource SettingsScrollViewerStyle}">
|
||||
<Grid Style="{StaticResource SettingsGridStyle}">
|
||||
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
|
||||
|
||||
<!-- App appearance -->
|
||||
|
||||
<TextBlock x:Uid="SettingsPageAppAppearance" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
|
||||
<controls:SettingsExpander
|
||||
x:Uid="SettingsPageLanguage"
|
||||
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}"
|
||||
IsExpanded="True">
|
||||
<ComboBox SelectedIndex="{x:Bind ViewModel.AppSettings.GeneralSettings.Language, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||
<ComboBoxItem x:Uid="SettingsPageSystemLanguage" />
|
||||
<ComboBoxItem x:Uid="SettingsPageEN" />
|
||||
<ComboBoxItem x:Uid="SettingsPageSC" />
|
||||
<ComboBoxItem x:Uid="SettingsPageTC" />
|
||||
<ComboBoxItem x:Uid="SettingsPageJA" />
|
||||
<ComboBoxItem x:Uid="SettingsPageKO" />
|
||||
</ComboBox>
|
||||
<controls:SettingsExpander.Items>
|
||||
<controls:SettingsCard>
|
||||
<Button x:Uid="SettingsPageRestart" Command="{x:Bind ViewModel.RestartAppCommand}" />
|
||||
</controls:SettingsCard>
|
||||
</controls:SettingsExpander.Items>
|
||||
</controls:SettingsExpander>
|
||||
|
||||
<!-- App behavior -->
|
||||
|
||||
<TextBlock x:Uid="SettingsPageAppBehavior" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageAutoStart" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ToggleSwitch
|
||||
x:Name="AutoStartupToggleSwitch"
|
||||
Loaded="AutoStartupToggleSwitch_Loaded"
|
||||
Unloaded="AutoStartupToggleSwitch_Unloaded" />
|
||||
</controls:SettingsCard>
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageAutoStartWindow" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ComboBox SelectedIndex="{x:Bind ViewModel.AppSettings.GeneralSettings.AutoStartWindowType, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||
<ComboBoxItem x:Uid="SettingsPageAutoStartInAppLyrics" />
|
||||
<ComboBoxItem x:Uid="SettingsPageAutoStartDockLyrics" />
|
||||
<ComboBoxItem x:Uid="SettingsPageAutoStartDesktopLyrics" />
|
||||
</ComboBox>
|
||||
</controls:SettingsCard>
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageIgnoreFullscreenWindow" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.GeneralSettings.IgnoreFullscreenWindow, Mode=TwoWay}" />
|
||||
</controls:SettingsCard>
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageHideWindow" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.GeneralSettings.HideWindowWhenNotPlaying, Mode=TwoWay}" />
|
||||
</controls:SettingsCard>
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageGlobalDrag" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.GeneralSettings.IsDragEverywhereEnabled, Mode=TwoWay}" />
|
||||
</controls:SettingsCard>
|
||||
|
||||
<!-- Desktop mode -->
|
||||
|
||||
<TextBlock x:Uid="SettingsPageAppDesktop" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageAutoLock" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.DesktopModeSettings.AutoLockOnDesktopMode, Mode=TwoWay}" />
|
||||
</controls:SettingsCard>
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageLockHotKey" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<TextBlock
|
||||
Margin="0,0,0,2"
|
||||
VerticalAlignment="Center"
|
||||
Text="Ctrl + Alt + " />
|
||||
<ComboBox SelectedIndex="{x:Bind ViewModel.AppSettings.DesktopModeSettings.LockHotKeyIndex, Mode=TwoWay}">
|
||||
<ComboBoxItem Content="A" />
|
||||
<ComboBoxItem Content="B" />
|
||||
<ComboBoxItem Content="C" />
|
||||
<ComboBoxItem Content="D" />
|
||||
<ComboBoxItem Content="E" />
|
||||
<ComboBoxItem Content="F" />
|
||||
<ComboBoxItem Content="G" />
|
||||
<ComboBoxItem Content="H" />
|
||||
<ComboBoxItem Content="I" />
|
||||
<ComboBoxItem Content="J" />
|
||||
<ComboBoxItem Content="K" />
|
||||
<ComboBoxItem Content="L" />
|
||||
<ComboBoxItem Content="M" />
|
||||
<ComboBoxItem Content="N" />
|
||||
<ComboBoxItem Content="O" />
|
||||
<ComboBoxItem Content="P" />
|
||||
<ComboBoxItem Content="Q" />
|
||||
<ComboBoxItem Content="R" />
|
||||
<ComboBoxItem Content="S" />
|
||||
<ComboBoxItem Content="T" />
|
||||
<ComboBoxItem Content="U" />
|
||||
<ComboBoxItem Content="V" />
|
||||
<ComboBoxItem Content="W" />
|
||||
<ComboBoxItem Content="X" />
|
||||
<ComboBoxItem Content="Y" />
|
||||
<ComboBoxItem Content="Z" />
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
</controls:SettingsCard>
|
||||
|
||||
<!-- Dock mode -->
|
||||
|
||||
<TextBlock x:Uid="SettingsPageAppDock" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageDockMonitor" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<ComboBox ItemsSource="{x:Bind ViewModel.MonitorDeviceNames, Mode=OneWay}" SelectedItem="{x:Bind ViewModel.AppSettings.DockModeSettings.DockMonitorDeviceName, Mode=TwoWay}" />
|
||||
<Button
|
||||
Command="{x:Bind ViewModel.RefreshMonitorDeviceNamesCommand}"
|
||||
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
FontSize=12,
|
||||
Glyph=}"
|
||||
Style="{StaticResource GhostButtonStyle}" />
|
||||
</StackPanel>
|
||||
</controls:SettingsCard>
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageDockWindowHeight" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<local:ExtendedSlider
|
||||
Default="64"
|
||||
Frequency="1"
|
||||
Maximum="200"
|
||||
Minimum="64"
|
||||
Unit="px"
|
||||
Value="{x:Bind ViewModel.AppSettings.DockModeSettings.DockWindowHeight, Mode=TwoWay}" />
|
||||
</controls:SettingsCard>
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageDockPlacement" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ComboBox SelectedIndex="{x:Bind ViewModel.AppSettings.DockModeSettings.DockPlacement, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||
<ComboBoxItem x:Uid="SettingsPageDockPlacementTop" />
|
||||
<ComboBoxItem x:Uid="SettingsPageDockPlacementBottom" />
|
||||
</ComboBox>
|
||||
</controls:SettingsCard>
|
||||
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,50 @@
|
||||
using BetterLyrics.WinUI3.Models.Settings;
|
||||
using BetterLyrics.WinUI3.ViewModels;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Controls.Primitives;
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
using Microsoft.UI.Xaml.Input;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
using Windows.Foundation;
|
||||
using Windows.Foundation.Collections;
|
||||
|
||||
// To learn more about WinUI, the WinUI project structure,
|
||||
// and more about our project templates, see: http://aka.ms/winui-project-info.
|
||||
|
||||
namespace BetterLyrics.WinUI3.Controls
|
||||
{
|
||||
public sealed partial class AppSettingsControl : UserControl
|
||||
{
|
||||
public AppSettingsControlViewModel ViewModel => (AppSettingsControlViewModel)DataContext;
|
||||
|
||||
public AppSettingsControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContext = Ioc.Default.GetRequiredService<AppSettingsControlViewModel>();
|
||||
}
|
||||
|
||||
private async void AutoStartupToggleSwitch_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
AutoStartupToggleSwitch.IsOn = await ViewModel.DetectIsAutoStartupEnabledAsync();
|
||||
AutoStartupToggleSwitch.Toggled += AutoStartupToggleSwitch_Toggled;
|
||||
}
|
||||
|
||||
private void AutoStartupToggleSwitch_Toggled(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ViewModel.ToggleAutoStartupAsync(AutoStartupToggleSwitch.IsOn);
|
||||
}
|
||||
|
||||
private void AutoStartupToggleSwitch_Unloaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
AutoStartupToggleSwitch.Toggled -= AutoStartupToggleSwitch_Toggled;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<UserControl
|
||||
x:Class="BetterLyrics.WinUI3.Controls.ExtendedSlider"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:BetterLyrics.WinUI3.Controls"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock
|
||||
Margin="6,0,2,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Bind Value, Mode=OneWay}" />
|
||||
<TextBlock
|
||||
Margin="0,0,14,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Bind Unit, Mode=OneWay}" />
|
||||
<Slider
|
||||
Maximum="{x:Bind Maximum, Mode=OneWay}"
|
||||
Minimum="{x:Bind Minimum, Mode=OneWay}"
|
||||
SnapsTo="Ticks"
|
||||
StepFrequency="{x:Bind Frequency, Mode=OneWay}"
|
||||
TickFrequency="{x:Bind Frequency, Mode=OneWay}"
|
||||
TickPlacement="Outside"
|
||||
Value="{x:Bind Value, Mode=TwoWay}" />
|
||||
<Button
|
||||
Margin="3,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
Click="ResetButton_Click"
|
||||
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
FontSize=12,
|
||||
Glyph=}"
|
||||
Style="{StaticResource GhostButtonStyle}"
|
||||
Visibility="{x:Bind ResetButtonVisibility, Mode=OneWay}" />
|
||||
<Button
|
||||
x:Name="SubtractButton"
|
||||
Margin="3,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
Click="SubtractButton_Click"
|
||||
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
FontSize=12,
|
||||
Glyph=}"
|
||||
Style="{StaticResource GhostButtonStyle}" />
|
||||
<Button
|
||||
x:Name="AddButton"
|
||||
Margin="3,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
Click="AddButton_Click"
|
||||
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
FontSize=12,
|
||||
Glyph=}"
|
||||
Style="{StaticResource GhostButtonStyle}" />
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,129 @@
|
||||
using Microsoft.UI.Input;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Controls.Primitives;
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
using Microsoft.UI.Xaml.Input;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
using Windows.Foundation;
|
||||
using Windows.Foundation.Collections;
|
||||
|
||||
// To learn more about WinUI, the WinUI project structure,
|
||||
// and more about our project templates, see: http://aka.ms/winui-project-info.
|
||||
|
||||
namespace BetterLyrics.WinUI3.Controls
|
||||
{
|
||||
public sealed partial class ExtendedSlider : UserControl
|
||||
{
|
||||
public ExtendedSlider()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void Subtract()
|
||||
{
|
||||
if (Value - Frequency < Minimum)
|
||||
{
|
||||
Value = Minimum;
|
||||
}
|
||||
else
|
||||
{
|
||||
Value -= Frequency;
|
||||
}
|
||||
}
|
||||
|
||||
private void Add()
|
||||
{
|
||||
if (Value + Frequency > Maximum)
|
||||
{
|
||||
Value = Maximum;
|
||||
}
|
||||
else
|
||||
{
|
||||
Value += Frequency;
|
||||
}
|
||||
}
|
||||
|
||||
private void SubtractTimer_Tick(object? sender, object e)
|
||||
{
|
||||
Subtract();
|
||||
}
|
||||
|
||||
private void AddTimer_Tick(object? sender, object e)
|
||||
{
|
||||
Add();
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty FrequencyProperty =
|
||||
DependencyProperty.Register(nameof(Frequency), typeof(double), typeof(ExtendedSlider), new PropertyMetadata(default));
|
||||
public static readonly DependencyProperty MinimumProperty =
|
||||
DependencyProperty.Register(nameof(Minimum), typeof(double), typeof(ExtendedSlider), new PropertyMetadata(default));
|
||||
public static readonly DependencyProperty MaximumProperty =
|
||||
DependencyProperty.Register(nameof(Maximum), typeof(double), typeof(ExtendedSlider), new PropertyMetadata(default));
|
||||
public static readonly DependencyProperty ValueProperty =
|
||||
DependencyProperty.Register(nameof(Value), typeof(double), typeof(ExtendedSlider), new PropertyMetadata(default));
|
||||
public static readonly DependencyProperty DefaultProperty =
|
||||
DependencyProperty.Register(nameof(Default), typeof(double), typeof(ExtendedSlider), new PropertyMetadata(default));
|
||||
public static readonly DependencyProperty ResetButtonVisibilityProperty =
|
||||
DependencyProperty.Register(nameof(ResetButtonVisibility), typeof(Visibility), typeof(ExtendedSlider), new PropertyMetadata(Visibility.Visible));
|
||||
public static readonly DependencyProperty UnitProperty =
|
||||
DependencyProperty.Register(nameof(Unit), typeof(string), typeof(ExtendedSlider), new PropertyMetadata(""));
|
||||
|
||||
public double Frequency
|
||||
{
|
||||
get => (double)GetValue(FrequencyProperty);
|
||||
set => SetValue(FrequencyProperty, value);
|
||||
}
|
||||
public double Minimum
|
||||
{
|
||||
get => (double)GetValue(MinimumProperty);
|
||||
set => SetValue(MinimumProperty, value);
|
||||
}
|
||||
public double Maximum
|
||||
{
|
||||
get => (double)GetValue(MaximumProperty);
|
||||
set => SetValue(MaximumProperty, value);
|
||||
}
|
||||
public double Value
|
||||
{
|
||||
get => (double)GetValue(ValueProperty);
|
||||
set => SetValue(ValueProperty, value);
|
||||
}
|
||||
public double Default
|
||||
{
|
||||
get => (double)GetValue(DefaultProperty);
|
||||
set => SetValue(DefaultProperty, value);
|
||||
}
|
||||
public Visibility ResetButtonVisibility
|
||||
{
|
||||
get => (Visibility)GetValue(ResetButtonVisibilityProperty);
|
||||
set => SetValue(ResetButtonVisibilityProperty, value);
|
||||
}
|
||||
public string Unit
|
||||
{
|
||||
get => (string)GetValue(UnitProperty);
|
||||
set => SetValue(UnitProperty, value);
|
||||
}
|
||||
|
||||
private void ResetButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Value = Default;
|
||||
}
|
||||
|
||||
private void SubtractButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Subtract();
|
||||
}
|
||||
|
||||
private void AddButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Add();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<UserControl
|
||||
x:Class="BetterLyrics.WinUI3.Controls.LyricsBavkgroundSettingsControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:CommunityToolkit.WinUI.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:uc="using:BetterLyrics.WinUI3.Controls"
|
||||
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid>
|
||||
<ScrollViewer Style="{StaticResource SettingsScrollViewerStyle}">
|
||||
<Grid Style="{StaticResource SettingsGridStyle}">
|
||||
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
|
||||
|
||||
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageTheme" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ComboBox x:Name="ThemeComboBox" SelectedIndex="{x:Bind ViewModel.AppSettings.LyricsBackgroundSettings.LyricsBackgroundTheme, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||
<ComboBoxItem x:Uid="SettingsPageFollowSystem" />
|
||||
<ComboBoxItem x:Uid="SettingsPageLight" />
|
||||
<ComboBoxItem x:Uid="SettingsPageDark" />
|
||||
</ComboBox>
|
||||
</controls:SettingsCard>
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageLyricsPureColorBgOpacity" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<uc:ExtendedSlider
|
||||
Default="100"
|
||||
Frequency="1"
|
||||
Maximum="100"
|
||||
Minimum="0"
|
||||
Unit="%"
|
||||
Value="{x:Bind ViewModel.AppSettings.LyricsBackgroundSettings.PureColorOverlayOpacity, Mode=TwoWay}" />
|
||||
</controls:SettingsCard>
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageLyricsBackgroundOpacity" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<uc:ExtendedSlider
|
||||
Default="100"
|
||||
Frequency="1"
|
||||
Maximum="100"
|
||||
Minimum="0"
|
||||
Unit="%"
|
||||
Value="{x:Bind ViewModel.AppSettings.LyricsBackgroundSettings.CoverOverlayOpacity, Mode=TwoWay}" />
|
||||
</controls:SettingsCard>
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageLyricsBackgroundSpeed" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<uc:ExtendedSlider
|
||||
Default="50"
|
||||
Frequency="1"
|
||||
Maximum="100"
|
||||
Minimum="0"
|
||||
Unit="%"
|
||||
Value="{x:Bind ViewModel.AppSettings.LyricsBackgroundSettings.CoverOverlaySpeed, Mode=TwoWay}" />
|
||||
</controls:SettingsCard>
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageLyricsBackgroundBlurAmount" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<uc:ExtendedSlider
|
||||
Default="100"
|
||||
Frequency="1"
|
||||
Maximum="100"
|
||||
Minimum="0"
|
||||
Value="{x:Bind ViewModel.AppSettings.LyricsBackgroundSettings.CoverOverlayBlurAmount, Mode=TwoWay}" />
|
||||
</controls:SettingsCard>
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageBackgroundAcrylicEffectAmount" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<uc:ExtendedSlider
|
||||
Default="0"
|
||||
Frequency="1"
|
||||
Maximum="10"
|
||||
Minimum="0"
|
||||
Value="{x:Bind ViewModel.AppSettings.LyricsBackgroundSettings.CoverAcrylicEffectAmount, Mode=TwoWay}" />
|
||||
</controls:SettingsCard>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,33 @@
|
||||
using BetterLyrics.WinUI3.ViewModels;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Controls.Primitives;
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
using Microsoft.UI.Xaml.Input;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
using Windows.Foundation;
|
||||
using Windows.Foundation.Collections;
|
||||
|
||||
// To learn more about WinUI, the WinUI project structure,
|
||||
// and more about our project templates, see: http://aka.ms/winui-project-info.
|
||||
|
||||
namespace BetterLyrics.WinUI3.Controls
|
||||
{
|
||||
public sealed partial class LyricsBavkgroundSettingsControl : UserControl
|
||||
{
|
||||
public LyricsBackgroundSettingsControlViewModel ViewModel => (LyricsBackgroundSettingsControlViewModel)DataContext;
|
||||
|
||||
public LyricsBavkgroundSettingsControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContext = Ioc.Default.GetRequiredService<LyricsBackgroundSettingsControlViewModel>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,323 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<UserControl
|
||||
x:Class="BetterLyrics.WinUI3.Controls.LyricsSettingsControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:CommunityToolkit.WinUI.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
|
||||
xmlns:local="using:BetterLyrics.WinUI3.Controls"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid>
|
||||
<ScrollViewer Style="{StaticResource SettingsScrollViewerStyle}">
|
||||
<Grid Style="{StaticResource SettingsGridStyle}">
|
||||
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
|
||||
|
||||
<!-- Lyrics style -->
|
||||
|
||||
<TextBlock x:Uid="SettingsPageLyricsStyle" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageLyricsAlignment" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ComboBox SelectedIndex="{x:Bind LyricsStyleSettings.LyricsAlignmentType, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsLeft" />
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsCenter" />
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsRight" />
|
||||
</ComboBox>
|
||||
</controls:SettingsCard>
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageLyricsFontFamily" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ComboBox ItemsSource="{x:Bind SystemFontNames, Mode=OneWay}" SelectedItem="{x:Bind LyricsStyleSettings.LyricsFontFamily, Mode=TwoWay}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
</controls:SettingsCard>
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageLyricsFontWeight" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ComboBox SelectedIndex="{x:Bind LyricsStyleSettings.LyricsFontWeight, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsThin" />
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsExtraLight" />
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsLight" />
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsSemiLight" />
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsNormal" />
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsMedium" />
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsSemiBold" />
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsBold" />
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsExtraBold" />
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsBlack" />
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsExtraBlack" />
|
||||
</ComboBox>
|
||||
</controls:SettingsCard>
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageLyricsBgFontOpacity" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<local:ExtendedSlider
|
||||
Default="30"
|
||||
Frequency="1"
|
||||
Maximum="100"
|
||||
Minimum="0"
|
||||
Unit="%"
|
||||
Value="{x:Bind LyricsStyleSettings.LyricsBgFontOpacity, Mode=TwoWay}" />
|
||||
</controls:SettingsCard>
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageLyricsFontStrokeWidth" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<local:ExtendedSlider
|
||||
Default="0"
|
||||
Frequency="1"
|
||||
Maximum="5"
|
||||
Minimum="0"
|
||||
Value="{x:Bind LyricsStyleSettings.LyricsFontStrokeWidth, Mode=TwoWay}" />
|
||||
</controls:SettingsCard>
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageLyricsStrokeFontColor" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ComboBox SelectedIndex="{x:Bind LyricsStyleSettings.LyricsStrokeFontColorType, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsFontColorAdaptiveColored" />
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsFontColorAdaptiveGrayed" />
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsFontColorCustom" />
|
||||
</ComboBox>
|
||||
</controls:SettingsCard>
|
||||
|
||||
<ColorPicker
|
||||
ColorSpectrumShape="Box"
|
||||
IsAlphaEnabled="True"
|
||||
IsAlphaSliderVisible="True"
|
||||
IsAlphaTextInputVisible="True"
|
||||
IsColorChannelTextInputVisible="True"
|
||||
IsColorSliderVisible="True"
|
||||
IsHexInputVisible="True"
|
||||
IsMoreButtonVisible="True"
|
||||
Color="{x:Bind LyricsStyleSettings.LyricsCustomStrokeFontColor, Mode=TwoWay}">
|
||||
<interactivity:Interaction.Behaviors>
|
||||
<interactivity:DataTriggerBehavior
|
||||
Binding="{x:Bind LyricsStyleSettings.LyricsStrokeFontColorType, Mode=OneWay, Converter={StaticResource EnumToIntConverter}}"
|
||||
ComparisonCondition="Equal"
|
||||
Value="2">
|
||||
<interactivity:ChangePropertyAction PropertyName="Visibility" Value="Visible" />
|
||||
</interactivity:DataTriggerBehavior>
|
||||
<interactivity:DataTriggerBehavior
|
||||
Binding="{x:Bind LyricsStyleSettings.LyricsStrokeFontColorType, Mode=OneWay, Converter={StaticResource EnumToIntConverter}}"
|
||||
ComparisonCondition="NotEqual"
|
||||
Value="2">
|
||||
<interactivity:ChangePropertyAction PropertyName="Visibility" Value="Collapsed" />
|
||||
</interactivity:DataTriggerBehavior>
|
||||
</interactivity:Interaction.Behaviors>
|
||||
</ColorPicker>
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageLyricsBgFontColor" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ComboBox SelectedIndex="{x:Bind LyricsStyleSettings.LyricsBgFontColorType, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsFontColorAdaptiveColored" />
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsFontColorAdaptiveGrayed" />
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsFontColorCustom" />
|
||||
</ComboBox>
|
||||
</controls:SettingsCard>
|
||||
|
||||
<ColorPicker
|
||||
ColorSpectrumShape="Box"
|
||||
IsAlphaEnabled="True"
|
||||
IsAlphaSliderVisible="True"
|
||||
IsAlphaTextInputVisible="True"
|
||||
IsColorChannelTextInputVisible="True"
|
||||
IsColorSliderVisible="True"
|
||||
IsHexInputVisible="True"
|
||||
IsMoreButtonVisible="True"
|
||||
Color="{x:Bind LyricsStyleSettings.LyricsCustomBgFontColor, Mode=TwoWay}">
|
||||
<interactivity:Interaction.Behaviors>
|
||||
<interactivity:DataTriggerBehavior
|
||||
Binding="{x:Bind LyricsStyleSettings.LyricsBgFontColorType, Mode=OneWay, Converter={StaticResource EnumToIntConverter}}"
|
||||
ComparisonCondition="Equal"
|
||||
Value="2">
|
||||
<interactivity:ChangePropertyAction PropertyName="Visibility" Value="Visible" />
|
||||
</interactivity:DataTriggerBehavior>
|
||||
<interactivity:DataTriggerBehavior
|
||||
Binding="{x:Bind LyricsStyleSettings.LyricsBgFontColorType, Mode=OneWay, Converter={StaticResource EnumToIntConverter}}"
|
||||
ComparisonCondition="NotEqual"
|
||||
Value="2">
|
||||
<interactivity:ChangePropertyAction PropertyName="Visibility" Value="Collapsed" />
|
||||
</interactivity:DataTriggerBehavior>
|
||||
</interactivity:Interaction.Behaviors>
|
||||
</ColorPicker>
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageLyricsFgFontColor" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ComboBox SelectedIndex="{x:Bind LyricsStyleSettings.LyricsFgFontColorType, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsFontColorAdaptiveColored" />
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsFontColorAdaptiveGrayed" />
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsFontColorCustom" />
|
||||
</ComboBox>
|
||||
</controls:SettingsCard>
|
||||
|
||||
<ColorPicker
|
||||
ColorSpectrumShape="Box"
|
||||
IsAlphaEnabled="True"
|
||||
IsAlphaSliderVisible="True"
|
||||
IsAlphaTextInputVisible="True"
|
||||
IsColorChannelTextInputVisible="True"
|
||||
IsColorSliderVisible="True"
|
||||
IsHexInputVisible="True"
|
||||
IsMoreButtonVisible="True"
|
||||
Color="{x:Bind LyricsStyleSettings.LyricsCustomFgFontColor, Mode=TwoWay}">
|
||||
<interactivity:Interaction.Behaviors>
|
||||
<interactivity:DataTriggerBehavior
|
||||
Binding="{x:Bind LyricsStyleSettings.LyricsFgFontColorType, Mode=OneWay, Converter={StaticResource EnumToIntConverter}}"
|
||||
ComparisonCondition="Equal"
|
||||
Value="2">
|
||||
<interactivity:ChangePropertyAction PropertyName="Visibility" Value="Visible" />
|
||||
</interactivity:DataTriggerBehavior>
|
||||
<interactivity:DataTriggerBehavior
|
||||
Binding="{x:Bind LyricsStyleSettings.LyricsFgFontColorType, Mode=OneWay, Converter={StaticResource EnumToIntConverter}}"
|
||||
ComparisonCondition="NotEqual"
|
||||
Value="2">
|
||||
<interactivity:ChangePropertyAction PropertyName="Visibility" Value="Collapsed" />
|
||||
</interactivity:DataTriggerBehavior>
|
||||
</interactivity:Interaction.Behaviors>
|
||||
</ColorPicker>
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageLyricsFontSize" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<local:ExtendedSlider
|
||||
Frequency="2"
|
||||
Maximum="96"
|
||||
Minimum="12"
|
||||
ResetButtonVisibility="Collapsed"
|
||||
Value="{x:Bind LyricsStyleSettings.LyricsFontSize, Mode=TwoWay}" />
|
||||
</controls:SettingsCard>
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageLyricsLineSpacingFactor" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<local:ExtendedSlider
|
||||
x:Uid="SettingsPageLyricsLineSpacingFactorSlider"
|
||||
Default="0.5"
|
||||
Frequency="0.1"
|
||||
Maximum="2"
|
||||
Minimum="0"
|
||||
Unit="x"
|
||||
Value="{x:Bind LyricsStyleSettings.LyricsLineSpacingFactor, Mode=TwoWay}" />
|
||||
</controls:SettingsCard>
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageLyricsTranslationSeparator" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<TextBox AcceptsReturn="True" Text="{x:Bind LyricsStyleSettings.LyricsTranslationSeparator, Mode=TwoWay}" />
|
||||
<Button Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, FontSize=12, Glyph=}" Style="{StaticResource GhostButtonStyle}" />
|
||||
</StackPanel>
|
||||
</controls:SettingsCard>
|
||||
|
||||
<!-- Effect -->
|
||||
|
||||
<TextBlock
|
||||
x:Uid="SettingsPageLyricsEffect"
|
||||
Style="{StaticResource SettingsSectionHeaderTextBlockStyle}"
|
||||
Text="Effect" />
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageLyricsVerticalEdgeOpacity" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<local:ExtendedSlider
|
||||
x:Uid="SettingsPageLyricsVerticalEdgeOpacitySlider"
|
||||
Default="0"
|
||||
Frequency="1"
|
||||
Maximum="100"
|
||||
Minimum="0"
|
||||
Unit="%"
|
||||
Value="{x:Bind LyricsEffectSettings.LyricsVerticalEdgeOpacity, Mode=TwoWay}" />
|
||||
</controls:SettingsCard>
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageLyricsBlurAmount" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<local:ExtendedSlider
|
||||
x:Uid="SettingsPageLyricsBlurAmountExtendedSlider"
|
||||
Default="5"
|
||||
Frequency="1"
|
||||
Maximum="10"
|
||||
Minimum="0"
|
||||
Value="{x:Bind LyricsEffectSettings.LyricsBlurAmount, Mode=TwoWay}" />
|
||||
</controls:SettingsCard>
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageLyricsHighlightScope" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ComboBox SelectedIndex="{x:Bind LyricsEffectSettings.LyricsHighlightScope, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsRendingScopeCurrentChar" />
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsRendingScopeLineStartToCurrentChar" />
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsRendingScopeCurrentLine" />
|
||||
</ComboBox>
|
||||
</controls:SettingsCard>
|
||||
|
||||
<controls:SettingsExpander
|
||||
x:Uid="SettingsPageLyricsGlowEffect"
|
||||
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}"
|
||||
IsExpanded="{x:Bind LyricsEffectSettings.IsLyricsGlowEffectEnabled, Mode=OneWay}">
|
||||
<ToggleSwitch IsOn="{x:Bind LyricsEffectSettings.IsLyricsGlowEffectEnabled, Mode=TwoWay}" />
|
||||
<controls:SettingsExpander.Items>
|
||||
<controls:SettingsCard x:Uid="SettingsPageScope" IsEnabled="{x:Bind LyricsEffectSettings.IsLyricsGlowEffectEnabled, Mode=OneWay}">
|
||||
<ComboBox SelectedIndex="{x:Bind LyricsEffectSettings.LyricsGlowEffectScope, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsRendingScopeCurrentChar" />
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsRendingScopeLineStartToCurrentChar" />
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsRendingScopeCurrentLine" />
|
||||
</ComboBox>
|
||||
</controls:SettingsCard>
|
||||
</controls:SettingsExpander.Items>
|
||||
</controls:SettingsExpander>
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageLyricsFloatAnimation" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ToggleSwitch IsOn="{x:Bind LyricsEffectSettings.IsLyricsFloatAnimationEnabled, Mode=TwoWay}" />
|
||||
</controls:SettingsCard>
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageFan" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ToggleSwitch IsOn="{x:Bind LyricsEffectSettings.IsFanLyricsEnabled, Mode=TwoWay}" />
|
||||
</controls:SettingsCard>
|
||||
|
||||
<controls:SettingsExpander
|
||||
x:Uid="SettingsPageScrollEasing"
|
||||
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}"
|
||||
IsExpanded="True">
|
||||
<ComboBox SelectedIndex="{x:Bind LyricsEffectSettings.LyricsScrollEasingType, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||
<ComboBoxItem x:Uid="SettingsPageEasingTypeLinear" />
|
||||
<ComboBoxItem x:Uid="SettingsPageEasingTypeSmoothStep" />
|
||||
<ComboBoxItem x:Uid="SettingsPageEasingTypeEaseInOutSine" />
|
||||
<ComboBoxItem x:Uid="SettingsPageEasingTypeEaseInOutQuad" />
|
||||
<ComboBoxItem x:Uid="SettingsPageEasingTypeEaseInOutCubic" />
|
||||
<ComboBoxItem x:Uid="SettingsPageEasingTypeEaseInOutQuart" />
|
||||
<ComboBoxItem x:Uid="SettingsPageEasingTypeEaseInOutQuint" />
|
||||
<ComboBoxItem x:Uid="SettingsPageEasingTypeEaseInOutExpo" />
|
||||
<ComboBoxItem x:Uid="SettingsPageEasingTypeEaseInOutCirc" />
|
||||
<ComboBoxItem x:Uid="SettingsPageEasingTypeEaseInOutBack" />
|
||||
<ComboBoxItem x:Uid="SettingsPageEasingTypeEaseInOutElastic" />
|
||||
<ComboBoxItem x:Uid="SettingsPageEasingTypeEaseInOutBounce" />
|
||||
</ComboBox>
|
||||
<controls:SettingsExpander.Items>
|
||||
<controls:SettingsCard x:Uid="SettingsPageScrollTopDuration">
|
||||
<local:ExtendedSlider
|
||||
x:Uid="SettingsPageLyricsScrollTopDurationExtendedSlider"
|
||||
Default="500"
|
||||
Frequency="50"
|
||||
Maximum="1000"
|
||||
Minimum="50"
|
||||
Unit="ms"
|
||||
Value="{x:Bind LyricsEffectSettings.LyricsScrollTopDuration, Mode=TwoWay}" />
|
||||
</controls:SettingsCard>
|
||||
<controls:SettingsCard x:Uid="SettingsPageScrollDuration">
|
||||
<local:ExtendedSlider
|
||||
x:Uid="SettingsPageLyricsScrollDurationExtendedSlider"
|
||||
Default="500"
|
||||
Frequency="50"
|
||||
Maximum="1000"
|
||||
Minimum="50"
|
||||
Unit="ms"
|
||||
Value="{x:Bind LyricsEffectSettings.LyricsScrollDuration, Mode=TwoWay}" />
|
||||
</controls:SettingsCard>
|
||||
<controls:SettingsCard x:Uid="SettingsPageScrollBottomDuration">
|
||||
<local:ExtendedSlider
|
||||
x:Uid="SettingsPageLyricsScrollBottomDurationExtendedSlider"
|
||||
Default="500"
|
||||
Frequency="50"
|
||||
Maximum="1000"
|
||||
Minimum="50"
|
||||
Unit="ms"
|
||||
Value="{x:Bind LyricsEffectSettings.LyricsScrollBottomDuration, Mode=TwoWay}" />
|
||||
</controls:SettingsCard>
|
||||
</controls:SettingsExpander.Items>
|
||||
</controls:SettingsExpander>
|
||||
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,53 @@
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using BetterLyrics.WinUI3.Models.Settings;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Controls.Primitives;
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
using Microsoft.UI.Xaml.Input;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
using Windows.Foundation;
|
||||
using Windows.Foundation.Collections;
|
||||
|
||||
// To learn more about WinUI, the WinUI project structure,
|
||||
// and more about our project templates, see: http://aka.ms/winui-project-info.
|
||||
|
||||
namespace BetterLyrics.WinUI3.Controls
|
||||
{
|
||||
public sealed partial class LyricsSettingsControl : UserControl
|
||||
{
|
||||
public ObservableCollection<string> SystemFontNames { get; set; } = [.. FontHelper.SystemFontFamilies];
|
||||
|
||||
public LyricsSettingsControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty LyricsStyleSettingsProperty =
|
||||
DependencyProperty.Register(nameof(LyricsStyleSettings), typeof(LyricsStyleSettings), typeof(LyricsSettingsControl), new PropertyMetadata(default));
|
||||
|
||||
public LyricsStyleSettings LyricsStyleSettings
|
||||
{
|
||||
get => (LyricsStyleSettings)GetValue(LyricsStyleSettingsProperty);
|
||||
set => SetValue(LyricsStyleSettingsProperty, value);
|
||||
}
|
||||
|
||||
|
||||
public static readonly DependencyProperty LyricsEffectSettingsProperty =
|
||||
DependencyProperty.Register(nameof(LyricsEffectSettings), typeof(LyricsEffectSettings), typeof(LyricsSettingsControl), new PropertyMetadata(default));
|
||||
|
||||
public LyricsEffectSettings LyricsEffectSettings
|
||||
{
|
||||
get => (LyricsEffectSettings)GetValue(LyricsEffectSettingsProperty);
|
||||
set => SetValue(LyricsEffectSettingsProperty, value);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<UserControl
|
||||
x:Class="BetterLyrics.WinUI3.Controls.MediaSettingsControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:CommunityToolkit.WinUI.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
|
||||
xmlns:local="using:BetterLyrics.WinUI3.Controls"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid>
|
||||
<ScrollViewer Style="{StaticResource SettingsScrollViewerStyle}">
|
||||
<Grid Style="{StaticResource SettingsGridStyle}">
|
||||
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
|
||||
|
||||
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
<controls:SettingsExpander
|
||||
x:Uid="SettingsPageMusicLib"
|
||||
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}"
|
||||
IsExpanded="True"
|
||||
ItemsSource="{x:Bind ViewModel.AppSettings.LocalMediaFolders, Mode=OneWay}">
|
||||
<controls:SettingsExpander.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<controls:SettingsCard>
|
||||
<controls:SettingsCard.Header>
|
||||
<HyperlinkButton
|
||||
Click="LocalFolderHyperlinkButton_Click"
|
||||
Content="{Binding Path, Mode=OneWay}"
|
||||
Tag="{Binding Path, Mode=OneWay}" />
|
||||
</controls:SettingsCard.Header>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<HyperlinkButton
|
||||
x:Uid="SettingsPageRemovePath"
|
||||
Click="SettingsPageRemovePathButton_Click"
|
||||
Tag="{Binding}" />
|
||||
<ToggleSwitch DataContext="{Binding}" IsOn="{Binding IsEnabled, Mode=TwoWay}" />
|
||||
</StackPanel>
|
||||
</controls:SettingsCard>
|
||||
</DataTemplate>
|
||||
</controls:SettingsExpander.ItemTemplate>
|
||||
<controls:SettingsExpander.ItemsHeader>
|
||||
<InfoBar
|
||||
x:Uid="SettingsPageRemoveInfo"
|
||||
BorderThickness="0"
|
||||
CornerRadius="0"
|
||||
IsClosable="False"
|
||||
IsOpen="True"
|
||||
Severity="Success">
|
||||
|
||||
<interactivity:Interaction.Behaviors>
|
||||
|
||||
<interactivity:DataTriggerBehavior
|
||||
Binding="{x:Bind ViewModel.AppSettings.LocalMediaFolders.Count, Mode=OneWay}"
|
||||
ComparisonCondition="Equal"
|
||||
Value="0">
|
||||
<interactivity:ChangePropertyAction PropertyName="Visibility" Value="Collapsed" />
|
||||
</interactivity:DataTriggerBehavior>
|
||||
<interactivity:DataTriggerBehavior
|
||||
Binding="{x:Bind ViewModel.AppSettings.LocalMediaFolders.Count, Mode=OneWay}"
|
||||
ComparisonCondition="NotEqual"
|
||||
Value="0">
|
||||
<interactivity:ChangePropertyAction PropertyName="Visibility" Value="Visible" />
|
||||
</interactivity:DataTriggerBehavior>
|
||||
|
||||
</interactivity:Interaction.Behaviors>
|
||||
|
||||
</InfoBar>
|
||||
</controls:SettingsExpander.ItemsHeader>
|
||||
<controls:SettingsExpander.ItemsFooter>
|
||||
<controls:SettingsCard x:Uid="SettingsPageAddFolder" Style="{StaticResource DefaultSettingsExpanderItemStyle}">
|
||||
<Button
|
||||
x:Uid="SettingsPageAddFolderButton"
|
||||
Command="{x:Bind ViewModel.SelectAndAddFolderCommand}"
|
||||
CommandParameter="{Binding ElementName=RootGrid}" />
|
||||
</controls:SettingsCard>
|
||||
</controls:SettingsExpander.ItemsFooter>
|
||||
</controls:SettingsExpander>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,50 @@
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.ViewModels;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Controls.Primitives;
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
using Microsoft.UI.Xaml.Input;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
using Windows.Foundation;
|
||||
using Windows.Foundation.Collections;
|
||||
using Windows.System;
|
||||
|
||||
// To learn more about WinUI, the WinUI project structure,
|
||||
// and more about our project templates, see: http://aka.ms/winui-project-info.
|
||||
|
||||
namespace BetterLyrics.WinUI3.Controls
|
||||
{
|
||||
public sealed partial class MediaSettingsControl : UserControl
|
||||
{
|
||||
public MediaSettingsControlViewModel ViewModel => (MediaSettingsControlViewModel)DataContext;
|
||||
public MediaSettingsControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContext = Ioc.Default.GetRequiredService<MediaSettingsControlViewModel>();
|
||||
}
|
||||
|
||||
private void SettingsPageRemovePathButton_Click(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
|
||||
{
|
||||
ViewModel.RemoveFolderAsync((LocalMediaFolder)(sender as HyperlinkButton)!.Tag);
|
||||
}
|
||||
|
||||
private async void LocalFolderHyperlinkButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is HyperlinkButton button && button.Tag is string uriStr)
|
||||
{
|
||||
if (Uri.TryCreate(uriStr, UriKind.Absolute, out var uri))
|
||||
{
|
||||
await Launcher.LaunchUriAsync(uri);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,320 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<UserControl
|
||||
x:Class="BetterLyrics.WinUI3.Controls.PlaybackSettingsControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:CommunityToolkit.WinUI.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
|
||||
xmlns:local="using:BetterLyrics.WinUI3.Controls"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:models="using:BetterLyrics.WinUI3.Models"
|
||||
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid ColumnSpacing="6">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid Grid.Column="0">
|
||||
<ScrollViewer Margin="0,72,0,0" Style="{StaticResource SettingsScrollViewerStyle}">
|
||||
<Grid Style="{StaticResource SettingsGridStyle}">
|
||||
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageMediaSourceProvidersConfig">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.SelectedMediaSourceProvider.IsEnabled, Mode=TwoWay}" />
|
||||
</controls:SettingsCard>
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageLastFMTrack" IsEnabled="{x:Bind ViewModel.IsLastFMAuthenticated, Mode=OneWay}">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.SelectedMediaSourceProvider.IsLastFMTrackEnabled, Mode=TwoWay}" />
|
||||
</controls:SettingsCard>
|
||||
|
||||
<!-- 时间轴相关配置 -->
|
||||
<controls:SettingsCard x:Uid="SettingsPageLyricsTimelineThreshold">
|
||||
<local:ExtendedSlider
|
||||
x:Uid="SettingsPageLyricsTimelineThresholdReset"
|
||||
Frequency="100"
|
||||
Maximum="1000"
|
||||
Minimum="0"
|
||||
ResetButtonVisibility="Collapsed"
|
||||
Unit="ms"
|
||||
Value="{x:Bind ViewModel.SelectedMediaSourceProvider.TimelineSyncThreshold, Mode=TwoWay}" />
|
||||
</controls:SettingsCard>
|
||||
<controls:SettingsExpander x:Uid="MainPagePositionOffsetSlider" IsExpanded="True">
|
||||
<local:ExtendedSlider
|
||||
x:Uid="SettingsPagePositionOffsetReset"
|
||||
Default="0"
|
||||
Frequency="100"
|
||||
Maximum="5000"
|
||||
Minimum="-5000"
|
||||
Unit="ms"
|
||||
Value="{x:Bind ViewModel.SelectedMediaSourceProvider.PositionOffset, Mode=TwoWay}" />
|
||||
<controls:SettingsExpander.Items>
|
||||
<controls:SettingsCard x:Uid="LyricsPagePositionOffsetHint">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.SelectedMediaSourceProvider.ResetPositionOffsetOnSongChanged, Mode=TwoWay}" />
|
||||
</controls:SettingsCard>
|
||||
</controls:SettingsExpander.Items>
|
||||
</controls:SettingsExpander>
|
||||
|
||||
<!-- 专辑封面源配置 -->
|
||||
<TextBlock x:Uid="SettingsPageAlbumArtSearchProvidersConfig" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
<ListView
|
||||
x:Name="AlbumArtSearchProvidersListView"
|
||||
AllowDrop="True"
|
||||
CanDragItems="True"
|
||||
CanReorderItems="True"
|
||||
DragItemsCompleted="AlbumArtSearchProvidersListView_DragItemsCompleted"
|
||||
ItemContainerStyle="{StaticResource ListViewStretchedItemContainerStyle}"
|
||||
ItemsSource="{x:Bind ViewModel.SelectedMediaSourceProvider.AlbumArtSearchProvidersInfo, Mode=OneWay}"
|
||||
SelectionMode="None">
|
||||
<ListView.OpacityTransition>
|
||||
<ScalarTransition />
|
||||
</ListView.OpacityTransition>
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate x:DataType="models:AlbumArtSearchProviderInfo">
|
||||
<controls:SettingsCard Header="{Binding Provider, Converter={StaticResource AlbumArtSearchProviderToDisplayNameConverter}, Mode=OneWay}">
|
||||
<controls:SettingsCard.HeaderIcon>
|
||||
<FontIcon FontFamily="Segoe UI Symbol" Glyph="⠿" />
|
||||
</controls:SettingsCard.HeaderIcon>
|
||||
<ToggleSwitch IsOn="{Binding IsEnabled, Mode=TwoWay}" />
|
||||
</controls:SettingsCard>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
|
||||
<!-- 歌词源配置 -->
|
||||
<TextBlock x:Uid="SettingsPageLyricsSearchProvidersConfig" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
<ListView
|
||||
x:Name="LyricsSearchProvidersListView"
|
||||
AllowDrop="True"
|
||||
CanDragItems="True"
|
||||
CanReorderItems="True"
|
||||
DragItemsCompleted="LyricsSearchProvidersListView_DragItemsCompleted"
|
||||
ItemsSource="{x:Bind ViewModel.SelectedMediaSourceProvider.LyricsSearchProvidersInfo, Mode=OneWay}"
|
||||
SelectionMode="None">
|
||||
<ListView.OpacityTransition>
|
||||
<ScalarTransition />
|
||||
</ListView.OpacityTransition>
|
||||
<ListView.ItemContainerStyle>
|
||||
<Style TargetType="ListViewItem">
|
||||
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
|
||||
<Setter Property="Margin" Value="0" />
|
||||
<Setter Property="Padding" Value="0" />
|
||||
</Style>
|
||||
</ListView.ItemContainerStyle>
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate x:DataType="models:LyricsSearchProviderInfo">
|
||||
<controls:SettingsCard Header="{Binding Provider, Converter={StaticResource LyricsSearchProviderToDisplayNameConverter}, Mode=OneWay}">
|
||||
<controls:SettingsCard.HeaderIcon>
|
||||
<FontIcon FontFamily="Segoe UI Symbol" Glyph="⠿" />
|
||||
</controls:SettingsCard.HeaderIcon>
|
||||
<ToggleSwitch IsOn="{Binding IsEnabled, Mode=TwoWay}" />
|
||||
</controls:SettingsCard>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
<ListView
|
||||
VerticalAlignment="Top"
|
||||
ItemsSource="{x:Bind ViewModel.AppSettings.MediaSourceProvidersInfo, Mode=OneWay}"
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Auto"
|
||||
ScrollViewer.HorizontalScrollMode="Enabled"
|
||||
ScrollViewer.VerticalScrollBarVisibility="Disabled"
|
||||
ScrollViewer.VerticalScrollMode="Disabled"
|
||||
SelectedItem="{x:Bind ViewModel.SelectedMediaSourceProvider, Mode=TwoWay}">
|
||||
<ListView.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<ItemsStackPanel Orientation="Horizontal" />
|
||||
</ItemsPanelTemplate>
|
||||
</ListView.ItemsPanel>
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate x:DataType="models:MediaSourceProviderInfo">
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<ImageIcon Height="16" Source="{Binding Provider, Converter={StaticResource MediaSourceProviderToLogoUriConverter}, Mode=OneWay}" />
|
||||
<TextBlock
|
||||
MaxWidth="200"
|
||||
Text="{Binding Provider, Converter={StaticResource MediaSourceProviderToDisplayedNameConverter}, Mode=OneWay}"
|
||||
TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
<interactivity:Interaction.Behaviors>
|
||||
<interactivity:DataTriggerBehavior
|
||||
Binding="{x:Bind ViewModel.AppSettings.MediaSourceProvidersInfo.Count, Mode=OneWay}"
|
||||
ComparisonCondition="NotEqual"
|
||||
Value="0">
|
||||
<interactivity:ChangePropertyAction PropertyName="Visibility" Value="Visible" />
|
||||
</interactivity:DataTriggerBehavior>
|
||||
<interactivity:DataTriggerBehavior
|
||||
Binding="{x:Bind ViewModel.AppSettings.MediaSourceProvidersInfo.Count, Mode=OneWay}"
|
||||
ComparisonCondition="Equal"
|
||||
Value="0">
|
||||
<interactivity:ChangePropertyAction PropertyName="Visibility" Value="Collapsed" />
|
||||
</interactivity:DataTriggerBehavior>
|
||||
</interactivity:Interaction.Behaviors>
|
||||
</Grid>
|
||||
<StackPanel
|
||||
Grid.Column="0"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Spacing="12">
|
||||
<interactivity:Interaction.Behaviors>
|
||||
<interactivity:DataTriggerBehavior
|
||||
Binding="{x:Bind ViewModel.AppSettings.MediaSourceProvidersInfo.Count, Mode=OneWay}"
|
||||
ComparisonCondition="Equal"
|
||||
Value="0">
|
||||
<interactivity:ChangePropertyAction PropertyName="Visibility" Value="Visible" />
|
||||
</interactivity:DataTriggerBehavior>
|
||||
<interactivity:DataTriggerBehavior
|
||||
Binding="{x:Bind ViewModel.AppSettings.MediaSourceProvidersInfo.Count, Mode=OneWay}"
|
||||
ComparisonCondition="NotEqual"
|
||||
Value="0">
|
||||
<interactivity:ChangePropertyAction PropertyName="Visibility" Value="Collapsed" />
|
||||
</interactivity:DataTriggerBehavior>
|
||||
</interactivity:Interaction.Behaviors>
|
||||
<Image MaxWidth="200" Source="/Assets/Leaf.png" />
|
||||
<TextBlock
|
||||
x:Uid="SettingsPagePlaybackNotFound"
|
||||
HorizontalAlignment="Center"
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}" />
|
||||
</StackPanel>
|
||||
<Grid Grid.Column="1">
|
||||
<ScrollViewer Style="{StaticResource SettingsScrollViewerStyle}">
|
||||
<Grid Style="{StaticResource SettingsGridStyle}">
|
||||
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
|
||||
<!-- Last.fm -->
|
||||
<TextBlock x:Uid="SettingsPageLastFM" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
<controls:SettingsExpander
|
||||
x:Uid="SettingsPageLastFMManager"
|
||||
HeaderIcon="{ui:BitmapIcon Source=ms-appx:///Assets/LastFM.png}"
|
||||
IsExpanded="{x:Bind ViewModel.IsLastFMAuthenticated, Mode=OneWay}">
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<Button
|
||||
x:Uid="SettingsPageLastFMAuth"
|
||||
Command="{x:Bind ViewModel.LastFMAuthCommand}"
|
||||
IsEnabled="{x:Bind ViewModel.IsLastFMAuthenticated, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}" />
|
||||
<Button
|
||||
x:Uid="SettingsPageLastFMUnAuth"
|
||||
Command="{x:Bind ViewModel.LastFMUnAuthCommand}"
|
||||
IsEnabled="{x:Bind ViewModel.IsLastFMAuthenticated, Mode=OneWay}" />
|
||||
</StackPanel>
|
||||
<controls:SettingsExpander.Items>
|
||||
<controls:SettingsCard x:Uid="SettingsPageLastFMUsername" IsEnabled="{x:Bind ViewModel.IsLastFMAuthenticated, Mode=OneWay}">
|
||||
<HyperlinkButton Content="{x:Bind ViewModel.LastFMUser.Name, Mode=OneWay}" NavigateUri="{x:Bind ViewModel.LastFMUser.Url, Mode=OneWay}" />
|
||||
</controls:SettingsCard>
|
||||
<controls:SettingsCard x:Uid="SettingsPageLastFMPlaycount" IsEnabled="{x:Bind ViewModel.IsLastFMAuthenticated, Mode=OneWay}">
|
||||
<TextBlock Text="{x:Bind ViewModel.LastFMUser.Playcount, Mode=OneWay}" />
|
||||
</controls:SettingsCard>
|
||||
<controls:SettingsCard x:Uid="SettingsPageLastFMRegistered" IsEnabled="{x:Bind ViewModel.IsLastFMAuthenticated, Mode=OneWay}">
|
||||
<TextBlock Text="{x:Bind ViewModel.LastFMUser.Registered.ToLongDateString(), Mode=OneWay}" />
|
||||
</controls:SettingsCard>
|
||||
<controls:SettingsCard IsEnabled="{x:Bind ViewModel.IsLastFMAuthenticated, Mode=OneWay}">
|
||||
<Button x:Uid="SettingsPageLastFMRefresh" Command="{x:Bind ViewModel.LastFMRefreshCommand}" />
|
||||
</controls:SettingsCard>
|
||||
</controls:SettingsExpander.Items>
|
||||
</controls:SettingsExpander>
|
||||
<!-- Lyrics translation -->
|
||||
<TextBlock x:Uid="SettingsPageTranslation" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
<controls:SettingsExpander
|
||||
x:Uid="LyricsPageTranslationEnabled"
|
||||
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}"
|
||||
IsExpanded="True">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.TranslationSettings.IsTranslationEnabled, Mode=TwoWay}" />
|
||||
<controls:SettingsExpander.Items>
|
||||
<controls:SettingsCard x:Uid="SettingsPageTargetLanguage">
|
||||
<ComboBox SelectedIndex="{x:Bind ViewModel.AppSettings.TranslationSettings.SelectedTargetLanguageIndex, Mode=TwoWay}">
|
||||
<ComboBoxItem Content="العربية" Tag="ar" />
|
||||
<ComboBoxItem Content="Azərbaycan dili" Tag="az" />
|
||||
<ComboBoxItem Content="简体中文" Tag="zh-Hans" />
|
||||
<ComboBoxItem Content="繁體中文" Tag="zh-Hant" />
|
||||
<ComboBoxItem Content="Čeština" Tag="cs" />
|
||||
<ComboBoxItem Content="Dansk" Tag="da" />
|
||||
<ComboBoxItem Content="Nederlands" Tag="nl" />
|
||||
<ComboBoxItem Content="English" Tag="en" />
|
||||
<ComboBoxItem Content="Esperanto" Tag="eo" />
|
||||
<ComboBoxItem Content="Suomi" Tag="fi" />
|
||||
<ComboBoxItem Content="Français" Tag="fr" />
|
||||
<ComboBoxItem Content="Deutsch" Tag="de" />
|
||||
<ComboBoxItem Content="Ελληνικά" Tag="el" />
|
||||
<ComboBoxItem Content="עברית" Tag="he" />
|
||||
<ComboBoxItem Content="हिन्दी" Tag="hi" />
|
||||
<ComboBoxItem Content="Magyar" Tag="hu" />
|
||||
<ComboBoxItem Content="Bahasa Indonesia" Tag="id" />
|
||||
<ComboBoxItem Content="Gaeilge" Tag="ga" />
|
||||
<ComboBoxItem Content="Italiano" Tag="it" />
|
||||
<ComboBoxItem Content="日本語" Tag="ja" />
|
||||
<ComboBoxItem Content="한국어" Tag="ko" />
|
||||
<ComboBoxItem Content="فارسی" Tag="fa" />
|
||||
<ComboBoxItem Content="Polski" Tag="pl" />
|
||||
<ComboBoxItem Content="Português" Tag="pt" />
|
||||
<ComboBoxItem Content="Русский" Tag="ru" />
|
||||
<ComboBoxItem Content="Slovenčina" Tag="sk" />
|
||||
<ComboBoxItem Content="Español" Tag="es" />
|
||||
<ComboBoxItem Content="Svenska" Tag="sv" />
|
||||
<ComboBoxItem Content="Türkçe" Tag="tr" />
|
||||
<ComboBoxItem Content="Українська" Tag="uk" />
|
||||
<ComboBoxItem Content="Tiếng Việt" Tag="vi" />
|
||||
</ComboBox>
|
||||
</controls:SettingsCard>
|
||||
<controls:SettingsCard x:Uid="SettingsPageTranslationConfig">
|
||||
<controls:SettingsCard.Description>
|
||||
<HyperlinkButton Margin="0,6,0,0" NavigateUri="https://github.com/LibreTranslate/LibreTranslate">
|
||||
<TextBlock
|
||||
x:Uid="SettingsPageTranslationInfoLink"
|
||||
FontSize="14"
|
||||
TextWrapping="Wrap" />
|
||||
</HyperlinkButton>
|
||||
</controls:SettingsCard.Description>
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.TranslationSettings.IsLibreTranslateEnabled, Mode=TwoWay}" />
|
||||
</controls:SettingsCard>
|
||||
<controls:SettingsCard x:Uid="SettingsPageLibreTranslateServer" IsEnabled="{x:Bind ViewModel.AppSettings.TranslationSettings.IsLibreTranslateEnabled, Mode=OneWay}">
|
||||
<StackPanel Orientation="Horizontal" Spacing="12">
|
||||
<TextBox
|
||||
x:Name="LibreTranslateServerTextBox"
|
||||
IsEnabled="{x:Bind ViewModel.IsLibreTranslateServerTesting, Converter={StaticResource BoolNegationConverter}, Mode=OneWay}"
|
||||
PlaceholderText="http://localhost:5000"
|
||||
Text="{x:Bind ViewModel.AppSettings.TranslationSettings.LibreTranslateServer, Mode=TwoWay}" />
|
||||
<Button
|
||||
x:Uid="SettingsPageServerTestButton"
|
||||
Command="{x:Bind ViewModel.LibreTranslateServerTestCommand}"
|
||||
IsEnabled="{x:Bind ViewModel.IsLibreTranslateServerTesting, Converter={StaticResource BoolNegationConverter}, Mode=OneWay}" />
|
||||
</StackPanel>
|
||||
</controls:SettingsCard>
|
||||
<controls:SettingsCard x:Uid="LyricsPageTranslationOnly" IsEnabled="{x:Bind ViewModel.AppSettings.TranslationSettings.IsTranslationEnabled, Mode=OneWay}">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.TranslationSettings.ShowTranslationOnly, Mode=TwoWay}" />
|
||||
</controls:SettingsCard>
|
||||
</controls:SettingsExpander.Items>
|
||||
</controls:SettingsExpander>
|
||||
<controls:SettingsCard x:Uid="LyricsPageLyricsProviderPrefix">
|
||||
<TextBlock Foreground="{ThemeResource TextFillColorSecondaryBrush}" Text="{x:Bind ViewModel.LyricsSearchProvider, Mode=OneWay, Converter={StaticResource LyricsSearchProviderToDisplayNameConverter}}" />
|
||||
</controls:SettingsCard>
|
||||
<controls:SettingsCard x:Uid="LyricsPageTranslationProviderPrefix">
|
||||
<TextBlock Foreground="{ThemeResource TextFillColorSecondaryBrush}" Text="{x:Bind ViewModel.TranslationSearchProvider, Mode=OneWay, Converter={StaticResource TranslationSearchProviderToDisplayNameConverter}}" />
|
||||
</controls:SettingsCard>
|
||||
<!-- LX music server -->
|
||||
<TextBlock x:Uid="SettingsPageLXMusicServer" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
<controls:SettingsCard>
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<TextBox
|
||||
IsEnabled="{x:Bind ViewModel.IsLXMusicServerTesting, Converter={StaticResource BoolNegationConverter}, Mode=OneWay}"
|
||||
PlaceholderText="http://127.0.0.1:23330"
|
||||
Text="{x:Bind ViewModel.AppSettings.GeneralSettings.LXMusicServer, Mode=TwoWay}" />
|
||||
<Button
|
||||
x:Uid="SettingsPageServerTestButton"
|
||||
Command="{x:Bind ViewModel.LXMusicServerTestCommand}"
|
||||
IsEnabled="{x:Bind ViewModel.IsLXMusicServerTesting, Converter={StaticResource BoolNegationConverter}, Mode=OneWay}" />
|
||||
</StackPanel>
|
||||
</controls:SettingsCard>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
</UserControl>
|
||||
@@ -0,0 +1,45 @@
|
||||
using BetterLyrics.WinUI3.ViewModels;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Controls.Primitives;
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
using Microsoft.UI.Xaml.Input;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
using Windows.Foundation;
|
||||
using Windows.Foundation.Collections;
|
||||
|
||||
// To learn more about WinUI, the WinUI project structure,
|
||||
// and more about our project templates, see: http://aka.ms/winui-project-info.
|
||||
|
||||
namespace BetterLyrics.WinUI3.Controls
|
||||
{
|
||||
public sealed partial class PlaybackSettingsControl : UserControl
|
||||
{
|
||||
public PlaybackSettingsControlViewModel ViewModel => (PlaybackSettingsControlViewModel)DataContext;
|
||||
|
||||
public PlaybackSettingsControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContext = Ioc.Default.GetRequiredService<PlaybackSettingsControlViewModel>();
|
||||
}
|
||||
|
||||
private void AlbumArtSearchProvidersListView_DragItemsCompleted(ListViewBase sender, DragItemsCompletedEventArgs args)
|
||||
{
|
||||
// <20><> AlbumArtSearchProvidersInfo <20><><EFBFBD><EFBFBD> CollectionChanged <20>¼<EFBFBD>
|
||||
ViewModel.SelectedMediaSourceProvider?.AlbumArtSearchProvidersInfo?.Refresh();
|
||||
}
|
||||
|
||||
private void LyricsSearchProvidersListView_DragItemsCompleted(ListViewBase sender, DragItemsCompletedEventArgs args)
|
||||
{
|
||||
// <20><> LyricsSearchProvidersInfo <20><><EFBFBD><EFBFBD> CollectionChanged <20>¼<EFBFBD>
|
||||
ViewModel.SelectedMediaSourceProvider?.LyricsSearchProvidersInfo?.Refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,9 +15,9 @@ namespace BetterLyrics.WinUI3.Converter
|
||||
return provider switch
|
||||
{
|
||||
TranslationSearchProvider.LrcLib => "LrcLib",
|
||||
TranslationSearchProvider.QQ => "QQ",
|
||||
TranslationSearchProvider.Netease => "Netease",
|
||||
TranslationSearchProvider.Kugou => "Kugou",
|
||||
TranslationSearchProvider.QQ => "QQ 音乐",
|
||||
TranslationSearchProvider.Netease => "网易云音乐",
|
||||
TranslationSearchProvider.Kugou => "酷狗音乐",
|
||||
TranslationSearchProvider.AmllTtmlDb => "amll-ttml-db",
|
||||
TranslationSearchProvider.LocalLrcFile => App.ResourceLoader!.GetString("LyricsSearchProviderLocalLrcFile"),
|
||||
TranslationSearchProvider.LocalMusicFile => App.ResourceLoader!.GetString("LyricsSearchProviderLocalMusicFile"),
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Enums
|
||||
{
|
||||
public enum SettingsStoreType
|
||||
{
|
||||
Container,
|
||||
JSON
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Extensions
|
||||
{
|
||||
// https://stackoverflow.com/a/32013610/11048731
|
||||
public class FullyObservableCollection<T> : ObservableCollection<T>
|
||||
where T : INotifyPropertyChanged
|
||||
{
|
||||
/// <summary>
|
||||
/// Occurs when a property is changed within an item.
|
||||
/// </summary>
|
||||
public event EventHandler<ItemPropertyChangedEventArgs> ItemPropertyChanged;
|
||||
|
||||
public FullyObservableCollection() : base()
|
||||
{ }
|
||||
|
||||
public FullyObservableCollection(List<T> list) : base(list)
|
||||
{
|
||||
ObserveAll();
|
||||
}
|
||||
|
||||
public FullyObservableCollection(IEnumerable<T> enumerable) : base(enumerable)
|
||||
{
|
||||
ObserveAll();
|
||||
}
|
||||
|
||||
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
if (e.Action == NotifyCollectionChangedAction.Remove ||
|
||||
e.Action == NotifyCollectionChangedAction.Replace)
|
||||
{
|
||||
foreach (T item in e.OldItems)
|
||||
item.PropertyChanged -= ChildPropertyChanged;
|
||||
}
|
||||
|
||||
if (e.Action == NotifyCollectionChangedAction.Add ||
|
||||
e.Action == NotifyCollectionChangedAction.Replace)
|
||||
{
|
||||
foreach (T item in e.NewItems)
|
||||
item.PropertyChanged += ChildPropertyChanged;
|
||||
}
|
||||
|
||||
base.OnCollectionChanged(e);
|
||||
}
|
||||
|
||||
protected void OnItemPropertyChanged(ItemPropertyChangedEventArgs e)
|
||||
{
|
||||
ItemPropertyChanged?.Invoke(this, e);
|
||||
}
|
||||
|
||||
protected void OnItemPropertyChanged(int index, PropertyChangedEventArgs e)
|
||||
{
|
||||
OnItemPropertyChanged(new ItemPropertyChangedEventArgs(index, e));
|
||||
}
|
||||
|
||||
protected override void ClearItems()
|
||||
{
|
||||
foreach (T item in Items)
|
||||
item.PropertyChanged -= ChildPropertyChanged;
|
||||
|
||||
base.ClearItems();
|
||||
}
|
||||
|
||||
private void ObserveAll()
|
||||
{
|
||||
foreach (T item in Items)
|
||||
item.PropertyChanged += ChildPropertyChanged;
|
||||
}
|
||||
|
||||
private void ChildPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
T typedSender = (T)sender;
|
||||
int i = Items.IndexOf(typedSender);
|
||||
|
||||
if (i < 0)
|
||||
throw new ArgumentException("Received property notification from item not in collection");
|
||||
|
||||
OnItemPropertyChanged(i, e);
|
||||
}
|
||||
|
||||
public void Refresh()
|
||||
{
|
||||
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides data for the <see cref="FullyObservableCollection{T}.ItemPropertyChanged"/> event.
|
||||
/// </summary>
|
||||
public class ItemPropertyChangedEventArgs : PropertyChangedEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the index in the collection for which the property change has occurred.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Index in parent collection.
|
||||
/// </value>
|
||||
public int CollectionIndex { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ItemPropertyChangedEventArgs"/> class.
|
||||
/// </summary>
|
||||
/// <param name="index">The index in the collection of changed item.</param>
|
||||
/// <param name="name">The name of the property that changed.</param>
|
||||
public ItemPropertyChangedEventArgs(int index, string name) : base(name)
|
||||
{
|
||||
CollectionIndex = index;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ItemPropertyChangedEventArgs"/> class.
|
||||
/// </summary>
|
||||
/// <param name="index">The index.</param>
|
||||
/// <param name="args">The <see cref="PropertyChangedEventArgs"/> instance containing the event data.</param>
|
||||
public ItemPropertyChangedEventArgs(int index, PropertyChangedEventArgs args) : this(index, args.PropertyName)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using Microsoft.Graphics.Canvas.Brushes;
|
||||
using Microsoft.Graphics.Canvas.UI.Xaml;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.UI;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Helper
|
||||
{
|
||||
public class CanvasHelper
|
||||
{
|
||||
public static CanvasLinearGradientBrush CreateHorizontalFillBrush(
|
||||
ICanvasAnimatedControl control,
|
||||
List<(double position, double opacity)> stops,
|
||||
double startX,
|
||||
double width
|
||||
)
|
||||
{
|
||||
return new CanvasLinearGradientBrush(control, stops.Select(stops => new CanvasGradientStop
|
||||
{
|
||||
Position = (float)stops.position,
|
||||
Color = Color.FromArgb((byte)(stops.opacity * 255), 128, 128, 128),
|
||||
}).ToArray())
|
||||
{
|
||||
StartPoint = new Vector2((float)startX, 0),
|
||||
EndPoint = new Vector2((float)(startX + width), 0),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -52,7 +52,7 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
return Color.FromArgb(255, fg.R, fg.G, fg.B);
|
||||
}
|
||||
|
||||
public static Color GetInterpolatedColor(float progress, Color startColor, Color targetColor)
|
||||
public static Color GetInterpolatedColor(double progress, Color startColor, Color targetColor)
|
||||
{
|
||||
byte Lerp(byte a, byte b) => (byte)(a + (progress * (b - a)));
|
||||
return Color.FromArgb(
|
||||
|
||||
@@ -67,21 +67,8 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
);
|
||||
}
|
||||
|
||||
// <20>Ӵ洢<D3B4><E6B4A2><EFBFBD><EFBFBD>ȡĿ<C8A1><C4BF><EFBFBD><EFBFBD><EFBFBD>ߺ<EFBFBD>λ<EFBFBD><CEBB>
|
||||
int targetWidth = _settingsService.DesktopWindowWidth;
|
||||
int targetHeight = _settingsService.DesktopWindowHeight;
|
||||
int targetX = _settingsService.DesktopWindowLeft;
|
||||
int targetY = _settingsService.DesktopWindowTop;
|
||||
|
||||
// <20><><EFBFBD>ô<EFBFBD><C3B4>ڴ<EFBFBD>С<EFBFBD><D0A1>λ<EFBFBD><CEBB>
|
||||
window.AppWindow.MoveAndResize(
|
||||
new Windows.Graphics.RectInt32(
|
||||
targetX,
|
||||
targetY,
|
||||
targetWidth,
|
||||
targetHeight
|
||||
)
|
||||
);
|
||||
window.AppWindow.MoveAndResize(_settingsService.AppSettings.DesktopModeSettings.WindowBounds.ToRectInt32());
|
||||
|
||||
// <20><><EFBFBD><EFBFBD>ԭTopMost״̬
|
||||
if (!_originalTopmostStates.ContainsKey(hwnd))
|
||||
|
||||
@@ -78,7 +78,7 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
|
||||
RegisterAppBar(hwnd, monitorDeviceName, appBarHeight, dockPlacement);
|
||||
|
||||
var monitorInfo = MonitorHelper.GetMonitorInfoExFromDeviceName(_settingsService.DockMonitorDeviceName);
|
||||
var monitorInfo = MonitorHelper.GetMonitorInfoExFromDeviceName(_settingsService.AppSettings.DockModeSettings.DockMonitorDeviceName);
|
||||
|
||||
int screenWidth = monitorInfo.rcMonitor.Width;
|
||||
int screenHeight = monitorInfo.rcMonitor.Bottom - monitorInfo.rcMonitor.Top;
|
||||
|
||||
@@ -10,67 +10,67 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
{
|
||||
public class EasingHelper
|
||||
{
|
||||
public static float EaseInOutSine(float t)
|
||||
public static double EaseInOutSine(double t)
|
||||
{
|
||||
return -(MathF.Cos(MathF.PI * t) - 1f) / 2f;
|
||||
return -(Math.Cos(Math.PI * t) - 1f) / 2f;
|
||||
}
|
||||
public static float EaseInOutQuad(float t)
|
||||
public static double EaseInOutQuad(double t)
|
||||
{
|
||||
return t < 0.5f ? 2 * t * t : -1 + (4 - 2 * t) * t;
|
||||
}
|
||||
|
||||
public static float EaseInOutCubic(float t)
|
||||
public static double EaseInOutCubic(double t)
|
||||
{
|
||||
return t < 0.5f ? 4 * t * t * t : 1 - MathF.Pow(-2 * t + 2, 3) / 2;
|
||||
return t < 0.5f ? 4 * t * t * t : 1 - Math.Pow(-2 * t + 2, 3) / 2;
|
||||
}
|
||||
public static float EaseInOutQuart(float t)
|
||||
public static double EaseInOutQuart(double t)
|
||||
{
|
||||
return t < 0.5f ? 8 * t * t * t * t : 1 - MathF.Pow(-2 * t + 2, 4) / 2;
|
||||
return t < 0.5f ? 8 * t * t * t * t : 1 - Math.Pow(-2 * t + 2, 4) / 2;
|
||||
}
|
||||
|
||||
public static float EaseInOutQuint(float t)
|
||||
public static double EaseInOutQuint(double t)
|
||||
{
|
||||
return t < 0.5f ? 16 * t * t * t * t * t : 1 - MathF.Pow(-2 * t + 2, 5) / 2;
|
||||
return t < 0.5f ? 16 * t * t * t * t * t : 1 - Math.Pow(-2 * t + 2, 5) / 2;
|
||||
}
|
||||
|
||||
public static float EaseInOutExpo(float t)
|
||||
public static double EaseInOutExpo(double t)
|
||||
{
|
||||
return t == 0
|
||||
? 0
|
||||
: t == 1
|
||||
? 1
|
||||
: t < 0.5 ? MathF.Pow(2, 20 * t - 10) / 2
|
||||
: (2 - MathF.Pow(2, -20 * t + 10)) / 2;
|
||||
: t < 0.5 ? Math.Pow(2, 20 * t - 10) / 2
|
||||
: (2 - Math.Pow(2, -20 * t + 10)) / 2;
|
||||
}
|
||||
|
||||
public static float EaseInOutCirc(float t)
|
||||
public static double EaseInOutCirc(double t)
|
||||
{
|
||||
return t < 0.5f
|
||||
? (1 - MathF.Sqrt(1 - MathF.Pow(2 * t, 2))) / 2
|
||||
: (MathF.Sqrt(1 - MathF.Pow(-2 * t + 2, 2)) + 1) / 2;
|
||||
? (1 - Math.Sqrt(1 - Math.Pow(2 * t, 2))) / 2
|
||||
: (Math.Sqrt(1 - Math.Pow(-2 * t + 2, 2)) + 1) / 2;
|
||||
}
|
||||
|
||||
public static float EaseInOutBack(float t)
|
||||
public static double EaseInOutBack(double t)
|
||||
{
|
||||
float c1 = 1.70158f;
|
||||
float c2 = c1 * 1.525f;
|
||||
double c1 = 1.70158f;
|
||||
double c2 = c1 * 1.525f;
|
||||
|
||||
return t < 0.5
|
||||
? (MathF.Pow(2 * t, 2) * ((c2 + 1) * 2 * t - c2)) / 2
|
||||
: (MathF.Pow(2 * t - 2, 2) * ((c2 + 1) * (t * 2 - 2) + c2) + 2) / 2;
|
||||
? (Math.Pow(2 * t, 2) * ((c2 + 1) * 2 * t - c2)) / 2
|
||||
: (Math.Pow(2 * t - 2, 2) * ((c2 + 1) * (t * 2 - 2) + c2) + 2) / 2;
|
||||
}
|
||||
|
||||
public static float EaseInOutElastic(float t)
|
||||
public static double EaseInOutElastic(double t)
|
||||
{
|
||||
if (t == 0 || t == 1) return t;
|
||||
float p = 0.3f;
|
||||
float s = p / 4;
|
||||
double p = 0.3f;
|
||||
double s = p / 4;
|
||||
return t < 0.5f
|
||||
? -(MathF.Pow(2, 20 * t - 10) * MathF.Sin((20 * t - 11.125f) * (2 * MathF.PI) / p)) / 2
|
||||
: (MathF.Pow(2, -20 * t + 10) * MathF.Sin((20 * t - 11.125f) * (2 * MathF.PI) / p)) / 2 + 1;
|
||||
? -(Math.Pow(2, 20 * t - 10) * Math.Sin((20 * t - 11.125f) * (2 * Math.PI) / p)) / 2
|
||||
: (Math.Pow(2, -20 * t + 10) * Math.Sin((20 * t - 11.125f) * (2 * Math.PI) / p)) / 2 + 1;
|
||||
}
|
||||
|
||||
private static float EaseOutBounce(float t)
|
||||
private static double EaseOutBounce(double t)
|
||||
{
|
||||
if (t < 4 / 11f)
|
||||
{
|
||||
@@ -90,7 +90,7 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
}
|
||||
}
|
||||
|
||||
public static float EaseInOutBounce(float t)
|
||||
public static double EaseInOutBounce(double t)
|
||||
{
|
||||
if (t < 0.5f)
|
||||
{
|
||||
@@ -102,17 +102,17 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
}
|
||||
}
|
||||
|
||||
public static float SmoothStep(float t)
|
||||
public static double SmoothStep(double t)
|
||||
{
|
||||
return t * t * (3f - 2f * t);
|
||||
}
|
||||
|
||||
public static float CubicBezier(float t, float p0, float p1, float p2, float p3)
|
||||
public static double CubicBezier(double t, double p0, double p1, double p2, double p3)
|
||||
{
|
||||
float u = 1 - t;
|
||||
double u = 1 - t;
|
||||
return u * u * u * p0 + 3 * u * u * t * p1 + 3 * u * t * t * p2 + t * t * t * p3;
|
||||
}
|
||||
|
||||
public static float Linear(float t) => t;
|
||||
public static double Linear(double t) => t;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
|
||||
public static bool IsSwitchableNormalizedMatch(string fileName, string q1, string q2)
|
||||
{
|
||||
var normFileName = StringHelper.Normalize(fileName.Normalize());
|
||||
var normFileName = StringHelper.Normalize(fileName);
|
||||
var normQ1 = StringHelper.Normalize(q1);
|
||||
var normQ2 = StringHelper.Normalize(q2);
|
||||
|
||||
|
||||
@@ -11,10 +11,6 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
{
|
||||
public static class FontHelper
|
||||
{
|
||||
private static readonly ISettingsService _settingsService = Ioc.Default.GetRequiredService<ISettingsService>();
|
||||
|
||||
public static string[] SystemFontFamilies => CanvasTextFormat.GetSystemFontFamilies();
|
||||
|
||||
public static string GetUserPreferredFontFamily() => SystemFontFamilies.ElementAtOrDefault(_settingsService.SelectedFontFamilyIndex) ?? "Segoe UI";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public static float GetAverageLuminance(CanvasBitmap bitmap)
|
||||
public static double GetAverageLuminance(CanvasBitmap bitmap)
|
||||
{
|
||||
var pixels = bitmap.GetPixelBytes();
|
||||
double sum = 0;
|
||||
@@ -152,7 +152,7 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
double y = 0.299 * r + 0.587 * g + 0.114 * b;
|
||||
sum += y / 255.0;
|
||||
}
|
||||
return (float)(sum / (pixels.Length / 4));
|
||||
return (double)(sum / (pixels.Length / 4));
|
||||
}
|
||||
|
||||
public static byte[] MakeSquareWithThemeColor(byte[] imageBytes)
|
||||
@@ -185,7 +185,7 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
{
|
||||
using (Image image = Image.Load(imageBytes))
|
||||
{
|
||||
var factor = Math.Max((float)size / image.Width, (float)size / image.Height);
|
||||
var factor = Math.Max((double)size / image.Width, (double)size / image.Height);
|
||||
|
||||
int width = (int)(image.Width * factor);
|
||||
int height = (int)(image.Height * factor);
|
||||
|
||||
@@ -101,7 +101,7 @@ namespace BetterLyrics.WinUI3.Services
|
||||
|
||||
public static string GetUserTargetLanguageCode()
|
||||
{
|
||||
return SupportedTargetLanguages[_settingsService.SelectedTargetLanguageIndex].Code;
|
||||
return SupportedTargetLanguages[_settingsService.AppSettings.TranslationSettings.SelectedTargetLanguageIndex].Code;
|
||||
}
|
||||
|
||||
public static int GetDefaultTargetLanguageIndex()
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.Security.Credentials;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Helper
|
||||
{
|
||||
public static class PasswordVaultHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 保存敏感数据到 PasswordVault
|
||||
/// </summary>
|
||||
/// <param name="resource">资源标识,比如 "MyApp"</param>
|
||||
/// <param name="key">键名,比如 "SessionKey"</param>
|
||||
/// <param name="value">要保存的值</param>
|
||||
public static void Save(string resource, string key, string value)
|
||||
{
|
||||
var vault = new PasswordVault();
|
||||
|
||||
// 删除旧值(避免重复存储)
|
||||
try
|
||||
{
|
||||
var oldCredential = vault.Retrieve(resource, key);
|
||||
if (oldCredential != null)
|
||||
{
|
||||
vault.Remove(oldCredential);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 没有旧值就忽略
|
||||
}
|
||||
|
||||
vault.Add(new PasswordCredential(resource, key, value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从 PasswordVault 获取敏感数据
|
||||
/// </summary>
|
||||
/// <param name="resource">资源标识</param>
|
||||
/// <param name="key">键名</param>
|
||||
/// <returns>存储的值,若不存在则返回 null</returns>
|
||||
public static string? Get(string resource, string key)
|
||||
{
|
||||
var vault = new PasswordVault();
|
||||
try
|
||||
{
|
||||
var credential = vault.Retrieve(resource, key);
|
||||
credential.RetrievePassword();
|
||||
return credential.Password;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除指定的敏感数据
|
||||
/// </summary>
|
||||
public static void Delete(string resource, string key)
|
||||
{
|
||||
var vault = new PasswordVault();
|
||||
try
|
||||
{
|
||||
var credential = vault.Retrieve(resource, key);
|
||||
vault.Remove(credential);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 不存在就忽略
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,11 +11,13 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
{
|
||||
public class PathHelper
|
||||
{
|
||||
private static string LocalFolder => ApplicationData.Current.LocalFolder.Path;
|
||||
public static string LocalFolder => ApplicationData.Current.LocalFolder.Path;
|
||||
public static string CacheFolder => ApplicationData.Current.LocalCacheFolder.Path;
|
||||
public static string AssetsFolder => Path.Combine(Package.Current.InstalledPath, "Assets");
|
||||
|
||||
//public static string LanguageProfilePath => Path.Combine(AssetsFolder, "Core14.profile.xml");
|
||||
public static string SettingsDirectory => Path.Combine(LocalFolder, "settings");
|
||||
public static string SettingsFilePath => Path.Combine(SettingsDirectory, "settings.json");
|
||||
|
||||
public static string LanguageProfilePath => Path.Combine(AssetsFolder, "Wiki82.profile.xml");
|
||||
public static string LogoPath => Path.Combine(AssetsFolder, "Logo.ico");
|
||||
public static string AIMPLogoPath => Path.Combine(AssetsFolder, "AIMP.png");
|
||||
@@ -58,6 +60,8 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
|
||||
public static void EnsureDirectories()
|
||||
{
|
||||
Directory.CreateDirectory(SettingsDirectory);
|
||||
|
||||
Directory.CreateDirectory(LogDirectory);
|
||||
|
||||
Directory.CreateDirectory(LrcLibLyricsCacheDirectory);
|
||||
|
||||
22
BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/RectHelper.cs
Normal file
22
BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/RectHelper.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.Graphics;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Helper
|
||||
{
|
||||
public static class RectHelper
|
||||
{
|
||||
public static RectInt32 ToRectInt32(this Windows.Foundation.Rect rect)
|
||||
{
|
||||
return new RectInt32(
|
||||
(int)rect.X,
|
||||
(int)rect.Y,
|
||||
(int)rect.Width,
|
||||
(int)rect.Height
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,7 +38,7 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
{
|
||||
if (_endpointVolume != null)
|
||||
{
|
||||
float level = _endpointVolume.GetMasterVolumeLevelScalar();
|
||||
double level = _endpointVolume.GetMasterVolumeLevelScalar();
|
||||
_masterVolume = (int)(level * 100);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,21 +10,22 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
where T : struct
|
||||
{
|
||||
private T _currentValue;
|
||||
private float _durationSeconds;
|
||||
private double _durationSeconds;
|
||||
private EasingType? _easingType;
|
||||
private Func<T, T, float, T> _interpolator;
|
||||
private Func<T, T, double, T> _interpolator;
|
||||
private bool _isTransitioning;
|
||||
private float _progress;
|
||||
private double _progress;
|
||||
private T _startValue;
|
||||
private T _targetValue;
|
||||
|
||||
public float DurationSeconds => _durationSeconds;
|
||||
public double DurationSeconds => _durationSeconds;
|
||||
|
||||
public bool IsTransitioning => _isTransitioning;
|
||||
public T Value => _currentValue;
|
||||
public T TargetValue => _targetValue;
|
||||
public EasingType? EasingType => _easingType;
|
||||
|
||||
public ValueTransition(T initialValue, float durationSeconds, Func<T, T, float, T>? interpolator = null, EasingType? easingType = null)
|
||||
public ValueTransition(T initialValue, double durationSeconds, Func<T, T, double, T>? interpolator = null, EasingType? easingType = null)
|
||||
{
|
||||
_currentValue = initialValue;
|
||||
_startValue = initialValue;
|
||||
@@ -45,12 +46,12 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
}
|
||||
else
|
||||
{
|
||||
_easingType = EasingType.Linear;
|
||||
_easingType = Enums.EasingType.Linear;
|
||||
_interpolator = GetInterpolatorByEasingType(_easingType.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetDuration(float seconds)
|
||||
public void SetDuration(double seconds)
|
||||
{
|
||||
if (seconds <= 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(seconds), "Duration must be positive.");
|
||||
@@ -102,7 +103,7 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
{
|
||||
if (!_isTransitioning) return;
|
||||
|
||||
_progress += (float)(elapsedTime / TimeSpan.FromSeconds(_durationSeconds));
|
||||
_progress += (double)(elapsedTime / TimeSpan.FromSeconds(_durationSeconds));
|
||||
if (_progress >= 1f)
|
||||
{
|
||||
_progress = 1f;
|
||||
@@ -115,51 +116,51 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
}
|
||||
}
|
||||
|
||||
private Func<T, T, float, T> GetInterpolatorByEasingType(EasingType type)
|
||||
private Func<T, T, double, T> GetInterpolatorByEasingType(EasingType type)
|
||||
{
|
||||
if (typeof(T) == typeof(float))
|
||||
if (typeof(T) == typeof(double))
|
||||
{
|
||||
return (start, end, progress) =>
|
||||
{
|
||||
float s = (float)(object)start;
|
||||
float e = (float)(object)end;
|
||||
float t = progress;
|
||||
double s = (double)(object)start;
|
||||
double e = (double)(object)end;
|
||||
double t = progress;
|
||||
switch (type)
|
||||
{
|
||||
case EasingType.EaseInOutSine:
|
||||
case Enums.EasingType.EaseInOutSine:
|
||||
t = EasingHelper.EaseInOutSine(t);
|
||||
break;
|
||||
case EasingType.EaseInOutQuad:
|
||||
case Enums.EasingType.EaseInOutQuad:
|
||||
t = EasingHelper.EaseInOutQuad(t);
|
||||
break;
|
||||
case EasingType.EaseInOutCubic:
|
||||
case Enums.EasingType.EaseInOutCubic:
|
||||
t = EasingHelper.EaseInOutCubic(t);
|
||||
break;
|
||||
case EasingType.EaseInOutQuart:
|
||||
case Enums.EasingType.EaseInOutQuart:
|
||||
t = EasingHelper.EaseInOutQuart(t);
|
||||
break;
|
||||
case EasingType.EaseInOutQuint:
|
||||
case Enums.EasingType.EaseInOutQuint:
|
||||
t = EasingHelper.EaseInOutQuint(t);
|
||||
break;
|
||||
case EasingType.EaseInOutExpo:
|
||||
case Enums.EasingType.EaseInOutExpo:
|
||||
t = EasingHelper.EaseInOutExpo(t);
|
||||
break;
|
||||
case EasingType.EaseInOutCirc:
|
||||
case Enums.EasingType.EaseInOutCirc:
|
||||
t = EasingHelper.EaseInOutCirc(t);
|
||||
break;
|
||||
case EasingType.EaseInOutBack:
|
||||
case Enums.EasingType.EaseInOutBack:
|
||||
t = EasingHelper.EaseInOutBack(t);
|
||||
break;
|
||||
case EasingType.EaseInOutElastic:
|
||||
case Enums.EasingType.EaseInOutElastic:
|
||||
t = EasingHelper.EaseInOutElastic(t);
|
||||
break;
|
||||
case EasingType.EaseInOutBounce:
|
||||
case Enums.EasingType.EaseInOutBounce:
|
||||
t = EasingHelper.EaseInOutBounce(t);
|
||||
break;
|
||||
case EasingType.SmoothStep:
|
||||
case Enums.EasingType.SmoothStep:
|
||||
t = EasingHelper.SmoothStep(t);
|
||||
break;
|
||||
case EasingType.Linear:
|
||||
case Enums.EasingType.Linear:
|
||||
t = EasingHelper.Linear(t);
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -5,13 +5,11 @@ using CommunityToolkit.Mvvm.ComponentModel;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Models
|
||||
{
|
||||
public partial class AlbumArtSearchProviderInfo : ObservableObject
|
||||
public partial class AlbumArtSearchProviderInfo : ObservableRecipient
|
||||
{
|
||||
[ObservableProperty]
|
||||
public partial bool IsEnabled { get; set; }
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsEnabled { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial AlbumArtSearchProvider Provider { get; set; }
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial AlbumArtSearchProvider Provider { get; set; }
|
||||
|
||||
public AlbumArtSearchProviderInfo() { }
|
||||
|
||||
|
||||
@@ -4,13 +4,10 @@ using CommunityToolkit.Mvvm.ComponentModel;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Models
|
||||
{
|
||||
public partial class LocalMediaFolder : ObservableObject
|
||||
public partial class LocalMediaFolder : ObservableRecipient
|
||||
{
|
||||
[ObservableProperty]
|
||||
public partial bool IsEnabled { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial string Path { get; set; }
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsEnabled { get; set; }
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial string Path { get; set; }
|
||||
|
||||
public LocalMediaFolder() { }
|
||||
|
||||
|
||||
@@ -3,43 +3,55 @@
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using Microsoft.Graphics.Canvas;
|
||||
using Microsoft.Graphics.Canvas.Effects;
|
||||
using Microsoft.Graphics.Canvas.Geometry;
|
||||
using Microsoft.Graphics.Canvas.Text;
|
||||
using Microsoft.Graphics.Canvas.UI.Xaml;
|
||||
using Microsoft.UI;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Shapes;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Windows.Foundation;
|
||||
using Windows.Graphics.Effects;
|
||||
using Windows.UI;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Models
|
||||
{
|
||||
public class LyricsLine
|
||||
{
|
||||
private const float _animationDuration = 0.3f;
|
||||
public ValueTransition<float> AngleTransition { get; set; } = new(
|
||||
initialValue: 0f,
|
||||
private const double _animationDuration = 0.3;
|
||||
public ValueTransition<double> AngleTransition { get; set; } = new(
|
||||
initialValue: 0,
|
||||
durationSeconds: _animationDuration,
|
||||
easingType: EasingType.EaseInOutSine
|
||||
);
|
||||
public ValueTransition<float> BlurAmountTransition { get; set; } = new(
|
||||
initialValue: 0f,
|
||||
public ValueTransition<double> BlurAmountTransition { get; set; } = new(
|
||||
initialValue: 0,
|
||||
durationSeconds: _animationDuration,
|
||||
easingType: EasingType.EaseInOutSine
|
||||
);
|
||||
public ValueTransition<float> HighlightOpacityTransition { get; set; } = new(
|
||||
initialValue: 0f,
|
||||
public ValueTransition<double> HighlightOpacityTransition { get; set; } = new(
|
||||
initialValue: 0,
|
||||
durationSeconds: _animationDuration,
|
||||
easingType: EasingType.EaseInOutSine
|
||||
);
|
||||
public ValueTransition<float> OpacityTransition { get; set; } = new(
|
||||
initialValue: 0f,
|
||||
public ValueTransition<double> OpacityTransition { get; set; } = new(
|
||||
initialValue: 0,
|
||||
durationSeconds: _animationDuration,
|
||||
easingType: EasingType.EaseInOutSine
|
||||
);
|
||||
public ValueTransition<float> ScaleTransition { get; set; } = new(
|
||||
initialValue: 0f,
|
||||
public ValueTransition<double> ScaleTransition { get; set; } = new(
|
||||
initialValue: 0.75,
|
||||
durationSeconds: _animationDuration,
|
||||
easingType: EasingType.EaseInOutSine
|
||||
);
|
||||
public ValueTransition<double> YOffsetTransition { get; set; } = new(
|
||||
initialValue: 0,
|
||||
durationSeconds: 0.5,
|
||||
easingType: EasingType.EaseInOutSine
|
||||
);
|
||||
|
||||
public CanvasTextLayout? CanvasTextLayout { get; private set; }
|
||||
|
||||
@@ -57,30 +69,60 @@ namespace BetterLyrics.WinUI3.Models
|
||||
|
||||
public CanvasGeometry? TextGeometry { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 背景文字层(底字)
|
||||
/// </summary>
|
||||
public CanvasCommandList? BackgroundFontEffect { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 背景层
|
||||
/// </summary>
|
||||
public OpacityEffect? BackgroundEffect { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 辉光层
|
||||
/// </summary>
|
||||
public GaussianBlurEffect? ForegroundBlurEffect { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 高亮层
|
||||
/// </summary>
|
||||
public AlphaMaskEffect? ForegroundHighlightEffect { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 前景文字层
|
||||
/// </summary>
|
||||
public CanvasCommandList? ForegroundFontEffect { get; private set; }
|
||||
|
||||
public void UpdateCenterPosition(float maxWidth, TextAlignmentType type)
|
||||
public CanvasCommandList? ComposedLineEffect { get; private set; }
|
||||
|
||||
public CanvasCommandList? CurrentCharMask { get; private set; }
|
||||
public CanvasCommandList? LineStartToCurrentCharMask { get; private set; }
|
||||
public CanvasCommandList? CurrentLineMask { get; private set; }
|
||||
|
||||
public CanvasCommandList? PlaceholderEffect { get; private set; }
|
||||
|
||||
public void UpdateCenterPosition(double maxWidth, TextAlignmentType type)
|
||||
{
|
||||
if (CanvasTextLayout == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
float centerY = Position.Y + (float)CanvasTextLayout.LayoutBounds.Height;
|
||||
double centerY = Position.Y + (double)CanvasTextLayout.LayoutBounds.Height;
|
||||
CenterPosition = type switch
|
||||
{
|
||||
TextAlignmentType.Left => new Vector2(Position.X, centerY),
|
||||
TextAlignmentType.Center => new Vector2(Position.X + maxWidth / 2, centerY),
|
||||
TextAlignmentType.Right => new Vector2(Position.X + maxWidth, centerY),
|
||||
TextAlignmentType.Left => new Vector2(Position.X, (float)centerY),
|
||||
TextAlignmentType.Center => new Vector2((float)(Position.X + maxWidth / 2.0), (float)centerY),
|
||||
TextAlignmentType.Right => new Vector2((float)(Position.X + maxWidth), (float)centerY),
|
||||
_ => throw new System.ArgumentOutOfRangeException(nameof(type), type, null),
|
||||
};
|
||||
}
|
||||
|
||||
public void UpdateTextLayout(ICanvasAnimatedControl control, CanvasTextFormat textFormat, float maxWidth, float maxHeight, TextAlignmentType type)
|
||||
public void RecreateTextLayout(ICanvasAnimatedControl control, CanvasTextFormat textFormat, double maxWidth, double maxHeight, TextAlignmentType type)
|
||||
{
|
||||
CanvasTextLayout?.Dispose();
|
||||
CanvasTextLayout = null;
|
||||
CanvasTextLayout = new CanvasTextLayout(control, DisplayedText, textFormat, maxWidth, maxHeight);
|
||||
CanvasTextLayout = new CanvasTextLayout(control, DisplayedText, textFormat, (float)maxWidth, (float)maxHeight);
|
||||
CanvasTextLayout.HorizontalAlignment = type.ToCanvasHorizontalAlignment();
|
||||
}
|
||||
|
||||
@@ -90,7 +132,7 @@ namespace BetterLyrics.WinUI3.Models
|
||||
TextGeometry = null;
|
||||
}
|
||||
|
||||
public void UpdateTextGeometry()
|
||||
public void RecreateTextGeometry()
|
||||
{
|
||||
DisposeTextGeometry();
|
||||
if (CanvasTextLayout == null)
|
||||
@@ -108,7 +150,7 @@ namespace BetterLyrics.WinUI3.Models
|
||||
ForegroundFontEffect = null;
|
||||
}
|
||||
|
||||
public void UpdateFontEffect(ICanvasAnimatedControl control, bool drawStroke, Color strokeColor, int strokeWidth, Color fontColor)
|
||||
public void RecreateFontEffect(ICanvasAnimatedControl control, Color strokeColor, int strokeWidth, Color bgFontColor, Color fgFontColor)
|
||||
{
|
||||
DisposeFontEffects();
|
||||
if (TextGeometry == null)
|
||||
@@ -119,13 +161,372 @@ namespace BetterLyrics.WinUI3.Models
|
||||
using var bgFontEffectDs = BackgroundFontEffect.CreateDrawingSession();
|
||||
ForegroundFontEffect = new CanvasCommandList(control);
|
||||
using var fgFontEffectDs = ForegroundFontEffect.CreateDrawingSession();
|
||||
if (drawStroke)
|
||||
// 大于 0 才描边,避免不必要的资源浪费
|
||||
if (strokeWidth > 0)
|
||||
{
|
||||
bgFontEffectDs.DrawGeometry(TextGeometry, Position, strokeColor, strokeWidth); // 描边
|
||||
fgFontEffectDs.DrawGeometry(TextGeometry, Position, strokeColor, strokeWidth); // 描边
|
||||
}
|
||||
bgFontEffectDs.FillGeometry(TextGeometry, Position, fontColor); // 填充
|
||||
fgFontEffectDs.FillGeometry(TextGeometry, Position, fontColor); // 填充
|
||||
bgFontEffectDs.FillGeometry(TextGeometry, Position, bgFontColor); // 填充
|
||||
fgFontEffectDs.FillGeometry(TextGeometry, Position, fgFontColor); // 填充
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 背景层
|
||||
/// </summary>
|
||||
/// <param name="lyricsLayerOpacity">_lyricsOpacityTransition.Value</param>
|
||||
public void RecreateBackgroundEffect(double lyricsLayerOpacity)
|
||||
{
|
||||
BackgroundEffect?.Dispose();
|
||||
BackgroundEffect = null;
|
||||
if (BackgroundFontEffect == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
BackgroundEffect = new OpacityEffect
|
||||
{
|
||||
Source = new GaussianBlurEffect
|
||||
{
|
||||
Source = BackgroundFontEffect,
|
||||
BlurAmount = (float)BlurAmountTransition.Value,
|
||||
BorderMode = EffectBorderMode.Soft,
|
||||
Optimization = EffectOptimization.Speed,
|
||||
},
|
||||
Opacity = (float)(OpacityTransition.Value * lyricsLayerOpacity),
|
||||
};
|
||||
}
|
||||
|
||||
public void UpdateBackgroundEffect(double lyricsLayerOpacity)
|
||||
{
|
||||
BackgroundEffect?.Opacity = (float)(OpacityTransition.Value * lyricsLayerOpacity);
|
||||
GaussianBlurEffect? blurEffect = (GaussianBlurEffect?)(BackgroundEffect?.Source);
|
||||
blurEffect?.BlurAmount = (float)BlurAmountTransition.Value;
|
||||
}
|
||||
|
||||
private IGraphicsEffectSource GetAlphaMask(ICanvasAnimatedControl control, LineRenderingType lineRenderingType)
|
||||
{
|
||||
if (PlaceholderEffect == null)
|
||||
{
|
||||
RecreatePlaceholder(control);
|
||||
}
|
||||
|
||||
var result = lineRenderingType switch
|
||||
{
|
||||
LineRenderingType.CurrentChar => CurrentCharMask,
|
||||
LineRenderingType.LineStartToCurrentChar => LineStartToCurrentCharMask,
|
||||
// Here, cuz AlphaMask only takes care of alpha channel
|
||||
// so ForegroundFontEffect can be a mask for CurrentLine
|
||||
// And we don't need to create a new mask for CurrentLine
|
||||
LineRenderingType.CurrentLine => CurrentLineMask,
|
||||
_ => PlaceholderEffect
|
||||
};
|
||||
return result ?? PlaceholderEffect!;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 销毁并重新创建辉光效果层
|
||||
/// 仅需在布局重构 (Relayout) 时调用
|
||||
/// </summary>
|
||||
/// <param name="lineRenderingType">_lyricsGlowEffectScope</param>
|
||||
/// <param name="glowEffectAmount">_lyricsGlowEffectAmount</param>
|
||||
public void RecreateForegroundBlurEffect(ICanvasAnimatedControl control, LineRenderingType lineRenderingType, double glowEffectAmount)
|
||||
{
|
||||
ForegroundBlurEffect?.Dispose();
|
||||
ForegroundBlurEffect = null;
|
||||
if (ForegroundFontEffect == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var mask = GetAlphaMask(control, lineRenderingType);
|
||||
if (mask == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
ForegroundBlurEffect = new GaussianBlurEffect
|
||||
{
|
||||
Source = new AlphaMaskEffect
|
||||
{
|
||||
Source = ForegroundFontEffect,
|
||||
AlphaMask = mask,
|
||||
},
|
||||
BlurAmount = (float)glowEffectAmount,
|
||||
Optimization = EffectOptimization.Speed,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 仅当前行需要调用此方法(每次 Update 都调用一次)
|
||||
/// </summary>
|
||||
/// <param name="control"></param>
|
||||
/// <param name="lineRenderingType"></param>
|
||||
/// <param name="glowEffectAmount"></param>
|
||||
public void UpdateForegroundBlurEffect(ICanvasAnimatedControl control, LineRenderingType lineRenderingType, double glowEffectAmount)
|
||||
{
|
||||
if (ForegroundBlurEffect == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (ForegroundFontEffect == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var mask = GetAlphaMask(control, lineRenderingType);
|
||||
if (mask == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
ForegroundBlurEffect.BlurAmount = (float)glowEffectAmount;
|
||||
var alphaMaskEffect = (AlphaMaskEffect)ForegroundBlurEffect.Source;
|
||||
alphaMaskEffect.Source = ForegroundFontEffect;
|
||||
alphaMaskEffect.AlphaMask = mask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 销毁并重新创建高亮效果层
|
||||
/// 仅需在布局重构 (Relayout) 时调用
|
||||
/// </summary>
|
||||
/// <param name="control"></param>
|
||||
/// <param name="lineRenderingType"></param>
|
||||
public void RecreateForegroundHighlightEffect(ICanvasAnimatedControl control, LineRenderingType lineRenderingType)
|
||||
{
|
||||
ForegroundHighlightEffect?.Dispose();
|
||||
ForegroundHighlightEffect = null;
|
||||
|
||||
if (ForegroundFontEffect == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var mask = GetAlphaMask(control, lineRenderingType);
|
||||
if (mask == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ForegroundHighlightEffect = new AlphaMaskEffect
|
||||
{
|
||||
Source = ForegroundFontEffect,
|
||||
AlphaMask = mask,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 仅当前行需要调用此方法(每次 Update 都调用一次)
|
||||
/// </summary>
|
||||
/// <param name="control"></param>
|
||||
/// <param name="lineRenderingType"></param>
|
||||
public void UpdateForegroundHighlightEffect(ICanvasAnimatedControl control, LineRenderingType lineRenderingType)
|
||||
{
|
||||
if (ForegroundHighlightEffect == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (ForegroundFontEffect == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var mask = GetAlphaMask(control, lineRenderingType);
|
||||
if (mask == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ForegroundHighlightEffect.Source = ForegroundFontEffect;
|
||||
ForegroundHighlightEffect.AlphaMask = mask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 仅当前播放行需要调用此方法(每次 Update 都调用一次)
|
||||
/// </summary>
|
||||
/// <param name="control"></param>
|
||||
/// <param name="playingLineIndex"></param>
|
||||
/// <param name="charStartIndex"></param>
|
||||
/// <param name="charLength"></param>
|
||||
/// <param name="charProgress"></param>
|
||||
public void RecreateCurrentCharMask(ICanvasAnimatedControl control, int charStartIndex, int charLength, double charProgress)
|
||||
{
|
||||
CurrentCharMask?.Dispose();
|
||||
CurrentCharMask = null;
|
||||
CurrentCharMask = new CanvasCommandList(control);
|
||||
|
||||
if (CanvasTextLayout == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using var ds = CurrentCharMask.CreateDrawingSession();
|
||||
|
||||
var highlightRegion = CanvasTextLayout
|
||||
.GetCharacterRegions(charStartIndex, charLength)
|
||||
.FirstOrDefault();
|
||||
|
||||
double highlightTotalWidth = (double)highlightRegion.LayoutBounds.Width;
|
||||
// Draw the highlight for the current character
|
||||
double highlightWidth = highlightTotalWidth * charProgress;
|
||||
|
||||
double fadingWidth = (double)highlightRegion.LayoutBounds.Height / 2;
|
||||
|
||||
// Rects
|
||||
var highlightRect = new Rect(
|
||||
highlightRegion.LayoutBounds.X,
|
||||
highlightRegion.LayoutBounds.Y + Position.Y,
|
||||
highlightWidth,
|
||||
highlightRegion.LayoutBounds.Height
|
||||
);
|
||||
|
||||
var fadeInRect = new Rect(
|
||||
highlightRect.Right - fadingWidth,
|
||||
highlightRegion.LayoutBounds.Y + Position.Y,
|
||||
fadingWidth,
|
||||
highlightRegion.LayoutBounds.Height
|
||||
);
|
||||
var fadeOutRect = new Rect(
|
||||
highlightRect.Right,
|
||||
highlightRegion.LayoutBounds.Y + Position.Y,
|
||||
fadingWidth,
|
||||
highlightRegion.LayoutBounds.Height
|
||||
);
|
||||
|
||||
// Brushes
|
||||
using var fadeInBrush = CanvasHelper.CreateHorizontalFillBrush(
|
||||
control,
|
||||
[(0f, 0f), (1f, 1f)],
|
||||
(double)highlightRect.Right - fadingWidth,
|
||||
fadingWidth
|
||||
);
|
||||
using var fadeOutBrush = CanvasHelper.CreateHorizontalFillBrush(
|
||||
control,
|
||||
[(0f, 1f), (1f, 0f)],
|
||||
(double)highlightRect.Right,
|
||||
fadingWidth
|
||||
);
|
||||
|
||||
ds.FillRectangle(fadeInRect, fadeInBrush);
|
||||
ds.FillRectangle(fadeOutRect, fadeOutBrush);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 仅当前播放行需要调用此方法(每次 Update 都调用一次)
|
||||
/// </summary>
|
||||
/// <param name="control"></param>
|
||||
/// <param name="playingLineIndex"></param>
|
||||
/// <param name="charStartIndex"></param>
|
||||
/// <param name="charLength"></param>
|
||||
/// <param name="charProgress"></param>
|
||||
public void RecreateLineStartToCurrentCharMask(ICanvasAnimatedControl control, int charStartIndex, int charLength, double charProgress)
|
||||
{
|
||||
LineStartToCurrentCharMask?.Dispose();
|
||||
LineStartToCurrentCharMask = null;
|
||||
LineStartToCurrentCharMask = new CanvasCommandList(control);
|
||||
|
||||
if (CanvasTextLayout == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using var ds = LineStartToCurrentCharMask.CreateDrawingSession();
|
||||
|
||||
var regions = CanvasTextLayout.GetCharacterRegions(0, charStartIndex);
|
||||
var highlightRegion = CanvasTextLayout
|
||||
.GetCharacterRegions(charStartIndex, charLength)
|
||||
.FirstOrDefault();
|
||||
if (regions.Length > 0)
|
||||
{
|
||||
// Draw the mask for the current line
|
||||
for (int j = 0; j < regions.Length; j++)
|
||||
{
|
||||
var region = regions[j];
|
||||
var rect = new Rect(
|
||||
region.LayoutBounds.X,
|
||||
region.LayoutBounds.Y + Position.Y,
|
||||
region.LayoutBounds.Width,
|
||||
region.LayoutBounds.Height
|
||||
);
|
||||
ds.FillRectangle(rect, Color.FromArgb(255, 128, 128, 128));
|
||||
}
|
||||
}
|
||||
|
||||
double highlightTotalWidth = (double)highlightRegion.LayoutBounds.Width;
|
||||
// Draw the highlight for the current character
|
||||
double highlightWidth = highlightTotalWidth * charProgress;
|
||||
|
||||
double fadingWidth = (double)highlightRegion.LayoutBounds.Height / 2;
|
||||
|
||||
// Rects
|
||||
var highlightRect = new Rect(
|
||||
highlightRegion.LayoutBounds.X,
|
||||
highlightRegion.LayoutBounds.Y + Position.Y,
|
||||
highlightWidth,
|
||||
highlightRegion.LayoutBounds.Height
|
||||
);
|
||||
|
||||
var fadeInRect = new Rect(
|
||||
highlightRect.Right - fadingWidth,
|
||||
highlightRegion.LayoutBounds.Y + Position.Y,
|
||||
fadingWidth,
|
||||
highlightRegion.LayoutBounds.Height
|
||||
);
|
||||
var fadeOutRect = new Rect(
|
||||
highlightRect.Right,
|
||||
highlightRegion.LayoutBounds.Y + Position.Y,
|
||||
fadingWidth,
|
||||
highlightRegion.LayoutBounds.Height
|
||||
);
|
||||
|
||||
// Brushes
|
||||
using var fadeOutBrush = CanvasHelper.CreateHorizontalFillBrush(
|
||||
control,
|
||||
[(0f, 1f), (1f, 0f)],
|
||||
(double)highlightRect.Right,
|
||||
fadingWidth
|
||||
);
|
||||
|
||||
ds.FillRectangle(highlightRect, Color.FromArgb(255, 128, 128, 128));
|
||||
ds.FillRectangle(fadeOutRect, fadeOutBrush);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重建当前行遮罩
|
||||
/// 仅需在布局重构 (Relayout) 时调用
|
||||
/// </summary>
|
||||
/// <param name="control"></param>
|
||||
public void RecreateCurrentLineMask(ICanvasAnimatedControl control)
|
||||
{
|
||||
CurrentLineMask?.Dispose();
|
||||
CurrentLineMask = null;
|
||||
|
||||
if (CanvasTextLayout == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CurrentLineMask = new CanvasCommandList(control);
|
||||
using var ds = CurrentLineMask.CreateDrawingSession();
|
||||
|
||||
var regions = CanvasTextLayout.GetCharacterRegions(0, OriginalText.Length);
|
||||
if (regions.Length > 0)
|
||||
{
|
||||
for (int j = 0; j < regions.Length; j++)
|
||||
{
|
||||
var region = regions[j];
|
||||
var rect = new Rect(
|
||||
region.LayoutBounds.X,
|
||||
region.LayoutBounds.Y + Position.Y,
|
||||
region.LayoutBounds.Width,
|
||||
region.LayoutBounds.Height
|
||||
);
|
||||
ds.FillRectangle(rect, Colors.White);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void RecreatePlaceholder(ICanvasAnimatedControl control)
|
||||
{
|
||||
PlaceholderEffect?.Dispose();
|
||||
PlaceholderEffect = null;
|
||||
PlaceholderEffect = new CanvasCommandList(control);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,13 +5,11 @@ using CommunityToolkit.Mvvm.ComponentModel;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Models
|
||||
{
|
||||
public partial class LyricsSearchProviderInfo : ObservableObject
|
||||
public partial class LyricsSearchProviderInfo : ObservableRecipient
|
||||
{
|
||||
[ObservableProperty]
|
||||
public partial bool IsEnabled { get; set; }
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsEnabled { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial LyricsSearchProvider Provider { get; set; }
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsSearchProvider Provider { get; set; }
|
||||
|
||||
public LyricsSearchProviderInfo() { }
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// 2025/6/23 by Zhe Fang
|
||||
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using BetterLyrics.WinUI3.Extensions;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -9,47 +10,84 @@ using System.Linq;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Models
|
||||
{
|
||||
public partial class MediaSourceProviderInfo : ObservableObject
|
||||
public partial class MediaSourceProviderInfo : ObservableRecipient
|
||||
{
|
||||
[ObservableProperty]
|
||||
public partial bool IsEnabled { get; set; }
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsEnabled { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial string Provider { get; set; }
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial string Provider { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial bool IsLastFMTrackEnabled { get; set; }
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsLastFMTrackEnabled { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial int TimelineSyncThreshold { get; set; }
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int TimelineSyncThreshold { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial int PositionOffset { get; set; }
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int PositionOffset { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial bool ResetPositionOffsetOnSongChanged { get; set; }
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool ResetPositionOffsetOnSongChanged { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial ObservableCollection<LyricsSearchProviderInfo> LyricsSearchProvidersInfo { get; set; }
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial FullyObservableCollection<LyricsSearchProviderInfo> LyricsSearchProvidersInfo { get; set; }
|
||||
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial FullyObservableCollection<AlbumArtSearchProviderInfo> AlbumArtSearchProvidersInfo { get; set; }
|
||||
|
||||
public MediaSourceProviderInfo() { }
|
||||
|
||||
public MediaSourceProviderInfo(string provider)
|
||||
public MediaSourceProviderInfo(string provider) : base()
|
||||
{
|
||||
switch (provider)
|
||||
{
|
||||
case Constants.PlayerID.AppleMusic:
|
||||
// Apple Music 的特性
|
||||
TimelineSyncThreshold = 1000;
|
||||
PositionOffset = 1000;
|
||||
break;
|
||||
default:
|
||||
// 设置 100 以防不必要的重复同步
|
||||
TimelineSyncThreshold = 100;
|
||||
PositionOffset = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
Provider = provider;
|
||||
IsEnabled = true;
|
||||
IsLastFMTrackEnabled = false;
|
||||
if (provider == Constants.PlayerID.AppleMusic)
|
||||
{
|
||||
TimelineSyncThreshold = PositionOffset = 1000;
|
||||
}
|
||||
else
|
||||
{
|
||||
TimelineSyncThreshold = 0;
|
||||
PositionOffset = 0;
|
||||
}
|
||||
ResetPositionOffsetOnSongChanged = false;
|
||||
LyricsSearchProvidersInfo = [.. Enum.GetValues<LyricsSearchProvider>().Select(p => new LyricsSearchProviderInfo(p, true))];
|
||||
AlbumArtSearchProvidersInfo = [.. Enum.GetValues<AlbumArtSearchProvider>().Select(p => new AlbumArtSearchProviderInfo(p, true))];
|
||||
}
|
||||
|
||||
partial void OnAlbumArtSearchProvidersInfoChanged(FullyObservableCollection<AlbumArtSearchProviderInfo> oldValue, FullyObservableCollection<AlbumArtSearchProviderInfo> newValue)
|
||||
{
|
||||
oldValue?.CollectionChanged -= AlbumArtSearchProvidersInfo_CollectionChanged;
|
||||
oldValue?.ItemPropertyChanged -= AlbumArtSearchProvidersInfo_ItemPropertyChanged;
|
||||
newValue?.CollectionChanged += AlbumArtSearchProvidersInfo_CollectionChanged;
|
||||
newValue?.ItemPropertyChanged += AlbumArtSearchProvidersInfo_ItemPropertyChanged;
|
||||
}
|
||||
|
||||
partial void OnLyricsSearchProvidersInfoChanged(FullyObservableCollection<LyricsSearchProviderInfo> oldValue, FullyObservableCollection<LyricsSearchProviderInfo> newValue)
|
||||
{
|
||||
oldValue?.CollectionChanged -= LyricsSearchProvidersInfo_CollectionChanged;
|
||||
oldValue?.ItemPropertyChanged -= LyricsSearchProvidersInfo_ItemPropertyChanged;
|
||||
newValue?.CollectionChanged += LyricsSearchProvidersInfo_CollectionChanged;
|
||||
newValue?.ItemPropertyChanged += LyricsSearchProvidersInfo_ItemPropertyChanged;
|
||||
}
|
||||
|
||||
private void AlbumArtSearchProvidersInfo_ItemPropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||
{
|
||||
OnPropertyChanged(nameof(AlbumArtSearchProvidersInfo));
|
||||
}
|
||||
|
||||
private void AlbumArtSearchProvidersInfo_CollectionChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
OnPropertyChanged(nameof(AlbumArtSearchProvidersInfo));
|
||||
}
|
||||
|
||||
private void LyricsSearchProvidersInfo_CollectionChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
OnPropertyChanged(nameof(LyricsSearchProvidersInfo));
|
||||
}
|
||||
|
||||
private void LyricsSearchProvidersInfo_ItemPropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||
{
|
||||
OnPropertyChanged(nameof(LyricsSearchProvidersInfo));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Models.Settings
|
||||
{
|
||||
public partial class AlbumArtLayoutSettings : ObservableRecipient
|
||||
{
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial TextAlignmentType SongInfoAlignmentType { get; set; } = TextAlignmentType.Left;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int CoverImageRadius { get; set; } = 12; // 12 % of the cover image size
|
||||
|
||||
public AlbumArtLayoutSettings() { }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using BetterLyrics.WinUI3.Extensions;
|
||||
using BetterLyrics.WinUI3.Services;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Models.Settings
|
||||
{
|
||||
public partial class AppSettings : ObservableRecipient
|
||||
{
|
||||
public string Version { get; set; } = Helper.MetadataHelper.AppVersion;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsStyleSettings StandardLyricsStyleSettings { get; set; } = new LyricsStyleSettings(32, TextAlignmentType.Left, 0);
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsStyleSettings DesktopLyricsStyleSettings { get; set; } = new LyricsStyleSettings(28, TextAlignmentType.Center, 2);
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsStyleSettings DockLyricsStyleSettings { get; set; } = new LyricsStyleSettings(16, TextAlignmentType.Center, 0);
|
||||
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsEffectSettings StandardLyricsEffectSettings { get; set; } = new LyricsEffectSettings(100, 500, 1000, EasingType.EaseInOutSine);
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsEffectSettings DesktopLyricsEffectSettings { get; set; } = new LyricsEffectSettings(500, 500, 500, EasingType.EaseInOutSine);
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsEffectSettings DockLyricsEffectSettings { get; set; } = new LyricsEffectSettings(500, 500, 500, EasingType.EaseInOutSine);
|
||||
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial StandardModeSettings StandardModeSettings { get; set; } = new StandardModeSettings();
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial DesktopModeSettings DesktopModeSettings { get; set; } = new DesktopModeSettings();
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial DockModeSettings DockModeSettings { get; set; } = new DockModeSettings();
|
||||
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsBackgroundSettings LyricsBackgroundSettings { get; set; } = new LyricsBackgroundSettings();
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial AlbumArtLayoutSettings AlbumArtLayoutSettings { get; set; } = new AlbumArtLayoutSettings();
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial TranslationSettings TranslationSettings { get; set; } = new TranslationSettings();
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial GeneralSettings GeneralSettings { get; set; } = new GeneralSettings();
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial MusicGallerySettings MusicGallerySettings { get; set; } = new MusicGallerySettings();
|
||||
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial FullyObservableCollection<LocalMediaFolder> LocalMediaFolders { get; set; } = [];
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial FullyObservableCollection<MediaSourceProviderInfo> MediaSourceProvidersInfo { get; set; } = [];
|
||||
|
||||
public AppSettings() { }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.Foundation;
|
||||
using Windows.Graphics;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Models.Settings
|
||||
{
|
||||
public partial class DesktopModeSettings : ObservableRecipient
|
||||
{
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial Rect WindowBounds { get; set; } = new Rect(100, 100, 400, 200);
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool AutoLockOnDesktopMode { get; set; } = false;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int LockHotKeyIndex { get; set; } = 'U' - 'A'; // Default to 'U' key
|
||||
|
||||
public DesktopModeSettings() { }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Models.Settings
|
||||
{
|
||||
public partial class DockModeSettings : ObservableRecipient
|
||||
{
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial DockPlacement DockPlacement { get; set; } = DockPlacement.Top;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int DockWindowHeight { get; set; } = 64;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial string DockMonitorDeviceName { get; set; } = MonitorHelper.GetPrimaryMonitorDeviceName();
|
||||
|
||||
public DockModeSettings() { }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Models.Settings
|
||||
{
|
||||
public partial class GeneralSettings : ObservableRecipient
|
||||
{
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial AutoStartWindowType AutoStartWindowType { get; set; } = AutoStartWindowType.StandardMode;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial Language Language { get; set; } = Language.FollowSystem;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IgnoreFullscreenWindow { get; set; } = false;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial string LXMusicServer { get; set; } = string.Empty;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool HideWindowWhenNotPlaying { get; set; } = true;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsDragEverywhereEnabled { get; set; } = false;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsDisplayType DisplayType { get; set; } = LyricsDisplayType.SplitView;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsImmersiveMode { get; set; } = false;
|
||||
|
||||
public GeneralSettings() { }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Models.Settings
|
||||
{
|
||||
public partial class LastFMSettings : ObservableRecipient
|
||||
{
|
||||
public LastFMSettings() { }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Microsoft.UI.Xaml;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Models.Settings
|
||||
{
|
||||
public partial class LyricsBackgroundSettings : ObservableRecipient
|
||||
{
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial ElementTheme LyricsBackgroundTheme { get; set; } = ElementTheme.Dark;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int CoverOverlayBlurAmount { get; set; } = 100; // 100 % of the cover image size
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int CoverOverlayOpacity { get; set; } = 100; // 100 % = 1.0
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int PureColorOverlayOpacity { get; set; } = 100; // 100 % = 1.0
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int CoverOverlaySpeed { get; set; } = 50; // 50 % of the base rotate speed
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int CoverAcrylicEffectAmount { get; set; } = 0;
|
||||
|
||||
public LyricsBackgroundSettings() { }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Models.Settings
|
||||
{
|
||||
public partial class LyricsEffectSettings : ObservableRecipient
|
||||
{
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int LyricsBlurAmount { get; set; } = 5;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial LineRenderingType LyricsGlowEffectScope { get; set; } = LineRenderingType.CurrentChar;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial LineRenderingType LyricsHighlightScope { get; set; } = LineRenderingType.LineStartToCurrentChar;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsLyricsFloatAnimationEnabled { get; set; } = true;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int LyricsScrollDuration { get; set; }
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int LyricsScrollTopDuration { get; set; }
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int LyricsScrollBottomDuration { get; set; }
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int LyricsVerticalEdgeOpacity { get; set; } = 0; // 0% opacity
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsFanLyricsEnabled { get; set; } = false;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsLyricsGlowEffectEnabled { get; set; } = true;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial EasingType LyricsScrollEasingType { get; set; }
|
||||
|
||||
public LyricsEffectSettings(int lyricsScrollTopDuration, int lyricsScrollDuration, int lyricsScrollBottomDuration, EasingType lyricsScrollEasingType)
|
||||
{
|
||||
LyricsScrollTopDuration = lyricsScrollTopDuration;
|
||||
LyricsScrollDuration = lyricsScrollDuration;
|
||||
LyricsScrollBottomDuration = lyricsScrollBottomDuration;
|
||||
LyricsScrollEasingType = lyricsScrollEasingType;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Microsoft.UI;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.UI;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Models.Settings
|
||||
{
|
||||
public partial class LyricsStyleSettings : ObservableRecipient
|
||||
{
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int LyricsFontSize { get; set; }
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial TextAlignmentType LyricsAlignmentType { get; set; }
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int LyricsBgFontOpacity { get; set; } = 30; // 30% opacity
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int LyricsFontStrokeWidth { get; set; }
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial Color LyricsCustomBgFontColor { get; set; } = Colors.White;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial Color LyricsCustomFgFontColor { get; set; } = Colors.White;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial Color LyricsCustomStrokeFontColor { get; set; } = Colors.White;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsFontColorType LyricsBgFontColorType { get; set; } = LyricsFontColorType.AdaptiveGrayed;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsFontColorType LyricsFgFontColorType { get; set; } = LyricsFontColorType.AdaptiveGrayed;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsFontColorType LyricsStrokeFontColorType { get; set; } = LyricsFontColorType.AdaptiveGrayed;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsFontWeight LyricsFontWeight { get; set; } = LyricsFontWeight.Bold;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial double LyricsLineSpacingFactor { get; set; } = 0.5;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial string LyricsTranslationSeparator { get; set; } = StringHelper.NewLine;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial string LyricsFontFamily { get; set; } = FontHelper.SystemFontFamilies.FirstOrDefault() ?? "";
|
||||
|
||||
public LyricsStyleSettings() { }
|
||||
|
||||
public LyricsStyleSettings(int lyricsFontSize, TextAlignmentType lyricsAlignmentType, int lyricsFontStrokeWidth)
|
||||
{
|
||||
LyricsFontSize = lyricsFontSize;
|
||||
LyricsAlignmentType = lyricsAlignmentType;
|
||||
LyricsFontStrokeWidth = lyricsFontStrokeWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Models.Settings
|
||||
{
|
||||
public partial class MusicGallerySettings : ObservableRecipient
|
||||
{
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial PlaybackOrder PlaybackOrder { get; set; } = PlaybackOrder.RepeatAll;
|
||||
|
||||
public MusicGallerySettings() { }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.Foundation;
|
||||
using Windows.Graphics;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Models.Settings
|
||||
{
|
||||
public partial class StandardModeSettings : ObservableRecipient
|
||||
{
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial Rect WindowBounds { get; set; } = new Rect(100, 100, 1000, 600);
|
||||
|
||||
public StandardModeSettings() { }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using BetterLyrics.WinUI3.Services;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Models.Settings
|
||||
{
|
||||
public partial class TranslationSettings : ObservableRecipient
|
||||
{
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsLibreTranslateEnabled { get; set; } = false;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial string LibreTranslateServer { get; set; } = string.Empty;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsTranslationEnabled { get; set; } = true;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool ShowTranslationOnly { get; set; } = false;
|
||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int SelectedTargetLanguageIndex { get; set; } = LanguageHelper.GetDefaultTargetLanguageIndex();
|
||||
|
||||
public TranslationSettings() { }
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@
|
||||
<canvas:CanvasAnimatedControl
|
||||
x:Name="LyricsCanvas"
|
||||
Draw="LyricsCanvas_Draw"
|
||||
Paused="{x:Bind ViewModel.IsPlaying, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}"
|
||||
Update="LyricsCanvas_Update" />
|
||||
<Grid
|
||||
Margin="36"
|
||||
|
||||
@@ -1,20 +1,15 @@
|
||||
// 2025/6/23 by Zhe Fang
|
||||
|
||||
using System.Collections.Generic;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.Models.Settings;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Serialization
|
||||
{
|
||||
|
||||
[JsonSerializable(typeof(List<AlbumArtSearchProviderInfo>))]
|
||||
[JsonSerializable(typeof(List<LyricsSearchProviderInfo>))]
|
||||
[JsonSerializable(typeof(List<MediaSourceProviderInfo>))]
|
||||
[JsonSerializable(typeof(List<LocalMediaFolder>))]
|
||||
[JsonSerializable(typeof(List<string>))]
|
||||
[JsonSerializable(typeof(TranslateResponse))]
|
||||
[JsonSerializable(typeof(JsonElement))]
|
||||
[JsonSerializable(typeof(AppSettings))]
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
internal partial class SourceGenerationContext : JsonSerializerContext { }
|
||||
}
|
||||
|
||||
@@ -10,8 +10,6 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -31,11 +29,11 @@ namespace BetterLyrics.WinUI3.Services.AlbumArtSearchService
|
||||
_iTunesHttpClinet = new();
|
||||
}
|
||||
|
||||
public async Task<byte[]?> SearchAsync(string title, string artist, string album, byte[]? bytesFromSMTC = null)
|
||||
public async Task<byte[]?> SearchAsync(string mediaSessionId, string title, string artist, string album, byte[]? bytesFromSMTC = null)
|
||||
{
|
||||
byte[]? result = null;
|
||||
|
||||
foreach (var provider in _settingsService.AlbumArtSearchProvidersInfo)
|
||||
foreach (var provider in _settingsService.AppSettings.MediaSourceProvidersInfo.Where(x => x.Provider == mediaSessionId).FirstOrDefault()?.AlbumArtSearchProvidersInfo ?? [])
|
||||
{
|
||||
if (!provider.IsEnabled)
|
||||
{
|
||||
@@ -45,7 +43,7 @@ namespace BetterLyrics.WinUI3.Services.AlbumArtSearchService
|
||||
switch (provider.Provider)
|
||||
{
|
||||
case AlbumArtSearchProvider.Local:
|
||||
result = SearchFile(artist, album);
|
||||
result = SearchFile(artist, title);
|
||||
break;
|
||||
case AlbumArtSearchProvider.SMTC:
|
||||
result = bytesFromSMTC;
|
||||
@@ -66,15 +64,15 @@ namespace BetterLyrics.WinUI3.Services.AlbumArtSearchService
|
||||
return null;
|
||||
}
|
||||
|
||||
private byte[]? SearchFile(string artist, string album)
|
||||
private byte[]? SearchFile(string artist, string title)
|
||||
{
|
||||
foreach (var folder in _settingsService.LocalMediaFolders)
|
||||
foreach (var folder in _settingsService.AppSettings.LocalMediaFolders)
|
||||
{
|
||||
if (Directory.Exists(folder.Path) && folder.IsEnabled)
|
||||
{
|
||||
foreach (var file in Directory.GetFiles(folder.Path, $"*.*", SearchOption.AllDirectories))
|
||||
{
|
||||
if (FileHelper.IsSwitchableNormalizedMatch(Path.GetFileNameWithoutExtension(file), album, artist))
|
||||
if (FileHelper.IsSwitchableNormalizedMatch(Path.GetFileNameWithoutExtension(file), title, artist))
|
||||
{
|
||||
Track track = new(file);
|
||||
var bytes = track.EmbeddedPictures.FirstOrDefault()?.PictureData;
|
||||
|
||||
@@ -8,6 +8,6 @@ namespace BetterLyrics.WinUI3.Services.AlbumArtSearchService
|
||||
{
|
||||
public interface IAlbumArtSearchService
|
||||
{
|
||||
Task<byte[]?> SearchAsync(string title, string artist, string album, byte[]? bytesFromSMTC = null);
|
||||
Task<byte[]?> SearchAsync(string mediaSessionId, string title, string artist, string album, byte[]? bytesFromSMTC = null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ using BetterLyrics.WinUI3.Helper;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.Services.SettingsService;
|
||||
using BetterLyrics.WinUI3.ViewModels;
|
||||
using BetterLyrics.WinUI3.ViewModels.SettingsPageViewModel;
|
||||
using BetterLyrics.WinUI3.Views;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
@@ -40,7 +39,7 @@ namespace BetterLyrics.WinUI3.Services.LastFMService
|
||||
_settingsService = settingsService;
|
||||
|
||||
_client = new LastfmClient(Constants.LastFM.ApiKey, Constants.LastFM.SharedSecret);
|
||||
_client.Session.SessionKey = _settingsService.LastFMSessionKey;
|
||||
_client.Session.SessionKey = PasswordVaultHelper.Get(Constants.App.AppName, Constants.LastFM.SessionKeyCredentialKey) ?? string.Empty;
|
||||
UpdateAuthStatusAsync();
|
||||
}
|
||||
|
||||
@@ -49,7 +48,7 @@ namespace BetterLyrics.WinUI3.Services.LastFMService
|
||||
try
|
||||
{
|
||||
await _client.AuthenticateViaWebAsync();
|
||||
_settingsService.LastFMSessionKey = _client.Session.SessionKey;
|
||||
PasswordVaultHelper.Save(Constants.App.AppName, Constants.LastFM.SessionKeyCredentialKey, _client.Session.SessionKey);
|
||||
await UpdateAuthStatusAsync();
|
||||
}
|
||||
catch (Exception)
|
||||
@@ -61,7 +60,7 @@ namespace BetterLyrics.WinUI3.Services.LastFMService
|
||||
public async Task ConfirmUnAuthAsync()
|
||||
{
|
||||
_client.Session.SessionKey = "";
|
||||
_settingsService.LastFMSessionKey = "";
|
||||
PasswordVaultHelper.Delete(Constants.App.AppName, Constants.LastFM.SessionKeyCredentialKey);
|
||||
await UpdateAuthStatusAsync();
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,5 @@ namespace BetterLyrics.WinUI3.Services.LibWatcherService
|
||||
public interface ILibWatcherService
|
||||
{
|
||||
event EventHandler<LibChangedEventArgs>? MusicLibraryFilesChanged;
|
||||
|
||||
public void UpdateWatchers(List<LocalMediaFolder> folders);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,11 +14,25 @@ namespace BetterLyrics.WinUI3.Services.LibWatcherService
|
||||
{
|
||||
public class LibWatcherService : BaseViewModel, IDisposable, ILibWatcherService
|
||||
{
|
||||
private readonly ISettingsService _settingsService;
|
||||
private readonly Dictionary<string, FileSystemWatcher> _watchers = [];
|
||||
|
||||
public LibWatcherService(ISettingsService settingsService) : base(settingsService)
|
||||
public LibWatcherService(ISettingsService settingsService)
|
||||
{
|
||||
UpdateWatchers(_settingsService.LocalMediaFolders);
|
||||
_settingsService = settingsService;
|
||||
_settingsService.AppSettings.LocalMediaFolders.CollectionChanged += LocalMediaFolders_CollectionChanged;
|
||||
_settingsService.AppSettings.LocalMediaFolders.ItemPropertyChanged += LocalMediaFolders_ItemPropertyChanged;
|
||||
UpdateWatchers();
|
||||
}
|
||||
|
||||
private void LocalMediaFolders_ItemPropertyChanged(object? sender, Extensions.ItemPropertyChangedEventArgs e)
|
||||
{
|
||||
UpdateWatchers();
|
||||
}
|
||||
|
||||
private void LocalMediaFolders_CollectionChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
UpdateWatchers();
|
||||
}
|
||||
|
||||
public event EventHandler<LibChangedEventArgs>? MusicLibraryFilesChanged;
|
||||
@@ -32,8 +46,9 @@ namespace BetterLyrics.WinUI3.Services.LibWatcherService
|
||||
_watchers.Clear();
|
||||
}
|
||||
|
||||
public void UpdateWatchers(List<LocalMediaFolder> folders)
|
||||
private void UpdateWatchers()
|
||||
{
|
||||
var folders = _settingsService.AppSettings.LocalMediaFolders;
|
||||
// 移除不再监听的
|
||||
foreach (var key in _watchers.Keys.ToList())
|
||||
{
|
||||
|
||||
@@ -92,7 +92,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
|
||||
try
|
||||
{
|
||||
foreach (var provider in _settingsService.MediaSourceProvidersInfo.Where(x => x.Provider == mediaSessionId).FirstOrDefault()?.LyricsSearchProvidersInfo ?? [])
|
||||
foreach (var provider in _settingsService.AppSettings.MediaSourceProvidersInfo.Where(x => x.Provider == mediaSessionId).FirstOrDefault()?.LyricsSearchProvidersInfo ?? [])
|
||||
{
|
||||
if (!provider.IsEnabled)
|
||||
{
|
||||
@@ -169,7 +169,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
|
||||
private async Task<string?> SearchFile(string title, string artist, LyricsFormat format)
|
||||
{
|
||||
foreach (var folder in _settingsService.LocalMediaFolders)
|
||||
foreach (var folder in _settingsService.AppSettings.LocalMediaFolders)
|
||||
{
|
||||
if (Directory.Exists(folder.Path) && folder.IsEnabled)
|
||||
{
|
||||
@@ -191,7 +191,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
|
||||
|
||||
private string? SearchEmbedded(string title, string artist)
|
||||
{
|
||||
foreach (var folder in _settingsService.LocalMediaFolders)
|
||||
foreach (var folder in _settingsService.AppSettings.LocalMediaFolders)
|
||||
{
|
||||
if (Directory.Exists(folder.Path) && folder.IsEnabled)
|
||||
{
|
||||
|
||||
@@ -21,6 +21,8 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
|
||||
Task NextAsync();
|
||||
Task ChangePosition(double seconds);
|
||||
|
||||
MediaSourceProviderInfo? GetCurrentMediaSourceProviderInfo();
|
||||
|
||||
bool IsPlaying { get; }
|
||||
SongInfo? SongInfo { get; }
|
||||
TimeSpan Position { get; }
|
||||
|
||||
@@ -2,18 +2,20 @@
|
||||
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using BetterLyrics.WinUI3.Events;
|
||||
using BetterLyrics.WinUI3.Extensions;
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.Models.Settings;
|
||||
using BetterLyrics.WinUI3.Services.AlbumArtSearchService;
|
||||
using BetterLyrics.WinUI3.Services.LastFMService;
|
||||
using BetterLyrics.WinUI3.Services.SettingsService;
|
||||
using BetterLyrics.WinUI3.ViewModels;
|
||||
using BetterLyrics.WinUI3.ViewModels.SettingsPageViewModel;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using CommunityToolkit.Mvvm.Messaging.Messages;
|
||||
using EvtSource;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Graphics.Canvas;
|
||||
using Microsoft.UI.Dispatching;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
using System;
|
||||
@@ -33,11 +35,12 @@ using WindowsMediaController;
|
||||
namespace BetterLyrics.WinUI3.Services.MediaSessionsService
|
||||
{
|
||||
public partial class MediaSessionsService : BaseViewModel, IMediaSessionsService,
|
||||
IRecipient<PropertyChangedMessage<ObservableCollection<MediaSourceProviderInfo>>>,
|
||||
IRecipient<PropertyChangedMessage<ObservableCollection<AlbumArtSearchProviderInfo>>>
|
||||
IRecipient<PropertyChangedMessage<bool>>,
|
||||
IRecipient<PropertyChangedMessage<FullyObservableCollection<AlbumArtSearchProviderInfo>>>
|
||||
{
|
||||
private readonly IAlbumArtSearchService _albumArtSearchService;
|
||||
private readonly ILogger<MediaSessionsService> _logger;
|
||||
private readonly ISettingsService _settingsService;
|
||||
|
||||
private double _lxMusicPositionSeconds = 0;
|
||||
private double _lxMusicDurationSeconds = 0;
|
||||
@@ -53,9 +56,8 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
|
||||
private readonly LatestOnlyTaskRunner _onAnyMediaPropertyChangedRunner = new();
|
||||
|
||||
private SongInfo? _cachedSongInfo;
|
||||
private List<MediaSourceProviderInfo> _mediaSourceProvidersInfo;
|
||||
private byte[]? _SMTCAlbumArtBytes = null;
|
||||
private int _targetAlbumArtSize = 400;
|
||||
private int _targetAlbumArtSize = 500;
|
||||
|
||||
public event EventHandler<IsPlayingChangedEventArgs>? IsPlayingChanged;
|
||||
public event EventHandler<TimelineChangedEventArgs>? TimelineChanged;
|
||||
@@ -63,22 +65,39 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
|
||||
public event EventHandler<AlbumArtChangedEventArgs>? AlbumArtChangedChanged;
|
||||
public event EventHandler<MediaSourceProvidersInfoEventArgs>? MediaSourceProvidersInfoChanged;
|
||||
|
||||
public MediaSessionsService(ISettingsService settingsService, IAlbumArtSearchService albumArtSearchService) : base(settingsService)
|
||||
public MediaSessionsService(ISettingsService settingsService, IAlbumArtSearchService albumArtSearchService)
|
||||
{
|
||||
_settingsService = settingsService;
|
||||
_albumArtSearchService = albumArtSearchService;
|
||||
_logger = Ioc.Default.GetRequiredService<ILogger<MediaSessionsService>>();
|
||||
|
||||
_mediaSourceProvidersInfo = _settingsService.MediaSourceProvidersInfo;
|
||||
_settingsService.AppSettings.MediaSourceProvidersInfo.ItemPropertyChanged += MediaSourceProvidersInfo_ItemPropertyChanged;
|
||||
|
||||
InitMediaManager();
|
||||
}
|
||||
|
||||
private void MediaSourceProvidersInfo_ItemPropertyChanged(object? sender, ItemPropertyChangedEventArgs e)
|
||||
{
|
||||
switch (e.PropertyName)
|
||||
{
|
||||
case nameof(MediaSourceProviderInfo.AlbumArtSearchProvidersInfo):
|
||||
_ = _albumArtRefreshRunner.RunAsync(async tokne =>
|
||||
{
|
||||
await UpdateAlbumArtRelated(tokne);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsPlaying => _cachedIsPlaying;
|
||||
public SongInfo? SongInfo => _cachedSongInfo;
|
||||
public TimeSpan Position => _cachedPosition;
|
||||
|
||||
private bool IsMediaSourceEnabled(string id)
|
||||
{
|
||||
return _mediaSourceProvidersInfo.FirstOrDefault(s => s.Provider == id)?.IsEnabled ?? true;
|
||||
return _settingsService.AppSettings.MediaSourceProvidersInfo.FirstOrDefault(s => s.Provider == id)?.IsEnabled ?? true;
|
||||
}
|
||||
|
||||
private void InitMediaManager()
|
||||
@@ -94,6 +113,7 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
|
||||
Task.Run(() =>
|
||||
{
|
||||
MediaManager_OnFocusedSessionChanged(null);
|
||||
_mediaManager.CurrentMediaSessions.ToList().ForEach(x => RecordMediaSourceProviderInfo(x.Value));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -138,7 +158,7 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
|
||||
|
||||
var focusedSession = _mediaManager.GetFocusedSession();
|
||||
|
||||
RecordMediaSourceProviderInfo(mediaSession);
|
||||
//RecordMediaSourceProviderInfo(mediaSession);
|
||||
if (mediaSession != focusedSession) return;
|
||||
|
||||
if (!IsMediaSourceEnabled(mediaSession.Id))
|
||||
@@ -169,7 +189,7 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
|
||||
|
||||
var focusedSession = _mediaManager.GetFocusedSession();
|
||||
|
||||
RecordMediaSourceProviderInfo(mediaSession);
|
||||
//RecordMediaSourceProviderInfo(mediaSession);
|
||||
if (mediaSession != focusedSession) return;
|
||||
|
||||
if (!IsMediaSourceEnabled(id))
|
||||
@@ -204,6 +224,15 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
|
||||
}
|
||||
else
|
||||
{
|
||||
_dispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, () =>
|
||||
{
|
||||
var currentMediaSourceProviderInfo = GetCurrentMediaSourceProviderInfo();
|
||||
if (currentMediaSourceProviderInfo?.ResetPositionOffsetOnSongChanged == true)
|
||||
{
|
||||
currentMediaSourceProviderInfo?.PositionOffset = 0;
|
||||
}
|
||||
});
|
||||
|
||||
_cachedSongInfo = new SongInfo
|
||||
{
|
||||
Title = mediaProperties.Title,
|
||||
@@ -282,18 +311,14 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
|
||||
var id = mediaSession?.Id;
|
||||
if (string.IsNullOrEmpty(id)) return;
|
||||
|
||||
var found = _mediaSourceProvidersInfo.FirstOrDefault(x => x.Provider == id);
|
||||
if (found == null)
|
||||
_dispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, () =>
|
||||
{
|
||||
_mediaSourceProvidersInfo.Add(new MediaSourceProviderInfo(id));
|
||||
// 在这里就写进设置
|
||||
// 因为 SettingsPageViewModel 可能还没有初始化
|
||||
_settingsService.MediaSourceProvidersInfo = _mediaSourceProvidersInfo;
|
||||
_dispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, () =>
|
||||
var found = _settingsService.AppSettings.MediaSourceProvidersInfo.FirstOrDefault(x => x.Provider == id);
|
||||
if (found == null)
|
||||
{
|
||||
MediaSourceProvidersInfoChanged?.Invoke(this, new MediaSourceProvidersInfoEventArgs(_mediaSourceProvidersInfo));
|
||||
});
|
||||
}
|
||||
_settingsService.AppSettings.MediaSourceProvidersInfo.Add(new MediaSourceProviderInfo(id));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void SendNullMessages()
|
||||
@@ -328,6 +353,7 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
|
||||
}
|
||||
|
||||
byte[]? bytes = await _albumArtSearchService.SearchAsync(
|
||||
SongInfo?.SourceAppUserModelId ?? "",
|
||||
_cachedSongInfo.Title,
|
||||
_cachedSongInfo.Artist,
|
||||
_cachedSongInfo?.Album ?? string.Empty,
|
||||
@@ -367,7 +393,7 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
|
||||
{
|
||||
try
|
||||
{
|
||||
_sse = new EventSourceReader(new Uri($"{_settingsService.LXMusicServer}{Constants.LXMusic.QuerySuffix}")).Start();
|
||||
_sse = new EventSourceReader(new Uri($"{_settingsService.AppSettings.GeneralSettings.LXMusicServer}{Constants.LXMusic.QuerySuffix}")).Start();
|
||||
_sse.MessageReceived += Sse_MessageReceived;
|
||||
_sse.Disconnected += Sse_Disconnected;
|
||||
}
|
||||
@@ -470,26 +496,24 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
|
||||
}
|
||||
}
|
||||
|
||||
public void Receive(PropertyChangedMessage<ObservableCollection<MediaSourceProviderInfo>> message)
|
||||
public MediaSourceProviderInfo? GetCurrentMediaSourceProviderInfo()
|
||||
{
|
||||
if (message.Sender is SettingsPageViewModel)
|
||||
return _settingsService.AppSettings.MediaSourceProvidersInfo.Where(x => x.Provider == _cachedSongInfo?.SourceAppUserModelId)?.FirstOrDefault();
|
||||
}
|
||||
|
||||
public async void Receive(PropertyChangedMessage<bool> message)
|
||||
{
|
||||
if (message.Sender is MediaSourceProviderInfo)
|
||||
{
|
||||
if (message.PropertyName == nameof(SettingsPageViewModel.MediaSourceProvidersInfo))
|
||||
if (message.PropertyName == nameof(MediaSourceProviderInfo.IsEnabled))
|
||||
{
|
||||
_mediaSourceProvidersInfo = [.. message.NewValue];
|
||||
MediaManager_OnFocusedSessionChanged(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async void Receive(PropertyChangedMessage<ObservableCollection<AlbumArtSearchProviderInfo>> message)
|
||||
{
|
||||
if (message.Sender is SettingsPageViewModel)
|
||||
else if (message.Sender is AlbumArtSearchProviderInfo)
|
||||
{
|
||||
if (message.PropertyName == nameof(SettingsPageViewModel.AlbumArtSearchProvidersInfo))
|
||||
if (message.PropertyName == nameof(AlbumArtSearchProviderInfo.IsEnabled))
|
||||
{
|
||||
// Album art search providers info changed, re-fetch album art
|
||||
_logger.LogInformation("Album art search providers info changed, refreshing album art.");
|
||||
await _albumArtRefreshRunner.RunAsync(async tokne =>
|
||||
{
|
||||
await UpdateAlbumArtRelated(tokne);
|
||||
@@ -497,5 +521,9 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Receive(PropertyChangedMessage<FullyObservableCollection<AlbumArtSearchProviderInfo>> message)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
using System.Collections.Generic;
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.Models.Settings;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Windows.UI;
|
||||
|
||||
@@ -10,104 +11,10 @@ namespace BetterLyrics.WinUI3.Services.SettingsService
|
||||
{
|
||||
public interface ISettingsService
|
||||
{
|
||||
AppSettings AppSettings { get; set; }
|
||||
// App behavior
|
||||
|
||||
AutoStartWindowType AutoStartWindowType { get; set; }
|
||||
|
||||
int CoverImageRadius { get; set; }
|
||||
|
||||
int CoverOverlayBlurAmount { get; set; }
|
||||
int CoverOverlayOpacity { get; set; }
|
||||
bool IsDynamicCoverOverlayEnabled { get; set; }
|
||||
int CoverAcrylicEffectAmount { get; set; }
|
||||
bool IsFanLyricsEnabled { get; set; }
|
||||
bool IsFirstRun { get; set; }
|
||||
bool IsLyricsGlowEffectEnabled { get; set; }
|
||||
Language Language { get; set; }
|
||||
int DesktopWindowLeft { get; set; }
|
||||
int DesktopWindowTop { get; set; }
|
||||
int DesktopWindowWidth { get; set; }
|
||||
int DesktopWindowHeight { get; set; }
|
||||
|
||||
int StandardWindowWidth { get; set; }
|
||||
int StandardWindowHeight { get; set; }
|
||||
int StandardWindowLeft { get; set; }
|
||||
int StandardWindowTop { get; set; }
|
||||
|
||||
bool AutoLockOnDesktopMode { get; set; }
|
||||
|
||||
string LibreTranslateServer { get; set; }
|
||||
int SelectedTargetLanguageIndex { get; set; }
|
||||
int PositionOffset { get; set; }
|
||||
// Lyrics lib
|
||||
|
||||
List<LocalMediaFolder> LocalMediaFolders { get; set; }
|
||||
|
||||
// Lyrics style and effetc
|
||||
|
||||
TextAlignmentType LyricsAlignmentType { get; set; }
|
||||
TextAlignmentType SongInfoAlignmentType { get; set; }
|
||||
|
||||
int LyricsBlurAmount { get; set; }
|
||||
|
||||
Color LyricsCustomBgFontColor { get; set; }
|
||||
Color LyricsCustomFgFontColor { get; set; }
|
||||
Color LyricsCustomStrokeFontColor { get; set; }
|
||||
|
||||
int LyricsBgFontOpacity { get; set; }
|
||||
|
||||
LyricsFontColorType LyricsBgFontColorType { get; set; }
|
||||
LyricsFontColorType LyricsFgFontColorType { get; set; }
|
||||
LyricsFontColorType LyricsStrokeFontColorType { get; set; }
|
||||
|
||||
int LyricsStandardFontSize { get; set; }
|
||||
int LyricsDockFontSize { get; set; }
|
||||
int LyricsDesktopFontSize { get; set; }
|
||||
|
||||
ElementTheme LyricsBackgroundTheme { get; set; }
|
||||
|
||||
int LyricsFontStrokeWidth { get; set; }
|
||||
|
||||
LyricsFontWeight LyricsFontWeight { get; set; }
|
||||
|
||||
LineRenderingType LyricsGlowEffectScope { get; set; }
|
||||
LineRenderingType LyricsHighlightScope { get; set; }
|
||||
|
||||
bool IsLyricsFloatAnimationEnabled { get; set; }
|
||||
|
||||
float LyricsLineSpacingFactor { get; set; }
|
||||
|
||||
List<AlbumArtSearchProviderInfo> AlbumArtSearchProvidersInfo { get; set; }
|
||||
List<MediaSourceProviderInfo> MediaSourceProvidersInfo { get; set; }
|
||||
|
||||
EasingType LyricsScrollEasingType { get; set; }
|
||||
int LyricsScrollDuration { get; set; }
|
||||
|
||||
int LyricsVerticalEdgeOpacity { get; set; }
|
||||
|
||||
bool IgnoreFullscreenWindow { get; set; }
|
||||
|
||||
bool IsTranslationEnabled { get; set; }
|
||||
bool ShowTranslationOnly { get; set; }
|
||||
|
||||
LyricsDisplayType DisplayType { get; set; }
|
||||
|
||||
int LockHotKeyIndex { get; set; }
|
||||
bool IsImmersiveMode { get; set; }
|
||||
string LXMusicServer { get; set; }
|
||||
DockPlacement DockPlacement { get; set; }
|
||||
bool HideWindowWhenNotPlaying { get; set; }
|
||||
int DockWindowHeight { get; set; }
|
||||
int SelectedFontFamilyIndex { get; set; }
|
||||
string LyricsFontFamily { get; set; }
|
||||
bool IsDragEverywhereEnabled { get; set; }
|
||||
PlaybackOrder PlaybackOrder { get; set; }
|
||||
bool IsLibreTranslateEnabled { get; set; }
|
||||
string DockMonitorDeviceName { get; set; }
|
||||
|
||||
// LastFM
|
||||
string LastFMSessionKey { get; set; }
|
||||
|
||||
string LyricsTranslationSeparator { get; set; }
|
||||
bool ImportSettings(string importPath);
|
||||
void ExportSettings(string exportPath);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,708 +1,213 @@
|
||||
// 2025/6/23 by Zhe Fang
|
||||
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using BetterLyrics.WinUI3.Extensions;
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.Models.Settings;
|
||||
using BetterLyrics.WinUI3.Serialization;
|
||||
using CommunityToolkit.WinUI.Helpers;
|
||||
using Microsoft.UI;
|
||||
using Microsoft.UI.Xaml;
|
||||
using BetterLyrics.WinUI3.ViewModels;
|
||||
using BetterLyrics.WinUI3.Views;
|
||||
using CommunityToolkit.WinUI;
|
||||
using Microsoft.UI.Dispatching;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Windows.Media.Core;
|
||||
using Windows.Storage;
|
||||
using Windows.UI;
|
||||
using Windows.Globalization;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Services.SettingsService
|
||||
{
|
||||
public class SettingsService : ISettingsService
|
||||
// TODO 初始化时从文件读取到对象,后续独写操作先操纵对象,写入用 Debounce 写入文件
|
||||
// 新建一个 AppSettings 类
|
||||
public partial class SettingsService : BaseViewModel, ISettingsService
|
||||
{
|
||||
public const string LyricsCustomBgFontColorKey = "LyricsCustomBgFontColor";
|
||||
public const string LyricsCustomFgFontColorKey = "LyricsCustomFgFontColor";
|
||||
public const string LyricsCustomStrokeFontColorKey = "LyricsCustomStrokeFontColor";
|
||||
|
||||
// App behavior
|
||||
|
||||
private const string AutoStartWindowTypeKey = "AutoStartWindowType";
|
||||
|
||||
private const string CoverImageRadiusKey = "AlbumArtCornerRadius";
|
||||
private const string CoverOverlayBlurAmountKey = "CoverOverlayBlurAmount";
|
||||
private const string CoverOverlayOpacityKey = "CoverOverlayOpacity";
|
||||
private const string IsCoverOverlayEnabledKey = "IsCoverOverlayEnabled";
|
||||
|
||||
private const string CoverAcrylicEffectAmountKey = "CoverAcrylicEffectAmount";
|
||||
|
||||
private const string DesktopWindowLeftKey = "DesktopWindowLeft";
|
||||
private const string DesktopWindowTopKey = "DesktopWindowTop";
|
||||
private const string DesktopWindowWidthKey = "DesktopWindowWidth";
|
||||
private const string DesktopWindowHeightKey = "DesktopWindowHeight";
|
||||
|
||||
private const string StandardWindowLeftKey = "StandardWindowLeft";
|
||||
private const string StandardWindowTopKey = "StandardWindowTop";
|
||||
private const string StandardWindowWidthKey = "StandardWindowWidth";
|
||||
private const string StandardWindowHeightKey = "StandardWindowHeight";
|
||||
|
||||
private const string AutoLockOnDesktopModeKey = "AutoLockOnDesktopMode";
|
||||
private const string IsImmersiveModeKey = "IsImmersiveMode";
|
||||
|
||||
private const string IsDynamicCoverOverlayEnabledKey = "IsDynamicCoverOverlayEnabled";
|
||||
private const string IsFanLyricsEnabledKey = "IsFanLyricsEnabled";
|
||||
private const string IsFirstRunKey = "IsFirstRun";
|
||||
private const string IsLyricsGlowEffectEnabledKey = "IsLyricsGlowEffectEnabled";
|
||||
private const string LanguageKey = "Language";
|
||||
|
||||
private const string LocalMediaFoldersKey = "LocalLyricsFolders";
|
||||
private const string LyricsAlignmentTypeKey = "TextAlignmentType";
|
||||
private const string SongInfoAlignmentTypeKey = "SongInfoAlignmentType";
|
||||
private const string LyricsBlurAmountKey = "LyricsBlurAmount";
|
||||
|
||||
private const string LyricsBgFontColorTypeKey = "_lyricsBgFontColorType";
|
||||
private const string LyricsFgFontColorTypeKey = "LyricsFgFontColorType";
|
||||
private const string LyricsStrokeFontColorTypeKey = "LyricsStrokeFontColorType";
|
||||
|
||||
private const string LyricsFontStrokeWidthKey = "LyricsFontStrokeWidth";
|
||||
|
||||
// Lyrics font size
|
||||
private const string LyricsStandardFontSizeKey = "LyricsStandardFontSize";
|
||||
private const string LyricsDockFontSizeKey = "LyricsDockFontSize";
|
||||
private const string LyricsDesktopFontSizeKey = "LyricsDesktopFontSize";
|
||||
|
||||
private const string LyricsFontWeightKey = "LyricsFontWeightKey";
|
||||
private const string LyricsGlowEffectScopeKey = "LyricsGlowEffectScope";
|
||||
private const string LyricsHighlightSopeKey = "LyricsHighlightSope";
|
||||
private const string LyricsLineSpacingFactorKey = "LyricsLineSpacingFactor";
|
||||
private const string AlbumArtSearchProvidersInfoKey = "AlbumArtSearchProvidersInfo";
|
||||
private const string LyricsVerticalEdgeOpacityKey = "LyricsVerticalEdgeOpacity";
|
||||
|
||||
private const string MediaSourceProvidersInfoKey = "MediaSourceProvidersInfo";
|
||||
|
||||
// Translation
|
||||
private const string IsTranslationEnabledKey = "IsTranslationEnabled";
|
||||
private const string ShowTranslationOnlyKey = "ShowTranslationOnly";
|
||||
private const string IsLibreTranslateEnabledKey = "IsLibreTranslateEnabled";
|
||||
private const string LibreTranslateServerKey = "LibreTranslateServer";
|
||||
private const string SelectedTargetLanguageIndexKey = "SelectedTargetLanguageIndex";
|
||||
|
||||
// LX Music
|
||||
private const string LXMusicServerKey = "LXMusicServer";
|
||||
|
||||
private const string LyricsBackgroundThemeKey = "LyricsBackgroundTheme";
|
||||
private const string IgnoreFullscreenWindowKey = "IgnoreFullscreenWindow";
|
||||
private const string PreferredDisplayTypeKey = "PreferredDisplayTypeKey";
|
||||
|
||||
private const string LyricsScrollEasingTypeKey = "LyricsScrollEasingType";
|
||||
private const string LyricsScrollDurationKey = "LyricsScrollDuration";
|
||||
|
||||
private const string IsLyricsFloatAnimationEnabledKey = "IsLyricsFloatAnimationEnabled";
|
||||
|
||||
private const string PlaybackOrderKey = "PlaybackOrder";
|
||||
|
||||
private const string PositionOffsetKey = "PositionOffset";
|
||||
|
||||
private const string LockHotKeyIndexKey = "LockHotKeyIndex";
|
||||
private const string DockPlacementKey = "DockPlacement";
|
||||
private const string LyricsBgFontOpacityKey = "LyricsBgFontOpacity";
|
||||
private const string HideWindowWhenNotPlayingKey = "HideWindowWhenNotPlaying";
|
||||
private const string DockWindowHeightKey = "DockWindowHeight";
|
||||
|
||||
private const string SelectedFontFamilyIndexKey = "SelectedFontFamilyIndex";
|
||||
private const string LyricsFontFamilyKey = "LyricsFontFamily";
|
||||
private const string IsDragEverywhereEnabledKey = "IsDragEverywhereEnabled";
|
||||
|
||||
private const string DockMonitorDeviceNameKey = "DockMonitorDeviceName";
|
||||
|
||||
// LastFM
|
||||
private const string LastFMSessionKeyKey = "LastFMSessionKey";
|
||||
|
||||
private const string LyricsTranslationSeparatorKey = "LyricsTranslationSeparator";
|
||||
|
||||
private readonly ApplicationDataContainer _localSettings;
|
||||
public AppSettings AppSettings { get; set; }
|
||||
|
||||
public SettingsService()
|
||||
{
|
||||
_localSettings = ApplicationData.Current.LocalSettings;
|
||||
AppSettings = ReadAppSettings();
|
||||
|
||||
SetDefault(IsFirstRunKey, true);
|
||||
// Lyrics lib
|
||||
SetDefault(LocalMediaFoldersKey, "[]");
|
||||
SetDefault(
|
||||
AlbumArtSearchProvidersInfoKey,
|
||||
System.Text.Json.JsonSerializer.Serialize(
|
||||
Enum.GetValues<AlbumArtSearchProvider>()
|
||||
.Select(p => new AlbumArtSearchProviderInfo(p, true))
|
||||
.ToList(),
|
||||
SourceGenerationContext.Default.ListAlbumArtSearchProviderInfo
|
||||
)
|
||||
);
|
||||
if (AlbumArtSearchProvidersInfo.Count != Enum.GetValues<AlbumArtSearchProvider>().Length)
|
||||
{
|
||||
AlbumArtSearchProvidersInfo = Enum.GetValues<AlbumArtSearchProvider>()
|
||||
.Select(p => new AlbumArtSearchProviderInfo(
|
||||
p,
|
||||
AlbumArtSearchProvidersInfo
|
||||
.Where(x => x.Provider == p)
|
||||
.FirstOrDefault()
|
||||
?.IsEnabled ?? true
|
||||
))
|
||||
.ToList();
|
||||
}
|
||||
AppSettings.PropertyChanged += AppSettings_PropertyChanged;
|
||||
|
||||
SetDefault(MediaSourceProvidersInfoKey, "[]");
|
||||
var tmp = MediaSourceProvidersInfo;
|
||||
for (int i = 0; i < tmp.Count; i++)
|
||||
AppSettings.StandardModeSettings.PropertyChanged += AppSettings_PropertyChanged;
|
||||
AppSettings.DesktopModeSettings.PropertyChanged += AppSettings_PropertyChanged;
|
||||
AppSettings.DockModeSettings.PropertyChanged += AppSettings_PropertyChanged;
|
||||
|
||||
AppSettings.StandardLyricsStyleSettings.PropertyChanged += AppSettings_PropertyChanged;
|
||||
AppSettings.DesktopLyricsStyleSettings.PropertyChanged += AppSettings_PropertyChanged;
|
||||
AppSettings.DockLyricsStyleSettings.PropertyChanged += AppSettings_PropertyChanged;
|
||||
|
||||
AppSettings.StandardLyricsEffectSettings.PropertyChanged += AppSettings_PropertyChanged;
|
||||
AppSettings.DesktopLyricsEffectSettings.PropertyChanged += AppSettings_PropertyChanged;
|
||||
AppSettings.DockLyricsEffectSettings.PropertyChanged += AppSettings_PropertyChanged;
|
||||
|
||||
AppSettings.LyricsBackgroundSettings.PropertyChanged += AppSettings_PropertyChanged;
|
||||
AppSettings.AlbumArtLayoutSettings.PropertyChanged += AppSettings_PropertyChanged;
|
||||
AppSettings.TranslationSettings.PropertyChanged += AppSettings_PropertyChanged;
|
||||
AppSettings.GeneralSettings.PropertyChanged += AppSettings_PropertyChanged;
|
||||
AppSettings.MusicGallerySettings.PropertyChanged += AppSettings_PropertyChanged;
|
||||
|
||||
AppSettings.MediaSourceProvidersInfo.CollectionChanged += AppSettings_CollectionChanged;
|
||||
AppSettings.MediaSourceProvidersInfo.ItemPropertyChanged += AppSettings_ItemPropertyChanged;
|
||||
|
||||
AppSettings.LocalMediaFolders.CollectionChanged += AppSettings_CollectionChanged;
|
||||
AppSettings.LocalMediaFolders.ItemPropertyChanged += AppSettings_ItemPropertyChanged;
|
||||
|
||||
AppSettings.Version = MetadataHelper.AppVersion;
|
||||
|
||||
EnsureMediaSourceProvidersInfo();
|
||||
}
|
||||
|
||||
private void EnsureMediaSourceProvidersInfo()
|
||||
{
|
||||
// 确保当 LyricsSearchProvider 和 AlbumArtSearchProvider 枚举更新时,AppSettings 中的相关信息也能更新
|
||||
foreach (var x in AppSettings.MediaSourceProvidersInfo)
|
||||
{
|
||||
var mediaSource = tmp[i];
|
||||
if (mediaSource.LyricsSearchProvidersInfo == null || mediaSource.LyricsSearchProvidersInfo.Count != Enum.GetValues<LyricsSearchProvider>().Length)
|
||||
// 更新 LyricsSearchProvidersInfo
|
||||
foreach (var p in Enum.GetValues<LyricsSearchProvider>())
|
||||
{
|
||||
mediaSource.LyricsSearchProvidersInfo = [..Enum.GetValues<LyricsSearchProvider>()
|
||||
.Select(p => new LyricsSearchProviderInfo(
|
||||
p,
|
||||
mediaSource.LyricsSearchProvidersInfo?
|
||||
.Where(x => x.Provider == p)
|
||||
.FirstOrDefault()
|
||||
?.IsEnabled ?? true
|
||||
))];
|
||||
var item = x.LyricsSearchProvidersInfo.FirstOrDefault(i => i.Provider == p);
|
||||
if (item == null)
|
||||
{
|
||||
x.LyricsSearchProvidersInfo.Add(new LyricsSearchProviderInfo(p, true));
|
||||
}
|
||||
// 可根据需要更新 item.IsEnabled
|
||||
}
|
||||
// 移除多余项
|
||||
for (int i = x.LyricsSearchProvidersInfo.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (!Enum.IsDefined(typeof(LyricsSearchProvider), x.LyricsSearchProvidersInfo[i].Provider))
|
||||
x.LyricsSearchProvidersInfo.RemoveAt(i);
|
||||
}
|
||||
|
||||
// 更新 AlbumArtSearchProvidersInfo
|
||||
foreach (var p in Enum.GetValues<AlbumArtSearchProvider>())
|
||||
{
|
||||
var item = x.AlbumArtSearchProvidersInfo.FirstOrDefault(i => i.Provider == p);
|
||||
if (item == null)
|
||||
{
|
||||
x.AlbumArtSearchProvidersInfo.Add(new AlbumArtSearchProviderInfo(p, true));
|
||||
}
|
||||
// 可根据需要更新 item.IsEnabled
|
||||
}
|
||||
for (int i = x.AlbumArtSearchProvidersInfo.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (!Enum.IsDefined(typeof(AlbumArtSearchProvider), x.AlbumArtSearchProvidersInfo[i].Provider))
|
||||
x.AlbumArtSearchProvidersInfo.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
MediaSourceProvidersInfo = tmp;
|
||||
|
||||
// App appearance
|
||||
SetDefault(LanguageKey, (int)Language.FollowSystem);
|
||||
|
||||
SetDefault(DesktopWindowHeightKey, 600);
|
||||
SetDefault(DesktopWindowLeftKey, 200);
|
||||
SetDefault(DesktopWindowTopKey, 200);
|
||||
SetDefault(DesktopWindowWidthKey, 1200);
|
||||
|
||||
SetDefault(StandardWindowHeightKey, 800);
|
||||
SetDefault(StandardWindowLeftKey, 200);
|
||||
SetDefault(StandardWindowTopKey, 200);
|
||||
SetDefault(StandardWindowWidthKey, 1600);
|
||||
|
||||
SetDefault(AutoLockOnDesktopModeKey, false);
|
||||
SetDefault(IsImmersiveModeKey, false);
|
||||
// App behavior
|
||||
SetDefault(AutoStartWindowTypeKey, (int)AutoStartWindowType.StandardMode);
|
||||
// Album art
|
||||
SetDefault(IsCoverOverlayEnabledKey, true);
|
||||
SetDefault(IsDynamicCoverOverlayEnabledKey, true);
|
||||
SetDefault(CoverOverlayOpacityKey, 100); // 100 % = 1.0
|
||||
SetDefault(CoverOverlayBlurAmountKey, 100);
|
||||
SetDefault(CoverImageRadiusKey, 12); // 12 %
|
||||
SetDefault(CoverAcrylicEffectAmountKey, 0);
|
||||
// Lyrics
|
||||
SetDefault(LyricsAlignmentTypeKey, (int)TextAlignmentType.Left);
|
||||
SetDefault(SongInfoAlignmentTypeKey, (int)TextAlignmentType.Left);
|
||||
SetDefault(LyricsFontWeightKey, (int)LyricsFontWeight.Bold);
|
||||
SetDefault(LyricsBlurAmountKey, 5);
|
||||
|
||||
SetDefault(LyricsBackgroundThemeKey, (int)ElementTheme.Dark);
|
||||
|
||||
SetDefault(LyricsBgFontColorTypeKey, (int)LyricsFontColorType.AdaptiveGrayed);
|
||||
SetDefault(LyricsFgFontColorTypeKey, (int)LyricsFontColorType.AdaptiveGrayed);
|
||||
SetDefault(LyricsStrokeFontColorTypeKey, (int)LyricsFontColorType.AdaptiveGrayed);
|
||||
|
||||
SetDefault(LyricsCustomBgFontColorKey, Colors.White.ToInt());
|
||||
SetDefault(LyricsCustomFgFontColorKey, Colors.White.ToInt());
|
||||
SetDefault(LyricsCustomStrokeFontColorKey, Colors.White.ToInt());
|
||||
|
||||
SetDefault(LyricsStandardFontSizeKey, 32);
|
||||
SetDefault(LyricsDockFontSizeKey, 16);
|
||||
SetDefault(LyricsDesktopFontSizeKey, 28);
|
||||
|
||||
SetDefault(LyricsLineSpacingFactorKey, 0.5f);
|
||||
SetDefault(LyricsVerticalEdgeOpacityKey, 0);
|
||||
SetDefault(IsLyricsGlowEffectEnabledKey, true);
|
||||
SetDefault(LyricsGlowEffectScopeKey, (int)LineRenderingType.CurrentChar);
|
||||
SetDefault(LyricsHighlightSopeKey, (int)LineRenderingType.LineStartToCurrentChar);
|
||||
SetDefault(IsFanLyricsEnabledKey, false);
|
||||
|
||||
SetDefault(LibreTranslateServerKey, "");
|
||||
SetDefault(IsLibreTranslateEnabledKey, false);
|
||||
SetDefault(IsTranslationEnabledKey, true);
|
||||
SetDefault(ShowTranslationOnlyKey, false);
|
||||
SetDefault(SelectedTargetLanguageIndexKey, LanguageHelper.GetDefaultTargetLanguageIndex());
|
||||
|
||||
SetDefault(LXMusicServerKey, "");
|
||||
|
||||
SetDefault(LyricsFontStrokeWidthKey, 3);
|
||||
SetDefault(IgnoreFullscreenWindowKey, false);
|
||||
SetDefault(PreferredDisplayTypeKey, (int)LyricsDisplayType.SplitView);
|
||||
|
||||
SetDefault(LyricsScrollEasingTypeKey, (int)EasingType.EaseInOutSine);
|
||||
SetDefault(LyricsScrollDurationKey, 500); // 500ms
|
||||
|
||||
SetDefault(IsLyricsFloatAnimationEnabledKey, true);
|
||||
|
||||
SetDefault(PositionOffsetKey, 0);
|
||||
SetDefault(LockHotKeyIndexKey, 'U' - 'A');
|
||||
SetDefault(DockPlacementKey, (int)DockPlacement.Top);
|
||||
SetDefault(LyricsBgFontOpacityKey, 30); // 30%
|
||||
SetDefault(HideWindowWhenNotPlayingKey, false);
|
||||
SetDefault(DockWindowHeightKey, 64); // 64px
|
||||
SetDefault(SelectedFontFamilyIndexKey, 0);
|
||||
SetDefault(LyricsFontFamilyKey, FontHelper.SystemFontFamilies.ElementAtOrDefault(0));
|
||||
SetDefault(IsDragEverywhereEnabledKey, false);
|
||||
SetDefault(DockMonitorDeviceNameKey, MonitorHelper.GetPrimaryMonitorDeviceName());
|
||||
|
||||
SetDefault(LastFMSessionKeyKey, "");
|
||||
|
||||
SetDefault(LyricsTranslationSeparatorKey, StringHelper.NewLine);
|
||||
}
|
||||
|
||||
public bool IsDragEverywhereEnabled
|
||||
{
|
||||
get => GetValue<bool>(IsDragEverywhereEnabledKey);
|
||||
set => SetValue(IsDragEverywhereEnabledKey, value);
|
||||
}
|
||||
|
||||
public string LyricsFontFamily
|
||||
{
|
||||
get => GetValue<string>(LyricsFontFamilyKey)!;
|
||||
set => SetValue(LyricsFontFamilyKey, value);
|
||||
}
|
||||
|
||||
public int SelectedFontFamilyIndex
|
||||
{
|
||||
get => GetValue<int>(SelectedFontFamilyIndexKey);
|
||||
set => SetValue(SelectedFontFamilyIndexKey, value);
|
||||
}
|
||||
|
||||
public bool HideWindowWhenNotPlaying
|
||||
{
|
||||
get => GetValue<bool>(HideWindowWhenNotPlayingKey);
|
||||
set => SetValue(HideWindowWhenNotPlayingKey, value);
|
||||
}
|
||||
|
||||
public int DockWindowHeight
|
||||
{
|
||||
get => GetValue<int>(DockWindowHeightKey);
|
||||
set => SetValue(DockWindowHeightKey, value);
|
||||
}
|
||||
|
||||
public int LyricsBgFontOpacity
|
||||
{
|
||||
get => GetValue<int>(LyricsBgFontOpacityKey);
|
||||
set => SetValue(LyricsBgFontOpacityKey, value);
|
||||
}
|
||||
|
||||
public bool ShowTranslationOnly
|
||||
{
|
||||
get => GetValue<bool>(ShowTranslationOnlyKey);
|
||||
set => SetValue(ShowTranslationOnlyKey, value);
|
||||
}
|
||||
|
||||
public DockPlacement DockPlacement
|
||||
{
|
||||
get => (DockPlacement)GetValue<int>(DockPlacementKey);
|
||||
set => SetValue(DockPlacementKey, (int)value);
|
||||
}
|
||||
|
||||
public int LockHotKeyIndex
|
||||
{
|
||||
get => GetValue<int>(LockHotKeyIndexKey);
|
||||
set => SetValue(LockHotKeyIndexKey, value);
|
||||
}
|
||||
|
||||
public EasingType LyricsScrollEasingType
|
||||
{
|
||||
get => (EasingType)GetValue<int>(LyricsScrollEasingTypeKey);
|
||||
set => SetValue(LyricsScrollEasingTypeKey, (int)value);
|
||||
}
|
||||
|
||||
public int LyricsScrollDuration
|
||||
{
|
||||
get => GetValue<int>(LyricsScrollDurationKey);
|
||||
set => SetValue(LyricsScrollDurationKey, value);
|
||||
}
|
||||
|
||||
public LyricsDisplayType DisplayType
|
||||
{
|
||||
get => (LyricsDisplayType)GetValue<int>(PreferredDisplayTypeKey);
|
||||
set => SetValue(PreferredDisplayTypeKey, (int)value);
|
||||
}
|
||||
|
||||
public ElementTheme LyricsBackgroundTheme
|
||||
private void AppSettings_ItemPropertyChanged(object? sender, ItemPropertyChangedEventArgs e)
|
||||
{
|
||||
get => (ElementTheme)GetValue<int>(LyricsBackgroundThemeKey);
|
||||
set => SetValue(LyricsBackgroundThemeKey, (int)value);
|
||||
WriteAppSettingsDebounce();
|
||||
}
|
||||
|
||||
public AutoStartWindowType AutoStartWindowType
|
||||
private void AppSettings_CollectionChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
get => (AutoStartWindowType)GetValue<int>(AutoStartWindowTypeKey);
|
||||
set => SetValue(AutoStartWindowTypeKey, (int)value);
|
||||
WriteAppSettingsDebounce();
|
||||
}
|
||||
|
||||
public int DesktopWindowLeft
|
||||
{
|
||||
get => GetValue<int>(DesktopWindowLeftKey);
|
||||
set => SetValue(DesktopWindowLeftKey, value);
|
||||
}
|
||||
|
||||
public int DesktopWindowTop
|
||||
{
|
||||
get => GetValue<int>(DesktopWindowTopKey);
|
||||
set => SetValue(DesktopWindowTopKey, value);
|
||||
}
|
||||
|
||||
public int DesktopWindowWidth
|
||||
{
|
||||
get => GetValue<int>(DesktopWindowWidthKey);
|
||||
set => SetValue(DesktopWindowWidthKey, value);
|
||||
}
|
||||
|
||||
public int DesktopWindowHeight
|
||||
{
|
||||
get => GetValue<int>(DesktopWindowHeightKey);
|
||||
set => SetValue(DesktopWindowHeightKey, value);
|
||||
}
|
||||
|
||||
public int StandardWindowLeft
|
||||
{
|
||||
get => GetValue<int>(StandardWindowLeftKey);
|
||||
set => SetValue(StandardWindowLeftKey, value);
|
||||
}
|
||||
|
||||
public int StandardWindowTop
|
||||
{
|
||||
get => GetValue<int>(StandardWindowTopKey);
|
||||
set => SetValue(StandardWindowTopKey, value);
|
||||
}
|
||||
|
||||
public int StandardWindowWidth
|
||||
{
|
||||
get => GetValue<int>(StandardWindowWidthKey);
|
||||
set => SetValue(StandardWindowWidthKey, value);
|
||||
}
|
||||
|
||||
public int StandardWindowHeight
|
||||
{
|
||||
get => GetValue<int>(StandardWindowHeightKey);
|
||||
set => SetValue(StandardWindowHeightKey, value);
|
||||
}
|
||||
|
||||
public bool AutoLockOnDesktopMode
|
||||
{
|
||||
get => GetValue<bool>(AutoLockOnDesktopModeKey);
|
||||
set => SetValue(AutoLockOnDesktopModeKey, value);
|
||||
}
|
||||
|
||||
public int CoverImageRadius
|
||||
{
|
||||
get => GetValue<int>(CoverImageRadiusKey);
|
||||
set => SetValue(CoverImageRadiusKey, value);
|
||||
}
|
||||
|
||||
public int CoverOverlayBlurAmount
|
||||
{
|
||||
get => GetValue<int>(CoverOverlayBlurAmountKey);
|
||||
set => SetValue(CoverOverlayBlurAmountKey, value);
|
||||
}
|
||||
|
||||
public int CoverOverlayOpacity
|
||||
{
|
||||
get => GetValue<int>(CoverOverlayOpacityKey);
|
||||
set => SetValue(CoverOverlayOpacityKey, value);
|
||||
}
|
||||
|
||||
public bool IsDynamicCoverOverlayEnabled
|
||||
{
|
||||
get => GetValue<bool>(IsDynamicCoverOverlayEnabledKey);
|
||||
set => SetValue(IsDynamicCoverOverlayEnabledKey, value);
|
||||
}
|
||||
|
||||
public int CoverAcrylicEffectAmount
|
||||
{
|
||||
get => GetValue<int>(CoverAcrylicEffectAmountKey);
|
||||
set => SetValue(CoverAcrylicEffectAmountKey, value);
|
||||
}
|
||||
|
||||
public bool IsFanLyricsEnabled
|
||||
{
|
||||
get => GetValue<bool>(IsFanLyricsEnabledKey);
|
||||
set => SetValue(IsFanLyricsEnabledKey, value);
|
||||
}
|
||||
|
||||
public bool IsFirstRun
|
||||
{
|
||||
get => GetValue<bool>(IsFirstRunKey);
|
||||
set => SetValue(IsFirstRunKey, value);
|
||||
}
|
||||
|
||||
public bool IsLyricsGlowEffectEnabled
|
||||
{
|
||||
get => GetValue<bool>(IsLyricsGlowEffectEnabledKey);
|
||||
set => SetValue(IsLyricsGlowEffectEnabledKey, value);
|
||||
}
|
||||
|
||||
public Language Language
|
||||
{
|
||||
get => (Language)GetValue<int>(LanguageKey);
|
||||
set => SetValue(LanguageKey, (int)value);
|
||||
}
|
||||
|
||||
public List<LocalMediaFolder> LocalMediaFolders
|
||||
{
|
||||
get =>
|
||||
System.Text.Json.JsonSerializer.Deserialize(
|
||||
GetValue<string>(LocalMediaFoldersKey) ?? "[]",
|
||||
SourceGenerationContext.Default.ListLocalMediaFolder
|
||||
)!;
|
||||
set =>
|
||||
SetValue(
|
||||
LocalMediaFoldersKey,
|
||||
System.Text.Json.JsonSerializer.Serialize(
|
||||
value,
|
||||
SourceGenerationContext.Default.ListLocalMediaFolder
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public TextAlignmentType LyricsAlignmentType
|
||||
{
|
||||
get => (TextAlignmentType)GetValue<int>(LyricsAlignmentTypeKey);
|
||||
set => SetValue(LyricsAlignmentTypeKey, (int)value);
|
||||
}
|
||||
|
||||
public TextAlignmentType SongInfoAlignmentType
|
||||
{
|
||||
get => (TextAlignmentType)GetValue<int>(SongInfoAlignmentTypeKey);
|
||||
set => SetValue(SongInfoAlignmentTypeKey, (int)value);
|
||||
}
|
||||
|
||||
public int LyricsBlurAmount
|
||||
{
|
||||
get => GetValue<int>(LyricsBlurAmountKey);
|
||||
set => SetValue(LyricsBlurAmountKey, value);
|
||||
}
|
||||
|
||||
public Color LyricsCustomBgFontColor
|
||||
{
|
||||
get => GetValue<int>(LyricsCustomBgFontColorKey)!.ToColor();
|
||||
set => SetValue(LyricsCustomBgFontColorKey, value.ToInt());
|
||||
}
|
||||
|
||||
public Color LyricsCustomFgFontColor
|
||||
{
|
||||
get => GetValue<int>(LyricsCustomFgFontColorKey)!.ToColor();
|
||||
set => SetValue(LyricsCustomFgFontColorKey, value.ToInt());
|
||||
}
|
||||
|
||||
public Color LyricsCustomStrokeFontColor
|
||||
{
|
||||
get => GetValue<int>(LyricsCustomStrokeFontColorKey)!.ToColor();
|
||||
set => SetValue(LyricsCustomStrokeFontColorKey, value.ToInt());
|
||||
}
|
||||
|
||||
public LyricsFontColorType LyricsBgFontColorType
|
||||
{
|
||||
get => (LyricsFontColorType)GetValue<int>(LyricsBgFontColorTypeKey);
|
||||
set => SetValue(LyricsBgFontColorTypeKey, (int)value);
|
||||
}
|
||||
|
||||
public LyricsFontColorType LyricsFgFontColorType
|
||||
{
|
||||
get => (LyricsFontColorType)GetValue<int>(LyricsFgFontColorTypeKey);
|
||||
set => SetValue(LyricsFgFontColorTypeKey, (int)value);
|
||||
}
|
||||
|
||||
public LyricsFontColorType LyricsStrokeFontColorType
|
||||
{
|
||||
get => (LyricsFontColorType)GetValue<int>(LyricsStrokeFontColorTypeKey);
|
||||
set => SetValue(LyricsStrokeFontColorTypeKey, (int)value);
|
||||
}
|
||||
|
||||
public int LyricsFontStrokeWidth
|
||||
{
|
||||
get => GetValue<int>(LyricsFontStrokeWidthKey);
|
||||
set => SetValue(LyricsFontStrokeWidthKey, value);
|
||||
}
|
||||
|
||||
public int LyricsStandardFontSize
|
||||
{
|
||||
get => GetValue<int>(LyricsStandardFontSizeKey);
|
||||
set => SetValue(LyricsStandardFontSizeKey, value);
|
||||
}
|
||||
|
||||
public int LyricsDockFontSize
|
||||
{
|
||||
get => GetValue<int>(LyricsDockFontSizeKey);
|
||||
set => SetValue(LyricsDockFontSizeKey, value);
|
||||
}
|
||||
|
||||
public int LyricsDesktopFontSize
|
||||
{
|
||||
get => GetValue<int>(LyricsDesktopFontSizeKey);
|
||||
set => SetValue(LyricsDesktopFontSizeKey, value);
|
||||
}
|
||||
|
||||
public LyricsFontWeight LyricsFontWeight
|
||||
{
|
||||
get => (LyricsFontWeight)GetValue<int>(LyricsFontWeightKey);
|
||||
set => SetValue(LyricsFontWeightKey, (int)value);
|
||||
}
|
||||
|
||||
public LineRenderingType LyricsGlowEffectScope
|
||||
{
|
||||
get => (LineRenderingType)GetValue<int>(LyricsGlowEffectScopeKey);
|
||||
set => SetValue(LyricsGlowEffectScopeKey, (int)value);
|
||||
}
|
||||
|
||||
public LineRenderingType LyricsHighlightScope
|
||||
{
|
||||
get => (LineRenderingType)GetValue<int>(LyricsHighlightSopeKey);
|
||||
set => SetValue(LyricsHighlightSopeKey, (int)value);
|
||||
}
|
||||
|
||||
public float LyricsLineSpacingFactor
|
||||
{
|
||||
get => GetValue<float>(LyricsLineSpacingFactorKey);
|
||||
set => SetValue(LyricsLineSpacingFactorKey, value);
|
||||
}
|
||||
|
||||
public List<AlbumArtSearchProviderInfo> AlbumArtSearchProvidersInfo
|
||||
{
|
||||
get =>
|
||||
System.Text.Json.JsonSerializer.Deserialize(
|
||||
GetValue<string>(AlbumArtSearchProvidersInfoKey) ?? "[]",
|
||||
SourceGenerationContext.Default.ListAlbumArtSearchProviderInfo
|
||||
)!;
|
||||
set =>
|
||||
SetValue(
|
||||
AlbumArtSearchProvidersInfoKey,
|
||||
System.Text.Json.JsonSerializer.Serialize(
|
||||
value,
|
||||
SourceGenerationContext.Default.ListAlbumArtSearchProviderInfo
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public List<MediaSourceProviderInfo> MediaSourceProvidersInfo
|
||||
{
|
||||
get =>
|
||||
System.Text.Json.JsonSerializer.Deserialize(
|
||||
GetValue<string>(MediaSourceProvidersInfoKey) ?? "[]",
|
||||
SourceGenerationContext.Default.ListMediaSourceProviderInfo
|
||||
)!;
|
||||
set =>
|
||||
SetValue(
|
||||
MediaSourceProvidersInfoKey,
|
||||
System.Text.Json.JsonSerializer.Serialize(
|
||||
value,
|
||||
SourceGenerationContext.Default.ListMediaSourceProviderInfo
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public int LyricsVerticalEdgeOpacity
|
||||
{
|
||||
get => GetValue<int>(LyricsVerticalEdgeOpacityKey);
|
||||
set => SetValue(LyricsVerticalEdgeOpacityKey, value);
|
||||
}
|
||||
|
||||
public string LibreTranslateServer
|
||||
{
|
||||
get => GetValue<string>(LibreTranslateServerKey)!;
|
||||
set => SetValue(LibreTranslateServerKey, value);
|
||||
}
|
||||
|
||||
public bool IsTranslationEnabled
|
||||
{
|
||||
get => GetValue<bool>(IsTranslationEnabledKey);
|
||||
set => SetValue(IsTranslationEnabledKey, value);
|
||||
}
|
||||
|
||||
public bool IsLibreTranslateEnabled
|
||||
{
|
||||
get => GetValue<bool>(IsLibreTranslateEnabledKey);
|
||||
set => SetValue(IsLibreTranslateEnabledKey, value);
|
||||
}
|
||||
|
||||
public int SelectedTargetLanguageIndex
|
||||
{
|
||||
get => GetValue<int>(SelectedTargetLanguageIndexKey);
|
||||
set => SetValue(SelectedTargetLanguageIndexKey, value);
|
||||
}
|
||||
|
||||
public string LXMusicServer
|
||||
{
|
||||
get => GetValue<string>(LXMusicServerKey)!;
|
||||
set => SetValue(LXMusicServerKey, value);
|
||||
}
|
||||
|
||||
public bool IgnoreFullscreenWindow
|
||||
{
|
||||
get => GetValue<bool>(IgnoreFullscreenWindowKey);
|
||||
set => SetValue(IgnoreFullscreenWindowKey, value);
|
||||
}
|
||||
|
||||
public bool IsLyricsFloatAnimationEnabled
|
||||
{
|
||||
get => GetValue<bool>(IsLyricsFloatAnimationEnabledKey);
|
||||
set => SetValue(IsLyricsFloatAnimationEnabledKey, value);
|
||||
}
|
||||
|
||||
public PlaybackOrder PlaybackOrder
|
||||
{
|
||||
get => (PlaybackOrder)GetValue<int>(PlaybackOrderKey);
|
||||
set => SetValue(PlaybackOrderKey, (int)value);
|
||||
}
|
||||
|
||||
public int PositionOffset
|
||||
{
|
||||
get => GetValue<int>(PositionOffsetKey);
|
||||
set => SetValue(PositionOffsetKey, value);
|
||||
}
|
||||
|
||||
public bool IsImmersiveMode
|
||||
{
|
||||
get => GetValue<bool>(IsImmersiveModeKey);
|
||||
set => SetValue(IsImmersiveModeKey, value);
|
||||
}
|
||||
|
||||
public string DockMonitorDeviceName
|
||||
{
|
||||
get => GetValue<string>(DockMonitorDeviceNameKey)!;
|
||||
set => SetValue(DockMonitorDeviceNameKey, value);
|
||||
}
|
||||
|
||||
// LastFM
|
||||
|
||||
public string LastFMSessionKey
|
||||
{
|
||||
get => GetValue<string>(LastFMSessionKeyKey)!;
|
||||
set => SetValue(LastFMSessionKeyKey, value);
|
||||
}
|
||||
|
||||
public string LyricsTranslationSeparator
|
||||
{
|
||||
get => GetValue<string>(LyricsTranslationSeparatorKey)!;
|
||||
set => SetValue(LyricsTranslationSeparatorKey, value);
|
||||
}
|
||||
|
||||
// Common methods
|
||||
|
||||
private T? GetValue<T>(string key)
|
||||
private void AppSettings_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||
{
|
||||
if (_localSettings.Values.TryGetValue(key, out object? value))
|
||||
switch (e.PropertyName)
|
||||
{
|
||||
return (T)value;
|
||||
case nameof(GeneralSettings.IsDragEverywhereEnabled):
|
||||
LyricsWindow? lyricsWindow = WindowHelper.GetWindowByWindowType<LyricsWindow>();
|
||||
lyricsWindow?.UpdateTitleBarArea();
|
||||
break;
|
||||
case nameof(GeneralSettings.Language):
|
||||
switch (AppSettings.GeneralSettings.Language)
|
||||
{
|
||||
case Enums.Language.FollowSystem:
|
||||
ApplicationLanguages.PrimaryLanguageOverride = "";
|
||||
break;
|
||||
case Enums.Language.English:
|
||||
ApplicationLanguages.PrimaryLanguageOverride = "en-US";
|
||||
break;
|
||||
case Enums.Language.SimplifiedChinese:
|
||||
ApplicationLanguages.PrimaryLanguageOverride = "zh-CN";
|
||||
break;
|
||||
case Enums.Language.TraditionalChinese:
|
||||
ApplicationLanguages.PrimaryLanguageOverride = "zh-TW";
|
||||
break;
|
||||
case Enums.Language.Japanese:
|
||||
ApplicationLanguages.PrimaryLanguageOverride = "ja-JP";
|
||||
break;
|
||||
case Enums.Language.Korean:
|
||||
ApplicationLanguages.PrimaryLanguageOverride = "ko-KR";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return default;
|
||||
WriteAppSettingsDebounce();
|
||||
}
|
||||
|
||||
private void SetDefault<T>(string key, T value)
|
||||
/// <summary>
|
||||
/// Export settings to specific folder
|
||||
/// </summary>
|
||||
/// <param name="exportPath">Target folder path (not file path)</param>
|
||||
public void ExportSettings(string exportPath)
|
||||
{
|
||||
if (_localSettings.Values.ContainsKey(key) && _localSettings.Values[key] is T)
|
||||
return;
|
||||
_localSettings.Values[key] = value;
|
||||
// 导出到文件
|
||||
var exportJson = System.Text.Json.JsonSerializer.Serialize(AppSettings, SourceGenerationContext.Default.AppSettings);
|
||||
File.WriteAllText(Path.Combine(exportPath, $"BetterLyrics_Settings_Export_{DateTime.Now:yyyyMMdd_HHmmss}.json"), exportJson);
|
||||
}
|
||||
|
||||
private void SetValue<T>(string key, T value)
|
||||
/// <summary>
|
||||
/// Indicate a value whether import action is successfullt done
|
||||
/// </summary>
|
||||
/// <param name="importPath"></param>
|
||||
/// <returns></returns>
|
||||
public bool ImportSettings(string importPath)
|
||||
{
|
||||
_localSettings.Values[key] = value;
|
||||
// TODO 导入有问题
|
||||
if (!File.Exists(importPath))
|
||||
return false;
|
||||
|
||||
var importJson = File.ReadAllText(importPath);
|
||||
var importData = System.Text.Json.JsonSerializer.Deserialize(importJson, SourceGenerationContext.Default.AppSettings);
|
||||
|
||||
if (importData == null)
|
||||
return false;
|
||||
|
||||
AppSettings = importData;
|
||||
SaveAppSettings();
|
||||
return true;
|
||||
}
|
||||
|
||||
private static AppSettings ReadAppSettings()
|
||||
{
|
||||
if (!File.Exists(PathHelper.SettingsFilePath))
|
||||
return new AppSettings();
|
||||
|
||||
var json = File.ReadAllText(PathHelper.SettingsFilePath);
|
||||
var data = System.Text.Json.JsonSerializer.Deserialize(json, SourceGenerationContext.Default.AppSettings);
|
||||
|
||||
if (data == null)
|
||||
return new AppSettings();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
private void WriteAppSettingsDebounce()
|
||||
{
|
||||
_dispatcherQueueTimer.Debounce(() =>
|
||||
{
|
||||
_dispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, () =>
|
||||
{
|
||||
SaveAppSettings();
|
||||
});
|
||||
}, Constants.Time.DebounceTimeout);
|
||||
}
|
||||
|
||||
private void SaveAppSettings()
|
||||
{
|
||||
File.WriteAllText(PathHelper.SettingsFilePath, System.Text.Json.JsonSerializer.Serialize(AppSettings, SourceGenerationContext.Default.AppSettings));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,10 +18,12 @@ namespace BetterLyrics.WinUI3.Services.TranslateService
|
||||
{
|
||||
public class TranslateService : BaseViewModel, ITranslateService
|
||||
{
|
||||
private readonly ISettingsService _settingsService;
|
||||
private readonly HttpClient _httpClient;
|
||||
|
||||
public TranslateService(ISettingsService settingsService) : base(settingsService)
|
||||
public TranslateService(ISettingsService settingsService)
|
||||
{
|
||||
_settingsService = settingsService;
|
||||
_httpClient = new HttpClient();
|
||||
}
|
||||
|
||||
@@ -46,12 +48,12 @@ namespace BetterLyrics.WinUI3.Services.TranslateService
|
||||
return ChineseConverter.ConvertToTraditionalChinese(text);
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(_settingsService.LibreTranslateServer))
|
||||
if (string.IsNullOrEmpty(_settingsService.AppSettings.TranslationSettings.LibreTranslateServer))
|
||||
{
|
||||
throw new Exception("LibreTranslate server URL is not set in settings.");
|
||||
}
|
||||
|
||||
var url = $"{_settingsService.LibreTranslateServer}/translate";
|
||||
var url = $"{_settingsService.AppSettings.TranslationSettings.LibreTranslateServer}/translate";
|
||||
var response = await _httpClient.PostAsync(url, new FormUrlEncodedContent(
|
||||
[
|
||||
new("q", text),
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,25 @@
|
||||
using BetterLyrics.WinUI3.Models.Settings;
|
||||
using BetterLyrics.WinUI3.Services.SettingsService;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BetterLyrics.WinUI3.ViewModels
|
||||
{
|
||||
public partial class AlbumArtLayoutSettingsControlViewModel : BaseViewModel
|
||||
{
|
||||
private readonly ISettingsService _settingsService;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial AppSettings AppSettings { get; set; }
|
||||
|
||||
public AlbumArtLayoutSettingsControlViewModel(ISettingsService settingsService)
|
||||
{
|
||||
_settingsService = settingsService;
|
||||
AppSettings = _settingsService.AppSettings;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using BetterLyrics.WinUI3.Models.Settings;
|
||||
using BetterLyrics.WinUI3.Services.SettingsService;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BetterLyrics.WinUI3.ViewModels
|
||||
{
|
||||
public partial class AllLyricsSettingsControlViewModel : BaseViewModel
|
||||
{
|
||||
private readonly ISettingsService _settingsService;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial AppSettings AppSettings { get; set; }
|
||||
|
||||
public AllLyricsSettingsControlViewModel(ISettingsService settingsService)
|
||||
{
|
||||
_settingsService = settingsService;
|
||||
AppSettings = _settingsService.AppSettings;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using BetterLyrics.WinUI3.Models.Settings;
|
||||
using BetterLyrics.WinUI3.Services.SettingsService;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.ApplicationModel;
|
||||
|
||||
namespace BetterLyrics.WinUI3.ViewModels
|
||||
{
|
||||
public partial class AppSettingsControlViewModel : BaseViewModel
|
||||
{
|
||||
private readonly ISettingsService _settingsService;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial AppSettings AppSettings { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial ObservableCollection<string> MonitorDeviceNames { get; set; }
|
||||
|
||||
|
||||
public AppSettingsControlViewModel(ISettingsService settingsService)
|
||||
{
|
||||
_settingsService = settingsService;
|
||||
MonitorDeviceNames = [.. MonitorHelper.GetAllMonitorDeviceNames()];
|
||||
AppSettings = _settingsService.AppSettings;
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private static void RestartApp()
|
||||
{
|
||||
WindowHelper.RestartApp();
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void RefreshMonitorDeviceNames()
|
||||
{
|
||||
MonitorDeviceNames = [.. MonitorHelper.GetAllMonitorDeviceNames()];
|
||||
AppSettings.DockModeSettings.DockMonitorDeviceName = MonitorHelper.GetPrimaryMonitorDeviceName();
|
||||
}
|
||||
|
||||
public async Task<bool> ToggleAutoStartupAsync(bool target)
|
||||
{
|
||||
StartupTask startupTask = await StartupTask.GetAsync(Constants.App.AutoStartupTaskId);
|
||||
if (target)
|
||||
{
|
||||
await startupTask.RequestEnableAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
startupTask.Disable();
|
||||
}
|
||||
return await DetectIsAutoStartupEnabledAsync();
|
||||
}
|
||||
|
||||
public async Task<bool> DetectIsAutoStartupEnabledAsync()
|
||||
{
|
||||
bool result = false;
|
||||
var startupTask = await StartupTask.GetAsync(Constants.App.AutoStartupTaskId);
|
||||
switch (startupTask.State)
|
||||
{
|
||||
case StartupTaskState.Disabled:
|
||||
case StartupTaskState.DisabledByUser:
|
||||
case StartupTaskState.DisabledByPolicy:
|
||||
result = false;
|
||||
break;
|
||||
case StartupTaskState.Enabled:
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -12,15 +12,13 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
{
|
||||
private protected readonly DispatcherQueue _dispatcherQueue;
|
||||
private protected readonly DispatcherQueueTimer _dispatcherQueueTimer;
|
||||
private protected readonly ISettingsService _settingsService;
|
||||
|
||||
public BaseViewModel(ISettingsService settingsService)
|
||||
public BaseViewModel()
|
||||
{
|
||||
IsActive = true;
|
||||
|
||||
_dispatcherQueue = DispatcherQueue.GetForCurrentThread();
|
||||
_dispatcherQueueTimer = _dispatcherQueue.CreateTimer();
|
||||
_settingsService = settingsService;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ using Microsoft.UI.Xaml;
|
||||
|
||||
namespace BetterLyrics.WinUI3.ViewModels
|
||||
{
|
||||
public partial class BaseWindowViewModel(ISettingsService settingsService) : BaseViewModel(settingsService)
|
||||
public partial class BaseWindowViewModel : BaseViewModel
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
using BetterLyrics.WinUI3.Models.Settings;
|
||||
using BetterLyrics.WinUI3.Services.SettingsService;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BetterLyrics.WinUI3.ViewModels
|
||||
{
|
||||
public partial class LyricsBackgroundSettingsControlViewModel : BaseViewModel
|
||||
{
|
||||
private readonly ISettingsService _settingsService;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial AppSettings AppSettings { get; set; }
|
||||
|
||||
public LyricsBackgroundSettingsControlViewModel(ISettingsService settingsService)
|
||||
{
|
||||
_settingsService = settingsService;
|
||||
AppSettings = _settingsService.AppSettings;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.Models.Settings;
|
||||
using BetterLyrics.WinUI3.Services.MediaSessionsService;
|
||||
using BetterLyrics.WinUI3.Services.SettingsService;
|
||||
using BetterLyrics.WinUI3.Views;
|
||||
@@ -24,32 +25,27 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
IRecipient<PropertyChangedMessage<bool>>,
|
||||
IRecipient<PropertyChangedMessage<int>>,
|
||||
IRecipient<PropertyChangedMessage<string>>,
|
||||
IRecipient<PropertyChangedMessage<TimeSpan>>,
|
||||
IRecipient<PropertyChangedMessage<LyricsSearchProvider?>>,
|
||||
IRecipient<PropertyChangedMessage<TranslationSearchProvider?>>
|
||||
IRecipient<PropertyChangedMessage<TimeSpan>>
|
||||
{
|
||||
private readonly IMediaSessionsService _mediaSessionsService;
|
||||
private readonly ISettingsService _settingsService;
|
||||
|
||||
private readonly ThrottleHelper _timelineThrottle = new(TimeSpan.FromSeconds(1));
|
||||
|
||||
private bool _isDockMode = false;
|
||||
private bool _isDesktopMode = false;
|
||||
|
||||
private int _lyricsStandardFontSize = 8;
|
||||
private int _lyricsDockFontSize = 8;
|
||||
private int _lyricsDesktopFontSize = 8;
|
||||
|
||||
public LyricsPageViewModel(ISettingsService settingsService, IMediaSessionsService mediaSessionsService) : base(settingsService)
|
||||
public LyricsPageViewModel(ISettingsService settingsService, IMediaSessionsService mediaSessionsService)
|
||||
{
|
||||
IsFirstRun = _settingsService.IsFirstRun;
|
||||
IsTranslationEnabled = _settingsService.IsTranslationEnabled;
|
||||
DisplayType = _settingsService.DisplayType;
|
||||
PositionOffset = _settingsService.PositionOffset;
|
||||
IsImmersiveMode = _settingsService.IsImmersiveMode;
|
||||
ShowTranslationOnly = _settingsService.ShowTranslationOnly;
|
||||
_settingsService = settingsService;
|
||||
IsTranslationEnabled = _settingsService.AppSettings.TranslationSettings.IsTranslationEnabled;
|
||||
DisplayType = _settingsService.AppSettings.GeneralSettings.DisplayType;
|
||||
IsImmersiveMode = _settingsService.AppSettings.GeneralSettings.IsImmersiveMode;
|
||||
ShowTranslationOnly = _settingsService.AppSettings.TranslationSettings.ShowTranslationOnly;
|
||||
|
||||
UpdateHintMessageFontSize();
|
||||
|
||||
LyricsFontFamily = _settingsService.LyricsFontFamily;
|
||||
LyricsFontFamily = _settingsService.AppSettings.StandardLyricsStyleSettings.LyricsFontFamily;
|
||||
|
||||
OnIsImmersiveModeChanged(IsImmersiveMode);
|
||||
|
||||
@@ -104,28 +100,18 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
public partial bool IsImmersiveMode { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial float BottomCommandGridOpacity { get; set; }
|
||||
public partial double BottomCommandGridOpacity { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial float BottomCommandFlyoutTriggerOpacity { get; set; }
|
||||
public partial double BottomCommandFlyoutTriggerOpacity { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial LyricsDisplayType DisplayType { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial bool IsFirstRun { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial bool IsWelcomeTeachingTipOpen { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial SongInfo? SongInfo { get; set; } = null;
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial int PositionOffset { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial bool IsTranslationEnabled { get; set; }
|
||||
@@ -137,25 +123,19 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
[ObservableProperty]
|
||||
public partial bool IsSongPlaying { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial LyricsSearchProvider? LyricsSearchProvider { get; set; } = null;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial TranslationSearchProvider? TranslationSearchProvider { get; set; } = null;
|
||||
|
||||
private void UpdateHintMessageFontSize()
|
||||
{
|
||||
if (_isDockMode)
|
||||
{
|
||||
HintMessageFontSize = _settingsService.LyricsDockFontSize;
|
||||
HintMessageFontSize = _settingsService.AppSettings.DockLyricsStyleSettings.LyricsFontSize;
|
||||
}
|
||||
else if (_isDesktopMode)
|
||||
{
|
||||
HintMessageFontSize = _settingsService.LyricsDesktopFontSize;
|
||||
HintMessageFontSize = _settingsService.AppSettings.DesktopLyricsStyleSettings.LyricsFontSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
HintMessageFontSize = _settingsService.LyricsStandardFontSize;
|
||||
HintMessageFontSize = _settingsService.AppSettings.StandardLyricsStyleSettings.LyricsFontSize;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,7 +152,7 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
}
|
||||
else
|
||||
{
|
||||
DisplayType = _settingsService.DisplayType;
|
||||
DisplayType = _settingsService.AppSettings.GeneralSettings.DisplayType;
|
||||
}
|
||||
UpdateHintMessageFontSize();
|
||||
}
|
||||
@@ -185,7 +165,7 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
}
|
||||
else
|
||||
{
|
||||
DisplayType = _settingsService.DisplayType;
|
||||
DisplayType = _settingsService.AppSettings.GeneralSettings.DisplayType;
|
||||
}
|
||||
UpdateHintMessageFontSize();
|
||||
}
|
||||
@@ -226,20 +206,9 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
await _mediaSessionsService.NextAsync();
|
||||
}
|
||||
|
||||
partial void OnIsFirstRunChanged(bool value)
|
||||
{
|
||||
IsWelcomeTeachingTipOpen = value;
|
||||
_settingsService.IsFirstRun = false;
|
||||
}
|
||||
|
||||
partial void OnIsTranslationEnabledChanged(bool value)
|
||||
{
|
||||
_settingsService.IsTranslationEnabled = value;
|
||||
}
|
||||
|
||||
partial void OnPositionOffsetChanged(int value)
|
||||
{
|
||||
_settingsService.PositionOffset = value;
|
||||
_settingsService.AppSettings.TranslationSettings.IsTranslationEnabled = value;
|
||||
}
|
||||
|
||||
partial void OnIsImmersiveModeChanged(bool value)
|
||||
@@ -258,22 +227,14 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
|
||||
partial void OnShowTranslationOnlyChanged(bool value)
|
||||
{
|
||||
_settingsService.ShowTranslationOnly = value;
|
||||
_settingsService.AppSettings.TranslationSettings.ShowTranslationOnly = value;
|
||||
}
|
||||
|
||||
public void Receive(PropertyChangedMessage<int> message)
|
||||
{
|
||||
if (message.Sender is SettingsPageViewModel.SettingsPageViewModel)
|
||||
if (message.Sender is LyricsStyleSettings)
|
||||
{
|
||||
if (message.PropertyName == nameof(SettingsPageViewModel.SettingsPageViewModel.LyricsStandardFontSize))
|
||||
{
|
||||
UpdateHintMessageFontSize();
|
||||
}
|
||||
else if (message.PropertyName == nameof(SettingsPageViewModel.SettingsPageViewModel.LyricsDockFontSize))
|
||||
{
|
||||
UpdateHintMessageFontSize();
|
||||
}
|
||||
else if (message.PropertyName == nameof(SettingsPageViewModel.SettingsPageViewModel.LyricsDesktopFontSize))
|
||||
if (message.PropertyName == nameof(LyricsStyleSettings.LyricsFontSize))
|
||||
{
|
||||
UpdateHintMessageFontSize();
|
||||
}
|
||||
@@ -282,9 +243,9 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
|
||||
public void Receive(PropertyChangedMessage<string> message)
|
||||
{
|
||||
if (message.Sender is SettingsPageViewModel.SettingsPageViewModel)
|
||||
if (message.Sender is LyricsStyleSettings)
|
||||
{
|
||||
if (message.PropertyName == nameof(SettingsPageViewModel.SettingsPageViewModel.LyricsFontFamily))
|
||||
if (message.PropertyName == nameof(LyricsStyleSettings.LyricsFontFamily))
|
||||
{
|
||||
LyricsFontFamily = message.NewValue;
|
||||
}
|
||||
@@ -312,27 +273,5 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Receive(PropertyChangedMessage<LyricsSearchProvider?> message)
|
||||
{
|
||||
if (message.Sender is LyricsRendererViewModel.LyricsRendererViewModel)
|
||||
{
|
||||
if (message.PropertyName == nameof(LyricsRendererViewModel.LyricsRendererViewModel.LyricsSearchProvider))
|
||||
{
|
||||
LyricsSearchProvider = message.NewValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Receive(PropertyChangedMessage<TranslationSearchProvider?> message)
|
||||
{
|
||||
if (message.Sender is LyricsRendererViewModel.LyricsRendererViewModel)
|
||||
{
|
||||
if (message.PropertyName == nameof(LyricsRendererViewModel.LyricsRendererViewModel.TranslationSearchProvider))
|
||||
{
|
||||
TranslationSearchProvider = message.NewValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.Models.Settings;
|
||||
using BetterLyrics.WinUI3.Services.LastFMService;
|
||||
using BetterLyrics.WinUI3.Services.LibWatcherService;
|
||||
using BetterLyrics.WinUI3.Services.LyricsSearchService;
|
||||
@@ -15,14 +17,15 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
public partial class LyricsRendererViewModel
|
||||
{
|
||||
public LyricsRendererViewModel(
|
||||
ISettingsService settingsService,
|
||||
IMediaSessionsService mediaSessionsService,
|
||||
ILyricsSearchService musicSearchService,
|
||||
ILibWatcherService libWatcherService,
|
||||
ISettingsService settingsService,
|
||||
IMediaSessionsService mediaSessionsService,
|
||||
ILyricsSearchService musicSearchService,
|
||||
ILibWatcherService libWatcherService,
|
||||
ITranslateService libreTranslateService,
|
||||
ILastFMService lastFMService
|
||||
) : base(settingsService)
|
||||
)
|
||||
{
|
||||
_settingsService = settingsService;
|
||||
_lyrcsSearchService = musicSearchService;
|
||||
_mediaSessionsService = mediaSessionsService;
|
||||
_libWatcherService = libWatcherService;
|
||||
@@ -30,78 +33,67 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
|
||||
_lastFMService = lastFMService;
|
||||
|
||||
_mediaSourceProvidersInfo = _settingsService.MediaSourceProvidersInfo;
|
||||
|
||||
_logger = Ioc.Default.GetRequiredService<ILogger<LyricsRendererViewModel>>();
|
||||
|
||||
_albumArtCornerRadius = _settingsService.CoverImageRadius;
|
||||
_isDynamicCoverOverlayEnabled = _settingsService.IsDynamicCoverOverlayEnabled;
|
||||
_albumArtBgOpacity = _settingsService.CoverOverlayOpacity;
|
||||
_albumArtBgBlurAmount = _settingsService.CoverOverlayBlurAmount;
|
||||
_coverAcrylicEffectAmount = _settingsService.CoverAcrylicEffectAmount;
|
||||
_settingsService.AppSettings.MediaSourceProvidersInfo.ItemPropertyChanged += MediaSourceProvidersInfo_ItemPropertyChanged;
|
||||
_settingsService.AppSettings.LocalMediaFolders.CollectionChanged += LocalMediaFolders_CollectionChanged;
|
||||
_settingsService.AppSettings.LocalMediaFolders.ItemPropertyChanged += LocalMediaFolders_ItemPropertyChanged;
|
||||
|
||||
_lyricsBgFontColorType = _settingsService.LyricsBgFontColorType;
|
||||
_lyricsFgFontColorType = _settingsService.LyricsFgFontColorType;
|
||||
_lyricsStyleSettings = _settingsService.AppSettings.StandardLyricsStyleSettings;
|
||||
_lyricsEffectSettings = _settingsService.AppSettings.StandardLyricsEffectSettings;
|
||||
|
||||
_lyricsTextFormat.FontWeight = _settingsService.LyricsFontWeight.ToFontWeight();
|
||||
|
||||
_lyricsTextFormat.FontFamily = _artistTextFormat.FontFamily = _titleTextFormat.FontFamily = _settingsService.LyricsFontFamily;
|
||||
|
||||
_lyricsAlignmentType = _settingsService.LyricsAlignmentType;
|
||||
_lyricsVerticalEdgeOpacity = _settingsService.LyricsVerticalEdgeOpacity;
|
||||
_lyricsLineSpacingFactor = _settingsService.LyricsLineSpacingFactor;
|
||||
|
||||
_lyricsStandardFontSize = _settingsService.LyricsStandardFontSize;
|
||||
_lyricsDockFontSize = _settingsService.LyricsDockFontSize;
|
||||
_lyricsDesktopFontSize = _settingsService.LyricsDesktopFontSize;
|
||||
|
||||
_lyricsBlurAmount = _settingsService.LyricsBlurAmount;
|
||||
_isLyricsGlowEffectEnabled = _settingsService.IsLyricsGlowEffectEnabled;
|
||||
_lyricsGlowEffectScope = _settingsService.LyricsGlowEffectScope;
|
||||
_lyricsHighlightScope = _settingsService.LyricsHighlightScope;
|
||||
|
||||
_customBgFontColor = _settingsService.LyricsCustomBgFontColor;
|
||||
_customFgFontColor = _settingsService.LyricsCustomFgFontColor;
|
||||
|
||||
_lyricsBgTheme = _settingsService.LyricsBackgroundTheme;
|
||||
|
||||
_isFanLyricsEnabled = _settingsService.IsFanLyricsEnabled;
|
||||
|
||||
// 歌词描边
|
||||
_lyricsFontStrokeWidth = _settingsService.LyricsFontStrokeWidth;
|
||||
_lyricsStrokeFontColorType = _settingsService.LyricsStrokeFontColorType;
|
||||
_customStrokeFontColor = _settingsService.LyricsCustomStrokeFontColor;
|
||||
|
||||
_isTranslationEnabled = _settingsService.IsTranslationEnabled;
|
||||
_showTranslationOnly = _settingsService.ShowTranslationOnly;
|
||||
_isLibreTranslateEnabled = _settingsService.IsLibreTranslateEnabled;
|
||||
_targetLanguageIndex = _settingsService.SelectedTargetLanguageIndex;
|
||||
_lyricsTranslationSeparator = _settingsService.LyricsTranslationSeparator;
|
||||
|
||||
_dockPlacement = _settingsService.DockPlacement;
|
||||
|
||||
_titleTextFormat.HorizontalAlignment = _artistTextFormat.HorizontalAlignment = _settingsService.SongInfoAlignmentType.ToCanvasHorizontalAlignment();
|
||||
_titleTextFormat.HorizontalAlignment = _artistTextFormat.HorizontalAlignment = _settingsService.AppSettings.AlbumArtLayoutSettings.SongInfoAlignmentType.ToCanvasHorizontalAlignment();
|
||||
|
||||
_timelineSyncThreshold = 0;
|
||||
|
||||
_canvasYScrollTransition.SetDuration(_settingsService.LyricsScrollDuration / 1000f);
|
||||
_canvasYScrollTransition.SetEasingType(_settingsService.LyricsScrollEasingType);
|
||||
_defaultOpacity = _settingsService.LyricsBgFontOpacity / 100f;
|
||||
_displayType = _displayTypeReceived = _settingsService.AppSettings.GeneralSettings.DisplayType;
|
||||
|
||||
_isLyricsFloatAnimationEnabled = _settingsService.IsLyricsFloatAnimationEnabled;
|
||||
_displayType = _displayTypeReceived = _settingsService.DisplayType;
|
||||
|
||||
_libWatcherService.MusicLibraryFilesChanged +=
|
||||
LibWatcherService_MusicLibraryFilesChanged;
|
||||
_libWatcherService.MusicLibraryFilesChanged += LibWatcherService_MusicLibraryFilesChanged;
|
||||
|
||||
_mediaSessionsService.IsPlayingChanged += PlaybackService_IsPlayingChanged;
|
||||
_mediaSessionsService.SongInfoChanged += PlaybackService_SongInfoChanged;
|
||||
_mediaSessionsService.AlbumArtChangedChanged += PlaybackService_AlbumArtChangedChanged;
|
||||
_mediaSessionsService.TimelineChanged += PlaybackService_TimelineChanged;
|
||||
|
||||
_isPlaying = _mediaSessionsService.IsPlaying;
|
||||
IsPlaying = _mediaSessionsService.IsPlaying;
|
||||
|
||||
UpdateColorConfig();
|
||||
}
|
||||
|
||||
private void LocalMediaFolders_ItemPropertyChanged(object? sender, Extensions.ItemPropertyChangedEventArgs e)
|
||||
{
|
||||
// Music lib changed, re-fetch lyrics
|
||||
_logger.LogInformation("Local lyrics folders changed, refreshing lyrics.");
|
||||
_ = _refreshLyricsRunner.RunAsync(async tokne =>
|
||||
{
|
||||
await RefreshLyricsAsync(tokne);
|
||||
});
|
||||
}
|
||||
|
||||
private void LocalMediaFolders_CollectionChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
// Music lib changed, re-fetch lyrics
|
||||
_logger.LogInformation("Local lyrics folders changed, refreshing lyrics.");
|
||||
_ = _refreshLyricsRunner.RunAsync(async tokne =>
|
||||
{
|
||||
await RefreshLyricsAsync(tokne);
|
||||
});
|
||||
}
|
||||
|
||||
private void MediaSourceProvidersInfo_ItemPropertyChanged(object? sender, Extensions.ItemPropertyChangedEventArgs e)
|
||||
{
|
||||
switch (e.PropertyName)
|
||||
{
|
||||
case nameof(MediaSourceProviderInfo.LyricsSearchProvidersInfo):
|
||||
_logger.LogInformation("MediaSourceProviderInfo.LyricsSearchProvidersInfo changed, refreshing lyrics.");
|
||||
_ = _refreshLyricsRunner.RunAsync(async token =>
|
||||
{
|
||||
await RefreshLyricsAsync(token);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,15 +35,15 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
|
||||
if (_isDockMode)
|
||||
{
|
||||
FillBackground(control, combinedDs, _immersiveBgColorTransition.Value, 0f, _immersiveBgOpacityTransition.Value * _albumArtBgOpacity / 100f);
|
||||
FillBackground(control, combinedDs, _immersiveBgColorTransition.Value, 0f, _immersiveBgOpacityTransition.Value * _settingsService.AppSettings.LyricsBackgroundSettings.PureColorOverlayOpacity / 100f);
|
||||
}
|
||||
else if (_isDesktopMode)
|
||||
{
|
||||
FillBackground(control, combinedDs, _immersiveBgColorTransition.Value, 0f, _immersiveBgOpacityTransition.Value * _albumArtBgOpacity / 100f);
|
||||
FillBackground(control, combinedDs, _immersiveBgColorTransition.Value, 0f, _immersiveBgOpacityTransition.Value * _settingsService.AppSettings.LyricsBackgroundSettings.PureColorOverlayOpacity / 100f);
|
||||
}
|
||||
else
|
||||
{
|
||||
FillBackground(control, combinedDs, _albumArtAccentColorTransition.Value, 0f, _albumArtBgOpacity / 100f);
|
||||
FillBackground(control, combinedDs, _albumArtAccentColorTransition.Value, 0f, _settingsService.AppSettings.LyricsBackgroundSettings.PureColorOverlayOpacity / 100f);
|
||||
DrawAlbumArtBackground(control, combinedDs);
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
_playingLineIndex,
|
||||
out int charStartIndex,
|
||||
out int charLength,
|
||||
out float charProgress
|
||||
out double charProgress
|
||||
);
|
||||
|
||||
ds.DrawText(
|
||||
@@ -102,21 +102,21 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
|
||||
private void DrawBackgroundImgae(OpacityEffect effect, CanvasDrawingSession ds, CanvasBitmap canvasBitmap)
|
||||
{
|
||||
float imageWidth = (float)canvasBitmap.Size.Width;
|
||||
float imageHeight = (float)canvasBitmap.Size.Height;
|
||||
double imageWidth = (double)canvasBitmap.Size.Width;
|
||||
double imageHeight = (double)canvasBitmap.Size.Height;
|
||||
|
||||
float targetSize = MathF.Sqrt(MathF.Pow(_canvasWidth, 2) + MathF.Pow(_canvasHeight, 2));
|
||||
float scaleFactor = targetSize / MathF.Min(imageWidth, imageHeight);
|
||||
double targetSize = Math.Sqrt(Math.Pow(_canvasWidth, 2) + Math.Pow(_canvasHeight, 2));
|
||||
double scaleFactor = targetSize / Math.Min(imageWidth, imageHeight);
|
||||
|
||||
float x = _canvasWidth / 2 - imageWidth * scaleFactor / 2;
|
||||
float y = _canvasHeight / 2 - imageHeight * scaleFactor / 2;
|
||||
double x = _canvasWidth / 2 - imageWidth * scaleFactor / 2;
|
||||
double y = _canvasHeight / 2 - imageHeight * scaleFactor / 2;
|
||||
|
||||
ds.DrawImage(effect, new Vector2(x, y));
|
||||
ds.DrawImage(effect, new Vector2((float)x, (float)y));
|
||||
}
|
||||
|
||||
private void DrawForegroundImgae(OpacityEffect effect, CanvasDrawingSession ds)
|
||||
{
|
||||
ds.DrawImage(effect, new Vector2(_albumArtXTransition.Value, _albumArtYTransition.Value));
|
||||
ds.DrawImage(effect, new Vector2((float)_albumArtXTransition.Value, (float)_albumArtYTransition.Value));
|
||||
}
|
||||
|
||||
private void DrawAlbumArtBackground(ICanvasAnimatedControl control, CanvasDrawingSession ds)
|
||||
@@ -126,7 +126,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
return;
|
||||
}
|
||||
|
||||
ds.Transform = Matrix3x2.CreateRotation(_rotateAngle, control.Size.ToVector2() * 0.5f);
|
||||
ds.Transform = Matrix3x2.CreateRotation((float)_rotateAngle, control.Size.ToVector2() * 0.5f);
|
||||
ds.DrawImage(_albumArtBgEffect);
|
||||
ds.Transform = Matrix3x2.Identity;
|
||||
}
|
||||
@@ -158,7 +158,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
ds.DrawImage(new OpacityEffect
|
||||
{
|
||||
Source = opacity,
|
||||
Opacity = _albumArtOpacityTransition.Value
|
||||
Opacity = (float)_albumArtOpacityTransition.Value
|
||||
});
|
||||
}
|
||||
|
||||
@@ -174,7 +174,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawSingleTitleAndArtist(ICanvasAnimatedControl control, CanvasDrawingSession ds, string? title, string? artist, float opacity)
|
||||
private void DrawSingleTitleAndArtist(ICanvasAnimatedControl control, CanvasDrawingSession ds, string? title, string? artist, double opacity)
|
||||
{
|
||||
var maxWidth = _lyricsLayoutOrientation switch
|
||||
{
|
||||
@@ -189,19 +189,19 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
|
||||
using CanvasTextLayout titleLayout = new(
|
||||
control, title ?? string.Empty,
|
||||
_titleTextFormat, maxWidth, _canvasHeight
|
||||
_titleTextFormat, (float)maxWidth, (float)_canvasHeight
|
||||
);
|
||||
using CanvasTextLayout artistLayout = new(
|
||||
control, artist ?? string.Empty,
|
||||
_artistTextFormat, maxWidth, _canvasHeight
|
||||
_artistTextFormat, (float)maxWidth, (float)_canvasHeight
|
||||
);
|
||||
ds.DrawTextLayout(
|
||||
titleLayout,
|
||||
new Vector2(_titleXTransition.Value, _titleYTransition.Value),
|
||||
new Vector2((float)_titleXTransition.Value, (float)_titleYTransition.Value),
|
||||
_bgFontColor.WithAlpha((byte)(_albumArtOpacityTransition.Value * 255 * opacity)));
|
||||
ds.DrawTextLayout(
|
||||
artistLayout,
|
||||
new Vector2(_titleXTransition.Value, _titleYTransition.Value + (float)titleLayout.LayoutBounds.Height),
|
||||
new Vector2((float)_titleXTransition.Value, (float)(_titleYTransition.Value + titleLayout.LayoutBounds.Height)),
|
||||
_bgFontColor.WithAlpha((byte)(_albumArtOpacityTransition.Value * 128 * opacity)));
|
||||
}
|
||||
|
||||
@@ -224,18 +224,18 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
var textLayout = line.CanvasTextLayout;
|
||||
if (textLayout == null) continue;
|
||||
|
||||
float layoutWidth = (float)textLayout.LayoutBounds.Width;
|
||||
float layoutHeight = (float)textLayout.LayoutBounds.Height;
|
||||
double layoutWidth = (double)textLayout.LayoutBounds.Width;
|
||||
double layoutHeight = (double)textLayout.LayoutBounds.Height;
|
||||
|
||||
if (layoutWidth <= 0 || layoutHeight <= 0) continue;
|
||||
|
||||
float yOffset = _canvasYScrollTransition.Value + _canvasHeight / 2 + _lyricsYTransition.Value;
|
||||
double yOffset = line.YOffsetTransition.Value + _canvasHeight / 2 + _lyricsYTransition.Value;
|
||||
|
||||
// 组合变换:缩放 -> 旋转 -> 平移
|
||||
ds.Transform =
|
||||
Matrix3x2.CreateScale(line.ScaleTransition.Value, line.CenterPosition)
|
||||
* Matrix3x2.CreateRotation(line.AngleTransition.Value, currentPlayingLine.Position)
|
||||
* Matrix3x2.CreateTranslation(_lyricsXTransition.Value, yOffset);
|
||||
Matrix3x2.CreateScale((float)line.ScaleTransition.Value, line.CenterPosition)
|
||||
* Matrix3x2.CreateRotation((float)line.AngleTransition.Value, currentPlayingLine.Position)
|
||||
* Matrix3x2.CreateTranslation((float)_lyricsXTransition.Value, (float)yOffset);
|
||||
|
||||
if (line.BackgroundFontEffect == null || line.ForegroundFontEffect == null) continue;
|
||||
|
||||
@@ -245,183 +245,35 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
// Mock gradient blurred lyrics layer
|
||||
// 先铺一层带默认透明度的已经加了模糊效果的歌词作为最底层(背景歌词层次)
|
||||
// Current line will not be blurred
|
||||
combinedDs.DrawImage(
|
||||
new OpacityEffect
|
||||
{
|
||||
Source = new GaussianBlurEffect
|
||||
{
|
||||
Source = line.BackgroundFontEffect,
|
||||
BlurAmount = line.BlurAmountTransition.Value,
|
||||
BorderMode = EffectBorderMode.Soft,
|
||||
Optimization = EffectOptimization.Speed,
|
||||
},
|
||||
Opacity = line.OpacityTransition.Value * _lyricsOpacityTransition.Value,
|
||||
}
|
||||
);
|
||||
combinedDs.DrawImage(line.BackgroundEffect);
|
||||
|
||||
if (line.HighlightOpacityTransition.Value != 0)
|
||||
{
|
||||
// 再叠加高亮行歌词层(前景歌词层)
|
||||
using var mask = new CanvasCommandList(control.Device);
|
||||
using var maskDs = mask.CreateDrawingSession();
|
||||
|
||||
using var highlightMask = new CanvasCommandList(control.Device);
|
||||
using var highlightMaskDs = highlightMask.CreateDrawingSession();
|
||||
|
||||
if (i == _playingLineIndex)
|
||||
if (line.ForegroundBlurEffect == null || line.ForegroundHighlightEffect == null || line.PlaceholderEffect == null)
|
||||
{
|
||||
GetLinePlayingProgress(
|
||||
i,
|
||||
out int charStartIndex,
|
||||
out int charLength,
|
||||
out float charProgress
|
||||
);
|
||||
var regions = textLayout.GetCharacterRegions(0, charStartIndex);
|
||||
var highlightRegion = textLayout
|
||||
.GetCharacterRegions(charStartIndex, charLength)
|
||||
.FirstOrDefault();
|
||||
if (regions.Length > 0)
|
||||
{
|
||||
// Draw the mask for the current line
|
||||
for (int j = 0; j < regions.Length; j++)
|
||||
{
|
||||
var region = regions[j];
|
||||
var rect = new Rect(
|
||||
region.LayoutBounds.X,
|
||||
region.LayoutBounds.Y + line.Position.Y,
|
||||
region.LayoutBounds.Width,
|
||||
region.LayoutBounds.Height
|
||||
);
|
||||
maskDs.FillRectangle(rect, Color.FromArgb(255, 128, 128, 128));
|
||||
}
|
||||
}
|
||||
|
||||
float highlightTotalWidth = (float)highlightRegion.LayoutBounds.Width;
|
||||
// Draw the highlight for the current character
|
||||
float highlightWidth = highlightTotalWidth * charProgress;
|
||||
|
||||
float fadingWidth = (float)highlightRegion.LayoutBounds.Height / 2;
|
||||
|
||||
// Rects
|
||||
var highlightRect = new Rect(
|
||||
highlightRegion.LayoutBounds.X,
|
||||
highlightRegion.LayoutBounds.Y + line.Position.Y,
|
||||
highlightWidth,
|
||||
highlightRegion.LayoutBounds.Height
|
||||
);
|
||||
|
||||
var fadeInRect = new Rect(
|
||||
highlightRect.Right - fadingWidth,
|
||||
highlightRegion.LayoutBounds.Y + line.Position.Y,
|
||||
fadingWidth,
|
||||
highlightRegion.LayoutBounds.Height
|
||||
);
|
||||
var fadeOutRect = new Rect(
|
||||
highlightRect.Right,
|
||||
highlightRegion.LayoutBounds.Y + line.Position.Y,
|
||||
fadingWidth,
|
||||
highlightRegion.LayoutBounds.Height
|
||||
);
|
||||
|
||||
// Brushes
|
||||
using var fadeInBrush = CreateHorizontalFillBrush(
|
||||
control,
|
||||
[(0f, 0f), (1f, 1f)],
|
||||
(float)highlightRect.Right - fadingWidth,
|
||||
fadingWidth
|
||||
);
|
||||
using var fadeOutBrush = CreateHorizontalFillBrush(
|
||||
control,
|
||||
[(0f, 1f), (1f, 0f)],
|
||||
(float)highlightRect.Right,
|
||||
fadingWidth
|
||||
);
|
||||
|
||||
maskDs.FillRectangle(highlightRect, Color.FromArgb(255, 128, 128, 128));
|
||||
maskDs.FillRectangle(fadeOutRect, fadeOutBrush);
|
||||
|
||||
highlightMaskDs.FillRectangle(fadeInRect, fadeInBrush);
|
||||
highlightMaskDs.FillRectangle(fadeOutRect, fadeOutBrush);
|
||||
}
|
||||
else
|
||||
{
|
||||
//float height = 0f;
|
||||
var regions = textLayout.GetCharacterRegions(0, line.OriginalText.Length);
|
||||
if (regions.Length > 0)
|
||||
{
|
||||
//height = (float)regions[^1].LayoutBounds.Bottom - (float)regions[0].LayoutBounds.Top;
|
||||
|
||||
for (int j = 0; j < regions.Length; j++)
|
||||
{
|
||||
var region = regions[j];
|
||||
var rect = new Rect(
|
||||
region.LayoutBounds.X,
|
||||
region.LayoutBounds.Y + line.Position.Y,
|
||||
region.LayoutBounds.Width,
|
||||
region.LayoutBounds.Height
|
||||
);
|
||||
maskDs.FillRectangle(rect, Colors.White);
|
||||
}
|
||||
}
|
||||
|
||||
//maskDs.FillRectangle(
|
||||
// new Rect(
|
||||
// textLayout.LayoutBounds.X,
|
||||
// line.Position.Y,
|
||||
// textLayout.LayoutBounds.Width,
|
||||
// height
|
||||
// ),
|
||||
// Colors.White
|
||||
//);
|
||||
return;
|
||||
}
|
||||
|
||||
using var opacityEffect = new OpacityEffect
|
||||
{
|
||||
Source = new BlendEffect
|
||||
{
|
||||
Background = _isLyricsGlowEffectEnabled
|
||||
? new GaussianBlurEffect
|
||||
{
|
||||
Source = new AlphaMaskEffect
|
||||
{
|
||||
Source = line.ForegroundFontEffect,
|
||||
AlphaMask = _lyricsGlowEffectScope switch
|
||||
{
|
||||
LineRenderingType.CurrentChar => highlightMask,
|
||||
LineRenderingType.LineStartToCurrentChar => mask,
|
||||
LineRenderingType.CurrentLine => line.ForegroundFontEffect,
|
||||
_ => mask,
|
||||
},
|
||||
},
|
||||
BlurAmount = _lyricsGlowEffectAmount,
|
||||
Optimization = EffectOptimization.Speed,
|
||||
}
|
||||
: new CanvasCommandList(control.Device),
|
||||
Foreground = new AlphaMaskEffect
|
||||
{
|
||||
Source = line.ForegroundFontEffect,
|
||||
AlphaMask = _lyricsHighlightScope switch
|
||||
{
|
||||
LineRenderingType.CurrentChar => highlightMask,
|
||||
LineRenderingType.LineStartToCurrentChar => mask,
|
||||
LineRenderingType.CurrentLine => line.ForegroundFontEffect,
|
||||
_ => mask,
|
||||
},
|
||||
},
|
||||
Background = _lyricsEffectSettings.IsLyricsGlowEffectEnabled ? line.ForegroundBlurEffect : line.PlaceholderEffect,
|
||||
Foreground = line.ForegroundHighlightEffect,
|
||||
},
|
||||
Opacity = line.HighlightOpacityTransition.Value * _lyricsOpacityTransition.Value,
|
||||
Opacity = (float)(line.HighlightOpacityTransition.Value * _lyricsOpacityTransition.Value),
|
||||
};
|
||||
|
||||
combinedDs.DrawImage(opacityEffect);
|
||||
|
||||
if (i == _playingLineIndex)
|
||||
{
|
||||
if (_isLyricsFloatAnimationEnabled)
|
||||
if (_lyricsEffectSettings.IsLyricsFloatAnimationEnabled)
|
||||
{
|
||||
ds.DrawImage(new DisplacementMapEffect
|
||||
{
|
||||
Source = combined,
|
||||
Displacement = mask,
|
||||
Displacement = line.LineStartToCurrentCharMask,
|
||||
XChannelSelect = EffectChannelSelect.Red,
|
||||
YChannelSelect = EffectChannelSelect.Alpha,
|
||||
Amount = 1f,
|
||||
@@ -444,65 +296,44 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
|
||||
// Reset scale
|
||||
ds.Transform = Matrix3x2.Identity;
|
||||
|
||||
line.DisposeFontEffects();
|
||||
line.DisposeTextGeometry();
|
||||
}
|
||||
}
|
||||
|
||||
private void FillBackground(ICanvasAnimatedControl control, CanvasDrawingSession ds, Color color, float radius, float opacity)
|
||||
private void FillBackground(ICanvasAnimatedControl control, CanvasDrawingSession ds, Color color, double radius, double opacity)
|
||||
{
|
||||
ds.FillRoundedRectangle(
|
||||
new Rect(0, 0, _canvasWidth, _canvasHeight),
|
||||
radius,
|
||||
radius,
|
||||
(float)radius,
|
||||
(float)radius,
|
||||
color.WithAlpha((byte)(opacity * 255))
|
||||
);
|
||||
}
|
||||
|
||||
private void FillBackground(ICanvasAnimatedControl control, CanvasDrawingSession ds, CanvasLinearGradientBrush brush, float radius, float opacity)
|
||||
private void FillBackground(ICanvasAnimatedControl control, CanvasDrawingSession ds, CanvasLinearGradientBrush brush, double radius, double opacity)
|
||||
{
|
||||
ds.FillRoundedRectangle(
|
||||
new Rect(0, 0, _canvasWidth, _canvasHeight),
|
||||
radius,
|
||||
radius,
|
||||
(float)radius,
|
||||
(float)radius,
|
||||
brush
|
||||
);
|
||||
}
|
||||
|
||||
private CanvasLinearGradientBrush CreateHorizontalFillBrush(
|
||||
ICanvasAnimatedControl control,
|
||||
List<(float position, float opacity)> stops,
|
||||
float startX,
|
||||
float width
|
||||
)
|
||||
{
|
||||
return new CanvasLinearGradientBrush(control, stops.Select(stops => new CanvasGradientStop
|
||||
{
|
||||
Position = stops.position,
|
||||
Color = Color.FromArgb((byte)(stops.opacity * 255), 128, 128, 128),
|
||||
}).ToArray())
|
||||
{
|
||||
StartPoint = new Vector2(startX, 0),
|
||||
EndPoint = new Vector2(startX + width, 0),
|
||||
};
|
||||
}
|
||||
|
||||
private CanvasLinearGradientBrush CreateVerticalFillBrush(
|
||||
ICanvasAnimatedControl control,
|
||||
List<(float position, Color color)> stops,
|
||||
float startY,
|
||||
float height
|
||||
List<(double position, Color color)> stops,
|
||||
double startY,
|
||||
double height
|
||||
)
|
||||
{
|
||||
return new CanvasLinearGradientBrush(control, stops.Select(x => new CanvasGradientStop
|
||||
{
|
||||
Position = x.position,
|
||||
Position = (float)x.position,
|
||||
Color = x.color,
|
||||
}).ToArray())
|
||||
{
|
||||
StartPoint = new Vector2(0, startY),
|
||||
EndPoint = new Vector2(0, startY + height),
|
||||
StartPoint = new Vector2(0, (float)startY),
|
||||
EndPoint = new Vector2(0, (float)(startY + height)),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,21 +19,21 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
|
||||
private CanvasCommandList? _albumArtBgEffect;
|
||||
|
||||
private OpacityEffect CreateBgImageEffect(CanvasBitmap canvasBitmap, float opacity)
|
||||
private OpacityEffect CreateBgImageEffect(CanvasBitmap canvasBitmap, double opacity)
|
||||
{
|
||||
float imageWidth = (float)canvasBitmap.Size.Width;
|
||||
float imageHeight = (float)canvasBitmap.Size.Height;
|
||||
double imageWidth = (double)canvasBitmap.Size.Width;
|
||||
double imageHeight = (double)canvasBitmap.Size.Height;
|
||||
|
||||
float targetSize = MathF.Sqrt(MathF.Pow(_canvasWidth, 2) + MathF.Pow(_canvasHeight, 2));
|
||||
float scaleFactor = targetSize / MathF.Min(imageWidth, imageHeight);
|
||||
double targetSize = Math.Sqrt(Math.Pow(_canvasWidth, 2) + Math.Pow(_canvasHeight, 2));
|
||||
double scaleFactor = targetSize / Math.Min(imageWidth, imageHeight);
|
||||
|
||||
// Original source: https://zhuanlan.zhihu.com/p/37178216
|
||||
float gain = _lyricsBgBrightnessTransition.Value;
|
||||
double gain = _lyricsBgBrightnessTransition.Value;
|
||||
|
||||
float whiteX = 1 - 0.5f * gain;
|
||||
float whiteY = 0.5f + 0.5f * gain;
|
||||
float blackX = 0.5f - 0.5f * gain;
|
||||
float blackY = 0 + 0.5f * gain;
|
||||
double whiteX = 1 - 0.5f * gain;
|
||||
double whiteY = 0.5f + 0.5f * gain;
|
||||
double blackX = 0.5f - 0.5f * gain;
|
||||
double blackY = 0 + 0.5f * gain;
|
||||
|
||||
return new OpacityEffect
|
||||
{
|
||||
@@ -41,34 +41,33 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
{
|
||||
Source = new ScaleEffect
|
||||
{
|
||||
Scale = new Vector2(scaleFactor),
|
||||
Scale = new Vector2((float)scaleFactor),
|
||||
Source = canvasBitmap,
|
||||
},
|
||||
WhitePoint = new Vector2(whiteX, whiteY),
|
||||
BlackPoint = new Vector2(blackX, blackY),
|
||||
WhitePoint = new Vector2((float)whiteX, (float)whiteY),
|
||||
BlackPoint = new Vector2((float)blackX, (float)blackY),
|
||||
},
|
||||
Opacity = opacity,
|
||||
Opacity = (float)opacity,
|
||||
};
|
||||
}
|
||||
|
||||
private OpacityEffect? CreateFgImageEffect(ICanvasAnimatedControl control, CanvasBitmap canvasBitmap, float opacity)
|
||||
private OpacityEffect? CreateFgImageEffect(ICanvasAnimatedControl control, CanvasBitmap canvasBitmap, double opacity)
|
||||
{
|
||||
// TODO 最大化/还原时图片大小未跟随改变
|
||||
if (opacity == 0) return null;
|
||||
|
||||
float imageWidth = (float)canvasBitmap.Size.Width;
|
||||
float imageHeight = (float)canvasBitmap.Size.Height;
|
||||
double imageWidth = (double)canvasBitmap.Size.Width;
|
||||
double imageHeight = (double)canvasBitmap.Size.Height;
|
||||
|
||||
float scaleFactor = _albumArtSize / Math.Min(imageWidth, imageHeight);
|
||||
double scaleFactor = _albumArtSize / Math.Min(imageWidth, imageHeight);
|
||||
if (scaleFactor < 0.01f) return null;
|
||||
|
||||
float cornerRadius = _albumArtCornerRadius / 100f * _albumArtSize / 2;
|
||||
double cornerRadius = _settingsService.AppSettings.AlbumArtLayoutSettings.CoverImageRadius / 100f * _albumArtSize / 2;
|
||||
|
||||
var cornerRadiusMask = new CanvasCommandList(control);
|
||||
using var cornerRadiusMaskDs = cornerRadiusMask.CreateDrawingSession();
|
||||
cornerRadiusMaskDs.FillRoundedRectangle(
|
||||
new Rect(0, 0, imageWidth * scaleFactor, imageHeight * scaleFactor),
|
||||
cornerRadius, cornerRadius, Colors.White
|
||||
(float)cornerRadius, (float)cornerRadius, Colors.White
|
||||
);
|
||||
|
||||
return new OpacityEffect
|
||||
@@ -77,12 +76,12 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
{
|
||||
Source = new ScaleEffect
|
||||
{
|
||||
Scale = new Vector2(scaleFactor),
|
||||
Scale = new Vector2((float)scaleFactor),
|
||||
Source = canvasBitmap,
|
||||
},
|
||||
AlphaMask = cornerRadiusMask,
|
||||
},
|
||||
Opacity = opacity,
|
||||
Opacity = (float)opacity,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -105,7 +104,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
|
||||
using var blurredCover = new GaussianBlurEffect
|
||||
{
|
||||
BlurAmount = _albumArtBgBlurAmount,
|
||||
BlurAmount = _settingsService.AppSettings.LyricsBackgroundSettings.CoverOverlayBlurAmount,
|
||||
Source = overlappedCovers,
|
||||
BorderMode = EffectBorderMode.Soft,
|
||||
Optimization = EffectOptimization.Speed,
|
||||
@@ -114,7 +113,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
using var combined = new CanvasCommandList(control);
|
||||
using var combinedDs = combined.CreateDrawingSession();
|
||||
|
||||
if (_coverAcrylicEffectAmount > 0 && _coverAcrylicNoiseCanvasBitmap != null)
|
||||
if (_settingsService.AppSettings.LyricsBackgroundSettings.CoverAcrylicEffectAmount > 0 && _coverAcrylicNoiseCanvasBitmap != null)
|
||||
{
|
||||
// 应用亚克力噪点效果
|
||||
combinedDs.DrawImage(new BlendEffect
|
||||
@@ -124,7 +123,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
Foreground = new OpacityEffect
|
||||
{
|
||||
Source = _coverAcrylicNoiseCanvasBitmap,
|
||||
Opacity = _coverAcrylicEffectAmount / 100f,
|
||||
Opacity = _settingsService.AppSettings.LyricsBackgroundSettings.CoverAcrylicEffectAmount / 100f,
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -137,7 +136,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
using var albumArtBgDs = _albumArtBgEffect.CreateDrawingSession();
|
||||
albumArtBgDs.DrawImage(new OpacityEffect
|
||||
{
|
||||
Opacity = _albumArtBgOpacity / 100f,
|
||||
Opacity = _settingsService.AppSettings.LyricsBackgroundSettings.CoverOverlayOpacity / 100f,
|
||||
Source = combined,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using BetterLyrics.WinUI3.Extensions;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.Models.Settings;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using CommunityToolkit.Mvvm.Messaging.Messages;
|
||||
using Microsoft.Extensions.Logging;
|
||||
@@ -15,7 +17,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
public partial class LyricsRendererViewModel
|
||||
: IRecipient<PropertyChangedMessage<int>>,
|
||||
IRecipient<PropertyChangedMessage<string>>,
|
||||
IRecipient<PropertyChangedMessage<float>>,
|
||||
IRecipient<PropertyChangedMessage<double>>,
|
||||
IRecipient<PropertyChangedMessage<bool>>,
|
||||
IRecipient<PropertyChangedMessage<Color>>,
|
||||
IRecipient<PropertyChangedMessage<LyricsDisplayType>>,
|
||||
@@ -24,78 +26,45 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
IRecipient<PropertyChangedMessage<LyricsFontWeight>>,
|
||||
IRecipient<PropertyChangedMessage<LineRenderingType>>,
|
||||
IRecipient<PropertyChangedMessage<ElementTheme>>,
|
||||
IRecipient<PropertyChangedMessage<EasingType>>,
|
||||
IRecipient<PropertyChangedMessage<DockPlacement>>,
|
||||
IRecipient<PropertyChangedMessage<ObservableCollection<MediaSourceProviderInfo>>>,
|
||||
IRecipient<PropertyChangedMessage<ObservableCollection<LocalMediaFolder>>>
|
||||
IRecipient<PropertyChangedMessage<EasingType>>
|
||||
{
|
||||
public void Receive(PropertyChangedMessage<ObservableCollection<LocalMediaFolder>> message)
|
||||
{
|
||||
if (message.Sender is SettingsPageViewModel.SettingsPageViewModel)
|
||||
{
|
||||
if (message.PropertyName == nameof(SettingsPageViewModel.SettingsPageViewModel.LocalMediaFolders))
|
||||
{
|
||||
// Music lib changed, re-fetch lyrics
|
||||
_logger.LogInformation("Local lyrics folders changed, refreshing lyrics.");
|
||||
_ = _refreshLyricsRunner.RunAsync(async tokne =>
|
||||
{
|
||||
await RefreshLyricsAsync(tokne);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Receive(PropertyChangedMessage<ObservableCollection<MediaSourceProviderInfo>> message)
|
||||
{
|
||||
if (message.Sender is SettingsPageViewModel.SettingsPageViewModel)
|
||||
{
|
||||
if (message.PropertyName == nameof(SettingsPageViewModel.SettingsPageViewModel.MediaSourceProvidersInfo))
|
||||
{
|
||||
_mediaSourceProvidersInfo = message.NewValue.ToList();
|
||||
|
||||
UpdateTimelineSyncThreshold();
|
||||
UpdatePositionOffset();
|
||||
UpdateIsLastFMTrackEnabled();
|
||||
|
||||
// Media source providers info changed (maybe include lyrics search providers info changed), re-fetch lyrics
|
||||
_logger.LogInformation("Lyrics search providers info changed, refreshing lyrics.");
|
||||
_ = _refreshLyricsRunner.RunAsync(async token =>
|
||||
{
|
||||
await RefreshLyricsAsync(token);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Receive(PropertyChangedMessage<bool> message)
|
||||
{
|
||||
if (message.Sender is SettingsPageViewModel.SettingsPageViewModel)
|
||||
if (message.Sender is SettingsPageViewModel)
|
||||
{
|
||||
if (message.PropertyName == nameof(SettingsPageViewModel.SettingsPageViewModel.IsDynamicCoverOverlayEnabled))
|
||||
{
|
||||
_isDynamicCoverOverlayEnabled = message.NewValue;
|
||||
}
|
||||
else if (message.PropertyName == nameof(SettingsPageViewModel.SettingsPageViewModel.IsDebugOverlayEnabled))
|
||||
if (message.PropertyName == nameof(SettingsPageViewModel.IsDebugOverlayEnabled))
|
||||
{
|
||||
_isDebugOverlayEnabled = message.NewValue;
|
||||
_isDebugOverlayEnabledChanged = true;
|
||||
}
|
||||
else if (message.PropertyName == nameof(SettingsPageViewModel.SettingsPageViewModel.IsLyricsGlowEffectEnabled))
|
||||
}
|
||||
else if (message.Sender is LyricsEffectSettings)
|
||||
{
|
||||
if (message.PropertyName == nameof(LyricsEffectSettings.IsLyricsGlowEffectEnabled))
|
||||
{
|
||||
_isLyricsGlowEffectEnabled = message.NewValue;
|
||||
}
|
||||
else if (message.PropertyName == nameof(SettingsPageViewModel.SettingsPageViewModel.IsFanLyricsEnabled))
|
||||
else if (message.PropertyName == nameof(LyricsEffectSettings.IsFanLyricsEnabled))
|
||||
{
|
||||
_isFanLyricsEnabled = message.NewValue;
|
||||
_isLayoutChanged = true;
|
||||
}
|
||||
else if (message.PropertyName == nameof(SettingsPageViewModel.SettingsPageViewModel.IsLyricsFloatAnimationEnabled))
|
||||
else if (message.PropertyName == nameof(LyricsEffectSettings.IsLyricsFloatAnimationEnabled))
|
||||
{
|
||||
_isLyricsFloatAnimationEnabled = message.NewValue;
|
||||
}
|
||||
else if (message.PropertyName == nameof(SettingsPageViewModel.SettingsPageViewModel.IsLibreTranslateEnabled))
|
||||
}
|
||||
else if (message.Sender is TranslationSettings)
|
||||
{
|
||||
if (message.PropertyName == nameof(TranslationSettings.IsLibreTranslateEnabled))
|
||||
{
|
||||
UpdateTranslations();
|
||||
}
|
||||
else if (message.PropertyName == nameof(TranslationSettings.IsTranslationEnabled))
|
||||
{
|
||||
_logger.LogInformation("Translation enabled state changed: {IsEnabled}", _settingsService.AppSettings.TranslationSettings.IsTranslationEnabled);
|
||||
UpdateTranslations();
|
||||
}
|
||||
else if (message.PropertyName == nameof(TranslationSettings.ShowTranslationOnly))
|
||||
{
|
||||
_isLibreTranslateEnabled = message.NewValue;
|
||||
UpdateTranslations();
|
||||
}
|
||||
}
|
||||
@@ -126,20 +95,25 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
UpdateImmersiveBackgroundOpacity();
|
||||
}
|
||||
}
|
||||
else if (message.Sender is LyricsPageViewModel)
|
||||
else if (message.Sender is MediaSourceProviderInfo)
|
||||
{
|
||||
if (message.PropertyName == nameof(LyricsPageViewModel.IsTranslationEnabled))
|
||||
if (message.PropertyName == nameof(MediaSourceProviderInfo.IsLastFMTrackEnabled))
|
||||
{
|
||||
_isTranslationEnabled = message.NewValue;
|
||||
_logger.LogInformation("Translation enabled state changed: {IsEnabled}", _isTranslationEnabled);
|
||||
UpdateTranslations();
|
||||
}
|
||||
else if (message.PropertyName == nameof(LyricsPageViewModel.ShowTranslationOnly))
|
||||
{
|
||||
_showTranslationOnly = message.NewValue;
|
||||
UpdateTranslations();
|
||||
UpdateIsLastFMTrackEnabled();
|
||||
}
|
||||
}
|
||||
if (message.Sender is LyricsSearchProviderInfo)
|
||||
{
|
||||
if (message.PropertyName == nameof(LyricsSearchProviderInfo.IsEnabled))
|
||||
{
|
||||
_logger.LogInformation("LyricsSearchProviderInfo.IsEnabled changed, refreshing lyrics.");
|
||||
_ = _refreshLyricsRunner.RunAsync(async token =>
|
||||
{
|
||||
await RefreshLyricsAsync(token);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void Receive(PropertyChangedMessage<Color> message)
|
||||
@@ -153,33 +127,29 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
UpdateColorConfig();
|
||||
}
|
||||
}
|
||||
else if (message.Sender is SettingsPageViewModel.SettingsPageViewModel)
|
||||
else if (message.Sender is LyricsStyleSettings)
|
||||
{
|
||||
if (message.PropertyName == nameof(SettingsPageViewModel.SettingsPageViewModel.LyricsCustomBgFontColor))
|
||||
if (message.PropertyName == nameof(LyricsStyleSettings.LyricsCustomBgFontColor))
|
||||
{
|
||||
_customBgFontColor = message.NewValue;
|
||||
UpdateColorConfig();
|
||||
}
|
||||
else if (message.PropertyName == nameof(SettingsPageViewModel.SettingsPageViewModel.LyricsCustomFgFontColor))
|
||||
else if (message.PropertyName == nameof(LyricsStyleSettings.LyricsCustomFgFontColor))
|
||||
{
|
||||
_customFgFontColor = message.NewValue;
|
||||
UpdateColorConfig();
|
||||
}
|
||||
else if (message.PropertyName == nameof(SettingsPageViewModel.SettingsPageViewModel.LyricsCustomStrokeFontColor))
|
||||
else if (message.PropertyName == nameof(LyricsStyleSettings.LyricsCustomStrokeFontColor))
|
||||
{
|
||||
_customStrokeFontColor = message.NewValue;
|
||||
UpdateColorConfig();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Receive(PropertyChangedMessage<float> message)
|
||||
public void Receive(PropertyChangedMessage<double> message)
|
||||
{
|
||||
if (message.Sender is SettingsPageViewModel.SettingsPageViewModel)
|
||||
if (message.Sender is LyricsStyleSettings)
|
||||
{
|
||||
if (message.PropertyName == nameof(SettingsPageViewModel.SettingsPageViewModel.LyricsLineSpacingFactor))
|
||||
if (message.PropertyName == nameof(LyricsStyleSettings.LyricsLineSpacingFactor))
|
||||
{
|
||||
_lyricsLineSpacingFactor = message.NewValue;
|
||||
_isLayoutChanged = true;
|
||||
}
|
||||
}
|
||||
@@ -187,102 +157,120 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
|
||||
public void Receive(PropertyChangedMessage<int> message)
|
||||
{
|
||||
if (message.Sender is SettingsPageViewModel.SettingsPageViewModel)
|
||||
if (message.Sender is AlbumArtLayoutSettings)
|
||||
{
|
||||
if (message.PropertyName == nameof(SettingsPageViewModel.SettingsPageViewModel.CoverImageRadius))
|
||||
if (message.PropertyName == nameof(AlbumArtLayoutSettings.CoverImageRadius))
|
||||
{
|
||||
_albumArtCornerRadius = message.NewValue;
|
||||
_isAlbumArtCornerRadiusChanged = true;
|
||||
}
|
||||
else if (message.PropertyName == nameof(SettingsPageViewModel.SettingsPageViewModel.CoverOverlayOpacity))
|
||||
}
|
||||
else if (message.Sender is LyricsBackgroundSettings)
|
||||
{
|
||||
if (message.PropertyName == nameof(LyricsBackgroundSettings.CoverOverlayOpacity))
|
||||
{
|
||||
_albumArtBgOpacity = message.NewValue;
|
||||
_isAlbumArtBgOpacityChanged = true;
|
||||
}
|
||||
else if (message.PropertyName == nameof(SettingsPageViewModel.SettingsPageViewModel.CoverOverlayBlurAmount))
|
||||
else if (message.PropertyName == nameof(LyricsBackgroundSettings.CoverOverlayBlurAmount))
|
||||
{
|
||||
_albumArtBgBlurAmount = message.NewValue;
|
||||
_isAlbumArtBgBlurAmountChanged = true;
|
||||
}
|
||||
else if (message.PropertyName == nameof(SettingsPageViewModel.SettingsPageViewModel.CoverAcrylicEffectAmount))
|
||||
else if (message.PropertyName == nameof(LyricsBackgroundSettings.CoverAcrylicEffectAmount))
|
||||
{
|
||||
_coverAcrylicEffectAmount = message.NewValue;
|
||||
_isCoverAcrylicEffectAmountChanged = true;
|
||||
}
|
||||
else if (message.PropertyName == nameof(SettingsPageViewModel.SettingsPageViewModel.LyricsVerticalEdgeOpacity))
|
||||
else if (message.PropertyName == nameof(LyricsBackgroundSettings.CoverOverlaySpeed))
|
||||
{
|
||||
}
|
||||
}
|
||||
else if (message.Sender is LyricsEffectSettings)
|
||||
{
|
||||
if (message.PropertyName == nameof(LyricsEffectSettings.LyricsVerticalEdgeOpacity))
|
||||
{
|
||||
_lyricsVerticalEdgeOpacity = message.NewValue;
|
||||
_isLayoutChanged = true;
|
||||
}
|
||||
else if (message.PropertyName == nameof(SettingsPageViewModel.SettingsPageViewModel.LyricsBlurAmount))
|
||||
else if (message.PropertyName == nameof(LyricsEffectSettings.LyricsBlurAmount))
|
||||
{
|
||||
_lyricsBlurAmount = message.NewValue;
|
||||
_isLayoutChanged = true;
|
||||
}
|
||||
else if (message.PropertyName == nameof(SettingsPageViewModel.SettingsPageViewModel.LyricsStandardFontSize))
|
||||
else if (message.PropertyName == nameof(LyricsEffectSettings.LyricsScrollDuration))
|
||||
{
|
||||
_lyricsStandardFontSize = message.NewValue;
|
||||
_isLayoutChanged = true;
|
||||
}
|
||||
else if (message.PropertyName == nameof(SettingsPageViewModel.SettingsPageViewModel.LyricsDockFontSize))
|
||||
else if (message.PropertyName == nameof(LyricsEffectSettings.LyricsScrollTopDuration))
|
||||
{
|
||||
_lyricsDockFontSize = message.NewValue;
|
||||
_isLayoutChanged = true;
|
||||
}
|
||||
else if (message.PropertyName == nameof(SettingsPageViewModel.SettingsPageViewModel.LyricsDesktopFontSize))
|
||||
else if (message.PropertyName == nameof(LyricsEffectSettings.LyricsScrollBottomDuration))
|
||||
{
|
||||
_lyricsDesktopFontSize = message.NewValue;
|
||||
_isLayoutChanged = true;
|
||||
}
|
||||
else if (message.PropertyName == nameof(SettingsPageViewModel.SettingsPageViewModel.SelectedTargetLanguageIndex))
|
||||
}
|
||||
else if (message.Sender is LyricsStyleSettings)
|
||||
{
|
||||
if (message.PropertyName == nameof(LyricsStyleSettings.LyricsFontSize))
|
||||
{
|
||||
_targetLanguageIndex = message.NewValue;
|
||||
_logger.LogInformation("Target language index changed: {Index}", _targetLanguageIndex);
|
||||
_isLayoutChanged = true;
|
||||
}
|
||||
else if (message.PropertyName == nameof(LyricsStyleSettings.LyricsFontStrokeWidth))
|
||||
{
|
||||
_isLayoutChanged = true;
|
||||
}
|
||||
else if (message.PropertyName == nameof(LyricsStyleSettings.LyricsBgFontOpacity))
|
||||
{
|
||||
_isLayoutChanged = true;
|
||||
}
|
||||
}
|
||||
else if (message.Sender is TranslationSettings)
|
||||
{
|
||||
if (message.PropertyName == nameof(TranslationSettings.SelectedTargetLanguageIndex))
|
||||
{
|
||||
_logger.LogInformation("Target language index changed: {Index}", _settingsService.AppSettings.TranslationSettings.SelectedTargetLanguageIndex);
|
||||
UpdateTranslations();
|
||||
}
|
||||
else if (message.PropertyName == nameof(SettingsPageViewModel.SettingsPageViewModel.LyricsFontStrokeWidth))
|
||||
}
|
||||
else if (message.Sender is MediaSourceProviderInfo)
|
||||
{
|
||||
if (message.PropertyName == nameof(MediaSourceProviderInfo.TimelineSyncThreshold))
|
||||
{
|
||||
_lyricsFontStrokeWidth = message.NewValue;
|
||||
_isLayoutChanged = true;
|
||||
UpdateTimelineSyncThreshold();
|
||||
}
|
||||
else if (message.PropertyName == nameof(SettingsPageViewModel.SettingsPageViewModel.LyricsScrollDuration))
|
||||
else if (message.PropertyName == nameof(MediaSourceProviderInfo.PositionOffset))
|
||||
{
|
||||
_canvasYScrollTransition.SetDuration(message.NewValue / 1000f);
|
||||
}
|
||||
else if (message.PropertyName == nameof(SettingsPageViewModel.SettingsPageViewModel.LyricsBgFontOpacity))
|
||||
{
|
||||
_defaultOpacity = message.NewValue / 100f;
|
||||
_isLayoutChanged = true;
|
||||
UpdatePositionOffset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Receive(PropertyChangedMessage<LineRenderingType> message)
|
||||
{
|
||||
if (message.Sender is SettingsPageViewModel.SettingsPageViewModel)
|
||||
if (message.Sender is LyricsEffectSettings)
|
||||
{
|
||||
if (message.PropertyName == nameof(SettingsPageViewModel.SettingsPageViewModel.LyricsGlowEffectScope))
|
||||
if (message.PropertyName == nameof(LyricsEffectSettings.LyricsGlowEffectScope))
|
||||
{
|
||||
_lyricsGlowEffectScope = message.NewValue;
|
||||
_isLayoutChanged = true;
|
||||
}
|
||||
else if (message.PropertyName == nameof(SettingsPageViewModel.SettingsPageViewModel.LyricsHighlightScope))
|
||||
else if (message.PropertyName == nameof(LyricsEffectSettings.LyricsHighlightScope))
|
||||
{
|
||||
_lyricsHighlightScope = message.NewValue;
|
||||
_isLayoutChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Receive(PropertyChangedMessage<TextAlignmentType> message)
|
||||
{
|
||||
if (message.Sender is SettingsPageViewModel.SettingsPageViewModel)
|
||||
if (message.Sender is LyricsStyleSettings)
|
||||
{
|
||||
if (message.PropertyName == nameof(SettingsPageViewModel.SettingsPageViewModel.LyricsAlignmentType))
|
||||
if (message.PropertyName == nameof(LyricsStyleSettings.LyricsAlignmentType))
|
||||
{
|
||||
_lyricsAlignmentType = message.NewValue;
|
||||
_isLayoutChanged = true;
|
||||
}
|
||||
else if (message.PropertyName == nameof(SettingsPageViewModel.SettingsPageViewModel.SongInfoAlignmentType))
|
||||
}
|
||||
else if (message.Sender is AlbumArtLayoutSettings)
|
||||
{
|
||||
if (message.PropertyName == nameof(AlbumArtLayoutSettings.SongInfoAlignmentType))
|
||||
{
|
||||
_titleTextFormat.HorizontalAlignment = _artistTextFormat.HorizontalAlignment =
|
||||
message.NewValue.ToCanvasHorizontalAlignment();
|
||||
_settingsService.AppSettings.AlbumArtLayoutSettings.SongInfoAlignmentType.ToCanvasHorizontalAlignment();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -294,21 +282,18 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
|
||||
public void Receive(PropertyChangedMessage<LyricsFontColorType> message)
|
||||
{
|
||||
if (message.Sender is SettingsPageViewModel.SettingsPageViewModel)
|
||||
if (message.Sender is LyricsStyleSettings)
|
||||
{
|
||||
if (message.PropertyName == nameof(SettingsPageViewModel.SettingsPageViewModel.LyricsBgFontColorType))
|
||||
if (message.PropertyName == nameof(LyricsStyleSettings.LyricsBgFontColorType))
|
||||
{
|
||||
_lyricsBgFontColorType = message.NewValue;
|
||||
UpdateColorConfig();
|
||||
}
|
||||
else if (message.PropertyName == nameof(SettingsPageViewModel.SettingsPageViewModel.LyricsFgFontColorType))
|
||||
else if (message.PropertyName == nameof(LyricsStyleSettings.LyricsFgFontColorType))
|
||||
{
|
||||
_lyricsFgFontColorType = message.NewValue;
|
||||
UpdateColorConfig();
|
||||
}
|
||||
else if (message.PropertyName == nameof(SettingsPageViewModel.SettingsPageViewModel.LyricsStrokeFontColorType))
|
||||
else if (message.PropertyName == nameof(LyricsStyleSettings.LyricsStrokeFontColorType))
|
||||
{
|
||||
_lyricsStrokeFontColorType = message.NewValue;
|
||||
UpdateColorConfig();
|
||||
}
|
||||
}
|
||||
@@ -316,11 +301,10 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
|
||||
public void Receive(PropertyChangedMessage<LyricsFontWeight> message)
|
||||
{
|
||||
if (message.Sender is SettingsPageViewModel.SettingsPageViewModel)
|
||||
if (message.Sender is LyricsStyleSettings)
|
||||
{
|
||||
if (message.PropertyName == nameof(SettingsPageViewModel.SettingsPageViewModel.LyricsFontWeight))
|
||||
if (message.PropertyName == nameof(LyricsStyleSettings.LyricsFontWeight))
|
||||
{
|
||||
_lyricsTextFormat.FontWeight = message.NewValue.ToFontWeight();
|
||||
_isLayoutChanged = true;
|
||||
}
|
||||
}
|
||||
@@ -328,11 +312,10 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
|
||||
public void Receive(PropertyChangedMessage<ElementTheme> message)
|
||||
{
|
||||
if (message.Sender is SettingsPageViewModel.SettingsPageViewModel)
|
||||
if (message.Sender is LyricsBackgroundSettings)
|
||||
{
|
||||
if (message.PropertyName == nameof(SettingsPageViewModel.SettingsPageViewModel.LyricsBackgroundTheme))
|
||||
if (message.PropertyName == nameof(LyricsBackgroundSettings.LyricsBackgroundTheme))
|
||||
{
|
||||
_lyricsBgTheme = message.NewValue;
|
||||
UpdateColorConfig();
|
||||
}
|
||||
}
|
||||
@@ -340,9 +323,9 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
|
||||
public void Receive(PropertyChangedMessage<EasingType> message)
|
||||
{
|
||||
if (message.Sender is SettingsPageViewModel.SettingsPageViewModel)
|
||||
if (message.Sender is LyricsEffectSettings)
|
||||
{
|
||||
if (message.PropertyName == nameof(SettingsPageViewModel.SettingsPageViewModel.LyricsScrollEasingType))
|
||||
if (message.PropertyName == nameof(LyricsEffectSettings.LyricsScrollEasingType))
|
||||
{
|
||||
_canvasYScrollTransition.SetEasingType(message.NewValue);
|
||||
}
|
||||
@@ -351,30 +334,17 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
|
||||
public void Receive(PropertyChangedMessage<string> message)
|
||||
{
|
||||
if (message.Sender is SettingsPageViewModel.SettingsPageViewModel)
|
||||
if (message.Sender is LyricsStyleSettings)
|
||||
{
|
||||
if (message.PropertyName == nameof(SettingsPageViewModel.SettingsPageViewModel.LyricsFontFamily))
|
||||
if (message.PropertyName == nameof(LyricsStyleSettings.LyricsFontFamily))
|
||||
{
|
||||
_lyricsTextFormat.FontFamily = _artistTextFormat.FontFamily = _titleTextFormat.FontFamily = message.NewValue;
|
||||
_isLayoutChanged = true;
|
||||
}
|
||||
else if (message.PropertyName == nameof(SettingsPageViewModel.SettingsPageViewModel.LyricsTranslationSeparator))
|
||||
else if (message.PropertyName == nameof(LyricsStyleSettings.LyricsTranslationSeparator))
|
||||
{
|
||||
_lyricsTranslationSeparator = message.NewValue;
|
||||
UpdateTranslations();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Receive(PropertyChangedMessage<DockPlacement> message)
|
||||
{
|
||||
if (message.Sender is SettingsPageViewModel.SettingsPageViewModel)
|
||||
{
|
||||
if (message.PropertyName == nameof(SettingsPageViewModel.SettingsPageViewModel.DockPlacement))
|
||||
{
|
||||
_dockPlacement = message.NewValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
{
|
||||
public partial class LyricsRendererViewModel
|
||||
{
|
||||
private readonly ValueTransition<float> _canvasYScrollTransition = new(
|
||||
private readonly ValueTransition<double> _canvasYScrollTransition = new(
|
||||
initialValue: 0f,
|
||||
durationSeconds: 0.3f,
|
||||
easingType: EasingType.EaseInOutSine
|
||||
@@ -30,68 +30,68 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
interpolator: (from, to, progress) => Helper.ColorHelper.GetInterpolatedColor(progress, from, to)
|
||||
);
|
||||
|
||||
private readonly ValueTransition<float> _immersiveBgOpacityTransition = new(
|
||||
private readonly ValueTransition<double> _immersiveBgOpacityTransition = new(
|
||||
initialValue: 1f,
|
||||
durationSeconds: 0.3f
|
||||
);
|
||||
|
||||
private readonly ValueTransition<float> _titleXTransition = new(
|
||||
private readonly ValueTransition<double> _titleXTransition = new(
|
||||
initialValue: 0f,
|
||||
durationSeconds: 0.3f,
|
||||
easingType: EasingType.EaseInOutBack
|
||||
);
|
||||
|
||||
private readonly ValueTransition<float> _titleYTransition = new(
|
||||
private readonly ValueTransition<double> _titleYTransition = new(
|
||||
initialValue: 0f,
|
||||
durationSeconds: 0.3f,
|
||||
easingType: EasingType.EaseInOutBack
|
||||
);
|
||||
|
||||
private readonly ValueTransition<float> _lyricsXTransition = new(
|
||||
private readonly ValueTransition<double> _lyricsXTransition = new(
|
||||
initialValue: 0f,
|
||||
durationSeconds: 0.3f,
|
||||
easingType: EasingType.EaseInOutBack
|
||||
);
|
||||
|
||||
private readonly ValueTransition<float> _lyricsYTransition = new(
|
||||
private readonly ValueTransition<double> _lyricsYTransition = new(
|
||||
initialValue: 0f,
|
||||
durationSeconds: 0.3f,
|
||||
easingType: EasingType.EaseInOutBack
|
||||
);
|
||||
|
||||
private readonly ValueTransition<float> _lyricsOpacityTransition = new(
|
||||
private readonly ValueTransition<double> _lyricsOpacityTransition = new(
|
||||
initialValue: 0f,
|
||||
durationSeconds: 0.3f
|
||||
);
|
||||
|
||||
private readonly ValueTransition<float> _albumArtBgTransition = new(
|
||||
private readonly ValueTransition<double> _albumArtBgTransition = new(
|
||||
initialValue: 0f,
|
||||
durationSeconds: 1f
|
||||
);
|
||||
|
||||
private readonly ValueTransition<float> _albumArtOpacityTransition = new(
|
||||
private readonly ValueTransition<double> _albumArtOpacityTransition = new(
|
||||
initialValue: 0f,
|
||||
durationSeconds: 1f
|
||||
);
|
||||
|
||||
private readonly ValueTransition<float> _albumArtXTransition = new(
|
||||
private readonly ValueTransition<double> _albumArtXTransition = new(
|
||||
initialValue: 0f,
|
||||
durationSeconds: 0.3f,
|
||||
easingType: EasingType.EaseInOutBack
|
||||
);
|
||||
|
||||
private readonly ValueTransition<float> _albumArtYTransition = new(
|
||||
private readonly ValueTransition<double> _albumArtYTransition = new(
|
||||
initialValue: 0f,
|
||||
durationSeconds: 0.3f,
|
||||
easingType: EasingType.EaseInOutBack
|
||||
);
|
||||
|
||||
private readonly ValueTransition<float> _songInfoOpacityTransition = new(
|
||||
private readonly ValueTransition<double> _songInfoOpacityTransition = new(
|
||||
initialValue: 0f,
|
||||
durationSeconds: 1f
|
||||
);
|
||||
|
||||
private readonly ValueTransition<float> _lyricsBgBrightnessTransition = new(
|
||||
private readonly ValueTransition<double> _lyricsBgBrightnessTransition = new(
|
||||
initialValue: 0f,
|
||||
durationSeconds: 1f
|
||||
);
|
||||
|
||||
@@ -37,11 +37,14 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
|
||||
private bool _isAlbumArtCornerRadiusChanged = true;
|
||||
|
||||
private bool _isAlbumArtBgOpacityChanged = false;
|
||||
private bool _isAlbumArtBgBlurAmountChanged = false;
|
||||
|
||||
public void Update(ICanvasAnimatedControl control, CanvasAnimatedUpdateEventArgs args)
|
||||
{
|
||||
_elapsedTime = args.Timing.ElapsedTime;
|
||||
|
||||
if (_isPlaying)
|
||||
if (IsPlaying)
|
||||
{
|
||||
TotalTime += _elapsedTime;
|
||||
_totalPlayingTime += _elapsedTime;
|
||||
@@ -59,8 +62,8 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
_isDisplayTypeChanged = _displayType != _displayTypeReceived;
|
||||
_isPlayingLineChanged = _playingLineIndex != playingLineIndex;
|
||||
|
||||
_canvasWidth = (float)control.Size.Width;
|
||||
_canvasHeight = (float)control.Size.Height;
|
||||
_canvasWidth = control.Size.Width;
|
||||
_canvasHeight = control.Size.Height;
|
||||
_displayType = _displayTypeReceived;
|
||||
_playingLineIndex = playingLineIndex;
|
||||
|
||||
@@ -78,11 +81,9 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
_isDebugOverlayEnabledChanged = false;
|
||||
}
|
||||
|
||||
if (_isDynamicCoverOverlayEnabled)
|
||||
{
|
||||
_rotateAngle += _coverRotateSpeed;
|
||||
_rotateAngle %= MathF.PI * 2;
|
||||
}
|
||||
|
||||
_rotateAngle += _coverRotateBaseSpeed * _settingsService.AppSettings.LyricsBackgroundSettings.CoverOverlaySpeed / 100.0;
|
||||
_rotateAngle %= Math.PI * 2;
|
||||
|
||||
if (_isCanvasWidthChanged)
|
||||
{
|
||||
@@ -107,17 +108,17 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
switch (_lyricsLayoutOrientation)
|
||||
{
|
||||
case LyricsLayoutOrientation.Horizontal:
|
||||
_albumArtSize = MathF.Min((_canvasHeight - _topMargin - _bottomMargin) * 8.5f / 16, (_canvasWidth - _leftMargin - _middleMargin - _rightMargin) / 2);
|
||||
_albumArtSize = MathF.Max(0, _albumArtSize);
|
||||
_albumArtYTransition.StartTransition((_canvasHeight - _albumArtSize * 1.05f - _titleTextFormat.FontSize - _artistTextFormat.FontSize) / 2, jumpTo);
|
||||
_titleYTransition.StartTransition(_albumArtYTransition.TargetValue + _albumArtSize * 1.05f, jumpTo);
|
||||
_albumArtSize = Math.Min((_canvasHeight - _topMargin - _bottomMargin) * 8.5 / 16.0, (_canvasWidth - _leftMargin - _middleMargin - _rightMargin) / 2.0);
|
||||
_albumArtSize = Math.Max(0, _albumArtSize);
|
||||
_albumArtYTransition.StartTransition((_canvasHeight - _albumArtSize * 1.05 - _titleTextFormat.FontSize - _artistTextFormat.FontSize) / 2.0, jumpTo);
|
||||
_titleYTransition.StartTransition(_albumArtYTransition.TargetValue + _albumArtSize * 1.05, jumpTo);
|
||||
_lyricsYTransition.StartTransition(0, jumpTo);
|
||||
switch (_displayType)
|
||||
{
|
||||
case LyricsDisplayType.AlbumArtOnly:
|
||||
_lyricsOpacityTransition.StartTransition(0f, jumpTo);
|
||||
_albumArtOpacityTransition.StartTransition(1f, jumpTo);
|
||||
_albumArtXTransition.StartTransition(_canvasWidth / 2 - _albumArtSize / 2, jumpTo);
|
||||
_albumArtXTransition.StartTransition(_canvasWidth / 2.0 - _albumArtSize / 2.0, jumpTo);
|
||||
_titleXTransition.StartTransition(_albumArtXTransition.TargetValue, jumpTo);
|
||||
break;
|
||||
case LyricsDisplayType.LyricsOnly:
|
||||
@@ -128,8 +129,8 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
case LyricsDisplayType.SplitView:
|
||||
_lyricsOpacityTransition.StartTransition(1f, jumpTo);
|
||||
_albumArtOpacityTransition.StartTransition(1f, jumpTo);
|
||||
_lyricsXTransition.StartTransition((_canvasWidth - _leftMargin - _middleMargin - _rightMargin) / 2 + _leftMargin + _middleMargin, jumpTo);
|
||||
_albumArtXTransition.StartTransition(_leftMargin + ((_canvasWidth - _leftMargin - _middleMargin - _rightMargin) / 2 - _albumArtSize) / 2, jumpTo);
|
||||
_lyricsXTransition.StartTransition((_canvasWidth - _leftMargin - _middleMargin - _rightMargin) / 2.0 + _leftMargin + _middleMargin, jumpTo);
|
||||
_albumArtXTransition.StartTransition(_leftMargin + ((_canvasWidth - _leftMargin - _middleMargin - _rightMargin) / 2.0 - _albumArtSize) / 2.0, jumpTo);
|
||||
_titleXTransition.StartTransition(_albumArtXTransition.TargetValue, jumpTo);
|
||||
break;
|
||||
default:
|
||||
@@ -140,13 +141,13 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
_albumArtSize = 64;
|
||||
_lyricsXTransition.StartTransition(_leftMargin, jumpTo);
|
||||
_albumArtXTransition.StartTransition(_leftMargin, jumpTo);
|
||||
_titleXTransition.StartTransition(_leftMargin + _albumArtSize * 1.2f, jumpTo);
|
||||
_titleXTransition.StartTransition(_leftMargin + _albumArtSize * 1.2, jumpTo);
|
||||
switch (_displayType)
|
||||
{
|
||||
case LyricsDisplayType.AlbumArtOnly:
|
||||
_lyricsOpacityTransition.StartTransition(0f, jumpTo);
|
||||
_albumArtOpacityTransition.StartTransition(1f, jumpTo);
|
||||
_albumArtYTransition.StartTransition((_canvasHeight - _albumArtSize) / 2, jumpTo);
|
||||
_albumArtYTransition.StartTransition((_canvasHeight - _albumArtSize) / 2.0, jumpTo);
|
||||
_titleYTransition.StartTransition(_albumArtYTransition.TargetValue, jumpTo);
|
||||
break;
|
||||
case LyricsDisplayType.LyricsOnly:
|
||||
@@ -223,13 +224,24 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
{
|
||||
UpdateCoverAcrylicOverlay(control);
|
||||
UpdateAlbumArtBgEffect(control);
|
||||
|
||||
_isCoverAcrylicEffectAmountChanged = false;
|
||||
}
|
||||
|
||||
if (_isAlbumArtBgOpacityChanged)
|
||||
{
|
||||
UpdateAlbumArtBgEffect(control);
|
||||
_isAlbumArtBgOpacityChanged = false;
|
||||
}
|
||||
|
||||
if (_isAlbumArtBgBlurAmountChanged)
|
||||
{
|
||||
UpdateAlbumArtBgEffect(control);
|
||||
_isAlbumArtBgBlurAmountChanged = false;
|
||||
}
|
||||
|
||||
_albumArtChanged = false;
|
||||
|
||||
if (_isCanvasWidthChanged || _lyricsXTransition.IsTransitioning)
|
||||
if (_isCanvasHeightChanged || _isCanvasWidthChanged || _lyricsXTransition.IsTransitioning)
|
||||
{
|
||||
_maxLyricsWidth = _canvasWidth - _lyricsXTransition.Value - _rightMargin;
|
||||
_maxLyricsWidth = Math.Max(_maxLyricsWidth, 0);
|
||||
@@ -239,13 +251,16 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
if (_isLayoutChanged)
|
||||
{
|
||||
ReLayout(control);
|
||||
UpdateCanvasYScrollOffset(control, true, false);
|
||||
}
|
||||
else
|
||||
|
||||
if (_isLayoutChanged || _isPlayingLineChanged)
|
||||
{
|
||||
UpdateCanvasYScrollOffset(control, false, true);
|
||||
UpdateCanvasTargetYScrollOffset();
|
||||
_canvasYScrollTransition.StartTransition(_canvasTargetYScrollOffset, _isLayoutChanged);
|
||||
}
|
||||
|
||||
UpdateVisibleLinesBoundary();
|
||||
|
||||
UpdateLinesProps(control);
|
||||
|
||||
_isLayoutChanged = false;
|
||||
@@ -264,6 +279,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
_albumArtBgTransition.Update(_elapsedTime);
|
||||
_lyricsBgBrightnessTransition.Update(_elapsedTime);
|
||||
_songInfoOpacityTransition.Update(_elapsedTime);
|
||||
_canvasYScrollTransition.Update(_elapsedTime);
|
||||
}
|
||||
|
||||
private void ReLayout(ICanvasAnimatedControl control)
|
||||
@@ -273,18 +289,29 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
|
||||
if (_isDockMode)
|
||||
{
|
||||
_lyricsTextFormat.FontSize = _lyricsDockFontSize;
|
||||
_lyricsStyleSettings = _settingsService.AppSettings.DockLyricsStyleSettings;
|
||||
_lyricsEffectSettings = _settingsService.AppSettings.DockLyricsEffectSettings;
|
||||
}
|
||||
else if (_isDesktopMode)
|
||||
{
|
||||
_lyricsTextFormat.FontSize = _lyricsDesktopFontSize;
|
||||
_lyricsStyleSettings = _settingsService.AppSettings.DesktopLyricsStyleSettings;
|
||||
_lyricsEffectSettings = _settingsService.AppSettings.DesktopLyricsEffectSettings;
|
||||
}
|
||||
else
|
||||
{
|
||||
_lyricsTextFormat.FontSize = _lyricsStandardFontSize;
|
||||
_lyricsStyleSettings = _settingsService.AppSettings.StandardLyricsStyleSettings;
|
||||
_lyricsEffectSettings = _settingsService.AppSettings.StandardLyricsEffectSettings;
|
||||
}
|
||||
|
||||
float y = 0;
|
||||
_lyricsTextFormat.FontSize = _lyricsStyleSettings.LyricsFontSize;
|
||||
_lyricsTextFormat.FontWeight = _lyricsStyleSettings.LyricsFontWeight.ToFontWeight();
|
||||
// TODO:FontFamily 无法设置
|
||||
_lyricsTextFormat.FontFamily = _artistTextFormat.FontFamily = _titleTextFormat.FontFamily = _lyricsStyleSettings.LyricsFontFamily;
|
||||
|
||||
_canvasYScrollTransition.SetDuration(_lyricsEffectSettings.LyricsScrollDuration / 1000.0);
|
||||
_canvasYScrollTransition.SetEasingType(_lyricsEffectSettings.LyricsScrollEasingType);
|
||||
|
||||
double y = 0;
|
||||
|
||||
// Init Positions
|
||||
for (int i = 0; i < _lyricsDataArr.ElementAtOrDefault(_langIndex)?.LyricsLines.Count; i++)
|
||||
@@ -296,26 +323,27 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
continue;
|
||||
}
|
||||
|
||||
line.Position = new Vector2(0, y);
|
||||
line.UpdateTextLayout(control, _lyricsTextFormat, _maxLyricsWidth, _canvasHeight, _isDockMode ? TextAlignmentType.Center : _lyricsAlignmentType);
|
||||
line.UpdateCenterPosition(_maxLyricsWidth, _isDockMode ? TextAlignmentType.Center : _lyricsAlignmentType);
|
||||
line.RecreatePlaceholder(control);
|
||||
|
||||
//line.UpdateTextGeometry();
|
||||
//line.UpdateFontEffect(control, _isDesktopMode, _strokeFontColor, _lyricsFontStrokeWidth, _bgFontColor);
|
||||
line.Position = new Vector2(0, (float)y);
|
||||
line.RecreateTextLayout(control, _lyricsTextFormat, _maxLyricsWidth, _canvasHeight, _lyricsStyleSettings.LyricsAlignmentType);
|
||||
line.UpdateCenterPosition(_maxLyricsWidth, _lyricsStyleSettings.LyricsAlignmentType);
|
||||
|
||||
if (line.CanvasTextLayout == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
line.RecreateTextGeometry();
|
||||
line.RecreateFontEffect(control, _strokeFontColor, _lyricsStyleSettings.LyricsFontStrokeWidth, _bgFontColor, _fgFontColor);
|
||||
line.RecreateBackgroundEffect(_lyricsOpacityTransition.Value);
|
||||
line.RecreateCurrentLineMask(control);
|
||||
line.RecreateForegroundBlurEffect(control, _lyricsEffectSettings.LyricsGlowEffectScope, _lyricsGlowEffectAmount);
|
||||
line.RecreateForegroundHighlightEffect(control, _lyricsEffectSettings.LyricsHighlightScope);
|
||||
|
||||
y +=
|
||||
(float)line.CanvasTextLayout.LayoutBounds.Height
|
||||
(double)line.CanvasTextLayout!.LayoutBounds.Height
|
||||
/ line.CanvasTextLayout.LineCount
|
||||
* (line.CanvasTextLayout.LineCount + _lyricsLineSpacingFactor);
|
||||
* (line.CanvasTextLayout.LineCount + _lyricsStyleSettings.LyricsLineSpacingFactor);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateCanvasYScrollOffset(ICanvasAnimatedControl control, bool forceScroll, bool withAnimation)
|
||||
private void UpdateCanvasTargetYScrollOffset()
|
||||
{
|
||||
var (startLineIndex, endLineIndex) = GetMaxLyricsLineIndexBoundaries();
|
||||
|
||||
@@ -323,30 +351,29 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
|
||||
// Set _scrollOffsetY
|
||||
|
||||
if ((!_isPlayingLineChanged && forceScroll) || _isPlayingLineChanged)
|
||||
{
|
||||
LyricsLine? currentPlayingLine = _lyricsDataArr.ElementAtOrDefault(_langIndex)?.LyricsLines.ElementAtOrDefault(_playingLineIndex);
|
||||
LyricsLine? currentPlayingLine = _lyricsDataArr.ElementAtOrDefault(_langIndex)?.LyricsLines.ElementAtOrDefault(_playingLineIndex);
|
||||
|
||||
if (currentPlayingLine == null) return;
|
||||
if (currentPlayingLine == null) return;
|
||||
|
||||
var playingTextLayout = currentPlayingLine?.CanvasTextLayout;
|
||||
var playingTextLayout = currentPlayingLine?.CanvasTextLayout;
|
||||
|
||||
if (playingTextLayout == null) return;
|
||||
if (playingTextLayout == null) return;
|
||||
|
||||
float? targetYScrollOffset = (float?)(-currentPlayingLine!.Position.Y + _lyricsDataArr.ElementAtOrDefault(_langIndex)?.LyricsLines[0].Position.Y - playingTextLayout.LayoutBounds.Height / 2);
|
||||
double? targetYScrollOffset = -currentPlayingLine!.Position.Y + _lyricsDataArr.ElementAtOrDefault(_langIndex)?.LyricsLines[0].Position.Y - playingTextLayout.LayoutBounds.Height / 2.0;
|
||||
|
||||
if (!targetYScrollOffset.HasValue) return;
|
||||
if (!targetYScrollOffset.HasValue) return;
|
||||
|
||||
_canvasYScrollTransition.StartTransition(targetYScrollOffset.Value, !withAnimation);
|
||||
}
|
||||
_canvasTargetYScrollOffset = targetYScrollOffset.Value;
|
||||
}
|
||||
|
||||
_canvasYScrollTransition.Update(_elapsedTime);
|
||||
private void UpdateVisibleLinesBoundary()
|
||||
{
|
||||
var (startLineIndex, endLineIndex) = GetMaxLyricsLineIndexBoundaries();
|
||||
|
||||
// Update visible line indices
|
||||
var lines = _lyricsDataArr.ElementAtOrDefault(_langIndex)?.LyricsLines;
|
||||
if (lines == null || lines.Count == 0) return;
|
||||
|
||||
float offset = _canvasYScrollTransition.Value + _canvasHeight / 2;
|
||||
double offset = _canvasYScrollTransition.Value + _canvasHeight / 2;
|
||||
int startVisibleLineIndex = FindFirstVisibleLine(lines, offset);
|
||||
int endVisibleLineIndex = FindLastVisibleLine(lines, offset, _canvasHeight);
|
||||
|
||||
@@ -361,7 +388,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
_endVisibleLineIndex = endVisibleLineIndex;
|
||||
}
|
||||
|
||||
private int FindFirstVisibleLine(IList<LyricsLine> lines, float offset)
|
||||
private int FindFirstVisibleLine(IList<LyricsLine> lines, double offset)
|
||||
{
|
||||
int left = 0, right = lines.Count - 1, result = -1;
|
||||
while (left <= right)
|
||||
@@ -370,7 +397,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
var line = lines[mid];
|
||||
var layout = line.CanvasTextLayout;
|
||||
if (layout == null) break;
|
||||
float value = offset + line.Position.Y + (float)layout.LayoutBounds.Height;
|
||||
double value = offset + line.Position.Y + (double)layout.LayoutBounds.Height;
|
||||
if (value >= 0)
|
||||
{
|
||||
result = mid;
|
||||
@@ -384,7 +411,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
return result;
|
||||
}
|
||||
|
||||
private int FindLastVisibleLine(IList<LyricsLine> lines, float offset, float canvasHeight)
|
||||
private int FindLastVisibleLine(IList<LyricsLine> lines, double offset, double canvasHeight)
|
||||
{
|
||||
int left = 0, right = lines.Count - 1, result = -1;
|
||||
while (left <= right)
|
||||
@@ -393,7 +420,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
var line = lines[mid];
|
||||
var layout = line.CanvasTextLayout;
|
||||
if (layout == null) break;
|
||||
float value = offset + line.Position.Y + (float)layout.LayoutBounds.Height;
|
||||
double value = offset + line.Position.Y + (double)layout.LayoutBounds.Height;
|
||||
if (value >= canvasHeight)
|
||||
{
|
||||
result = mid;
|
||||
@@ -415,10 +442,10 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
}
|
||||
else
|
||||
{
|
||||
ThemeTypeSent = _lyricsBgTheme;
|
||||
ThemeTypeSent = _settingsService.AppSettings.LyricsBackgroundSettings.LyricsBackgroundTheme;
|
||||
}
|
||||
|
||||
float brightness;
|
||||
double brightness;
|
||||
Color grayedEnvironmentalColor = Colors.Transparent;
|
||||
|
||||
bool isLight = ThemeTypeSent switch
|
||||
@@ -462,7 +489,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
}
|
||||
}
|
||||
|
||||
switch (_lyricsBgFontColorType)
|
||||
switch (_lyricsStyleSettings.LyricsBgFontColorType)
|
||||
{
|
||||
case LyricsFontColorType.AdaptiveGrayed:
|
||||
_bgFontColor = _adaptiveGrayedFontColor;
|
||||
@@ -471,13 +498,13 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
_bgFontColor = _adaptiveColoredFontColor ?? _adaptiveGrayedFontColor;
|
||||
break;
|
||||
case LyricsFontColorType.Custom:
|
||||
_bgFontColor = _customBgFontColor ?? _adaptiveGrayedFontColor;
|
||||
_bgFontColor = _lyricsStyleSettings.LyricsCustomBgFontColor;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (_lyricsFgFontColorType)
|
||||
switch (_lyricsStyleSettings.LyricsFgFontColorType)
|
||||
{
|
||||
case LyricsFontColorType.AdaptiveGrayed:
|
||||
_fgFontColor = _adaptiveGrayedFontColor;
|
||||
@@ -486,13 +513,13 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
_fgFontColor = _adaptiveColoredFontColor ?? _adaptiveGrayedFontColor;
|
||||
break;
|
||||
case LyricsFontColorType.Custom:
|
||||
_fgFontColor = _customFgFontColor ?? _adaptiveGrayedFontColor;
|
||||
_fgFontColor = _lyricsStyleSettings.LyricsCustomFgFontColor;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (_lyricsStrokeFontColorType)
|
||||
switch (_lyricsStyleSettings.LyricsStrokeFontColorType)
|
||||
{
|
||||
case LyricsFontColorType.AdaptiveGrayed:
|
||||
_strokeFontColor = grayedEnvironmentalColor.WithBrightness(0.7);
|
||||
@@ -501,7 +528,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
_strokeFontColor = _environmentalColor.WithBrightness(0.7);
|
||||
break;
|
||||
case LyricsFontColorType.Custom:
|
||||
_strokeFontColor = _customStrokeFontColor ?? _environmentalColor;
|
||||
_strokeFontColor = _lyricsStyleSettings.LyricsCustomStrokeFontColor;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -518,32 +545,67 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
|
||||
if (currentPlayingLine == null) return;
|
||||
|
||||
for (int i = _startVisibleLineIndex; i <= _endVisibleLineIndex; i++)
|
||||
for (int i = _startVisibleLineIndex; i <= _endVisibleLineIndex + 1; i++)
|
||||
{
|
||||
var line = _lyricsDataArr.ElementAtOrDefault(_langIndex)?.LyricsLines.ElementAtOrDefault(i);
|
||||
|
||||
if (line == null) continue;
|
||||
|
||||
line.UpdateTextGeometry();
|
||||
line.UpdateFontEffect(control, _isDesktopMode, _strokeFontColor, _lyricsFontStrokeWidth, _bgFontColor);
|
||||
line.UpdateBackgroundEffect(_lyricsOpacityTransition.Value);
|
||||
|
||||
if (_isLayoutChanged || _isVisibleLinesBoundaryChanged || _isPlayingLineChanged)
|
||||
if (i == _playingLineIndex)
|
||||
{
|
||||
float distanceFromPlayingLine = Math.Abs(line.Position.Y - currentPlayingLine.Position.Y);
|
||||
float distanceFactor = Math.Clamp(distanceFromPlayingLine / (_canvasHeight / 2), 0, 1);
|
||||
GetLinePlayingProgress(
|
||||
_playingLineIndex,
|
||||
out int charStartIndex,
|
||||
out int charLength,
|
||||
out double charProgress
|
||||
);
|
||||
|
||||
line.AngleTransition.StartTransition(_isFanLyricsEnabled
|
||||
? (float)Math.PI
|
||||
* (30f / 180f)
|
||||
line.RecreateCurrentCharMask(control, charStartIndex, charLength, charProgress);
|
||||
line.RecreateLineStartToCurrentCharMask(control, charStartIndex, charLength, charProgress);
|
||||
|
||||
line.UpdateForegroundBlurEffect(control, _lyricsEffectSettings.LyricsGlowEffectScope, _lyricsGlowEffectAmount);
|
||||
line.UpdateForegroundHighlightEffect(control, _lyricsEffectSettings.LyricsHighlightScope);
|
||||
}
|
||||
|
||||
if (_isLayoutChanged || _isPlayingLineChanged)
|
||||
{
|
||||
int lineCountDelta = i - _playingLineIndex;
|
||||
int absoluteLineCountDelta = Math.Abs(lineCountDelta);
|
||||
double distanceFromPlayingLine = Math.Abs(line.Position.Y - currentPlayingLine.Position.Y);
|
||||
double distanceFactor = Math.Clamp(distanceFromPlayingLine / (_canvasHeight / 2), 0, 1);
|
||||
|
||||
line.AngleTransition.StartTransition(_lyricsEffectSettings.IsFanLyricsEnabled
|
||||
? Math.PI
|
||||
* (30.0 / 180.0)
|
||||
* distanceFactor
|
||||
* (i > _playingLineIndex ? 1 : -1)
|
||||
: 0
|
||||
);
|
||||
|
||||
line.BlurAmountTransition.StartTransition(_lyricsBlurAmount * distanceFactor);
|
||||
line.BlurAmountTransition.StartTransition(_lyricsEffectSettings.LyricsBlurAmount * distanceFactor);
|
||||
line.ScaleTransition.StartTransition(_highlightedScale - distanceFactor * (_highlightedScale - _defaultScale));
|
||||
line.OpacityTransition.StartTransition(_defaultOpacity - distanceFactor * _defaultOpacity * (1 - _lyricsVerticalEdgeOpacity / 100f));
|
||||
line.OpacityTransition.StartTransition(_lyricsStyleSettings.LyricsBgFontOpacity / 100.0 - distanceFactor * _lyricsStyleSettings.LyricsBgFontOpacity / 100.0 * (1 - _lyricsEffectSettings.LyricsVerticalEdgeOpacity / 100.0));
|
||||
line.HighlightOpacityTransition.StartTransition(i == _playingLineIndex ? 1f : 0f);
|
||||
|
||||
double yScrollDuration;
|
||||
if (lineCountDelta < 0)
|
||||
{
|
||||
yScrollDuration = _canvasYScrollTransition.DurationSeconds + distanceFactor * (_lyricsEffectSettings.LyricsScrollTopDuration / 1000.0 - _canvasYScrollTransition.DurationSeconds);
|
||||
}
|
||||
else if (lineCountDelta == 0)
|
||||
{
|
||||
yScrollDuration = _canvasYScrollTransition.DurationSeconds;
|
||||
}
|
||||
else
|
||||
{
|
||||
yScrollDuration = _canvasYScrollTransition.DurationSeconds + distanceFactor * (_lyricsEffectSettings.LyricsScrollBottomDuration / 1000.0 - _canvasYScrollTransition.DurationSeconds);
|
||||
}
|
||||
|
||||
line.YOffsetTransition.SetEasingType(_canvasYScrollTransition.EasingType ?? EasingType.Linear);
|
||||
line.YOffsetTransition.SetDuration(yScrollDuration);
|
||||
line.YOffsetTransition.StartTransition(_canvasTargetYScrollOffset, _isLayoutChanged);
|
||||
}
|
||||
|
||||
line.AngleTransition.Update(_elapsedTime);
|
||||
@@ -551,12 +613,13 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
line.BlurAmountTransition.Update(_elapsedTime);
|
||||
line.OpacityTransition.Update(_elapsedTime);
|
||||
line.HighlightOpacityTransition.Update(_elapsedTime);
|
||||
line.YOffsetTransition.Update(_elapsedTime);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateImmersiveBackgroundOpacity()
|
||||
{
|
||||
float targetOpacity;
|
||||
double targetOpacity;
|
||||
if (_isDesktopMode)
|
||||
{
|
||||
if (_isLyricsWindowLocked)
|
||||
@@ -584,7 +647,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
|
||||
private void UpdateCoverAcrylicOverlay(ICanvasAnimatedControl control)
|
||||
{
|
||||
if (_coverAcrylicEffectAmount > 0)
|
||||
if (_settingsService.AppSettings.LyricsBackgroundSettings.CoverAcrylicEffectAmount > 0)
|
||||
{
|
||||
var ret = ImageHelper.GenerateNoiseBGRA((int)_canvasWidth, (int)_canvasHeight);
|
||||
_coverAcrylicNoiseCanvasBitmap?.Dispose();
|
||||
@@ -599,25 +662,20 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
}
|
||||
}
|
||||
|
||||
private MediaSourceProviderInfo? GetCurrentMediaSourceProviderInfo()
|
||||
{
|
||||
return _mediaSourceProvidersInfo.Where(x => x.Provider == SongInfo?.SourceAppUserModelId)?.FirstOrDefault();
|
||||
}
|
||||
|
||||
private void UpdateTimelineSyncThreshold()
|
||||
{
|
||||
_timelineSyncThreshold = GetCurrentMediaSourceProviderInfo()?.TimelineSyncThreshold ?? 0;
|
||||
_timelineSyncThreshold = _mediaSessionsService.GetCurrentMediaSourceProviderInfo()?.TimelineSyncThreshold ?? 0;
|
||||
}
|
||||
|
||||
private void UpdatePositionOffset()
|
||||
{
|
||||
var current = GetCurrentMediaSourceProviderInfo();
|
||||
var current = _mediaSessionsService.GetCurrentMediaSourceProviderInfo();
|
||||
_positionOffset = TimeSpan.FromMilliseconds(current?.PositionOffset ?? 0);
|
||||
}
|
||||
|
||||
private void UpdateIsLastFMTrackEnabled()
|
||||
{
|
||||
var current = GetCurrentMediaSourceProviderInfo();
|
||||
var current = _mediaSessionsService.GetCurrentMediaSourceProviderInfo();
|
||||
_isLastFMTrackEnabled = current?.IsLastFMTrackEnabled ?? false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,11 +4,13 @@ using BetterLyrics.WinUI3.Enums;
|
||||
using BetterLyrics.WinUI3.Events;
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.Models.Settings;
|
||||
using BetterLyrics.WinUI3.Services;
|
||||
using BetterLyrics.WinUI3.Services.LastFMService;
|
||||
using BetterLyrics.WinUI3.Services.LibWatcherService;
|
||||
using BetterLyrics.WinUI3.Services.LyricsSearchService;
|
||||
using BetterLyrics.WinUI3.Services.MediaSessionsService;
|
||||
using BetterLyrics.WinUI3.Services.SettingsService;
|
||||
using BetterLyrics.WinUI3.Services.TranslateService;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.WinUI;
|
||||
@@ -31,6 +33,9 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
{
|
||||
public partial class LyricsRendererViewModel : BaseViewModel
|
||||
{
|
||||
private LyricsStyleSettings _lyricsStyleSettings;
|
||||
private LyricsEffectSettings _lyricsEffectSettings;
|
||||
|
||||
private bool _isLastFMTrackEnabled = false;
|
||||
private bool _isLastFMTracked = false;
|
||||
private TimeSpan _totalPlayingTime = TimeSpan.Zero;
|
||||
@@ -49,6 +54,8 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
private int _drawFrameCount = 0;
|
||||
private int _displayedDrawFrameCount = 0;
|
||||
|
||||
private Queue<SoftwareBitmap?> _cachedAlbumArtSwBitmaps = [];
|
||||
|
||||
private SoftwareBitmap? _lastAlbumArtSwBitmap = null;
|
||||
private SoftwareBitmap? _albumArtSwBitmap = null;
|
||||
|
||||
@@ -57,8 +64,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
|
||||
private CanvasBitmap? _coverAcrylicNoiseCanvasBitmap = null;
|
||||
|
||||
private float _albumArtSize = 0f;
|
||||
private int _albumArtCornerRadius = 0;
|
||||
private double _albumArtSize = 0f;
|
||||
|
||||
private string? _lastSongTitle;
|
||||
private string? _songTitle;
|
||||
@@ -66,17 +72,16 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
private string? _lastSongArtist;
|
||||
private string? _songArtist;
|
||||
|
||||
private float _canvasWidth = 0f;
|
||||
private float _canvasHeight = 0f;
|
||||
private double _canvasWidth = 0f;
|
||||
private double _canvasHeight = 0f;
|
||||
|
||||
private float _defaultOpacity;
|
||||
private readonly float _highlightedOpacity = 1.0f;
|
||||
private readonly double _defaultScale = 0.75f;
|
||||
private readonly double _highlightedScale = 1.0f;
|
||||
|
||||
private readonly float _defaultScale = 0.75f;
|
||||
private readonly float _highlightedScale = 1.0f;
|
||||
private readonly double _coverRotateBaseSpeed = 0.003f;
|
||||
private double _rotateAngle = 0f;
|
||||
|
||||
private readonly float _coverRotateSpeed = 0.003f;
|
||||
private float _rotateAngle = 0f;
|
||||
private double _canvasTargetYScrollOffset = 0;
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
@@ -86,28 +91,11 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial TranslationSearchProvider? TranslationSearchProvider { get; set; } = null;
|
||||
|
||||
private TextAlignmentType _lyricsAlignmentType;
|
||||
private readonly double _lyricsGlowEffectAmount = 8f;
|
||||
|
||||
private readonly float _lyricsGlowEffectAmount = 8f;
|
||||
private int _lyricsBlurAmount;
|
||||
private int _lyricsVerticalEdgeOpacity;
|
||||
|
||||
private ElementTheme _lyricsBgTheme;
|
||||
private LineRenderingType _lyricsGlowEffectScope;
|
||||
private LineRenderingType _lyricsHighlightScope;
|
||||
|
||||
private int _lyricsFontStrokeWidth;
|
||||
private int _lyricsStandardFontSize;
|
||||
private int _lyricsDockFontSize;
|
||||
private int _lyricsDesktopFontSize;
|
||||
private float _lyricsLineSpacingFactor;
|
||||
|
||||
private LyricsFontColorType _lyricsBgFontColorType;
|
||||
private LyricsFontColorType _lyricsFgFontColorType;
|
||||
private LyricsFontColorType _lyricsStrokeFontColorType;
|
||||
|
||||
private float _maxLyricsWidth = 0f;
|
||||
private double _maxLyricsWidth = 0f;
|
||||
|
||||
private readonly ISettingsService _settingsService;
|
||||
private readonly ILyricsSearchService _lyrcsSearchService;
|
||||
private readonly ILibWatcherService _libWatcherService;
|
||||
private readonly IMediaSessionsService _mediaSessionsService;
|
||||
@@ -115,13 +103,11 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
private readonly ILastFMService _lastFMService;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
private readonly float _leftMargin = 36f;
|
||||
private readonly float _middleMargin = 36f;
|
||||
private readonly float _rightMargin = 36f;
|
||||
private readonly float _topMargin = 36f;
|
||||
private readonly float _bottomMargin = 36f;
|
||||
|
||||
private DockPlacement _dockPlacement;
|
||||
private readonly double _leftMargin = 36f;
|
||||
private readonly double _middleMargin = 36f;
|
||||
private readonly double _rightMargin = 36f;
|
||||
private readonly double _topMargin = 36f;
|
||||
private readonly double _bottomMargin = 36f;
|
||||
|
||||
private Color _adaptiveGrayedFontColor = Colors.Transparent;
|
||||
private Color? _adaptiveColoredFontColor = null;
|
||||
@@ -137,10 +123,6 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
private Color _fgFontColor;
|
||||
private Color _strokeFontColor;
|
||||
|
||||
private Color? _customBgFontColor;
|
||||
private Color? _customFgFontColor;
|
||||
private Color? _customStrokeFontColor;
|
||||
|
||||
private int _playingLineIndex = -1;
|
||||
|
||||
private int _startVisibleLineIndex = -1;
|
||||
@@ -149,36 +131,26 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
private bool _isDebugOverlayEnabled = false;
|
||||
private bool _isDesktopMode = false;
|
||||
private bool _isDockMode = false;
|
||||
private bool _isFanLyricsEnabled = false;
|
||||
|
||||
private bool _isPlaying = true;
|
||||
[ObservableProperty]
|
||||
public partial bool IsPlaying { get; set; } = false;
|
||||
|
||||
private bool _isLyricsWindowLocked = false;
|
||||
private bool _isMouseWithinWindow = false;
|
||||
|
||||
private bool _isDynamicCoverOverlayEnabled;
|
||||
private bool _isLyricsGlowEffectEnabled;
|
||||
|
||||
private bool _isLyricsFloatAnimationEnabled;
|
||||
|
||||
private bool _isLayoutChanged = true;
|
||||
|
||||
private int _langIndex = 0;
|
||||
|
||||
private List<LyricsData> _lyricsDataArr = [];
|
||||
private bool _isTranslationEnabled;
|
||||
private bool _showTranslationOnly;
|
||||
private int _targetLanguageIndex;
|
||||
private bool _isLibreTranslateEnabled;
|
||||
private string _lyricsTranslationSeparator;
|
||||
|
||||
private List<MediaSourceProviderInfo> _mediaSourceProvidersInfo;
|
||||
private int _timelineSyncThreshold = 0;
|
||||
|
||||
private CanvasTextFormat _lyricsTextFormat = new()
|
||||
{
|
||||
HorizontalAlignment = CanvasHorizontalAlignment.Left,
|
||||
VerticalAlignment = CanvasVerticalAlignment.Top,
|
||||
FontSize = 12,
|
||||
};
|
||||
private CanvasTextFormat _titleTextFormat = new()
|
||||
{
|
||||
@@ -212,11 +184,6 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
|
||||
private LyricsLayoutOrientation _lyricsLayoutOrientation;
|
||||
|
||||
private int _albumArtBgBlurAmount;
|
||||
private int _albumArtBgOpacity;
|
||||
|
||||
private int _coverAcrylicEffectAmount;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial bool IsTranslating { get; set; } = false;
|
||||
|
||||
@@ -250,7 +217,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
return GetMaxLyricsLineIndexBoundaries().Item2;
|
||||
}
|
||||
|
||||
private void GetLinePlayingProgress(int lineIndex, out int charStartIndex, out int charLength, out float charProgress)
|
||||
private void GetLinePlayingProgress(int lineIndex, out int charStartIndex, out int charLength, out double charProgress)
|
||||
{
|
||||
charStartIndex = 0;
|
||||
charLength = 0;
|
||||
@@ -265,7 +232,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
else if (nextLine != null) lineEndMs = nextLine.StartMs;
|
||||
else lineEndMs = _songDurationMs;
|
||||
|
||||
float now = (float)TotalTime.TotalMilliseconds + (float)_positionOffset.TotalMilliseconds;
|
||||
double now = (double)TotalTime.TotalMilliseconds + (double)_positionOffset.TotalMilliseconds;
|
||||
|
||||
// 1. 还没到本句
|
||||
if (now < line.StartMs)
|
||||
@@ -325,11 +292,11 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
int textLength = line.OriginalText.Length;
|
||||
if (textLength == 0) return;
|
||||
|
||||
float lineProgress = (now - line.StartMs) / (lineEndMs - line.StartMs);
|
||||
double lineProgress = (now - line.StartMs) / (lineEndMs - line.StartMs);
|
||||
lineProgress = Math.Clamp(lineProgress, 0f, 1f);
|
||||
|
||||
// 计算当前高亮到第几个字
|
||||
float charFloatIndex = lineProgress * textLength;
|
||||
double charFloatIndex = lineProgress * textLength;
|
||||
int charIndex = (int)charFloatIndex;
|
||||
charStartIndex = Math.Clamp(charIndex, 0, textLength - 1);
|
||||
charLength = 1;
|
||||
@@ -364,12 +331,13 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
|
||||
private void PlaybackService_IsPlayingChanged(object? sender, IsPlayingChangedEventArgs e)
|
||||
{
|
||||
_isPlaying = e.IsPlaying;
|
||||
IsPlaying = e.IsPlaying;
|
||||
}
|
||||
|
||||
private void PlaybackService_TimelineChanged(object? sender, TimelineChangedEventArgs e)
|
||||
{
|
||||
if (Math.Abs(TotalTime.TotalMilliseconds - e.Position.TotalMilliseconds) >= _timelineSyncThreshold)
|
||||
var diff = Math.Abs(TotalTime.TotalMilliseconds - e.Position.TotalMilliseconds);
|
||||
if (diff >= _timelineSyncThreshold)
|
||||
{
|
||||
TotalTime = e.Position;
|
||||
if (TotalTime.TotalSeconds <= 1)
|
||||
@@ -378,6 +346,11 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
_isLastFMTracked = false;
|
||||
}
|
||||
}
|
||||
// 大跨度,刷新布局,避免歌词不显示
|
||||
if (diff >= _timelineSyncThreshold + 5000)
|
||||
{
|
||||
_isLayoutChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void PlaybackService_SongInfoChanged(object? sender, SongInfoChangedEventArgs e)
|
||||
@@ -418,14 +391,24 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
{
|
||||
if (e.AlbumArtSwBitmap != _albumArtSwBitmap)
|
||||
{
|
||||
//_lastAlbumArtSwBitmap?.Dispose();
|
||||
_lastAlbumArtSwBitmap = null;
|
||||
_cachedAlbumArtSwBitmaps.Append(_albumArtSwBitmap);
|
||||
|
||||
_lastAlbumArtSwBitmap = _albumArtSwBitmap;
|
||||
|
||||
//_albumArtSwBitmap?.Dispose();
|
||||
_albumArtSwBitmap = null;
|
||||
if (_cachedAlbumArtSwBitmaps.Count > 2)
|
||||
{
|
||||
_cachedAlbumArtSwBitmaps.Dequeue()?.Dispose();
|
||||
}
|
||||
|
||||
_cachedAlbumArtSwBitmaps.Append(e.AlbumArtSwBitmap);
|
||||
|
||||
_albumArtSwBitmap = e.AlbumArtSwBitmap;
|
||||
|
||||
if (_cachedAlbumArtSwBitmaps.Count > 2)
|
||||
{
|
||||
_cachedAlbumArtSwBitmaps.Dequeue()?.Dispose();
|
||||
}
|
||||
|
||||
_albumArtChanged = true;
|
||||
|
||||
_albumArtLightAccentColor = e.AlbumArtLightAccentColor ?? Colors.Transparent;
|
||||
@@ -433,6 +416,10 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
|
||||
UpdateColorConfig();
|
||||
}
|
||||
else
|
||||
{
|
||||
e.AlbumArtSwBitmap?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateTranslations()
|
||||
@@ -442,7 +429,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
_isLayoutChanged = true;
|
||||
|
||||
IsTranslating = true;
|
||||
if (_isTranslationEnabled)
|
||||
if (_settingsService.AppSettings.TranslationSettings.IsTranslationEnabled)
|
||||
{
|
||||
_ = _refreshLyricsRunner.RunAsync(async token =>
|
||||
{
|
||||
@@ -480,19 +467,19 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
int found = _translateService.SearchTranslatedLyricsItself(_lyricsDataArr);
|
||||
if (found >= 0)
|
||||
{
|
||||
if (_showTranslationOnly)
|
||||
if (_settingsService.AppSettings.TranslationSettings.ShowTranslationOnly)
|
||||
{
|
||||
_lyricsDataArr[found].SetDisplayedTextInOriginalText();
|
||||
_langIndex = found;
|
||||
}
|
||||
else
|
||||
{
|
||||
_lyricsDataArr[0].SetDisplayedTextAlongWith(_lyricsDataArr[found], _lyricsTranslationSeparator, 50);
|
||||
_lyricsDataArr[0].SetDisplayedTextAlongWith(_lyricsDataArr[found], _lyricsStyleSettings.LyricsTranslationSeparator, 50);
|
||||
_langIndex = 0;
|
||||
}
|
||||
TranslationSearchProvider = LyricsSearchProvider.ToTranslationSearchProvider();
|
||||
}
|
||||
else if (_isLibreTranslateEnabled)
|
||||
else if (_settingsService.AppSettings.TranslationSettings.IsLibreTranslateEnabled)
|
||||
{
|
||||
string translated = string.Empty;
|
||||
try
|
||||
@@ -500,7 +487,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
translated = await _translateService.TranslateTextAsync(originalText, targetLangCode, token);
|
||||
if (translated == string.Empty) return;
|
||||
|
||||
if (_showTranslationOnly)
|
||||
if (_settingsService.AppSettings.TranslationSettings.ShowTranslationOnly)
|
||||
{
|
||||
_lyricsDataArr[^1] = _lyricsDataArr[0].CreateLyricsDataFrom(translated);
|
||||
_lyricsDataArr[^1].SetDisplayedTextInOriginalText();
|
||||
@@ -508,7 +495,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
|
||||
}
|
||||
else
|
||||
{
|
||||
_lyricsDataArr[0].SetDisplayedTextAlongWith(translated, _lyricsTranslationSeparator);
|
||||
_lyricsDataArr[0].SetDisplayedTextAlongWith(translated, _lyricsStyleSettings.LyricsTranslationSeparator);
|
||||
_langIndex = 0;
|
||||
}
|
||||
TranslationSearchProvider = Enums.TranslationSearchProvider.LibreTranslate;
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.Models.Settings;
|
||||
using BetterLyrics.WinUI3.Services.MediaSessionsService;
|
||||
using BetterLyrics.WinUI3.Services.SettingsService;
|
||||
using BetterLyrics.WinUI3.ViewModels;
|
||||
using BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel;
|
||||
using BetterLyrics.WinUI3.ViewModels.SettingsPageViewModel;
|
||||
using BetterLyrics.WinUI3.Views;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
@@ -15,13 +15,8 @@ using CommunityToolkit.Mvvm.Input;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using CommunityToolkit.Mvvm.Messaging.Messages;
|
||||
using CommunityToolkit.WinUI;
|
||||
using Microsoft.UI;
|
||||
using Microsoft.UI.Windowing;
|
||||
using Microsoft.UI.Xaml;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Vanara.PInvoke;
|
||||
using Windows.System;
|
||||
using Windows.UI;
|
||||
@@ -38,7 +33,9 @@ namespace BetterLyrics.WinUI3
|
||||
IRecipient<PropertyChangedMessage<ElementTheme>>,
|
||||
IRecipient<PropertyChangedMessage<DockPlacement>>
|
||||
{
|
||||
private readonly IMediaSessionsService _mediaSessionsService = Ioc.Default.GetRequiredService<IMediaSessionsService>();
|
||||
private readonly IMediaSessionsService _mediaSessionsService;
|
||||
private readonly ISettingsService _settingsService;
|
||||
|
||||
private ForegroundWindowWatcher? _windowWatcher = null;
|
||||
private bool _ignoreFullscreenWindow;
|
||||
private bool _hideWindowWhenNotPlaying;
|
||||
@@ -47,15 +44,18 @@ namespace BetterLyrics.WinUI3
|
||||
private int _dockWindowHeight;
|
||||
private string _dockMonitorDeviceName;
|
||||
|
||||
public LyricsWindowViewModel(ISettingsService settingsService) : base(settingsService)
|
||||
public LyricsWindowViewModel(ISettingsService settingsService, IMediaSessionsService mediaSessionsService)
|
||||
{
|
||||
_dockMonitorDeviceName = _settingsService.DockMonitorDeviceName;
|
||||
_ignoreFullscreenWindow = _settingsService.IgnoreFullscreenWindow;
|
||||
_hideWindowWhenNotPlaying = _settingsService.HideWindowWhenNotPlaying;
|
||||
IsImmersiveMode = _settingsService.IsImmersiveMode;
|
||||
_dockPlacement = _settingsService.DockPlacement;
|
||||
_dockWindowHeight = _settingsService.DockWindowHeight;
|
||||
OnIsImmersiveModeChanged(_settingsService.IsImmersiveMode);
|
||||
_settingsService = settingsService;
|
||||
_mediaSessionsService = mediaSessionsService;
|
||||
|
||||
_dockMonitorDeviceName = _settingsService.AppSettings.DockModeSettings.DockMonitorDeviceName;
|
||||
_ignoreFullscreenWindow = _settingsService.AppSettings.GeneralSettings.IgnoreFullscreenWindow;
|
||||
_hideWindowWhenNotPlaying = _settingsService.AppSettings.GeneralSettings.HideWindowWhenNotPlaying;
|
||||
IsImmersiveMode = _settingsService.AppSettings.GeneralSettings.IsImmersiveMode;
|
||||
_dockPlacement = _settingsService.AppSettings.DockModeSettings.DockPlacement;
|
||||
_dockWindowHeight = _settingsService.AppSettings.DockModeSettings.DockWindowHeight;
|
||||
OnIsImmersiveModeChanged(_settingsService.AppSettings.GeneralSettings.IsImmersiveMode);
|
||||
|
||||
_mediaSessionsService.IsPlayingChanged += PlaybackService_IsPlayingChanged;
|
||||
}
|
||||
@@ -86,7 +86,7 @@ namespace BetterLyrics.WinUI3
|
||||
public partial bool IsImmersiveMode { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial float TopCommandGridOpacity { get; set; }
|
||||
public partial double TopCommandGridOpacity { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial ElementTheme ThemeType { get; set; } = ElementTheme.Default;
|
||||
@@ -153,13 +153,13 @@ namespace BetterLyrics.WinUI3
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (message.Sender is SettingsPageViewModel)
|
||||
else if (message.Sender is GeneralSettings)
|
||||
{
|
||||
if (message.PropertyName == nameof(SettingsPageViewModel.IgnoreFullscreenWindow))
|
||||
if (message.PropertyName == nameof(GeneralSettings.IgnoreFullscreenWindow))
|
||||
{
|
||||
_ignoreFullscreenWindow = message.NewValue;
|
||||
}
|
||||
else if (message.PropertyName == nameof(SettingsPageViewModel.HideWindowWhenNotPlaying))
|
||||
else if (message.PropertyName == nameof(GeneralSettings.HideWindowWhenNotPlaying))
|
||||
{
|
||||
_hideWindowWhenNotPlaying = message.NewValue;
|
||||
UpdateDockWindow();
|
||||
@@ -180,19 +180,19 @@ namespace BetterLyrics.WinUI3
|
||||
|
||||
public void Receive(PropertyChangedMessage<int> message)
|
||||
{
|
||||
if (message.Sender is SettingsPageViewModel)
|
||||
if (message.Sender is DockModeSettings)
|
||||
{
|
||||
if (message.PropertyName == nameof(SettingsPageViewModel.DockWindowHeight))
|
||||
if (message.PropertyName == nameof(DockModeSettings.DockWindowHeight))
|
||||
{
|
||||
_dockWindowHeight = message.NewValue;
|
||||
UpdateDockWindow();
|
||||
}
|
||||
else if (message.Sender is SettingsPageViewModel)
|
||||
}
|
||||
else if (message.Sender is DesktopModeSettings)
|
||||
{
|
||||
if (message.PropertyName == nameof(DesktopModeSettings.LockHotKeyIndex))
|
||||
{
|
||||
if (message.PropertyName == nameof(SettingsPageViewModel.LockHotKeyIndex))
|
||||
{
|
||||
UpdateLockHotKey(message.NewValue);
|
||||
}
|
||||
UpdateLockHotKey(message.NewValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -251,12 +251,12 @@ namespace BetterLyrics.WinUI3
|
||||
public void UpdateAccentColor(nint hwnd)
|
||||
{
|
||||
WindowPixelSampleMode mode = IsDesktopMode ? WindowPixelSampleMode.WindowEdge : _dockPlacement.ToWindowPixelSampleMode();
|
||||
ActivatedWindowAccentColor = Helper.ColorHelper.GetAccentColor(hwnd, _settingsService.DockMonitorDeviceName, mode).ToColor();
|
||||
ActivatedWindowAccentColor = ColorHelper.GetAccentColor(hwnd, _settingsService.AppSettings.DockModeSettings.DockMonitorDeviceName, mode).ToColor();
|
||||
}
|
||||
|
||||
public void InitLockHotKey()
|
||||
{
|
||||
UpdateLockHotKey(_settingsService.LockHotKeyIndex);
|
||||
UpdateLockHotKey(_settingsService.AppSettings.DesktopModeSettings.LockHotKeyIndex);
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
@@ -269,7 +269,7 @@ namespace BetterLyrics.WinUI3
|
||||
{
|
||||
DesktopModeHelper.SetClickThrough(window, false);
|
||||
IsLyricsWindowLocked = false;
|
||||
IsImmersiveMode = _settingsService.IsImmersiveMode;
|
||||
IsImmersiveMode = _settingsService.AppSettings.GeneralSettings.IsImmersiveMode;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -327,14 +327,14 @@ namespace BetterLyrics.WinUI3
|
||||
[RelayCommand]
|
||||
private void OnImmersiveToggleButtonEnabledChanged()
|
||||
{
|
||||
_settingsService.IsImmersiveMode = IsImmersiveMode;
|
||||
_settingsService.AppSettings.GeneralSettings.IsImmersiveMode = IsImmersiveMode;
|
||||
}
|
||||
|
||||
public void Receive(PropertyChangedMessage<DockPlacement> message)
|
||||
{
|
||||
if (message.Sender is SettingsPageViewModel)
|
||||
if (message.Sender is DockModeSettings)
|
||||
{
|
||||
if (message.PropertyName == nameof(SettingsPageViewModel.DockPlacement))
|
||||
if (message.PropertyName == nameof(DockModeSettings.DockPlacement))
|
||||
{
|
||||
_dockPlacement = message.NewValue;
|
||||
UpdateDockWindow();
|
||||
@@ -344,9 +344,9 @@ namespace BetterLyrics.WinUI3
|
||||
|
||||
public void Receive(PropertyChangedMessage<string> message)
|
||||
{
|
||||
if (message.Sender is SettingsPageViewModel)
|
||||
if (message.Sender is DockModeSettings)
|
||||
{
|
||||
if (message.PropertyName == nameof(SettingsPageViewModel.SelectedDockMonitorDeviceName))
|
||||
if (message.PropertyName == nameof(DockModeSettings.DockMonitorDeviceName))
|
||||
{
|
||||
_dockMonitorDeviceName = message.NewValue;
|
||||
UpdateDockWindow();
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.Models.Settings;
|
||||
using BetterLyrics.WinUI3.Services.LibWatcherService;
|
||||
using BetterLyrics.WinUI3.Services.SettingsService;
|
||||
using BetterLyrics.WinUI3.Views;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using WinRT.Interop;
|
||||
|
||||
namespace BetterLyrics.WinUI3.ViewModels
|
||||
{
|
||||
public partial class MediaSettingsControlViewModel : BaseViewModel
|
||||
{
|
||||
private readonly ISettingsService _settingsService;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial AppSettings AppSettings { get; set; }
|
||||
|
||||
public MediaSettingsControlViewModel(ISettingsService settingsService)
|
||||
{
|
||||
_settingsService = settingsService;
|
||||
AppSettings = _settingsService.AppSettings;
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task SelectAndAddFolderAsync(UIElement sender)
|
||||
{
|
||||
var window = WindowHelper.GetWindowByWindowType<SettingsWindow>();
|
||||
if (window == null) return;
|
||||
|
||||
var picker = new Windows.Storage.Pickers.FolderPicker();
|
||||
picker.FileTypeFilter.Add("*");
|
||||
|
||||
var hwnd = WindowNative.GetWindowHandle(window);
|
||||
InitializeWithWindow.Initialize(picker, hwnd);
|
||||
|
||||
var folder = await picker.PickSingleFolderAsync();
|
||||
|
||||
if (folder != null)
|
||||
{
|
||||
AddFolderAsync(folder.Path);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddFolderAsync(string path)
|
||||
{
|
||||
var normalizedPath = Path.GetFullPath(path).TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar;
|
||||
|
||||
if (AppSettings.LocalMediaFolders.Any(x => Path.GetFullPath(x.Path).TrimEnd(Path.DirectorySeparatorChar).Equals(normalizedPath.TrimEnd(Path.DirectorySeparatorChar), StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
App.Current.SettingsWindowNotificationPanel?.Notify(App.ResourceLoader!.GetString("SettingsPagePathExistedInfo"), InfoBarSeverity.Warning);
|
||||
}
|
||||
else if (AppSettings.LocalMediaFolders.Any(item => normalizedPath.StartsWith(Path.GetFullPath(item.Path).TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
// 添加的文件夹是现有文件夹的子文件夹
|
||||
App.Current.SettingsWindowNotificationPanel?.Notify(App.ResourceLoader!.GetString("SettingsPagePathBeIncludedInfo"), InfoBarSeverity.Warning);
|
||||
}
|
||||
else if (AppSettings.LocalMediaFolders.Any(item => Path.GetFullPath(item.Path).TrimEnd(Path.DirectorySeparatorChar).StartsWith(normalizedPath, StringComparison.OrdinalIgnoreCase))
|
||||
)
|
||||
{
|
||||
// 添加的文件夹是现有文件夹的父文件夹
|
||||
App.Current.SettingsWindowNotificationPanel?.Notify(App.ResourceLoader!.GetString("SettingsPagePathIncludingOthersInfo"), InfoBarSeverity.Warning);
|
||||
}
|
||||
else
|
||||
{
|
||||
AppSettings.LocalMediaFolders.Add(new LocalMediaFolder(path, true));
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveFolderAsync(LocalMediaFolder folder)
|
||||
{
|
||||
AppSettings.LocalMediaFolders.Remove(folder);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
using ATL;
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using BetterLyrics.WinUI3.Extensions;
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.Models.Settings;
|
||||
using BetterLyrics.WinUI3.Services;
|
||||
using BetterLyrics.WinUI3.Services.LibWatcherService;
|
||||
using BetterLyrics.WinUI3.Services.SettingsService;
|
||||
@@ -25,10 +27,11 @@ using Windows.Media.Playback;
|
||||
|
||||
namespace BetterLyrics.WinUI3.ViewModels
|
||||
{
|
||||
public partial class MusicGalleryViewModel : BaseViewModel,
|
||||
IRecipient<PropertyChangedMessage<ObservableCollection<LocalMediaFolder>>>
|
||||
public partial class MusicGalleryViewModel : BaseViewModel
|
||||
{
|
||||
private readonly ILibWatcherService _libWatcherService;
|
||||
private readonly ISettingsService _settingsService;
|
||||
|
||||
private readonly MediaPlayer _mediaPlayer = new();
|
||||
private readonly MediaTimelineController _timelineController = new();
|
||||
private readonly SystemMediaTransportControls _smtc;
|
||||
@@ -85,13 +88,18 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
[ObservableProperty]
|
||||
public partial string SongSearchQuery { get; set; } = string.Empty;
|
||||
|
||||
public MusicGalleryViewModel(ISettingsService settingsService, ILibWatcherService libWatcherService) : base(settingsService)
|
||||
public MusicGalleryViewModel(ISettingsService settingsService, ILibWatcherService libWatcherService)
|
||||
{
|
||||
_settingsService = settingsService;
|
||||
|
||||
SongsTabInfoList.Add(new SongsTabInfo(App.ResourceLoader!.GetString("MusicGalleryPageAllSongs"), "\uE8A9", false, CommonSongProperty.Title, string.Empty));
|
||||
|
||||
RefreshSongs();
|
||||
|
||||
PlaybackOrder = _settingsService.PlaybackOrder;
|
||||
_settingsService.AppSettings.LocalMediaFolders.CollectionChanged += LocalMediaFolders_CollectionChanged;
|
||||
_settingsService.AppSettings.LocalMediaFolders.ItemPropertyChanged += LocalMediaFolders_ItemPropertyChanged;
|
||||
|
||||
PlaybackOrder = _settingsService.AppSettings.MusicGallerySettings.PlaybackOrder;
|
||||
|
||||
_mediaPlayer.MediaOpened += MediaPlayer_MediaOpened;
|
||||
_mediaPlayer.MediaEnded += MediaPlayer_MediaEnded;
|
||||
@@ -110,6 +118,16 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
_libWatcherService.MusicLibraryFilesChanged += LibWatcherService_MusicLibraryFilesChanged;
|
||||
}
|
||||
|
||||
private void LocalMediaFolders_ItemPropertyChanged(object? sender, ItemPropertyChangedEventArgs e)
|
||||
{
|
||||
RefreshSongs();
|
||||
}
|
||||
|
||||
private void LocalMediaFolders_CollectionChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
RefreshSongs();
|
||||
}
|
||||
|
||||
private void MediaPlayer_MediaEnded(MediaPlayer sender, object args)
|
||||
{
|
||||
PlayNextTrack();
|
||||
@@ -242,7 +260,7 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
|
||||
Task.Run(() =>
|
||||
{
|
||||
foreach (var folder in _settingsService.LocalMediaFolders)
|
||||
foreach (var folder in _settingsService.AppSettings.LocalMediaFolders)
|
||||
{
|
||||
if (Directory.Exists(folder.Path) && folder.IsEnabled)
|
||||
{
|
||||
@@ -264,7 +282,7 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
IsDataLoading = false;
|
||||
});
|
||||
});
|
||||
}, TimeSpan.FromMilliseconds(100));
|
||||
}, Constants.Time.DebounceTimeout);
|
||||
}
|
||||
|
||||
public void ApplyPlaylist()
|
||||
@@ -405,18 +423,7 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
|
||||
partial void OnPlaybackOrderChanged(PlaybackOrder value)
|
||||
{
|
||||
_settingsService.PlaybackOrder = value;
|
||||
}
|
||||
|
||||
public void Receive(PropertyChangedMessage<ObservableCollection<LocalMediaFolder>> message)
|
||||
{
|
||||
if (message.Sender is SettingsPageViewModel.SettingsPageViewModel)
|
||||
{
|
||||
if (message.PropertyName == nameof(SettingsPageViewModel.SettingsPageViewModel.LocalMediaFolders))
|
||||
{
|
||||
RefreshSongs();
|
||||
}
|
||||
}
|
||||
_settingsService.AppSettings.MusicGallerySettings.PlaybackOrder = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,206 @@
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using BetterLyrics.WinUI3.Extensions;
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.Models.Settings;
|
||||
using BetterLyrics.WinUI3.Services;
|
||||
using BetterLyrics.WinUI3.Services.LastFMService;
|
||||
using BetterLyrics.WinUI3.Services.MediaSessionsService;
|
||||
using BetterLyrics.WinUI3.Services.SettingsService;
|
||||
using BetterLyrics.WinUI3.Services.TranslateService;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using CommunityToolkit.Mvvm.Messaging.Messages;
|
||||
using CommunityToolkit.WinUI;
|
||||
using Hqub.Lastfm.Entities;
|
||||
using Microsoft.UI.Dispatching;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BetterLyrics.WinUI3.ViewModels
|
||||
{
|
||||
public partial class PlaybackSettingsControlViewModel : BaseViewModel,
|
||||
IRecipient<PropertyChangedMessage<LyricsSearchProvider?>>,
|
||||
IRecipient<PropertyChangedMessage<TranslationSearchProvider?>>
|
||||
{
|
||||
private readonly IMediaSessionsService _mediaSessionsService;
|
||||
private readonly ITranslateService _libreTranslateService;
|
||||
private readonly ILastFMService _lastFMService;
|
||||
private readonly ISettingsService _settingsService;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial AppSettings AppSettings { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial MediaSourceProviderInfo? SelectedMediaSourceProvider { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial bool IsLastFMAuthenticated { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial User? LastFMUser { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial bool IsLibreTranslateServerTesting { get; set; } = false;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial bool IsLXMusicServerTesting { get; set; } = false;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial LyricsSearchProvider? LyricsSearchProvider { get; set; } = null;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial TranslationSearchProvider? TranslationSearchProvider { get; set; } = null;
|
||||
|
||||
|
||||
|
||||
public PlaybackSettingsControlViewModel(
|
||||
ISettingsService settingsService,
|
||||
IMediaSessionsService mediaSessionsService,
|
||||
ITranslateService libreTranslateService,
|
||||
ILastFMService lastFMService)
|
||||
{
|
||||
_settingsService = settingsService;
|
||||
_mediaSessionsService = mediaSessionsService;
|
||||
_libreTranslateService = libreTranslateService;
|
||||
|
||||
_lastFMService = lastFMService;
|
||||
_lastFMService.UserChanged += LastFMService_UserChanged;
|
||||
_lastFMService.IsAuthenticatedChanged += LastFMService_IsAuthenticatedChanged;
|
||||
|
||||
_mediaSessionsService.SongInfoChanged += MediaSessionsService_SongInfoChanged;
|
||||
|
||||
AppSettings = _settingsService.AppSettings;
|
||||
AppSettings.MediaSourceProvidersInfo.CollectionChanged += MediaSourceProvidersInfo_CollectionChanged;
|
||||
|
||||
IsLastFMAuthenticated = _lastFMService.IsAuthenticated;
|
||||
LastFMUser = _lastFMService.User;
|
||||
|
||||
SelectedMediaSourceProvider = AppSettings.MediaSourceProvidersInfo.FirstOrDefault();
|
||||
}
|
||||
|
||||
private void MediaSourceProvidersInfo_CollectionChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
SelectedMediaSourceProvider = AppSettings.MediaSourceProvidersInfo.FirstOrDefault();
|
||||
}
|
||||
|
||||
private void LastFMService_IsAuthenticatedChanged(object? sender, Events.LastFMIsAuthenticatedChangedEventArgs e)
|
||||
{
|
||||
IsLastFMAuthenticated = e.IsAuthenticated;
|
||||
}
|
||||
|
||||
private void LastFMService_UserChanged(object? sender, Events.LastFMUserChangedEventArgs e)
|
||||
{
|
||||
LastFMUser = e.User;
|
||||
}
|
||||
|
||||
private void MediaSessionsService_SongInfoChanged(object? sender, Events.SongInfoChangedEventArgs e)
|
||||
{
|
||||
var current = AppSettings.MediaSourceProvidersInfo.Where(x => x.Provider == e.SongInfo?.SourceAppUserModelId)?.FirstOrDefault();
|
||||
if (_mediaSessionsService.Position.TotalSeconds <= 1 && current?.ResetPositionOffsetOnSongChanged == true)
|
||||
{
|
||||
current.PositionOffset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void MediaSessionsService_SessionIdsChanged(object? sender, Events.MediaSourceProvidersInfoEventArgs e)
|
||||
{
|
||||
SelectedMediaSourceProvider = AppSettings.MediaSourceProvidersInfo.FirstOrDefault();
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void LibreTranslateServerTest()
|
||||
{
|
||||
IsLibreTranslateServerTesting = true;
|
||||
Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
string targetLangCode = LanguageHelper.SupportedTargetLanguages[AppSettings.TranslationSettings.SelectedTargetLanguageIndex].Code;
|
||||
string result = await _libreTranslateService.TranslateTextAsync("Hello, world!", targetLangCode, null);
|
||||
_dispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, () =>
|
||||
{
|
||||
App.Current.SettingsWindowNotificationPanel?.Notify(App.ResourceLoader!.GetString("SettingsPageServerTestSuccessInfo"), InfoBarSeverity.Success);
|
||||
});
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
_dispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, () =>
|
||||
{
|
||||
App.Current.SettingsWindowNotificationPanel?.Notify(App.ResourceLoader!.GetString("SettingsPageServerTestFailedInfo"), InfoBarSeverity.Error);
|
||||
});
|
||||
}
|
||||
_dispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, () =>
|
||||
{
|
||||
IsLibreTranslateServerTesting = false;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task LastFMAuthAsync()
|
||||
{
|
||||
await _lastFMService.AuthAsync();
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task LastFMUnAuthAsync()
|
||||
{
|
||||
await _lastFMService.UnAuthAsync();
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task LastFMRefreshAsync()
|
||||
{
|
||||
await _lastFMService.RefreshAsync();
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void LXMusicServerTest()
|
||||
{
|
||||
IsLXMusicServerTesting = true;
|
||||
Task.Run(async () =>
|
||||
{
|
||||
bool testResult = await NetHelper.CheckConnectivity($"{AppSettings.GeneralSettings.LXMusicServer}/status");
|
||||
_dispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, () =>
|
||||
{
|
||||
if (testResult)
|
||||
{
|
||||
App.Current.SettingsWindowNotificationPanel?.Notify(App.ResourceLoader!.GetString("SettingsPageServerTestSuccessInfo"), InfoBarSeverity.Success);
|
||||
}
|
||||
else
|
||||
{
|
||||
App.Current.SettingsWindowNotificationPanel?.Notify(App.ResourceLoader!.GetString("SettingsPageServerTestFailedInfo"), InfoBarSeverity.Error);
|
||||
}
|
||||
IsLXMusicServerTesting = false;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public void Receive(PropertyChangedMessage<LyricsSearchProvider?> message)
|
||||
{
|
||||
if (message.Sender is LyricsRendererViewModel.LyricsRendererViewModel)
|
||||
{
|
||||
if (message.PropertyName == nameof(LyricsRendererViewModel.LyricsRendererViewModel.LyricsSearchProvider))
|
||||
{
|
||||
LyricsSearchProvider = message.NewValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Receive(PropertyChangedMessage<TranslationSearchProvider?> message)
|
||||
{
|
||||
if (message.Sender is LyricsRendererViewModel.LyricsRendererViewModel)
|
||||
{
|
||||
if (message.PropertyName == nameof(LyricsRendererViewModel.LyricsRendererViewModel.TranslationSearchProvider))
|
||||
{
|
||||
TranslationSearchProvider = message.NewValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
// 2025/6/23 by Zhe Fang
|
||||
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.Models.Settings;
|
||||
using BetterLyrics.WinUI3.Services;
|
||||
using BetterLyrics.WinUI3.Services.LastFMService;
|
||||
using BetterLyrics.WinUI3.Services.LibWatcherService;
|
||||
using BetterLyrics.WinUI3.Services.MediaSessionsService;
|
||||
using BetterLyrics.WinUI3.Services.SettingsService;
|
||||
using BetterLyrics.WinUI3.Services.TranslateService;
|
||||
using BetterLyrics.WinUI3.Views;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using CommunityToolkit.WinUI;
|
||||
using Microsoft.UI.Dispatching;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.ApplicationModel;
|
||||
using WinRT.Interop;
|
||||
|
||||
namespace BetterLyrics.WinUI3.ViewModels
|
||||
{
|
||||
public partial class SettingsPageViewModel : BaseViewModel
|
||||
{
|
||||
private readonly ISettingsService _settingsService;
|
||||
|
||||
public string Version { get; set; } = MetadataHelper.AppVersion;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial AppSettings AppSettings { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial bool IsDebugOverlayEnabled { get; set; } = false;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial object NavViewSelectedItemTag { get; set; } = "App";
|
||||
|
||||
public SettingsPageViewModel(ISettingsService settingsService)
|
||||
{
|
||||
_settingsService = settingsService;
|
||||
AppSettings = _settingsService.AppSettings;
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task LaunchProjectGitHubPageAsync()
|
||||
{
|
||||
await Windows.System.Launcher.LaunchUriAsync(new Uri(Constants.Link.GithubUrl));
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private static async Task OpenCacheFolderAsync()
|
||||
{
|
||||
await Windows.System.Launcher.LaunchFolderPathAsync(Helper.PathHelper.CacheFolder);
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private static void RestartApp()
|
||||
{
|
||||
Helper.WindowHelper.RestartApp();
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task ImportSettingsAsync()
|
||||
{
|
||||
var window = WindowHelper.GetWindowByWindowType<SettingsWindow>();
|
||||
if (window == null) return;
|
||||
|
||||
var picker = new Windows.Storage.Pickers.FileOpenPicker();
|
||||
picker.FileTypeFilter.Add(".json");
|
||||
|
||||
var hwnd = WindowNative.GetWindowHandle(window);
|
||||
InitializeWithWindow.Initialize(picker, hwnd);
|
||||
|
||||
var file = await picker.PickSingleFileAsync();
|
||||
|
||||
var succeed = _settingsService.ImportSettings(file.Path);
|
||||
if (succeed)
|
||||
{
|
||||
WindowHelper.RestartApp();
|
||||
}
|
||||
else
|
||||
{
|
||||
App.Current.SettingsWindowNotificationPanel?.Notify(App.ResourceLoader?.GetString("ImportSettingsFailed") ?? "");
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task ExportSettingsAsync()
|
||||
{
|
||||
var window = WindowHelper.GetWindowByWindowType<SettingsWindow>();
|
||||
if (window == null) return;
|
||||
|
||||
var picker = new Windows.Storage.Pickers.FolderPicker();
|
||||
picker.FileTypeFilter.Add("*");
|
||||
|
||||
var hwnd = WindowNative.GetWindowHandle(window);
|
||||
InitializeWithWindow.Initialize(picker, hwnd);
|
||||
|
||||
var folder = await picker.PickSingleFolderAsync();
|
||||
|
||||
if (folder != null)
|
||||
{
|
||||
_settingsService.ExportSettings(folder.Path);
|
||||
App.Current.SettingsWindowNotificationPanel?.Notify(App.ResourceLoader?.GetString("ExportSettingsSuccess") ?? "", InfoBarSeverity.Success);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,132 +0,0 @@
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.Services.LastFMService;
|
||||
using BetterLyrics.WinUI3.Services.LibWatcherService;
|
||||
using BetterLyrics.WinUI3.Services.MediaSessionsService;
|
||||
using BetterLyrics.WinUI3.Services.SettingsService;
|
||||
using BetterLyrics.WinUI3.Services.TranslateService;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BetterLyrics.WinUI3.ViewModels.SettingsPageViewModel
|
||||
{
|
||||
public partial class SettingsPageViewModel
|
||||
{
|
||||
public SettingsPageViewModel(
|
||||
ISettingsService settingsService,
|
||||
ILibWatcherService libWatcherService,
|
||||
IMediaSessionsService mediaSessionsService,
|
||||
ITranslateService libreTranslateService,
|
||||
ILastFMService lastFMService) : base(settingsService)
|
||||
{
|
||||
_libWatcherService = libWatcherService;
|
||||
_mediaSessionsService = mediaSessionsService;
|
||||
_libreTranslateService = libreTranslateService;
|
||||
|
||||
// LastFM
|
||||
_lastFMService = lastFMService;
|
||||
_lastFMService.UserChanged += LastFMService_UserChanged;
|
||||
_lastFMService.IsAuthenticatedChanged += LastFMService_IsAuthenticatedChanged;
|
||||
IsLastFMAuthenticated = _lastFMService.IsAuthenticated;
|
||||
LastFMUser = _lastFMService.User;
|
||||
|
||||
IsLibreTranslateEnabled = _settingsService.IsLibreTranslateEnabled;
|
||||
LibreTranslateServer = _settingsService.LibreTranslateServer;
|
||||
SelectedTargetLanguageIndex = _settingsService.SelectedTargetLanguageIndex;
|
||||
|
||||
LocalMediaFolders = [.. _settingsService.LocalMediaFolders];
|
||||
AlbumArtSearchProvidersInfo = [.. _settingsService.AlbumArtSearchProvidersInfo];
|
||||
|
||||
Language = _settingsService.Language;
|
||||
CoverImageRadius = _settingsService.CoverImageRadius;
|
||||
|
||||
AutoStartWindowType = _settingsService.AutoStartWindowType;
|
||||
AutoLockOnDesktopMode = _settingsService.AutoLockOnDesktopMode;
|
||||
|
||||
IsDynamicCoverOverlayEnabled = _settingsService.IsDynamicCoverOverlayEnabled;
|
||||
CoverOverlayOpacity = _settingsService.CoverOverlayOpacity;
|
||||
CoverOverlayBlurAmount = _settingsService.CoverOverlayBlurAmount;
|
||||
|
||||
CoverAcrylicEffectAmount = _settingsService.CoverAcrylicEffectAmount;
|
||||
|
||||
LyricsAlignmentType = _settingsService.LyricsAlignmentType;
|
||||
SongInfoAlignmentType = _settingsService.SongInfoAlignmentType;
|
||||
LyricsFontWeight = _settingsService.LyricsFontWeight;
|
||||
LyricsBlurAmount = _settingsService.LyricsBlurAmount;
|
||||
LyricsVerticalEdgeOpacity = _settingsService.LyricsVerticalEdgeOpacity;
|
||||
LyricsLineSpacingFactor = _settingsService.LyricsLineSpacingFactor;
|
||||
|
||||
// Font size
|
||||
LyricsStandardFontSize = _settingsService.LyricsStandardFontSize;
|
||||
LyricsDockFontSize = _settingsService.LyricsDockFontSize;
|
||||
LyricsDesktopFontSize = _settingsService.LyricsDesktopFontSize;
|
||||
|
||||
IsLyricsGlowEffectEnabled = _settingsService.IsLyricsGlowEffectEnabled;
|
||||
LyricsGlowEffectScope = _settingsService.LyricsGlowEffectScope;
|
||||
LyricsHighlightScope = _settingsService.LyricsHighlightScope;
|
||||
IsFanLyricsEnabled = _settingsService.IsFanLyricsEnabled;
|
||||
|
||||
LyricsBgFontColorType = _settingsService.LyricsBgFontColorType;
|
||||
LyricsFgFontColorType = _settingsService.LyricsFgFontColorType;
|
||||
LyricsStrokeFontColorType = _settingsService.LyricsStrokeFontColorType;
|
||||
|
||||
LyricsCustomBgFontColor = _settingsService.LyricsCustomBgFontColor;
|
||||
LyricsCustomFgFontColor = _settingsService.LyricsCustomFgFontColor;
|
||||
LyricsCustomStrokeFontColor = _settingsService.LyricsCustomStrokeFontColor;
|
||||
|
||||
LyricsFontStrokeWidth = _settingsService.LyricsFontStrokeWidth;
|
||||
LyricsBackgroundTheme = _settingsService.LyricsBackgroundTheme;
|
||||
MediaSourceProvidersInfo = [.. _settingsService.MediaSourceProvidersInfo];
|
||||
SelectedMediaSourceProvider = MediaSourceProvidersInfo.FirstOrDefault();
|
||||
|
||||
IgnoreFullscreenWindow = _settingsService.IgnoreFullscreenWindow;
|
||||
|
||||
LyricsScrollEasingType = _settingsService.LyricsScrollEasingType;
|
||||
LyricsScrollDuration = _settingsService.LyricsScrollDuration;
|
||||
|
||||
IsLyricsFloatAnimationEnabled = _settingsService.IsLyricsFloatAnimationEnabled;
|
||||
LockHotKeyIndex = _settingsService.LockHotKeyIndex;
|
||||
|
||||
LXMusicServer = _settingsService.LXMusicServer;
|
||||
DockPlacement = _settingsService.DockPlacement;
|
||||
LyricsBgFontOpacity = _settingsService.LyricsBgFontOpacity;
|
||||
HideWindowWhenNotPlaying = _settingsService.HideWindowWhenNotPlaying;
|
||||
DockWindowHeight = _settingsService.DockWindowHeight;
|
||||
|
||||
SystemFontNames = [.. FontHelper.SystemFontFamilies];
|
||||
SelectedFontFamilyIndex = _settingsService.SelectedFontFamilyIndex;
|
||||
LyricsFontFamily = _settingsService.LyricsFontFamily;
|
||||
IsDragEverywhereEnabled = _settingsService.IsDragEverywhereEnabled;
|
||||
|
||||
MonitorDeviceNames = [.. MonitorHelper.GetAllMonitorDeviceNames()];
|
||||
SelectedDockMonitorDeviceName = _settingsService.DockMonitorDeviceName;
|
||||
|
||||
LyricsTranslationSeparator = _settingsService.LyricsTranslationSeparator;
|
||||
|
||||
_mediaSessionsService.MediaSourceProvidersInfoChanged += MediaSessionsService_SessionIdsChanged;
|
||||
_mediaSessionsService.SongInfoChanged += MediaSessionsService_SongInfoChanged;
|
||||
}
|
||||
|
||||
private void MediaSessionsService_SongInfoChanged(object? sender, Events.SongInfoChangedEventArgs e)
|
||||
{
|
||||
var current = MediaSourceProvidersInfo.Where(x => x.Provider == e.SongInfo?.SourceAppUserModelId)?.FirstOrDefault();
|
||||
if (_mediaSessionsService.Position.TotalSeconds <= 1 && current?.ResetPositionOffsetOnSongChanged == true)
|
||||
{
|
||||
current.PositionOffset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void LastFMService_IsAuthenticatedChanged(object? sender, Events.LastFMIsAuthenticatedChangedEventArgs e)
|
||||
{
|
||||
IsLastFMAuthenticated = e.IsAuthenticated;
|
||||
}
|
||||
|
||||
private void LastFMService_UserChanged(object? sender, Events.LastFMUserChangedEventArgs e)
|
||||
{
|
||||
LastFMUser = e.User;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,227 +0,0 @@
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using BetterLyrics.WinUI3.Views;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Windows.Globalization;
|
||||
using Windows.UI;
|
||||
|
||||
namespace BetterLyrics.WinUI3.ViewModels.SettingsPageViewModel
|
||||
{
|
||||
public partial class SettingsPageViewModel
|
||||
{
|
||||
partial void OnDockPlacementChanged(DockPlacement value)
|
||||
{
|
||||
_settingsService.DockPlacement = value;
|
||||
}
|
||||
partial void OnLyricsScrollEasingTypeChanged(EasingType value)
|
||||
{
|
||||
_settingsService.LyricsScrollEasingType = value;
|
||||
}
|
||||
partial void OnLyricsScrollDurationChanged(int value)
|
||||
{
|
||||
_settingsService.LyricsScrollDuration = value;
|
||||
}
|
||||
partial void OnLyricsBackgroundThemeChanged(ElementTheme value)
|
||||
{
|
||||
_settingsService.LyricsBackgroundTheme = value;
|
||||
}
|
||||
partial void OnLyricsFontStrokeWidthChanged(int value)
|
||||
{
|
||||
_settingsService.LyricsFontStrokeWidth = value;
|
||||
}
|
||||
partial void OnIgnoreFullscreenWindowChanged(bool value)
|
||||
{
|
||||
_settingsService.IgnoreFullscreenWindow = value;
|
||||
}
|
||||
partial void OnSelectedTargetLanguageIndexChanged(int value)
|
||||
{
|
||||
_settingsService.SelectedTargetLanguageIndex = value;
|
||||
}
|
||||
partial void OnLibreTranslateServerChanged(string value)
|
||||
{
|
||||
_settingsService.LibreTranslateServer = value;
|
||||
}
|
||||
partial void OnLXMusicServerChanged(string value)
|
||||
{
|
||||
_settingsService.LXMusicServer = value;
|
||||
}
|
||||
partial void OnAutoStartWindowTypeChanged(AutoStartWindowType value)
|
||||
{
|
||||
_settingsService.AutoStartWindowType = value;
|
||||
}
|
||||
partial void OnAutoLockOnDesktopModeChanged(bool value)
|
||||
{
|
||||
_settingsService.AutoLockOnDesktopMode = value;
|
||||
}
|
||||
partial void OnCoverImageRadiusChanged(int value)
|
||||
{
|
||||
_settingsService.CoverImageRadius = value;
|
||||
}
|
||||
partial void OnCoverOverlayBlurAmountChanged(int value)
|
||||
{
|
||||
_settingsService.CoverOverlayBlurAmount = value;
|
||||
}
|
||||
partial void OnCoverAcrylicEffectAmountChanged(int value)
|
||||
{
|
||||
_settingsService.CoverAcrylicEffectAmount = value;
|
||||
}
|
||||
partial void OnCoverOverlayOpacityChanged(int value)
|
||||
{
|
||||
_settingsService.CoverOverlayOpacity = value;
|
||||
}
|
||||
partial void OnIsDynamicCoverOverlayEnabledChanged(bool value)
|
||||
{
|
||||
_settingsService.IsDynamicCoverOverlayEnabled = value;
|
||||
}
|
||||
partial void OnLanguageChanged(Enums.Language value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case Enums.Language.FollowSystem:
|
||||
ApplicationLanguages.PrimaryLanguageOverride = "";
|
||||
break;
|
||||
case Enums.Language.English:
|
||||
ApplicationLanguages.PrimaryLanguageOverride = "en-US";
|
||||
break;
|
||||
case Enums.Language.SimplifiedChinese:
|
||||
ApplicationLanguages.PrimaryLanguageOverride = "zh-CN";
|
||||
break;
|
||||
case Enums.Language.TraditionalChinese:
|
||||
ApplicationLanguages.PrimaryLanguageOverride = "zh-TW";
|
||||
break;
|
||||
case Enums.Language.Japanese:
|
||||
ApplicationLanguages.PrimaryLanguageOverride = "ja-JP";
|
||||
break;
|
||||
case Enums.Language.Korean:
|
||||
ApplicationLanguages.PrimaryLanguageOverride = "ko-KR";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
_settingsService.Language = Language;
|
||||
}
|
||||
partial void OnIsFanLyricsEnabledChanged(bool value)
|
||||
{
|
||||
_settingsService.IsFanLyricsEnabled = value;
|
||||
}
|
||||
partial void OnIsLyricsGlowEffectEnabledChanged(bool value)
|
||||
{
|
||||
_settingsService.IsLyricsGlowEffectEnabled = value;
|
||||
}
|
||||
partial void OnLyricsAlignmentTypeChanged(TextAlignmentType value)
|
||||
{
|
||||
_settingsService.LyricsAlignmentType = value;
|
||||
}
|
||||
partial void OnSongInfoAlignmentTypeChanged(TextAlignmentType value)
|
||||
{
|
||||
_settingsService.SongInfoAlignmentType = value;
|
||||
}
|
||||
partial void OnLyricsBlurAmountChanged(int value)
|
||||
{
|
||||
_settingsService.LyricsBlurAmount = value;
|
||||
}
|
||||
partial void OnLyricsCustomBgFontColorChanged(Color value)
|
||||
{
|
||||
_settingsService.LyricsCustomBgFontColor = value;
|
||||
}
|
||||
partial void OnLyricsCustomFgFontColorChanged(Color value)
|
||||
{
|
||||
_settingsService.LyricsCustomFgFontColor = value;
|
||||
}
|
||||
partial void OnLyricsCustomStrokeFontColorChanged(Color value)
|
||||
{
|
||||
_settingsService.LyricsCustomStrokeFontColor = value;
|
||||
}
|
||||
partial void OnLyricsBgFontColorTypeChanged(LyricsFontColorType value)
|
||||
{
|
||||
_settingsService.LyricsBgFontColorType = value;
|
||||
}
|
||||
partial void OnLyricsFgFontColorTypeChanged(LyricsFontColorType value)
|
||||
{
|
||||
_settingsService.LyricsFgFontColorType = value;
|
||||
}
|
||||
partial void OnLyricsStrokeFontColorTypeChanged(LyricsFontColorType value)
|
||||
{
|
||||
_settingsService.LyricsStrokeFontColorType = value;
|
||||
}
|
||||
partial void OnLyricsStandardFontSizeChanged(int value)
|
||||
{
|
||||
_settingsService.LyricsStandardFontSize = value;
|
||||
}
|
||||
partial void OnLyricsDockFontSizeChanged(int value)
|
||||
{
|
||||
_settingsService.LyricsDockFontSize = value;
|
||||
}
|
||||
partial void OnLyricsDesktopFontSizeChanged(int value)
|
||||
{
|
||||
_settingsService.LyricsDesktopFontSize = value;
|
||||
}
|
||||
partial void OnLyricsFontWeightChanged(LyricsFontWeight value)
|
||||
{
|
||||
_settingsService.LyricsFontWeight = value;
|
||||
}
|
||||
partial void OnLyricsGlowEffectScopeChanged(LineRenderingType value)
|
||||
{
|
||||
_settingsService.LyricsGlowEffectScope = value;
|
||||
}
|
||||
partial void OnLyricsHighlightScopeChanged(LineRenderingType value)
|
||||
{
|
||||
_settingsService.LyricsHighlightScope = value;
|
||||
}
|
||||
partial void OnLyricsLineSpacingFactorChanged(float value)
|
||||
{
|
||||
_settingsService.LyricsLineSpacingFactor = value;
|
||||
}
|
||||
partial void OnLyricsVerticalEdgeOpacityChanged(int value)
|
||||
{
|
||||
_settingsService.LyricsVerticalEdgeOpacity = value;
|
||||
}
|
||||
partial void OnIsLyricsFloatAnimationEnabledChanged(bool value)
|
||||
{
|
||||
_settingsService.IsLyricsFloatAnimationEnabled = value;
|
||||
}
|
||||
partial void OnLyricsBgFontOpacityChanged(int value)
|
||||
{
|
||||
_settingsService.LyricsBgFontOpacity = value;
|
||||
}
|
||||
partial void OnHideWindowWhenNotPlayingChanged(bool value)
|
||||
{
|
||||
_settingsService.HideWindowWhenNotPlaying = value;
|
||||
}
|
||||
partial void OnDockWindowHeightChanged(int value)
|
||||
{
|
||||
_settingsService.DockWindowHeight = value;
|
||||
}
|
||||
partial void OnSelectedFontFamilyIndexChanged(int value)
|
||||
{
|
||||
_settingsService.SelectedFontFamilyIndex = value;
|
||||
LyricsFontFamily = SystemFontNames[value];
|
||||
}
|
||||
partial void OnLyricsFontFamilyChanged(string value)
|
||||
{
|
||||
_settingsService.LyricsFontFamily = value;
|
||||
}
|
||||
partial void OnIsDragEverywhereEnabledChanged(bool value)
|
||||
{
|
||||
_settingsService.IsDragEverywhereEnabled = value;
|
||||
|
||||
LyricsWindow? lyricsWindow = WindowHelper.GetWindowByWindowType<LyricsWindow>();
|
||||
if (lyricsWindow != null)
|
||||
{
|
||||
lyricsWindow.UpdateTitleBarArea();
|
||||
}
|
||||
}
|
||||
partial void OnIsLibreTranslateEnabledChanged(bool value)
|
||||
{
|
||||
_settingsService.IsLibreTranslateEnabled = value;
|
||||
}
|
||||
partial void OnSelectedDockMonitorDeviceNameChanged(string value)
|
||||
{
|
||||
_settingsService.DockMonitorDeviceName = value;
|
||||
}
|
||||
partial void OnLyricsTranslationSeparatorChanged(string value)
|
||||
{
|
||||
_settingsService.LyricsTranslationSeparator = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,248 +0,0 @@
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Hqub.Lastfm.Entities;
|
||||
using Microsoft.UI.Xaml;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.UI;
|
||||
|
||||
namespace BetterLyrics.WinUI3.ViewModels.SettingsPageViewModel
|
||||
{
|
||||
public partial class SettingsPageViewModel
|
||||
{
|
||||
public string Version { get; set; } = MetadataHelper.AppVersion;
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial bool IsLibreTranslateEnabled { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial bool IsDragEverywhereEnabled { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial string LyricsFontFamily { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial ObservableCollection<string> SystemFontNames { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial int SelectedFontFamilyIndex { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial DockPlacement DockPlacement { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial int LockHotKeyIndex { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial ElementTheme LyricsBackgroundTheme { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial AutoStartWindowType AutoStartWindowType { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial bool AutoLockOnDesktopMode { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial int CoverImageRadius { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial int CoverOverlayBlurAmount { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial int CoverOverlayOpacity { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial bool IsDebugOverlayEnabled { get; set; } = false;
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial bool IsLogEnabled { get; set; } = false;
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial bool IsDynamicCoverOverlayEnabled { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial int CoverAcrylicEffectAmount { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial Enums.Language Language { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial ObservableCollection<LocalMediaFolder> LocalMediaFolders { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial ObservableCollection<AlbumArtSearchProviderInfo> AlbumArtSearchProvidersInfo { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial ObservableCollection<MediaSourceProviderInfo> MediaSourceProvidersInfo { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial MediaSourceProviderInfo? SelectedMediaSourceProvider { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial bool IsFanLyricsEnabled { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial bool IsLyricsGlowEffectEnabled { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial TextAlignmentType LyricsAlignmentType { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial TextAlignmentType SongInfoAlignmentType { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial int LyricsBlurAmount { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial Color LyricsCustomBgFontColor { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial Color LyricsCustomFgFontColor { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial Color LyricsCustomStrokeFontColor { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial int LyricsBgFontOpacity { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial LyricsFontColorType LyricsBgFontColorType { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial LyricsFontColorType LyricsFgFontColorType { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial LyricsFontColorType LyricsStrokeFontColorType { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial int LyricsStandardFontSize { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial int LyricsDockFontSize { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial int LyricsDesktopFontSize { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial LyricsFontWeight LyricsFontWeight { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial LineRenderingType LyricsGlowEffectScope { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial LineRenderingType LyricsHighlightScope { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial float LyricsLineSpacingFactor { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial int LyricsVerticalEdgeOpacity { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial object NavViewSelectedItemTag { get; set; } = "App";
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial bool IsLyricsFloatAnimationEnabled { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial string LibreTranslateServer { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial int SelectedTargetLanguageIndex { get; set; } = 0;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial bool IsLibreTranslateServerTesting { get; set; } = false;
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial int LyricsFontStrokeWidth { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial bool IgnoreFullscreenWindow { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial EasingType LyricsScrollEasingType { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial int LyricsScrollDuration { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial bool IsLXMusicServerTesting { get; set; } = false;
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial string LXMusicServer { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial bool HideWindowWhenNotPlaying { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial int DockWindowHeight { get; set; }
|
||||
|
||||
// Dock Monitor
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial string SelectedDockMonitorDeviceName { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial ObservableCollection<string> MonitorDeviceNames { get; set; }
|
||||
|
||||
// LastFM
|
||||
[ObservableProperty]
|
||||
public partial bool IsLastFMAuthenticated { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial User? LastFMUser { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial string LyricsTranslationSeparator { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,270 +0,0 @@
|
||||
// 2025/6/23 by Zhe Fang
|
||||
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.Services;
|
||||
using BetterLyrics.WinUI3.Services.LastFMService;
|
||||
using BetterLyrics.WinUI3.Services.LibWatcherService;
|
||||
using BetterLyrics.WinUI3.Services.MediaSessionsService;
|
||||
using BetterLyrics.WinUI3.Services.TranslateService;
|
||||
using BetterLyrics.WinUI3.Views;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using CommunityToolkit.WinUI;
|
||||
using Microsoft.UI.Dispatching;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.ApplicationModel;
|
||||
using WinRT.Interop;
|
||||
|
||||
namespace BetterLyrics.WinUI3.ViewModels.SettingsPageViewModel
|
||||
{
|
||||
public partial class SettingsPageViewModel : BaseViewModel
|
||||
{
|
||||
private readonly ILibWatcherService _libWatcherService;
|
||||
private readonly IMediaSessionsService _mediaSessionsService;
|
||||
private readonly ITranslateService _libreTranslateService;
|
||||
private readonly ILastFMService _lastFMService;
|
||||
|
||||
private void MediaSessionsService_SessionIdsChanged(object? sender, Events.MediaSourceProvidersInfoEventArgs e)
|
||||
{
|
||||
MediaSourceProvidersInfo = [.. e.MediaSourceProviersInfo];
|
||||
}
|
||||
|
||||
public void OnLyricsSearchProvidersReordered()
|
||||
{
|
||||
_settingsService.MediaSourceProvidersInfo = [.. MediaSourceProvidersInfo];
|
||||
Broadcast(
|
||||
MediaSourceProvidersInfo,
|
||||
MediaSourceProvidersInfo,
|
||||
nameof(MediaSourceProvidersInfo)
|
||||
);
|
||||
}
|
||||
|
||||
public void OnAlbumArtSearchProvidersReordered()
|
||||
{
|
||||
_settingsService.AlbumArtSearchProvidersInfo = [.. AlbumArtSearchProvidersInfo];
|
||||
Broadcast(
|
||||
AlbumArtSearchProvidersInfo,
|
||||
AlbumArtSearchProvidersInfo,
|
||||
nameof(AlbumArtSearchProvidersInfo)
|
||||
);
|
||||
}
|
||||
|
||||
public void RemoveFolderAsync(LocalMediaFolder folder)
|
||||
{
|
||||
LocalMediaFolders.Remove(folder);
|
||||
_settingsService.LocalMediaFolders = [.. LocalMediaFolders];
|
||||
_libWatcherService.UpdateWatchers([.. LocalMediaFolders]);
|
||||
Broadcast(LocalMediaFolders, LocalMediaFolders, nameof(LocalMediaFolders));
|
||||
}
|
||||
|
||||
public void ToggleLocalLyricsFolder()
|
||||
{
|
||||
_settingsService.LocalMediaFolders = [.. LocalMediaFolders];
|
||||
Broadcast(LocalMediaFolders, LocalMediaFolders, nameof(LocalMediaFolders));
|
||||
}
|
||||
|
||||
public void ToggleAlbumArtSearchProvider(AlbumArtSearchProviderInfo providerInfo)
|
||||
{
|
||||
_settingsService.AlbumArtSearchProvidersInfo = [.. AlbumArtSearchProvidersInfo];
|
||||
Broadcast(
|
||||
AlbumArtSearchProvidersInfo,
|
||||
AlbumArtSearchProvidersInfo,
|
||||
nameof(AlbumArtSearchProvidersInfo)
|
||||
);
|
||||
}
|
||||
|
||||
public void BroadcastMediaSourceProvidersInfoChanged()
|
||||
{
|
||||
_dispatcherQueueTimer.Debounce(() =>
|
||||
{
|
||||
_settingsService.MediaSourceProvidersInfo = [.. MediaSourceProvidersInfo];
|
||||
Broadcast(
|
||||
MediaSourceProvidersInfo,
|
||||
MediaSourceProvidersInfo,
|
||||
nameof(MediaSourceProvidersInfo)
|
||||
);
|
||||
}, TimeSpan.FromMilliseconds(100));
|
||||
}
|
||||
|
||||
private void AddFolderAsync(string path)
|
||||
{
|
||||
var normalizedPath = Path.GetFullPath(path).TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar;
|
||||
|
||||
if (LocalMediaFolders.Any(x => Path.GetFullPath(x.Path).TrimEnd(Path.DirectorySeparatorChar).Equals(normalizedPath.TrimEnd(Path.DirectorySeparatorChar), StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
App.Current.SettingsWindowNotificationPanel?.Notify(App.ResourceLoader!.GetString("SettingsPagePathExistedInfo"), InfoBarSeverity.Warning);
|
||||
}
|
||||
else if (LocalMediaFolders.Any(item => normalizedPath.StartsWith(Path.GetFullPath(item.Path).TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
// 添加的文件夹是现有文件夹的子文件夹
|
||||
App.Current.SettingsWindowNotificationPanel?.Notify(App.ResourceLoader!.GetString("SettingsPagePathBeIncludedInfo"), InfoBarSeverity.Warning);
|
||||
}
|
||||
else if (LocalMediaFolders.Any(item => Path.GetFullPath(item.Path).TrimEnd(Path.DirectorySeparatorChar).StartsWith(normalizedPath, StringComparison.OrdinalIgnoreCase))
|
||||
)
|
||||
{
|
||||
// 添加的文件夹是现有文件夹的父文件夹
|
||||
App.Current.SettingsWindowNotificationPanel?.Notify(App.ResourceLoader!.GetString("SettingsPagePathIncludingOthersInfo"), InfoBarSeverity.Warning);
|
||||
}
|
||||
else
|
||||
{
|
||||
LocalMediaFolders.Add(new LocalMediaFolder(path, true));
|
||||
_settingsService.LocalMediaFolders = [.. LocalMediaFolders];
|
||||
_libWatcherService.UpdateWatchers([.. LocalMediaFolders]);
|
||||
Broadcast(LocalMediaFolders, LocalMediaFolders, nameof(LocalMediaFolders));
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task LaunchProjectGitHubPageAsync()
|
||||
{
|
||||
await Windows.System.Launcher.LaunchUriAsync(new Uri(Constants.Link.GithubUrl));
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private static async Task OpenCacheFolderAsync()
|
||||
{
|
||||
await Windows.System.Launcher.LaunchFolderPathAsync(Helper.PathHelper.CacheFolder);
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private static void RestartApp()
|
||||
{
|
||||
Helper.WindowHelper.RestartApp();
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task SelectAndAddFolderAsync(UIElement sender)
|
||||
{
|
||||
var window = Helper.WindowHelper.GetWindowByWindowType<SettingsWindow>();
|
||||
if (window == null) return;
|
||||
|
||||
var picker = new Windows.Storage.Pickers.FolderPicker();
|
||||
picker.FileTypeFilter.Add("*");
|
||||
|
||||
var hwnd = WindowNative.GetWindowHandle(window);
|
||||
InitializeWithWindow.Initialize(picker, hwnd);
|
||||
|
||||
var folder = await picker.PickSingleFolderAsync();
|
||||
|
||||
if (folder != null)
|
||||
{
|
||||
AddFolderAsync(folder.Path);
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void LibreTranslateServerTest()
|
||||
{
|
||||
IsLibreTranslateServerTesting = true;
|
||||
Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
string targetLangCode = LanguageHelper.SupportedTargetLanguages[SelectedTargetLanguageIndex].Code;
|
||||
string result = await _libreTranslateService.TranslateTextAsync("Hello, world!", targetLangCode, null);
|
||||
_dispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, () =>
|
||||
{
|
||||
App.Current.SettingsWindowNotificationPanel?.Notify(App.ResourceLoader!.GetString("SettingsPageServerTestSuccessInfo"), InfoBarSeverity.Success);
|
||||
});
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
_dispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, () =>
|
||||
{
|
||||
App.Current.SettingsWindowNotificationPanel?.Notify(App.ResourceLoader!.GetString("SettingsPageServerTestFailedInfo"), InfoBarSeverity.Error);
|
||||
});
|
||||
}
|
||||
_dispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, () =>
|
||||
{
|
||||
IsLibreTranslateServerTesting = false;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void LXMusicServerTest()
|
||||
{
|
||||
IsLXMusicServerTesting = true;
|
||||
Task.Run(async () =>
|
||||
{
|
||||
bool testResult = await NetHelper.CheckConnectivity($"{LXMusicServer}/status");
|
||||
_dispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, () =>
|
||||
{
|
||||
if (testResult)
|
||||
{
|
||||
App.Current.SettingsWindowNotificationPanel?.Notify(App.ResourceLoader!.GetString("SettingsPageServerTestSuccessInfo"), InfoBarSeverity.Success);
|
||||
}
|
||||
else
|
||||
{
|
||||
App.Current.SettingsWindowNotificationPanel?.Notify(App.ResourceLoader!.GetString("SettingsPageServerTestFailedInfo"), InfoBarSeverity.Error);
|
||||
}
|
||||
IsLXMusicServerTesting = false;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void RefreshMonitorDeviceNames()
|
||||
{
|
||||
MonitorDeviceNames = [.. MonitorHelper.GetAllMonitorDeviceNames()];
|
||||
SelectedDockMonitorDeviceName = MonitorHelper.GetPrimaryMonitorDeviceName();
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task LastFMAuthAsync()
|
||||
{
|
||||
await _lastFMService.AuthAsync();
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task LastFMUnAuthAsync()
|
||||
{
|
||||
await _lastFMService.UnAuthAsync();
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task LastFMRefreshAsync()
|
||||
{
|
||||
await _lastFMService.RefreshAsync();
|
||||
}
|
||||
|
||||
public async Task<bool> ToggleAutoStartupAsync(bool target)
|
||||
{
|
||||
StartupTask startupTask = await StartupTask.GetAsync(Constants.App.AutoStartupTaskId);
|
||||
if (target)
|
||||
{
|
||||
await startupTask.RequestEnableAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
startupTask.Disable();
|
||||
}
|
||||
return await DetectIsAutoStartupEnabledAsync();
|
||||
}
|
||||
|
||||
public async Task<bool> DetectIsAutoStartupEnabledAsync()
|
||||
{
|
||||
bool result = false;
|
||||
var startupTask = await StartupTask.GetAsync(Constants.App.AutoStartupTaskId);
|
||||
switch (startupTask.State)
|
||||
{
|
||||
case StartupTaskState.Disabled:
|
||||
case StartupTaskState.DisabledByUser:
|
||||
case StartupTaskState.DisabledByPolicy:
|
||||
result = false;
|
||||
break;
|
||||
case StartupTaskState.Enabled:
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace BetterLyrics.WinUI3.ViewModels
|
||||
{
|
||||
public partial class SettingsWindowViewModel(ISettingsService settingsService) : BaseWindowViewModel(settingsService)
|
||||
public partial class SettingsWindowViewModel : BaseWindowViewModel
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,10 @@ using WinUIEx;
|
||||
|
||||
namespace BetterLyrics.WinUI3.ViewModels
|
||||
{
|
||||
public partial class SystemTrayViewModel(ISettingsService settingsService) : BaseViewModel(settingsService), IRecipient<PropertyChangedMessage<bool>>
|
||||
public partial class SystemTrayViewModel(ISettingsService settingsService) : BaseViewModel, IRecipient<PropertyChangedMessage<bool>>
|
||||
{
|
||||
private readonly ISettingsService _settingsService = settingsService;
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedRecipients]
|
||||
public partial bool IsLyricsWindowLocked { get; set; } = false;
|
||||
|
||||
@@ -220,37 +220,29 @@
|
||||
|
||||
<!-- Lyrics & Translation -->
|
||||
<Button
|
||||
Click="TranslationButton_Click"
|
||||
Click="PlaybackSettingsShortcutButton_Click"
|
||||
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}"
|
||||
Glyph=}"
|
||||
Style="{StaticResource GhostButtonStyle}">
|
||||
<ToolTipService.ToolTip>
|
||||
<ToolTip x:Name="TranslationToolTip" x:Uid="LyricsPageTranslationButtonToolTip" />
|
||||
<ToolTip x:Uid="LyricsPagePlaybackSourceButtonToolTip" />
|
||||
</ToolTipService.ToolTip>
|
||||
<Button.ContextFlyout>
|
||||
<Flyout x:Name="TranslationFlyout" ShouldConstrainToRootBounds="False">
|
||||
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
|
||||
<controls:SettingsExpander
|
||||
x:Uid="LyricsPageTranslationEnabled"
|
||||
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}"
|
||||
IsExpanded="True">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.IsTranslationEnabled, Mode=TwoWay}" />
|
||||
<controls:SettingsExpander.Items>
|
||||
<controls:SettingsCard x:Uid="LyricsPageTranslationOnly" IsEnabled="{x:Bind ViewModel.IsTranslationEnabled, Mode=OneWay}">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.ShowTranslationOnly, Mode=TwoWay}" />
|
||||
</controls:SettingsCard>
|
||||
</controls:SettingsExpander.Items>
|
||||
</controls:SettingsExpander>
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<TextBlock x:Uid="LyricsPageLyricsProviderPrefix" Foreground="{ThemeResource TextFillColorSecondaryBrush}" />
|
||||
<TextBlock Foreground="{ThemeResource TextFillColorSecondaryBrush}" Text="{x:Bind ViewModel.LyricsSearchProvider, Mode=OneWay, Converter={StaticResource LyricsSearchProviderToDisplayNameConverter}}" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<TextBlock x:Uid="LyricsPageTranslationProviderPrefix" Foreground="{ThemeResource TextFillColorSecondaryBrush}" />
|
||||
<TextBlock Foreground="{ThemeResource TextFillColorSecondaryBrush}" Text="{x:Bind ViewModel.TranslationSearchProvider, Mode=OneWay, Converter={StaticResource TranslationSearchProviderToDisplayNameConverter}}" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
<Flyout
|
||||
x:Name="PlaybackSettingsFlyout"
|
||||
Placement="Right"
|
||||
ShouldConstrainToRootBounds="False">
|
||||
<Flyout.FlyoutPresenterStyle>
|
||||
<Style TargetType="FlyoutPresenter">
|
||||
<Setter Property="MinWidth" Value="850" />
|
||||
<Setter Property="Padding" Value="0" />
|
||||
<Setter Property="CornerRadius" Value="12" />
|
||||
<Setter Property="ScrollViewer.VerticalScrollMode" Value="Disabled" />
|
||||
<Setter Property="ScrollViewer.HorizontalScrollMode" Value="Disabled" />
|
||||
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Hidden" />
|
||||
</Style>
|
||||
</Flyout.FlyoutPresenterStyle>
|
||||
<uc:PlaybackSettingsControl MaxWidth="850" MaxHeight="500" />
|
||||
</Flyout>
|
||||
</Button.ContextFlyout>
|
||||
</Button>
|
||||
@@ -352,13 +344,6 @@
|
||||
</Grid.ContextFlyout>
|
||||
</Grid>
|
||||
|
||||
<TeachingTip
|
||||
x:Name="WelcomeTeachingTip"
|
||||
x:Uid="MainPageWelcomeTeachingTip"
|
||||
Closed="WelcomeTeachingTip_Closed"
|
||||
IsOpen="{x:Bind ViewModel.IsWelcomeTeachingTipOpen, Mode=OneWay}"
|
||||
Target="{x:Bind RootGrid}" />
|
||||
|
||||
<uc:SystemTray />
|
||||
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// 2025/6/23 by Zhe Fang
|
||||
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using BetterLyrics.WinUI3.Models.Settings;
|
||||
using BetterLyrics.WinUI3.Services.MediaSessionsService;
|
||||
using BetterLyrics.WinUI3.Services.SettingsService;
|
||||
using BetterLyrics.WinUI3.ViewModels;
|
||||
@@ -28,27 +29,22 @@ namespace BetterLyrics.WinUI3.Views
|
||||
DataContext = Ioc.Default.GetRequiredService<LyricsPageViewModel>();
|
||||
}
|
||||
|
||||
private void WelcomeTeachingTip_Closed(TeachingTip sender, TeachingTipClosedEventArgs args)
|
||||
{
|
||||
ViewModel.IsFirstRun = false;
|
||||
}
|
||||
|
||||
private void LyricsOnlyRadioButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ViewModel.DisplayType = LyricsDisplayType.LyricsOnly;
|
||||
_settingsService.DisplayType = ViewModel.DisplayType;
|
||||
_settingsService.AppSettings.GeneralSettings.DisplayType = ViewModel.DisplayType;
|
||||
}
|
||||
|
||||
private void AlbumArtOnlyRadioButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ViewModel.DisplayType = LyricsDisplayType.AlbumArtOnly;
|
||||
_settingsService.DisplayType = ViewModel.DisplayType;
|
||||
_settingsService.AppSettings.GeneralSettings.DisplayType = ViewModel.DisplayType;
|
||||
}
|
||||
|
||||
private void SplitViewRadioButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ViewModel.DisplayType = LyricsDisplayType.SplitView;
|
||||
_settingsService.DisplayType = ViewModel.DisplayType;
|
||||
_settingsService.AppSettings.GeneralSettings.DisplayType = ViewModel.DisplayType;
|
||||
}
|
||||
|
||||
private void BottomCommandGrid_PointerEntered(object sender, Microsoft.UI.Xaml.Input.PointerRoutedEventArgs e)
|
||||
@@ -74,9 +70,9 @@ namespace BetterLyrics.WinUI3.Views
|
||||
DisplayTypeSwitchFlyout.ShowAt(BottomRightCommandStackPanel);
|
||||
}
|
||||
|
||||
private void TranslationButton_Click(object sender, RoutedEventArgs e)
|
||||
private void PlaybackSettingsShortcutButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
TranslationFlyout.ShowAt(BottomRightCommandStackPanel);
|
||||
PlaybackSettingsFlyout.ShowAt(BottomRightCommandStackPanel);
|
||||
}
|
||||
|
||||
private void RootGrid_SizeChanged(object sender, SizeChangedEventArgs e)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user