mirror of
https://github.com/jayfunc/BetterLyrics.git
synced 2026-01-12 10:54:55 +08:00
Compare commits
142 Commits
v1.0.119.0
...
v1.1.175.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2f627d7531 | ||
|
|
caed76e9b9 | ||
|
|
a74dc705c9 | ||
|
|
21eb8fcf9c | ||
|
|
4662d3d54d | ||
|
|
b10f108f93 | ||
|
|
2defe620c7 | ||
|
|
315c10c83c | ||
|
|
981bc3f933 | ||
|
|
88460899bd | ||
|
|
8341642658 | ||
|
|
26f4ff3a58 | ||
|
|
b1b763c6fe | ||
|
|
28323c39f6 | ||
|
|
b099965715 | ||
|
|
8f9fdc18bb | ||
|
|
5a549bd5f5 | ||
|
|
48e94f275b | ||
|
|
691071d725 | ||
|
|
591c1a6d00 | ||
|
|
4e6a2df2cb | ||
|
|
8b196e45a4 | ||
|
|
0ddeaef126 | ||
|
|
e3747c113a | ||
|
|
1b1449ce3b | ||
|
|
ea246a96be | ||
|
|
28722d325a | ||
|
|
7238713ff5 | ||
|
|
66c42f81f2 | ||
|
|
3e6ba725d2 | ||
|
|
ffb0c58a58 | ||
|
|
3b61f568d0 | ||
|
|
b925a10d69 | ||
|
|
720f4b311e | ||
|
|
6c03002051 | ||
|
|
9cebd56bd5 | ||
|
|
f0a4c1251d | ||
|
|
a8418d4234 | ||
|
|
53abc4526c | ||
|
|
4d3b982904 | ||
|
|
5faace562d | ||
|
|
290b7f38b4 | ||
|
|
6f02a1a46c | ||
|
|
4f74e48cfb | ||
|
|
06f08558cc | ||
|
|
a2b21ed3d5 | ||
|
|
4cb1ca0bb3 | ||
|
|
81ed341e47 | ||
|
|
a9f92f4cb7 | ||
|
|
62719ed513 | ||
|
|
c9bd7725d0 | ||
|
|
b60952916c | ||
|
|
ec0917b6c8 | ||
|
|
583fa106ce | ||
|
|
88488e4813 | ||
|
|
6e65310b6d | ||
|
|
22bd7c2252 | ||
|
|
5c50bd569a | ||
|
|
401c33003c | ||
|
|
664451c530 | ||
|
|
657c81add5 | ||
|
|
1dd63ab9ba | ||
|
|
0a9b9bf484 | ||
|
|
794079f20b | ||
|
|
be9a67f57d | ||
|
|
5b5d62d688 | ||
|
|
dfe428645e | ||
|
|
8e2c977a44 | ||
|
|
47806c924d | ||
|
|
bbda1cd797 | ||
|
|
2099332f02 | ||
|
|
016d9a626f | ||
|
|
cff6f202d6 | ||
|
|
f643f86567 | ||
|
|
e9b50c84ac | ||
|
|
4c590bcf6f | ||
|
|
68a1c6a465 | ||
|
|
f46364a491 | ||
|
|
75f047e389 | ||
|
|
1cb21b1373 | ||
|
|
4592be10e8 | ||
|
|
c0217150c1 | ||
|
|
0705bde0e2 | ||
|
|
3f5122c93f | ||
|
|
97f061d887 | ||
|
|
77525a62ff | ||
|
|
ad473bbd1d | ||
|
|
b1126026c2 | ||
|
|
2f84155e6e | ||
|
|
1769167811 | ||
|
|
551da8c0b0 | ||
|
|
a5b3671ce3 | ||
|
|
181a06c932 | ||
|
|
93d567e21d | ||
|
|
9da8510de6 | ||
|
|
3ed9e599be | ||
|
|
e277faea9e | ||
|
|
21dcd7de4b | ||
|
|
31540beaa0 | ||
|
|
63ffe6b661 | ||
|
|
5cb880021c | ||
|
|
b00f2b5865 | ||
|
|
90a75f1b96 | ||
|
|
735f03542f | ||
|
|
b7853ded26 | ||
|
|
88fc0adbec | ||
|
|
a3366422a2 | ||
|
|
8f6e106282 | ||
|
|
08d4f4ce90 | ||
|
|
212041a509 | ||
|
|
c0f2b4106a | ||
|
|
c704edde19 | ||
|
|
35de1ef7db | ||
|
|
1c8840e053 | ||
|
|
2d0839d777 | ||
|
|
7e6ce08c56 | ||
|
|
28f75fa751 | ||
|
|
051a7af21a | ||
|
|
c8b8853561 | ||
|
|
baab2bcc7a | ||
|
|
9a3e4adc0c | ||
|
|
8d909da139 | ||
|
|
d97f5fec37 | ||
|
|
9a12b06b7e | ||
|
|
3fca90ca72 | ||
|
|
220e940bbb | ||
|
|
dc627bd1ef | ||
|
|
3c852a9d2f | ||
|
|
ecff788c6c | ||
|
|
c471f128c1 | ||
|
|
4a389d5e33 | ||
|
|
ae1fa1c54d | ||
|
|
738a4a0bec | ||
|
|
37ae278a11 | ||
|
|
45094bde31 | ||
|
|
81b6ebbdf6 | ||
|
|
8cb8a026ad | ||
|
|
4eeaf9aeec | ||
|
|
f7f5e127a0 | ||
|
|
b44a29997b | ||
|
|
f19888223e | ||
|
|
a612e9c6cb |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -407,3 +407,4 @@ FodyWeavers.xsd
|
||||
*.sln.iml
|
||||
/BetterLyrics.WinUI3/BetterLyrics.WinUI3 (Package)/BetterLyrics.WinUI3 (Package)_TemporaryKey.pfx
|
||||
/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Constants/LastFM.cs
|
||||
/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Constants/Discord.cs
|
||||
|
||||
@@ -143,8 +143,8 @@
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.6584" />
|
||||
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.8.251003001" />
|
||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.7175" />
|
||||
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.8.251106002" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(WapProjPath)\Microsoft.DesktopBridge.targets" />
|
||||
</Project>
|
||||
@@ -12,7 +12,7 @@
|
||||
<Identity
|
||||
Name="37412.BetterLyrics"
|
||||
Publisher="CN=E1428B0E-DC1D-4EA4-ACB1-4556569D5BA9"
|
||||
Version="1.0.119.0" />
|
||||
Version="1.1.175.0" />
|
||||
|
||||
<mp:PhoneIdentity PhoneProductId="ca4a4830-fc19-40d9-b823-53e2bff3d816" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
|
||||
|
||||
|
||||
@@ -50,11 +50,10 @@
|
||||
<converter:CornerRadiusToDoubleConverter x:Key="CornerRadiusToDoubleConverter" />
|
||||
<converter:LyricsSearchProviderToDisplayNameConverter x:Key="LyricsSearchProviderToDisplayNameConverter" />
|
||||
<converter:TranslationSearchProviderToDisplayNameConverter x:Key="TranslationSearchProviderToDisplayNameConverter" />
|
||||
<converter:TransliterationSearchProviderToDisplayNameConverter x:Key="TransliterationSearchProviderToDisplayNameConverter" />
|
||||
<converter:AlbumArtSearchProviderToDisplayNameConverter x:Key="AlbumArtSearchProviderToDisplayNameConverter" />
|
||||
<converter:SecondsToFormattedTimeConverter x:Key="SecondsToFormattedTimeConverter" />
|
||||
<converter:MillisecondsToFormattedTimeConverter x:Key="MillisecondsToFormattedTimeConverter" />
|
||||
<converter:MediaSourceProviderToLogoUriConverter x:Key="MediaSourceProviderToLogoUriConverter" />
|
||||
<converter:MediaSourceProviderToDisplayedNameConverter x:Key="MediaSourceProviderToDisplayedNameConverter" />
|
||||
<converter:FPSToTimeSpanConverter x:Key="FPSToTimeSpanConverter" />
|
||||
<converter:ShortcutToStringConverter x:Key="ShortcutToStringConverter" />
|
||||
<converter:BoolNegationToVisibilityConverter x:Key="BoolNegationToVisibilityConverter" />
|
||||
@@ -69,6 +68,13 @@
|
||||
<converter:TrackToLyricsConverter x:Key="TrackToLyricsConverter" />
|
||||
<converter:IntToBoolConverter x:Key="IntToBoolConverter" />
|
||||
<converter:IndexToDisplayConverter x:Key="IndexToDisplayConverter" />
|
||||
<converter:IntToDoubleConverter x:Key="IntToDoubleConverter" />
|
||||
<converter:MillisecondsToSecondsConverter x:Key="MillisecondsToSecondsConverter" />
|
||||
<converter:PictureInfosToImageSourceConverter x:Key="PictureInfosToImageSourceConverter" />
|
||||
<converter:LyricsFontWeightToFontWeightConverter x:Key="LyricsFontWeightToFontWeightConverter" />
|
||||
<converter:TextAlignmentTypeToHorizontalAlignmentConverter x:Key="TextAlignmentTypeToHorizontalAlignmentConverter" />
|
||||
<converter:LyricsLayoutOrientationToOrientationConverter x:Key="LyricsLayoutOrientationToOrientationConverter" />
|
||||
<converter:LyricsLayoutOrientationNegationToOrientationConverter x:Key="LyricsLayoutOrientationNegationToOrientationConverter" />
|
||||
|
||||
<converters:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
|
||||
<converters:BoolNegationConverter x:Key="BoolNegationConverter" />
|
||||
@@ -90,8 +96,7 @@
|
||||
<Setter Property="VerticalAlignment" Value="Top" />
|
||||
<Setter Property="CornerRadius" Value="4" />
|
||||
<Setter Property="BorderThickness" Value="0" />
|
||||
<Setter Property="Padding" Value="16,9,16,11" />
|
||||
<Setter Property="Margin" Value="0" />
|
||||
<Setter Property="Padding" Value="14,6,14,9" />
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
</Style>
|
||||
<Style x:Key="GhostButtonStyle" TargetType="Button">
|
||||
@@ -105,10 +110,10 @@
|
||||
x:Key="TitleBarToggleButtonStyle"
|
||||
BasedOn="{StaticResource ToggleButtonRevealStyle}"
|
||||
TargetType="ToggleButton">
|
||||
<Setter Property="VerticalAlignment" Value="Top" />
|
||||
<Setter Property="CornerRadius" Value="4" />
|
||||
<Setter Property="VerticalAlignment" Value="Stretch" />
|
||||
<Setter Property="BorderThickness" Value="0" />
|
||||
<Setter Property="Padding" Value="16,9,16,11" />
|
||||
<Setter Property="Padding" Value="14,6,14,9" />
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
</Style>
|
||||
<Style x:Key="GhostToggleButtonStyle" TargetType="ToggleButton">
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
// 2025/6/23 by Zhe Fang
|
||||
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using BetterLyrics.WinUI3.Hooks;
|
||||
using BetterLyrics.WinUI3.Services.AlbumArtSearchService;
|
||||
using BetterLyrics.WinUI3.Services.DiscordService;
|
||||
using BetterLyrics.WinUI3.Services.LastFMService;
|
||||
using BetterLyrics.WinUI3.Services.LibWatcherService;
|
||||
using BetterLyrics.WinUI3.Services.LiveStatesService;
|
||||
using BetterLyrics.WinUI3.Services.LyricsSearchService;
|
||||
using BetterLyrics.WinUI3.Services.MediaSessionsService;
|
||||
using BetterLyrics.WinUI3.Services.ResourceService;
|
||||
using BetterLyrics.WinUI3.Services.SettingsService;
|
||||
using BetterLyrics.WinUI3.Services.TranslateService;
|
||||
using BetterLyrics.WinUI3.ViewModels;
|
||||
using BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel;
|
||||
using BetterLyrics.WinUI3.Views;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
@@ -20,6 +20,7 @@ using Microsoft.UI.Xaml;
|
||||
using Microsoft.Windows.ApplicationModel.Resources;
|
||||
using Serilog;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -67,10 +68,28 @@ namespace BetterLyrics.WinUI3
|
||||
|
||||
protected override void OnLaunched(LaunchActivatedEventArgs args)
|
||||
{
|
||||
WindowHelper.OpenOrShowWindow<LyricsWindow>();
|
||||
if (Ioc.Default.GetRequiredService<ISettingsService>().AppSettings.MusicGallerySettings.AutoOpen)
|
||||
var settingsService = Ioc.Default.GetRequiredService<ISettingsService>();
|
||||
|
||||
WindowHook.OpenOrShowWindow<SystemTrayWindow>();
|
||||
|
||||
if (settingsService.AppSettings.GeneralSettings.AutoStartLyricsWindow)
|
||||
{
|
||||
WindowHelper.OpenOrShowWindow<MusicGalleryWindow>();
|
||||
var defaultStatus = settingsService.AppSettings.WindowBoundsRecords.Where(x => x.IsDefault);
|
||||
if (defaultStatus != null)
|
||||
{
|
||||
foreach (var item in defaultStatus)
|
||||
{
|
||||
WindowHook.OpenOrShowWindow<NowPlayingWindow>(item);
|
||||
if (!settingsService.AppSettings.GeneralSettings.MultiNowPlayingWindowMode)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (settingsService.AppSettings.MusicGallerySettings.AutoOpen)
|
||||
{
|
||||
WindowHook.OpenOrShowWindow<MusicGalleryWindow>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,7 +109,6 @@ namespace BetterLyrics.WinUI3
|
||||
loggingBuilder.AddSerilog();
|
||||
})
|
||||
// Services
|
||||
.AddSingleton<ILiveStatesService, LiveStatesService>()
|
||||
.AddSingleton<ISettingsService, SettingsService>()
|
||||
.AddSingleton<IMediaSessionsService, MediaSessionsService>()
|
||||
.AddSingleton<IAlbumArtSearchService, AlbumArtSearchService>()
|
||||
@@ -99,6 +117,7 @@ namespace BetterLyrics.WinUI3
|
||||
.AddSingleton<ITranslateService, TranslateService>()
|
||||
.AddSingleton<ILastFMService, LastFMService>()
|
||||
.AddSingleton<IResourceService, ResourceService>()
|
||||
.AddSingleton<IDiscordService, DiscordService>()
|
||||
// ViewModels
|
||||
.AddSingleton<AppSettingsControlViewModel>()
|
||||
.AddSingleton<PlaybackSettingsControlViewModel>()
|
||||
@@ -107,14 +126,17 @@ namespace BetterLyrics.WinUI3
|
||||
.AddSingleton<LyricsWindowSettingsControlViewModel>()
|
||||
.AddSingleton<LyricsWindowSwitchControlViewModel>()
|
||||
.AddSingleton<LyricsWindowSwitchWindowViewModel>()
|
||||
.AddSingleton<LyricsWindowViewModel>()
|
||||
.AddSingleton<SettingsWindowViewModel>()
|
||||
.AddSingleton<SystemTrayViewModel>()
|
||||
.AddSingleton<SettingsPageViewModel>()
|
||||
.AddSingleton<LyricsPageViewModel>()
|
||||
.AddSingleton<MusicGalleryViewModel>()
|
||||
.AddSingleton<LyricsRendererViewModel>()
|
||||
.AddSingleton<MusicGalleryPageViewModel>()
|
||||
.AddSingleton<AboutControlViewModel>()
|
||||
.AddSingleton<MusicGalleryWindowViewModel>()
|
||||
|
||||
.AddTransient<NowPlayingWindowViewModel>()
|
||||
.AddTransient<NowPlayingPageViewModel>()
|
||||
.AddTransient<NowPlayingBarViewModel>()
|
||||
|
||||
.BuildServiceProvider()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -23,24 +23,29 @@
|
||||
<None Remove="Assets\Segoe Fluent Icons.ttf" />
|
||||
<None Remove="Assets\Wiki82.profile.xml" />
|
||||
<None Remove="Controls\AboutControl.xaml" />
|
||||
<None Remove="Controls\AlbumArtLayoutSettingsControl.xaml" />
|
||||
<None Remove="Controls\AlbumArtAreaEffectSettingsControl.xaml" />
|
||||
<None Remove="Controls\AppSettingsControl.xaml" />
|
||||
<None Remove="Controls\DemoWindowGrid.xaml" />
|
||||
<None Remove="Controls\ExtendedSlider.xaml" />
|
||||
<None Remove="Controls\FontFamilyAutoSuggestBox.xaml" />
|
||||
<None Remove="Controls\ImageSwitcher.xaml" />
|
||||
<None Remove="Controls\LyricsSearchControl.xaml" />
|
||||
<None Remove="Controls\LyricsStyleSettingsControl.xaml" />
|
||||
<None Remove="Controls\LyricsWindowSettingsControl.xaml" />
|
||||
<None Remove="Controls\LyricsWindowSwitchControl.xaml" />
|
||||
<None Remove="Controls\MediaSettingsControl.xaml" />
|
||||
<None Remove="Controls\NowPlayingBar.xaml" />
|
||||
<None Remove="Controls\PlaybackSettingsControl.xaml" />
|
||||
<None Remove="Controls\PropertyRow.xaml" />
|
||||
<None Remove="Controls\ShortcutTextBox.xaml" />
|
||||
<None Remove="Controls\SystemTray.xaml" />
|
||||
<None Remove="Controls\WindowSettingsControl.xaml" />
|
||||
<None Remove="Views\LyricsSearchWindow.xaml" />
|
||||
<None Remove="Views\LyricsWindowSwitchWindow.xaml" />
|
||||
<None Remove="Views\MusicGalleryPage.xaml" />
|
||||
<None Remove="Views\MusicGalleryWindow.xaml" />
|
||||
<None Remove="Views\SettingsWindow.xaml" />
|
||||
<None Remove="Views\SystemTrayWindow.xaml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Logo.ico" />
|
||||
@@ -61,34 +66,38 @@
|
||||
<PackageReference Include="CommunityToolkit.WinUI.Helpers" Version="8.2.250402" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.Media" Version="8.2.250402" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.Triggers" Version="8.2.250402" />
|
||||
<PackageReference Include="ComputeSharp.D2D1.WinUI" Version="3.2.0" />
|
||||
<PackageReference Include="csharp-kana" Version="1.0.2" />
|
||||
<PackageReference Include="csharp-pinyin" Version="1.0.1" />
|
||||
<PackageReference Include="DevWinUI.Controls" Version="9.4.2" />
|
||||
<PackageReference Include="DevWinUI.Controls" Version="9.7.0" />
|
||||
<PackageReference Include="Dubya.WindowsMediaController" Version="2.5.5" />
|
||||
<PackageReference Include="H.NotifyIcon.WinUI" Version="2.3.2" />
|
||||
<PackageReference Include="F23.StringSimilarity" Version="7.0.1" />
|
||||
<PackageReference Include="H.NotifyIcon.WinUI" Version="2.4.1" />
|
||||
<PackageReference Include="Hqub.Last.fm" Version="2.5.1" />
|
||||
<PackageReference Include="Lyricify.Lyrics.Helper-NativeAot" Version="0.1.4-alpha.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.10" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.10" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="10.0.0" />
|
||||
<PackageReference Include="Microsoft.Graphics.Win2D" Version="1.3.2" />
|
||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.6901" />
|
||||
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.8.251003001" />
|
||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.7175" />
|
||||
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.8.251106002" />
|
||||
<PackageReference Include="NAudio.Wasapi" Version="2.2.1" />
|
||||
<PackageReference Include="Nito.AsyncEx" Version="5.1.2" />
|
||||
<PackageReference Include="Nito.AsyncEx.Tasks" Version="5.1.2" />
|
||||
<PackageReference Include="NTextCat" Version="0.3.65" />
|
||||
<PackageReference Include="Serilog.Extensions.Logging" Version="9.0.3-dev-02320" />
|
||||
<PackageReference Include="Serilog.Extensions.Logging" Version="10.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="7.0.0" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="9.0.10" />
|
||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="9.0.10" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="10.0.0" />
|
||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="10.0.0" />
|
||||
<PackageReference Include="TagLibSharp" Version="2.3.0" />
|
||||
<PackageReference Include="Ude.NetStandard" Version="1.2.0" />
|
||||
<PackageReference Include="Vanara.PInvoke.DwmApi" Version="4.2.1" />
|
||||
<PackageReference Include="Vanara.PInvoke.Gdi32" Version="4.2.1" />
|
||||
<PackageReference Include="Vanara.PInvoke.Shell32" Version="4.2.1" />
|
||||
<PackageReference Include="Vanara.PInvoke.User32" Version="4.2.1" />
|
||||
<PackageReference Include="Vanara.Windows.Shell" Version="4.2.1" />
|
||||
<PackageReference Include="VCollab.DiscordRichPresence" Version="1.7.0" />
|
||||
<PackageReference Include="WinUIEx" Version="2.9.0" />
|
||||
<PackageReference Include="z440.atl.core" Version="7.6.0" />
|
||||
<PackageReference Include="z440.atl.core" Version="7.9.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\ColorThief.WinUI3\ColorThief.WinUI3.csproj" />
|
||||
@@ -106,8 +115,13 @@
|
||||
</ItemGroup>
|
||||
<!--Disable Trimming for Specific Packages-->
|
||||
<ItemGroup>
|
||||
<TrimmerRootAssembly Include="TagLibSharp" />
|
||||
<TrimmerRootAssembly Include="NAudio.Wasapi" />
|
||||
<TrimmerRootAssembly Include="TagLibSharp" />
|
||||
<TrimmerRootAssembly Include="Vanara.PInvoke.DwmApi" />
|
||||
<TrimmerRootAssembly Include="Vanara.PInvoke.Gdi32" />
|
||||
<TrimmerRootAssembly Include="Vanara.PInvoke.Shell32" />
|
||||
<TrimmerRootAssembly Include="Vanara.PInvoke.User32" />
|
||||
<TrimmerRootAssembly Include="Vanara.Windows.Shell" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Update="Assets\AIMP.png">
|
||||
@@ -116,6 +130,9 @@
|
||||
<Content Update="Assets\AlbumArtPlaceholder.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\Alipay.jpg">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\AMLLPlayer.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
@@ -206,6 +223,9 @@
|
||||
<Content Update="Assets\Spotify.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\WeChatReward.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\Wiki82.profile.xml">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
@@ -276,7 +296,7 @@
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\AlbumArtLayoutSettingsControl.xaml">
|
||||
<Page Update="Controls\AlbumArtAreaStyleSettingsControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
@@ -318,6 +338,41 @@
|
||||
<ItemGroup>
|
||||
<Folder Include="TemplateSelector\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\NowPlayingBar.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Views\SystemTrayWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\WindowSettingsControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\AlbumArtAreaEffectSettingsControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\ImageSwitcher.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\ShadowImage.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\PropertyRow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\AboutControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
|
||||
@@ -4,7 +4,7 @@ using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Extensions
|
||||
namespace BetterLyrics.WinUI3.Collections
|
||||
{
|
||||
// https://stackoverflow.com/a/32013610/11048731
|
||||
public class FullyObservableCollection<T> : ObservableCollection<T>
|
||||
@@ -2,8 +2,8 @@
|
||||
{
|
||||
public static class AmllTTmlDB
|
||||
{
|
||||
private const string BaseUrl = "https://raw.githubusercontent.com/Steve-xmh/amll-ttml-db/refs/heads/main/";
|
||||
public const string QueryPrefix = $"{BaseUrl}raw-lyrics/";
|
||||
public const string Index = $"{BaseUrl}metadata/raw-lyrics-index.jsonl";
|
||||
public const string BaseUrl = "https://raw.githubusercontent.com/Steve-xmh/amll-ttml-db/refs/heads/main";
|
||||
public const string QueryPrefix = "raw-lyrics";
|
||||
public const string IndexSuffix = "metadata/raw-lyrics-index.jsonl";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
public static class App
|
||||
{
|
||||
public const string AppAuthor = "Zhe Fang";
|
||||
public const string AppAuthorNicknameEN = "jayfunc";
|
||||
public const string AppAuthorNicknameZH = "摘叶飞镖";
|
||||
public const string AppName = "BetterLyrics";
|
||||
|
||||
public const string AutoStartupTaskId = "AutoStartup";
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace BetterLyrics.WinUI3.Constants
|
||||
{
|
||||
class Discord
|
||||
{
|
||||
public const string AppID = "Your Discord app ID here";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace BetterLyrics.WinUI3.Constants
|
||||
{
|
||||
public class ExtendedGenreFiled
|
||||
{
|
||||
public const string NetEaseCloudMusicTrackID = "NCM-";
|
||||
public const string QQMusicTrackID = "QQ-";
|
||||
public const string FileName = "FILENAME-";
|
||||
}
|
||||
}
|
||||
@@ -2,13 +2,25 @@
|
||||
{
|
||||
public static class Link
|
||||
{
|
||||
public const string GitHubUrl = "https://github.com/jayfunc/BetterLyrics";
|
||||
public const string ShareHubUrl = $"{GitHubUrl}/blob/dev/ShareHub/index.md";
|
||||
public const string WikiUrl = $"{GitHubUrl}/wiki";
|
||||
public const string AppleMusicCfgUrl = $"{WikiUrl}/%5BEN%5D-Lyrics-provider-configuration#apple-music";
|
||||
public const string FAQUrl = $"{GitHubUrl}/blob/dev/FAQ/index.md";
|
||||
public const string QQGroupUrl = "https://qun.qq.com/universal-share/share?ac=1&authKey=4Q%2BYTq3wZldYpF5SbS5c19ECFsiYoLZFAIcBNNzYpBUtiEjaZ8sZ%2F%2BnFN0qw3lad&busi_data=eyJncm91cENvZGUiOiIxMDU0NzAwMzg4IiwidG9rZW4iOiJiVnhqemVYN0N5QVc3b1ZkR24wWmZOTUtvUkJoWm1JRWlaWW5iZnlBcXJtZUtGc2FFTHNlUlFZMi9iRm03cWF5IiwidWluIjoiMTM5NTczOTY2MCJ9&data=39UmAihyH_o6CZaOs7nk2mO_lz2ruODoDou6pxxh7utcxP4WF5sbDBDOPvZ_Wqfzeey4441anegsLYQJxkrBAA&svctype=4&tempid=h5_group_info";
|
||||
public const string DiscordUrl = "https://discord.gg/5yAQPnyCKv";
|
||||
public const string TelegramUrl = "https://t.me/+svhSLZ7awPsxNGY1";
|
||||
public const string MicrosoftStore = "https://apps.microsoft.com/detail/9p1wcd1p597r";
|
||||
|
||||
public const string AuthorGitHub = "https://github.com/jayfunc";
|
||||
|
||||
public const string BetterLyricsGitHub = $"{AuthorGitHub}/BetterLyrics";
|
||||
|
||||
public const string ShareHub = $"{BetterLyricsGitHub}/blob/dev/ShareHub/index.md";
|
||||
public const string TermsOfService = $"{BetterLyricsGitHub}/blob/dev/TermsofService.md";
|
||||
public const string PrivacyPolicy = $"{BetterLyricsGitHub}/blob/dev/PrivacyPolicy.md";
|
||||
public const string UserGuide = $"{BetterLyricsGitHub}/wiki/User-Guide";
|
||||
|
||||
public const string AppleMusicCfg = $"{UserGuide}#lyrics-source-configuration";
|
||||
|
||||
public const string QQGroup = "https://qun.qq.com/universal-share/share?ac=1&authKey=4Q%2BYTq3wZldYpF5SbS5c19ECFsiYoLZFAIcBNNzYpBUtiEjaZ8sZ%2F%2BnFN0qw3lad&busi_data=eyJncm91cENvZGUiOiIxMDU0NzAwMzg4IiwidG9rZW4iOiJiVnhqemVYN0N5QVc3b1ZkR24wWmZOTUtvUkJoWm1JRWlaWW5iZnlBcXJtZUtGc2FFTHNlUlFZMi9iRm03cWF5IiwidWluIjoiMTM5NTczOTY2MCJ9&data=39UmAihyH_o6CZaOs7nk2mO_lz2ruODoDou6pxxh7utcxP4WF5sbDBDOPvZ_Wqfzeey4441anegsLYQJxkrBAA&svctype=4&tempid=h5_group_info";
|
||||
public const string Discord = "https://discord.gg/5yAQPnyCKv";
|
||||
public const string Telegram = "https://t.me/+svhSLZ7awPsxNGY1";
|
||||
|
||||
public const string BuyMeACoffee = "https://buymeacoffee.com/founchoo";
|
||||
public const string PayPal = "https://paypal.me/zhefangpay";
|
||||
public const string Afdian = "https://afdian.com/a/jayfunc";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,8 @@
|
||||
public const string Edge = "MSEdge";
|
||||
public const string BetterLyrics = "37412.BetterLyrics_rd1g0rsrrtxw8!App";
|
||||
public const string BetterLyricsDebug = "37412.BetterLyrics_c8mj3v9sysxb4!App";
|
||||
public const string SaltPlayerForWindows = "Sakawish.SaltPlayerforWindows_q65q631pyh094!SaltPlayerforWindows";
|
||||
public const string SaltPlayerForWindowsMS = "Sakawish.SaltPlayerforWindows_q65q631pyh094!SaltPlayerforWindows";
|
||||
public const string SaltPlayerForWindowsSteam = "Salt Player for Windows.exe";
|
||||
public const string MoeKoeMusic = "cn.MoeKoe.Music";
|
||||
public const string MoeKoeMusicAlternative = "electron.app.MoeKoe Music";
|
||||
public const string Listen1 = "com.listen1.listen1";
|
||||
|
||||
@@ -20,7 +20,8 @@
|
||||
public const string Edge = "Microsoft Edge";
|
||||
public const string BetterLyrics = "BetterLyrics";
|
||||
public const string BetterLyricsDebug = "BetterLyrics (Debug)";
|
||||
public const string SaltPlayerForWindows = "Salt Player for Windows";
|
||||
public const string SaltPlayerForWindowsMS = "Salt Player for Windows (Microsoft Store)";
|
||||
public const string SaltPlayerForWindowsSteam = "Salt Player for Windows (Steam)";
|
||||
public const string MoeKoeMusic = "MoeKoe Music";
|
||||
public const string Listen1 = "Listen 1";
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace BetterLyrics.WinUI3.Constants
|
||||
{
|
||||
public static class Time
|
||||
{
|
||||
public static readonly TimeSpan DebounceTimeout = TimeSpan.FromMilliseconds(300);
|
||||
public static readonly TimeSpan DebounceTimeout = TimeSpan.FromMilliseconds(250);
|
||||
public static readonly TimeSpan AnimationDuration = TimeSpan.FromMilliseconds(350);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,32 +28,40 @@
|
||||
</StackPanel>
|
||||
</dev:SettingsExpander.Header>
|
||||
<dev:SettingsExpander.Description>
|
||||
<StackPanel
|
||||
Margin="0,2,0,0"
|
||||
Orientation="Horizontal"
|
||||
Spacing="2">
|
||||
<TextBlock Text="©" />
|
||||
<HyperlinkButton
|
||||
Margin="0,-1,0,0"
|
||||
Content="Zhe Fang"
|
||||
NavigateUri="https://github.com/jayfunc" />
|
||||
<TextBlock Text="2025" />
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<StackPanel
|
||||
Margin="0,2,0,0"
|
||||
Orientation="Horizontal"
|
||||
Spacing="2">
|
||||
<TextBlock Text="©" />
|
||||
<HyperlinkButton
|
||||
Margin="0,-1,0,0"
|
||||
Content="{x:Bind const:App.AppAuthor}"
|
||||
NavigateUri="https://github.com/jayfunc" />
|
||||
<TextBlock Text="2025" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</dev:SettingsExpander.Description>
|
||||
<RichTextBlock Foreground="{ThemeResource TextFillColorSecondaryBrush}">
|
||||
<Paragraph>
|
||||
<Run x:Uid="SettingsPageVersion" />
|
||||
<Run Text="{x:Bind helper:MetadataHelper.AppVersion}" />
|
||||
</Paragraph>
|
||||
</RichTextBlock>
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<RichTextBlock
|
||||
Margin="0,-1,0,0"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}">
|
||||
<Paragraph>
|
||||
<Run x:Uid="SettingsPageVersion" />
|
||||
<Run Text="{x:Bind helper:MetadataHelper.AppVersion}" />
|
||||
</Paragraph>
|
||||
</RichTextBlock>
|
||||
</StackPanel>
|
||||
<dev:SettingsExpander.Items>
|
||||
|
||||
<dev:SettingsCard HorizontalContentAlignment="Left" ContentAlignment="Left">
|
||||
<StackPanel Spacing="6">
|
||||
<TextBlock x:Uid="SetingsPageInstructions" />
|
||||
<StackPanel Margin="-12,0,0,0" Orientation="Horizontal">
|
||||
<HyperlinkButton Content="GitHub" NavigateUri="{x:Bind const:Link.GitHubUrl}" />
|
||||
<HyperlinkButton Content="Wiki" NavigateUri="{x:Bind const:Link.WikiUrl}" />
|
||||
<HyperlinkButton Content="GitHub" NavigateUri="{x:Bind const:Link.BetterLyricsGitHub}" />
|
||||
<HyperlinkButton x:Uid="UserGuide" NavigateUri="{x:Bind const:Link.UserGuide}" />
|
||||
<HyperlinkButton x:Uid="PrivacyPolicy" NavigateUri="{x:Bind const:Link.PrivacyPolicy}" />
|
||||
<HyperlinkButton x:Uid="TermsOfService" NavigateUri="{x:Bind const:Link.TermsOfService}" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
|
||||
@@ -63,9 +71,9 @@
|
||||
<StackPanel Spacing="6">
|
||||
<TextBlock x:Uid="SetingsPageFeedback" />
|
||||
<StackPanel Margin="-12,0,0,0" Orientation="Horizontal">
|
||||
<HyperlinkButton x:Uid="SettingsPageQQGroup" NavigateUri="{x:Bind const:Link.QQGroupUrl}" />
|
||||
<HyperlinkButton x:Uid="SettingsPageDiscord" NavigateUri="{x:Bind const:Link.DiscordUrl}" />
|
||||
<HyperlinkButton x:Uid="SettingsPageTelegram" NavigateUri="{x:Bind const:Link.TelegramUrl}" />
|
||||
<HyperlinkButton x:Uid="SettingsPageQQGroup" NavigateUri="{x:Bind const:Link.QQGroup}" />
|
||||
<HyperlinkButton x:Uid="SettingsPageDiscord" NavigateUri="{x:Bind const:Link.Discord}" />
|
||||
<HyperlinkButton x:Uid="SettingsPageTelegram" NavigateUri="{x:Bind const:Link.Telegram}" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</dev:SettingsCard>
|
||||
@@ -74,14 +82,14 @@
|
||||
<StackPanel Spacing="6">
|
||||
<TextBlock x:Uid="SetingsPageDonation" />
|
||||
<StackPanel Margin="-12,0,0,0" Orientation="Horizontal">
|
||||
<HyperlinkButton Content="Buy Me a Coffee" NavigateUri="https://buymeacoffee.com/founchoo" />
|
||||
<HyperlinkButton Content="PayPal" NavigateUri="https://paypal.me/zhefangpay" />
|
||||
<Button
|
||||
Content="支付宝"
|
||||
Foreground="{ThemeResource AccentTextFillColorPrimaryBrush}"
|
||||
Style="{StaticResource GhostButtonStyle}">
|
||||
<Button.Flyout>
|
||||
<Flyout>
|
||||
<HyperlinkButton Content="Buy Me a Coffee" NavigateUri="{x:Bind const:Link.BuyMeACoffee}" />
|
||||
<HyperlinkButton Content="PayPal" NavigateUri="{x:Bind const:Link.PayPal}" />
|
||||
<HyperlinkButton
|
||||
x:Name="AlipayButton"
|
||||
Click="AlipayButton_Click"
|
||||
Content="支付宝">
|
||||
<HyperlinkButton.ContextFlyout>
|
||||
<Flyout x:Name="AlipayFlyout">
|
||||
<Flyout.FlyoutPresenterStyle>
|
||||
<Style TargetType="FlyoutPresenter">
|
||||
<Setter Property="CornerRadius" Value="12" />
|
||||
@@ -90,14 +98,14 @@
|
||||
</Flyout.FlyoutPresenterStyle>
|
||||
<Image Height="300" Source="/Assets/Alipay.jpg" />
|
||||
</Flyout>
|
||||
</Button.Flyout>
|
||||
</Button>
|
||||
<Button
|
||||
Content="微信"
|
||||
Foreground="{ThemeResource AccentTextFillColorPrimaryBrush}"
|
||||
Style="{StaticResource GhostButtonStyle}">
|
||||
<Button.Flyout>
|
||||
<Flyout>
|
||||
</HyperlinkButton.ContextFlyout>
|
||||
</HyperlinkButton>
|
||||
<HyperlinkButton
|
||||
x:Name="WeChatButton"
|
||||
Click="WeChat_Click"
|
||||
Content="微信">
|
||||
<HyperlinkButton.ContextFlyout>
|
||||
<Flyout x:Name="WeChatFlyout">
|
||||
<Flyout.FlyoutPresenterStyle>
|
||||
<Style TargetType="FlyoutPresenter">
|
||||
<Setter Property="CornerRadius" Value="12" />
|
||||
@@ -106,8 +114,9 @@
|
||||
</Flyout.FlyoutPresenterStyle>
|
||||
<Image Height="300" Source="/Assets/WeChatReward.png" />
|
||||
</Flyout>
|
||||
</Button.Flyout>
|
||||
</Button>
|
||||
</HyperlinkButton.ContextFlyout>
|
||||
</HyperlinkButton>
|
||||
<HyperlinkButton Content="爱发电" NavigateUri="{x:Bind const:Link.Afdian}" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<TextBlock Foreground="{ThemeResource TextFillColorSecondaryBrush}" Text="*" />
|
||||
@@ -119,16 +128,13 @@
|
||||
</StackPanel>
|
||||
</dev:SettingsCard>
|
||||
|
||||
<dev:SettingsCard HorizontalContentAlignment="Left" ContentAlignment="Left">
|
||||
<StackPanel Spacing="6">
|
||||
<TextBlock x:Uid="SetingsPageContributors" />
|
||||
<StackPanel Margin="-12,0,0,0" Orientation="Horizontal">
|
||||
<HyperlinkButton Content="jayfunc" NavigateUri="https://github.com/jayfunc" />
|
||||
<HyperlinkButton Content="Raspberry-Monster" NavigateUri="https://github.com/Raspberry-Monster" />
|
||||
<HyperlinkButton Content="ZHider" NavigateUri="https://github.com/ZHider" />
|
||||
<HyperlinkButton Content="kusutori" NavigateUri="https://github.com/kusutori" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
<dev:SettingsCard x:Uid="SettingsPageThanksList">
|
||||
<Button
|
||||
Click="Patron_Click"
|
||||
Content="{ui:FontIcon FontSize=16,
|
||||
FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}"
|
||||
Style="{StaticResource AccentButtonStyle}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
</dev:SettingsExpander.Items>
|
||||
@@ -176,10 +182,6 @@
|
||||
</dev:SettingsExpander.ItemsHeader>
|
||||
</dev:SettingsExpander>
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageDebugOverlay">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.IsDebugOverlayEnabled, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageFixedTimeStep" Visibility="Collapsed">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.AdvancedSettings.IsFixedTimeStep, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
@@ -197,5 +199,327 @@
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
|
||||
<Grid
|
||||
x:Name="CreditsReel"
|
||||
Background="{ThemeResource AcrylicInAppFillColorDefaultBrush}"
|
||||
Opacity="0"
|
||||
SizeChanged="CreditsReel_SizeChanged"
|
||||
Tapped="CreditsReel_Tapped"
|
||||
Visibility="Collapsed">
|
||||
<Grid.OpacityTransition>
|
||||
<ScalarTransition />
|
||||
</Grid.OpacityTransition>
|
||||
<ScrollViewer
|
||||
x:Name="CreditsReelScrollViewer"
|
||||
ScrollViewer.VerticalScrollBarVisibility="Hidden"
|
||||
ScrollViewer.VerticalScrollMode="Disabled">
|
||||
<RichTextBlock
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalTextAlignment="Center"
|
||||
LineHeight="28"
|
||||
PointerEntered="RichTextBlock_PointerEntered"
|
||||
PointerExited="RichTextBlock_PointerExited">
|
||||
|
||||
<Paragraph x:Name="CreditsReelHeader" />
|
||||
|
||||
<!-- 贡献者 -->
|
||||
<Paragraph Margin="0,20,0,0" FontWeight="Bold">
|
||||
<Run x:Uid="SetingsPageContributors" />
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Hyperlink NavigateUri="https://github.com/jayfunc">
|
||||
<Run Text="jayfunc" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Hyperlink NavigateUri="https://github.com/Raspberry-Monster">
|
||||
<Run Text="Raspberry-Monster" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Hyperlink NavigateUri="https://github.com/ZHider">
|
||||
<Run Text="ZHider" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Hyperlink NavigateUri="https://github.com/kusutori">
|
||||
<Run Text="kusutori" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
|
||||
<!-- 打赏者 -->
|
||||
<Paragraph Margin="0,20,0,0" FontWeight="Bold">
|
||||
<Run x:Uid="SettingsPagePatrons" />
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Run Text="YE" />
|
||||
<Run Foreground="{ThemeResource TextFillColorSecondaryBrush}" Text="Dec 3, 2025" />
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Run Text="**玄" />
|
||||
<Run Foreground="{ThemeResource TextFillColorSecondaryBrush}" Text="Nov 23, 2025" />
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Run Text="**智" />
|
||||
<Run Foreground="{ThemeResource TextFillColorSecondaryBrush}" Text="Nov 21, 2025" />
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Run Text="*鹤" />
|
||||
<Run Foreground="{ThemeResource TextFillColorSecondaryBrush}" Text="Nov 17, 2025" />
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Run Text="借过" />
|
||||
<Run Foreground="{ThemeResource TextFillColorSecondaryBrush}" Text="Nov 2, 2025" />
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Run Text="**华" />
|
||||
<Run Foreground="{ThemeResource TextFillColorSecondaryBrush}" Text="Aug 28, 2025" />
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Run x:Uid="SettingsPageYouNowUsing" FontStyle="Italic" />
|
||||
</Paragraph>
|
||||
|
||||
<!-- 依赖包 -->
|
||||
<Paragraph Margin="0,20,0,0" FontWeight="Bold">
|
||||
<Run x:Uid="SetingsPageDeps" />
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Hyperlink NavigateUri="https://www.nuget.org/packages/3v.EvtSource">
|
||||
<Run Text="3v.EvtSource" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Hyperlink NavigateUri="https://www.nuget.org/packages/CommunityToolkit.Labs.WinUI.Controls.OpacityMaskView">
|
||||
<Run Text="CommunityToolkit.Labs.WinUI.Controls.OpacityMaskView" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Hyperlink NavigateUri="https://www.nuget.org/packages/CommunityToolkit.Labs.WinUI.Shimmer">
|
||||
<Run Text="CommunityToolkit.Labs.WinUI.Shimmer" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Hyperlink NavigateUri="https://www.nuget.org/packages/CommunityToolkit.Mvvm">
|
||||
<Run Text="CommunityToolkit.Mvvm" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Hyperlink NavigateUri="https://www.nuget.org/packages/CommunityToolkit.WinUI.Behaviors">
|
||||
<Run Text="CommunityToolkit.WinUI.Behaviors" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Hyperlink NavigateUri="https://www.nuget.org/packages/CommunityToolkit.WinUI.Controls.Primitives">
|
||||
<Run Text="CommunityToolkit.WinUI.Controls.Primitives" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Hyperlink NavigateUri="https://www.nuget.org/packages/CommunityToolkit.WinUI.Controls.Segmented">
|
||||
<Run Text="CommunityToolkit.WinUI.Controls.Segmented" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Hyperlink NavigateUri="https://www.nuget.org/packages/CommunityToolkit.WinUI.Converters">
|
||||
<Run Text="CommunityToolkit.WinUI.Converters" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Hyperlink NavigateUri="https://www.nuget.org/packages/CommunityToolkit.WinUI.Extensions">
|
||||
<Run Text="CommunityToolkit.WinUI.Extensions" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Hyperlink NavigateUri="https://www.nuget.org/packages/CommunityToolkit.WinUI.Helpers">
|
||||
<Run Text="CommunityToolkit.WinUI.Helpers" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Hyperlink NavigateUri="https://www.nuget.org/packages/CommunityToolkit.WinUI.Media">
|
||||
<Run Text="CommunityToolkit.WinUI.Media" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Hyperlink NavigateUri="https://www.nuget.org/packages/CommunityToolkit.WinUI.Triggers">
|
||||
<Run Text="CommunityToolkit.WinUI.Triggers" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Hyperlink NavigateUri="https://www.nuget.org/packages/ComputeSharp.D2D1.WinUI">
|
||||
<Run Text="ComputeSharp.D2D1.WinUI" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Hyperlink NavigateUri="https://www.nuget.org/packages/csharp-kana">
|
||||
<Run Text="csharp-kana" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Hyperlink NavigateUri="https://www.nuget.org/packages/csharp-pinyin">
|
||||
<Run Text="csharp-pinyin" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Hyperlink NavigateUri="https://www.nuget.org/packages/DevWinUI.Controls">
|
||||
<Run Text="DevWinUI.Controls" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Hyperlink NavigateUri="https://www.nuget.org/packages/Dubya.WindowsMediaController">
|
||||
<Run Text="Dubya.WindowsMediaController" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Hyperlink NavigateUri="https://www.nuget.org/packages/F23.StringSimilarity">
|
||||
<Run Text="F23.StringSimilarity" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Hyperlink NavigateUri="https://www.nuget.org/packages/H.NotifyIcon.WinUI">
|
||||
<Run Text="H.NotifyIcon.WinUI" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Hyperlink NavigateUri="https://www.nuget.org/packages/Hqub.Last.fm">
|
||||
<Run Text="Hqub.Last.fm" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Hyperlink NavigateUri="https://www.nuget.org/packages/Lyricify.Lyrics.Helper-NativeAot">
|
||||
<Run Text="Lyricify.Lyrics.Helper-NativeAot" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Hyperlink NavigateUri="https://www.nuget.org/packages/Microsoft.Extensions.DependencyInjection">
|
||||
<Run Text="Microsoft.Extensions.DependencyInjection" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Hyperlink NavigateUri="https://www.nuget.org/packages/Microsoft.Extensions.Logging">
|
||||
<Run Text="Microsoft.Extensions.Logging" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Hyperlink NavigateUri="https://www.nuget.org/packages/Microsoft.Graphics.Win2D">
|
||||
<Run Text="Microsoft.Graphics.Win2D" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Hyperlink NavigateUri="https://www.nuget.org/packages/Microsoft.Windows.SDK.BuildTools">
|
||||
<Run Text="Microsoft.Windows.SDK.BuildTools" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Hyperlink NavigateUri="https://www.nuget.org/packages/Microsoft.WindowsAppSDK">
|
||||
<Run Text="Microsoft.WindowsAppSDK" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Hyperlink NavigateUri="https://www.nuget.org/packages/NAudio.Wasapi">
|
||||
<Run Text="NAudio.Wasapi" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Hyperlink NavigateUri="https://www.nuget.org/packages/Nito.AsyncEx">
|
||||
<Run Text="Nito.AsyncEx" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Hyperlink NavigateUri="https://www.nuget.org/packages/Nito.AsyncEx.Tasks">
|
||||
<Run Text="Nito.AsyncEx.Tasks" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Hyperlink NavigateUri="https://www.nuget.org/packages/NTextCat">
|
||||
<Run Text="NTextCat" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Hyperlink NavigateUri="https://www.nuget.org/packages/Serilog.Extensions.Logging">
|
||||
<Run Text="Serilog.Extensions.Logging" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Hyperlink NavigateUri="https://www.nuget.org/packages/Serilog.Sinks.File">
|
||||
<Run Text="Serilog.Sinks.File" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Hyperlink NavigateUri="https://www.nuget.org/packages/System.Drawing.Common">
|
||||
<Run Text="System.Drawing.Common" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Hyperlink NavigateUri="https://www.nuget.org/packages/System.Text.Encoding.CodePages">
|
||||
<Run Text="System.Text.Encoding.CodePages" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Hyperlink NavigateUri="https://www.nuget.org/packages/TagLibSharp">
|
||||
<Run Text="TagLibSharp" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Hyperlink NavigateUri="https://www.nuget.org/packages/Ude.NetStandard">
|
||||
<Run Text="Ude.NetStandard" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Hyperlink NavigateUri="https://www.nuget.org/packages/Vanara.PInvoke.DwmApi">
|
||||
<Run Text="Vanara.PInvoke.DwmApi" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Hyperlink NavigateUri="https://www.nuget.org/packages/Vanara.PInvoke.Gdi32">
|
||||
<Run Text="Vanara.PInvoke.Gdi32" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Hyperlink NavigateUri="https://www.nuget.org/packages/Vanara.PInvoke.Shell32">
|
||||
<Run Text="Vanara.PInvoke.Shell32" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Hyperlink NavigateUri="https://www.nuget.org/packages/Vanara.PInvoke.User32">
|
||||
<Run Text="Vanara.PInvoke.User32" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Hyperlink NavigateUri="https://www.nuget.org/packages/Vanara.Windows.Shell">
|
||||
<Run Text="Vanara.Windows.Shell" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Hyperlink NavigateUri="https://www.nuget.org/packages/VCollab.DiscordRichPresence">
|
||||
<Run Text="VCollab.DiscordRichPresence" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Hyperlink NavigateUri="https://www.nuget.org/packages/WinUIEx">
|
||||
<Run Text="WinUIEx" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Hyperlink NavigateUri="https://www.nuget.org/packages/z440.atl.core">
|
||||
<Run Text="z440.atl.core" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
|
||||
<Paragraph Margin="0,20,0,0" FontWeight="Bold">
|
||||
<Run Text="{x:Bind const:App.AppName}" />
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Run Text="Proudly built by" />
|
||||
<Hyperlink NavigateUri="{x:Bind const:Link.AuthorGitHub}">
|
||||
<Run Text="{x:Bind const:App.AppAuthor}" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
|
||||
<Paragraph x:Name="CreditsReelFooter" />
|
||||
|
||||
</RichTextBlock>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
using BetterLyrics.WinUI3.ViewModels;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.UI.ApplicationSettings;
|
||||
|
||||
// To learn more about WinUI, the WinUI project structure,
|
||||
// and more about our project templates, see: http://aka.ms/winui-project-info.
|
||||
@@ -9,6 +12,7 @@ namespace BetterLyrics.WinUI3.Controls
|
||||
{
|
||||
public sealed partial class AboutControl : UserControl
|
||||
{
|
||||
private bool _isCreditsScrolling = false;
|
||||
public AboutControlViewModel ViewModel => (AboutControlViewModel)DataContext;
|
||||
|
||||
public AboutControl()
|
||||
@@ -16,5 +20,56 @@ namespace BetterLyrics.WinUI3.Controls
|
||||
InitializeComponent();
|
||||
DataContext = Ioc.Default.GetRequiredService<AboutControlViewModel>();
|
||||
}
|
||||
|
||||
private async void Patron_Click(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
|
||||
{
|
||||
CompositionTarget.Rendering += CompositionTarget_Rendering;
|
||||
CreditsReel.Visibility = Microsoft.UI.Xaml.Visibility.Visible;
|
||||
CreditsReel.Opacity = 1;
|
||||
_isCreditsScrolling = true;
|
||||
}
|
||||
|
||||
private void CompositionTarget_Rendering(object? sender, object e)
|
||||
{
|
||||
if (_isCreditsScrolling)
|
||||
{
|
||||
CreditsReelScrollViewer.ChangeView(null, CreditsReelScrollViewer.VerticalOffset + 0.5, null);
|
||||
}
|
||||
}
|
||||
|
||||
private async void CreditsReel_Tapped(object sender, Microsoft.UI.Xaml.Input.TappedRoutedEventArgs e)
|
||||
{
|
||||
CreditsReel.Opacity = 0;
|
||||
await Task.Delay(Constants.Time.AnimationDuration);
|
||||
CreditsReel.Visibility = Microsoft.UI.Xaml.Visibility.Collapsed;
|
||||
CompositionTarget.Rendering -= CompositionTarget_Rendering;
|
||||
CreditsReelScrollViewer.ChangeView(null, 0, null);
|
||||
}
|
||||
|
||||
private void CreditsReel_SizeChanged(object sender, Microsoft.UI.Xaml.SizeChangedEventArgs e)
|
||||
{
|
||||
CreditsReelHeader.LineHeight = e.NewSize.Height;
|
||||
CreditsReelFooter.LineHeight = e.NewSize.Height / 2;
|
||||
}
|
||||
|
||||
private void RichTextBlock_PointerEntered(object sender, Microsoft.UI.Xaml.Input.PointerRoutedEventArgs e)
|
||||
{
|
||||
_isCreditsScrolling = false;
|
||||
}
|
||||
|
||||
private void RichTextBlock_PointerExited(object sender, Microsoft.UI.Xaml.Input.PointerRoutedEventArgs e)
|
||||
{
|
||||
_isCreditsScrolling = true;
|
||||
}
|
||||
|
||||
private void WeChat_Click(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
|
||||
{
|
||||
WeChatFlyout.ShowAt(WeChatButton);
|
||||
}
|
||||
|
||||
private void AlipayButton_Click(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
|
||||
{
|
||||
AlipayFlyout.ShowAt(AlipayButton);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<UserControl
|
||||
x:Class="BetterLyrics.WinUI3.Controls.AlbumArtAreaEffectSettingsControl"
|
||||
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:dev="using:DevWinUI"
|
||||
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="SettingsPageAlbumEffect" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageImageSwitchType" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ComboBox SelectedIndex="{x:Bind AlbumArtAreaEffectSettings.ImageSwitchType, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||
<ComboBoxItem x:Uid="SettingsPageCrossfade" />
|
||||
<ComboBoxItem x:Uid="SettingsPageSlide" />
|
||||
</ComboBox>
|
||||
</dev:SettingsCard>
|
||||
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,25 @@
|
||||
using BetterLyrics.WinUI3.Models.Settings;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
// 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 AlbumArtAreaEffectSettingsControl : UserControl
|
||||
{
|
||||
public static readonly DependencyProperty AlbumArtAreaEffectSettingsProperty =
|
||||
DependencyProperty.Register(nameof(AlbumArtAreaEffectSettings), typeof(AlbumArtAreaEffectSettings), typeof(AlbumArtAreaEffectSettingsControl), new PropertyMetadata(default));
|
||||
|
||||
public AlbumArtAreaEffectSettings AlbumArtAreaEffectSettings
|
||||
{
|
||||
get => (AlbumArtAreaEffectSettings)GetValue(AlbumArtAreaEffectSettingsProperty);
|
||||
set => SetValue(AlbumArtAreaEffectSettingsProperty, value);
|
||||
}
|
||||
|
||||
public AlbumArtAreaEffectSettingsControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<UserControl
|
||||
x:Class="BetterLyrics.WinUI3.Controls.AlbumArtLayoutSettingsControl"
|
||||
x:Class="BetterLyrics.WinUI3.Controls.AlbumArtAreaStyleSettingsControl"
|
||||
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:dev="using:DevWinUI"
|
||||
xmlns:local="using:BetterLyrics.WinUI3.Controls"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:dev="using:DevWinUI"
|
||||
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||
mc:Ignorable="d">
|
||||
|
||||
@@ -16,43 +16,52 @@
|
||||
<Grid Style="{StaticResource SettingsGridStyle}">
|
||||
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
|
||||
|
||||
<TextBlock x:Uid="SettingsPageAlbumStyle" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
|
||||
<!-- 整体对齐 -->
|
||||
<dev:SettingsCard x:Uid="SettingsPageAlignment" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ComboBox SelectedIndex="{x:Bind AlbumArtLayoutSettings.SongInfoAlignmentType, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||
<ComboBoxItem x:Uid="SettingsPageLeft" />
|
||||
<ComboBoxItem x:Uid="SettingsPageCenter" />
|
||||
<ComboBoxItem x:Uid="SettingsPageRight" />
|
||||
</ComboBox>
|
||||
</dev:SettingsCard>
|
||||
|
||||
<TextBlock x:Uid="SettingsPageAlbumArt" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
|
||||
<!-- 专辑高度 -->
|
||||
<dev:SettingsExpander
|
||||
x:Uid="SettingsPageAlbumArtSize"
|
||||
x:Uid="SettingsPageAlbumArtHeight"
|
||||
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}"
|
||||
Glyph=}"
|
||||
IsExpanded="True">
|
||||
<dev:SettingsExpander.Items>
|
||||
<dev:SettingsCard x:Uid="SettingsPageAutoAdjust">
|
||||
<ToggleSwitch IsOn="{x:Bind AlbumArtLayoutSettings.AutoAlbumArtSize, Mode=TwoWay}" />
|
||||
<ToggleSwitch IsOn="{x:Bind AlbumArtLayoutSettings.IsAutoCoverImageHeight, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
<dev:SettingsCard IsEnabled="{x:Bind AlbumArtLayoutSettings.AutoAlbumArtSize, Converter={StaticResource BoolNegationConverter}, Mode=OneWay}">
|
||||
<local:ExtendedSlider
|
||||
Frequency="2"
|
||||
Maximum="800"
|
||||
Minimum="10"
|
||||
ResetButtonVisibility="Collapsed"
|
||||
Unit="px"
|
||||
Value="{x:Bind AlbumArtLayoutSettings.AlbumArtSize, Mode=TwoWay}" />
|
||||
<dev:SettingsCard IsEnabled="{x:Bind AlbumArtLayoutSettings.IsAutoCoverImageHeight, Converter={StaticResource BoolNegationConverter}, Mode=OneWay}">
|
||||
<NumberBox
|
||||
Minimum="0"
|
||||
SpinButtonPlacementMode="Inline"
|
||||
Value="{x:Bind AlbumArtLayoutSettings.CoverImageHeight, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
</dev:SettingsExpander.Items>
|
||||
</dev:SettingsExpander>
|
||||
|
||||
<!-- 专辑圆角 -->
|
||||
<dev:SettingsCard x:Uid="SettingsPageAlbumRadius" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<local:ExtendedSlider
|
||||
Default="12"
|
||||
|
||||
Maximum="100"
|
||||
Minimum="0"
|
||||
Unit="%"
|
||||
Value="{x:Bind AlbumArtLayoutSettings.CoverImageRadius, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
<!-- 专辑阴影 -->
|
||||
<dev:SettingsCard x:Uid="SettingsPageAlbumShadowAmount" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<local:ExtendedSlider
|
||||
Default="12"
|
||||
|
||||
Maximum="64"
|
||||
Minimum="0"
|
||||
Value="{x:Bind AlbumArtLayoutSettings.CoverImageShadowAmount, Mode=TwoWay}" />
|
||||
@@ -60,14 +69,6 @@
|
||||
|
||||
<TextBlock x:Uid="SettingsPageSongInfo" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageSongInfoAlignment" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ComboBox SelectedIndex="{x:Bind AlbumArtLayoutSettings.SongInfoAlignmentType, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||
<ComboBoxItem x:Uid="SettingsPageSongInfoLeft" />
|
||||
<ComboBoxItem x:Uid="SettingsPageSongInfoCenter" />
|
||||
<ComboBoxItem x:Uid="SettingsPageSongInfoRight" />
|
||||
</ComboBox>
|
||||
</dev:SettingsCard>
|
||||
|
||||
<dev:SettingsExpander
|
||||
x:Uid="SettingsPageLyricsFontSize"
|
||||
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
@@ -89,21 +90,15 @@
|
||||
</dev:SettingsExpander.Items>
|
||||
</dev:SettingsExpander>
|
||||
|
||||
<dev:SettingsExpander
|
||||
x:Uid="SettingsPageShowTitle"
|
||||
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}"
|
||||
IsExpanded="True">
|
||||
<dev:SettingsCard x:Uid="SettingsPageShowTitle" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ToggleSwitch IsOn="{x:Bind AlbumArtLayoutSettings.ShowTitle, Mode=TwoWay}" />
|
||||
<dev:SettingsExpander.Items>
|
||||
<dev:SettingsCard x:Uid="SettingsPageShowArtists">
|
||||
<ToggleSwitch IsEnabled="{x:Bind AlbumArtLayoutSettings.ShowTitle, Mode=OneWay}" IsOn="{x:Bind AlbumArtLayoutSettings.ShowArtists, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
<dev:SettingsCard x:Uid="SettingsPageShowAlbum">
|
||||
<ToggleSwitch IsEnabled="{x:Bind AlbumArtLayoutSettings.ShowTitle, Mode=OneWay}" IsOn="{x:Bind AlbumArtLayoutSettings.ShowAlbum, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
</dev:SettingsExpander.Items>
|
||||
</dev:SettingsExpander>
|
||||
</dev:SettingsCard>
|
||||
<dev:SettingsCard x:Uid="SettingsPageShowArtists" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ToggleSwitch IsOn="{x:Bind AlbumArtLayoutSettings.ShowArtists, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
<dev:SettingsCard x:Uid="SettingsPageShowAlbum" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ToggleSwitch IsOn="{x:Bind AlbumArtLayoutSettings.ShowAlbum, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
@@ -7,18 +7,18 @@ using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Controls
|
||||
{
|
||||
public sealed partial class AlbumArtLayoutSettingsControl : UserControl
|
||||
public sealed partial class AlbumArtAreaStyleSettingsControl : UserControl
|
||||
{
|
||||
public static readonly DependencyProperty AlbumArtLayoutSettingsProperty =
|
||||
DependencyProperty.Register(nameof(AlbumArtLayoutSettings), typeof(AlbumArtLayoutSettings), typeof(AlbumArtLayoutSettingsControl), new PropertyMetadata(default));
|
||||
DependencyProperty.Register(nameof(AlbumArtLayoutSettings), typeof(AlbumArtAreaStyleSettings), typeof(AlbumArtAreaStyleSettingsControl), new PropertyMetadata(default));
|
||||
|
||||
public AlbumArtLayoutSettings AlbumArtLayoutSettings
|
||||
public AlbumArtAreaStyleSettings AlbumArtLayoutSettings
|
||||
{
|
||||
get => (AlbumArtLayoutSettings)GetValue(AlbumArtLayoutSettingsProperty);
|
||||
get => (AlbumArtAreaStyleSettings)GetValue(AlbumArtLayoutSettingsProperty);
|
||||
set => SetValue(AlbumArtLayoutSettingsProperty, value);
|
||||
}
|
||||
|
||||
public AlbumArtLayoutSettingsControl()
|
||||
public AlbumArtAreaStyleSettingsControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
@@ -44,9 +44,9 @@
|
||||
</dev:SettingsExpander.Items>
|
||||
</dev:SettingsExpander>
|
||||
|
||||
<!-- App behavior -->
|
||||
<!-- Startup -->
|
||||
|
||||
<TextBlock x:Uid="SettingsPageAppBehavior" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
<TextBlock x:Uid="SettingsPageStartup" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageAutoStart" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ToggleSwitch
|
||||
@@ -59,38 +59,42 @@
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.MusicGallerySettings.AutoOpen, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageAutoOpenLyricsWindow" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.GeneralSettings.AutoStartLyricsWindow, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
<!-- Music gallery window -->
|
||||
|
||||
<TextBlock x:Uid="SettingsPageMusicGallery" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageAutoPlayWhenOpenMusicGalleryWindow" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.MusicGallerySettings.AutoPlay, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageExitOnGalleryWindowClosed" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.MusicGallerySettings.ExitOnWindowClosed, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
<!-- Lyrics window -->
|
||||
|
||||
<TextBlock x:Uid="SettingsPageLyricsWindow" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageExitOnLyricsWindowClosed" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.GeneralSettings.ExitOnLyricsWindowClosed, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageListenNewSession" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.GeneralSettings.ListenOnNewPlaybackSource, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
<!-- Playback shortcut -->
|
||||
|
||||
<TextBlock x:Uid="SettingsPageShortcut" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageShowHideHotKey" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<local:ShortcutTextBox Shortcut="{x:Bind ViewModel.AppSettings.GeneralSettings.ShowOrHideLyricsWindowShortcut, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageBorderlessHotKey" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<local:ShortcutTextBox Shortcut="{x:Bind ViewModel.AppSettings.GeneralSettings.BorderlessShortcut, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageClickThroughHotKey" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<local:ShortcutTextBox Shortcut="{x:Bind ViewModel.AppSettings.GeneralSettings.ClickThroughShortcut, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageLyricsWindowSwitchHotKey" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<local:ShortcutTextBox Shortcut="{x:Bind ViewModel.AppSettings.GeneralSettings.LyricsWindowSwitchShortcut, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
<!-- Playback shortcut -->
|
||||
|
||||
<TextBlock x:Uid="SettingsPagePlaybackShortcut" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPagePlayOrPauseSongHotKey" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<local:ShortcutTextBox Shortcut="{x:Bind ViewModel.AppSettings.GeneralSettings.PlayOrPauseShortcut, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
@@ -6,25 +6,54 @@
|
||||
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:models="using:BetterLyrics.WinUI3.Models"
|
||||
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid>
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<TextBlock
|
||||
x:Name="SelectedLocalizedFontFamilyTextBlock"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{StaticResource TextFillColorSecondaryBrush}"
|
||||
IsTextSelectionEnabled="True" />
|
||||
<AutoSuggestBox
|
||||
x:Name="AutoSuggestBox"
|
||||
Width="150"
|
||||
MinWidth="180"
|
||||
GotFocus="AutoSuggestBox_GotFocus"
|
||||
LostFocus="AutoSuggestBox_LostFocus"
|
||||
SuggestionChosen="AutoSuggestBox_SuggestionChosen"
|
||||
Text="{x:Bind SelectedFontFamily, Mode=OneWay}"
|
||||
TextChanged="AutoSuggestBox_TextChanged" />
|
||||
TextChanged="AutoSuggestBox_TextChanged">
|
||||
<!--<AutoSuggestBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="models:ExtendedFontFamily">
|
||||
<StackPanel>
|
||||
<TextBlock Text="{x:Bind LocalizedFontFamily}" TextWrapping="Wrap" />
|
||||
<TextBlock
|
||||
FontSize="12"
|
||||
Foreground="{StaticResource TextFillColorSecondaryBrush}"
|
||||
Text="{x:Bind FontFamily}"
|
||||
TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</AutoSuggestBox.ItemTemplate>-->
|
||||
</AutoSuggestBox>
|
||||
<Button
|
||||
Click="Button_Click"
|
||||
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
FontSize=12,
|
||||
Glyph=}"
|
||||
Style="{StaticResource GhostButtonStyle}" />
|
||||
Style="{StaticResource GhostButtonStyle}">
|
||||
<ToolTipService.ToolTip>
|
||||
<ToolTip x:Uid="SettingsPageRefreshDropdown" />
|
||||
</ToolTipService.ToolTip>
|
||||
</Button>
|
||||
<Button Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, FontSize=12, Glyph=}" Style="{StaticResource GhostButtonStyle}">
|
||||
<ToolTipService.ToolTip>
|
||||
<ToolTip x:Uid="SettingsPageCollapseDropdown" />
|
||||
</ToolTipService.ToolTip>
|
||||
</Button>
|
||||
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.Services.SettingsService;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using System.Collections.Generic;
|
||||
@@ -11,11 +14,15 @@ namespace BetterLyrics.WinUI3.Controls
|
||||
{
|
||||
public sealed partial class FontFamilyAutoSuggestBox : UserControl
|
||||
{
|
||||
private List<string> SystemFontNames { get; set; } = [.. FontHelper.SystemFontFamilies];
|
||||
private readonly ISettingsService _settingsService = Ioc.Default.GetRequiredService<ISettingsService>();
|
||||
|
||||
//private List<ExtendedFontFamily> FontFamilies { get; set; } = [];
|
||||
private List<string> FontFamilies { get; set; } = [];
|
||||
|
||||
public FontFamilyAutoSuggestBox()
|
||||
{
|
||||
InitializeComponent();
|
||||
RefreshFontFamilies();
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SelectedFontFamilyProperty =
|
||||
@@ -27,20 +34,47 @@ namespace BetterLyrics.WinUI3.Controls
|
||||
set => SetValue(SelectedFontFamilyProperty, value);
|
||||
}
|
||||
|
||||
private void RefreshFontFamilies()
|
||||
{
|
||||
//Task.Run(() =>
|
||||
//{
|
||||
// var fontFamilies = FontHelper.SystemFontFamilies.Select(x => new ExtendedFontFamily()
|
||||
// {
|
||||
// FontFamily = x,
|
||||
// LocalizedFontFamily = FontHelper.GetLocalizedFontFamilyName(x, _settingsService.AppSettings.GeneralSettings.LanguageCode)
|
||||
// }).OrderBy(x => x.LocalizedFontFamily).ToList();
|
||||
// DispatcherQueue.TryEnqueue(() =>
|
||||
// {
|
||||
// FontFamilies = fontFamilies;
|
||||
// });
|
||||
//});
|
||||
FontFamilies = FontHelper.SystemFontFamilies.OrderBy(x => x).ToList();
|
||||
}
|
||||
|
||||
private void AutoSuggestBox_SuggestionChosen(AutoSuggestBox sender, AutoSuggestBoxSuggestionChosenEventArgs args)
|
||||
{
|
||||
SelectedFontFamily = args.SelectedItem.ToString() ?? "";
|
||||
if (args.SelectedItem is ExtendedFontFamily extendedFontFamily)
|
||||
{
|
||||
SelectedFontFamily = extendedFontFamily.FontFamily;
|
||||
}
|
||||
else
|
||||
{
|
||||
SelectedFontFamily = args.SelectedItem.ToString() ?? "";
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateAutoSuggestBoxItemsSource()
|
||||
private void UpdateAutoSuggestBoxItemsSource(string? query = null)
|
||||
{
|
||||
query ??= AutoSuggestBox.Text;
|
||||
|
||||
//var suitableItems = new List<ExtendedFontFamily>();
|
||||
var suitableItems = new List<string>();
|
||||
var splitText = AutoSuggestBox.Text.ToLower().Split(" ");
|
||||
foreach (var fontFamily in SystemFontNames)
|
||||
var splitText = query.ToLower().Split(" ");
|
||||
foreach (var fontFamily in FontFamilies)
|
||||
{
|
||||
var found = splitText.All((key) =>
|
||||
bool found = splitText.All((key) =>
|
||||
{
|
||||
//return fontFamily.FontFamily.ToLower().Contains(key) || fontFamily.LocalizedFontFamily.ToLower().Contains(key);
|
||||
return fontFamily.ToLower().Contains(key);
|
||||
});
|
||||
if (found)
|
||||
@@ -50,9 +84,15 @@ namespace BetterLyrics.WinUI3.Controls
|
||||
}
|
||||
if (suitableItems.Count == 0)
|
||||
{
|
||||
//suitableItems.Add(new ExtendedFontFamily()
|
||||
//{
|
||||
// FontFamily = "",
|
||||
// LocalizedFontFamily = "N/A"
|
||||
//});
|
||||
suitableItems.Add("N/A");
|
||||
}
|
||||
AutoSuggestBox.ItemsSource = suitableItems.Order();
|
||||
//AutoSuggestBox.ItemsSource = suitableItems.OrderBy(x => x.LocalizedFontFamily);
|
||||
AutoSuggestBox.ItemsSource = suitableItems.OrderBy(x => x);
|
||||
}
|
||||
|
||||
private void AutoSuggestBox_TextChanged(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args)
|
||||
@@ -63,16 +103,18 @@ namespace BetterLyrics.WinUI3.Controls
|
||||
{
|
||||
UpdateAutoSuggestBoxItemsSource();
|
||||
}
|
||||
|
||||
SelectedLocalizedFontFamilyTextBlock.Text = FontHelper.GetLocalizedFontFamilyName(SelectedFontFamily, _settingsService.AppSettings.GeneralSettings.LanguageCode);
|
||||
}
|
||||
|
||||
private void Button_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
SystemFontNames = [.. FontHelper.SystemFontFamilies];
|
||||
RefreshFontFamilies();
|
||||
}
|
||||
|
||||
private void AutoSuggestBox_GotFocus(object sender, RoutedEventArgs e)
|
||||
{
|
||||
UpdateAutoSuggestBoxItemsSource();
|
||||
UpdateAutoSuggestBoxItemsSource("");
|
||||
}
|
||||
|
||||
private void AutoSuggestBox_LostFocus(object sender, RoutedEventArgs e)
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<UserControl
|
||||
x:Class="BetterLyrics.WinUI3.Controls.ImageSwitcher"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:const="using:BetterLyrics.WinUI3.Constants"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:BetterLyrics.WinUI3.Controls"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid>
|
||||
<Grid.OpacityTransition>
|
||||
<ScalarTransition Duration="{x:Bind const:Time.AnimationDuration}" />
|
||||
</Grid.OpacityTransition>
|
||||
<local:ShadowImage
|
||||
x:Name="LastAlbumArtImage"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
CornerRadiusAmount="{x:Bind CornerRadiusAmount, Mode=OneWay}"
|
||||
ShadowAmount="{x:Bind ShadowAmount, Mode=OneWay}" />
|
||||
<local:ShadowImage
|
||||
x:Name="AlbumArtImage"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
CornerRadiusAmount="{x:Bind CornerRadiusAmount, Mode=OneWay}"
|
||||
ShadowAmount="{x:Bind ShadowAmount, Mode=OneWay}" />
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,133 @@
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
|
||||
// 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 ImageSwitcher : UserControl
|
||||
{
|
||||
public int CornerRadiusAmount
|
||||
{
|
||||
get { return (int)GetValue(CornerRadiusAmountProperty); }
|
||||
set { SetValue(CornerRadiusAmountProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CornerRadiusAmountProperty =
|
||||
DependencyProperty.Register(nameof(CornerRadiusAmount), typeof(int), typeof(ImageSwitcher), new PropertyMetadata(0));
|
||||
|
||||
public int ShadowAmount
|
||||
{
|
||||
get { return (int)GetValue(ShadowAmountProperty); }
|
||||
set { SetValue(ShadowAmountProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ShadowAmountProperty =
|
||||
DependencyProperty.Register(nameof(ShadowAmount), typeof(int), typeof(ImageSwitcher), new PropertyMetadata(0));
|
||||
|
||||
public ImageSource? Source
|
||||
{
|
||||
get { return (ImageSource?)GetValue(SourceProperty); }
|
||||
set { SetValue(SourceProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SourceProperty =
|
||||
DependencyProperty.Register(nameof(Source), typeof(ImageSource), typeof(ImageSwitcher), new PropertyMetadata(null, OnDependencyPropertyChanged));
|
||||
|
||||
public ImageSwitchType SwitchType
|
||||
{
|
||||
get { return (ImageSwitchType)GetValue(SwitchTypeProperty); }
|
||||
set { SetValue(SwitchTypeProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SwitchTypeProperty =
|
||||
DependencyProperty.Register(nameof(SwitchType), typeof(ImageSwitchType), typeof(ImageSwitcher), new PropertyMetadata(ImageSwitchType.Crossfade));
|
||||
|
||||
public ImageSwitcher()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void UpdateSource()
|
||||
{
|
||||
switch (SwitchType)
|
||||
{
|
||||
case ImageSwitchType.Crossfade:
|
||||
UpdateSourceCrossfade();
|
||||
break;
|
||||
case ImageSwitchType.Slide:
|
||||
UpdateSourceSlide();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateSourceCrossfade()
|
||||
{
|
||||
// Ϊ<><CEAA><EFBFBD><EFBFBD>ͼƬ<CDBC><C6AC><EFBFBD>þ<EFBFBD>Դ
|
||||
LastAlbumArtImage.Source = AlbumArtImage.Source;
|
||||
// ʹ<><CAB9><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɼ<EFBFBD>
|
||||
LastAlbumArtImage.TranslationTransition = null;
|
||||
LastAlbumArtImage.OpacityTransition = null;
|
||||
LastAlbumArtImage.Translation = new();
|
||||
LastAlbumArtImage.Opacity = 1;
|
||||
LastAlbumArtImage.OpacityTransition = new ScalarTransition { Duration = Constants.Time.AnimationDuration };
|
||||
|
||||
// ʹǰ<CAB9><C7B0>ͼƬ<CDBC><C6AC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɼ<EFBFBD>
|
||||
AlbumArtImage.TranslationTransition = null;
|
||||
AlbumArtImage.OpacityTransition = null;
|
||||
AlbumArtImage.Translation = new();
|
||||
AlbumArtImage.Opacity = 0;
|
||||
AlbumArtImage.OpacityTransition = new ScalarTransition { Duration = Constants.Time.AnimationDuration };
|
||||
// ֮<><D6AE>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Դ
|
||||
AlbumArtImage.Source = Source;
|
||||
|
||||
// <20><><EFBFBD>浭<EFBFBD><E6B5AD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
LastAlbumArtImage.Opacity = 0;
|
||||
AlbumArtImage.Opacity = 1;
|
||||
}
|
||||
|
||||
private void UpdateSourceSlide()
|
||||
{
|
||||
// Ϊ<><CEAA><EFBFBD><EFBFBD>ͼƬ<CDBC><C6AC><EFBFBD>þ<EFBFBD>Դ
|
||||
LastAlbumArtImage.Source = AlbumArtImage.Source;
|
||||
// ʹ<><CAB9><EFBFBD><EFBFBD>λ
|
||||
LastAlbumArtImage.TranslationTransition = null;
|
||||
LastAlbumArtImage.OpacityTransition = null;
|
||||
LastAlbumArtImage.Translation = new();
|
||||
LastAlbumArtImage.Opacity = 1;
|
||||
LastAlbumArtImage.TranslationTransition = new Vector3Transition { Duration = Constants.Time.AnimationDuration };
|
||||
LastAlbumArtImage.OpacityTransition = new ScalarTransition { Duration = Constants.Time.AnimationDuration };
|
||||
|
||||
// ʹǰ<CAB9><C7B0>ͼƬ<CDBC><C6AC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɼ<EFBFBD>
|
||||
AlbumArtImage.TranslationTransition = null;
|
||||
AlbumArtImage.OpacityTransition = null;
|
||||
AlbumArtImage.Translation = new(-(float)ActualWidth, 0, 0);
|
||||
AlbumArtImage.Opacity = 0;
|
||||
AlbumArtImage.TranslationTransition = new Vector3Transition { Duration = Constants.Time.AnimationDuration };
|
||||
AlbumArtImage.OpacityTransition = new ScalarTransition { Duration = Constants.Time.AnimationDuration };
|
||||
// ֮<><D6AE>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Դ
|
||||
AlbumArtImage.Source = Source;
|
||||
|
||||
// <20><><EFBFBD><EFBFBD>
|
||||
LastAlbumArtImage.Opacity = 0;
|
||||
AlbumArtImage.Opacity = 1;
|
||||
LastAlbumArtImage.Translation = new(-(float)ActualWidth, 0, 0);
|
||||
AlbumArtImage.Translation = new();
|
||||
}
|
||||
|
||||
private static void OnDependencyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is ImageSwitcher imageSwitcher)
|
||||
{
|
||||
if (e.Property == SourceProperty)
|
||||
{
|
||||
imageSwitcher.UpdateSource();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@
|
||||
<Grid Style="{StaticResource SettingsGridStyle}">
|
||||
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
|
||||
|
||||
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
<TextBlock x:Uid="SettingsPageBackgroundOverlay" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageTheme" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ComboBox x:Name="ThemeComboBox" SelectedIndex="{x:Bind LyricsBackgroundSettings.LyricsBackgroundTheme, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||
@@ -47,51 +47,6 @@
|
||||
</dev:SettingsExpander.Items>
|
||||
</dev:SettingsExpander>
|
||||
|
||||
<dev:SettingsExpander
|
||||
x:Uid="SettingsPageAlbumArtLayer"
|
||||
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}"
|
||||
IsExpanded="{x:Bind LyricsBackgroundSettings.IsCoverOverlayEnabled, Mode=OneWay}">
|
||||
<ToggleSwitch IsOn="{x:Bind LyricsBackgroundSettings.IsCoverOverlayEnabled, Mode=TwoWay}" />
|
||||
<dev:SettingsExpander.Items>
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageOpacity" IsEnabled="{x:Bind LyricsBackgroundSettings.IsCoverOverlayEnabled, Mode=OneWay}">
|
||||
<uc:ExtendedSlider
|
||||
Default="100"
|
||||
Maximum="100"
|
||||
Minimum="0"
|
||||
Unit="%"
|
||||
Value="{x:Bind LyricsBackgroundSettings.CoverOverlayOpacity, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageSpeed" IsEnabled="{x:Bind LyricsBackgroundSettings.IsCoverOverlayEnabled, Mode=OneWay}">
|
||||
<uc:ExtendedSlider
|
||||
Default="50"
|
||||
Maximum="100"
|
||||
Minimum="0"
|
||||
Unit="%"
|
||||
Value="{x:Bind LyricsBackgroundSettings.CoverOverlaySpeed, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageBlurAmount" IsEnabled="{x:Bind LyricsBackgroundSettings.IsCoverOverlayEnabled, Mode=OneWay}">
|
||||
<uc:ExtendedSlider
|
||||
Default="100"
|
||||
Maximum="100"
|
||||
Minimum="0"
|
||||
Value="{x:Bind LyricsBackgroundSettings.CoverOverlayBlurAmount, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageBackgroundAcrylicEffectAmount" IsEnabled="{x:Bind LyricsBackgroundSettings.IsCoverOverlayEnabled, Mode=OneWay}">
|
||||
<uc:ExtendedSlider
|
||||
Default="0"
|
||||
Maximum="10"
|
||||
Minimum="0"
|
||||
Value="{x:Bind LyricsBackgroundSettings.CoverAcrylicEffectAmount, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
</dev:SettingsExpander.Items>
|
||||
</dev:SettingsExpander>
|
||||
|
||||
<dev:SettingsExpander
|
||||
x:Uid="SettingsPageFluidLayer"
|
||||
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
@@ -128,18 +83,58 @@
|
||||
<dev:SettingsExpander.Items>
|
||||
<dev:SettingsCard x:Uid="SettingsPageAmount" IsEnabled="{x:Bind LyricsBackgroundSettings.IsSnowFlakeOverlayEnabled, Mode=OneWay}">
|
||||
<uc:ExtendedSlider
|
||||
Maximum="100"
|
||||
Minimum="10"
|
||||
Maximum="10"
|
||||
Minimum="0"
|
||||
ResetButtonVisibility="Collapsed"
|
||||
Value="{x:Bind LyricsBackgroundSettings.SnowFlakeOverlayAmount, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
<dev:SettingsCard x:Uid="SettingsPageSpeed" IsEnabled="{x:Bind LyricsBackgroundSettings.IsSnowFlakeOverlayEnabled, Mode=OneWay}">
|
||||
<uc:ExtendedSlider
|
||||
Maximum="10"
|
||||
Minimum="1"
|
||||
ResetButtonVisibility="Collapsed"
|
||||
Value="{x:Bind LyricsBackgroundSettings.SnowFlakeOverlaySpeed, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
</dev:SettingsExpander.Items>
|
||||
</dev:SettingsExpander>
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageSpectrumLayer" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ToggleSwitch IsOn="{x:Bind LyricsBackgroundSettings.IsSpectrumOverlayEnabled, Mode=TwoWay}" />
|
||||
<dev:SettingsCard x:Uid="SettingsPageFogLayer" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ToggleSwitch IsOn="{x:Bind LyricsBackgroundSettings.IsFogOverlayEnabled, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
<dev:SettingsExpander
|
||||
x:Uid="SettingsPageSpectrumLayer"
|
||||
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}"
|
||||
IsExpanded="{x:Bind LyricsBackgroundSettings.IsSpectrumOverlayEnabled, Mode=OneWay}">
|
||||
<ToggleSwitch IsOn="{x:Bind LyricsBackgroundSettings.IsSpectrumOverlayEnabled, Mode=TwoWay}" />
|
||||
<dev:SettingsExpander.Items>
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageSpectrumLayerPlacement" IsEnabled="{x:Bind LyricsBackgroundSettings.IsSpectrumOverlayEnabled, Mode=OneWay}">
|
||||
<ComboBox SelectedIndex="{x:Bind LyricsBackgroundSettings.SpectrumPlacement, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||
<ComboBoxItem x:Uid="SettingsPageSpectrumPlacementTop" />
|
||||
<ComboBoxItem x:Uid="SettingsPageSpectrumPlacementBottom" />
|
||||
</ComboBox>
|
||||
</dev:SettingsCard>
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageSpectrumLayerStyle" IsEnabled="{x:Bind LyricsBackgroundSettings.IsSpectrumOverlayEnabled, Mode=OneWay}">
|
||||
<ComboBox SelectedIndex="{x:Bind LyricsBackgroundSettings.SpectrumStyle, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||
<ComboBoxItem x:Uid="SettingsPageSpectrumStyleCurve" />
|
||||
<ComboBoxItem x:Uid="SettingsPageSpectrumStyleBar" />
|
||||
</ComboBox>
|
||||
</dev:SettingsCard>
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageAmount" IsEnabled="{x:Bind LyricsBackgroundSettings.IsSpectrumOverlayEnabled, Mode=OneWay}">
|
||||
<uc:ExtendedSlider
|
||||
Default="128"
|
||||
Maximum="1024"
|
||||
Minimum="1"
|
||||
Value="{x:Bind LyricsBackgroundSettings.SpectrumCount, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
</dev:SettingsExpander.Items>
|
||||
</dev:SettingsExpander>
|
||||
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<UserControl
|
||||
x:Class="BetterLyrics.WinUI3.Renderer.LyricsRenderer"
|
||||
x:Class="BetterLyrics.WinUI3.Controls.LyricsCanvas"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:canvas="using:Microsoft.Graphics.Canvas.UI.Xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
|
||||
xmlns:local="using:BetterLyrics.WinUI3.Renderer"
|
||||
xmlns:local="using:BetterLyrics.WinUI3.Controls"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
Unloaded="LyricsCanvas_Unloaded"
|
||||
Unloaded="Canvas_Unloaded"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid>
|
||||
<canvas:CanvasAnimatedControl
|
||||
x:Name="LyricsCanvas"
|
||||
CreateResources="LyricsCanvas_CreateResources"
|
||||
Draw="LyricsCanvas_Draw"
|
||||
Update="LyricsCanvas_Update" />
|
||||
x:Name="Canvas"
|
||||
CreateResources="Canvas_CreateResources"
|
||||
Draw="Canvas_Draw"
|
||||
Update="Canvas_Update" />
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,878 @@
|
||||
// 2025/6/23 by Zhe Fang
|
||||
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using BetterLyrics.WinUI3.Extensions;
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using BetterLyrics.WinUI3.Logic;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.Models.Settings;
|
||||
using BetterLyrics.WinUI3.Renderer;
|
||||
using BetterLyrics.WinUI3.Services.LastFMService;
|
||||
using BetterLyrics.WinUI3.Services.MediaSessionsService;
|
||||
using BetterLyrics.WinUI3.Services.SettingsService;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using CommunityToolkit.Mvvm.Messaging.Messages;
|
||||
using Microsoft.Graphics.Canvas.UI.Xaml;
|
||||
using Microsoft.UI;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Windows.Foundation;
|
||||
using Windows.UI;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Controls
|
||||
{
|
||||
public sealed partial class LyricsCanvas : UserControl,
|
||||
IRecipient<PropertyChangedMessage<TimeSpan>>,
|
||||
IRecipient<PropertyChangedMessage<LyricsData?>>,
|
||||
IRecipient<PropertyChangedMessage<SongInfo?>>,
|
||||
IRecipient<PropertyChangedMessage<int>>,
|
||||
IRecipient<PropertyChangedMessage<double>>,
|
||||
IRecipient<PropertyChangedMessage<bool>>,
|
||||
IRecipient<PropertyChangedMessage<TextAlignmentType>>,
|
||||
IRecipient<PropertyChangedMessage<LyricsFontWeight>>,
|
||||
IRecipient<PropertyChangedMessage<string>>
|
||||
{
|
||||
private readonly ISettingsService _settingsService = Ioc.Default.GetRequiredService<ISettingsService>();
|
||||
private readonly IMediaSessionsService _mediaSessionsService = Ioc.Default.GetRequiredService<IMediaSessionsService>();
|
||||
private readonly ILastFMService _lastFMService = Ioc.Default.GetRequiredService<ILastFMService>();
|
||||
|
||||
private readonly LyricsRenderer _lyricsRenderer = new();
|
||||
private readonly FluidBackgroundRenderer _fluidRenderer = new();
|
||||
private readonly PureColorBackgroundRenderer _pureColorRenderer = new();
|
||||
private readonly SnowRenderer _snowRenderer = new();
|
||||
private readonly FogRenderer _fogRenderer = new();
|
||||
private readonly SpectrumRenderer _spectrumRenderer = new();
|
||||
|
||||
private readonly LyricsSynchronizer _synchronizer = new();
|
||||
private readonly LyricsAnimator _animator = new();
|
||||
|
||||
private readonly SpectrumAnalyzer _spectrumAnalyzer = new();
|
||||
|
||||
private readonly ValueTransition<Color> _immersiveBgColorTransition = new(
|
||||
initialValue: Colors.Transparent,
|
||||
durationSeconds: 0.3f,
|
||||
interpolator: (from, to, progress) => Helper.ColorHelper.GetInterpolatedColor(progress, from, to)
|
||||
);
|
||||
private readonly ValueTransition<double> _immersiveBgOpacityTransition = new(
|
||||
initialValue: 1f,
|
||||
durationSeconds: 0.3f
|
||||
);
|
||||
private readonly ValueTransition<Color> _accentColor1Transition = new(
|
||||
initialValue: Colors.Transparent,
|
||||
durationSeconds: 0.3f,
|
||||
interpolator: (from, to, progress) => Helper.ColorHelper.GetInterpolatedColor(progress, from, to)
|
||||
);
|
||||
private readonly ValueTransition<Color> _accentColor2Transition = new(
|
||||
initialValue: Colors.Transparent,
|
||||
durationSeconds: 0.3f,
|
||||
interpolator: (from, to, progress) => Helper.ColorHelper.GetInterpolatedColor(progress, from, to)
|
||||
);
|
||||
private readonly ValueTransition<Color> _accentColor3Transition = new(
|
||||
initialValue: Colors.Transparent,
|
||||
durationSeconds: 0.3f,
|
||||
interpolator: (from, to, progress) => Helper.ColorHelper.GetInterpolatedColor(progress, from, to)
|
||||
);
|
||||
private readonly ValueTransition<Color> _accentColor4Transition = new(
|
||||
initialValue: Colors.Transparent,
|
||||
durationSeconds: 0.3f,
|
||||
interpolator: (from, to, progress) => Helper.ColorHelper.GetInterpolatedColor(progress, from, to)
|
||||
);
|
||||
private readonly ValueTransition<double> _canvasYScrollTransition = new(
|
||||
initialValue: 0f,
|
||||
durationSeconds: 0.3f,
|
||||
easingType: EasingType.EaseInOutSine
|
||||
);
|
||||
private readonly ValueTransition<double> _mouseYScrollTransition = new(
|
||||
initialValue: 0f,
|
||||
durationSeconds: 0.3f,
|
||||
easingType: EasingType.EaseInOutSine
|
||||
);
|
||||
|
||||
private TimeSpan _songPositionWithOffset;
|
||||
private TimeSpan _songPosition; // <20><>ǰ<EFBFBD><C7B0><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1>
|
||||
private TimeSpan _totalPlayedTime; // <20><>ǰ<EFBFBD><C7B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ػ<EFBFBD><D8BB>ظ<EFBFBD><D8B8><EFBFBD><EFBFBD>ŵ<EFBFBD>ʱ<EFBFBD>䣩
|
||||
private bool _isLastFMTracked = false;
|
||||
|
||||
private double _renderLyricsStartX = 0;
|
||||
private double _renderLyricsStartY = 0;
|
||||
private double _renderLyricsWidth = 0;
|
||||
private double _renderLyricsHeight = 0;
|
||||
private double _renderLyricsOpacity = 0;
|
||||
|
||||
private LyricsWindowStatus? _lyricsWindowStatus = null;
|
||||
private AlbumArtThemeColors _albumArtThemeColors = new();
|
||||
|
||||
private Point _mousePosition = new(0, 0);
|
||||
private int _mouseHoverLineIndex = -1;
|
||||
private bool _isMouseInLyricsArea = false;
|
||||
private bool _isMousePressing = false;
|
||||
private bool _isMouseScrolling = false;
|
||||
|
||||
private List<RenderLyricsLine>? _renderLyricsLines = null;
|
||||
|
||||
private bool _isLayoutChanged = true;
|
||||
private bool _isMouseScrollingChanged = false;
|
||||
|
||||
private int _playingLineIndex;
|
||||
private (int Start, int End) _visibleRange;
|
||||
private double _canvasTargetScrollOffset;
|
||||
|
||||
public TimeSpan SongPosition => _songPosition;
|
||||
public double CurrentCanvasYScroll => _canvasYScrollTransition.Value;
|
||||
public double ActualLyricsHeight => LyricsLayoutManager.CalculateActualHeight(_renderLyricsLines);
|
||||
public int CurrentHoveringLineIndex => _mouseHoverLineIndex;
|
||||
|
||||
public LyricsWindowStatus? LyricsWindowStatus
|
||||
{
|
||||
get { return (LyricsWindowStatus?)GetValue(LyricsWindowStatusProperty); }
|
||||
set { SetValue(LyricsWindowStatusProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty LyricsWindowStatusProperty =
|
||||
DependencyProperty.Register(nameof(LyricsWindowStatus), typeof(LyricsWindowStatus), typeof(LyricsCanvas), new PropertyMetadata(null, OnDependencyPropertyChanged));
|
||||
|
||||
public AlbumArtThemeColors AlbumArtThemeColors
|
||||
{
|
||||
get { return (AlbumArtThemeColors)GetValue(AlbumArtThemeColorsProperty); }
|
||||
set { SetValue(AlbumArtThemeColorsProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty AlbumArtThemeColorsProperty =
|
||||
DependencyProperty.Register(nameof(AlbumArtThemeColors), typeof(AlbumArtThemeColors), typeof(LyricsCanvas), new PropertyMetadata(new AlbumArtThemeColors(), OnDependencyPropertyChanged));
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><CABC> X <20><><EFBFBD><EFBFBD>
|
||||
public double LyricsStartX
|
||||
{
|
||||
get { return (double)GetValue(LyricsStartXProperty); }
|
||||
set { SetValue(LyricsStartXProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty LyricsStartXProperty =
|
||||
DependencyProperty.Register(nameof(LyricsStartX), typeof(double), typeof(LyricsCanvas), new PropertyMetadata(0.0, OnDependencyPropertyChanged));
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼ Y <20><><EFBFBD><EFBFBD>
|
||||
public double LyricsStartY
|
||||
{
|
||||
get { return (double)GetValue(LyricsStartYProperty); }
|
||||
set { SetValue(LyricsStartYProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty LyricsStartYProperty =
|
||||
DependencyProperty.Register(nameof(LyricsStartY), typeof(double), typeof(LyricsCanvas), new PropertyMetadata(0.0, OnDependencyPropertyChanged));
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
public double LyricsWidth
|
||||
{
|
||||
get { return (double)GetValue(LyricsWidthProperty); }
|
||||
set { SetValue(LyricsWidthProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty LyricsWidthProperty =
|
||||
DependencyProperty.Register(nameof(LyricsWidth), typeof(double), typeof(LyricsCanvas), new PropertyMetadata(0.0, OnDependencyPropertyChanged));
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߶<EFBFBD>
|
||||
public double LyricsHeight
|
||||
{
|
||||
get { return (double)GetValue(LyricsHeightProperty); }
|
||||
set { SetValue(LyricsHeightProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty LyricsHeightProperty =
|
||||
DependencyProperty.Register(nameof(LyricsHeight), typeof(double), typeof(LyricsCanvas), new PropertyMetadata(0.0, OnDependencyPropertyChanged));
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><CDB8><EFBFBD><EFBFBD>
|
||||
public double LyricsOpacity
|
||||
{
|
||||
get { return (double)GetValue(LyricsOpacityProperty); }
|
||||
set { SetValue(LyricsOpacityProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty LyricsOpacityProperty =
|
||||
DependencyProperty.Register(nameof(LyricsOpacity), typeof(double), typeof(LyricsCanvas), new PropertyMetadata(0.0, OnDependencyPropertyChanged));
|
||||
|
||||
/// <summary>
|
||||
/// <20>û<EFBFBD><C3BB>ٿ<EFBFBD><D9BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѹ<EFBFBD><D1B9><EFBFBD><EFBFBD>ľ<EFBFBD><C4BE>루<EFBFBD><EBA3A8> 0 <20><>ʼ<EFBFBD>㣩
|
||||
/// </summary>
|
||||
public double MouseScrollOffset
|
||||
{
|
||||
get { return (double)GetValue(MouseScrollOffsetProperty); }
|
||||
set { SetValue(MouseScrollOffsetProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty MouseScrollOffsetProperty =
|
||||
DependencyProperty.Register(nameof(MouseScrollOffset), typeof(double), typeof(LyricsCanvas), new PropertyMetadata(0.0, OnDependencyPropertyChanged));
|
||||
|
||||
/// <summary>
|
||||
/// <20>û<EFBFBD><C3BB><EFBFBD><EFBFBD>굱ǰ<EAB5B1><C7B0>λ<EFBFBD>ã<EFBFBD><C3A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڸ<EFBFBD><DAB8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ͻǣ<CFBD>
|
||||
/// </summary>
|
||||
public Point MousePosition
|
||||
{
|
||||
get { return (Point)GetValue(MousePositionProperty); }
|
||||
set { SetValue(MousePositionProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty MousePositionProperty =
|
||||
DependencyProperty.Register(nameof(MousePosition), typeof(Point), typeof(LyricsCanvas), new PropertyMetadata(new Point(0, 0), OnDependencyPropertyChanged));
|
||||
|
||||
public bool IsMouseInLyricsArea
|
||||
{
|
||||
get { return (bool)GetValue(IsMouseInLyricsAreaProperty); }
|
||||
set { SetValue(IsMouseInLyricsAreaProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsMouseInLyricsAreaProperty =
|
||||
DependencyProperty.Register(nameof(IsMouseInLyricsArea), typeof(bool), typeof(LyricsCanvas), new PropertyMetadata(false, OnDependencyPropertyChanged));
|
||||
|
||||
public bool IsMousePressing
|
||||
{
|
||||
get { return (bool)GetValue(IsMousePressingProperty); }
|
||||
set { SetValue(IsMousePressingProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsMousePressingProperty =
|
||||
DependencyProperty.Register(nameof(IsMousePressing), typeof(bool), typeof(LyricsCanvas), new PropertyMetadata(false, OnDependencyPropertyChanged));
|
||||
|
||||
public bool IsMouseScrolling
|
||||
{
|
||||
get { return (bool)GetValue(IsMouseScrollingProperty); }
|
||||
set { SetValue(IsMouseScrollingProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsMouseScrollingProperty =
|
||||
DependencyProperty.Register(nameof(IsMouseScrolling), typeof(bool), typeof(LyricsCanvas), new PropertyMetadata(false, OnDependencyPropertyChanged));
|
||||
|
||||
public LyricsCanvas()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
WeakReferenceMessenger.Default.RegisterAll(this);
|
||||
|
||||
UpdateRenderLyricsLines();
|
||||
}
|
||||
|
||||
private static void OnDependencyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is LyricsCanvas canvas)
|
||||
{
|
||||
if (e.Property == LyricsWindowStatusProperty)
|
||||
{
|
||||
canvas._lyricsWindowStatus = (LyricsWindowStatus)e.NewValue;
|
||||
canvas._isLayoutChanged = true;
|
||||
}
|
||||
else if (e.Property == LyricsStartXProperty)
|
||||
{
|
||||
canvas._renderLyricsStartX = Convert.ToDouble(e.NewValue);
|
||||
canvas._isLayoutChanged = true;
|
||||
}
|
||||
else if (e.Property == LyricsStartYProperty)
|
||||
{
|
||||
canvas._renderLyricsStartY = Convert.ToDouble(e.NewValue);
|
||||
canvas._isLayoutChanged = true;
|
||||
}
|
||||
else if (e.Property == LyricsWidthProperty)
|
||||
{
|
||||
canvas._renderLyricsWidth = Convert.ToDouble(e.NewValue);
|
||||
canvas._isLayoutChanged = true;
|
||||
}
|
||||
else if (e.Property == LyricsHeightProperty)
|
||||
{
|
||||
canvas._renderLyricsHeight = Convert.ToDouble(e.NewValue);
|
||||
canvas._isLayoutChanged = true;
|
||||
}
|
||||
else if (e.Property == LyricsOpacityProperty)
|
||||
{
|
||||
canvas._renderLyricsOpacity = Convert.ToDouble(e.NewValue);
|
||||
canvas._isLayoutChanged = true;
|
||||
}
|
||||
else if (e.Property == MouseScrollOffsetProperty)
|
||||
{
|
||||
canvas._mouseYScrollTransition.StartTransition(Convert.ToDouble(e.NewValue));
|
||||
}
|
||||
else if (e.Property == MousePositionProperty)
|
||||
{
|
||||
canvas._mousePosition = (Point)e.NewValue;
|
||||
}
|
||||
else if (e.Property == IsMouseInLyricsAreaProperty)
|
||||
{
|
||||
canvas._isMouseInLyricsArea = (bool)e.NewValue;
|
||||
}
|
||||
else if (e.Property == IsMousePressingProperty)
|
||||
{
|
||||
canvas._isMousePressing = (bool)e.NewValue;
|
||||
}
|
||||
else if (e.Property == IsMouseScrollingProperty)
|
||||
{
|
||||
var value = (bool)e.NewValue;
|
||||
if (canvas._isMouseScrolling != value)
|
||||
{
|
||||
canvas._isMouseScrollingChanged = true;
|
||||
}
|
||||
canvas._isMouseScrolling = value;
|
||||
}
|
||||
else if (e.Property == AlbumArtThemeColorsProperty)
|
||||
{
|
||||
var albumArtThemeColors = (AlbumArtThemeColors)e.NewValue;
|
||||
canvas._immersiveBgColorTransition.StartTransition(albumArtThemeColors.EnvColor);
|
||||
canvas._accentColor1Transition.StartTransition(albumArtThemeColors.AccentColor1);
|
||||
canvas._accentColor2Transition.StartTransition(albumArtThemeColors.AccentColor2);
|
||||
canvas._accentColor3Transition.StartTransition(albumArtThemeColors.AccentColor3);
|
||||
canvas._accentColor4Transition.StartTransition(albumArtThemeColors.AccentColor4);
|
||||
|
||||
canvas._albumArtThemeColors = albumArtThemeColors;
|
||||
canvas._isLayoutChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ====
|
||||
|
||||
private void Canvas_Draw(ICanvasAnimatedControl sender, CanvasAnimatedDrawEventArgs args)
|
||||
{
|
||||
if (_lyricsWindowStatus == null) return;
|
||||
|
||||
var bounds = new Rect(0, 0, sender.Size.Width, sender.Size.Height);
|
||||
|
||||
var albumArtLayout = _lyricsWindowStatus.AlbumArtLayoutSettings;
|
||||
var lyricsBg = _lyricsWindowStatus.LyricsBackgroundSettings;
|
||||
var lyricsStyle = _lyricsWindowStatus.LyricsStyleSettings;
|
||||
var lyricsEffect = _lyricsWindowStatus.LyricsEffectSettings;
|
||||
|
||||
double songDuration = _mediaSessionsService.CurrentSongInfo?.DurationMs ?? 0;
|
||||
bool isForceWordByWord = _settingsService.AppSettings.GeneralSettings.IsForceWordByWordEffect;
|
||||
|
||||
Color overlayColor;
|
||||
double finalOpacity;
|
||||
|
||||
if (_lyricsWindowStatus.IsAdaptToEnvironment)
|
||||
{
|
||||
// <20><><EFBFBD><EFBFBD>Ӧɫ
|
||||
overlayColor = _immersiveBgColorTransition.Value;
|
||||
finalOpacity = _immersiveBgOpacityTransition.Value * lyricsBg.PureColorOverlayOpacity / 100.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// ר<><D7A8>ɫ
|
||||
overlayColor = _accentColor1Transition.Value;
|
||||
finalOpacity = lyricsBg.PureColorOverlayOpacity / 100.0;
|
||||
}
|
||||
|
||||
_pureColorRenderer.Draw(
|
||||
args.DrawingSession,
|
||||
bounds,
|
||||
overlayColor,
|
||||
finalOpacity,
|
||||
lyricsBg.IsPureColorOverlayEnabled
|
||||
);
|
||||
|
||||
_fluidRenderer.Opacity = lyricsBg.FluidOverlayOpacity / 100.0;
|
||||
_fluidRenderer.IsEnabled = lyricsBg.IsFluidOverlayEnabled;
|
||||
_fluidRenderer.Draw(sender, args.DrawingSession);
|
||||
|
||||
_snowRenderer.Draw(sender, args.DrawingSession);
|
||||
|
||||
_fogRenderer.Draw(sender, args.DrawingSession);
|
||||
|
||||
_lyricsRenderer.Draw(
|
||||
control: sender,
|
||||
ds: args.DrawingSession,
|
||||
lines: _renderLyricsLines,
|
||||
playingLineIndex: _playingLineIndex,
|
||||
mouseHoverLineIndex: _mouseHoverLineIndex,
|
||||
isMousePressing: _isMousePressing,
|
||||
startVisibleIndex: _visibleRange.Start,
|
||||
endVisibleIndex: _visibleRange.End,
|
||||
lyricsX: _renderLyricsStartX,
|
||||
lyricsY: _renderLyricsStartY,
|
||||
lyricsWidth: _renderLyricsWidth,
|
||||
lyricsHeight: _renderLyricsHeight,
|
||||
userScrollOffset: _mouseYScrollTransition.Value,
|
||||
lyricsOpacity: _renderLyricsOpacity,
|
||||
playingLineTopOffsetFactor: lyricsStyle.PlayingLineTopOffset / 100.0,
|
||||
windowStatus: _lyricsWindowStatus,
|
||||
strokeColor: _albumArtThemeColors.StrokeFontColor,
|
||||
bgColor: _albumArtThemeColors.BgFontColor,
|
||||
fgColor: _albumArtThemeColors.FgFontColor,
|
||||
getPlaybackState: (lineIndex) =>
|
||||
{
|
||||
if (_renderLyricsLines == null) return new LinePlaybackState();
|
||||
|
||||
var line = _renderLyricsLines.ElementAtOrDefault(lineIndex);
|
||||
if (line == null) return new LinePlaybackState();
|
||||
|
||||
var nextLine = _renderLyricsLines.ElementAtOrDefault(lineIndex + 1);
|
||||
|
||||
return _synchronizer.GetLinePlayingProgress(
|
||||
_songPositionWithOffset.TotalMilliseconds,
|
||||
line,
|
||||
nextLine,
|
||||
songDuration,
|
||||
isForceWordByWord
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
if (_spectrumAnalyzer.IsCapturing)
|
||||
{
|
||||
_spectrumRenderer.Draw(
|
||||
resourceCreator: sender,
|
||||
ds: args.DrawingSession,
|
||||
spectrumData: _spectrumAnalyzer?.SmoothSpectrum,
|
||||
barCount: _spectrumAnalyzer?.BarCount ?? 1,
|
||||
isEnabled: lyricsBg.IsSpectrumOverlayEnabled,
|
||||
placement: lyricsBg.SpectrumPlacement,
|
||||
style: lyricsBg.SpectrumStyle,
|
||||
canvasWidth: sender.Size.Width,
|
||||
canvasHeight: sender.Size.Height,
|
||||
fillColor: _albumArtThemeColors.BgFontColor
|
||||
);
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
//args.DrawingSession.DrawText(
|
||||
// $"Lyrics render start pos: ({(int)_renderLyricsStartX}, {(int)_renderLyricsStartY})\n" +
|
||||
// $"Lyrics render size: [{(int)_renderLyricsWidth} x {(int)_renderLyricsHeight}]\n" +
|
||||
// $"Lyrics actual height: {LyricsLayoutManager.CalculateActualHeight(_renderLyricsLines)}\n" +
|
||||
// $"Playing line (idx): {_playingLineIndex}\n" +
|
||||
// $"Mouse hovering line (idx): {_mouseHoverLineIndex}\n" +
|
||||
// $"Visible lines range (idx): [{_visibleRange.Start}, {_visibleRange.End}]\n" +
|
||||
// $"Total line count: {LyricsLayoutManager.CalculateMaxRange(_renderLyricsLines).End + 1}\n" +
|
||||
// $"Played: {_songPosition} / {TimeSpan.FromMilliseconds(_mediaSessionsService.CurrentSongInfo?.DurationMs ?? 0)}\n" +
|
||||
// $"Y offset: {_canvasYScrollTransition.Value}\n" +
|
||||
// $"User scroll offset: {_mouseYScrollTransition.Value}",
|
||||
// new Vector2(0, 0), Colors.Red);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
private void Canvas_Update(ICanvasAnimatedControl sender, CanvasAnimatedUpdateEventArgs args)
|
||||
{
|
||||
if (_lyricsWindowStatus == null) return;
|
||||
|
||||
var lyricsBg = _lyricsWindowStatus.LyricsBackgroundSettings;
|
||||
var lyricsStyle = _lyricsWindowStatus.LyricsStyleSettings;
|
||||
var lyricsEffect = _lyricsWindowStatus.LyricsEffectSettings;
|
||||
var lyricsData = _mediaSessionsService.CurrentLyricsData;
|
||||
|
||||
TimeSpan elapsedTime = args.Timing.ElapsedTime;
|
||||
|
||||
_accentColor1Transition.Update(elapsedTime);
|
||||
_accentColor2Transition.Update(elapsedTime);
|
||||
_accentColor3Transition.Update(elapsedTime);
|
||||
_accentColor4Transition.Update(elapsedTime);
|
||||
|
||||
_immersiveBgOpacityTransition.Update(elapsedTime);
|
||||
_immersiveBgColorTransition.Update(elapsedTime);
|
||||
|
||||
UpdatePlaybackState(elapsedTime);
|
||||
|
||||
TriggerRelayout();
|
||||
|
||||
#region UpdatePlayingLineIndex
|
||||
|
||||
int newPlayingIndex = _synchronizer.GetCurrentLineIndex(_songPositionWithOffset.TotalMilliseconds, lyricsData);
|
||||
bool isPlayingLineChanged = newPlayingIndex != _playingLineIndex;
|
||||
_playingLineIndex = newPlayingIndex;
|
||||
|
||||
#endregion
|
||||
|
||||
#region UpdateTargetScrollOffset
|
||||
|
||||
if (isPlayingLineChanged || _isLayoutChanged)
|
||||
{
|
||||
var targetScroll = LyricsLayoutManager.CalculateTargetScrollOffset(_renderLyricsLines, _playingLineIndex);
|
||||
if (targetScroll.HasValue) _canvasTargetScrollOffset = targetScroll.Value;
|
||||
|
||||
_canvasYScrollTransition.SetEasingType(lyricsEffect.LyricsScrollEasingType);
|
||||
_canvasYScrollTransition.SetDuration(lyricsEffect.LyricsScrollDuration / 1000.0);
|
||||
_canvasYScrollTransition.StartTransition(_canvasTargetScrollOffset, _isLayoutChanged);
|
||||
}
|
||||
_canvasYScrollTransition.Update(elapsedTime);
|
||||
|
||||
#endregion
|
||||
|
||||
_mouseYScrollTransition.Update(elapsedTime);
|
||||
|
||||
_mouseHoverLineIndex = LyricsLayoutManager.FindMouseHoverLineIndex(
|
||||
_renderLyricsLines,
|
||||
_isMouseInLyricsArea,
|
||||
_mousePosition,
|
||||
_canvasYScrollTransition.Value + _mouseYScrollTransition.Value,
|
||||
_renderLyricsStartY,
|
||||
_renderLyricsHeight,
|
||||
lyricsStyle.PlayingLineTopOffset / 100.0
|
||||
);
|
||||
|
||||
_visibleRange = LyricsLayoutManager.CalculateVisibleRange(
|
||||
_renderLyricsLines,
|
||||
_canvasYScrollTransition.Value + _mouseYScrollTransition.Value, // <20><>ǰ<EFBFBD><C7B0><EFBFBD><EFBFBD>λ<EFBFBD><CEBB>
|
||||
_renderLyricsStartY,
|
||||
_renderLyricsHeight,
|
||||
sender.Size.Height,
|
||||
lyricsStyle.PlayingLineTopOffset / 100.0
|
||||
);
|
||||
|
||||
var maxRange = LyricsLayoutManager.CalculateMaxRange(_renderLyricsLines);
|
||||
|
||||
_animator.UpdateLines(
|
||||
_renderLyricsLines,
|
||||
_isMouseScrolling ? maxRange.Start : _visibleRange.Start,
|
||||
_isMouseScrolling ? maxRange.End : _visibleRange.End,
|
||||
_playingLineIndex,
|
||||
sender.Size.Height,
|
||||
_canvasTargetScrollOffset,
|
||||
lyricsStyle.PlayingLineTopOffset / 100.0,
|
||||
_lyricsWindowStatus.LyricsStyleSettings,
|
||||
_lyricsWindowStatus.LyricsEffectSettings,
|
||||
_canvasYScrollTransition,
|
||||
_albumArtThemeColors.BgFontColor,
|
||||
_albumArtThemeColors.FgFontColor,
|
||||
elapsedTime,
|
||||
_isMouseScrolling,
|
||||
_isLayoutChanged,
|
||||
isPlayingLineChanged,
|
||||
_isMouseScrollingChanged
|
||||
);
|
||||
|
||||
_isMouseScrollingChanged = false;
|
||||
|
||||
_lyricsRenderer.CalculateLyrics3DMatrix(
|
||||
lyricsEffect: lyricsEffect,
|
||||
lyricsX: _renderLyricsStartX,
|
||||
lyricsY: _renderLyricsStartY,
|
||||
lyricsWidth: _renderLyricsWidth,
|
||||
canvasHeight: sender.Size.Height
|
||||
);
|
||||
|
||||
_isLayoutChanged = false;
|
||||
|
||||
if (_fluidRenderer.IsEnabled)
|
||||
{
|
||||
_fluidRenderer.UpdateColors(
|
||||
_accentColor1Transition.Value,
|
||||
_accentColor2Transition.Value,
|
||||
_accentColor3Transition.Value,
|
||||
_accentColor4Transition.Value
|
||||
);
|
||||
_fluidRenderer.Update(elapsedTime);
|
||||
}
|
||||
|
||||
_snowRenderer.IsEnabled = lyricsBg.IsSnowFlakeOverlayEnabled;
|
||||
_snowRenderer.Amount = lyricsBg.SnowFlakeOverlayAmount / 100f;
|
||||
_snowRenderer.Speed = lyricsBg.SnowFlakeOverlaySpeed;
|
||||
_snowRenderer.Update(elapsedTime.TotalSeconds);
|
||||
|
||||
_fogRenderer.IsEnabled = lyricsBg.IsFogOverlayEnabled;
|
||||
_fogRenderer.Update(elapsedTime.TotalSeconds);
|
||||
|
||||
if (lyricsBg.IsSpectrumOverlayEnabled && !_spectrumAnalyzer.IsCapturing)
|
||||
{
|
||||
_spectrumAnalyzer.BarCount = lyricsBg.SpectrumCount;
|
||||
_spectrumAnalyzer.StartCapture();
|
||||
}
|
||||
else if (!lyricsBg.IsSpectrumOverlayEnabled && _spectrumAnalyzer.IsCapturing)
|
||||
{
|
||||
_spectrumAnalyzer.StopCapture();
|
||||
}
|
||||
if (_spectrumAnalyzer.IsCapturing)
|
||||
{
|
||||
_spectrumAnalyzer.UpdateSmoothSpectrum();
|
||||
}
|
||||
}
|
||||
|
||||
private void Canvas_Unloaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_fluidRenderer.Dispose();
|
||||
_snowRenderer.Dispose();
|
||||
_fogRenderer.Dispose();
|
||||
_spectrumRenderer.Dispose();
|
||||
|
||||
_renderLyricsLines = null;
|
||||
|
||||
DisposeAnalyzer();
|
||||
|
||||
Canvas.RemoveFromVisualTree();
|
||||
Canvas = null;
|
||||
}
|
||||
|
||||
private async void Canvas_CreateResources(CanvasAnimatedControl sender, Microsoft.Graphics.Canvas.UI.CanvasCreateResourcesEventArgs args)
|
||||
{
|
||||
args.TrackAsyncAction(_fluidRenderer.LoadResourcesAsync().AsAsyncAction());
|
||||
_snowRenderer.LoadResources();
|
||||
_fogRenderer.LoadResources();
|
||||
|
||||
_isLayoutChanged = true;
|
||||
TriggerRelayout();
|
||||
}
|
||||
|
||||
// ====
|
||||
|
||||
private void DisposeAnalyzer()
|
||||
{
|
||||
if (_spectrumAnalyzer.IsCapturing)
|
||||
{
|
||||
_spectrumAnalyzer.StopCapture();
|
||||
}
|
||||
_spectrumAnalyzer.Dispose();
|
||||
}
|
||||
|
||||
private void TriggerRelayout()
|
||||
{
|
||||
if (_renderLyricsLines == null || !_isLayoutChanged || _lyricsWindowStatus == null) return;
|
||||
|
||||
LyricsLayoutManager.MeasureAndArrange(
|
||||
resourceCreator: Canvas,
|
||||
lines: _renderLyricsLines,
|
||||
status: _lyricsWindowStatus,
|
||||
appSettings: _settingsService.AppSettings,
|
||||
canvasWidth: Canvas.Size.Width,
|
||||
canvasHeight: Canvas.Size.Height,
|
||||
lyricsWidth: _renderLyricsWidth,
|
||||
lyricsHeight: _renderLyricsHeight
|
||||
);
|
||||
}
|
||||
|
||||
private void UpdatePlaybackState(TimeSpan elapsedTime)
|
||||
{
|
||||
if (_mediaSessionsService.CurrentIsPlaying)
|
||||
{
|
||||
_songPosition += elapsedTime;
|
||||
_totalPlayedTime += elapsedTime;
|
||||
_songPositionWithOffset = _songPosition + TimeSpan.FromMilliseconds(_mediaSessionsService.CurrentMediaSourceProviderInfo?.PositionOffset ?? 0);
|
||||
CheckAndScrobbleLastFM();
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckAndScrobbleLastFM()
|
||||
{
|
||||
bool isEnabled = _mediaSessionsService.CurrentMediaSourceProviderInfo?.IsLastFMTrackEnabled ?? false;
|
||||
if (!isEnabled || _isLastFMTracked) return;
|
||||
|
||||
var songInfo = _mediaSessionsService.CurrentSongInfo;
|
||||
if (songInfo == null || songInfo.Duration <= 0) return;
|
||||
|
||||
if (_totalPlayedTime.TotalSeconds >= songInfo.Duration * 0.5)
|
||||
{
|
||||
_isLastFMTracked = true;
|
||||
_lastFMService.TrackAsync(songInfo);
|
||||
}
|
||||
}
|
||||
|
||||
private void ResetPlaybackState()
|
||||
{
|
||||
_songPosition = TimeSpan.Zero;
|
||||
_totalPlayedTime = TimeSpan.Zero;
|
||||
_isLastFMTracked = false;
|
||||
}
|
||||
|
||||
private void UpdateRenderLyricsLines()
|
||||
{
|
||||
_renderLyricsLines = null;
|
||||
_renderLyricsLines = _mediaSessionsService.CurrentLyricsData?.LyricsLines.Select(x => new RenderLyricsLine()
|
||||
{
|
||||
LyricsSyllables = x.LyricsSyllables,
|
||||
StartMs = x.StartMs,
|
||||
EndMs = x.EndMs,
|
||||
PhoneticText = x.PhoneticText,
|
||||
OriginalText = x.OriginalText,
|
||||
TranslatedText = x.TranslatedText
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
public void Receive(PropertyChangedMessage<TimeSpan> message)
|
||||
{
|
||||
if (message.Sender is IMediaSessionsService)
|
||||
{
|
||||
if (message.PropertyName == nameof(IMediaSessionsService.CurrentPosition))
|
||||
{
|
||||
var realPosition = message.NewValue;
|
||||
|
||||
var diff = Math.Abs(_songPosition.TotalMilliseconds - realPosition.TotalMilliseconds);
|
||||
var timelineSyncThreshold = _mediaSessionsService.CurrentMediaSourceProviderInfo?.TimelineSyncThreshold ?? 0;
|
||||
|
||||
// ƫ<><C6AB> or seek
|
||||
if (diff >= timelineSyncThreshold)
|
||||
{
|
||||
_songPosition = realPosition;
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˿<EFBFBD>ͷ<EFBFBD><CDB7><EFBFBD><EFBFBD><EFBFBD><EFBFBD> LastFM ͳ<><CDB3>״̬
|
||||
if (_songPosition.TotalSeconds <= 1)
|
||||
{
|
||||
_totalPlayedTime = TimeSpan.Zero;
|
||||
_isLastFMTracked = false;
|
||||
}
|
||||
}
|
||||
|
||||
// <20>϶<EFBFBD><CFB6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȴ<EFBFBD><C8B4><EFBFBD><EFBFBD><EFBFBD>
|
||||
if (diff >= timelineSyncThreshold + 5000)
|
||||
{
|
||||
_isLayoutChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Receive(PropertyChangedMessage<LyricsData?> message)
|
||||
{
|
||||
if (message.Sender is IMediaSessionsService)
|
||||
{
|
||||
if (message.PropertyName == nameof(IMediaSessionsService.CurrentLyricsData))
|
||||
{
|
||||
UpdateRenderLyricsLines();
|
||||
_isLayoutChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Receive(PropertyChangedMessage<SongInfo?> message)
|
||||
{
|
||||
if (message.Sender is IMediaSessionsService)
|
||||
{
|
||||
if (message.PropertyName == nameof(IMediaSessionsService.CurrentSongInfo))
|
||||
{
|
||||
ResetPlaybackState();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Receive(PropertyChangedMessage<int> message)
|
||||
{
|
||||
if (message.Sender == LyricsWindowStatus?.LyricsStyleSettings)
|
||||
{
|
||||
if (message.PropertyName == nameof(LyricsStyleSettings.PhoneticLyricsFontSize))
|
||||
{
|
||||
_isLayoutChanged = true;
|
||||
}
|
||||
else if (message.PropertyName == nameof(LyricsStyleSettings.OriginalLyricsFontSize))
|
||||
{
|
||||
_isLayoutChanged = true;
|
||||
}
|
||||
else if (message.PropertyName == nameof(LyricsStyleSettings.TranslatedLyricsFontSize))
|
||||
{
|
||||
_isLayoutChanged = true;
|
||||
}
|
||||
else if (message.PropertyName == nameof(LyricsStyleSettings.LyricsFontStrokeWidth))
|
||||
{
|
||||
_isLayoutChanged = true;
|
||||
}
|
||||
else if (message.PropertyName == nameof(LyricsStyleSettings.PlayingLineTopOffset))
|
||||
{
|
||||
_isLayoutChanged = true;
|
||||
}
|
||||
else if (message.PropertyName == nameof(LyricsStyleSettings.PhoneticLyricsOpacity))
|
||||
{
|
||||
_isLayoutChanged = true;
|
||||
}
|
||||
else if (message.PropertyName == nameof(LyricsStyleSettings.OriginalLyricsOpacity))
|
||||
{
|
||||
_isLayoutChanged = true;
|
||||
}
|
||||
else if (message.PropertyName == nameof(LyricsStyleSettings.TranslatedLyricsOpacity))
|
||||
{
|
||||
_isLayoutChanged = true;
|
||||
}
|
||||
}
|
||||
else if (message.Sender == LyricsWindowStatus?.LyricsEffectSettings)
|
||||
{
|
||||
if (message.PropertyName == nameof(LyricsEffectSettings.LyricsScrollDuration))
|
||||
{
|
||||
_isLayoutChanged = true;
|
||||
}
|
||||
else if (message.PropertyName == nameof(LyricsEffectSettings.LyricsScrollTopDuration))
|
||||
{
|
||||
_isLayoutChanged = true;
|
||||
}
|
||||
else if (message.PropertyName == nameof(LyricsEffectSettings.LyricsScrollBottomDuration))
|
||||
{
|
||||
_isLayoutChanged = true;
|
||||
}
|
||||
else if (message.PropertyName == nameof(LyricsEffectSettings.LyricsScrollTopDelay))
|
||||
{
|
||||
_isLayoutChanged = true;
|
||||
}
|
||||
else if (message.PropertyName == nameof(LyricsEffectSettings.LyricsScrollBottomDelay))
|
||||
{
|
||||
_isLayoutChanged = true;
|
||||
}
|
||||
else if (message.PropertyName == nameof(LyricsEffectSettings.FanLyricsAngle))
|
||||
{
|
||||
_isLayoutChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Receive(PropertyChangedMessage<double> message)
|
||||
{
|
||||
if (message.Sender == LyricsWindowStatus?.LyricsStyleSettings)
|
||||
{
|
||||
if (message.PropertyName == nameof(LyricsStyleSettings.LyricsLineSpacingFactor))
|
||||
{
|
||||
_isLayoutChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Receive(PropertyChangedMessage<bool> message)
|
||||
{
|
||||
if (message.Sender == LyricsWindowStatus?.LyricsEffectSettings)
|
||||
{
|
||||
if (message.PropertyName == nameof(LyricsEffectSettings.IsFanLyricsEnabled))
|
||||
{
|
||||
_isLayoutChanged = true;
|
||||
}
|
||||
else if (message.PropertyName == nameof(LyricsEffectSettings.IsLyricsBlurEffectEnabled))
|
||||
{
|
||||
_isLayoutChanged = true;
|
||||
}
|
||||
}
|
||||
else if (message.Sender == LyricsWindowStatus?.LyricsStyleSettings)
|
||||
{
|
||||
if (message.PropertyName == nameof(LyricsStyleSettings.IsDynamicLyricsFontSize))
|
||||
{
|
||||
_isLayoutChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Receive(PropertyChangedMessage<TextAlignmentType> message)
|
||||
{
|
||||
if (message.Sender == LyricsWindowStatus?.LyricsStyleSettings)
|
||||
{
|
||||
if (message.PropertyName == nameof(LyricsStyleSettings.LyricsAlignmentType))
|
||||
{
|
||||
_isLayoutChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Receive(PropertyChangedMessage<LyricsFontWeight> message)
|
||||
{
|
||||
if (message.Sender == LyricsWindowStatus?.LyricsStyleSettings)
|
||||
{
|
||||
if (message.PropertyName == nameof(LyricsStyleSettings.LyricsFontWeight))
|
||||
{
|
||||
_isLayoutChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Receive(PropertyChangedMessage<string> message)
|
||||
{
|
||||
if (message.Sender == LyricsWindowStatus?.LyricsStyleSettings)
|
||||
{
|
||||
if (message.PropertyName == nameof(LyricsStyleSettings.LyricsCJKFontFamily))
|
||||
{
|
||||
_isLayoutChanged = true;
|
||||
}
|
||||
else if (message.PropertyName == nameof(LyricsStyleSettings.LyricsWesternFontFamily))
|
||||
{
|
||||
_isLayoutChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -18,144 +18,85 @@
|
||||
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
|
||||
|
||||
<!-- Effect -->
|
||||
|
||||
<TextBlock
|
||||
x:Uid="SettingsPageLyricsEffect"
|
||||
Style="{StaticResource SettingsSectionHeaderTextBlockStyle}"
|
||||
Text="Effect" />
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageLyricsVerticalEdgeOpacity" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<local:ExtendedSlider
|
||||
x:Uid="SettingsPageLyricsVerticalEdgeOpacitySlider"
|
||||
Default="0"
|
||||
Maximum="100"
|
||||
Minimum="0"
|
||||
Unit="%"
|
||||
Value="{x:Bind LyricsEffectSettings.LyricsVerticalEdgeOpacity, Mode=TwoWay}" />
|
||||
<!-- 模糊效果 -->
|
||||
<dev:SettingsCard x:Uid="SettingsPageLyricsBlurEffect" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ToggleSwitch IsOn="{x:Bind LyricsEffectSettings.IsLyricsBlurEffectEnabled, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageLyricsBlurAmount" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<local:ExtendedSlider
|
||||
x:Uid="SettingsPageLyricsBlurAmountExtendedSlider"
|
||||
Default="5"
|
||||
Maximum="10"
|
||||
Minimum="0"
|
||||
Value="{x:Bind LyricsEffectSettings.LyricsBlurAmount, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageLyricsLineFade" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ToggleSwitch IsOn="{x:Bind LyricsEffectSettings.IsLyricsLineFadeEnabled, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
<!-- 高亮 -->
|
||||
<dev:SettingsExpander x:Uid="SettingsPageLyricsHighlight" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<dev:SettingsExpander.Items>
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPagePhoneticText">
|
||||
<local:ExtendedSlider
|
||||
Default="60"
|
||||
Frequency="5"
|
||||
Maximum="100"
|
||||
Minimum="0"
|
||||
Unit="%"
|
||||
Value="{x:Bind LyricsEffectSettings.PhoneticLyricsHighlightAmount, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageLyricsHighlightScope">
|
||||
<ComboBox SelectedIndex="{x:Bind LyricsEffectSettings.OriginalLyricsHighlightScope, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsRendingScopeCurrentChar" />
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsRendingScopeLineStartToCurrentChar" />
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsRendingScopeCurrentLine" />
|
||||
</ComboBox>
|
||||
</dev:SettingsCard>
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageOriginalText">
|
||||
<local:ExtendedSlider
|
||||
Default="60"
|
||||
Frequency="5"
|
||||
Maximum="100"
|
||||
Minimum="0"
|
||||
Unit="%"
|
||||
Value="{x:Bind LyricsEffectSettings.OriginalLyricsHighlightAmount, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageTranslatedText">
|
||||
<local:ExtendedSlider
|
||||
Default="60"
|
||||
Frequency="5"
|
||||
Maximum="100"
|
||||
Minimum="0"
|
||||
Unit="%"
|
||||
Value="{x:Bind LyricsEffectSettings.TranslatedLyricsHighlightAmount, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
</dev:SettingsExpander.Items>
|
||||
</dev:SettingsExpander>
|
||||
|
||||
<!-- 阴影 -->
|
||||
<dev:SettingsExpander
|
||||
x:Uid="SettingsPageLyricsShadow"
|
||||
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}"
|
||||
IsExpanded="{x:Bind LyricsEffectSettings.IsLyricsShadowEnabled, Mode=OneWay}">
|
||||
<ToggleSwitch IsOn="{x:Bind LyricsEffectSettings.IsLyricsShadowEnabled, Mode=TwoWay}" />
|
||||
<dev:SettingsExpander.Items>
|
||||
<dev:SettingsCard x:Uid="SettingsPageScope" IsEnabled="{x:Bind LyricsEffectSettings.IsLyricsShadowEnabled, Mode=OneWay}">
|
||||
<ComboBox SelectedIndex="{x:Bind LyricsEffectSettings.LyricsShadowScope, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsRendingScopeCurrentChar" />
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsRendingScopeLineStartToCurrentChar" />
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsRendingScopeCurrentLine" />
|
||||
</ComboBox>
|
||||
</dev:SettingsCard>
|
||||
<dev:SettingsCard x:Uid="SettingsPageAmount" IsEnabled="{x:Bind LyricsEffectSettings.IsLyricsShadowEnabled, Mode=OneWay}">
|
||||
<local:ExtendedSlider
|
||||
Default="8"
|
||||
Maximum="20"
|
||||
Minimum="1"
|
||||
Value="{x:Bind LyricsEffectSettings.LyricsShadowAmount, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
</dev:SettingsExpander.Items>
|
||||
</dev:SettingsExpander>
|
||||
|
||||
<!-- 辉光效果 -->
|
||||
<dev:SettingsExpander
|
||||
x:Uid="SettingsPageLyricsGlowEffect"
|
||||
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}"
|
||||
IsExpanded="{x:Bind LyricsEffectSettings.IsLyricsGlowEffectEnabled, Mode=OneWay}">
|
||||
<dev:SettingsExpander x:Uid="SettingsPageLyricsGlowEffect" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ToggleSwitch IsOn="{x:Bind LyricsEffectSettings.IsLyricsGlowEffectEnabled, Mode=TwoWay}" />
|
||||
<dev:SettingsExpander.Items>
|
||||
<dev:SettingsCard x:Uid="SettingsPageScope" IsEnabled="{x:Bind LyricsEffectSettings.IsLyricsGlowEffectEnabled, Mode=OneWay}">
|
||||
<dev:SettingsCard x:Uid="SettingsPageScope">
|
||||
<ComboBox SelectedIndex="{x:Bind LyricsEffectSettings.LyricsGlowEffectScope, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsRendingScopeCurrentChar" />
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsRendingScopeLineStartToCurrentChar" />
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsRendingScopeCurrentLine" />
|
||||
<ComboBoxItem x:Uid="SettingsPageEffectScopeLongDurationSyllable" />
|
||||
<ComboBoxItem x:Uid="SettingsPageEffectLineStartToCurrentChar" />
|
||||
</ComboBox>
|
||||
</dev:SettingsCard>
|
||||
<dev:SettingsCard x:Uid="SettingsPageAmount" IsEnabled="{x:Bind LyricsEffectSettings.IsLyricsGlowEffectEnabled, Mode=OneWay}">
|
||||
<dev:SettingsCard x:Uid="SettingsPageLongSyllableDuration">
|
||||
<local:ExtendedSlider
|
||||
Default="8"
|
||||
Maximum="20"
|
||||
Minimum="1"
|
||||
Default="700"
|
||||
Maximum="1000"
|
||||
Minimum="0"
|
||||
Unit="ms"
|
||||
Value="{x:Bind LyricsEffectSettings.LyricsGlowEffectLongSyllableDuration, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
<dev:SettingsCard x:Uid="SettingsPageAutoAdjust">
|
||||
<ToggleSwitch IsOn="{x:Bind LyricsEffectSettings.IsLyricsGlowEffectAmountAutoAdjust, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
<dev:SettingsCard x:Uid="SettingsPageAmount" IsEnabled="{x:Bind LyricsEffectSettings.IsLyricsGlowEffectAmountAutoAdjust, Converter={StaticResource BoolNegationConverter}, Mode=OneWay}">
|
||||
<local:ExtendedSlider
|
||||
Maximum="16"
|
||||
Minimum="0"
|
||||
Value="{x:Bind LyricsEffectSettings.LyricsGlowEffectAmount, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
</dev:SettingsExpander.Items>
|
||||
</dev:SettingsExpander>
|
||||
|
||||
<!-- 缩放效果 -->
|
||||
<dev:SettingsExpander x:Uid="SettingsPageLyricsScaleEffect" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ToggleSwitch IsOn="{x:Bind LyricsEffectSettings.IsLyricsScaleEffectEnabled, Mode=TwoWay}" />
|
||||
<dev:SettingsExpander.Items>
|
||||
<dev:SettingsCard x:Uid="SettingsPageLongSyllableDuration">
|
||||
<local:ExtendedSlider
|
||||
Default="700"
|
||||
Maximum="1000"
|
||||
Minimum="0"
|
||||
Unit="ms"
|
||||
Value="{x:Bind LyricsEffectSettings.LyricsScaleEffectLongSyllableDuration, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
<dev:SettingsCard x:Uid="SettingsPageAutoAdjust">
|
||||
<ToggleSwitch IsOn="{x:Bind LyricsEffectSettings.IsLyricsScaleEffectAmountAutoAdjust, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
<dev:SettingsCard x:Uid="SettingsPageAmount" IsEnabled="{x:Bind LyricsEffectSettings.IsLyricsScaleEffectAmountAutoAdjust, Converter={StaticResource BoolNegationConverter}, Mode=OneWay}">
|
||||
<local:ExtendedSlider
|
||||
Default="115"
|
||||
Maximum="200"
|
||||
Minimum="100"
|
||||
Unit="%"
|
||||
Value="{x:Bind LyricsEffectSettings.LyricsScaleEffectAmount, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
</dev:SettingsExpander.Items>
|
||||
</dev:SettingsExpander>
|
||||
|
||||
<!-- 浮动动画 -->
|
||||
<dev:SettingsExpander
|
||||
x:Uid="SettingsPageLyricsFloatAnimation"
|
||||
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}"
|
||||
IsExpanded="True">
|
||||
<dev:SettingsExpander x:Uid="SettingsPageLyricsFloatAnimation" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ToggleSwitch IsOn="{x:Bind LyricsEffectSettings.IsLyricsFloatAnimationEnabled, Mode=TwoWay}" />
|
||||
<dev:SettingsExpander.Items>
|
||||
<dev:SettingsCard x:Uid="SettingsPageAmount" IsEnabled="{x:Bind LyricsEffectSettings.IsLyricsGlowEffectEnabled, Mode=OneWay}">
|
||||
<dev:SettingsCard x:Uid="SettingsPageAutoAdjust">
|
||||
<ToggleSwitch IsOn="{x:Bind LyricsEffectSettings.IsLyricsFloatAnimationAmountAutoAdjust, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
<dev:SettingsCard x:Uid="SettingsPageAmount" IsEnabled="{x:Bind LyricsEffectSettings.IsLyricsFloatAnimationAmountAutoAdjust, Converter={StaticResource BoolNegationConverter}, Mode=OneWay}">
|
||||
<local:ExtendedSlider
|
||||
Default="1"
|
||||
Maximum="4"
|
||||
Minimum="1"
|
||||
Value="{x:Bind LyricsEffectSettings.LyricsFloatAmount, Mode=TwoWay}" />
|
||||
Default="4"
|
||||
Maximum="16"
|
||||
Minimum="0"
|
||||
Value="{x:Bind LyricsEffectSettings.LyricsFloatAnimationAmount, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
</dev:SettingsExpander.Items>
|
||||
</dev:SettingsExpander>
|
||||
@@ -224,7 +165,7 @@
|
||||
</dev:SettingsExpander.Items>
|
||||
</dev:SettingsExpander>
|
||||
|
||||
<!-- 滚动动画 -->
|
||||
<!-- 歌词动画 -->
|
||||
<dev:SettingsExpander x:Uid="SettingsPageScrollEasing" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ComboBox SelectedIndex="{x:Bind LyricsEffectSettings.LyricsScrollEasingType, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||
<ComboBoxItem x:Uid="SettingsPageEasingTypeLinear" />
|
||||
@@ -246,7 +187,7 @@
|
||||
Default="500"
|
||||
Frequency="50"
|
||||
Maximum="1000"
|
||||
Minimum="50"
|
||||
Minimum="0"
|
||||
Unit="ms"
|
||||
Value="{x:Bind LyricsEffectSettings.LyricsScrollTopDuration, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
@@ -255,7 +196,7 @@
|
||||
Default="500"
|
||||
Frequency="50"
|
||||
Maximum="1000"
|
||||
Minimum="50"
|
||||
Minimum="0"
|
||||
Unit="ms"
|
||||
Value="{x:Bind LyricsEffectSettings.LyricsScrollDuration, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
@@ -264,7 +205,7 @@
|
||||
Default="500"
|
||||
Frequency="50"
|
||||
Maximum="1000"
|
||||
Minimum="50"
|
||||
Minimum="0"
|
||||
Unit="ms"
|
||||
Value="{x:Bind LyricsEffectSettings.LyricsScrollBottomDuration, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
<Grid Grid.Column="0">
|
||||
<ScrollViewer>
|
||||
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
|
||||
|
||||
<TextBlock x:Uid="LyricsSearchControlSongInfoMapping" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
|
||||
<Grid
|
||||
@@ -34,22 +35,32 @@
|
||||
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||
CornerRadius="4">
|
||||
<StackPanel Spacing="6">
|
||||
<TextBlock x:Uid="LyricsSearchControlTitle" />
|
||||
<TextBlock
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
IsTextSelectionEnabled="True"
|
||||
Text="{x:Bind ViewModel.MappedSongSearchQuery.OriginalTitle, Mode=OneWay}"
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<TextBlock x:Uid="LyricsSearchControlMappedAs" VerticalAlignment="Center" />
|
||||
<TextBox Text="{x:Bind ViewModel.MappedSongSearchQuery.MappedTitle, Mode=TwoWay}" TextWrapping="Wrap" />
|
||||
<Button
|
||||
VerticalAlignment="Center"
|
||||
Command="{x:Bind ViewModel.ResetMappedTitleCommand}"
|
||||
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
FontSize=12,
|
||||
Glyph=}"
|
||||
Style="{StaticResource GhostButtonStyle}" />
|
||||
<local:PropertyRow x:Uid="LyricsSearchControlTitle" Value="{x:Bind ViewModel.MappedSongSearchQuery.OriginalTitle, Mode=OneWay}" />
|
||||
|
||||
<Grid ColumnSpacing="6">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock
|
||||
x:Uid="LyricsSearchControlMappedAs"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center" />
|
||||
<TextBox
|
||||
Grid.Column="1"
|
||||
Text="{x:Bind ViewModel.MappedSongSearchQuery.MappedTitle, Mode=TwoWay}"
|
||||
TextWrapping="Wrap" />
|
||||
<Button
|
||||
Grid.Column="2"
|
||||
VerticalAlignment="Center"
|
||||
Command="{x:Bind ViewModel.ResetMappedTitleCommand}"
|
||||
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
FontSize=12,
|
||||
Glyph=}"
|
||||
Style="{StaticResource GhostButtonStyle}" />
|
||||
</Grid>
|
||||
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
@@ -60,22 +71,44 @@
|
||||
CornerRadius="4">
|
||||
<StackPanel Spacing="6">
|
||||
|
||||
<TextBlock x:Uid="LyricsSearchControlArtist" />
|
||||
<TextBlock
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
IsTextSelectionEnabled="True"
|
||||
Text="{x:Bind ViewModel.MappedSongSearchQuery.OriginalArtist, Mode=OneWay}"
|
||||
TextWrapping="Wrap" />
|
||||
<local:PropertyRow x:Uid="LyricsSearchControlArtist" Value="{x:Bind ViewModel.MappedSongSearchQuery.OriginalArtist, Mode=OneWay}" />
|
||||
|
||||
<TextBlock x:Uid="LyricsSearchControlMappedAs" VerticalAlignment="Center" />
|
||||
<TextBox Text="{x:Bind ViewModel.MappedSongSearchQuery.MappedArtist, Mode=TwoWay}" TextWrapping="Wrap" />
|
||||
<Button
|
||||
VerticalAlignment="Center"
|
||||
Command="{x:Bind ViewModel.ResetMappedArtistCommand}"
|
||||
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
FontSize=12,
|
||||
Glyph=}"
|
||||
Style="{StaticResource GhostButtonStyle}" />
|
||||
<Grid ColumnSpacing="6">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock
|
||||
x:Uid="LyricsSearchControlMappedAs"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center" />
|
||||
<TextBox
|
||||
Grid.Column="1"
|
||||
Text="{x:Bind ViewModel.MappedSongSearchQuery.MappedArtist, Mode=TwoWay}"
|
||||
TextWrapping="Wrap" />
|
||||
<Button
|
||||
Grid.Column="2"
|
||||
VerticalAlignment="Center"
|
||||
Command="{x:Bind ViewModel.ResetMappedArtistCommand}"
|
||||
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
FontSize=12,
|
||||
Glyph=}"
|
||||
Style="{StaticResource GhostButtonStyle}" />
|
||||
</Grid>
|
||||
|
||||
<RichTextBlock
|
||||
FontSize="12"
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
TextWrapping="Wrap">
|
||||
<Paragraph>
|
||||
<Run Text="*" />
|
||||
<Run x:Uid="ArtistsSplitHint" />
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Run Text="; , / ; 、 ," />
|
||||
</Paragraph>
|
||||
</RichTextBlock>
|
||||
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
@@ -86,22 +119,32 @@
|
||||
CornerRadius="4">
|
||||
<StackPanel Spacing="6">
|
||||
|
||||
<TextBlock x:Uid="LyricsSearchControlAlbum" />
|
||||
<TextBlock
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
IsTextSelectionEnabled="True"
|
||||
Text="{x:Bind ViewModel.MappedSongSearchQuery.OriginalAlbum, Mode=OneWay}"
|
||||
TextWrapping="Wrap" />
|
||||
<local:PropertyRow x:Uid="LyricsSearchControlAlbum" Value="{x:Bind ViewModel.MappedSongSearchQuery.OriginalAlbum, Mode=OneWay}" />
|
||||
|
||||
<TextBlock x:Uid="LyricsSearchControlMappedAs" VerticalAlignment="Center" />
|
||||
<TextBox Text="{x:Bind ViewModel.MappedSongSearchQuery.MappedAlbum, Mode=TwoWay}" TextWrapping="Wrap" />
|
||||
<Button
|
||||
VerticalAlignment="Center"
|
||||
Command="{x:Bind ViewModel.ResetMappedAlbumCommand}"
|
||||
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
FontSize=12,
|
||||
Glyph=}"
|
||||
Style="{StaticResource GhostButtonStyle}" />
|
||||
<Grid ColumnSpacing="6">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock
|
||||
x:Uid="LyricsSearchControlMappedAs"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center" />
|
||||
<TextBox
|
||||
Grid.Column="1"
|
||||
Text="{x:Bind ViewModel.MappedSongSearchQuery.MappedAlbum, Mode=TwoWay}"
|
||||
TextWrapping="Wrap" />
|
||||
<Button
|
||||
Grid.Column="2"
|
||||
VerticalAlignment="Center"
|
||||
Command="{x:Bind ViewModel.ResetMappedAlbumCommand}"
|
||||
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
FontSize=12,
|
||||
Glyph=}"
|
||||
Style="{StaticResource GhostButtonStyle}" />
|
||||
</Grid>
|
||||
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
@@ -117,6 +160,10 @@
|
||||
Style="{StaticResource AccentButtonStyle}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
<dev:SettingsCard x:Uid="LyricsSearchControlIgnoreCache">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.GeneralSettings.IgnoreCacheWhenSearching, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
@@ -125,22 +172,31 @@
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate x:DataType="models:LyricsSearchResult">
|
||||
<ListViewItem IsEnabled="{x:Bind IsFound}">
|
||||
<StackPanel Padding="3,6" Opacity="{x:Bind IsFound, Converter={StaticResource BoolToPartialOpacityConverter}}">
|
||||
<TextBlock Foreground="{ThemeResource AccentTextFillColorPrimaryBrush}" Text="{x:Bind Provider, Converter={StaticResource LyricsSearchProviderToDisplayNameConverter}}" />
|
||||
<TextBlock
|
||||
Text="{x:Bind Title}"
|
||||
TextWrapping="Wrap"
|
||||
Visibility="{x:Bind IsFound, Converter={StaticResource BoolToVisibilityConverter}}" />
|
||||
<TextBlock
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
Text="{x:Bind Artist}"
|
||||
TextWrapping="Wrap"
|
||||
Visibility="{x:Bind IsFound, Converter={StaticResource BoolToVisibilityConverter}}" />
|
||||
<TextBlock
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
Text="{x:Bind Album}"
|
||||
TextWrapping="Wrap"
|
||||
Visibility="{x:Bind IsFound, Converter={StaticResource BoolToVisibilityConverter}}" />
|
||||
<StackPanel Padding="0,6" Opacity="{x:Bind IsFound, Converter={StaticResource BoolToPartialOpacityConverter}}">
|
||||
<local:PropertyRow
|
||||
Margin="-8,0,0,0"
|
||||
Link="{x:Bind Reference, Mode=OneWay}"
|
||||
ToolTipService.ToolTip="{x:Bind Reference, TargetNullValue=N/A, Mode=OneWay}"
|
||||
Value="{x:Bind Provider, Mode=OneWay, Converter={StaticResource LyricsSearchProviderToDisplayNameConverter}}" />
|
||||
<!-- Lyrics search result -->
|
||||
<StackPanel Visibility="{x:Bind IsFound, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
<local:PropertyRow x:Uid="SettingsPageSongTitle" Value="{x:Bind Title, TargetNullValue=N/A, Mode=OneWay}" />
|
||||
<local:PropertyRow x:Uid="SettingsPageArtist" Value="{x:Bind DisplayArtists, TargetNullValue=N/A, Mode=OneWay}" />
|
||||
<local:PropertyRow x:Uid="SettingsPageAlbum" Value="{x:Bind Album, TargetNullValue=N/A, Mode=OneWay}" />
|
||||
<local:PropertyRow
|
||||
x:Uid="LyricsSearchControlDurauion"
|
||||
Unit="s"
|
||||
Value="{x:Bind Duration, TargetNullValue=N/A, Mode=OneWay}" />
|
||||
<local:PropertyRow
|
||||
x:Uid="LyricsPageMatchPercentage"
|
||||
Unit="%"
|
||||
Value="{x:Bind MatchPercentage, Mode=OneWay}" />
|
||||
<local:PropertyRow
|
||||
x:Uid="LyricsPageCachePath"
|
||||
Link="{x:Bind SelfPath, TargetNullValue=N/A, Mode=OneWay}"
|
||||
ToolTipService.ToolTip="{x:Bind SelfPath, TargetNullValue=N/A, Mode=OneWay}" />
|
||||
</StackPanel>
|
||||
<!-- NOT FOUND -->
|
||||
<TextBlock
|
||||
x:Uid="LyricsSearchControlNotFound"
|
||||
VerticalAlignment="Center"
|
||||
@@ -209,23 +265,30 @@
|
||||
</interactivity:DataTriggerBehavior>
|
||||
</interactivity:Interaction.Behaviors>
|
||||
<Pivot.HeaderTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Style="{StaticResource BodyTextBlockStyle}" Text="{Binding LanguageCode, Mode=OneWay, Converter={StaticResource LanguageCodeToDisplayedNameConverter}}" />
|
||||
<DataTemplate x:DataType="models:LyricsData">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Style="{StaticResource BodyTextBlockStyle}" Text="{x:Bind LanguageCode, Mode=OneWay, Converter={StaticResource LanguageCodeToDisplayedNameConverter}}" />
|
||||
<InfoBadge
|
||||
x:Uid="LyricsSearchControlAutoGenerated"
|
||||
Margin="6,0,0,0"
|
||||
Style="{StaticResource StringInfoBadgeStyle}"
|
||||
Visibility="{x:Bind AutoGenerated, Converter={StaticResource BoolToVisibilityConverter}, Mode=OneWay}" />
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</Pivot.HeaderTemplate>
|
||||
<Pivot.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<ListView ItemsSource="{Binding LyricsLines, Mode=OneWay}" SelectionChanged="ListView_SelectionChanged">
|
||||
<DataTemplate x:DataType="models:LyricsData">
|
||||
<ListView ItemsSource="{x:Bind LyricsLines, Mode=OneWay}" SelectionChanged="ListView_SelectionChanged">
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<DataTemplate x:DataType="models:LyricsLine">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Foreground="{ThemeResource SystemFillColorNeutralBrush}" Text="{Binding StartMs, Converter={StaticResource MillisecondsToFormattedTimeConverter}}" />
|
||||
<TextBlock Foreground="{ThemeResource SystemFillColorNeutralBrush}" Text="{x:Bind StartMs, Mode=OneWay, Converter={StaticResource MillisecondsToFormattedTimeConverter}}" />
|
||||
<TextBlock
|
||||
Margin="1,0"
|
||||
Foreground="{ThemeResource SystemFillColorNeutralBrush}"
|
||||
Text="-" />
|
||||
<TextBlock Foreground="{ThemeResource SystemFillColorNeutralBrush}" Text="{Binding EndMs, Converter={StaticResource MillisecondsToFormattedTimeConverter}}" />
|
||||
<TextBlock Margin="6,0" Text="{Binding OriginalText}" />
|
||||
<TextBlock Foreground="{ThemeResource SystemFillColorNeutralBrush}" Text="{x:Bind EndMs, Mode=OneWay, Converter={StaticResource MillisecondsToFormattedTimeConverter}}" />
|
||||
<TextBlock Margin="6,0" Text="{x:Bind OriginalText, Mode=OneWay}" />
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
@@ -256,31 +319,29 @@
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid Grid.Row="1">
|
||||
<RelativePanel>
|
||||
<TextBlock
|
||||
x:Uid="LyricsSearchControlHelp"
|
||||
Margin="0,0,24,0"
|
||||
FontSize="12"
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
RelativePanel.AlignVerticalCenterWithPanel="True"
|
||||
RelativePanel.LeftOf="Reset"
|
||||
TextWrapping="Wrap" />
|
||||
<Button
|
||||
x:Name="Reset"
|
||||
x:Uid="LyricsSearchControlReset"
|
||||
Margin="0,0,6,0"
|
||||
Command="{x:Bind ViewModel.ResetCommand}"
|
||||
RelativePanel.AlignVerticalCenterWithPanel="True"
|
||||
RelativePanel.LeftOf="SaveChanges" />
|
||||
<Button
|
||||
x:Name="SaveChanges"
|
||||
x:Uid="LyricsSearchControlSaveChanges"
|
||||
Command="{x:Bind ViewModel.SaveCommand}"
|
||||
RelativePanel.AlignRightWithPanel="True"
|
||||
RelativePanel.AlignVerticalCenterWithPanel="True"
|
||||
Style="{StaticResource AccentButtonStyle}" />
|
||||
</RelativePanel>
|
||||
<Grid Grid.Row="1" ColumnSpacing="6">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock
|
||||
x:Uid="LyricsSearchControlHelp"
|
||||
Grid.Column="1"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="12"
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
TextWrapping="Wrap" />
|
||||
<Button
|
||||
x:Uid="LyricsSearchControlReset"
|
||||
Grid.Column="2"
|
||||
Command="{x:Bind ViewModel.ResetCommand}" />
|
||||
<Button
|
||||
x:Uid="LyricsSearchControlSaveChanges"
|
||||
Grid.Column="3"
|
||||
Command="{x:Bind ViewModel.SaveCommand}"
|
||||
Style="{StaticResource AccentButtonStyle}" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
||||
@@ -22,5 +22,6 @@ namespace BetterLyrics.WinUI3.Controls
|
||||
{
|
||||
ViewModel.SelectedLyricsLine = e.OriginalSource as LyricsLine;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,12 +23,32 @@
|
||||
|
||||
<dev: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" />
|
||||
<ComboBoxItem x:Uid="SettingsPageLeft" />
|
||||
<ComboBoxItem x:Uid="SettingsPageCenter" />
|
||||
<ComboBoxItem x:Uid="SettingsPageRight" />
|
||||
</ComboBox>
|
||||
</dev:SettingsCard>
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageLyricsCenterTopOffset" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<local:ExtendedSlider
|
||||
Default="50"
|
||||
Maximum="100"
|
||||
Minimum="0"
|
||||
Unit="%"
|
||||
Value="{x:Bind LyricsStyleSettings.PlayingLineTopOffset, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
<dev: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}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
<dev:SettingsExpander x:Uid="SettingsPageLyricsFontFamily" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<dev:SettingsExpander.Items>
|
||||
<dev:SettingsCard x:Uid="SettingsPageCJK">
|
||||
@@ -56,15 +76,6 @@
|
||||
</ComboBox>
|
||||
</dev:SettingsCard>
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageLyricsBgFontOpacity" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<local:ExtendedSlider
|
||||
Default="30"
|
||||
Maximum="100"
|
||||
Minimum="0"
|
||||
Unit="%"
|
||||
Value="{x:Bind LyricsStyleSettings.LyricsBgFontOpacity, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageLyricsFontStrokeWidth" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<local:ExtendedSlider
|
||||
Default="0"
|
||||
@@ -216,23 +227,35 @@
|
||||
</dev:SettingsExpander.Items>
|
||||
</dev:SettingsExpander>
|
||||
|
||||
<dev: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}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
<dev: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>
|
||||
</dev:SettingsCard>
|
||||
<!-- 字体不透明度 -->
|
||||
<dev:SettingsExpander x:Uid="SettingsPageLyricsOpacity" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<dev:SettingsExpander.Items>
|
||||
<dev:SettingsCard x:Uid="SettingsPagePhoneticText">
|
||||
<local:ExtendedSlider
|
||||
Default="60"
|
||||
Frequency="1"
|
||||
Maximum="100"
|
||||
Minimum="0"
|
||||
Value="{x:Bind LyricsStyleSettings.PhoneticLyricsOpacity, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
<dev:SettingsCard x:Uid="SettingsPageOriginalText">
|
||||
<local:ExtendedSlider
|
||||
Default="30"
|
||||
Frequency="1"
|
||||
Maximum="100"
|
||||
Minimum="0"
|
||||
Value="{x:Bind LyricsStyleSettings.OriginalLyricsOpacity, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
<dev:SettingsCard x:Uid="SettingsPageTranslatedText">
|
||||
<local:ExtendedSlider
|
||||
Default="60"
|
||||
Frequency="1"
|
||||
Maximum="100"
|
||||
Minimum="0"
|
||||
Value="{x:Bind LyricsStyleSettings.TranslatedLyricsOpacity, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
</dev:SettingsExpander.Items>
|
||||
</dev:SettingsExpander>
|
||||
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
@@ -13,21 +13,15 @@
|
||||
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid ColumnSpacing="6">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid Grid.Column="0">
|
||||
<Grid>
|
||||
|
||||
<Grid x:Name="DisplayGrid" SizeChanged="DisplayGrid_SizeChanged">
|
||||
<ScrollViewer Style="{StaticResource SettingsScrollViewerStyle}">
|
||||
<Grid Style="{StaticResource SettingsGridStyle}">
|
||||
|
||||
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
|
||||
|
||||
<TextBlock
|
||||
x:Uid="SettingsPageRecordedWindowStatus"
|
||||
RelativePanel.AlignLeftWithPanel="True"
|
||||
Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
<TextBlock x:Uid="SettingsPageRecordedWindowStatus" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
|
||||
<StackPanel Orientation="Horizontal" Spacing="3">
|
||||
|
||||
@@ -60,7 +54,7 @@
|
||||
</Button>
|
||||
|
||||
<!-- Sharing hub -->
|
||||
<HyperlinkButton x:Uid="SettingsPageShareHub" NavigateUri="{x:Bind constants:Link.ShareHubUrl}" />
|
||||
<HyperlinkButton x:Uid="SettingsPageShareHub" NavigateUri="{x:Bind constants:Link.ShareHub}" />
|
||||
|
||||
</StackPanel>
|
||||
|
||||
@@ -76,7 +70,7 @@
|
||||
Padding="0,12"
|
||||
CornerRadius="4"
|
||||
ItemsSource="{x:Bind ViewModel.AppSettings.WindowBoundsRecords, Mode=OneWay}"
|
||||
SelectedItem="{x:Bind ViewModel.LiveStates.LyricsWindowStatus, Mode=TwoWay}">
|
||||
SelectionMode="None">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<controls:WrapPanel HorizontalSpacing="0" VerticalSpacing="0" />
|
||||
@@ -90,10 +84,6 @@
|
||||
Spacing="6">
|
||||
<StackPanel.ContextFlyout>
|
||||
<MenuBarItemFlyout>
|
||||
<MenuFlyoutItem
|
||||
x:Uid="LyricsWindowSettingsControlSetDefault"
|
||||
Click="SetDefaultMenuFlyoutItem_Click"
|
||||
IsEnabled="{Binding IsDefault, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}" />
|
||||
<MenuFlyoutItem x:Uid="SettingsPageCreateFromCurrent" Click="CopyMenuFlyoutItem_Click" />
|
||||
<MenuFlyoutItem x:Uid="LyricsWindowSettingsControlShare" Click="ShareMenuFlyoutItem_Click" />
|
||||
<MenuFlyoutItem
|
||||
@@ -102,124 +92,161 @@
|
||||
IsEnabled="{Binding IsDefault, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}" />
|
||||
</MenuBarItemFlyout>
|
||||
</StackPanel.ContextFlyout>
|
||||
<uc:DemoWindowGrid LyricsWindowStatus="{Binding}" />
|
||||
<Grid>
|
||||
<Border
|
||||
BorderBrush="{ThemeResource AccentAAFillColorDefaultBrush}"
|
||||
BorderThickness="4"
|
||||
CornerRadius="4"
|
||||
Visibility="{Binding IsOpened, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}" />
|
||||
<uc:DemoWindowGrid
|
||||
Margin="4"
|
||||
LyricsWindowStatus="{Binding}"
|
||||
Tapped="DemoWindowGrid_Tapped" />
|
||||
</Grid>
|
||||
<Grid>
|
||||
<ToggleButton
|
||||
Grid.Column="0"
|
||||
HorizontalAlignment="Stretch"
|
||||
Click="SetDefaultMenuFlyoutItem_Click"
|
||||
IsChecked="{Binding IsDefault, Mode=OneWay}">
|
||||
<TextBlock x:Uid="LyricsWindowSettingsControlSetDefault" />
|
||||
</ToggleButton>
|
||||
</Grid>
|
||||
<Grid ColumnSpacing="4">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Button
|
||||
Grid.Column="0"
|
||||
HorizontalAlignment="Stretch"
|
||||
Click="ConfigButton_Click">
|
||||
<TextBlock x:Uid="LyricsWindowSettingsControlLyricsWindowConfig" />
|
||||
</Button>
|
||||
<Button
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Stretch"
|
||||
Click="CloseStatusButton_Click"
|
||||
IsEnabled="{Binding IsOpened, Mode=OneWay}">
|
||||
<TextBlock x:Uid="SettingsPageCloseStatus" />
|
||||
</Button>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
</StackPanel>
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageMultiNowPlayingWindows">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.GeneralSettings.MultiNowPlayingWindowMode, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageMusicGalleryLyrics">
|
||||
<Button HorizontalAlignment="Stretch" Click="EmbeddedConfigButton_Click">
|
||||
<TextBlock x:Uid="LyricsWindowSettingsControlLyricsWindowConfig" />
|
||||
</Button>
|
||||
</dev:SettingsCard>
|
||||
|
||||
</StackPanel>
|
||||
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
<Grid Grid.Column="1">
|
||||
|
||||
<Grid Padding="36,0" Style="{StaticResource SettingsGridStyle}">
|
||||
<Grid
|
||||
x:Name="ConfigGrid"
|
||||
Background="{ThemeResource AcrylicBackgroundFillColorDefaultBrush}"
|
||||
Opacity="{x:Bind ViewModel.IsConfigPanelOpened, Mode=OneWay, Converter={StaticResource BoolToOpacityConverter}}"
|
||||
Translation="{x:Bind ViewModel.ConfigPanelTranslation, Mode=OneWay}">
|
||||
<Grid.OpacityTransition>
|
||||
<ScalarTransition />
|
||||
</Grid.OpacityTransition>
|
||||
<Grid.TranslationTransition>
|
||||
<Vector3Transition />
|
||||
</Grid.TranslationTransition>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid
|
||||
Grid.Row="0"
|
||||
Padding="36,0"
|
||||
Style="{StaticResource SettingsGridStyle}">
|
||||
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock
|
||||
Grid.Column="0"
|
||||
Style="{StaticResource SettingsSectionHeaderTextBlockStyle}"
|
||||
Text="{x:Bind LyricsWindowStatus.Name, Mode=OneWay}" />
|
||||
<Button
|
||||
Grid.Column="2"
|
||||
Margin="0,30,0,0"
|
||||
Command="{x:Bind ViewModel.CloseConfigPanelCommand}"
|
||||
Content="{ui:FontIcon FontSize=16,
|
||||
FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}"
|
||||
Style="{StaticResource AccentButtonStyle}" />
|
||||
</Grid>
|
||||
|
||||
<TextBlock x:Uid="LyricsWindowSettingsControlCurrentLyricsWindowConfig" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
<SelectorBar x:Name="ConfigSelectorBar" SelectionChanged="ConfigSelectorBar_SelectionChanged">
|
||||
|
||||
<Pivot SelectionChanged="Pivot_SelectionChanged">
|
||||
<SelectorBarItem
|
||||
x:Name="WindowSelectorBarItem"
|
||||
x:Uid="AppSettingsControlGeneral"
|
||||
Tag="Window" />
|
||||
<SelectorBarItem
|
||||
x:Name="LayoutSelectorBarItem"
|
||||
x:Uid="SettingsPageLayout"
|
||||
Tag="Layout" />
|
||||
<SelectorBarItem
|
||||
x:Name="AlbumArtStyleSelectorBarItem"
|
||||
x:Uid="SettingsPageAlbumStyle"
|
||||
Tag="AlbumArtStyle" />
|
||||
<SelectorBarItem x:Uid="SettingsPageAlbumEffect" Tag="AlbumArtEffect" />
|
||||
<SelectorBarItem x:Uid="SettingsPageLyricsStyle" Tag="LyricsStyle" />
|
||||
<SelectorBarItem x:Uid="SettingsPageLyricsEffect" Tag="LyricsEffect" />
|
||||
<SelectorBarItem x:Uid="SettingsPageBackgroundOverlay" Tag="LyricsBackground" />
|
||||
|
||||
<PivotItem Tag="General">
|
||||
<PivotItem.Header>
|
||||
<TextBlock
|
||||
x:Uid="AppSettingsControlGeneral"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource BodyTextBlockStyle}" />
|
||||
</PivotItem.Header>
|
||||
</PivotItem>
|
||||
|
||||
<PivotItem Tag="AlbumArtStyle">
|
||||
<PivotItem.Header>
|
||||
<TextBlock
|
||||
x:Uid="SettingsPageAlbumStyle"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource BodyTextBlockStyle}" />
|
||||
</PivotItem.Header>
|
||||
</PivotItem>
|
||||
|
||||
<PivotItem Tag="LyricsStyle">
|
||||
<PivotItem.Header>
|
||||
<TextBlock
|
||||
x:Uid="SettingsPageLyricsStyle"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource BodyTextBlockStyle}" />
|
||||
</PivotItem.Header>
|
||||
</PivotItem>
|
||||
|
||||
<PivotItem Tag="LyricsEffect">
|
||||
<PivotItem.Header>
|
||||
<TextBlock
|
||||
x:Uid="SettingsPageLyricsEffect"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource BodyTextBlockStyle}" />
|
||||
</PivotItem.Header>
|
||||
</PivotItem>
|
||||
|
||||
<PivotItem Tag="LyricsBackground">
|
||||
<PivotItem.Header>
|
||||
<TextBlock
|
||||
x:Uid="SettingsPageBackgroundOverlay"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource BodyTextBlockStyle}" />
|
||||
</PivotItem.Header>
|
||||
</PivotItem>
|
||||
|
||||
<PivotItem Tag="Advanced">
|
||||
<PivotItem.Header>
|
||||
<TextBlock
|
||||
x:Uid="SettingsPageAdvanced"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource BodyTextBlockStyle}" />
|
||||
</PivotItem.Header>
|
||||
</PivotItem>
|
||||
|
||||
</Pivot>
|
||||
</SelectorBar>
|
||||
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<controls:SwitchPresenter Margin="0,110,0,0" Value="{x:Bind ViewModel.ListViewSelectedItemTag, Mode=OneWay}">
|
||||
<controls:SwitchPresenter Grid.Row="1" Value="{x:Bind ViewModel.SelectorBarSelectedItemTag, Mode=OneWay}">
|
||||
<controls:SwitchPresenter.ContentTransitions>
|
||||
<TransitionCollection>
|
||||
<PopupThemeTransition />
|
||||
</TransitionCollection>
|
||||
</controls:SwitchPresenter.ContentTransitions>
|
||||
|
||||
<!-- General -->
|
||||
<controls:Case Value="General">
|
||||
<!-- Window -->
|
||||
<controls:Case Value="Window">
|
||||
<uc:WindowSettingsControl LyricsWindowStatus="{x:Bind LyricsWindowStatus, Mode=OneWay}" />
|
||||
</controls:Case>
|
||||
|
||||
<!-- Layout -->
|
||||
<controls:Case Value="Layout">
|
||||
<ScrollViewer Style="{StaticResource SettingsScrollViewerStyle}">
|
||||
<Grid Style="{StaticResource SettingsGridStyle}">
|
||||
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
|
||||
|
||||
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
<TextBlock x:Uid="SettingsPageLayout" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageConfigName" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<StackPanel
|
||||
Margin="0,6,0,0"
|
||||
Orientation="Horizontal"
|
||||
Spacing="6">
|
||||
<TextBox Text="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.Name, Mode=TwoWay}" TextWrapping="Wrap" />
|
||||
<Button Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, FontSize=12, Glyph=}" Style="{StaticResource GhostButtonStyle}" />
|
||||
</StackPanel>
|
||||
</dev:SettingsCard>
|
||||
|
||||
<dev:SettingsExpander
|
||||
x:Uid="SettingsPageDisplayTypeSwitcher"
|
||||
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}"
|
||||
IsExpanded="True">
|
||||
<ComboBox SelectedIndex="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.LyricsDisplayType, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||
<dev:SettingsExpander x:Uid="SettingsPageDisplayTypeSwitcher" IsExpanded="True">
|
||||
<ComboBox SelectedIndex="{x:Bind LyricsWindowStatus.LyricsDisplayType, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||
<ComboBoxItem x:Uid="MainPageAlbumArtOnly" />
|
||||
<ComboBoxItem x:Uid="MainPageLyriscOnly" />
|
||||
<ComboBoxItem x:Uid="MainPageSplitView" />
|
||||
</ComboBox>
|
||||
<dev:SettingsExpander.Items>
|
||||
<dev:SettingsCard x:Uid="SettingsPageLayoutOrientation">
|
||||
<ComboBox SelectedIndex="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.LyricsLayoutOrientation, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||
<ComboBox SelectedIndex="{x:Bind LyricsWindowStatus.LyricsLayoutOrientation, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||
<ComboBoxItem x:Uid="SettingsPageLayoutOrientationHorizontal" />
|
||||
<ComboBoxItem x:Uid="SettingsPageLayoutOrientationVertical" />
|
||||
</ComboBox>
|
||||
@@ -227,115 +254,6 @@
|
||||
</dev:SettingsExpander.Items>
|
||||
</dev:SettingsExpander>
|
||||
|
||||
<dev:SettingsExpander
|
||||
x:Uid="SettingsPageWorkArea"
|
||||
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}"
|
||||
IsExpanded="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.IsWorkArea, Mode=OneWay}">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.IsWorkArea, Mode=TwoWay}" />
|
||||
<dev:SettingsExpander.Items>
|
||||
<dev:SettingsCard x:Uid="SettingsPageWorkAreaHeight" IsEnabled="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.IsWorkArea, Mode=OneWay}">
|
||||
<uc:ExtendedSlider
|
||||
Default="64"
|
||||
Maximum="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.MonitorBounds.Height, Mode=OneWay}"
|
||||
Minimum="64"
|
||||
Unit="px"
|
||||
Value="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.DockHeight, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageDockPlacement" IsEnabled="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.IsWorkArea, Mode=OneWay}">
|
||||
<ComboBox SelectedIndex="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.DockPlacement, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||
<ComboBoxItem x:Uid="SettingsPageDockPlacementTop" />
|
||||
<ComboBoxItem x:Uid="SettingsPageDockPlacementBottom" />
|
||||
</ComboBox>
|
||||
</dev:SettingsCard>
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageDockMonitor" IsEnabled="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.IsWorkArea, Mode=OneWay}">
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<ComboBox ItemsSource="{x:Bind ViewModel.MonitorDeviceNames, Mode=OneWay}" SelectedItem="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.MonitorDeviceName, Mode=TwoWay}" />
|
||||
<Button
|
||||
Command="{x:Bind ViewModel.RefreshMonitorDeviceNamesCommand}"
|
||||
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
FontSize=12,
|
||||
Glyph=}"
|
||||
Style="{StaticResource GhostButtonStyle}" />
|
||||
</StackPanel>
|
||||
</dev:SettingsCard>
|
||||
|
||||
</dev:SettingsExpander.Items>
|
||||
</dev:SettingsExpander>
|
||||
|
||||
<dev:SettingsExpander
|
||||
x:Uid="SettingsPageAdaptEnvColor"
|
||||
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}"
|
||||
IsExpanded="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.IsAdaptToEnvironment, Mode=OneWay}">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.IsAdaptToEnvironment, Mode=TwoWay}" />
|
||||
<dev:SettingsExpander.Items>
|
||||
<dev:SettingsCard
|
||||
x:Uid="SettingsPageEnvColorSample"
|
||||
Header="Environment color sample mode"
|
||||
IsEnabled="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.IsAdaptToEnvironment, Mode=OneWay}">
|
||||
<ComboBox SelectedIndex="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.EnvironmentSampleMode, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||
<ComboBoxItem x:Uid="SettingsPageEnvColorSampleBelow" />
|
||||
<ComboBoxItem x:Uid="SettingsPageEnvColorSampleAbove" />
|
||||
<ComboBoxItem x:Uid="SettingsPageEnvColorSampleInner" />
|
||||
<ComboBoxItem x:Uid="SettingsPageEnvColorSampleEdge" />
|
||||
</ComboBox>
|
||||
</dev:SettingsCard>
|
||||
</dev:SettingsExpander.Items>
|
||||
</dev:SettingsExpander>
|
||||
|
||||
<dev:SettingsExpander
|
||||
x:Uid="SettingsPageWindowBounds"
|
||||
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}"
|
||||
IsExpanded="True">
|
||||
<dev:SettingsExpander.Items>
|
||||
<dev:SettingsCard Header="X">
|
||||
<NumberBox
|
||||
SmallChange="10"
|
||||
SpinButtonPlacementMode="Inline"
|
||||
Value="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.WindowX, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
<dev:SettingsCard Header="Y">
|
||||
<NumberBox
|
||||
SmallChange="10"
|
||||
SpinButtonPlacementMode="Inline"
|
||||
Value="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.WindowY, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
<dev:SettingsCard x:Uid="SettingsPageWidth">
|
||||
<NumberBox
|
||||
SmallChange="10"
|
||||
SpinButtonPlacementMode="Inline"
|
||||
Value="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.WindowWidth, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
<dev:SettingsCard x:Uid="SettingsPageHeight">
|
||||
<NumberBox
|
||||
SmallChange="10"
|
||||
SpinButtonPlacementMode="Inline"
|
||||
Value="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.WindowHeight, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
</dev:SettingsExpander.Items>
|
||||
</dev:SettingsExpander>
|
||||
|
||||
<dev:SettingsExpander
|
||||
x:Uid="SettingsPageAOT"
|
||||
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}"
|
||||
IsExpanded="True">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.IsAlwaysOnTop, Mode=TwoWay}" />
|
||||
<dev:SettingsExpander.Items>
|
||||
<dev:SettingsCard x:Uid="SettingsPageForceAlwaysOnTop" IsEnabled="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.IsAlwaysOnTop, Mode=OneWay}">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.IsAlwaysOnTopPolling, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
</dev:SettingsExpander.Items>
|
||||
</dev:SettingsExpander>
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageHideWindow" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.AutoShowOrHideWindow, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
@@ -343,57 +261,32 @@
|
||||
|
||||
<!-- Album art area style -->
|
||||
<controls:Case Value="AlbumArtStyle">
|
||||
<uc:AlbumArtLayoutSettingsControl AlbumArtLayoutSettings="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.AlbumArtLayoutSettings, Mode=OneWay}" />
|
||||
<uc:AlbumArtAreaStyleSettingsControl AlbumArtLayoutSettings="{x:Bind LyricsWindowStatus.AlbumArtLayoutSettings, Mode=OneWay}" />
|
||||
</controls:Case>
|
||||
|
||||
<!-- Album art area effect -->
|
||||
<controls:Case Value="AlbumArtEffect">
|
||||
<uc:AlbumArtAreaEffectSettingsControl AlbumArtAreaEffectSettings="{x:Bind LyricsWindowStatus.AlbumArtAreaEffectSettings, Mode=OneWay}" />
|
||||
</controls:Case>
|
||||
|
||||
<!-- Lyrics style -->
|
||||
<controls:Case Value="LyricsStyle">
|
||||
<uc:LyricsStyleSettingsControl LyricsStyleSettings="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.LyricsStyleSettings, Mode=OneWay}" />
|
||||
<uc:LyricsStyleSettingsControl LyricsStyleSettings="{x:Bind LyricsWindowStatus.LyricsStyleSettings, Mode=OneWay}" />
|
||||
</controls:Case>
|
||||
|
||||
<!-- Lyrics effect -->
|
||||
<controls:Case Value="LyricsEffect">
|
||||
<uc:LyricsEffectSettingsControl LyricsEffectSettings="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.LyricsEffectSettings, Mode=OneWay}" />
|
||||
<uc:LyricsEffectSettingsControl LyricsEffectSettings="{x:Bind LyricsWindowStatus.LyricsEffectSettings, Mode=OneWay}" />
|
||||
</controls:Case>
|
||||
|
||||
<!-- Lyrics background -->
|
||||
<controls:Case Value="LyricsBackground">
|
||||
<uc:LyricsBackgroundSettingsControl LyricsBackgroundSettings="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.LyricsBackgroundSettings, Mode=OneWay}" />
|
||||
</controls:Case>
|
||||
|
||||
<!-- Advanced -->
|
||||
<controls:Case Value="Advanced">
|
||||
<ScrollViewer Style="{StaticResource SettingsScrollViewerStyle}">
|
||||
<Grid Style="{StaticResource SettingsGridStyle}">
|
||||
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageShowInSwitchers" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.IsShownInSwitchers, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageClickThrough" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.IsClickThrough, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageBorderless" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.IsBorderless, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageDragArea" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ComboBox SelectedIndex="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.TitleBarArea, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||
<ComboBoxItem x:Uid="SettingsPageTitleBarAreaNone" />
|
||||
<ComboBoxItem x:Uid="SettingsPageTitleBarAreaTop" />
|
||||
<ComboBoxItem x:Uid="SettingsPageTitleBarAreaWhole" />
|
||||
</ComboBox>
|
||||
</dev:SettingsCard>
|
||||
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
<uc:LyricsBackgroundSettingsControl LyricsBackgroundSettings="{x:Bind LyricsWindowStatus.LyricsBackgroundSettings, Mode=OneWay}" />
|
||||
</controls:Case>
|
||||
|
||||
</controls:SwitchPresenter>
|
||||
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using BetterLyrics.WinUI3.Hooks;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.Serialization;
|
||||
using BetterLyrics.WinUI3.Services.LiveStatesService;
|
||||
using BetterLyrics.WinUI3.Services.ResourceService;
|
||||
using BetterLyrics.WinUI3.Services.SettingsService;
|
||||
using BetterLyrics.WinUI3.ViewModels;
|
||||
using BetterLyrics.WinUI3.Views;
|
||||
@@ -10,7 +9,6 @@ using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Input;
|
||||
using NTextCat.Commons;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@@ -26,8 +24,15 @@ namespace BetterLyrics.WinUI3.Controls
|
||||
public LyricsWindowSettingsControlViewModel ViewModel => (LyricsWindowSettingsControlViewModel)DataContext;
|
||||
|
||||
private readonly ISettingsService _settingsService = Ioc.Default.GetRequiredService<ISettingsService>();
|
||||
private readonly ILiveStatesService _liveStatesService = Ioc.Default.GetRequiredService<ILiveStatesService>();
|
||||
private readonly IResourceService _resourceService = Ioc.Default.GetRequiredService<IResourceService>();
|
||||
|
||||
public LyricsWindowStatus LyricsWindowStatus
|
||||
{
|
||||
get { return (LyricsWindowStatus)GetValue(LyricsWindowStatusProperty); }
|
||||
set { SetValue(LyricsWindowStatusProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty LyricsWindowStatusProperty =
|
||||
DependencyProperty.Register(nameof(LyricsWindowStatus), typeof(LyricsWindowStatus), typeof(LyricsWindowSettingsControl), new PropertyMetadata(default));
|
||||
|
||||
public LyricsWindowSettingsControl()
|
||||
{
|
||||
@@ -41,10 +46,9 @@ namespace BetterLyrics.WinUI3.Controls
|
||||
{
|
||||
if (menuFlyoutItem.DataContext is LyricsWindowStatus data)
|
||||
{
|
||||
if (_liveStatesService.LiveStates.LyricsWindowStatus == data)
|
||||
{
|
||||
_liveStatesService.LiveStates.LyricsWindowStatus = ViewModel.AppSettings.WindowBoundsRecords.First();
|
||||
}
|
||||
var windows = WindowHook.GetWindows<NowPlayingWindow>();
|
||||
var window = windows.FirstOrDefault(x => x.LyricsWindowStatus == data);
|
||||
window?.CloseWindow();
|
||||
ViewModel.AppSettings.WindowBoundsRecords.Remove(data);
|
||||
}
|
||||
}
|
||||
@@ -52,12 +56,11 @@ namespace BetterLyrics.WinUI3.Controls
|
||||
|
||||
private void SetDefaultMenuFlyoutItem_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is MenuFlyoutItem menuFlyoutItem)
|
||||
if (sender is FrameworkElement element)
|
||||
{
|
||||
if (menuFlyoutItem.DataContext is LyricsWindowStatus data)
|
||||
if (element.DataContext is LyricsWindowStatus data)
|
||||
{
|
||||
ViewModel.AppSettings.WindowBoundsRecords.ForEach(x => x.IsDefault = false);
|
||||
data.IsDefault = true;
|
||||
data.IsDefault = !data.IsDefault;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -75,7 +78,7 @@ namespace BetterLyrics.WinUI3.Controls
|
||||
StorageFile? file;
|
||||
if (this.Parent is FlyoutPresenter)
|
||||
{
|
||||
file = await PickerHelper.PickSaveFileAsync<LyricsWindow>(fileTypeChoices);
|
||||
file = await PickerHelper.PickSaveFileAsync<NowPlayingWindow>(fileTypeChoices);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -87,7 +90,7 @@ namespace BetterLyrics.WinUI3.Controls
|
||||
clonedData.IsDefault = false;
|
||||
var json = System.Text.Json.JsonSerializer.Serialize(clonedData, SourceGenerationContext.Default.LyricsWindowStatus);
|
||||
File.WriteAllText(file.Path, json);
|
||||
DevWinUI.Growl.Success(_resourceService.GetLocalizedString("ExportSettingsSuccess"));
|
||||
ToastHelper.ShowToast("ExportSettingsSuccess", null, InfoBarSeverity.Success);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -117,24 +120,13 @@ namespace BetterLyrics.WinUI3.Controls
|
||||
}
|
||||
}
|
||||
|
||||
private void Pivot_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (sender is Pivot pivot)
|
||||
{
|
||||
if (pivot.SelectedItem is PivotItem pivotItem)
|
||||
{
|
||||
ViewModel?.ListViewSelectedItemTag = pivotItem.Tag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async void ImportButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
string[] fileTypeFilter = [".json"];
|
||||
StorageFile? file;
|
||||
if (this.Parent is FlyoutPresenter)
|
||||
{
|
||||
file = await PickerHelper.PickSingleFileAsync<LyricsWindow>(fileTypeFilter);
|
||||
file = await PickerHelper.PickSingleFileAsync<NowPlayingWindow>(fileTypeFilter);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -147,7 +139,71 @@ namespace BetterLyrics.WinUI3.Controls
|
||||
if (data != null)
|
||||
{
|
||||
ViewModel.AppSettings.WindowBoundsRecords.Add(data);
|
||||
DevWinUI.Growl.Success(_resourceService.GetLocalizedString("ImportSettingsSuccess"));
|
||||
ToastHelper.ShowToast("ImportSettingsSuccess", null, InfoBarSeverity.Success);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DisplayGrid_SizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
ViewModel.DisplayPanelHeight = e.NewSize.Height;
|
||||
}
|
||||
|
||||
private void ConfigButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
WindowSelectorBarItem.Visibility = LayoutSelectorBarItem.Visibility = Visibility.Visible;
|
||||
ConfigSelectorBar.SelectedItem = WindowSelectorBarItem;
|
||||
LyricsWindowStatus = (LyricsWindowStatus)((Button)sender).DataContext;
|
||||
ViewModel.OpenConfigPanel();
|
||||
}
|
||||
|
||||
private void EmbeddedConfigButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
WindowSelectorBarItem.Visibility = LayoutSelectorBarItem.Visibility = Visibility.Collapsed;
|
||||
ConfigSelectorBar.SelectedItem = AlbumArtStyleSelectorBarItem;
|
||||
LyricsWindowStatus = _settingsService.AppSettings.MusicGallerySettings.LyricsWindowStatus;
|
||||
ViewModel.OpenConfigPanel();
|
||||
}
|
||||
|
||||
private void DemoWindowGrid_Tapped(object sender, TappedRoutedEventArgs e)
|
||||
{
|
||||
var status = (LyricsWindowStatus)(((FrameworkElement)sender).DataContext);
|
||||
// <20>ģʽ
|
||||
if (_settingsService.AppSettings.GeneralSettings.MultiNowPlayingWindowMode)
|
||||
{
|
||||
WindowHook.OpenOrShowWindow<NowPlayingWindow>(status);
|
||||
}
|
||||
// <20><><EFBFBD><EFBFBD>ģʽ
|
||||
else
|
||||
{
|
||||
var openedWindows = WindowHook.GetWindows<NowPlayingWindow>();
|
||||
foreach (var item in openedWindows.Where(x => x.LyricsWindowStatus != status))
|
||||
{
|
||||
item.CloseWindow();
|
||||
}
|
||||
WindowHook.OpenOrShowWindow<NowPlayingWindow>(status);
|
||||
}
|
||||
}
|
||||
|
||||
private void ConfigSelectorBar_SelectionChanged(SelectorBar sender, SelectorBarSelectionChangedEventArgs args)
|
||||
{
|
||||
if (sender is SelectorBar bar)
|
||||
{
|
||||
if (bar.SelectedItem is SelectorBarItem item)
|
||||
{
|
||||
ViewModel?.SelectorBarSelectedItemTag = item.Tag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CloseStatusButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is FrameworkElement element)
|
||||
{
|
||||
if (element.DataContext is LyricsWindowStatus data)
|
||||
{
|
||||
var window = WindowHook.GetWindows<NowPlayingWindow>().FirstOrDefault(x => x.LyricsWindowStatus == data);
|
||||
window?.CloseWindow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,66 +11,77 @@
|
||||
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Background="{ThemeResource AcrylicInAppFillColorDefaultBrush}"
|
||||
CornerRadius="12">
|
||||
<FontIcon
|
||||
Margin="20"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Top"
|
||||
FontFamily="{StaticResource IconFontFamily}"
|
||||
Glyph="" />
|
||||
<Button
|
||||
Margin="12"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Top"
|
||||
Click="Button_Click"
|
||||
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}"
|
||||
Style="{StaticResource GhostButtonStyle}">
|
||||
<Button.KeyboardAccelerators>
|
||||
<KeyboardAccelerator Key="Escape" />
|
||||
</Button.KeyboardAccelerators>
|
||||
</Button>
|
||||
<Grid HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||
<Grid x:Name="ShadowCastGrid" />
|
||||
<Border
|
||||
x:Name="ShadowRect"
|
||||
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||
CornerRadius="12"
|
||||
Loaded="ShadowRect_Loaded"
|
||||
Translation="0,0,64">
|
||||
<Border.Shadow>
|
||||
<ThemeShadow x:Name="Shadow" />
|
||||
</Border.Shadow>
|
||||
</Border>
|
||||
<Grid Background="{ThemeResource AcrylicBackgroundFillColorDefaultBrush}" CornerRadius="12">
|
||||
<TextBlock
|
||||
x:Uid="SystemTraySwitch"
|
||||
Margin="20"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Top" />
|
||||
<Button
|
||||
Margin="12"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Top"
|
||||
Click="Button_Click"
|
||||
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}"
|
||||
Style="{StaticResource GhostButtonStyle}">
|
||||
<Button.KeyboardAccelerators>
|
||||
<KeyboardAccelerator Key="Escape" />
|
||||
</Button.KeyboardAccelerators>
|
||||
</Button>
|
||||
|
||||
<ListView
|
||||
Margin="48,56"
|
||||
ItemsSource="{x:Bind ViewModel.AppSettings.WindowBoundsRecords, Mode=OneWay}"
|
||||
SelectedItem="{x:Bind ViewModel.LiveStates.LyricsWindowStatus, Mode=TwoWay}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<controls:WrapPanel HorizontalSpacing="0" VerticalSpacing="0" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid
|
||||
Margin="0,10"
|
||||
Padding="5"
|
||||
AllowFocusOnInteraction="True"
|
||||
CornerRadius="4"
|
||||
Tapped="Grid_Tapped">
|
||||
<uc:DemoWindowGrid LyricsWindowStatus="{Binding}" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
<ListView
|
||||
Margin="48,56"
|
||||
ItemContainerStyle="{StaticResource ListViewStretchedItemContainerStyle}"
|
||||
ItemsSource="{x:Bind ViewModel.AppSettings.WindowBoundsRecords, Mode=OneWay}"
|
||||
SelectionMode="None">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<controls:WrapPanel HorizontalSpacing="0" VerticalSpacing="0" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid
|
||||
Margin="16"
|
||||
CornerRadius="4"
|
||||
Tapped="Grid_Tapped">
|
||||
<Border
|
||||
BorderBrush="{ThemeResource AccentAAFillColorDefaultBrush}"
|
||||
BorderThickness="4"
|
||||
Visibility="{Binding IsOpened, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}" />
|
||||
<uc:DemoWindowGrid Margin="4" LyricsWindowStatus="{Binding}" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
|
||||
<StackPanel
|
||||
Margin="20"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Bottom"
|
||||
Orientation="Horizontal"
|
||||
Spacing="6">
|
||||
<FontIcon
|
||||
Margin="0,1,0,0"
|
||||
FontFamily="{StaticResource IconFontFamily}"
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
Glyph="" />
|
||||
<TextBlock x:Uid="LyricsWindowSwitchWindowHelp" Foreground="{ThemeResource TextFillColorSecondaryBrush}" />
|
||||
</StackPanel>
|
||||
<StackPanel
|
||||
Margin="20"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Bottom"
|
||||
Orientation="Horizontal"
|
||||
Spacing="6">
|
||||
<HyperlinkButton Click="SettingsHypelinkButton_Click">
|
||||
<HyperlinkButton.Content>
|
||||
<TextBlock x:Uid="LyricsWindowSwitchWindowHelp" />
|
||||
</HyperlinkButton.Content>
|
||||
</HyperlinkButton>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
|
||||
</UserControl>
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using BetterLyrics.WinUI3.Hooks;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.Services.SettingsService;
|
||||
using BetterLyrics.WinUI3.ViewModels;
|
||||
using BetterLyrics.WinUI3.Views;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Input;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
// To learn more about WinUI, the WinUI project structure,
|
||||
@@ -16,6 +19,8 @@ namespace BetterLyrics.WinUI3.Controls
|
||||
{
|
||||
public LyricsWindowSwitchControlViewModel ViewModel => (LyricsWindowSwitchControlViewModel)DataContext;
|
||||
|
||||
private readonly ISettingsService _settingsService = Ioc.Default.GetRequiredService<ISettingsService>();
|
||||
|
||||
public LyricsWindowSwitchControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
@@ -24,6 +29,22 @@ namespace BetterLyrics.WinUI3.Controls
|
||||
|
||||
private async void Grid_Tapped(object sender, TappedRoutedEventArgs e)
|
||||
{
|
||||
var status = (LyricsWindowStatus)(((FrameworkElement)sender).DataContext);
|
||||
// <20>ģʽ
|
||||
if (_settingsService.AppSettings.GeneralSettings.MultiNowPlayingWindowMode)
|
||||
{
|
||||
WindowHook.OpenOrShowWindow<NowPlayingWindow>(status);
|
||||
}
|
||||
// <20><><EFBFBD><EFBFBD>ģʽ
|
||||
else
|
||||
{
|
||||
var openedWindows = WindowHook.GetWindows<NowPlayingWindow>();
|
||||
foreach (var item in openedWindows.Where(x => x.LyricsWindowStatus != status))
|
||||
{
|
||||
item.CloseWindow();
|
||||
}
|
||||
WindowHook.OpenOrShowWindow<NowPlayingWindow>(status);
|
||||
}
|
||||
await HideAsync();
|
||||
}
|
||||
|
||||
@@ -34,10 +55,21 @@ namespace BetterLyrics.WinUI3.Controls
|
||||
|
||||
private async Task HideAsync()
|
||||
{
|
||||
var lyricsWindowSwitchWindow = WindowHelper.GetWindowByWindowType<LyricsWindowSwitchWindow>();
|
||||
var lyricsWindowSwitchWindow = WindowHook.GetWindow<LyricsWindowSwitchWindow>();
|
||||
lyricsWindowSwitchWindow?.ViewModel.RootGridOpacity = 0;
|
||||
await Task.Delay(300);
|
||||
WindowHelper.HideWindow<LyricsWindowSwitchWindow>();
|
||||
lyricsWindowSwitchWindow?.HideWindow();
|
||||
}
|
||||
|
||||
private void ShadowRect_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Shadow.Receivers.Add(ShadowCastGrid);
|
||||
}
|
||||
|
||||
private async void SettingsHypelinkButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
await HideAsync();
|
||||
WindowHook.OpenOrShowWindow<SettingsWindow>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,49 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<Page
|
||||
x:Class="BetterLyrics.WinUI3.Views.LyricsPage"
|
||||
<UserControl
|
||||
x:Class="BetterLyrics.WinUI3.Controls.NowPlayingBar"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:animatedvisuals="using:Microsoft.UI.Xaml.Controls.AnimatedVisuals"
|
||||
xmlns:canvas="using:Microsoft.Graphics.Canvas.UI.Xaml"
|
||||
xmlns:const="using:BetterLyrics.WinUI3.Constants"
|
||||
xmlns:controls="using:CommunityToolkit.WinUI.Controls"
|
||||
xmlns:converters="using:CommunityToolkit.WinUI.Converters"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:dev="using:DevWinUI"
|
||||
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
|
||||
xmlns:local="using:BetterLyrics.WinUI3.Views"
|
||||
xmlns:local="using:BetterLyrics.WinUI3.Controls"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:media="using:CommunityToolkit.WinUI.Media"
|
||||
xmlns:renderer="using:BetterLyrics.WinUI3.Renderer"
|
||||
xmlns:uc="using:BetterLyrics.WinUI3.Controls"
|
||||
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid
|
||||
x:Name="RootGrid"
|
||||
RightTapped="RootGrid_RightTapped"
|
||||
SizeChanged="RootGrid_SizeChanged">
|
||||
<Grid x:Name="RootGrid">
|
||||
|
||||
<!-- Lyrics area -->
|
||||
<renderer:LyricsRenderer />
|
||||
|
||||
<dev:SnowFlakeEffect FlakeCount="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.LyricsBackgroundSettings.SnowFlakeOverlayAmount, Mode=OneWay}" Visibility="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.LyricsBackgroundSettings.IsSnowFlakeOverlayEnabled, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}" />
|
||||
|
||||
<ScrollViewer HorizontalAlignment="Center" VerticalScrollBarVisibility="Hidden">
|
||||
<StackPanel
|
||||
Margin="40"
|
||||
VerticalAlignment="Bottom"
|
||||
dev:Growl.GrowlParent="True" />
|
||||
</ScrollViewer>
|
||||
|
||||
<!--<Grid x:Name="ScrollGrid" PointerWheelChanged="ScrollGrid_PointerWheelChanged" Background="{ThemeResource AccentAcrylicBackgroundFillColorDefaultBrush}" Opacity="0.3"/>-->
|
||||
|
||||
<!-- Bottom command area -->
|
||||
<Grid
|
||||
x:Name="BottomCommandGrid"
|
||||
Margin="12"
|
||||
VerticalAlignment="Bottom"
|
||||
Background="Transparent"
|
||||
Background="{ThemeResource AcrylicInAppFillColorDefaultBrush}"
|
||||
Opacity="{x:Bind ViewModel.BottomCommandGridOpacity, Mode=OneWay}"
|
||||
PointerEntered="BottomCommandGrid_PointerEntered"
|
||||
PointerExited="BottomCommandGrid_PointerExited">
|
||||
@@ -52,22 +23,157 @@
|
||||
</Grid.OpacityTransition>
|
||||
|
||||
<Grid x:Name="BottomCommandContent">
|
||||
<Grid Padding="3" HorizontalAlignment="Left">
|
||||
|
||||
<Grid HorizontalAlignment="Left">
|
||||
<StackPanel
|
||||
x:Name="BottomLeftCommandStackPanel"
|
||||
Orientation="Horizontal"
|
||||
Spacing="3">
|
||||
|
||||
<StackPanel
|
||||
Margin="0,0,0,2"
|
||||
x:Name="SongInfoStackPanel"
|
||||
Margin="8"
|
||||
Padding="8"
|
||||
VerticalAlignment="Center"
|
||||
CornerRadius="4"
|
||||
Opacity="{x:Bind ShowSongInfo, Mode=OneWay, Converter={StaticResource BoolToOpacityConverter}}"
|
||||
Orientation="Horizontal"
|
||||
Spacing="2">
|
||||
Spacing="12"
|
||||
Tapped="SongInfoStackPanel_Tapped"
|
||||
Visibility="{x:Bind ShowSongInfo, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
<StackPanel.OpacityTransition>
|
||||
<ScalarTransition />
|
||||
</StackPanel.OpacityTransition>
|
||||
<interactivity:Interaction.Behaviors>
|
||||
<interactivity:EventTriggerBehavior EventName="PointerEntered">
|
||||
<interactivity:ChangePropertyAction PropertyName="Background" Value="{ThemeResource SubtleFillColorSecondaryBrush}" />
|
||||
</interactivity:EventTriggerBehavior>
|
||||
<interactivity:EventTriggerBehavior EventName="PointerExited">
|
||||
<interactivity:ChangePropertyAction PropertyName="Background" Value="Transparent" />
|
||||
</interactivity:EventTriggerBehavior>
|
||||
<interactivity:EventTriggerBehavior EventName="PointerPressed">
|
||||
<interactivity:ChangePropertyAction PropertyName="Background" Value="{ThemeResource SubtleFillColorTertiaryBrush}" />
|
||||
</interactivity:EventTriggerBehavior>
|
||||
<interactivity:EventTriggerBehavior EventName="PointerReleased">
|
||||
<interactivity:ChangePropertyAction PropertyName="Background" Value="{ThemeResource SubtleFillColorSecondaryBrush}" />
|
||||
</interactivity:EventTriggerBehavior>
|
||||
</interactivity:Interaction.Behaviors>
|
||||
<Grid VerticalAlignment="Center" CornerRadius="4">
|
||||
<local:ImageSwitcher
|
||||
x:Name="AlbumArtImageSwitcher"
|
||||
Width="36"
|
||||
Height="36" />
|
||||
</Grid>
|
||||
<StackPanel VerticalAlignment="Center">
|
||||
<TextBlock x:Name="TitleTextBlock" />
|
||||
<TextBlock
|
||||
x:Name="ArtistsTextBlock"
|
||||
FontSize="12"
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel
|
||||
x:Name="TimeStackPanel"
|
||||
Margin="8"
|
||||
Padding="8"
|
||||
VerticalAlignment="Center"
|
||||
Opacity="{x:Bind ShowTime, Mode=OneWay, Converter={StaticResource BoolToOpacityConverter}}"
|
||||
Orientation="Horizontal"
|
||||
Spacing="2"
|
||||
Tapped="TimeStackPanel_Tapped"
|
||||
Visibility="{x:Bind ShowTime, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
<StackPanel.OpacityTransition>
|
||||
<ScalarTransition />
|
||||
</StackPanel.OpacityTransition>
|
||||
<interactivity:Interaction.Behaviors>
|
||||
<interactivity:EventTriggerBehavior EventName="PointerEntered">
|
||||
<interactivity:ChangePropertyAction PropertyName="Background" Value="{ThemeResource SubtleFillColorSecondaryBrush}" />
|
||||
</interactivity:EventTriggerBehavior>
|
||||
<interactivity:EventTriggerBehavior EventName="PointerExited">
|
||||
<interactivity:ChangePropertyAction PropertyName="Background" Value="Transparent" />
|
||||
</interactivity:EventTriggerBehavior>
|
||||
<interactivity:EventTriggerBehavior EventName="PointerPressed">
|
||||
<interactivity:ChangePropertyAction PropertyName="Background" Value="{ThemeResource SubtleFillColorTertiaryBrush}" />
|
||||
</interactivity:EventTriggerBehavior>
|
||||
<interactivity:EventTriggerBehavior EventName="PointerReleased">
|
||||
<interactivity:ChangePropertyAction PropertyName="Background" Value="{ThemeResource SubtleFillColorSecondaryBrush}" />
|
||||
</interactivity:EventTriggerBehavior>
|
||||
</interactivity:Interaction.Behaviors>
|
||||
<TextBlock Foreground="{ThemeResource TextFillColorSecondaryBrush}" Text="{Binding ElementName=TimelineSlider, Path=Value, Converter={StaticResource SecondsToFormattedTimeConverter}}" />
|
||||
<TextBlock Foreground="{ThemeResource TextFillColorSecondaryBrush}" Text="/" />
|
||||
<TextBlock Text="{Binding ElementName=TimelineSlider, Path=Maximum, Converter={StaticResource SecondsToFormattedTimeConverter}}" />
|
||||
</StackPanel>
|
||||
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<Grid HorizontalAlignment="Center">
|
||||
<StackPanel
|
||||
x:Name="BottomCenterCommandStackPanel"
|
||||
Padding="16"
|
||||
Orientation="Horizontal"
|
||||
Spacing="3">
|
||||
<Button
|
||||
Command="{x:Bind ViewModel.PreviousSongCommand}"
|
||||
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}"
|
||||
Style="{StaticResource GhostButtonStyle}" />
|
||||
<Button
|
||||
Command="{x:Bind ViewModel.PauseSongCommand}"
|
||||
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}"
|
||||
Style="{StaticResource GhostButtonStyle}">
|
||||
<interactivity:Interaction.Behaviors>
|
||||
<interactivity:DataTriggerBehavior
|
||||
Binding="{x:Bind ViewModel.MediaSessionsService.CurrentIsPlaying, Mode=OneWay}"
|
||||
ComparisonCondition="Equal"
|
||||
Value="True">
|
||||
<interactivity:ChangePropertyAction PropertyName="Visibility" Value="Visible" />
|
||||
</interactivity:DataTriggerBehavior>
|
||||
<interactivity:DataTriggerBehavior
|
||||
Binding="{x:Bind ViewModel.MediaSessionsService.CurrentIsPlaying, Mode=OneWay}"
|
||||
ComparisonCondition="Equal"
|
||||
Value="False">
|
||||
<interactivity:ChangePropertyAction PropertyName="Visibility" Value="Collapsed" />
|
||||
</interactivity:DataTriggerBehavior>
|
||||
</interactivity:Interaction.Behaviors>
|
||||
</Button>
|
||||
<Button
|
||||
Command="{x:Bind ViewModel.PlaySongCommand}"
|
||||
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}"
|
||||
Style="{StaticResource GhostButtonStyle}">
|
||||
<interactivity:Interaction.Behaviors>
|
||||
<interactivity:DataTriggerBehavior
|
||||
Binding="{x:Bind ViewModel.MediaSessionsService.CurrentIsPlaying, Mode=OneWay}"
|
||||
ComparisonCondition="Equal"
|
||||
Value="True">
|
||||
<interactivity:ChangePropertyAction PropertyName="Visibility" Value="Collapsed" />
|
||||
</interactivity:DataTriggerBehavior>
|
||||
<interactivity:DataTriggerBehavior
|
||||
Binding="{x:Bind ViewModel.MediaSessionsService.CurrentIsPlaying, Mode=OneWay}"
|
||||
ComparisonCondition="Equal"
|
||||
Value="False">
|
||||
<interactivity:ChangePropertyAction PropertyName="Visibility" Value="Visible" />
|
||||
</interactivity:DataTriggerBehavior>
|
||||
</interactivity:Interaction.Behaviors>
|
||||
</Button>
|
||||
<Button
|
||||
Command="{x:Bind ViewModel.NextSongCommand}"
|
||||
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}"
|
||||
Style="{StaticResource GhostButtonStyle}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<Grid HorizontalAlignment="Right">
|
||||
<StackPanel
|
||||
x:Name="BottomRightCommandStackPanel"
|
||||
Padding="16"
|
||||
Orientation="Horizontal"
|
||||
Spacing="3">
|
||||
|
||||
<!-- Volume -->
|
||||
<Button Click="VolumeButton_Click" Style="{StaticResource GhostButtonStyle}">
|
||||
<Grid>
|
||||
@@ -168,7 +274,7 @@
|
||||
|
||||
<Button.ContextFlyout>
|
||||
<Flyout x:Name="VolumeFlyout" ShouldConstrainToRootBounds="False">
|
||||
<uc:ExtendedSlider
|
||||
<local:ExtendedSlider
|
||||
Frequency="10"
|
||||
IsSliderEnabled="False"
|
||||
Maximum="100"
|
||||
@@ -181,131 +287,54 @@
|
||||
</Button.ContextFlyout>
|
||||
</Button>
|
||||
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<Grid Padding="3" HorizontalAlignment="Center">
|
||||
<StackPanel
|
||||
x:Name="BottomCenterCommandStackPanel"
|
||||
Orientation="Horizontal"
|
||||
Spacing="3">
|
||||
<Button
|
||||
Command="{x:Bind ViewModel.PreviousSongCommand}"
|
||||
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}"
|
||||
Style="{StaticResource GhostButtonStyle}" />
|
||||
<Button
|
||||
Command="{x:Bind ViewModel.PauseSongCommand}"
|
||||
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}"
|
||||
Style="{StaticResource GhostButtonStyle}">
|
||||
<interactivity:Interaction.Behaviors>
|
||||
<interactivity:DataTriggerBehavior
|
||||
Binding="{x:Bind ViewModel.IsSongPlaying, Mode=OneWay}"
|
||||
ComparisonCondition="Equal"
|
||||
Value="True">
|
||||
<interactivity:ChangePropertyAction PropertyName="Visibility" Value="Visible" />
|
||||
</interactivity:DataTriggerBehavior>
|
||||
<interactivity:DataTriggerBehavior
|
||||
Binding="{x:Bind ViewModel.IsSongPlaying, Mode=OneWay}"
|
||||
ComparisonCondition="Equal"
|
||||
Value="False">
|
||||
<interactivity:ChangePropertyAction PropertyName="Visibility" Value="Collapsed" />
|
||||
</interactivity:DataTriggerBehavior>
|
||||
</interactivity:Interaction.Behaviors>
|
||||
</Button>
|
||||
<Button
|
||||
Command="{x:Bind ViewModel.PlaySongCommand}"
|
||||
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}"
|
||||
Style="{StaticResource GhostButtonStyle}">
|
||||
<interactivity:Interaction.Behaviors>
|
||||
<interactivity:DataTriggerBehavior
|
||||
Binding="{x:Bind ViewModel.IsSongPlaying, Mode=OneWay}"
|
||||
ComparisonCondition="Equal"
|
||||
Value="True">
|
||||
<interactivity:ChangePropertyAction PropertyName="Visibility" Value="Collapsed" />
|
||||
</interactivity:DataTriggerBehavior>
|
||||
<interactivity:DataTriggerBehavior
|
||||
Binding="{x:Bind ViewModel.IsSongPlaying, Mode=OneWay}"
|
||||
ComparisonCondition="Equal"
|
||||
Value="False">
|
||||
<interactivity:ChangePropertyAction PropertyName="Visibility" Value="Visible" />
|
||||
</interactivity:DataTriggerBehavior>
|
||||
</interactivity:Interaction.Behaviors>
|
||||
</Button>
|
||||
<Button
|
||||
Command="{x:Bind ViewModel.NextSongCommand}"
|
||||
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}"
|
||||
Style="{StaticResource GhostButtonStyle}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<Grid Padding="3" HorizontalAlignment="Right">
|
||||
<StackPanel
|
||||
x:Name="BottomRightCommandStackPanel"
|
||||
Orientation="Horizontal"
|
||||
Spacing="3">
|
||||
|
||||
<Button
|
||||
Click="LyricsSearchShortcutButton_Click"
|
||||
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}"
|
||||
Style="{StaticResource GhostButtonStyle}">
|
||||
<ToolTipService.ToolTip>
|
||||
<ToolTip x:Uid="LyricsPageLyricsSearchButtonToolTip" />
|
||||
</ToolTipService.ToolTip>
|
||||
</Button>
|
||||
|
||||
<!-- Lyrics window manager shortcut settings -->
|
||||
<Button
|
||||
Click="LyricsSettingsShortcutButton_Click"
|
||||
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}"
|
||||
Style="{StaticResource GhostButtonStyle}">
|
||||
<ToolTipService.ToolTip>
|
||||
<ToolTip x:Uid="LyricsPageLyricsSettingsButtonToolTip" />
|
||||
</ToolTipService.ToolTip>
|
||||
<Button.ContextFlyout>
|
||||
<Flyout
|
||||
x:Name="LyricsSettingsFlyout"
|
||||
Closed="LyricsSettingsFlyout_Closed"
|
||||
FlyoutPresenterStyle="{StaticResource FlyoutPageStyle}"
|
||||
Placement="Right"
|
||||
ShouldConstrainToRootBounds="False" />
|
||||
</Button.ContextFlyout>
|
||||
</Button>
|
||||
|
||||
<!-- Playback shortcut settings -->
|
||||
<Button
|
||||
Click="PlaybackSettingsShortcutButton_Click"
|
||||
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}"
|
||||
Style="{StaticResource GhostButtonStyle}">
|
||||
<ToolTipService.ToolTip>
|
||||
<ToolTip x:Uid="LyricsPagePlaybackSourceButtonToolTip" />
|
||||
</ToolTipService.ToolTip>
|
||||
<Button.ContextFlyout>
|
||||
<Flyout
|
||||
x:Name="PlaybackSettingsFlyout"
|
||||
Closed="PlaybackSettingsFlyout_Closed"
|
||||
FlyoutPresenterStyle="{StaticResource FlyoutPageStyle}"
|
||||
Placement="Right"
|
||||
ShouldConstrainToRootBounds="False" />
|
||||
</Button.ContextFlyout>
|
||||
</Button>
|
||||
|
||||
<!-- Settings -->
|
||||
<Button
|
||||
x:Name="SettingsButton"
|
||||
Command="{x:Bind ViewModel.OpenSettingsWindowCommand}"
|
||||
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}"
|
||||
Style="{StaticResource GhostButtonStyle}">
|
||||
<ToolTipService.ToolTip>
|
||||
<ToolTip x:Name="SettingsToolTip" x:Uid="LyricsPageSettingsButtonToolTip" />
|
||||
</ToolTipService.ToolTip>
|
||||
<!-- More -->
|
||||
<Button Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}" Style="{StaticResource GhostButtonStyle}">
|
||||
<Button.Flyout>
|
||||
<MenuFlyout>
|
||||
<!-- Lyrics search window -->
|
||||
<MenuFlyoutItem
|
||||
x:Uid="LyricsPageLyricsSearch"
|
||||
Command="{x:Bind ViewModel.OpenLyricsSearchWindowCommand}"
|
||||
Icon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}" />
|
||||
<!-- Lyrics window manager shortcut settings -->
|
||||
<MenuFlyoutItem
|
||||
x:Uid="LyricsPageLyricsSettings"
|
||||
Click="LyricsSettingsShortcutMenuFlyoutItem_Click"
|
||||
Icon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}">
|
||||
<MenuFlyoutItem.ContextFlyout>
|
||||
<Flyout
|
||||
x:Name="LyricsSettingsFlyout"
|
||||
Closed="LyricsSettingsFlyout_Closed"
|
||||
FlyoutPresenterStyle="{StaticResource FlyoutPageStyle}"
|
||||
Placement="Right"
|
||||
ShouldConstrainToRootBounds="False" />
|
||||
</MenuFlyoutItem.ContextFlyout>
|
||||
</MenuFlyoutItem>
|
||||
<!-- Playback shortcut settings -->
|
||||
<MenuFlyoutItem
|
||||
x:Uid="LyricsPagePlaybackSource"
|
||||
Click="PlaybackSettingsShortcutMenuFlyoutItem_Click"
|
||||
Icon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}">
|
||||
<MenuFlyoutItem.ContextFlyout>
|
||||
<Flyout
|
||||
x:Name="PlaybackSettingsFlyout"
|
||||
Closed="PlaybackSettingsFlyout_Closed"
|
||||
FlyoutPresenterStyle="{StaticResource FlyoutPageStyle}"
|
||||
Placement="Right"
|
||||
ShouldConstrainToRootBounds="False" />
|
||||
</MenuFlyoutItem.ContextFlyout>
|
||||
</MenuFlyoutItem>
|
||||
<!-- Settings -->
|
||||
<MenuFlyoutItem
|
||||
x:Uid="LyricsPageSettings"
|
||||
Command="{x:Bind ViewModel.OpenSettingsWindowCommand}"
|
||||
Icon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}" />
|
||||
</MenuFlyout>
|
||||
</Button.Flyout>
|
||||
</Button>
|
||||
|
||||
</StackPanel>
|
||||
@@ -313,21 +342,21 @@
|
||||
|
||||
<Slider
|
||||
x:Name="TimelineSlider"
|
||||
Margin="0,-32,0,0"
|
||||
Margin="0,-12,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Top"
|
||||
Maximum="{x:Bind ViewModel.SongDurationSeconds, Mode=OneWay}"
|
||||
Maximum="{x:Bind ViewModel.MediaSessionsService.CurrentSongInfo.DurationMs, Mode=OneWay, Converter={StaticResource MillisecondsToSecondsConverter}}"
|
||||
Minimum="0"
|
||||
Style="{StaticResource GhostSliderStyle}"
|
||||
ThumbToolTipValueConverter="{StaticResource SecondsToFormattedTimeConverter}"
|
||||
Value="{x:Bind ViewModel.TimelinePositionSeconds, Mode=OneWay}" />
|
||||
ThumbToolTipValueConverter="{StaticResource SecondsToFormattedTimeConverter}" />
|
||||
|
||||
<Grid
|
||||
x:Name="TimelineSliderLyricsLineInfo"
|
||||
Margin="0,-48,0,0"
|
||||
Margin="0,-32,0,0"
|
||||
Padding="8,4"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Top"
|
||||
Background="{ThemeResource SolidBackgroundFillColorQuarternaryBrush}"
|
||||
Background="{ThemeResource AcrylicInAppFillColorDefaultBrush}"
|
||||
CornerRadius="6"
|
||||
Opacity="{x:Bind ViewModel.TimelineSliderThumbOpacity, Mode=OneWay}">
|
||||
<Grid.OpacityTransition>
|
||||
@@ -347,7 +376,7 @@
|
||||
</Grid>
|
||||
<Grid
|
||||
Height="32"
|
||||
Margin="0,-32,0,0"
|
||||
Margin="0,-12,0,0"
|
||||
VerticalAlignment="Top"
|
||||
Background="Transparent"
|
||||
PointerEntered="TimelineSliderOverlay_PointerEntered"
|
||||
@@ -387,7 +416,8 @@
|
||||
<Flyout x:Name="BottomCommandFlyout" ShouldConstrainToRootBounds="False">
|
||||
<Flyout.FlyoutPresenterStyle>
|
||||
<Style TargetType="FlyoutPresenter">
|
||||
<Setter Property="MinWidth" Value="500" />
|
||||
<Setter Property="Padding" Value="0" />
|
||||
<Setter Property="MinWidth" Value="400" />
|
||||
<Setter Property="MinHeight" Value="100" />
|
||||
<Setter Property="CornerRadius" Value="12" />
|
||||
</Style>
|
||||
@@ -397,7 +427,7 @@
|
||||
</Grid.ContextFlyout>
|
||||
</Grid>
|
||||
|
||||
<uc:SystemTray />
|
||||
|
||||
</Grid>
|
||||
</Page>
|
||||
|
||||
</UserControl>
|
||||
@@ -0,0 +1,301 @@
|
||||
using BetterLyrics.WinUI3.Hooks;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.Services.MediaSessionsService;
|
||||
using BetterLyrics.WinUI3.ViewModels;
|
||||
using BetterLyrics.WinUI3.Views;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using CommunityToolkit.Mvvm.Messaging.Messages;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Input;
|
||||
using Microsoft.UI.Xaml.Media.Imaging;
|
||||
using System;
|
||||
using System.Numerics;
|
||||
|
||||
// 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 NowPlayingBar : UserControl,
|
||||
IRecipient<PropertyChangedMessage<SongInfo?>>,
|
||||
IRecipient<PropertyChangedMessage<BitmapImage?>>,
|
||||
IRecipient<PropertyChangedMessage<TimeSpan>>
|
||||
{
|
||||
public NowPlayingBarViewModel ViewModel => (NowPlayingBarViewModel)DataContext;
|
||||
|
||||
public event EventHandler? SongInfoTapped;
|
||||
public event EventHandler? TimeTapped;
|
||||
|
||||
public bool ShowTime
|
||||
{
|
||||
get { return (bool)GetValue(ShowTimeProperty); }
|
||||
set { SetValue(ShowTimeProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ShowTimeProperty =
|
||||
DependencyProperty.Register(nameof(ShowTime), typeof(bool), typeof(NowPlayingBar), new PropertyMetadata(false));
|
||||
|
||||
public bool ShowSongInfo
|
||||
{
|
||||
get { return (bool)GetValue(ShowSongInfoProperty); }
|
||||
set { SetValue(ShowSongInfoProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ShowSongInfoProperty =
|
||||
DependencyProperty.Register(nameof(ShowSongInfo), typeof(bool), typeof(NowPlayingBar), new PropertyMetadata(false));
|
||||
|
||||
public bool IsCompactMode
|
||||
{
|
||||
get { return (bool)GetValue(IsCompactModeProperty); }
|
||||
set { SetValue(IsCompactModeProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsCompactModeProperty =
|
||||
DependencyProperty.Register(nameof(IsCompactMode), typeof(bool), typeof(NowPlayingBar), new PropertyMetadata(false, OnDependencyPropertyChanged));
|
||||
|
||||
public bool IsAutoHideEnabled
|
||||
{
|
||||
get { return (bool)GetValue(IsAutoHideEnabledProperty); }
|
||||
set { SetValue(IsAutoHideEnabledProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsAutoHideEnabledProperty =
|
||||
DependencyProperty.Register(nameof(IsAutoHideEnabled), typeof(bool), typeof(NowPlayingBar), new PropertyMetadata(false, OnDependencyPropertyChanged));
|
||||
|
||||
private bool _isPointerInBottomCommandGrid = false;
|
||||
|
||||
public NowPlayingBar()
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContext = Ioc.Default.GetRequiredService<NowPlayingBarViewModel>();
|
||||
|
||||
WeakReferenceMessenger.Default.RegisterAll(this);
|
||||
}
|
||||
|
||||
private static void OnDependencyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is NowPlayingBar self)
|
||||
{
|
||||
if (e.Property == IsCompactModeProperty)
|
||||
{
|
||||
self.OnIsCompactModeChanged();
|
||||
}
|
||||
else if (e.Property == IsAutoHideEnabledProperty)
|
||||
{
|
||||
self.OnIsAutoHideEnabledChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnIsAutoHideEnabledChanged()
|
||||
{
|
||||
if (IsAutoHideEnabled)
|
||||
{
|
||||
if (!_isPointerInBottomCommandGrid)
|
||||
{
|
||||
ViewModel.BottomCommandGridOpacity = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ViewModel.BottomCommandGridOpacity = 1;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnIsCompactModeChanged()
|
||||
{
|
||||
if (IsCompactMode)
|
||||
{
|
||||
if (BottomCommandGrid.Children.Count != 0)
|
||||
{
|
||||
BottomCommandGrid.Children.Remove(BottomCommandContent);
|
||||
BottomCommandFlyoutContainer.Children.Add(BottomCommandContent);
|
||||
}
|
||||
BottomCommandFlyoutTriggerHint.Translation = new Vector3(0, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (BottomCommandFlyoutContainer.Children.Count != 0)
|
||||
{
|
||||
BottomCommandFlyout.Hide();
|
||||
BottomCommandFlyoutContainer.Children.Remove(BottomCommandContent);
|
||||
BottomCommandGrid.Children.Add(BottomCommandContent);
|
||||
}
|
||||
BottomCommandFlyoutTriggerHint.Translation = new Vector3(0, 12, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private void PlaybackSettingsShortcutMenuFlyoutItem_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
PlaybackSettingsFlyout.Content = new PlaybackSettingsControl
|
||||
{
|
||||
MaxHeight = 500,
|
||||
MaxWidth = 850,
|
||||
};
|
||||
PlaybackSettingsFlyout.ShowAt(BottomRightCommandStackPanel);
|
||||
}
|
||||
|
||||
private void VolumeButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
VolumeFlyout.ShowAt(BottomRightCommandStackPanel);
|
||||
}
|
||||
|
||||
private void PlaybackSettingsFlyout_Closed(object sender, object e)
|
||||
{
|
||||
PlaybackSettingsFlyout.Content = null;
|
||||
}
|
||||
|
||||
private void LyricsSettingsFlyout_Closed(object sender, object e)
|
||||
{
|
||||
LyricsSettingsFlyout.Content = null;
|
||||
}
|
||||
|
||||
private void LyricsSettingsShortcutMenuFlyoutItem_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
LyricsSettingsFlyout.Content = new LyricsWindowSettingsControl
|
||||
{
|
||||
MaxHeight = 500,
|
||||
MaxWidth = 850,
|
||||
};
|
||||
LyricsSettingsFlyout.ShowAt(BottomRightCommandStackPanel);
|
||||
}
|
||||
|
||||
private void TimelineSliderOverlay_PointerPressed(object sender, Microsoft.UI.Xaml.Input.PointerRoutedEventArgs e)
|
||||
{
|
||||
var grid = (Grid)sender;
|
||||
var pos = e.GetCurrentPoint(grid).Position;
|
||||
var ratio = pos.X / grid.ActualWidth;
|
||||
ViewModel.MediaSessionsService.ChangePosition(TimelineSlider.Maximum * ratio);
|
||||
}
|
||||
|
||||
private void TimelineSliderOverlay_PointerMoved(object sender, Microsoft.UI.Xaml.Input.PointerRoutedEventArgs e)
|
||||
{
|
||||
float targetX;
|
||||
var grid = (Grid)sender;
|
||||
var pos = e.GetCurrentPoint(grid).Position;
|
||||
var ratio = pos.X / grid.ActualWidth;
|
||||
ViewModel.TimelineSliderThumbSeconds = TimelineSlider.Maximum * ratio;
|
||||
if (pos.X + TimelineSliderLyricsLineInfo.ActualWidth > grid.ActualWidth)
|
||||
{
|
||||
targetX = (float)(grid.ActualWidth - TimelineSliderLyricsLineInfo.ActualWidth);
|
||||
}
|
||||
else
|
||||
{
|
||||
targetX = (float)pos.X;
|
||||
}
|
||||
TimelineSliderLyricsLineInfo.Translation = new Vector3(targetX, 0, 0);
|
||||
}
|
||||
|
||||
private void TimelineSliderOverlay_PointerEntered(object sender, Microsoft.UI.Xaml.Input.PointerRoutedEventArgs e)
|
||||
{
|
||||
ViewModel.TimelineSliderThumbOpacity = 0.7f;
|
||||
}
|
||||
|
||||
private void TimelineSliderOverlay_PointerExited(object sender, Microsoft.UI.Xaml.Input.PointerRoutedEventArgs e)
|
||||
{
|
||||
ViewModel.TimelineSliderThumbOpacity = 0f;
|
||||
}
|
||||
|
||||
private void ExtendedSlider_ValueChangedByUser(object sender, Events.ExtendedSliderValueChangedByUserEventArgs e)
|
||||
{
|
||||
SystemVolumeHook.MasterVolume = ViewModel.Volume;
|
||||
}
|
||||
|
||||
private void LyricsSearchShortcutButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
WindowHook.OpenOrShowWindow<LyricsSearchWindow>();
|
||||
}
|
||||
|
||||
private void SongInfoStackPanel_Tapped(object sender, TappedRoutedEventArgs e)
|
||||
{
|
||||
SongInfoTapped?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
private void TimeStackPanel_Tapped(object sender, TappedRoutedEventArgs e)
|
||||
{
|
||||
TimeTapped?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
private void BottomCommandGrid_PointerEntered(object sender, Microsoft.UI.Xaml.Input.PointerRoutedEventArgs e)
|
||||
{
|
||||
_isPointerInBottomCommandGrid = true;
|
||||
if (IsAutoHideEnabled && BottomCommandGrid.Children.Count != 0)
|
||||
{
|
||||
ViewModel.BottomCommandGridOpacity = 1f;
|
||||
}
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void BottomCommandGrid_PointerExited(object sender, Microsoft.UI.Xaml.Input.PointerRoutedEventArgs e)
|
||||
{
|
||||
_isPointerInBottomCommandGrid = false;
|
||||
if (IsAutoHideEnabled && BottomCommandGrid.Children.Count != 0)
|
||||
{
|
||||
ViewModel.BottomCommandGridOpacity = 0f;
|
||||
}
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void BottomCommandFlyoutTrigger_PointerEntered(object sender, Microsoft.UI.Xaml.Input.PointerRoutedEventArgs e)
|
||||
{
|
||||
if (BottomCommandFlyoutContainer.Children.Count != 0)
|
||||
{
|
||||
ViewModel.BottomCommandFlyoutTriggerOpacity = 1f;
|
||||
}
|
||||
}
|
||||
|
||||
private void BottomCommandFlyoutTrigger_PointerExited(object sender, Microsoft.UI.Xaml.Input.PointerRoutedEventArgs e)
|
||||
{
|
||||
if (BottomCommandFlyoutContainer.Children.Count != 0)
|
||||
{
|
||||
ViewModel.BottomCommandFlyoutTriggerOpacity = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
private void BottomCommandFlyoutTrigger_Tapped(object sender, Microsoft.UI.Xaml.Input.TappedRoutedEventArgs e)
|
||||
{
|
||||
if (BottomCommandFlyoutContainer.Children.Count != 0)
|
||||
{
|
||||
BottomCommandFlyout.ShowAt(BottomCommandFlyoutTrigger);
|
||||
}
|
||||
}
|
||||
|
||||
public void Receive(PropertyChangedMessage<SongInfo?> message)
|
||||
{
|
||||
if (message.Sender is IMediaSessionsService)
|
||||
{
|
||||
if (message.PropertyName == nameof(IMediaSessionsService.CurrentSongInfo))
|
||||
{
|
||||
TitleTextBlock.Text = message.NewValue?.Title;
|
||||
ArtistsTextBlock.Text = message.NewValue?.DisplayArtists;
|
||||
}
|
||||
}
|
||||
}
|
||||
public void Receive(PropertyChangedMessage<BitmapImage?> message)
|
||||
{
|
||||
if (message.Sender is IMediaSessionsService)
|
||||
{
|
||||
if (message.PropertyName == nameof(IMediaSessionsService.AlbumArtBitmapImage))
|
||||
{
|
||||
AlbumArtImageSwitcher.Source = message.NewValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Receive(PropertyChangedMessage<TimeSpan> message)
|
||||
{
|
||||
if (message.Sender is IMediaSessionsService)
|
||||
{
|
||||
if (message.PropertyName == nameof(IMediaSessionsService.CurrentPosition))
|
||||
{
|
||||
DispatcherQueue.TryEnqueue(() =>
|
||||
{
|
||||
TimelineSlider.Value = message.NewValue.TotalSeconds;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -21,8 +21,75 @@
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Grid Grid.Column="0">
|
||||
<ScrollViewer Margin="0,72,0,0" Style="{StaticResource SettingsScrollViewerStyle}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<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>
|
||||
|
||||
<InfoBar
|
||||
Grid.Row="0"
|
||||
IsClosable="False"
|
||||
IsOpen="{x:Bind ViewModel.AppSettings.MusicGallerySettings.LyricsWindowStatus.IsOpened, Mode=OneWay}"
|
||||
Message="音乐库窗口已打开,将忽略对其他播放源的监听"
|
||||
Severity="Informational" />
|
||||
|
||||
<!-- 播放源列表 -->
|
||||
<Grid Grid.Row="1" Margin="36,0,36,4">
|
||||
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
|
||||
<TextBlock x:Uid="SettingsPageConfigPlaybackSource" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
<ComboBox
|
||||
x:Name="MediaSourceProvidersListView"
|
||||
HorizontalAlignment="Stretch"
|
||||
ItemsSource="{x:Bind ViewModel.AppSettings.MediaSourceProvidersInfo, Mode=OneWay}"
|
||||
SelectedItem="{x:Bind ViewModel.SelectedMediaSourceProvider, Mode=TwoWay}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="models:MediaSourceProviderInfo">
|
||||
<Grid Padding="2,4" ColumnSpacing="12">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<ToolTipService.ToolTip>
|
||||
<ToolTip Content="{Binding Provider, Mode=OneWay}" />
|
||||
</ToolTipService.ToolTip>
|
||||
<Grid
|
||||
Grid.Column="0"
|
||||
Width="16"
|
||||
Height="16"
|
||||
CornerRadius="4">
|
||||
<ImageIcon Source="{Binding LogoPath}" />
|
||||
</Grid>
|
||||
<TextBlock
|
||||
Grid.Column="1"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding DisplayName, Mode=OneWay}"
|
||||
TextWrapping="Wrap" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<!-- 播放源配置 -->
|
||||
<ScrollViewer Grid.Row="2" Style="{StaticResource SettingsScrollViewerStyle}">
|
||||
<Grid Style="{StaticResource SettingsGridStyle}">
|
||||
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
|
||||
|
||||
@@ -34,6 +101,31 @@
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.SelectedMediaSourceProvider.IsLastFMTrackEnabled, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageDiscordPresence">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.SelectedMediaSourceProvider.IsDiscordPresenceEnabled, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
<!-- LX music server -->
|
||||
<dev:SettingsCard x:Uid="SettingsPageLXMusicServer" Visibility="{x:Bind ViewModel.SelectedMediaSourceProvider.IsLXMusic, Converter={StaticResource BoolToVisibilityConverter}, Mode=OneWay}">
|
||||
<Grid ColumnSpacing="6">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBox
|
||||
x:Uid="SettingsPageLXMusicServerInput"
|
||||
Grid.Column="0"
|
||||
IsEnabled="{x:Bind ViewModel.IsLXMusicServerTesting, Converter={StaticResource BoolNegationConverter}, Mode=OneWay}"
|
||||
Text="{x:Bind ViewModel.AppSettings.GeneralSettings.LXMusicServer, Mode=TwoWay}"
|
||||
TextWrapping="Wrap" />
|
||||
<Button
|
||||
x:Uid="SettingsPageServerTestButton"
|
||||
Grid.Column="1"
|
||||
Command="{x:Bind ViewModel.LXMusicServerTestCommand}"
|
||||
IsEnabled="{x:Bind ViewModel.IsLXMusicServerTesting, Converter={StaticResource BoolNegationConverter}, Mode=OneWay}" />
|
||||
</Grid>
|
||||
</dev:SettingsCard>
|
||||
|
||||
<!-- 时间轴相关配置 -->
|
||||
<dev:SettingsExpander x:Uid="SettingsPageLyricsTimeline" IsExpanded="True">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.SelectedMediaSourceProvider.IsTimelineSyncEnabled, Mode=TwoWay}" />
|
||||
@@ -93,6 +185,21 @@
|
||||
|
||||
<!-- 歌词源配置 -->
|
||||
<TextBlock x:Uid="SettingsPageLyricsSearchProvidersConfig" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
<dev:SettingsCard x:Uid="SettingsPageLyricsSearchType">
|
||||
<ComboBox SelectedIndex="{x:Bind ViewModel.SelectedMediaSourceProvider.LyricsSearchType, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsSearchSequential" />
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsSearchBestMatch" />
|
||||
</ComboBox>
|
||||
</dev:SettingsCard>
|
||||
<dev:SettingsCard x:Uid="SettingsPageMatchingThreshold">
|
||||
<local:ExtendedSlider
|
||||
Default="0"
|
||||
Maximum="100"
|
||||
Minimum="0"
|
||||
Unit="%"
|
||||
Value="{x:Bind ViewModel.SelectedMediaSourceProvider.MatchingThreshold, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
<ListView
|
||||
x:Name="LyricsSearchProvidersListView"
|
||||
AllowDrop="True"
|
||||
@@ -113,12 +220,48 @@
|
||||
</ListView.ItemContainerStyle>
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate x:DataType="models:LyricsSearchProviderInfo">
|
||||
<dev:SettingsCard Header="{Binding Provider, Converter={StaticResource LyricsSearchProviderToDisplayNameConverter}, Mode=OneWay}">
|
||||
<dev:SettingsCard.HeaderIcon>
|
||||
<FontIcon FontFamily="Segoe UI Symbol" Glyph="⠿" />
|
||||
</dev:SettingsCard.HeaderIcon>
|
||||
<ToggleSwitch IsOn="{Binding IsEnabled, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
<Grid>
|
||||
<dev:SettingsExpander Header="{Binding Provider, Converter={StaticResource LyricsSearchProviderToDisplayNameConverter}, Mode=OneWay}" IsExpanded="{Binding IsMatchingThresholdOverwritten, Mode=OneWay}">
|
||||
<dev:SettingsExpander.HeaderIcon>
|
||||
<FontIcon FontFamily="Segoe UI Symbol" Glyph="⠿" />
|
||||
</dev:SettingsExpander.HeaderIcon>
|
||||
<ToggleSwitch IsOn="{Binding IsEnabled, Mode=TwoWay}" />
|
||||
<dev:SettingsExpander.Items>
|
||||
<dev:SettingsCard x:Uid="SettingsPageOverwriteMatchingThreshold">
|
||||
<ToggleSwitch IsOn="{Binding IsMatchingThresholdOverwritten, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
<dev:SettingsCard x:Uid="SettingsPageMatchingThreshold" IsEnabled="{Binding IsMatchingThresholdOverwritten, Mode=OneWay}">
|
||||
<local:ExtendedSlider
|
||||
Default="0"
|
||||
Maximum="100"
|
||||
Minimum="0"
|
||||
Unit="%"
|
||||
Value="{Binding MatchingThreshold, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
</dev:SettingsExpander.Items>
|
||||
</dev:SettingsExpander>
|
||||
<Grid
|
||||
Width="48"
|
||||
HorizontalAlignment="Left"
|
||||
Background="{ThemeResource ControlStrokeColorDefaultBrush}"
|
||||
CornerRadius="4,0,0,4"
|
||||
Opacity="0">
|
||||
<interactivity:Interaction.Behaviors>
|
||||
<interactivity:EventTriggerBehavior EventName="PointerEntered">
|
||||
<interactivity:ChangePropertyAction PropertyName="Opacity" Value="1" />
|
||||
</interactivity:EventTriggerBehavior>
|
||||
<interactivity:EventTriggerBehavior EventName="PointerExited">
|
||||
<interactivity:ChangePropertyAction PropertyName="Opacity" Value="0" />
|
||||
</interactivity:EventTriggerBehavior>
|
||||
</interactivity:Interaction.Behaviors>
|
||||
<Grid.OpacityTransition>
|
||||
<ScalarTransition />
|
||||
</Grid.OpacityTransition>
|
||||
<ToolTipService.ToolTip>
|
||||
<ToolTip x:Uid="SettingsPageHoldDragSort" />
|
||||
</ToolTipService.ToolTip>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
@@ -127,57 +270,9 @@
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
|
||||
<!-- 播放源列表 -->
|
||||
<ListView
|
||||
x:Name="MediaSourceProvidersListView"
|
||||
VerticalAlignment="Top"
|
||||
AllowDrop="True"
|
||||
CanDragItems="True"
|
||||
CanReorderItems="True"
|
||||
DragItemsCompleted="MediaSourceProvidersListView_DragItemsCompleted"
|
||||
ItemsSource="{x:Bind ViewModel.AppSettings.MediaSourceProvidersInfo, Mode=OneWay}"
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Hidden"
|
||||
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">
|
||||
<FontIcon
|
||||
FontFamily="Segoe UI Symbol"
|
||||
FontSize="12"
|
||||
Glyph="⠿" />
|
||||
<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"
|
||||
@@ -203,24 +298,80 @@
|
||||
HorizontalAlignment="Center"
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- 右侧杂项设置 -->
|
||||
<Grid Grid.Column="1">
|
||||
<ScrollViewer Style="{StaticResource SettingsScrollViewerStyle}">
|
||||
<Grid Style="{StaticResource SettingsGridStyle}">
|
||||
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
|
||||
|
||||
<!-- Provider info -->
|
||||
<!-- Realtime info -->
|
||||
<TextBlock x:Uid="SettingsPageRealtimeStatus" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
<dev:SettingsCard x:Uid="LyricsPageLyricsProviderPrefix">
|
||||
<HyperlinkButton
|
||||
Content="{x:Bind ViewModel.LyricsSearchProvider, Mode=OneWay, Converter={StaticResource LyricsSearchProviderToDisplayNameConverter}}"
|
||||
IsEnabled="False"
|
||||
NavigateUri="{x:Bind ViewModel.OriginalLyricsRef, Mode=OneWay}" />
|
||||
|
||||
<!-- Playback source info -->
|
||||
<Expander
|
||||
x:Uid="SettingsPagePlaybackStatus"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Left">
|
||||
<StackPanel Spacing="6">
|
||||
<local:PropertyRow x:Uid="SettingsPagePlaybackSource" Value="{x:Bind ViewModel.MediaSessionsService.CurrentMediaSourceProviderInfo.DisplayName, Mode=OneWay}" />
|
||||
<local:PropertyRow x:Uid="SettingsPagePlaybackSourceID" Value="{x:Bind ViewModel.MediaSessionsService.CurrentSongInfo.PlayerId, TargetNullValue=N/A, Mode=OneWay}" />
|
||||
</StackPanel>
|
||||
</Expander>
|
||||
|
||||
<!-- Song info -->
|
||||
<Expander
|
||||
x:Uid="SettingsPageSongStatus"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Left">
|
||||
<StackPanel Spacing="6">
|
||||
<local:PropertyRow x:Uid="SettingsPageSongTitle" Value="{x:Bind ViewModel.MediaSessionsService.CurrentSongInfo.Title, TargetNullValue=N/A, Mode=OneWay}" />
|
||||
<local:PropertyRow x:Uid="SettingsPageArtist" Value="{x:Bind ViewModel.MediaSessionsService.CurrentSongInfo.DisplayArtists, TargetNullValue=N/A, Mode=OneWay}" />
|
||||
<local:PropertyRow x:Uid="SettingsPageAlbum" Value="{x:Bind ViewModel.MediaSessionsService.CurrentSongInfo.Album, TargetNullValue=N/A, Mode=OneWay}" />
|
||||
<local:PropertyRow
|
||||
x:Uid="LyricsSearchControlDurauion"
|
||||
Unit="s"
|
||||
Value="{x:Bind ViewModel.MediaSessionsService.CurrentSongInfo.Duration, TargetNullValue=N/A, Mode=OneWay}" />
|
||||
</StackPanel>
|
||||
</Expander>
|
||||
|
||||
<!-- Search result info -->
|
||||
<Expander
|
||||
x:Uid="SettingsPageSearchResultStatus"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Left">
|
||||
<StackPanel Spacing="6">
|
||||
<local:PropertyRow x:Uid="SettingsPageSongTitle" Value="{x:Bind ViewModel.MediaSessionsService.CurrentLyricsSearchResult.Title, TargetNullValue=N/A, Mode=OneWay}" />
|
||||
<local:PropertyRow x:Uid="SettingsPageArtist" Value="{x:Bind ViewModel.MediaSessionsService.CurrentLyricsSearchResult.DisplayArtists, TargetNullValue=N/A, Mode=OneWay}" />
|
||||
<local:PropertyRow x:Uid="SettingsPageAlbum" Value="{x:Bind ViewModel.MediaSessionsService.CurrentLyricsSearchResult.Album, TargetNullValue=N/A, Mode=OneWay}" />
|
||||
<local:PropertyRow
|
||||
x:Uid="LyricsSearchControlDurauion"
|
||||
Unit="s"
|
||||
Value="{x:Bind ViewModel.MediaSessionsService.CurrentLyricsSearchResult.Duration, TargetNullValue=N/A, Mode=OneWay}" />
|
||||
<local:PropertyRow
|
||||
x:Uid="LyricsPageLyricsProviderPrefix"
|
||||
Link="{x:Bind ViewModel.MediaSessionsService.CurrentLyricsSearchResult.Reference, Mode=OneWay}"
|
||||
ToolTipService.ToolTip="{x:Bind ViewModel.MediaSessionsService.CurrentLyricsSearchResult.Reference, TargetNullValue=N/A, Mode=OneWay}"
|
||||
Value="{x:Bind ViewModel.MediaSessionsService.CurrentLyricsSearchResult.ProviderIfFound, Mode=OneWay, Converter={StaticResource LyricsSearchProviderToDisplayNameConverter}}" />
|
||||
<local:PropertyRow x:Uid="LyricsPageTransliterationProviderPrefix" Value="{x:Bind ViewModel.MediaSessionsService.CurrentLyricsSearchResult.TransliterationProvider, Mode=OneWay, Converter={StaticResource TransliterationSearchProviderToDisplayNameConverter}}" />
|
||||
<local:PropertyRow x:Uid="LyricsPageTranslationProviderPrefix" Value="{x:Bind ViewModel.MediaSessionsService.CurrentLyricsSearchResult.TranslationProvider, Mode=OneWay, Converter={StaticResource TranslationSearchProviderToDisplayNameConverter}}" />
|
||||
<local:PropertyRow
|
||||
x:Uid="LyricsPageMatchPercentage"
|
||||
Unit="%"
|
||||
Value="{x:Bind ViewModel.MediaSessionsService.CurrentLyricsSearchResult.MatchPercentage, Mode=OneWay}" />
|
||||
<local:PropertyRow
|
||||
x:Uid="LyricsPageCachePath"
|
||||
Link="{x:Bind ViewModel.MediaSessionsService.CurrentLyricsSearchResult.SelfPath, TargetNullValue=N/A, Mode=OneWay}"
|
||||
ToolTipService.ToolTip="{x:Bind ViewModel.MediaSessionsService.CurrentLyricsSearchResult.SelfPath, TargetNullValue=N/A, Mode=OneWay}" />
|
||||
</StackPanel>
|
||||
</Expander>
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageListenNewSession">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.GeneralSettings.ListenOnNewPlaybackSource, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
<dev:SettingsCard x:Uid="LyricsPageTranslationProviderPrefix">
|
||||
<HyperlinkButton
|
||||
Content="{x:Bind ViewModel.TranslationSearchProvider, Mode=OneWay, Converter={StaticResource TranslationSearchProviderToDisplayNameConverter}}"
|
||||
IsEnabled="False"
|
||||
NavigateUri="{x:Bind ViewModel.TranslatedLyricsRef, Mode=OneWay}" />
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageForceWordByWordEffect">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.GeneralSettings.IsForceWordByWordEffect, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
<!-- Lyrics translation -->
|
||||
@@ -241,12 +392,7 @@
|
||||
</dev:SettingsCard>
|
||||
<dev:SettingsCard x:Uid="SettingsPageTranslationConfig" IsEnabled="{x:Bind ViewModel.AppSettings.TranslationSettings.IsTranslationEnabled, Mode=OneWay}">
|
||||
<dev:SettingsCard.Description>
|
||||
<HyperlinkButton Margin="0,6,0,0" NavigateUri="https://github.com/LibreTranslate/LibreTranslate">
|
||||
<TextBlock
|
||||
x:Uid="SettingsPageTranslationInfoLink"
|
||||
FontSize="14"
|
||||
TextWrapping="Wrap" />
|
||||
</HyperlinkButton>
|
||||
<HyperlinkButton Content="https://github.com/LibreTranslate/LibreTranslate" NavigateUri="https://github.com/LibreTranslate/LibreTranslate" />
|
||||
</dev:SettingsCard.Description>
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.TranslationSettings.IsLibreTranslateEnabled, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
@@ -320,19 +466,25 @@
|
||||
</dev:SettingsExpander.Items>
|
||||
</dev:SettingsExpander>
|
||||
|
||||
<!-- LX music server -->
|
||||
<TextBlock x:Uid="SettingsPageLXMusicServer" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
<dev:SettingsCard x:Uid="SettingsPageServerAddress">
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<!-- amll-ttml-db -->
|
||||
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" Text="amll-ttml-db" />
|
||||
<dev:SettingsCard x:Uid="SettingsPageAmllTtmlDbBaseUrl">
|
||||
<Grid ColumnSpacing="6">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBox
|
||||
x:Uid="SettingsPageLXMusicServerInput"
|
||||
IsEnabled="{x:Bind ViewModel.IsLXMusicServerTesting, Converter={StaticResource BoolNegationConverter}, Mode=OneWay}"
|
||||
Text="{x:Bind ViewModel.AppSettings.GeneralSettings.LXMusicServer, Mode=TwoWay}" />
|
||||
Grid.Column="0"
|
||||
Text="{x:Bind ViewModel.AppSettings.GeneralSettings.AmllTtmlDbBaseUrl, Mode=TwoWay}"
|
||||
TextWrapping="Wrap" />
|
||||
<Button
|
||||
x:Uid="SettingsPageServerTestButton"
|
||||
Command="{x:Bind ViewModel.LXMusicServerTestCommand}"
|
||||
IsEnabled="{x:Bind ViewModel.IsLXMusicServerTesting, Converter={StaticResource BoolNegationConverter}, Mode=OneWay}" />
|
||||
</StackPanel>
|
||||
Grid.Column="1"
|
||||
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
FontSize=12,
|
||||
Glyph=}"
|
||||
Style="{StaticResource GhostButtonStyle}" />
|
||||
</Grid>
|
||||
</dev:SettingsCard>
|
||||
|
||||
<!-- Apple Music token -->
|
||||
@@ -342,26 +494,38 @@
|
||||
Description="Use at your own risk"
|
||||
Foreground="{ThemeResource SystemFillColorCautionBrush}"
|
||||
Header="WARNING">
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<Grid ColumnSpacing="6">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBox
|
||||
MaxWidth="250"
|
||||
Grid.Column="0"
|
||||
PlaceholderText="media-user-token"
|
||||
Text="{x:Bind ViewModel.AppleMusicMediaUserToken, Mode=TwoWay}"
|
||||
TextWrapping="Wrap" />
|
||||
<HyperlinkButton Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, FontSize=12, Glyph=}" NavigateUri="{x:Bind constants:Link.AppleMusicCfgUrl}" />
|
||||
<HyperlinkButton
|
||||
Grid.Column="1"
|
||||
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
FontSize=12,
|
||||
Glyph=}"
|
||||
NavigateUri="{x:Bind constants:Link.AppleMusicCfg}" />
|
||||
<Button
|
||||
Grid.Column="2"
|
||||
Command="{x:Bind ViewModel.SaveAppleMusicMediaUserTokenCommand}"
|
||||
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
FontSize=12,
|
||||
Glyph=}"
|
||||
Style="{StaticResource GhostButtonStyle}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</dev:SettingsCard>
|
||||
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
|
||||
</UserControl>
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<UserControl
|
||||
x:Class="BetterLyrics.WinUI3.Controls.PropertyRow"
|
||||
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">
|
||||
|
||||
<Grid HorizontalAlignment="Left" ColumnSpacing="6">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Top"
|
||||
Text="{x:Bind Header, Mode=OneWay}" />
|
||||
|
||||
<Grid
|
||||
Grid.Column="1"
|
||||
VerticalAlignment="Top"
|
||||
PointerEntered="OnPointerEntered"
|
||||
PointerExited="OnPointerExited">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Grid Grid.Column="0">
|
||||
<RichTextBlock Foreground="{ThemeResource TextFillColorSecondaryBrush}" Visibility="{x:Bind TextVisibility, Mode=OneWay}">
|
||||
<Paragraph>
|
||||
<Run Text="{x:Bind Value, Mode=OneWay}" />
|
||||
<Run Text="{x:Bind Unit, Mode=OneWay}" />
|
||||
</Paragraph>
|
||||
</RichTextBlock>
|
||||
|
||||
<HyperlinkButton
|
||||
Margin="0,-2,0,0"
|
||||
Padding="0"
|
||||
HorizontalContentAlignment="Left"
|
||||
Click="OnLinkClicked"
|
||||
Visibility="{x:Bind LinkVisibility, Mode=OneWay}">
|
||||
<TextBlock Text="{x:Bind Value, Mode=OneWay}" TextWrapping="Wrap" />
|
||||
</HyperlinkButton>
|
||||
</Grid>
|
||||
|
||||
<Button
|
||||
x:Name="CopyButton"
|
||||
Grid.Column="1"
|
||||
Margin="8,-2,0,0"
|
||||
Padding="4"
|
||||
VerticalAlignment="Top"
|
||||
Click="OnCopyClicked"
|
||||
Opacity="0">
|
||||
<ToolTipService.ToolTip>
|
||||
<ToolTip x:Uid="Copy" />
|
||||
</ToolTipService.ToolTip>
|
||||
<Button.OpacityTransition>
|
||||
<ScalarTransition />
|
||||
</Button.OpacityTransition>
|
||||
<Grid>
|
||||
<FontIcon
|
||||
x:Name="CopyIcon"
|
||||
FontFamily="{StaticResource IconFontFamily}"
|
||||
FontSize="16"
|
||||
Glyph=""
|
||||
Opacity="1">
|
||||
<FontIcon.OpacityTransition>
|
||||
<ScalarTransition />
|
||||
</FontIcon.OpacityTransition>
|
||||
</FontIcon>
|
||||
<FontIcon
|
||||
x:Name="CheckIcon"
|
||||
FontFamily="{StaticResource IconFontFamily}"
|
||||
FontSize="16"
|
||||
Glyph=""
|
||||
Opacity="0">
|
||||
<FontIcon.OpacityTransition>
|
||||
<ScalarTransition />
|
||||
</FontIcon.OpacityTransition>
|
||||
</FontIcon>
|
||||
</Grid>
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
</UserControl>
|
||||
@@ -0,0 +1,115 @@
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Input;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.ApplicationModel.DataTransfer;
|
||||
|
||||
// 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 PropertyRow : UserControl
|
||||
{
|
||||
public PropertyRow()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
}
|
||||
|
||||
public string Header
|
||||
{
|
||||
get => (string)GetValue(HeaderProperty);
|
||||
set => SetValue(HeaderProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty HeaderProperty =
|
||||
DependencyProperty.Register(nameof(Header), typeof(string), typeof(PropertyRow), new PropertyMetadata(string.Empty));
|
||||
|
||||
public string Value
|
||||
{
|
||||
get => (string)GetValue(ValueProperty);
|
||||
set => SetValue(ValueProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty ValueProperty =
|
||||
DependencyProperty.Register(nameof(Value), typeof(string), typeof(PropertyRow), new PropertyMetadata(string.Empty));
|
||||
|
||||
public string Link
|
||||
{
|
||||
get => (string)GetValue(LinkProperty);
|
||||
set => SetValue(LinkProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty LinkProperty =
|
||||
DependencyProperty.Register(nameof(Link), typeof(string), typeof(PropertyRow), new PropertyMetadata(string.Empty));
|
||||
|
||||
public string Unit
|
||||
{
|
||||
get => (string)GetValue(UnitProperty);
|
||||
set => SetValue(UnitProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty UnitProperty =
|
||||
DependencyProperty.Register(nameof(Unit), typeof(string), typeof(PropertyRow), new PropertyMetadata(string.Empty));
|
||||
|
||||
private Visibility TextVisibility => Link == string.Empty ? Visibility.Visible : Visibility.Collapsed;
|
||||
private Visibility LinkVisibility => Link != string.Empty ? Visibility.Visible : Visibility.Collapsed;
|
||||
|
||||
private void OnPointerEntered(object sender, PointerRoutedEventArgs e)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Value))
|
||||
{
|
||||
CopyButton.Opacity = 1;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPointerExited(object sender, PointerRoutedEventArgs e)
|
||||
{
|
||||
CopyButton.Opacity = 0;
|
||||
}
|
||||
|
||||
private void OnCopyClicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var targetValue = string.IsNullOrEmpty(Link) ? Value : Link;
|
||||
|
||||
if (string.IsNullOrEmpty(targetValue)) return;
|
||||
|
||||
try
|
||||
{
|
||||
DataPackage dataPackage = new DataPackage();
|
||||
dataPackage.SetText(targetValue);
|
||||
Clipboard.SetContent(dataPackage);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"Copy failed: {ex.Message}");
|
||||
return;
|
||||
}
|
||||
|
||||
CheckIcon.Opacity = 1;
|
||||
CopyIcon.Opacity = 0;
|
||||
|
||||
this.DispatcherQueue.TryEnqueue(async () =>
|
||||
{
|
||||
await Task.Delay(1000);
|
||||
|
||||
CheckIcon.Opacity = 0;
|
||||
CopyIcon.Opacity = 1;
|
||||
});
|
||||
}
|
||||
|
||||
private async void OnLinkClicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Uri.TryCreate(Link, UriKind.Absolute, out var uri);
|
||||
if (uri != null)
|
||||
{
|
||||
if (uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps)
|
||||
{
|
||||
await Windows.System.Launcher.LaunchUriAsync(uri);
|
||||
}
|
||||
else if (uri.Scheme == Uri.UriSchemeFile)
|
||||
{
|
||||
await LauncherHelper.SelectAndShowFile(uri.LocalPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<UserControl
|
||||
x:Class="BetterLyrics.WinUI3.Controls.ShadowImage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:const="using:BetterLyrics.WinUI3.Constants"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:BetterLyrics.WinUI3.Controls"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d">
|
||||
<UserControl.OpacityTransition>
|
||||
<ScalarTransition />
|
||||
</UserControl.OpacityTransition>
|
||||
|
||||
<Grid Margin="-32" Padding="32">
|
||||
<Grid
|
||||
x:Name="ShadowCastGrid"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
SizeChanged="ShadowCastGrid_SizeChanged">
|
||||
<Image Source="{x:Bind Source, Mode=OneWay}" Stretch="Uniform" />
|
||||
</Grid>
|
||||
<Border
|
||||
x:Name="ShadowRect"
|
||||
Loaded="ShadowRect_Loaded"
|
||||
SizeChanged="ShadowRect_SizeChanged"
|
||||
Translation="0,0,0">
|
||||
<Border.Shadow>
|
||||
<ThemeShadow x:Name="Shadow" />
|
||||
</Border.Shadow>
|
||||
</Border>
|
||||
</Grid>
|
||||
|
||||
</UserControl>
|
||||
@@ -0,0 +1,93 @@
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
using 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 ShadowImage : UserControl
|
||||
{
|
||||
public int CornerRadiusAmount
|
||||
{
|
||||
get { return (int)GetValue(CornerRadiusAmountProperty); }
|
||||
set { SetValue(CornerRadiusAmountProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CornerRadiusAmountProperty =
|
||||
DependencyProperty.Register(nameof(CornerRadiusAmount), typeof(int), typeof(ShadowImage), new PropertyMetadata(0, OnDependencyPropertyChanged));
|
||||
|
||||
public int ShadowAmount
|
||||
{
|
||||
get { return (int)GetValue(ShadowAmountProperty); }
|
||||
set { SetValue(ShadowAmountProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ShadowAmountProperty =
|
||||
DependencyProperty.Register(nameof(ShadowAmount), typeof(int), typeof(ShadowImage), new PropertyMetadata(0, OnDependencyPropertyChanged));
|
||||
|
||||
public ImageSource? Source
|
||||
{
|
||||
get { return (ImageSource?)GetValue(SourceProperty); }
|
||||
set { SetValue(SourceProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SourceProperty =
|
||||
DependencyProperty.Register(nameof(Source), typeof(ImageSource), typeof(ShadowImage), new PropertyMetadata(null));
|
||||
|
||||
public ShadowImage()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private static void OnDependencyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is ShadowImage shadowImage)
|
||||
{
|
||||
if (e.Property == CornerRadiusAmountProperty)
|
||||
{
|
||||
shadowImage.UpdateShadowCastGridCornerRadius();
|
||||
shadowImage.UpdateShadowRectCornerRadius();
|
||||
}
|
||||
else if (e.Property == ShadowAmountProperty)
|
||||
{
|
||||
shadowImage.UpdateShadowRectShadow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateShadowRectShadow()
|
||||
{
|
||||
ShadowRect.Translation = new(0, 0, ShadowAmount);
|
||||
}
|
||||
|
||||
private void UpdateShadowCastGridCornerRadius()
|
||||
{
|
||||
var minSize = Math.Min(ShadowCastGrid.ActualHeight, ShadowCastGrid.ActualWidth);
|
||||
ShadowCastGrid.CornerRadius = new(CornerRadiusAmount / 100.0 * (minSize / 2));
|
||||
}
|
||||
|
||||
private void UpdateShadowRectCornerRadius()
|
||||
{
|
||||
var minSize = Math.Min(ShadowRect.ActualHeight, ShadowRect.ActualWidth);
|
||||
ShadowRect.CornerRadius = new(CornerRadiusAmount / 100.0 * (minSize / 2));
|
||||
}
|
||||
|
||||
private void ShadowCastGrid_SizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
UpdateShadowCastGridCornerRadius();
|
||||
}
|
||||
|
||||
private void ShadowRect_SizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
UpdateShadowRectCornerRadius();
|
||||
}
|
||||
|
||||
private void ShadowRect_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Shadow.Receivers.Add(ShadowCastGrid);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,11 @@
|
||||
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
FontSize=12,
|
||||
Glyph=}"
|
||||
Style="{StaticResource GhostButtonStyle}" />
|
||||
Style="{StaticResource GhostButtonStyle}">
|
||||
<ToolTipService.ToolTip>
|
||||
<ToolTip x:Uid="SettingsPageClear" />
|
||||
</ToolTipService.ToolTip>
|
||||
</Button>
|
||||
<Button
|
||||
Margin="3,0,0,0"
|
||||
HorizontalAlignment="Right"
|
||||
@@ -31,7 +35,11 @@
|
||||
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
FontSize=12,
|
||||
Glyph=}"
|
||||
Style="{StaticResource GhostButtonStyle}" />
|
||||
Style="{StaticResource GhostButtonStyle}">
|
||||
<ToolTipService.ToolTip>
|
||||
<ToolTip x:Uid="SettingsPageCheckShortcut" />
|
||||
</ToolTipService.ToolTip>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using BetterLyrics.WinUI3.Hooks;
|
||||
using BetterLyrics.WinUI3.Services.ResourceService;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using Microsoft.UI.Input;
|
||||
@@ -89,14 +90,14 @@ namespace BetterLyrics.WinUI3.Controls
|
||||
|
||||
private void CheckButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
bool registered = GlobalHotKeyHelper.IsHotKeyRegistered(Shortcut);
|
||||
bool registered = GlobalHotKeyHook.IsHotKeyRegistered(Shortcut);
|
||||
if (registered)
|
||||
{
|
||||
DevWinUI.Growl.Success(_resourceService.GetLocalizedString("SettingsPageShortcutRegSuccessInfo"));
|
||||
ToastHelper.ShowToast("SettingsPageShortcutRegSuccessInfo", null, InfoBarSeverity.Success);
|
||||
}
|
||||
else
|
||||
{
|
||||
DevWinUI.Growl.Error(_resourceService.GetLocalizedString("SettingsPageShortcutRegFailInfo"));
|
||||
ToastHelper.ShowToast("SettingsPageShortcutRegFailInfo", null, InfoBarSeverity.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
x:Name="TrayIcon"
|
||||
x:FieldModifier="public"
|
||||
ContextMenuMode="SecondWindow"
|
||||
DoubleClickCommand="{x:Bind ViewModel.OpenLyricsCommand}"
|
||||
DoubleClickCommand="{x:Bind ViewModel.OpenLyricsWindowSwitchCommand}"
|
||||
IconSource="ms-appx:///Assets/Logo.ico"
|
||||
LeftClickCommand="{x:Bind ViewModel.OpenLyricsCommand}"
|
||||
LeftClickCommand="{x:Bind ViewModel.OpenLyricsWindowSwitchCommand}"
|
||||
NoLeftClickDelay="True"
|
||||
ToolTipText="{x:Bind ViewModel.ToolTipText, Mode=OneWay}">
|
||||
<tb:TaskbarIcon.ContextFlyout>
|
||||
@@ -39,16 +39,11 @@
|
||||
Command="{x:Bind ViewModel.OpenLyricsSearchWindowCommand}"
|
||||
Icon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}" />
|
||||
<MenuFlyoutItem
|
||||
x:Uid="SystemTrayLyrics"
|
||||
Command="{x:Bind ViewModel.OpenLyricsCommand}"
|
||||
Icon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}" />
|
||||
<MenuFlyoutItem
|
||||
x:Uid="SystemTrayMusicGallery"
|
||||
Command="{x:Bind ViewModel.OpenMusicGalleryCommand}"
|
||||
Icon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}" />
|
||||
Glyph=}" />
|
||||
<MenuFlyoutItem
|
||||
x:Uid="SystemTraySettings"
|
||||
Command="{x:Bind ViewModel.OpenSettingsCommand}"
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<UserControl
|
||||
x:Class="BetterLyrics.WinUI3.Controls.WindowSettingsControl"
|
||||
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:dev="using:DevWinUI"
|
||||
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="AppSettingsControlGeneral" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageConfigName" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<StackPanel
|
||||
Margin="0,6,0,0"
|
||||
Orientation="Horizontal"
|
||||
Spacing="6">
|
||||
<TextBox Text="{x:Bind LyricsWindowStatus.Name, Mode=TwoWay}" TextWrapping="Wrap" />
|
||||
<Button Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, FontSize=12, Glyph=}" Style="{StaticResource GhostButtonStyle}" />
|
||||
</StackPanel>
|
||||
</dev:SettingsCard>
|
||||
|
||||
<dev:SettingsExpander
|
||||
x:Uid="SettingsPageWorkArea"
|
||||
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}"
|
||||
IsExpanded="{x:Bind LyricsWindowStatus.IsWorkArea, Mode=OneWay}">
|
||||
<ToggleSwitch IsOn="{x:Bind LyricsWindowStatus.IsWorkArea, Mode=TwoWay}" />
|
||||
<dev:SettingsExpander.Items>
|
||||
<dev:SettingsCard x:Uid="SettingsPageWorkAreaHeight" IsEnabled="{x:Bind LyricsWindowStatus.IsWorkArea, Mode=OneWay}">
|
||||
<local:ExtendedSlider
|
||||
Default="64"
|
||||
Maximum="{x:Bind LyricsWindowStatus.MonitorBounds.Height, Mode=OneWay}"
|
||||
Minimum="64"
|
||||
Unit="px"
|
||||
Value="{x:Bind LyricsWindowStatus.DockHeight, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageDockPlacement" IsEnabled="{x:Bind LyricsWindowStatus.IsWorkArea, Mode=OneWay}">
|
||||
<ComboBox SelectedIndex="{x:Bind LyricsWindowStatus.DockPlacement, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||
<ComboBoxItem x:Uid="SettingsPageDockPlacementTop" />
|
||||
<ComboBoxItem x:Uid="SettingsPageDockPlacementBottom" />
|
||||
</ComboBox>
|
||||
</dev:SettingsCard>
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageDockMonitor" IsEnabled="{x:Bind LyricsWindowStatus.IsWorkArea, Mode=OneWay}">
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<ComboBox ItemsSource="{x:Bind MonitorDeviceNames, Mode=OneWay}" SelectedItem="{x:Bind LyricsWindowStatus.MonitorDeviceName, Mode=TwoWay}" />
|
||||
<Button
|
||||
Click="RefreshMonitorButton_Click"
|
||||
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
FontSize=12,
|
||||
Glyph=}"
|
||||
Style="{StaticResource GhostButtonStyle}" />
|
||||
</StackPanel>
|
||||
</dev:SettingsCard>
|
||||
|
||||
</dev:SettingsExpander.Items>
|
||||
</dev:SettingsExpander>
|
||||
|
||||
<dev:SettingsExpander
|
||||
x:Uid="SettingsPageAdaptEnvColor"
|
||||
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}"
|
||||
IsExpanded="{x:Bind LyricsWindowStatus.IsAdaptToEnvironment, Mode=OneWay}">
|
||||
<ToggleSwitch IsOn="{x:Bind LyricsWindowStatus.IsAdaptToEnvironment, Mode=TwoWay}" />
|
||||
<dev:SettingsExpander.Items>
|
||||
<dev:SettingsCard
|
||||
x:Uid="SettingsPageEnvColorSample"
|
||||
Header="Environment color sample mode"
|
||||
IsEnabled="{x:Bind LyricsWindowStatus.IsAdaptToEnvironment, Mode=OneWay}">
|
||||
<ComboBox SelectedIndex="{x:Bind LyricsWindowStatus.EnvironmentSampleMode, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||
<ComboBoxItem x:Uid="SettingsPageEnvColorSampleBelow" />
|
||||
<ComboBoxItem x:Uid="SettingsPageEnvColorSampleAbove" />
|
||||
<ComboBoxItem x:Uid="SettingsPageEnvColorSampleInner" />
|
||||
<ComboBoxItem x:Uid="SettingsPageEnvColorSampleEdge" />
|
||||
</ComboBox>
|
||||
</dev:SettingsCard>
|
||||
</dev:SettingsExpander.Items>
|
||||
</dev:SettingsExpander>
|
||||
|
||||
<dev:SettingsExpander
|
||||
x:Uid="SettingsPageAOT"
|
||||
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}"
|
||||
IsExpanded="True">
|
||||
<ToggleSwitch IsOn="{x:Bind LyricsWindowStatus.IsAlwaysOnTop, Mode=TwoWay}" />
|
||||
<dev:SettingsExpander.Items>
|
||||
<dev:SettingsCard x:Uid="SettingsPageForceAlwaysOnTop" IsEnabled="{x:Bind LyricsWindowStatus.IsAlwaysOnTop, Mode=OneWay}">
|
||||
<ToggleSwitch IsOn="{x:Bind LyricsWindowStatus.IsAlwaysOnTopPolling, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
</dev:SettingsExpander.Items>
|
||||
</dev:SettingsExpander>
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageHideWindow" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ToggleSwitch IsOn="{x:Bind LyricsWindowStatus.AutoShowOrHideWindow, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageShowInSwitchers" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ToggleSwitch IsOn="{x:Bind LyricsWindowStatus.IsShownInSwitchers, Mode=TwoWay}" />
|
||||
</dev:SettingsCard>
|
||||
|
||||
<dev:SettingsCard x:Uid="SettingsPageDragArea" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||
<ComboBox SelectedIndex="{x:Bind LyricsWindowStatus.TitleBarArea, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||
<ComboBoxItem x:Uid="SettingsPageTitleBarAreaNone" />
|
||||
<ComboBoxItem x:Uid="SettingsPageTitleBarAreaTop" />
|
||||
<ComboBoxItem x:Uid="SettingsPageTitleBarAreaWhole" />
|
||||
</ComboBox>
|
||||
</dev:SettingsCard>
|
||||
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,43 @@
|
||||
using BetterLyrics.WinUI3.Hooks;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.Models.Settings;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
|
||||
// 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 WindowSettingsControl : UserControl
|
||||
{
|
||||
public static readonly DependencyProperty LyricsWindowStatusProperty =
|
||||
DependencyProperty.Register(nameof(LyricsWindowStatus), typeof(AlbumArtAreaEffectSettings), typeof(WindowSettingsControl), new PropertyMetadata(default));
|
||||
|
||||
public LyricsWindowStatus LyricsWindowStatus
|
||||
{
|
||||
get => (LyricsWindowStatus)GetValue(LyricsWindowStatusProperty);
|
||||
set => SetValue(LyricsWindowStatusProperty, value);
|
||||
}
|
||||
|
||||
public ObservableCollection<string> MonitorDeviceNames { get; set; } = [];
|
||||
|
||||
public WindowSettingsControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
MonitorDeviceNames = [.. MonitorHook.GetAllMonitorDeviceNames()];
|
||||
}
|
||||
|
||||
private void RefreshMonitorDeviceNames()
|
||||
{
|
||||
MonitorDeviceNames = [.. MonitorHook.GetAllMonitorDeviceNames()];
|
||||
LyricsWindowStatus.MonitorDeviceName = MonitorDeviceNames.FirstOrDefault() ?? "";
|
||||
}
|
||||
|
||||
private void RefreshMonitorButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
RefreshMonitorDeviceNames();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
using System;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Converter
|
||||
{
|
||||
public class IntToDoubleConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
if (value is int intValue)
|
||||
{
|
||||
return (double)intValue;
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using Microsoft.UI.Text;
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
using System;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Converter
|
||||
{
|
||||
public partial class LyricsFontWeightToFontWeightConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
if (value is LyricsFontWeight weight)
|
||||
{
|
||||
return weight.ToFontWeight();
|
||||
}
|
||||
return FontWeights.Normal;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using BetterLyrics.WinUI3.Extensions;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
using System;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Converter
|
||||
{
|
||||
public partial class LyricsLayoutOrientationNegationToOrientationConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
if (value is LyricsLayoutOrientation orientation)
|
||||
{
|
||||
return orientation.ToOrientationInverse();
|
||||
}
|
||||
return Orientation.Horizontal;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using BetterLyrics.WinUI3.Extensions;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
using System;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Converter
|
||||
{
|
||||
public partial class LyricsLayoutOrientationToOrientationConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
if (value is LyricsLayoutOrientation orientation)
|
||||
{
|
||||
return orientation.ToOrientation();
|
||||
}
|
||||
return Orientation.Horizontal;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
using BetterLyrics.WinUI3.Constants;
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
using System;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Converter
|
||||
{
|
||||
public class MediaSourceProviderToDisplayedNameConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
if (value is string provider)
|
||||
{
|
||||
return provider switch
|
||||
{
|
||||
PlayerID.Spotify => PlayerName.Spotify,
|
||||
PlayerID.AppleMusic => PlayerName.AppleMusic,
|
||||
PlayerID.iTunes => PlayerName.iTunes,
|
||||
PlayerID.KugouMusic => PlayerName.KugouMusic,
|
||||
PlayerID.NetEaseCloudMusic => PlayerName.NetEaseCloudMusic,
|
||||
PlayerID.QQMusic => PlayerName.QQMusic,
|
||||
PlayerID.LXMusic => PlayerName.LXMusic,
|
||||
PlayerID.LXMusicPortable => PlayerName.LXMusicPortable,
|
||||
PlayerID.MediaPlayerWindows11 => PlayerName.MediaPlayerWindows11,
|
||||
PlayerID.AIMP => PlayerName.AIMP,
|
||||
PlayerID.Foobar2000 => PlayerName.Foobar2000,
|
||||
PlayerID.MusicBee => PlayerName.MusicBee,
|
||||
PlayerID.PotPlayer => PlayerName.PotPlayer,
|
||||
PlayerID.Chrome => PlayerName.Chrome,
|
||||
PlayerID.Edge => PlayerName.Edge,
|
||||
PlayerID.BetterLyrics => PlayerName.BetterLyrics,
|
||||
PlayerID.BetterLyricsDebug => PlayerName.BetterLyricsDebug,
|
||||
PlayerID.SaltPlayerForWindows => PlayerName.SaltPlayerForWindows,
|
||||
PlayerID.MoeKoeMusic => PlayerName.MoeKoeMusic,
|
||||
PlayerID.MoeKoeMusicAlternative => PlayerName.MoeKoeMusic,
|
||||
PlayerID.Listen1 => PlayerName.Listen1,
|
||||
_ => provider,
|
||||
};
|
||||
}
|
||||
return value?.ToString() ?? "";
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
using BetterLyrics.WinUI3.Constants;
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
using System;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Converter
|
||||
{
|
||||
public class MediaSourceProviderToLogoUriConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
if (value is string provider)
|
||||
{
|
||||
return provider switch
|
||||
{
|
||||
PlayerID.Spotify => PathHelper.SpotifyLogoPath,
|
||||
PlayerID.AppleMusic => PathHelper.AppleMusicLogoPath,
|
||||
PlayerID.AppleMusicAlternative => PathHelper.AppleMusicLogoPath,
|
||||
PlayerID.iTunes => PathHelper.iTunesLogoPath,
|
||||
PlayerID.KugouMusic => PathHelper.KugouMusicLogoPath,
|
||||
PlayerID.NetEaseCloudMusic => PathHelper.NetEaseCloudMusicLogoPath,
|
||||
PlayerID.QQMusic => PathHelper.QQMusicLogoPath,
|
||||
PlayerID.LXMusic => PathHelper.LXMusicLogoPath,
|
||||
PlayerID.LXMusicPortable => PathHelper.LXMusicLogoPath,
|
||||
PlayerID.MediaPlayerWindows11 => PathHelper.MediaPlayerWindows11LogoPath,
|
||||
PlayerID.AIMP => PathHelper.AIMPLogoPath,
|
||||
PlayerID.Foobar2000 => PathHelper.Foobar2000LogoPath,
|
||||
PlayerID.MusicBee => PathHelper.MusicBeeLogoPath,
|
||||
PlayerID.PotPlayer => PathHelper.PotPlayerLogoPath,
|
||||
PlayerID.Chrome => PathHelper.ChromeLogoPath,
|
||||
PlayerID.Edge => PathHelper.EdgeLogoPath,
|
||||
PlayerID.BetterLyrics => PathHelper.LogoPath,
|
||||
PlayerID.BetterLyricsDebug => PathHelper.LogoPath,
|
||||
PlayerID.SaltPlayerForWindows => PathHelper.SaltPlayerForWindowsLogoPath,
|
||||
PlayerID.MoeKoeMusic => PathHelper.MoeKoeMusicLogoPath,
|
||||
PlayerID.MoeKoeMusicAlternative => PathHelper.MoeKoeMusicLogoPath,
|
||||
PlayerID.Listen1 => PathHelper.Listen1LogoPath,
|
||||
_ => PathHelper.UnknownPlayerLogoPath,
|
||||
};
|
||||
}
|
||||
return PathHelper.UnknownPlayerLogoPath;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
using System;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Converter
|
||||
{
|
||||
public class MillisecondsToSecondsConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
if (value is int intValue)
|
||||
{
|
||||
return intValue / 1000.0;
|
||||
}
|
||||
else if (value is double doubleValue)
|
||||
{
|
||||
return doubleValue / 1000.0;
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using ATL;
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
using Microsoft.UI.Xaml.Media.Imaging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Converter
|
||||
{
|
||||
public partial class PictureInfosToImageSourceConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
BitmapImage bitmapImage = new();
|
||||
if (value is IList<PictureInfo> list && list.FirstOrDefault()?.PictureData is byte[] pictureData)
|
||||
{
|
||||
bitmapImage.SetSource(ImageHelper.ToIRandomAccessStream(pictureData));
|
||||
}
|
||||
else
|
||||
{
|
||||
bitmapImage.UriSource = new Uri(PathHelper.AlbumArtPlaceholderPath);
|
||||
}
|
||||
return bitmapImage;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
using System;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Converter
|
||||
{
|
||||
public partial class TextAlignmentTypeToHorizontalAlignmentConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
if (value is TextAlignmentType type)
|
||||
{
|
||||
return type.ToHorizontalAlignment();
|
||||
}
|
||||
return HorizontalAlignment.Left;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
using ATL;
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using BetterLyrics.WinUI3.Extensions;
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
using System;
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace BetterLyrics.WinUI3.Converter
|
||||
{
|
||||
if (value is Track track)
|
||||
{
|
||||
return track.GetLyrics();
|
||||
return track.GetRawLyrics();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using BetterLyrics.WinUI3.Services.ResourceService;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
using System;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Converter
|
||||
{
|
||||
public partial class TransliterationSearchProviderToDisplayNameConverter : IValueConverter
|
||||
{
|
||||
private readonly IResourceService _resourceService = Ioc.Default.GetRequiredService<IResourceService>();
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
if (value is TransliterationSearchProvider provider)
|
||||
{
|
||||
return provider switch
|
||||
{
|
||||
TransliterationSearchProvider.LrcLib => "LrcLib",
|
||||
TransliterationSearchProvider.QQ => "QQ 音乐",
|
||||
TransliterationSearchProvider.Netease => "网易云音乐",
|
||||
TransliterationSearchProvider.Kugou => "酷狗音乐",
|
||||
TransliterationSearchProvider.AmllTtmlDb => "amll-ttml-db",
|
||||
TransliterationSearchProvider.AppleMusic => "Apple Music",
|
||||
TransliterationSearchProvider.LocalLrcFile => _resourceService.GetLocalizedString("LyricsSearchProviderLocalLrcFile"),
|
||||
TransliterationSearchProvider.LocalMusicFile => _resourceService.GetLocalizedString("LyricsSearchProviderLocalMusicFile"),
|
||||
TransliterationSearchProvider.LocalEslrcFile => _resourceService.GetLocalizedString("LyricsSearchProviderEslrcFile"),
|
||||
TransliterationSearchProvider.LocalTtmlFile => _resourceService.GetLocalizedString("LyricsSearchProviderTtmlFile"),
|
||||
TransliterationSearchProvider.BetterLyrics => "BetterLyrics",
|
||||
_ => "N/A",
|
||||
};
|
||||
}
|
||||
return "N/A";
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,24 +1,8 @@
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using System;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Enums
|
||||
namespace BetterLyrics.WinUI3.Enums
|
||||
{
|
||||
public enum ChineseRomanization
|
||||
{
|
||||
Pinyin,
|
||||
Jyutping,
|
||||
}
|
||||
|
||||
public static class ChineseRomanizationExtensions
|
||||
{
|
||||
public static string ToPhoneticCode(this ChineseRomanization chineseRomanization)
|
||||
{
|
||||
return chineseRomanization switch
|
||||
{
|
||||
ChineseRomanization.Pinyin => PhoneticHelper.PinyinCode,
|
||||
ChineseRomanization.Jyutping => PhoneticHelper.JyutpingCode,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(chineseRomanization))
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace BetterLyrics.WinUI3.Enums
|
||||
{
|
||||
public enum ImageSwitchType
|
||||
{
|
||||
Crossfade,
|
||||
Slide
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
namespace BetterLyrics.WinUI3.Enums
|
||||
{
|
||||
public enum LineMaskType
|
||||
{
|
||||
Glow,
|
||||
Highlight,
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
// 2025/6/23 by Zhe Fang
|
||||
|
||||
namespace BetterLyrics.WinUI3.Enums
|
||||
{
|
||||
public enum LineRenderingType
|
||||
{
|
||||
CurrentChar,
|
||||
LineStartToCurrentChar,
|
||||
CurrentLine
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace BetterLyrics.WinUI3.Enums
|
||||
{
|
||||
public enum LyricsEffectScope
|
||||
{
|
||||
LongDurationSyllable,
|
||||
LineStartToCurrentChar,
|
||||
}
|
||||
}
|
||||
@@ -11,72 +11,4 @@ namespace BetterLyrics.WinUI3.Enums
|
||||
Krc,
|
||||
NotSpecified,
|
||||
}
|
||||
|
||||
public static class LyricsFormatExtensions
|
||||
{
|
||||
public static LyricsFormat? DetectFormat(this string content)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(content))
|
||||
return null;
|
||||
|
||||
// TTML: 检查 <tt ... xmlns="http://www.w3.org/ns/ttml"
|
||||
if (System.Text.RegularExpressions.Regex.IsMatch(
|
||||
content,
|
||||
@"<tt\b[^>]*\bxmlns\s*=\s*[""']http://www\.w3\.org/ns/ttml[""']",
|
||||
System.Text.RegularExpressions.RegexOptions.IgnoreCase))
|
||||
{
|
||||
return LyricsFormat.Ttml;
|
||||
}
|
||||
// KRC: 检测主内容格式 [start,duration]<offset,duration,0>字...
|
||||
else if (System.Text.RegularExpressions.Regex.IsMatch(
|
||||
content,
|
||||
@"^\[\d+,\d+\](<\d+,\d+,0>.+)+",
|
||||
System.Text.RegularExpressions.RegexOptions.Multiline))
|
||||
{
|
||||
return LyricsFormat.Krc;
|
||||
}
|
||||
// QRC: 检测主内容格式 [start,duration]字(offset,duration)
|
||||
else if (System.Text.RegularExpressions.Regex.IsMatch(
|
||||
content,
|
||||
@"^\[\d+,\d+\].*?\(\d+,\d+\)",
|
||||
System.Text.RegularExpressions.RegexOptions.Multiline))
|
||||
{
|
||||
return LyricsFormat.Qrc;
|
||||
}
|
||||
// 标准LRC和增强型LRC
|
||||
else if (System.Text.RegularExpressions.Regex.IsMatch(content, @"\[\d{1,2}:\d{2}") ||
|
||||
System.Text.RegularExpressions.Regex.IsMatch(content, @"<\d{1,2}:\d{2}\.\d{2,3}>"))
|
||||
{
|
||||
return LyricsFormat.Lrc;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static string ToFileExtension(this LyricsFormat format)
|
||||
{
|
||||
return format switch
|
||||
{
|
||||
LyricsFormat.Lrc => ".lrc",
|
||||
LyricsFormat.Qrc => ".qrc",
|
||||
LyricsFormat.Krc => ".krc",
|
||||
LyricsFormat.Eslrc => ".eslrc",
|
||||
LyricsFormat.Ttml => ".ttml",
|
||||
_ => ".*",
|
||||
};
|
||||
}
|
||||
|
||||
public static LyricsSearchProvider? ToLyricsSearchProvider(this LyricsFormat format)
|
||||
{
|
||||
return format switch
|
||||
{
|
||||
LyricsFormat.Lrc => LyricsSearchProvider.LocalLrcFile,
|
||||
LyricsFormat.Eslrc => LyricsSearchProvider.LocalEslrcFile,
|
||||
LyricsFormat.Ttml => LyricsSearchProvider.LocalTtmlFile,
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
// 2025/6/23 by Zhe Fang
|
||||
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Enums
|
||||
{
|
||||
public enum LyricsSearchProvider
|
||||
@@ -17,70 +15,4 @@ namespace BetterLyrics.WinUI3.Enums
|
||||
LocalTtmlFile,
|
||||
AppleMusic,
|
||||
}
|
||||
|
||||
public static class LyricsSearchProviderExtensions
|
||||
{
|
||||
public static string GetCacheDirectory(this LyricsSearchProvider provider)
|
||||
{
|
||||
return provider switch
|
||||
{
|
||||
LyricsSearchProvider.LrcLib => PathHelper.LrcLibLyricsCacheDirectory,
|
||||
LyricsSearchProvider.QQ => PathHelper.QQLyricsCacheDirectory,
|
||||
LyricsSearchProvider.Netease => PathHelper.NeteaseLyricsCacheDirectory,
|
||||
LyricsSearchProvider.Kugou => PathHelper.KugouLyricsCacheDirectory,
|
||||
LyricsSearchProvider.AmllTtmlDb => PathHelper.AmllTtmlDbLyricsCacheDirectory,
|
||||
LyricsSearchProvider.AppleMusic => PathHelper.AppleMusicCacheDirectory,
|
||||
_ => throw new System.ArgumentOutOfRangeException(nameof(provider)),
|
||||
};
|
||||
}
|
||||
|
||||
public static LyricsFormat GetLyricsFormat(this LyricsSearchProvider provider)
|
||||
{
|
||||
return provider switch
|
||||
{
|
||||
LyricsSearchProvider.LrcLib => LyricsFormat.Lrc,
|
||||
LyricsSearchProvider.QQ => LyricsFormat.Qrc,
|
||||
LyricsSearchProvider.Kugou => LyricsFormat.Krc,
|
||||
LyricsSearchProvider.Netease => LyricsFormat.Lrc,
|
||||
LyricsSearchProvider.AmllTtmlDb => LyricsFormat.Ttml,
|
||||
LyricsSearchProvider.AppleMusic => LyricsFormat.Ttml,
|
||||
LyricsSearchProvider.LocalLrcFile => LyricsFormat.Lrc,
|
||||
LyricsSearchProvider.LocalEslrcFile => LyricsFormat.Eslrc,
|
||||
LyricsSearchProvider.LocalTtmlFile => LyricsFormat.Ttml,
|
||||
_ => LyricsFormat.NotSpecified,
|
||||
};
|
||||
}
|
||||
|
||||
public static bool IsLocal(this LyricsSearchProvider provider)
|
||||
{
|
||||
return provider
|
||||
is LyricsSearchProvider.LocalMusicFile
|
||||
or LyricsSearchProvider.LocalLrcFile
|
||||
or LyricsSearchProvider.LocalEslrcFile
|
||||
or LyricsSearchProvider.LocalTtmlFile;
|
||||
}
|
||||
|
||||
public static bool IsRemote(this LyricsSearchProvider provider)
|
||||
{
|
||||
return !provider.IsLocal();
|
||||
}
|
||||
|
||||
public static TranslationSearchProvider? ToTranslationSearchProvider(this LyricsSearchProvider? provider)
|
||||
{
|
||||
return provider switch
|
||||
{
|
||||
LyricsSearchProvider.LrcLib => TranslationSearchProvider.LrcLib,
|
||||
LyricsSearchProvider.QQ => TranslationSearchProvider.QQ,
|
||||
LyricsSearchProvider.Kugou => TranslationSearchProvider.Kugou,
|
||||
LyricsSearchProvider.Netease => TranslationSearchProvider.Netease,
|
||||
LyricsSearchProvider.AmllTtmlDb => TranslationSearchProvider.AmllTtmlDb,
|
||||
LyricsSearchProvider.AppleMusic => TranslationSearchProvider.AppleMusic,
|
||||
LyricsSearchProvider.LocalMusicFile => TranslationSearchProvider.LocalMusicFile,
|
||||
LyricsSearchProvider.LocalLrcFile => TranslationSearchProvider.LocalLrcFile,
|
||||
LyricsSearchProvider.LocalEslrcFile => TranslationSearchProvider.LocalEslrcFile,
|
||||
LyricsSearchProvider.LocalTtmlFile => TranslationSearchProvider.LocalTtmlFile,
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace BetterLyrics.WinUI3.Enums
|
||||
{
|
||||
public enum LyricsSearchType
|
||||
{
|
||||
Sequential,
|
||||
BestMatch
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,6 @@
|
||||
public enum ShortcutID
|
||||
{
|
||||
LyricsWindowShowOrHide,
|
||||
Borderless,
|
||||
ClickThrough,
|
||||
LyricsWindowSwitch,
|
||||
PlayOrPauseSong,
|
||||
NextSong,
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace BetterLyrics.WinUI3.Enums
|
||||
{
|
||||
public enum SpectrumPlacement
|
||||
{
|
||||
Top,
|
||||
Bottom,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace BetterLyrics.WinUI3.Enums
|
||||
{
|
||||
public enum SpectrumStyle
|
||||
{
|
||||
Curve,
|
||||
Bar
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
// 2025/6/23 by Zhe Fang
|
||||
|
||||
using Microsoft.Graphics.Canvas.Text;
|
||||
using Microsoft.UI.Xaml;
|
||||
using System;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Enums
|
||||
@@ -14,6 +15,17 @@ namespace BetterLyrics.WinUI3.Enums
|
||||
|
||||
public static class LyricsAlignmentTypeExtensions
|
||||
{
|
||||
public static HorizontalAlignment ToHorizontalAlignment(this TextAlignmentType alignmentType)
|
||||
{
|
||||
return alignmentType switch
|
||||
{
|
||||
TextAlignmentType.Left => HorizontalAlignment.Left,
|
||||
TextAlignmentType.Center => HorizontalAlignment.Center,
|
||||
TextAlignmentType.Right => HorizontalAlignment.Right,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(alignmentType), alignmentType, null),
|
||||
};
|
||||
}
|
||||
|
||||
public static CanvasHorizontalAlignment ToCanvasHorizontalAlignment(this TextAlignmentType alignmentType)
|
||||
{
|
||||
return alignmentType switch
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
namespace BetterLyrics.WinUI3.Enums
|
||||
{
|
||||
public enum TransliterationSearchProvider
|
||||
{
|
||||
QQ,
|
||||
Kugou,
|
||||
Netease,
|
||||
LrcLib,
|
||||
AmllTtmlDb,
|
||||
AppleMusic,
|
||||
LocalMusicFile,
|
||||
LocalLrcFile,
|
||||
LocalEslrcFile,
|
||||
LocalTtmlFile,
|
||||
BetterLyrics
|
||||
}
|
||||
}
|
||||
@@ -5,9 +5,8 @@ using Windows.UI;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Events
|
||||
{
|
||||
public class AlbumArtChangedEventArgs(byte[]? bytes, SoftwareBitmap? albumArtSwBitmap, List<Color> albumArtLightAccentColors, List<Color> albumArtDarkAccentColors) : EventArgs
|
||||
public class AlbumArtChangedEventArgs(SoftwareBitmap? albumArtSwBitmap, List<Color> albumArtLightAccentColors, List<Color> albumArtDarkAccentColors) : EventArgs
|
||||
{
|
||||
public byte[]? Bytes { get; set; } = bytes;
|
||||
public SoftwareBitmap? AlbumArtSwBitmap { get; set; } = albumArtSwBitmap;
|
||||
public List<Color> AlbumArtLightAccentColors { get; set; } = albumArtLightAccentColors;
|
||||
public List<Color> AlbumArtDarkAccentColors { get; set; } = albumArtDarkAccentColors;
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
using Microsoft.UI.Xaml;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Events
|
||||
{
|
||||
public class InteractiveAreaEventArgs : EventArgs
|
||||
{
|
||||
public IList<FrameworkElement> Elements { get; set; }
|
||||
|
||||
public InteractiveAreaEventArgs(IList<FrameworkElement> elements)
|
||||
{
|
||||
Elements = elements;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
// 2025/6/23 by Zhe Fang
|
||||
|
||||
using System;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Events
|
||||
{
|
||||
public class IsPlayingChangedEventArgs(bool isPlaying) : EventArgs
|
||||
{
|
||||
public bool IsPlaying { get; set; } = isPlaying;
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
// 2025/6/23 by Zhe Fang
|
||||
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using System;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Events
|
||||
{
|
||||
public class SongInfoChangedEventArgs(SongInfo? songInfo) : EventArgs
|
||||
{
|
||||
public SongInfo? SongInfo { get; set; } = songInfo;
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
// 2025/6/23 by Zhe Fang
|
||||
|
||||
using System;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Events
|
||||
{
|
||||
public class TimelineChangedEventArgs(TimeSpan position, TimeSpan end) : EventArgs()
|
||||
{
|
||||
public TimeSpan Position { get; set; } = position;
|
||||
public TimeSpan End { get; set; } = end;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using Microsoft.UI.Windowing;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Extensions
|
||||
{
|
||||
public static class AppWindowExtensions
|
||||
{
|
||||
extension(AppWindow appWindow)
|
||||
{
|
||||
public void SetIcons()
|
||||
{
|
||||
appWindow.SetIcon(PathHelper.LogoPath);
|
||||
appWindow.SetTaskbarIcon(PathHelper.LogoPath);
|
||||
appWindow.SetTitleBarIcon(PathHelper.LogoPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using Microsoft.Graphics.Canvas.Text;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Extensions
|
||||
{
|
||||
public static class CanvasTextLayoutExtensions
|
||||
{
|
||||
extension(CanvasTextLayout? canvasTextLayout)
|
||||
{
|
||||
public void SetFontFamily(string? text, string cjk, string latin)
|
||||
{
|
||||
if (canvasTextLayout == null) return;
|
||||
if (text == null) return;
|
||||
|
||||
for (int i = 0; i < text.Length; i++)
|
||||
{
|
||||
canvasTextLayout.SetFontFamily(i, 1, LanguageHelper.IsCJK(text[i]) ? cjk : latin);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using System;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Extensions
|
||||
{
|
||||
public static class ChineseRomanizationExtensions
|
||||
{
|
||||
extension(ChineseRomanization chineseRomanization)
|
||||
{
|
||||
public string ToPhoneticCode() => chineseRomanization switch
|
||||
{
|
||||
ChineseRomanization.Pinyin => PhoneticHelper.PinyinCode,
|
||||
ChineseRomanization.Jyutping => PhoneticHelper.JyutpingCode,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(chineseRomanization))
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using Windows.UI;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Extensions
|
||||
{
|
||||
public static class ColorExtensions
|
||||
{
|
||||
extension(Color color)
|
||||
{
|
||||
public Color WithAlpha(byte alpha)
|
||||
{
|
||||
return Color.FromArgb(alpha, color.R, color.G, color.B);
|
||||
}
|
||||
|
||||
public Color WithOpacity(float opacity)
|
||||
{
|
||||
return Color.FromArgb((byte)(opacity * 255), color.R, color.G, color.B);
|
||||
}
|
||||
|
||||
public Color WithBrightness(double brightness)
|
||||
{
|
||||
// 确保亮度因子在合理范围内
|
||||
brightness = Math.Max(0, Math.Min(1, brightness));
|
||||
|
||||
var hsl = CommunityToolkit.WinUI.Helpers.ColorHelper.ToHsl(color);
|
||||
double h = hsl.H;
|
||||
double s = hsl.S;
|
||||
|
||||
return CommunityToolkit.WinUI.Helpers.ColorHelper.FromHsl(h, s, brightness);
|
||||
}
|
||||
|
||||
public Vector3 ToVector3RGB()
|
||||
{
|
||||
return new Vector3((float)color.R / 0xff, (float)color.G / 0xff, (float)color.B / 0xff);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Extensions
|
||||
{
|
||||
public static class DisposableObjectExtension
|
||||
{
|
||||
extension(IDisposable? obj)
|
||||
{
|
||||
// Credit/Copyright to https://gist.github.com/tcartwright/dab50ebaff7c59f05013de0fb349cabd
|
||||
public bool IsDisposed()
|
||||
{
|
||||
/*
|
||||
TIM C: This hacky code is because MSFT does not provide a standard way to interrogate if an object is disposed or not.
|
||||
I wrote this based upon streams, but it should work for many other types of MSFT objects (maybe).
|
||||
*/
|
||||
if (obj == null) { return true; }
|
||||
|
||||
var objType = obj.GetType();
|
||||
//var foo = new System.IO.BufferedStream();
|
||||
|
||||
// the _disposed pattern should catch a lot of msft objects.... hopefully
|
||||
var isDisposedField = objType.GetField("_disposed", BindingFlags.NonPublic | BindingFlags.Instance) ??
|
||||
objType.GetField("disposed", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
|
||||
if (isDisposedField != null) { return Convert.ToBoolean(isDisposedField.GetValue(obj)); }
|
||||
|
||||
isDisposedField = objType.GetField("_isOpen", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
|
||||
if (isDisposedField != null) { return !Convert.ToBoolean(isDisposedField.GetValue(obj)); }
|
||||
|
||||
// Windows.Graphics.Imaging.SoftwareBitmap
|
||||
isDisposedField = objType.GetField("_objRef_global__System_IDisposable", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
if (isDisposedField != null) { return !Convert.ToBoolean(isDisposedField.GetValue(obj)); }
|
||||
|
||||
// System.IO.FileStream
|
||||
var strategyField = objType.GetField("_strategy", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
if (strategyField != null)
|
||||
{
|
||||
var strategy = strategyField.GetValue(obj);
|
||||
var isClosedField = strategy.GetType().GetProperty("IsClosed", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
if (isClosedField != null) { return Convert.ToBoolean(isClosedField.GetValue(strategy)); }
|
||||
}
|
||||
|
||||
// other streams that use this pattern to determine if they are disposed
|
||||
if (obj is Stream stream) { return !stream.CanRead && !stream.CanWrite; }
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Extensions
|
||||
{
|
||||
public static class EnumExtensions
|
||||
{
|
||||
extension<T>(T value) where T : struct, Enum
|
||||
{
|
||||
public T GetNext()
|
||||
{
|
||||
T[] values = Enum.GetValues<T>();
|
||||
int currentIndex = Array.IndexOf(values, value);
|
||||
int nextIndex = (currentIndex + 1) % values.Length;
|
||||
return values[nextIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Extensions
|
||||
{
|
||||
public static class EnumerableExtensions
|
||||
{
|
||||
extension<T>(IEnumerable<T> items)
|
||||
{
|
||||
public ObservableCollection<GroupInfoList> GetGroupedBy(Func<T, object> groupKeySelector, Func<object, object>? orderSelector = null)
|
||||
{
|
||||
var query = from item in items
|
||||
group item by groupKeySelector(item) into g
|
||||
orderby g.Key
|
||||
select new GroupInfoList(g.Cast<object>(), orderSelector) { Key = g.Key };
|
||||
|
||||
return new ObservableCollection<GroupInfoList>(query);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Extensions
|
||||
{
|
||||
public static class LyricsFormatExtensions
|
||||
{
|
||||
extension(LyricsFormat format)
|
||||
{
|
||||
public string ToFileExtension()
|
||||
{
|
||||
return format switch
|
||||
{
|
||||
LyricsFormat.Lrc => ".lrc",
|
||||
LyricsFormat.Qrc => ".qrc",
|
||||
LyricsFormat.Krc => ".krc",
|
||||
LyricsFormat.Eslrc => ".eslrc",
|
||||
LyricsFormat.Ttml => ".ttml",
|
||||
_ => ".*",
|
||||
};
|
||||
}
|
||||
|
||||
public LyricsSearchProvider? ToLyricsSearchProvider()
|
||||
{
|
||||
return format switch
|
||||
{
|
||||
LyricsFormat.Lrc => LyricsSearchProvider.LocalLrcFile,
|
||||
LyricsFormat.Eslrc => LyricsSearchProvider.LocalEslrcFile,
|
||||
LyricsFormat.Ttml => LyricsSearchProvider.LocalTtmlFile,
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using System;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Extensions
|
||||
{
|
||||
public static class LyricsLayoutOrientationExtensions
|
||||
{
|
||||
extension(LyricsLayoutOrientation orientation)
|
||||
{
|
||||
public Orientation ToOrientation() => orientation switch
|
||||
{
|
||||
LyricsLayoutOrientation.Horizontal => Orientation.Horizontal,
|
||||
LyricsLayoutOrientation.Vertical => Orientation.Vertical,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(orientation)),
|
||||
};
|
||||
|
||||
public Orientation ToOrientationInverse() => orientation switch
|
||||
{
|
||||
LyricsLayoutOrientation.Horizontal => Orientation.Vertical,
|
||||
LyricsLayoutOrientation.Vertical => Orientation.Horizontal,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(orientation)),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using System;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Extensions
|
||||
{
|
||||
public static class LyricsSearchProviderExtensions
|
||||
{
|
||||
extension(LyricsSearchProvider provider)
|
||||
{
|
||||
public string GetCacheDirectory() => provider switch
|
||||
{
|
||||
LyricsSearchProvider.LrcLib => PathHelper.LrcLibLyricsCacheDirectory,
|
||||
LyricsSearchProvider.QQ => PathHelper.QQLyricsCacheDirectory,
|
||||
LyricsSearchProvider.Netease => PathHelper.NeteaseLyricsCacheDirectory,
|
||||
LyricsSearchProvider.Kugou => PathHelper.KugouLyricsCacheDirectory,
|
||||
LyricsSearchProvider.AmllTtmlDb => PathHelper.AmllTtmlDbLyricsCacheDirectory,
|
||||
LyricsSearchProvider.AppleMusic => PathHelper.AppleMusicCacheDirectory,
|
||||
LyricsSearchProvider.LocalMusicFile => PathHelper.LocalMusicCacheDirectory,
|
||||
LyricsSearchProvider.LocalLrcFile => PathHelper.LocalLrcCacheDirectory,
|
||||
LyricsSearchProvider.LocalEslrcFile => PathHelper.LocalEslrcCacheDirectory,
|
||||
LyricsSearchProvider.LocalTtmlFile => PathHelper.LocalTtmlCacheDirectory,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(provider)),
|
||||
};
|
||||
|
||||
public LyricsFormat GetLyricsFormat() => provider switch
|
||||
{
|
||||
LyricsSearchProvider.LrcLib => LyricsFormat.Lrc,
|
||||
LyricsSearchProvider.QQ => LyricsFormat.Qrc,
|
||||
LyricsSearchProvider.Kugou => LyricsFormat.Krc,
|
||||
LyricsSearchProvider.Netease => LyricsFormat.Lrc,
|
||||
LyricsSearchProvider.AmllTtmlDb => LyricsFormat.Ttml,
|
||||
LyricsSearchProvider.AppleMusic => LyricsFormat.Ttml,
|
||||
LyricsSearchProvider.LocalLrcFile => LyricsFormat.Lrc,
|
||||
LyricsSearchProvider.LocalEslrcFile => LyricsFormat.Eslrc,
|
||||
LyricsSearchProvider.LocalTtmlFile => LyricsFormat.Ttml,
|
||||
_ => LyricsFormat.NotSpecified,
|
||||
};
|
||||
|
||||
public bool IsLocal() => provider
|
||||
is LyricsSearchProvider.LocalMusicFile
|
||||
or LyricsSearchProvider.LocalLrcFile
|
||||
or LyricsSearchProvider.LocalEslrcFile
|
||||
or LyricsSearchProvider.LocalTtmlFile;
|
||||
|
||||
public bool IsRemote() => !provider.IsLocal();
|
||||
|
||||
public TranslationSearchProvider? ToTranslationSearchProvider() => provider switch
|
||||
{
|
||||
LyricsSearchProvider.LrcLib => TranslationSearchProvider.LrcLib,
|
||||
LyricsSearchProvider.QQ => TranslationSearchProvider.QQ,
|
||||
LyricsSearchProvider.Kugou => TranslationSearchProvider.Kugou,
|
||||
LyricsSearchProvider.Netease => TranslationSearchProvider.Netease,
|
||||
LyricsSearchProvider.AmllTtmlDb => TranslationSearchProvider.AmllTtmlDb,
|
||||
LyricsSearchProvider.AppleMusic => TranslationSearchProvider.AppleMusic,
|
||||
LyricsSearchProvider.LocalMusicFile => TranslationSearchProvider.LocalMusicFile,
|
||||
LyricsSearchProvider.LocalLrcFile => TranslationSearchProvider.LocalLrcFile,
|
||||
LyricsSearchProvider.LocalEslrcFile => TranslationSearchProvider.LocalEslrcFile,
|
||||
LyricsSearchProvider.LocalTtmlFile => TranslationSearchProvider.LocalTtmlFile,
|
||||
_ => null,
|
||||
};
|
||||
|
||||
public TransliterationSearchProvider? ToTransliterationSearchProvider() => provider switch
|
||||
{
|
||||
LyricsSearchProvider.LrcLib => TransliterationSearchProvider.LrcLib,
|
||||
LyricsSearchProvider.QQ => TransliterationSearchProvider.QQ,
|
||||
LyricsSearchProvider.Kugou => TransliterationSearchProvider.Kugou,
|
||||
LyricsSearchProvider.Netease => TransliterationSearchProvider.Netease,
|
||||
LyricsSearchProvider.AmllTtmlDb => TransliterationSearchProvider.AmllTtmlDb,
|
||||
LyricsSearchProvider.AppleMusic => TransliterationSearchProvider.AppleMusic,
|
||||
LyricsSearchProvider.LocalMusicFile => TransliterationSearchProvider.LocalMusicFile,
|
||||
LyricsSearchProvider.LocalLrcFile => TransliterationSearchProvider.LocalLrcFile,
|
||||
LyricsSearchProvider.LocalEslrcFile => TransliterationSearchProvider.LocalEslrcFile,
|
||||
LyricsSearchProvider.LocalTtmlFile => TransliterationSearchProvider.LocalTtmlFile,
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using BetterLyrics.WinUI3.Hooks;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.Models.Settings;
|
||||
using BetterLyrics.WinUI3.Services.ResourceService;
|
||||
using BetterLyrics.WinUI3.Views;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Windows.Foundation;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Extensions
|
||||
{
|
||||
public static class LyricsWindowStatusExtensions
|
||||
{
|
||||
private static readonly IResourceService _resourceService = Ioc.Default.GetRequiredService<IResourceService>();
|
||||
|
||||
public static LyricsWindowStatus DesktopMode(Window? window = null)
|
||||
{
|
||||
window ??= WindowHook.GetWindow<SystemTrayWindow>();
|
||||
return new LyricsWindowStatus(window)
|
||||
{
|
||||
Name = _resourceService.GetLocalizedString("DesktopMode"),
|
||||
LyricsDisplayType = LyricsDisplayType.LyricsOnly,
|
||||
WindowBounds = new Rect(100, 100, 600, 250),
|
||||
IsAlwaysOnTop = true,
|
||||
IsAlwaysOnTopPolling = true,
|
||||
IsLocked = true,
|
||||
IsAdaptToEnvironment = true,
|
||||
IsShownInSwitchers = false,
|
||||
EnvironmentSampleMode = WindowPixelSampleMode.WindowEdge,
|
||||
LyricsStyleSettings = new()
|
||||
{
|
||||
LyricsAlignmentType = TextAlignmentType.Center,
|
||||
},
|
||||
LyricsBackgroundSettings = new LyricsBackgroundSettings
|
||||
{
|
||||
IsFluidOverlayEnabled = false,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static LyricsWindowStatus DockedMode(Window? window = null)
|
||||
{
|
||||
window ??= WindowHook.GetWindow<SystemTrayWindow>();
|
||||
var status = new LyricsWindowStatus(window)
|
||||
{
|
||||
Name = _resourceService.GetLocalizedString("DockedMode"),
|
||||
IsWorkArea = true,
|
||||
IsAlwaysOnTop = true,
|
||||
IsAlwaysOnTopPolling = true,
|
||||
IsAdaptToEnvironment = true,
|
||||
IsShownInSwitchers = false,
|
||||
LyricsDisplayType = LyricsDisplayType.LyricsOnly,
|
||||
EnvironmentSampleMode = WindowPixelSampleMode.BelowWindow,
|
||||
TitleBarArea = TitleBarArea.None,
|
||||
LyricsStyleSettings = new LyricsStyleSettings
|
||||
{
|
||||
LyricsAlignmentType = TextAlignmentType.Center,
|
||||
},
|
||||
LyricsBackgroundSettings = new LyricsBackgroundSettings
|
||||
{
|
||||
IsFluidOverlayEnabled = false,
|
||||
IsPureColorOverlayEnabled = true,
|
||||
}
|
||||
};
|
||||
status.WindowBounds = status.GetWindowBoundsWhenWorkArea();
|
||||
return status;
|
||||
}
|
||||
|
||||
public static LyricsWindowStatus FullscreenMode(Window? window = null)
|
||||
{
|
||||
window ??= WindowHook.GetWindow<SystemTrayWindow>();
|
||||
var status = new LyricsWindowStatus(window)
|
||||
{
|
||||
Name = _resourceService.GetLocalizedString("FullscreenMode"),
|
||||
LyricsLayoutOrientation = LyricsLayoutOrientation.Vertical,
|
||||
LyricsStyleSettings = new LyricsStyleSettings
|
||||
{
|
||||
LyricsAlignmentType = TextAlignmentType.Center,
|
||||
},
|
||||
IsFullscreen = true,
|
||||
};
|
||||
status.WindowBounds = new Rect(
|
||||
status.MonitorBounds.X,
|
||||
status.MonitorBounds.Y - 1,
|
||||
status.MonitorBounds.Width,
|
||||
status.MonitorBounds.Height + 1
|
||||
);
|
||||
return status;
|
||||
}
|
||||
|
||||
public static LyricsWindowStatus StandardMode(Window? window = null)
|
||||
{
|
||||
window ??= WindowHook.GetWindow<SystemTrayWindow>();
|
||||
return new LyricsWindowStatus(window)
|
||||
{
|
||||
Name = _resourceService.GetLocalizedString("StandardMode"),
|
||||
};
|
||||
}
|
||||
|
||||
public static LyricsWindowStatus NarrowMode(Window? window = null)
|
||||
{
|
||||
window ??= WindowHook.GetWindow<SystemTrayWindow>();
|
||||
return new LyricsWindowStatus(window)
|
||||
{
|
||||
Name = _resourceService.GetLocalizedString("NarrowMode"),
|
||||
WindowBounds = new Rect(100, 100, 400, 800),
|
||||
LyricsLayoutOrientation = LyricsLayoutOrientation.Vertical,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Extensions
|
||||
{
|
||||
public static class ObservableCollectionExtensions
|
||||
{
|
||||
extension<T>(ObservableCollection<T> list)
|
||||
{
|
||||
public void InsertRange(int index, IEnumerable<T> items)
|
||||
{
|
||||
if (list == null) return;
|
||||
if (items == null) return;
|
||||
if (index < 0 || index > list.Count) return;
|
||||
foreach (var item in items)
|
||||
{
|
||||
list.Insert(index++, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using Windows.Foundation;
|
||||
using Windows.Graphics;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Extensions
|
||||
{
|
||||
public static class PointExtensions
|
||||
{
|
||||
extension(Point point)
|
||||
{
|
||||
public PointInt32 ToPointInt32() => new((int)point.X, (int)point.Y);
|
||||
|
||||
public Point AddX(double deltaX) => new(point.X + deltaX, point.Y);
|
||||
public Point AddY(double deltaY) => new(point.X, point.Y + deltaY);
|
||||
|
||||
public Point WithX(double x) => new(x, point.Y);
|
||||
public Point WithY(double y) => new(point.X, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
using Windows.Foundation;
|
||||
using Windows.Graphics;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Extensions
|
||||
{
|
||||
public static class RectExtensions
|
||||
{
|
||||
extension(Rect rect)
|
||||
{
|
||||
public RectInt32 ToRectInt32() => new(
|
||||
(int)rect.X,
|
||||
(int)rect.Y,
|
||||
(int)rect.Width,
|
||||
(int)rect.Height
|
||||
);
|
||||
|
||||
public Rect WithHeight(double height) => new(
|
||||
rect.X,
|
||||
rect.Y,
|
||||
rect.Width,
|
||||
height
|
||||
);
|
||||
|
||||
public Rect WithWidth(double width) => new(
|
||||
rect.X,
|
||||
rect.Y,
|
||||
width,
|
||||
rect.Height
|
||||
);
|
||||
|
||||
public Rect WithX(double x) => new(
|
||||
x,
|
||||
rect.Y,
|
||||
rect.Width,
|
||||
rect.Height
|
||||
);
|
||||
|
||||
public Rect WithY(double y) => new(
|
||||
rect.X,
|
||||
y,
|
||||
rect.Width,
|
||||
rect.Height
|
||||
);
|
||||
|
||||
public Rect AddY(double y) => new(
|
||||
rect.X,
|
||||
rect.Y + y,
|
||||
rect.Width,
|
||||
rect.Height
|
||||
);
|
||||
|
||||
public Rect Extend(double left, double top, double right, double bottom) => new(
|
||||
rect.X - left,
|
||||
rect.Y - top,
|
||||
rect.Width + left + right,
|
||||
rect.Height + top + bottom
|
||||
);
|
||||
|
||||
public Rect Extend(double padding) => Extend(rect, padding, padding, padding, padding);
|
||||
|
||||
public Rect Scale(double scale)
|
||||
{
|
||||
double originalWidth = rect.Width;
|
||||
double originalHeight = rect.Height;
|
||||
|
||||
double scaledWidth = originalWidth * scale;
|
||||
double scaledHeight = originalHeight * scale;
|
||||
|
||||
double scaleOffsetX = (scaledWidth - originalWidth) / 2;
|
||||
double scaleOffsetY = (scaledHeight - originalHeight) / 2;
|
||||
|
||||
return new Rect(
|
||||
rect.X - scaleOffsetX,
|
||||
rect.Y - scaleOffsetY,
|
||||
scaledWidth,
|
||||
scaledHeight
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Extensions
|
||||
{
|
||||
public static class SongInfoExtensions
|
||||
{
|
||||
public static SongInfo Placeholder => new SongInfo
|
||||
{
|
||||
Title = "N/A",
|
||||
Album = "N/A",
|
||||
Artists = ["N/A"],
|
||||
};
|
||||
|
||||
extension(SongInfo songInfo)
|
||||
{
|
||||
public SongInfo WithTitle(string value)
|
||||
{
|
||||
songInfo.Title = value;
|
||||
return songInfo;
|
||||
}
|
||||
|
||||
public SongInfo WithArtist(string[] value)
|
||||
{
|
||||
songInfo.Artists = value;
|
||||
return songInfo;
|
||||
}
|
||||
|
||||
public SongInfo WithAlbum(string value)
|
||||
{
|
||||
songInfo.Album = value;
|
||||
return songInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using System.Linq;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Extensions
|
||||
{
|
||||
public static class StringExtensions
|
||||
{
|
||||
private static readonly string[] _splitter =
|
||||
[
|
||||
";"
|
||||
,
|
||||
","
|
||||
,
|
||||
"/"
|
||||
,
|
||||
";"
|
||||
,
|
||||
"、"
|
||||
,
|
||||
","
|
||||
];
|
||||
|
||||
extension(string str)
|
||||
{
|
||||
public string[] SplitByCommonSplitter()
|
||||
{
|
||||
var splitter = _splitter.FirstOrDefault(str.Contains);
|
||||
if (splitter != null)
|
||||
{
|
||||
return str.Split(splitter);
|
||||
}
|
||||
else
|
||||
{
|
||||
return [str];
|
||||
}
|
||||
}
|
||||
|
||||
public LyricsFormat? DetectFormat()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(str))
|
||||
return null;
|
||||
|
||||
// TTML: 检查 <tt ... xmlns="http://www.w3.org/ns/ttml"
|
||||
if (System.Text.RegularExpressions.Regex.IsMatch(
|
||||
str,
|
||||
@"<tt\b[^>]*\bxmlns\s*=\s*[""']http://www\.w3\.org/ns/ttml[""']",
|
||||
System.Text.RegularExpressions.RegexOptions.IgnoreCase))
|
||||
{
|
||||
return LyricsFormat.Ttml;
|
||||
}
|
||||
// KRC: 检测主内容格式 [start,duration]<offset,duration,0>字...
|
||||
else if (System.Text.RegularExpressions.Regex.IsMatch(
|
||||
str,
|
||||
@"^\[\d+,\d+\](<\d+,\d+,0>.+)+",
|
||||
System.Text.RegularExpressions.RegexOptions.Multiline))
|
||||
{
|
||||
return LyricsFormat.Krc;
|
||||
}
|
||||
// QRC: 检测主内容格式 [start,duration]字(offset,duration)
|
||||
else if (System.Text.RegularExpressions.Regex.IsMatch(
|
||||
str,
|
||||
@"^\[\d+,\d+\].*?\(\d+,\d+\)",
|
||||
System.Text.RegularExpressions.RegexOptions.Multiline))
|
||||
{
|
||||
return LyricsFormat.Qrc;
|
||||
}
|
||||
// 标准LRC和增强型LRC
|
||||
else if (System.Text.RegularExpressions.Regex.IsMatch(str, @"\[\d{1,2}:\d{2}") ||
|
||||
System.Text.RegularExpressions.Regex.IsMatch(str, @"<\d{1,2}:\d{2}\.\d{2,3}>"))
|
||||
{
|
||||
return LyricsFormat.Lrc;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using ATL;
|
||||
using System.IO;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Extensions
|
||||
{
|
||||
public static class TrackExtensions
|
||||
{
|
||||
extension(Track track)
|
||||
{
|
||||
public string GetParentFolderName() => Directory.GetParent(track.Path)?.Name ?? "";
|
||||
|
||||
public string GetParentFolderPath() => Directory.GetParent(track.Path)?.FullName ?? "";
|
||||
|
||||
public string GetRawLyrics()
|
||||
{
|
||||
if (track.Path is string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
return TagLib.File.Create(path).Tag.Lyrics;
|
||||
}
|
||||
catch (System.Exception)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public string GetFileName() => Path.GetFileName(track.Path);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using System.Numerics;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Extensions
|
||||
{
|
||||
public static class VectorExtensions
|
||||
{
|
||||
extension(Vector2 vector2)
|
||||
{
|
||||
public Vector2 WithX(float x)
|
||||
{
|
||||
return new Vector2(x, vector2.Y);
|
||||
}
|
||||
|
||||
public Vector2 WithY(float y)
|
||||
{
|
||||
return new Vector2(vector2.X, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using BetterLyrics.WinUI3.Services.ResourceService;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using Microsoft.UI.Windowing;
|
||||
using Microsoft.UI.Xaml;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Extensions
|
||||
{
|
||||
public static class WindowExtensions
|
||||
{
|
||||
private static readonly IResourceService _resourceService = Ioc.Default.GetRequiredService<IResourceService>();
|
||||
|
||||
extension(Window window)
|
||||
{
|
||||
public void Init(
|
||||
string titleKey,
|
||||
TitleBarHeightOption titleBarHeightOption = TitleBarHeightOption.Standard,
|
||||
BackdropType backdropType = BackdropType.DesktopAcrylic)
|
||||
{
|
||||
window.Title = _resourceService.GetLocalizedString(titleKey);
|
||||
window.AppWindow.TitleBar.PreferredTheme = TitleBarTheme.UseDefaultAppMode;
|
||||
window.AppWindow.SetIcons();
|
||||
|
||||
window.ExtendsContentIntoTitleBar = true;
|
||||
window.AppWindow.TitleBar.PreferredHeightOption = titleBarHeightOption;
|
||||
|
||||
window.SystemBackdrop = SystemBackdropHelper.CreateSystemBackdrop(backdropType);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
using Microsoft.UI.Windowing;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Helper
|
||||
{
|
||||
public static class AppWindowHelper
|
||||
{
|
||||
public static void SetIcons(this AppWindow appWindow)
|
||||
{
|
||||
appWindow.SetIcon(PathHelper.LogoPath);
|
||||
appWindow.SetTaskbarIcon(PathHelper.LogoPath);
|
||||
appWindow.SetTitleBarIcon(PathHelper.LogoPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,6 @@
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using Microsoft.Graphics.Canvas;
|
||||
using Microsoft.Graphics.Canvas.Brushes;
|
||||
using Microsoft.Graphics.Canvas;
|
||||
using Microsoft.Graphics.Canvas.Effects;
|
||||
using Microsoft.Graphics.Canvas.UI.Xaml;
|
||||
using Microsoft.UI;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Windows.Foundation;
|
||||
using System;
|
||||
using Windows.Graphics.Effects;
|
||||
using Windows.UI;
|
||||
|
||||
@@ -16,351 +8,6 @@ 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),
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 背景层
|
||||
/// </summary>
|
||||
/// <param name="lyricsLayerOpacity">_lyricsOpacityTransition.Value</param>
|
||||
public static OpacityEffect CreateBackgroundEffect(LyricsLine lyricsLine, CanvasCommandList backgroundFontEffect, double lyricsLayerOpacity)
|
||||
{
|
||||
if (lyricsLine.BlurAmountTransition.Value == 0)
|
||||
{
|
||||
return new OpacityEffect
|
||||
{
|
||||
Source = backgroundFontEffect,
|
||||
Opacity = (float)(lyricsLine.OpacityTransition.Value * lyricsLayerOpacity),
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
return new OpacityEffect
|
||||
{
|
||||
Source = new GaussianBlurEffect
|
||||
{
|
||||
Source = backgroundFontEffect,
|
||||
BlurAmount = (float)lyricsLine.BlurAmountTransition.Value,
|
||||
BorderMode = EffectBorderMode.Soft,
|
||||
Optimization = EffectOptimization.Speed,
|
||||
},
|
||||
Opacity = (float)(lyricsLine.OpacityTransition.Value * lyricsLayerOpacity),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public static CanvasCommandList CreateFontEffect(LyricsLine lyricsLine, ICanvasAnimatedControl control, Color strokeColor, int strokeWidth, Color fontColor)
|
||||
{
|
||||
CanvasCommandList list = new(control);
|
||||
using var ds = list.CreateDrawingSession();
|
||||
|
||||
// 描边
|
||||
if (strokeWidth > 0)
|
||||
{
|
||||
if (lyricsLine.PhoneticCanvasGeometry != null)
|
||||
{
|
||||
ds.DrawGeometry(lyricsLine.PhoneticCanvasGeometry, lyricsLine.PhoneticPosition, strokeColor, strokeWidth);
|
||||
}
|
||||
if (lyricsLine.OriginalCanvasGeometry != null)
|
||||
{
|
||||
ds.DrawGeometry(lyricsLine.OriginalCanvasGeometry, lyricsLine.OriginalPosition, strokeColor, strokeWidth);
|
||||
}
|
||||
if (lyricsLine.TranslatedCanvasGeometry != null)
|
||||
{
|
||||
ds.DrawGeometry(lyricsLine.TranslatedCanvasGeometry, lyricsLine.TranslatedPosition, strokeColor, strokeWidth);
|
||||
}
|
||||
}
|
||||
|
||||
// 绘制文本(填充)
|
||||
if (lyricsLine.PhoneticCanvasTextLayout != null)
|
||||
{
|
||||
ds.DrawTextLayout(lyricsLine.PhoneticCanvasTextLayout, lyricsLine.PhoneticPosition, fontColor);
|
||||
}
|
||||
if (lyricsLine.OriginalCanvasTextLayout != null)
|
||||
{
|
||||
ds.DrawTextLayout(lyricsLine.OriginalCanvasTextLayout, lyricsLine.OriginalPosition, fontColor);
|
||||
}
|
||||
if (lyricsLine.TranslatedCanvasTextLayout != null)
|
||||
{
|
||||
ds.DrawTextLayout(lyricsLine.TranslatedCanvasTextLayout, lyricsLine.TranslatedPosition, fontColor);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建辉光效果层
|
||||
/// 仅需在布局重构 (Relayout) 时调用
|
||||
/// </summary>
|
||||
/// <param name="lineRenderingType">_lyricsGlowEffectScope</param>
|
||||
/// <param name="glowEffectAmount">_lyricsGlowEffectAmount</param>
|
||||
public static GaussianBlurEffect CreateForegroundBlurEffect(CanvasCommandList foregroundFontEffect, IGraphicsEffectSource mask, double glowEffectAmount)
|
||||
{
|
||||
return new GaussianBlurEffect
|
||||
{
|
||||
Source = new AlphaMaskEffect
|
||||
{
|
||||
Source = foregroundFontEffect,
|
||||
AlphaMask = mask,
|
||||
},
|
||||
BlurAmount = (float)glowEffectAmount,
|
||||
Optimization = EffectOptimization.Speed,
|
||||
};
|
||||
}
|
||||
|
||||
public static CanvasCommandList CreateCharMask(ICanvasAnimatedControl control, LyricsLine lyricsLine, int charStartIndex, int charLength, double charProgress)
|
||||
{
|
||||
var mask = new CanvasCommandList(control);
|
||||
using var ds = mask.CreateDrawingSession();
|
||||
|
||||
if (lyricsLine.OriginalCanvasTextLayout == null)
|
||||
{
|
||||
return mask;
|
||||
}
|
||||
|
||||
var highlightRegion = lyricsLine.OriginalCanvasTextLayout.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 + lyricsLine.OriginalPosition.Y,
|
||||
highlightWidth,
|
||||
highlightRegion.LayoutBounds.Height
|
||||
);
|
||||
|
||||
var fadeInRect = new Rect(
|
||||
highlightRect.Right - fadingWidth,
|
||||
highlightRegion.LayoutBounds.Y + lyricsLine.OriginalPosition.Y,
|
||||
fadingWidth,
|
||||
highlightRegion.LayoutBounds.Height
|
||||
);
|
||||
var fadeOutRect = new Rect(
|
||||
highlightRect.Right,
|
||||
highlightRegion.LayoutBounds.Y + lyricsLine.OriginalPosition.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);
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
public static CanvasCommandList CreateLineStartToCharMask(ICanvasAnimatedControl control, LyricsLine lyricsLine, int charStartIndex, int charLength, double charProgress, bool fade)
|
||||
{
|
||||
var mask = new CanvasCommandList(control);
|
||||
|
||||
if (lyricsLine.OriginalCanvasTextLayout == null)
|
||||
{
|
||||
return mask;
|
||||
}
|
||||
|
||||
using var ds = mask.CreateDrawingSession();
|
||||
|
||||
var regions = lyricsLine.OriginalCanvasTextLayout.GetCharacterRegions(0, charStartIndex);
|
||||
var highlightRegion = lyricsLine.OriginalCanvasTextLayout
|
||||
.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 + lyricsLine.OriginalPosition.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 + lyricsLine.OriginalPosition.Y,
|
||||
highlightWidth,
|
||||
highlightRegion.LayoutBounds.Height
|
||||
);
|
||||
|
||||
var fadeInRect = new Rect(
|
||||
highlightRect.Right - fadingWidth,
|
||||
highlightRegion.LayoutBounds.Y + lyricsLine.OriginalPosition.Y,
|
||||
fadingWidth,
|
||||
highlightRegion.LayoutBounds.Height
|
||||
);
|
||||
|
||||
ds.FillRectangle(highlightRect, Color.FromArgb(255, 128, 128, 128));
|
||||
|
||||
if (fade)
|
||||
{
|
||||
var fadeOutRect = new Rect(
|
||||
highlightRect.Right,
|
||||
highlightRegion.LayoutBounds.Y + lyricsLine.OriginalPosition.Y,
|
||||
fadingWidth,
|
||||
highlightRegion.LayoutBounds.Height
|
||||
);
|
||||
using var fadeOutBrush = CreateHorizontalFillBrush(
|
||||
control,
|
||||
[(0f, 1f), (1f, 0f)],
|
||||
(double)highlightRect.Right,
|
||||
fadingWidth
|
||||
);
|
||||
ds.FillRectangle(fadeOutRect, fadeOutBrush);
|
||||
}
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
public static CanvasCommandList CreateLineMask(ICanvasAnimatedControl control, LyricsLine lyricsLine)
|
||||
{
|
||||
var mask = new CanvasCommandList(control);
|
||||
using var ds = mask.CreateDrawingSession();
|
||||
|
||||
if (lyricsLine.OriginalCanvasTextLayout == null)
|
||||
{
|
||||
return mask;
|
||||
}
|
||||
|
||||
var regions = lyricsLine.OriginalCanvasTextLayout.GetCharacterRegions(0, lyricsLine.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 + lyricsLine.OriginalPosition.Y,
|
||||
region.LayoutBounds.Width,
|
||||
region.LayoutBounds.Height
|
||||
);
|
||||
ds.FillRectangle(rect, Colors.White);
|
||||
}
|
||||
}
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
public static CanvasCommandList CreatePhoneticHighlightMask(ICanvasAnimatedControl control, LyricsLine lyricsLine)
|
||||
{
|
||||
var mask = new CanvasCommandList(control);
|
||||
using var ds = mask.CreateDrawingSession();
|
||||
|
||||
if (lyricsLine.PhoneticCanvasTextLayout == null)
|
||||
{
|
||||
return mask;
|
||||
}
|
||||
|
||||
var regions = lyricsLine.PhoneticCanvasTextLayout.GetCharacterRegions(0, lyricsLine.PhoneticText.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 + lyricsLine.PhoneticPosition.Y,
|
||||
region.LayoutBounds.Width,
|
||||
region.LayoutBounds.Height
|
||||
);
|
||||
ds.FillRectangle(rect, Colors.White);
|
||||
}
|
||||
}
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
public static CanvasCommandList CreateTranslatedHighlightMask(ICanvasAnimatedControl control, LyricsLine lyricsLine)
|
||||
{
|
||||
var mask = new CanvasCommandList(control);
|
||||
using var ds = mask.CreateDrawingSession();
|
||||
|
||||
if (lyricsLine.TranslatedCanvasTextLayout == null)
|
||||
{
|
||||
return mask;
|
||||
}
|
||||
|
||||
var regions = lyricsLine.TranslatedCanvasTextLayout.GetCharacterRegions(0, lyricsLine.TranslatedText.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 + lyricsLine.TranslatedPosition.Y,
|
||||
region.LayoutBounds.Width,
|
||||
region.LayoutBounds.Height
|
||||
);
|
||||
ds.FillRectangle(rect, Colors.White);
|
||||
}
|
||||
}
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建高亮效果层
|
||||
/// </summary>
|
||||
/// <param name="control"></param>
|
||||
/// <param name="lineRenderingType"></param>
|
||||
public static OpacityEffect CreateForegroundHighlightEffect(CanvasCommandList foregroundFontEffect, IGraphicsEffectSource mask, double opacity)
|
||||
{
|
||||
return new OpacityEffect
|
||||
{
|
||||
Source = new AlphaMaskEffect
|
||||
{
|
||||
Source = foregroundFontEffect,
|
||||
AlphaMask = mask,
|
||||
},
|
||||
Opacity = (float)opacity,
|
||||
};
|
||||
}
|
||||
|
||||
public static ShadowEffect CreateForegroundShadowEffect(CanvasCommandList foregroundFontEffect, IGraphicsEffectSource mask, Color shadowColor, double shadowAmount)
|
||||
{
|
||||
return new ShadowEffect
|
||||
@@ -371,34 +18,10 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
AlphaMask = mask,
|
||||
},
|
||||
ShadowColor = shadowColor,
|
||||
BlurAmount = (float)shadowAmount,
|
||||
BlurAmount = (float)Math.Clamp(shadowAmount, 0, 100),
|
||||
Optimization = EffectOptimization.Speed,
|
||||
};
|
||||
}
|
||||
|
||||
public static OpacityEffect CreateForegroundTranslationEffect(CanvasCommandList foregroundFontEffect, IGraphicsEffectSource mask, double opacity)
|
||||
{
|
||||
return new OpacityEffect
|
||||
{
|
||||
Source = new AlphaMaskEffect
|
||||
{
|
||||
Source = foregroundFontEffect,
|
||||
AlphaMask = mask,
|
||||
},
|
||||
Opacity = (float)opacity,
|
||||
};
|
||||
}
|
||||
|
||||
public static IGraphicsEffectSource GetAlphaMask(ICanvasAnimatedControl control, IGraphicsEffectSource charMask, IGraphicsEffectSource lineStartToCharMask, IGraphicsEffectSource lineMask, LineRenderingType lineRenderingType)
|
||||
{
|
||||
var result = lineRenderingType switch
|
||||
{
|
||||
LineRenderingType.CurrentChar => charMask,
|
||||
LineRenderingType.LineStartToCurrentChar => lineStartToCharMask,
|
||||
LineRenderingType.CurrentLine => lineMask,
|
||||
_ => new CanvasCommandList(control),
|
||||
};
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
using Microsoft.Graphics.Canvas.Text;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Helper
|
||||
{
|
||||
public static class CanvasTextLayoutExtensions
|
||||
{
|
||||
public static void SetFontFamily(this CanvasTextLayout? layout, string text, string cjk, string latin)
|
||||
{
|
||||
if (layout == null) return;
|
||||
|
||||
for (int i = 0; i < text.Length; i++)
|
||||
{
|
||||
layout.SetFontFamily(i, 1, LanguageHelper.IsCJK(text[i]) ? cjk : latin);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user