Compare commits

...

54 Commits

Author SHA1 Message Date
Zhe Fang
d0b626c508 fix: issue related with docked mode 2025-10-22 10:52:57 -04:00
Zhe Fang
67a45e90fa chore: update version code 2025-10-22 10:31:14 -04:00
Zhe Fang
b4c7655043 chores: move window color sampling settings item to general tab, remove useless debug writeline 2025-10-22 10:23:50 -04:00
Zhe Fang
2adc2aced2 fix: window color sampling incorrect behavior 2025-10-22 10:18:49 -04:00
Zhe Fang
e638739638 fix: improve docked mode window sizeing behaviors 2025-10-22 09:24:16 -04:00
Zhe Fang
c24213358e Merge pull request #118 from Storyteller-Studios/dev
Improve identification of NeteaseFamily and fix Lrc Parser unexpected behavior when parsing [Min:Sec:MillSec]
2025-10-22 07:58:28 -04:00
Raspberry-Monster
6e78f849c4 chores: Improve LrcParser 2025-10-22 14:10:23 +08:00
Raspberry-Monster
80444b69e0 chores: Improve identification of NeteaseFamily and fix Lrc Parser unexpected behavior when parsing [Min:Sec:MillSec] 2025-10-22 13:06:33 +08:00
Zhe Fang
78775e9bb3 Update README.md 2025-10-21 22:51:53 -04:00
Zhe Fang
78c81347c8 feat: add window bounds settings in ui, change ExtendedSlider layout 2025-10-21 17:15:15 -04:00
Zhe Fang
65941323eb chore: update version code 2025-10-21 15:34:13 -04:00
Zhe Fang
aee79b9971 Update README.md
chrore: update Google Drive link
2025-10-21 15:33:09 -04:00
Zhe Fang
97df1c1891 fix: MediaSourceProviderInfo ctor with 2 args didn't listen on ItemPropertyChanged and CollectionChanged events of LyricsSearchProvidersInfo and AlbumArtSearchProvidersInfo 2025-10-21 15:22:31 -04:00
Zhe Fang
8a831b17cc add ani for fluid bg 2025-10-21 09:33:07 -04:00
Zhe Fang
78076efe40 Update README.md 2025-10-21 09:09:09 -04:00
Zhe Fang
d0346bf422 fix white edge issue in docked mode 2025-10-21 07:09:36 -04:00
Zhe Fang
7cb4172e84 Update README.md 2025-10-20 22:07:36 -04:00
Zhe Fang
1f2426f51b Update README.md 2025-10-20 21:51:52 -04:00
Zhe Fang
e122fdabe8 add spectrum 2025-10-20 21:38:22 -04:00
Zhe Fang
97078d966d enhance lyrics window status manage, add fluid layer background, fix #111 #96 #91 2025-10-20 14:38:09 -04:00
Zhe Fang
c43b69b4cb rollback window ctrl btn to previous version 2025-10-12 09:40:10 -04:00
Zhe Fang
94b22552e5 update doc 2025-10-10 11:40:44 -04:00
Zhe Fang
6deb16f6cb update version code 2025-10-10 11:34:39 -04:00
Zhe Fang
e467ab9c73 替换 SourceAppUserModelId 为 PlayerId 并新增 SongId
将 SongInfo 中的 SourceAppUserModelId 属性替换为 PlayerId,新增可选属性 SongId 以支持更精确的歌曲标识。
更新了相关服务和方法的参数签名,增加对 SongId 的支持,包括 SearchSmartlyAsync 和 SearchSingleAsync 方法。
调整了 MediaSessionsService 的逻辑,支持不同播放器的 SongId 处理。
优化了代码的灵活性和可扩展性,便于处理多播放器和歌曲标识。
2025-10-10 11:29:50 -04:00
Zhe Fang
ea038c9c56 更新 README.md 2025-10-05 07:59:44 -04:00
Zhe Fang
560250ad30 更新 README.md 2025-10-05 07:57:35 -04:00
Zhe Fang
536acc69a5 更新 README.md 2025-10-05 07:56:00 -04:00
Zhe Fang
0bbb379912 update LICENSE.txt 2025-09-21 21:15:15 -04:00
Zhe Fang
1f4d29e6f2 更新 README.md 2025-09-13 06:49:20 -04:00
Zhe Fang
5d1d7476c9 update screenshots 2025-09-11 21:10:24 -04:00
Zhe Fang
e016baefe1 doc 2025-09-11 20:44:17 -04:00
Zhe Fang
70b6194788 Improve formatting and clarity in README.md 2025-09-11 20:32:26 -04:00
Zhe Fang
9f103b0ea3 Update README with QQ 音乐 details and grammar fixes 2025-09-10 09:30:39 -04:00
Zhe Fang
2924140f95 Refine README.md for grammar and clarity
Corrected grammar and punctuation throughout the README file for improved clarity and consistency.
2025-09-08 18:33:06 -04:00
Zhe Fang
3d3f168926 更新 README.md 2025-09-05 07:23:52 -04:00
Zhe Fang
63b2285a36 Update download link for app in README 2025-09-05 07:03:26 -04:00
Zhe Fang
780689fa05 Merge branch 'dev' of https://github.com/jayfunc/BetterLyrics into dev 2025-09-04 15:19:36 -04:00
Zhe Fang
01384717c4 更新应用版本和图像处理逻辑
在 `Package.appxmanifest` 中,将版本号更新为 `1.0.73.0`,发布者显示名称更改为 `Zhe Fang`。
在 `ImageHelper.cs` 中新增 `DataUrlToByteArray` 和 `GetImageBytesFromUrlAsync` 方法,以支持数据 URL 和网络图片的处理。
在 `MediaSessionsService.cs` 中,更新了音乐专辑封面图像的下载逻辑,改用新的图像获取方法并记录 URL 信息。
2025-09-04 15:19:33 -04:00
Zhe Fang
e18d78170a Add Apple Music configuration instructions
Added instructions for configuring Apple Music in the README.
2025-09-04 09:38:31 -04:00
Zhe Fang
023bf77afc Merge branch 'dev' of https://github.com/jayfunc/BetterLyrics into dev 2025-09-04 09:19:18 -04:00
Zhe Fang
2877ac2101 更新版本并增强媒体处理功能
- 更新 `Package.appxmanifest` 版本号至 `1.0.72.0`。
- 修改 `LXMusic.cs` 中的 `QuerySuffix`,新增 `picUrl` 过滤器。
- 清理 `MediaSourceProviderToLogoUriConverter.cs` 中的 `using` 语句。
- 在 `ImageHelper.cs` 中添加异步方法 `DownloadImageAsByteArrayAsync`,用于下载图像。
- 在 `MediaSessionsService.cs` 中添加 `_lxMusicAlbumArtBytes` 字节数组以存储专辑封面。
- 更新媒体属性处理逻辑,以支持从 `picUrl` 下载专辑封面。
- 修改 SSE 消息接收逻辑,支持异步操作以处理图像下载和更新。
2025-09-04 09:19:16 -04:00
Zhe Fang
16d82109bb 更新 README.md 2025-09-03 12:19:09 -04:00
Zhe Fang
c703f04119 Revise README for Microsoft Store and download options 2025-09-02 18:30:31 -04:00
Zhe Fang
998853f9d2 更新 README.md 2025-09-02 13:40:45 -04:00
Zhe Fang
f560735da0 更新 README.md 2025-09-02 13:35:09 -04:00
Zhe Fang
ab9da73b49 更新 README.md 2025-09-02 13:00:38 -04:00
Zhe Fang
dc364edf75 更新 README.md 2025-09-02 12:59:27 -04:00
Zhe Fang
7fbc8fbfe7 Merge branch 'dev' of https://github.com/jayfunc/BetterLyrics into dev 2025-09-02 07:38:47 -04:00
Zhe Fang
4a00bb2ddf 更新版本并添加对 Apple Music 的支持
- 将 `Package.appxmanifest` 的版本号更新为 `1.0.71.0`。
- 移除 `BetterLyrics.WinUI3.csproj` 中对 `TinyPinyin.Net` 的引用。
- 在 `PlaybackSettingsControl.xaml` 中更新目标语言选择,移除中文选项并添加多个新语言。
- 新增 Apple Music 令牌输入框和按钮,允许用户保存令牌。
- 在 `LyricsSearchProviderToDisplayNameConverter.cs` 和 `TranslationSearchProviderToDisplayNameConverter.cs` 中添加对 Apple Music 的支持。
- 在 `LyricsSearchProvider.cs` 中新增 `AppleMusic` 作为歌词搜索提供者,并添加相关缓存目录和格式。
- 更新 `LanguageHelper.cs` 中的目标语言列表。
- 将 `TranslationSettings.cs` 中的 `SelectedTargetLanguageIndex` 属性更改为 `SelectedTargetLanguageCode`。
- 在 `LyricsSearchService.cs` 中添加 Apple Music 的歌词搜索功能。
- 更新 `MediaSessionsService.cs` 中的翻译和歌词更新逻辑。
- 移除 `SettingsPageViewModel.cs` 中的库信息支持,添加对媒体会话服务的引用。
- 新增 `AppleMusic.cs` 文件,包含与 Apple Music API 交互的逻辑。
2025-09-02 07:38:45 -04:00
Zhe Fang
7472aa048f 更新 README.md 2025-08-27 22:07:14 -04:00
Zhe Fang
49b0f7a692 Merge branch 'dev' of https://github.com/jayfunc/BetterLyrics into dev 2025-08-27 08:28:44 -04:00
Zhe Fang
4d0602ebef 更新版本号并优化歌词窗口边界计算
在 `Package.appxmanifest` 文件中,将应用程序版本号从 `1.0.66.0` 更新为 `1.0.67.0`。
在 `LiveStates.cs` 文件中,修改了 `DemoLyricsWindowBounds` 的计算方式,以更准确地反映歌词窗口在监视器上的位置。
2025-08-27 08:28:42 -04:00
Zhe Fang
626395d93a Update instructions from 'Clone' to 'Fork' 2025-08-26 22:34:18 -04:00
Zhe Fang
0ab5602569 Revise translation contribution instructions
Updated translation instructions for contributors.
2025-08-26 16:50:34 -04:00
127 changed files with 4597 additions and 3146 deletions

View File

@@ -12,13 +12,13 @@
<Identity
Name="37412.BetterLyrics"
Publisher="CN=E1428B0E-DC1D-4EA4-ACB1-4556569D5BA9"
Version="1.0.66.0" />
Version="1.0.83.0" />
<mp:PhoneIdentity PhoneProductId="ca4a4830-fc19-40d9-b823-53e2bff3d816" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
<Properties>
<DisplayName>BetterLyrics</DisplayName>
<PublisherDisplayName>founchoo</PublisherDisplayName>
<PublisherDisplayName>Zhe Fang</PublisherDisplayName>
<Logo>Images\StoreLogo.png</Logo>
</Properties>

View File

@@ -84,7 +84,7 @@ namespace BetterLyrics.WinUI3
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
WindowHelper.OpenWindow<LyricsWindow>();
WindowHelper.OpenOrShowWindow<LyricsWindow>();
}
private static void ConfigureServices()
@@ -113,12 +113,11 @@ namespace BetterLyrics.WinUI3
.AddSingleton<ILastFMService, LastFMService>()
// ViewModels
.AddSingleton<AppSettingsControlViewModel>()
.AddSingleton<LyricsBackgroundSettingsControlViewModel>()
.AddSingleton<AlbumArtLayoutSettingsControlViewModel>()
.AddSingleton<PlaybackSettingsControlViewModel>()
.AddSingleton<MediaSettingsControlViewModel>()
.AddSingleton<AllLyricsSettingsControlViewModel>()
.AddSingleton<LyricsSearchControlViewModel>()
.AddSingleton<LyricsWindowSettingsControlViewModel>()
.AddSingleton<LyricsWindowSwitchControlViewModel>()
.AddSingleton<LyricsWindowViewModel>()
.AddSingleton<SettingsWindowViewModel>()
.AddSingleton<SystemTrayViewModel>()

Binary file not shown.

After

Width:  |  Height:  |  Size: 879 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

View File

@@ -20,19 +20,23 @@
<PRIResource Remove="ViewModels\Lyrics\**" />
</ItemGroup>
<ItemGroup>
<None Remove="Assets\effect.bin" />
<None Remove="Assets\Segoe Fluent Icons.ttf" />
<None Remove="Assets\Wiki82.profile.xml" />
<None Remove="Controls\AlbumArtLayoutSettingsControl.xaml" />
<None Remove="Controls\AllLyricsSettingsControl.xaml" />
<None Remove="Controls\AppSettingsControl.xaml" />
<None Remove="Controls\DemoWindowGrid.xaml" />
<None Remove="Controls\ExtendedSlider.xaml" />
<None Remove="Controls\LyricsSearchControl.xaml" />
<None Remove="Controls\LyricsSettingsControl.xaml" />
<None Remove="Controls\LyricsWindowSettingsControl.xaml" />
<None Remove="Controls\LyricsWindowSwitchControl.xaml" />
<None Remove="Controls\MediaSettingsControl.xaml" />
<None Remove="Controls\PlaybackSettingsControl.xaml" />
<None Remove="Controls\ShortcutTextBox.xaml" />
<None Remove="Controls\SystemTray.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" />
@@ -70,6 +74,7 @@
<PackageReference Include="Microsoft.Graphics.Win2D" Version="1.3.2" />
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.4654" />
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.7.250606001" />
<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" />
@@ -81,7 +86,6 @@
<PackageReference Include="System.Drawing.Common" Version="9.0.8" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="9.0.8" />
<PackageReference Include="TagLibSharp" Version="2.3.0" />
<PackageReference Include="TinyPinyin.Net" Version="1.0.2" />
<PackageReference Include="Ude.NetStandard" Version="1.2.0" />
<PackageReference Include="Vanara.PInvoke.CoreAudio" Version="4.1.6" />
<PackageReference Include="Vanara.PInvoke.DwmApi" Version="4.1.6" />
@@ -118,6 +122,9 @@
<Content Update="Assets\Edge.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Update="Assets\effect.bin">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Update="Assets\Empty.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
@@ -142,6 +149,9 @@
<Content Update="Assets\Leaf.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Update="Assets\Listen1.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Update="Assets\Logo.ico">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
@@ -154,6 +164,9 @@
<Content Update="Assets\MediaPlayerWindows11.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Update="Assets\MoeKoeMusic.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Update="Assets\MusicBee.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
@@ -172,6 +185,9 @@
<Content Update="Assets\Question.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Update="Assets\SaltPlayerForWindows.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Update="Assets\Segoe Fluent Icons.ttf">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
@@ -182,6 +198,26 @@
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<Page Update="Views\LyricsWindowSwitchWindow.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Page Update="Controls\LyricsWindowSwitchControl.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Page Update="Controls\DemoWindowGrid.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Page Update="Controls\LyricsWindowSettingsControl.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Page Update="Views\LyricsSearchWindow.xaml">
<Generator>MSBuild:Compile</Generator>
@@ -202,11 +238,6 @@
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Page Update="Controls\AllLyricsSettingsControl.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Page Update="Controls\LyricsSettingsControl.xaml">
<Generator>MSBuild:Compile</Generator>
@@ -257,6 +288,11 @@
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<PRIResource Update="Strings\en-US\Resources.resw">
<Generator></Generator>
</PRIResource>
</ItemGroup>
<!-- Publish Properties -->
<PropertyGroup>
<PublishReadyToRun Condition="'$(Configuration)' == 'Debug'">False</PublishReadyToRun>

View File

@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BetterLyrics.WinUI3.Constants
{
public static class AppleMusic
{
public const string MediaUserTokenKey = "AppleMusicMediaUserToken";
}
}

View File

@@ -8,6 +8,6 @@ namespace BetterLyrics.WinUI3.Constants
{
public static class LXMusic
{
public const string QuerySuffix = "/subscribe-player-status?filter=progress,duration";
public const string QuerySuffix = "/subscribe-player-status?filter=progress,duration,picUrl";
}
}

View File

@@ -26,5 +26,9 @@ namespace BetterLyrics.WinUI3.Constants
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 MoeKoeMusic = "cn.MoeKoe.Music";
public const string MoeKoeMusicAlternative = "electron.app.MoeKoe Music";
public const string Listen1 = "com.listen1.listen1";
}
}

View File

@@ -25,5 +25,8 @@ namespace BetterLyrics.WinUI3.Constants
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 MoeKoeMusic = "MoeKoe Music";
public const string Listen1 = "Listen 1";
}
}

View File

@@ -17,6 +17,27 @@
<TextBlock x:Uid="SettingsPageAlbumArt" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
<controls:SettingsExpander
x:Uid="SettingsPageAlbumArtSize"
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
Glyph=&#xE744;}"
IsExpanded="True">
<controls:SettingsExpander.Items>
<controls:SettingsCard x:Uid="SettingsPageAutoSize">
<ToggleSwitch IsOn="{x:Bind AlbumArtLayoutSettings.AutoAlbumArtSize, Mode=TwoWay}" />
</controls:SettingsCard>
<controls: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}" />
</controls:SettingsCard>
</controls:SettingsExpander.Items>
</controls:SettingsExpander>
<controls:SettingsCard x:Uid="SettingsPageAlbumRadius" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xEA3A;}">
<local:ExtendedSlider
Default="12"
@@ -24,7 +45,7 @@
Maximum="100"
Minimum="0"
Unit="%"
Value="{x:Bind ViewModel.AppSettings.AlbumArtLayoutSettings.CoverImageRadius, Mode=TwoWay}" />
Value="{x:Bind AlbumArtLayoutSettings.CoverImageRadius, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageAlbumShadowAmount" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xF5EF;}">
@@ -33,13 +54,13 @@
Frequency="1"
Maximum="64"
Minimum="0"
Value="{x:Bind ViewModel.AppSettings.AlbumArtLayoutSettings.CoverImageShadowAmount, Mode=TwoWay}" />
Value="{x:Bind AlbumArtLayoutSettings.CoverImageShadowAmount, Mode=TwoWay}" />
</controls:SettingsCard>
<TextBlock x:Uid="SettingsPageSongInfo" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
<controls:SettingsCard x:Uid="SettingsPageSongInfoAlignment" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xE8E3;}">
<ComboBox SelectedIndex="{x:Bind ViewModel.AppSettings.AlbumArtLayoutSettings.SongInfoAlignmentType, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
<ComboBox SelectedIndex="{x:Bind AlbumArtLayoutSettings.SongInfoAlignmentType, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
<ComboBoxItem x:Uid="SettingsPageSongInfoLeft" />
<ComboBoxItem x:Uid="SettingsPageSongInfoCenter" />
<ComboBoxItem x:Uid="SettingsPageSongInfoRight" />
@@ -50,14 +71,26 @@
<local:ExtendedSlider
Default="18"
Frequency="2"
Maximum="48"
Minimum="12"
Value="{x:Bind ViewModel.AppSettings.AlbumArtLayoutSettings.SongInfoFontSize, Mode=TwoWay}" />
Maximum="72"
Minimum="8"
Value="{x:Bind AlbumArtLayoutSettings.SongInfoFontSize, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsExpander
x:Uid="SettingsPageShowTitle"
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
Glyph=&#xEF3D;}"
IsExpanded="True">
<ToggleSwitch IsOn="{x:Bind AlbumArtLayoutSettings.ShowTitle, Mode=TwoWay}" />
<controls:SettingsExpander.Items>
<controls:SettingsCard x:Uid="SettingsPageShowArtists">
<ToggleSwitch IsEnabled="{x:Bind AlbumArtLayoutSettings.ShowTitle, Mode=OneWay}" IsOn="{x:Bind AlbumArtLayoutSettings.ShowArtists, Mode=TwoWay}" />
</controls:SettingsCard>
</controls:SettingsExpander.Items>
</controls:SettingsExpander>
</StackPanel>
</Grid>
</ScrollViewer>
</Grid>
</UserControl>

View File

@@ -1,3 +1,4 @@
using BetterLyrics.WinUI3.Models.Settings;
using BetterLyrics.WinUI3.ViewModels;
using CommunityToolkit.Mvvm.DependencyInjection;
using Microsoft.UI.Xaml;
@@ -22,11 +23,18 @@ namespace BetterLyrics.WinUI3.Controls
{
public sealed partial class AlbumArtLayoutSettingsControl : UserControl
{
public AlbumArtLayoutSettingsControlViewModel ViewModel => (AlbumArtLayoutSettingsControlViewModel)DataContext;
public static readonly DependencyProperty AlbumArtLayoutSettingsProperty =
DependencyProperty.Register(nameof(AlbumArtLayoutSettings), typeof(AlbumArtLayoutSettings), typeof(AlbumArtLayoutSettingsControl), new PropertyMetadata(default));
public AlbumArtLayoutSettings AlbumArtLayoutSettings
{
get => (AlbumArtLayoutSettings)GetValue(AlbumArtLayoutSettingsProperty);
set => SetValue(AlbumArtLayoutSettingsProperty, value);
}
public AlbumArtLayoutSettingsControl()
{
InitializeComponent();
DataContext = Ioc.Default.GetRequiredService<AlbumArtLayoutSettingsControlViewModel>();
}
}
}

View File

@@ -1,40 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<UserControl
x:Class="BetterLyrics.WinUI3.Controls.AllLyricsSettingsControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:CommunityToolkit.WinUI.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:BetterLyrics.WinUI3.Controls"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:uc="using:BetterLyrics.WinUI3.Controls"
mc:Ignorable="d">
<Grid>
<controls:SwitchPresenter Margin="0,72,0,0" Value="{Binding SelectedItem.Tag, ElementName=LyricsSettingsSegmentedControl}">
<controls:Case Value="Standard">
<uc:LyricsSettingsControl LyricsEffectSettings="{x:Bind ViewModel.AppSettings.StandardLyricsEffectSettings, Mode=OneWay}" LyricsStyleSettings="{x:Bind ViewModel.AppSettings.StandardLyricsStyleSettings, Mode=OneWay}" />
</controls:Case>
<controls:Case Value="Desktop">
<uc:LyricsSettingsControl LyricsEffectSettings="{x:Bind ViewModel.AppSettings.DesktopLyricsEffectSettings, Mode=OneWay}" LyricsStyleSettings="{x:Bind ViewModel.AppSettings.DesktopLyricsStyleSettings, Mode=OneWay}" />
</controls:Case>
<controls:Case Value="Dock">
<uc:LyricsSettingsControl LyricsEffectSettings="{x:Bind ViewModel.AppSettings.DockLyricsEffectSettings, Mode=OneWay}" LyricsStyleSettings="{x:Bind ViewModel.AppSettings.DockLyricsStyleSettings, Mode=OneWay}" />
</controls:Case>
<controls:Case Value="PictureInPicture">
<uc:LyricsSettingsControl LyricsEffectSettings="{x:Bind ViewModel.AppSettings.PictureInPictureLyricsEffectSettings, Mode=OneWay}" LyricsStyleSettings="{x:Bind ViewModel.AppSettings.PictureInPictureLyricsStyleSettings, Mode=OneWay}" />
</controls:Case>
</controls:SwitchPresenter>
<controls:Segmented
x:Name="LyricsSettingsSegmentedControl"
Margin="36,36,36,0"
HorizontalAlignment="Stretch"
VerticalAlignment="Top"
SelectedIndex="{x:Bind ViewModel.SelectedTabIndex, Mode=OneWay}">
<controls:SegmentedItem x:Uid="AllLyricsSettingsControlStandard" Tag="Standard" />
<controls:SegmentedItem x:Uid="AllLyricsSettingsControlDock" Tag="Dock" />
<controls:SegmentedItem x:Uid="AllLyricsSettingsControlDesktop" Tag="Desktop" />
<controls:SegmentedItem x:Uid="AllLyricsSettingsControlPictureInPicture" Tag="PictureInPicture" />
</controls:Segmented>
</Grid>
</UserControl>

View File

@@ -11,375 +11,87 @@
mc:Ignorable="d">
<Grid>
<controls:SwitchPresenter Margin="0,72,0,0" Value="{Binding SelectedItem.Tag, ElementName=SegmentedControl}">
<ScrollViewer Style="{StaticResource SettingsScrollViewerStyle}">
<Grid Style="{StaticResource SettingsGridStyle}">
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
<controls:Case Value="General">
<ScrollViewer Style="{StaticResource SettingsScrollViewerStyle}">
<Grid Style="{StaticResource SettingsGridStyle}">
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
<!-- App appearance -->
<!-- App appearance -->
<TextBlock x:Uid="SettingsPageAppAppearance" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
<TextBlock x:Uid="SettingsPageAppAppearance" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
<controls:SettingsExpander
x:Uid="SettingsPageLanguage"
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
Glyph=&#xF2B7;}"
IsExpanded="True">
<ComboBox SelectedIndex="{x:Bind ViewModel.AppSettings.GeneralSettings.Language, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
<ComboBoxItem x:Uid="SettingsPageSystemLanguage" />
<ComboBoxItem x:Uid="SettingsPageEN" />
<ComboBoxItem x:Uid="SettingsPageSC" />
<ComboBoxItem x:Uid="SettingsPageTC" />
<ComboBoxItem x:Uid="SettingsPageJA" />
<ComboBoxItem x:Uid="SettingsPageKO" />
</ComboBox>
<controls:SettingsExpander.Items>
<controls:SettingsCard>
<Button x:Uid="SettingsPageRestart" Command="{x:Bind ViewModel.RestartAppCommand}" />
</controls:SettingsCard>
</controls:SettingsExpander.Items>
</controls:SettingsExpander>
<!-- App behavior -->
<TextBlock x:Uid="SettingsPageAppBehavior" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
<controls:SettingsCard x:Uid="SettingsPageAutoStart" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xF71C;}">
<ToggleSwitch
x:Name="AutoStartupToggleSwitch"
Loaded="AutoStartupToggleSwitch_Loaded"
Unloaded="AutoStartupToggleSwitch_Unloaded" />
<controls:SettingsExpander
x:Uid="SettingsPageLanguage"
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
Glyph=&#xF2B7;}"
IsExpanded="True">
<ComboBox SelectedIndex="{x:Bind ViewModel.AppSettings.GeneralSettings.Language, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
<ComboBoxItem x:Uid="SettingsPageSystemLanguage" />
<ComboBoxItem x:Uid="SettingsPageEN" />
<ComboBoxItem x:Uid="SettingsPageSC" />
<ComboBoxItem x:Uid="SettingsPageTC" />
<ComboBoxItem x:Uid="SettingsPageJA" />
<ComboBoxItem x:Uid="SettingsPageKO" />
</ComboBox>
<controls:SettingsExpander.Items>
<controls:SettingsCard>
<Button x:Uid="SettingsPageRestart" Command="{x:Bind ViewModel.RestartAppCommand}" />
</controls:SettingsCard>
</controls:SettingsExpander.Items>
</controls:SettingsExpander>
<controls:SettingsCard x:Uid="SettingsPageAutoStartWindow" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xE736;}">
<ComboBox SelectedIndex="{x:Bind ViewModel.AppSettings.GeneralSettings.AutoStartWindowType, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
<ComboBoxItem x:Uid="SettingsPageAutoStartInAppLyrics" />
<ComboBoxItem x:Uid="SettingsPageAutoStartDockLyrics" />
<ComboBoxItem x:Uid="SettingsPageAutoStartDesktopLyrics" />
<ComboBoxItem x:Uid="SettingsPageAutoStartPIPLyrics" />
</ComboBox>
</controls:SettingsCard>
<!-- App behavior -->
<controls:SettingsExpander
x:Name="LyricsWindowManagerExpander"
x:Uid="SettingsPageLyricsWindowManager"
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
Glyph=&#xE61F;}"
IsExpanded="True" />
<TextBlock x:Uid="SettingsPageAppBehavior" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
<Grid
Margin="0,-20,0,0"
Padding="60,16"
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
CornerRadius="4"
Visibility="{Binding ElementName=LyricsWindowManagerExpander, Path=IsExpanded, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}">
<StackPanel Spacing="16">
<TextBlock x:Uid="SettingsPageCurrentLyricsWindowStatus" />
<StackPanel HorizontalAlignment="Left" Spacing="4">
<Grid
Width="{x:Bind ViewModel.LiveStates.DemoLyricsWindowMonitorBounds.Width, Mode=OneWay}"
Height="{x:Bind ViewModel.LiveStates.DemoLyricsWindowMonitorBounds.Height, Mode=OneWay}"
Background="{ThemeResource CardBackgroundFillColorSecondaryBrush}">
<Grid
Width="{x:Bind ViewModel.LiveStates.DemoLyricsWindowBounds.Width, Mode=OneWay}"
Height="{x:Bind ViewModel.LiveStates.DemoLyricsWindowBounds.Height, Mode=OneWay}"
Margin="{x:Bind ViewModel.LiveStates.DemoLyricsWindowBounds, Converter={StaticResource RectToMarginConverter}, Mode=OneWay}"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Background="{ThemeResource AccentFillColorDefaultBrush}"
CornerRadius="4" />
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontWeight="ExtraBlack"
Opacity="0.7"
Text="{x:Bind ViewModel.LiveStates.LyricsWindowMonitorName, Mode=OneWay}"
TextWrapping="Wrap" />
</Grid>
<Grid>
<Button
x:Uid="SettingsPageRecord"
HorizontalAlignment="Stretch"
Command="{x:Bind ViewModel.RecordCurrentWindowBoundsCommand}"
Style="{StaticResource AccentButtonStyle}" />
</Grid>
</StackPanel>
</StackPanel>
</Grid>
<controls:SettingsCard x:Uid="SettingsPageAutoStart" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xF71C;}">
<ToggleSwitch
x:Name="AutoStartupToggleSwitch"
Loaded="AutoStartupToggleSwitch_Loaded"
Unloaded="AutoStartupToggleSwitch_Unloaded" />
</controls:SettingsCard>
<StackPanel
Margin="0,-3,0,0"
Padding="60,16"
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
CornerRadius="4"
Spacing="16"
Visibility="{Binding ElementName=LyricsWindowManagerExpander, Path=IsExpanded, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}">
<TextBlock x:Uid="SettingsPageRecordedWindowStatus" />
<GridView
Margin="-2"
CornerRadius="4"
ItemsSource="{x:Bind ViewModel.AppSettings.WindowBoundsRecords, Mode=OneWay}"
SelectionMode="None">
<GridView.ItemContainerStyle>
<Style BasedOn="{StaticResource DefaultGridViewItemStyle}" TargetType="GridViewItem">
<Setter Property="Margin" Value="5,5,5,5" />
</Style>
</GridView.ItemContainerStyle>
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsWrapGrid Orientation="Horizontal" />
</ItemsPanelTemplate>
</GridView.ItemsPanel>
<GridView.ItemTemplate>
<DataTemplate>
<Grid>
<StackPanel Spacing="4">
<Grid
Width="{Binding DemoMonitorBounds.Width}"
Height="{Binding DemoMonitorBounds.Height}"
Background="{ThemeResource CardBackgroundFillColorSecondaryBrush}">
<Grid
Width="{Binding DemoWindowBounds.Width}"
Height="{Binding DemoWindowBounds.Height}"
Margin="{Binding DemoWindowBounds, Converter={StaticResource RectToMarginConverter}}"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Background="{ThemeResource AccentFillColorDefaultBrush}"
CornerRadius="4" />
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontWeight="ExtraBlack"
Opacity="0.7"
Text="{Binding MonitorDeviceName}"
TextWrapping="Wrap" />
</Grid>
<Grid ColumnSpacing="4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button
x:Uid="SettingsPageDelete"
Grid.Column="0"
HorizontalAlignment="Stretch"
Click="DeleteWindowBoundsRecordButton_Click" />
<Button
x:Uid="SettingsPageApply"
Grid.Column="1"
HorizontalAlignment="Stretch"
Click="ApplyWindowBoundsRecordButton_Click"
Style="{StaticResource AccentButtonStyle}" />
</Grid>
</StackPanel>
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
</StackPanel>
<controls:SettingsCard x:Uid="SettingsPageExitOnLyricsWindowClosed" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xE7E8;}">
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.GeneralSettings.ExitOnLyricsWindowClosed, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageIgnoreFullscreenWindow" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xE967;}">
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.GeneralSettings.IgnoreFullscreenWindow, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageListenNewSession" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xF270;}">
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.GeneralSettings.ListenOnNewPlaybackSource, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageHideWindow" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xED1A;}">
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.GeneralSettings.HideWindowWhenNotPlaying, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageShowHideHotKey" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xEDA7;}">
<local:ShortcutTextBox Shortcut="{x:Bind ViewModel.AppSettings.GeneralSettings.ShowOrHideLyricsWindowShortcut, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageShowHideHotKey" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xEDA7;}">
<local:ShortcutTextBox Shortcut="{x:Bind ViewModel.AppSettings.GeneralSettings.ShowOrHideLyricsWindowShortcut, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageBorderlessHotKey" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xEDA7;}">
<local:ShortcutTextBox Shortcut="{x:Bind ViewModel.AppSettings.GeneralSettings.BorderlessShortcut, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageGlobalDrag" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xE7C2;}">
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.GeneralSettings.IsDragEverywhereEnabled, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageClickThroughHotKey" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xEDA7;}">
<local:ShortcutTextBox Shortcut="{x:Bind ViewModel.AppSettings.GeneralSettings.ClickThroughShortcut, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageExitOnLyricsWindowClosed" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xE7E8;}">
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.GeneralSettings.ExitOnLyricsWindowClosed, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageLyricsWindowSwitchHotKey" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xEDA7;}">
<local:ShortcutTextBox Shortcut="{x:Bind ViewModel.AppSettings.GeneralSettings.LyricsWindowSwitchShortcut, Mode=TwoWay}" />
</controls:SettingsCard>
<!-- Playback shortcut -->
<!-- Playback shortcut -->
<TextBlock x:Uid="SettingsPagePlaybackShortcut" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
<TextBlock x:Uid="SettingsPagePlaybackShortcut" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
<controls:SettingsCard x:Uid="SettingsPagePlayOrPauseSongHotKey" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xEDA7;}">
<local:ShortcutTextBox Shortcut="{x:Bind ViewModel.AppSettings.GeneralSettings.PlayOrPauseShortcut, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPagePlayOrPauseSongHotKey" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xEDA7;}">
<local:ShortcutTextBox Shortcut="{x:Bind ViewModel.AppSettings.GeneralSettings.PlayOrPauseShortcut, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageNextSongHotKey" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xEDA7;}">
<local:ShortcutTextBox Shortcut="{x:Bind ViewModel.AppSettings.GeneralSettings.NextSongShortcut, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageNextSongHotKey" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xEDA7;}">
<local:ShortcutTextBox Shortcut="{x:Bind ViewModel.AppSettings.GeneralSettings.NextSongShortcut, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPagePreviousSongHotKey" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xEDA7;}">
<local:ShortcutTextBox Shortcut="{x:Bind ViewModel.AppSettings.GeneralSettings.PreviousSongShortcut, Mode=TwoWay}" />
</controls:SettingsCard>
</StackPanel>
</Grid>
</ScrollViewer>
</controls:Case>
<controls:Case Value="Standard">
<ScrollViewer Style="{StaticResource SettingsScrollViewerStyle}">
<Grid Style="{StaticResource SettingsGridStyle}">
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
<!-- Standard mode -->
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
<controls:SettingsCard x:Uid="SettingsPageDisplayTypeSwitcher" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xF246;}">
<ComboBox SelectedIndex="{x:Bind ViewModel.AppSettings.StandardModeSettings.LyricsDisplayType, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
<ComboBoxItem x:Uid="MainPageAlbumArtOnly" />
<ComboBoxItem x:Uid="MainPageLyriscOnly" />
<ComboBoxItem x:Uid="MainPageSplitView" />
</ComboBox>
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageAOT" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xE718;}">
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.StandardModeSettings.IsAlwaysOnTop, Mode=TwoWay}" />
</controls:SettingsCard>
</StackPanel>
</Grid>
</ScrollViewer>
</controls:Case>
<controls:Case Value="Desktop">
<ScrollViewer Style="{StaticResource SettingsScrollViewerStyle}">
<Grid Style="{StaticResource SettingsGridStyle}">
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
<!-- Desktop mode -->
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
<controls:SettingsCard x:Uid="SettingsPageDisplayTypeSwitcher" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xF246;}">
<ComboBox SelectedIndex="{x:Bind ViewModel.AppSettings.DesktopModeSettings.LyricsDisplayType, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
<ComboBoxItem x:Uid="MainPageAlbumArtOnly" />
<ComboBoxItem x:Uid="MainPageLyriscOnly" />
<ComboBoxItem x:Uid="MainPageSplitView" />
</ComboBox>
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageAOT" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xE718;}">
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.DesktopModeSettings.IsAlwaysOnTop, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageToggleHotKey" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xEDA7;}">
<local:ShortcutTextBox Shortcut="{x:Bind ViewModel.AppSettings.DesktopModeSettings.ToggleShortcut, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageAutoLock" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xE755;}">
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.DesktopModeSettings.AutoLockOnDesktopMode, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageLockHotKey" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xEDA7;}">
<local:ShortcutTextBox Shortcut="{x:Bind ViewModel.AppSettings.DesktopModeSettings.LockShortcut, Mode=TwoWay}" />
</controls:SettingsCard>
</StackPanel>
</Grid>
</ScrollViewer>
</controls:Case>
<controls:Case Value="Dock">
<ScrollViewer Style="{StaticResource SettingsScrollViewerStyle}">
<Grid Style="{StaticResource SettingsGridStyle}">
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
<!-- Dock mode -->
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
<controls:SettingsCard x:Uid="SettingsPageDisplayTypeSwitcher" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xF246;}">
<ComboBox SelectedIndex="{x:Bind ViewModel.AppSettings.DockModeSettings.LyricsDisplayType, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
<ComboBoxItem x:Uid="MainPageAlbumArtOnly" />
<ComboBoxItem x:Uid="MainPageLyriscOnly" />
<ComboBoxItem x:Uid="MainPageSplitView" />
</ComboBox>
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageToggleHotKey" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xEDA7;}">
<local:ShortcutTextBox Shortcut="{x:Bind ViewModel.AppSettings.DockModeSettings.ToggleShortcut, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageDockMonitor" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xE7F4;}">
<StackPanel Orientation="Horizontal" Spacing="6">
<ComboBox ItemsSource="{x:Bind ViewModel.MonitorDeviceNames, Mode=OneWay}" SelectedItem="{x:Bind ViewModel.AppSettings.DockModeSettings.DockMonitorDeviceName, Mode=TwoWay}" />
<Button
Command="{x:Bind ViewModel.RefreshMonitorDeviceNamesCommand}"
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
FontSize=12,
Glyph=&#xE72C;}"
Style="{StaticResource GhostButtonStyle}" />
</StackPanel>
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageDockWindowHeight" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xED5E;}">
<local:ExtendedSlider
Default="64"
Frequency="1"
Maximum="200"
Minimum="64"
Unit="px"
Value="{x:Bind ViewModel.AppSettings.DockModeSettings.DockWindowHeight, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageDockPlacement" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xE8E3;}">
<ComboBox SelectedIndex="{x:Bind ViewModel.AppSettings.DockModeSettings.DockPlacement, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
<ComboBoxItem x:Uid="SettingsPageDockPlacementTop" />
<ComboBoxItem x:Uid="SettingsPageDockPlacementBottom" />
</ComboBox>
</controls:SettingsCard>
</StackPanel>
</Grid>
</ScrollViewer>
</controls:Case>
<controls:Case Value="PictureInPicture">
<ScrollViewer Style="{StaticResource SettingsScrollViewerStyle}">
<Grid Style="{StaticResource SettingsGridStyle}">
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
<!-- Picture in picture mode -->
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
<controls:SettingsCard x:Uid="SettingsPageDisplayTypeSwitcher" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xF246;}">
<ComboBox SelectedIndex="{x:Bind ViewModel.AppSettings.PictureInPictureModeSettings.LyricsDisplayType, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
<ComboBoxItem x:Uid="MainPageAlbumArtOnly" />
<ComboBoxItem x:Uid="MainPageLyriscOnly" />
<ComboBoxItem x:Uid="MainPageSplitView" />
</ComboBox>
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageToggleHotKey" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xEDA7;}">
<local:ShortcutTextBox Shortcut="{x:Bind ViewModel.AppSettings.PictureInPictureModeSettings.ToggleShortcut, Mode=TwoWay}" />
</controls:SettingsCard>
</StackPanel>
</Grid>
</ScrollViewer>
</controls:Case>
</controls:SwitchPresenter>
<controls:Segmented
x:Name="SegmentedControl"
Margin="36,36,36,0"
HorizontalAlignment="Stretch"
VerticalAlignment="Top"
SelectedIndex="0">
<controls:SegmentedItem x:Uid="AppSettingsControlGeneral" Tag="General" />
<controls:SegmentedItem x:Uid="AllLyricsSettingsControlStandard" Tag="Standard" />
<controls:SegmentedItem x:Uid="AllLyricsSettingsControlDock" Tag="Dock" />
<controls:SegmentedItem x:Uid="AllLyricsSettingsControlDesktop" Tag="Desktop" />
<controls:SegmentedItem x:Uid="AllLyricsSettingsControlPictureInPicture" Tag="PictureInPicture" />
</controls:Segmented>
<controls:SettingsCard x:Uid="SettingsPagePreviousSongHotKey" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xEDA7;}">
<local:ShortcutTextBox Shortcut="{x:Bind ViewModel.AppSettings.GeneralSettings.PreviousSongShortcut, Mode=TwoWay}" />
</controls:SettingsCard>
</StackPanel>
</Grid>
</ScrollViewer>
</Grid>
</UserControl>

View File

@@ -49,33 +49,5 @@ namespace BetterLyrics.WinUI3.Controls
{
AutoStartupToggleSwitch.Toggled -= AutoStartupToggleSwitch_Toggled;
}
private void DeleteWindowBoundsRecordButton_Click(object sender, RoutedEventArgs e)
{
if (sender is Button button)
{
var data = button.DataContext as WindowBoundsRecord;
if (data != null)
{
ViewModel.AppSettings.WindowBoundsRecords.Remove(data);
}
}
}
private void ApplyWindowBoundsRecordButton_Click(object sender, RoutedEventArgs e)
{
if (sender is Button button)
{
var data = button.DataContext as WindowBoundsRecord;
if (data != null)
{
var lyricsWindow = WindowHelper.GetWindowByWindowType<LyricsWindow>();
if (lyricsWindow != null)
{
lyricsWindow.AppWindow.MoveAndResize(data.WindowBounds.ToRectInt32());
}
}
}
}
}
}

View File

@@ -0,0 +1,104 @@
<?xml version="1.0" encoding="utf-8" ?>
<UserControl
x:Class="BetterLyrics.WinUI3.Controls.DemoWindowGrid"
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:interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:local="using:BetterLyrics.WinUI3.Controls"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid
Width="{x:Bind LyricsWindowStatus.DemoMonitorBounds.Width, Mode=OneWay}"
Height="{x:Bind LyricsWindowStatus.DemoMonitorBounds.Height, Mode=OneWay}"
Background="{ThemeResource AcrylicBackgroundFillColorBaseBrush}"
CornerRadius="4">
<Grid
Width="{x:Bind LyricsWindowStatus.DemoWindowBounds.Width, Mode=OneWay}"
Height="{x:Bind LyricsWindowStatus.DemoWindowBounds.Height, Mode=OneWay}"
Margin="{x:Bind LyricsWindowStatus.DemoWindowBounds, Converter={StaticResource RectToMarginConverter}, Mode=OneWay}"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Background="{ThemeResource AccentAcrylicBackgroundFillColorDefaultBrush}"
BorderBrush="{ThemeResource AccentFillColorDefaultBrush}"
CornerRadius="4">
<interactivity:Interaction.Behaviors>
<interactivity:DataTriggerBehavior
Binding="{x:Bind LyricsWindowStatus.IsBorderless, Mode=OneWay}"
ComparisonCondition="Equal"
Value="True">
<interactivity:ChangePropertyAction PropertyName="BorderThickness" Value="0" />
</interactivity:DataTriggerBehavior>
<interactivity:DataTriggerBehavior
Binding="{x:Bind LyricsWindowStatus.IsBorderless, Mode=OneWay}"
ComparisonCondition="Equal"
Value="False">
<interactivity:ChangePropertyAction PropertyName="BorderThickness" Value="1" />
</interactivity:DataTriggerBehavior>
</interactivity:Interaction.Behaviors>
</Grid>
<!-- Is default -->
<Grid
Margin="4"
Padding="6,3"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Background="{ThemeResource AcrylicBackgroundFillColorBaseBrush}"
CornerRadius="4"
Opacity="0.7"
Visibility="{x:Bind LyricsWindowStatus.IsDefault, Converter={StaticResource BoolToVisibilityConverter}, Mode=OneWay}">
<TextBlock
x:Uid="DemoWindowControlDefault"
FontSize="12"
TextWrapping="Wrap" />
</Grid>
<!-- Is always on top -->
<Grid
Margin="4"
Padding="6,3"
HorizontalAlignment="Right"
VerticalAlignment="Top"
Background="{ThemeResource AcrylicBackgroundFillColorBaseBrush}"
CornerRadius="4"
Opacity="0.7"
Visibility="{x:Bind LyricsWindowStatus.IsAlwaysOnTop, Converter={StaticResource BoolToVisibilityConverter}, Mode=OneWay}">
<FontIcon
FontFamily="{StaticResource IconFontFamily}"
FontSize="12"
Glyph="&#xE718;" />
<FontIcon
FontFamily="{StaticResource IconFontFamily}"
FontSize="12"
Glyph="&#xE841;"
Visibility="{x:Bind LyricsWindowStatus.IsAlwaysOnTopPolling, Converter={StaticResource BoolToVisibilityConverter}, Mode=OneWay}" />
</Grid>
<!-- Moniter name -->
<Grid
Margin="4"
Padding="6,3"
HorizontalAlignment="Left"
VerticalAlignment="Bottom"
Background="{ThemeResource AcrylicBackgroundFillColorBaseBrush}"
CornerRadius="4"
Opacity="0.7">
<TextBlock
FontSize="12"
Text="{x:Bind LyricsWindowStatus.MonitorDeviceName, Mode=OneWay}"
TextWrapping="Wrap" />
</Grid>
<!-- Config name -->
<Grid
Padding="6,3"
HorizontalAlignment="Center"
VerticalAlignment="Center"
CornerRadius="4"
Opacity="0.7">
<TextBlock
FontWeight="ExtraBlack"
Text="{x:Bind LyricsWindowStatus.Name, Mode=OneWay}"
TextWrapping="Wrap" />
</Grid>
</Grid>
</UserControl>

View File

@@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Navigation;
using BetterLyrics.WinUI3.Models;
// 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 DemoWindowGrid : UserControl
{
public DemoWindowGrid()
{
InitializeComponent();
}
public static readonly DependencyProperty LyricsWindowStatusProperty =
DependencyProperty.Register(nameof(LyricsWindowStatus), typeof(LyricsWindowStatus), typeof(DemoWindowGrid), new PropertyMetadata(default));
public LyricsWindowStatus LyricsWindowStatus
{
get => (LyricsWindowStatus)GetValue(LyricsWindowStatusProperty);
set => SetValue(LyricsWindowStatusProperty, value);
}
}

View File

@@ -4,54 +4,58 @@
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:interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:local="using:BetterLyrics.WinUI3.Controls"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ui="using:CommunityToolkit.WinUI"
mc:Ignorable="d">
<StackPanel Orientation="Horizontal">
<TextBlock
Margin="6,0,2,0"
VerticalAlignment="Center"
Text="{x:Bind Value, Mode=OneWay}" />
<TextBlock
Margin="0,0,14,0"
VerticalAlignment="Center"
Text="{x:Bind Unit, Mode=OneWay}" />
<StackPanel>
<Slider
Maximum="{x:Bind Maximum, Mode=OneWay}"
Minimum="{x:Bind Minimum, Mode=OneWay}"
SnapsTo="Ticks"
StepFrequency="{x:Bind Frequency, Mode=OneWay}"
TickFrequency="{x:Bind Frequency, Mode=OneWay}"
TickPlacement="Outside"
TickPlacement="None"
Value="{x:Bind Value, Mode=TwoWay}" />
<Button
Margin="3,0,0,0"
VerticalAlignment="Center"
Click="ResetButton_Click"
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
FontSize=12,
Glyph=&#xE777;}"
Style="{StaticResource GhostButtonStyle}"
Visibility="{x:Bind ResetButtonVisibility, Mode=OneWay}" />
<Button
x:Name="SubtractButton"
Margin="3,0,0,0"
VerticalAlignment="Center"
Click="SubtractButton_Click"
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
FontSize=12,
Glyph=&#xE738;}"
Style="{StaticResource GhostButtonStyle}" />
<Button
x:Name="AddButton"
Margin="3,0,0,0"
VerticalAlignment="Center"
Click="AddButton_Click"
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
FontSize=12,
Glyph=&#xE710;}"
Style="{StaticResource GhostButtonStyle}" />
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
<Button
VerticalAlignment="Center"
Click="ResetButton_Click"
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
FontSize=12,
Glyph=&#xE777;}"
Style="{StaticResource GhostButtonStyle}"
Visibility="{x:Bind ResetButtonVisibility, Mode=OneWay}" />
<Button
x:Name="SubtractButton"
VerticalAlignment="Center"
Click="SubtractButton_Click"
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
FontSize=12,
Glyph=&#xE738;}"
Style="{StaticResource GhostButtonStyle}" />
<StackPanel
Margin="3,-2,3,0"
Orientation="Horizontal"
Spacing="2">
<TextBlock VerticalAlignment="Center" Text="{x:Bind Value, Mode=OneWay}" />
<TextBlock VerticalAlignment="Center" Text="{x:Bind Unit, Mode=OneWay}" />
</StackPanel>
<Button
x:Name="AddButton"
VerticalAlignment="Center"
Click="AddButton_Click"
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
FontSize=12,
Glyph=&#xE710;}"
Style="{StaticResource GhostButtonStyle}" />
</StackPanel>
</StackPanel>
</UserControl>

View File

@@ -18,60 +18,112 @@
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
<controls:SettingsCard x:Uid="SettingsPageTheme" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xE790;}">
<ComboBox x:Name="ThemeComboBox" SelectedIndex="{x:Bind ViewModel.AppSettings.LyricsBackgroundSettings.LyricsBackgroundTheme, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
<ComboBox x:Name="ThemeComboBox" SelectedIndex="{x:Bind LyricsBackgroundSettings.LyricsBackgroundTheme, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
<ComboBoxItem x:Uid="SettingsPageFollowSystem" />
<ComboBoxItem x:Uid="SettingsPageLight" />
<ComboBoxItem x:Uid="SettingsPageDark" />
</ComboBox>
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageLyricsPureColorBgOpacity" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xEB42;}">
<uc:ExtendedSlider
Default="100"
Frequency="1"
Maximum="100"
Minimum="0"
Unit="%"
Value="{x:Bind ViewModel.AppSettings.LyricsBackgroundSettings.PureColorOverlayOpacity, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsExpander
x:Uid="SettingsPagePureLayer"
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
Glyph=&#xEB42;}"
IsExpanded="{x:Bind LyricsBackgroundSettings.IsPureColorOverlayEnabled, Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind LyricsBackgroundSettings.IsPureColorOverlayEnabled, Mode=TwoWay}" />
<controls:SettingsExpander.Items>
<controls:SettingsCard x:Uid="SettingsPageLyricsBackgroundOpacity" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xEB42;}">
<uc:ExtendedSlider
Default="100"
Frequency="1"
Maximum="100"
Minimum="0"
Unit="%"
Value="{x:Bind ViewModel.AppSettings.LyricsBackgroundSettings.CoverOverlayOpacity, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageOpacity" IsEnabled="{x:Bind LyricsBackgroundSettings.IsPureColorOverlayEnabled, Mode=OneWay}">
<uc:ExtendedSlider
Default="100"
Frequency="1"
Maximum="100"
Minimum="0"
Unit="%"
Value="{x:Bind LyricsBackgroundSettings.PureColorOverlayOpacity, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageLyricsBackgroundSpeed" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xEC49;}">
<uc:ExtendedSlider
Default="50"
Frequency="1"
Maximum="100"
Minimum="0"
Unit="%"
Value="{x:Bind ViewModel.AppSettings.LyricsBackgroundSettings.CoverOverlaySpeed, Mode=TwoWay}" />
</controls:SettingsCard>
</controls:SettingsExpander.Items>
</controls:SettingsExpander>
<controls:SettingsCard x:Uid="SettingsPageLyricsBackgroundBlurAmount" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xE727;}">
<uc:ExtendedSlider
Default="100"
Frequency="1"
Maximum="100"
Minimum="0"
Value="{x:Bind ViewModel.AppSettings.LyricsBackgroundSettings.CoverOverlayBlurAmount, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsExpander
x:Uid="SettingsPageAlbumArtLayer"
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
Glyph=&#xE93C;}"
IsExpanded="{x:Bind LyricsBackgroundSettings.IsCoverOverlayEnabled, Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind LyricsBackgroundSettings.IsCoverOverlayEnabled, Mode=TwoWay}" />
<controls:SettingsExpander.Items>
<controls:SettingsCard x:Uid="SettingsPageOpacity" IsEnabled="{x:Bind LyricsBackgroundSettings.IsCoverOverlayEnabled, Mode=OneWay}">
<uc:ExtendedSlider
Default="100"
Frequency="1"
Maximum="100"
Minimum="0"
Unit="%"
Value="{x:Bind LyricsBackgroundSettings.CoverOverlayOpacity, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageSpeed" IsEnabled="{x:Bind LyricsBackgroundSettings.IsCoverOverlayEnabled, Mode=OneWay}">
<uc:ExtendedSlider
Default="50"
Frequency="1"
Maximum="100"
Minimum="0"
Unit="%"
Value="{x:Bind LyricsBackgroundSettings.CoverOverlaySpeed, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageBlurAmount" IsEnabled="{x:Bind LyricsBackgroundSettings.IsCoverOverlayEnabled, Mode=OneWay}">
<uc:ExtendedSlider
Default="100"
Frequency="1"
Maximum="100"
Minimum="0"
Value="{x:Bind LyricsBackgroundSettings.CoverOverlayBlurAmount, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageBackgroundAcrylicEffectAmount" IsEnabled="{x:Bind LyricsBackgroundSettings.IsCoverOverlayEnabled, Mode=OneWay}">
<uc:ExtendedSlider
Default="0"
Frequency="1"
Maximum="10"
Minimum="0"
Value="{x:Bind LyricsBackgroundSettings.CoverAcrylicEffectAmount, Mode=TwoWay}" />
</controls:SettingsCard>
</controls:SettingsExpander.Items>
</controls:SettingsExpander>
<controls:SettingsExpander
x:Uid="SettingsPageFluidLayer"
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
Glyph=&#xEDA8;}"
IsExpanded="{x:Bind LyricsBackgroundSettings.IsFluidOverlayEnabled, Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind LyricsBackgroundSettings.IsFluidOverlayEnabled, Mode=TwoWay}" />
<controls:SettingsExpander.Items>
<controls:SettingsCard x:Uid="SettingsPageOpacity" IsEnabled="{x:Bind LyricsBackgroundSettings.IsFluidOverlayEnabled, Mode=OneWay}">
<uc:ExtendedSlider
Default="100"
Frequency="1"
Maximum="100"
Minimum="0"
Unit="%"
Value="{x:Bind LyricsBackgroundSettings.FluidOverlayOpacity, Mode=TwoWay}" />
</controls:SettingsCard>
</controls:SettingsExpander.Items>
</controls:SettingsExpander>
<controls:SettingsExpander
x:Uid="SettingsPageSpectrumLayer"
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
Glyph=&#xF61F;}"
IsExpanded="{x:Bind LyricsBackgroundSettings.IsSpectrumOverlayEnabled, Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind LyricsBackgroundSettings.IsSpectrumOverlayEnabled, Mode=TwoWay}" />
</controls:SettingsExpander>
<controls:SettingsCard x:Uid="SettingsPageBackgroundAcrylicEffectAmount" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xE80A;}">
<uc:ExtendedSlider
Default="0"
Frequency="1"
Maximum="10"
Minimum="0"
Value="{x:Bind ViewModel.AppSettings.LyricsBackgroundSettings.CoverAcrylicEffectAmount, Mode=TwoWay}" />
</controls:SettingsCard>
</StackPanel>
</Grid>
</ScrollViewer>

View File

@@ -1,3 +1,4 @@
using BetterLyrics.WinUI3.Models.Settings;
using BetterLyrics.WinUI3.ViewModels;
using CommunityToolkit.Mvvm.DependencyInjection;
using Microsoft.UI.Xaml;
@@ -22,12 +23,18 @@ namespace BetterLyrics.WinUI3.Controls
{
public sealed partial class LyricsBackgroundSettingsControl : UserControl
{
public LyricsBackgroundSettingsControlViewModel ViewModel => (LyricsBackgroundSettingsControlViewModel)DataContext;
public static readonly DependencyProperty LyricsBackgroundSettingsProperty =
DependencyProperty.Register(nameof(LyricsBackgroundSettings), typeof(LyricsBackgroundSettings), typeof(LyricsBackgroundSettingsControl), new PropertyMetadata(default));
public LyricsBackgroundSettings LyricsBackgroundSettings
{
get => (LyricsBackgroundSettings)GetValue(LyricsBackgroundSettingsProperty);
set => SetValue(LyricsBackgroundSettingsProperty, value);
}
public LyricsBackgroundSettingsControl()
{
InitializeComponent();
DataContext = Ioc.Default.GetRequiredService<LyricsBackgroundSettingsControlViewModel>();
}
}
}

View File

@@ -0,0 +1,388 @@
<?xml version="1.0" encoding="utf-8" ?>
<UserControl
x:Class="BetterLyrics.WinUI3.Controls.LyricsWindowSettingsControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:CommunityToolkit.WinUI.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:uc="using:BetterLyrics.WinUI3.Controls"
xmlns:ui="using:CommunityToolkit.WinUI"
mc:Ignorable="d">
<Grid ColumnSpacing="6">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid Grid.Column="0">
<ScrollViewer Style="{StaticResource SettingsScrollViewerStyle}">
<Grid Style="{StaticResource SettingsGridStyle}">
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
<TextBlock
x:Uid="SettingsPageRecordedWindowStatus"
RelativePanel.AlignLeftWithPanel="True"
Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
<Button x:Uid="SettingsPageCreateFromCurrent" Command="{x:Bind ViewModel.CopyLyricsWindowStatusCommand}" />
<Button
x:Uid="SettingsPageCreateFromTemplates"
VerticalAlignment="Center"
RelativePanel.AlignRightWithPanel="True">
<Button.Flyout>
<MenuFlyout>
<MenuFlyoutItem x:Uid="SettingsPageStandardMode" Command="{x:Bind ViewModel.CreateStandardLyricsWindowStatusCommand}" />
<MenuFlyoutItem x:Uid="SettingsPageDesktopMode" Command="{x:Bind ViewModel.CreateTransparentLyricsWindowStatusCommand}" />
<MenuFlyoutItem x:Uid="SettingsPageDockedMode" Command="{x:Bind ViewModel.CreateDockedLyricsWindowStatusCommand}" />
<MenuFlyoutItem x:Uid="SettingsPageFullscreenMode" Command="{x:Bind ViewModel.CreateFullLyricsWindowStatusCommand}" />
<MenuFlyoutItem x:Uid="SettingsPageNarrowMode" Command="{x:Bind ViewModel.CreateNarrowLyricsWindowStatusCommand}" />
</MenuFlyout>
</Button.Flyout>
</Button>
<StackPanel
Padding="24,0"
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
CornerRadius="4"
Spacing="16"
Visibility="{Binding ElementName=LyricsWindowManagerExpander, Path=IsExpanded, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}">
<ListView
x:Name="WindowStatusListView"
Padding="0,12"
CornerRadius="4"
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>
<StackPanel
Padding="0,10"
RightTapped="StackPanel_RightTapped"
Spacing="6">
<StackPanel.ContextFlyout>
<MenuBarItemFlyout>
<MenuFlyoutItem
x:Uid="LyricsWindowSettingsControlSetDefault"
Click="SetDefaultMenuFlyoutItem_Click"
IsEnabled="{Binding IsDefault, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}" />
<MenuFlyoutItem
x:Uid="SettingsPageDelete"
Click="DeleteMenuFlyoutItem_Click"
IsEnabled="{Binding IsDefault, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}" />
</MenuBarItemFlyout>
</StackPanel.ContextFlyout>
<uc:DemoWindowGrid LyricsWindowStatus="{Binding}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
</StackPanel>
</Grid>
</ScrollViewer>
</Grid>
<Grid Grid.Column="1">
<controls:SwitchPresenter Margin="0,100,0,0" Value="{x:Bind ViewModel.ListViewSelectedItemTag, Mode=OneWay}">
<controls:SwitchPresenter.ContentTransitions>
<TransitionCollection>
<PopupThemeTransition />
</TransitionCollection>
</controls:SwitchPresenter.ContentTransitions>
<!-- General -->
<controls:Case Value="General">
<ScrollViewer Style="{StaticResource SettingsScrollViewerStyle}">
<Grid Style="{StaticResource SettingsGridStyle}">
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
<controls:SettingsCard x:Uid="SettingsPageConfigName" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xE8AC;}">
<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=&#xE8FB;}" Style="{StaticResource GhostButtonStyle}" />
</StackPanel>
</controls:SettingsCard>
<controls:SettingsExpander
x:Uid="SettingsPageDisplayTypeSwitcher"
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
Glyph=&#xF246;}"
IsExpanded="True">
<ComboBox SelectedIndex="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.LyricsDisplayType, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
<ComboBoxItem x:Uid="MainPageAlbumArtOnly" />
<ComboBoxItem x:Uid="MainPageLyriscOnly" />
<ComboBoxItem x:Uid="MainPageSplitView" />
</ComboBox>
<controls:SettingsExpander.Items>
<controls:SettingsCard x:Uid="SettingsPageLayoutOrientation">
<ComboBox SelectedIndex="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.LyricsLayoutOrientation, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
<ComboBoxItem x:Uid="SettingsPageLayoutOrientationHorizontal" />
<ComboBoxItem x:Uid="SettingsPageLayoutOrientationVertical" />
</ComboBox>
</controls:SettingsCard>
</controls:SettingsExpander.Items>
</controls:SettingsExpander>
<controls:SettingsExpander
x:Uid="SettingsPageAdaptEnvColor"
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
Glyph=&#xE88F;}"
IsExpanded="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.IsAdaptToEnvironment, Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.IsAdaptToEnvironment, Mode=TwoWay}" />
<controls:SettingsExpander.Items>
<controls:SettingsCard x:Uid="SettingsPageEnvColorSample" Header="Environment color sample mode">
<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>
</controls:SettingsCard>
</controls:SettingsExpander.Items>
</controls:SettingsExpander>
<controls:SettingsCard x:Uid="SettingsPageDockMonitor" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xE7F4;}">
<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=&#xE72C;}"
Style="{StaticResource GhostButtonStyle}" />
</StackPanel>
</controls:SettingsCard>
<controls:SettingsExpander
x:Uid="SettingsPageWindowBounds"
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
Glyph=&#xF16B;}"
IsExpanded="True">
<controls:SettingsExpander.Items>
<controls:SettingsCard Header="X">
<uc:ExtendedSlider
Frequency="1"
Maximum="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.MonitorBounds.Right, Mode=OneWay}"
Minimum="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.MonitorBounds.Left, Mode=OneWay}"
ResetButtonVisibility="Collapsed"
Unit="px"
Value="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.WindowX, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard Header="Y">
<uc:ExtendedSlider
Frequency="1"
Maximum="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.MonitorBounds.Bottom, Mode=OneWay}"
Minimum="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.MonitorBounds.Top, Mode=OneWay}"
ResetButtonVisibility="Collapsed"
Unit="px"
Value="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.WindowY, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageWidth">
<uc:ExtendedSlider
Frequency="1"
Maximum="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.MonitorBounds.Width, Mode=OneWay}"
Minimum="64"
ResetButtonVisibility="Collapsed"
Unit="px"
Value="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.WindowWidth, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageHeight">
<uc:ExtendedSlider
Frequency="1"
Maximum="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.MonitorBounds.Height, Mode=OneWay}"
Minimum="64"
ResetButtonVisibility="Collapsed"
Unit="px"
Value="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.WindowHeight, Mode=TwoWay}" />
</controls:SettingsCard>
</controls:SettingsExpander.Items>
</controls:SettingsExpander>
<controls:SettingsExpander
x:Uid="SettingsPageAOT"
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
Glyph=&#xE718;}"
IsExpanded="True">
<ToggleSwitch IsOn="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.IsAlwaysOnTop, Mode=TwoWay}" />
<controls:SettingsExpander.Items>
<controls:SettingsCard x:Uid="SettingsPageForceAlwaysOnTop" IsEnabled="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.IsAlwaysOnTop, Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.IsAlwaysOnTopPolling, Mode=TwoWay}" />
</controls:SettingsCard>
</controls:SettingsExpander.Items>
</controls:SettingsExpander>
<controls:SettingsExpander
x:Uid="SettingsPageWorkArea"
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
Glyph=&#xE78B;}"
IsExpanded="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.IsWorkArea, Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.IsWorkArea, Mode=TwoWay}" />
<controls:SettingsExpander.Items>
<controls:SettingsCard x:Uid="SettingsPageWorkAreaHeight" IsEnabled="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.IsWorkArea, Mode=OneWay}">
<uc:ExtendedSlider
Default="64"
Frequency="1"
Maximum="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.MonitorBounds.Height, Mode=OneWay}"
Minimum="64"
Unit="px"
Value="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.DockHeight, Mode=TwoWay}" />
</controls:SettingsCard>
<controls: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>
</controls:SettingsCard>
</controls:SettingsExpander.Items>
</controls:SettingsExpander>
<controls:SettingsCard x:Uid="SettingsPageHideWindow" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xED1A;}">
<ToggleSwitch IsOn="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.AutoShowOrHideWindow, Mode=TwoWay}" />
</controls:SettingsCard>
</StackPanel>
</Grid>
</ScrollViewer>
</controls:Case>
<!-- Album art area style -->
<controls:Case Value="AlbumArtStyle">
<uc:AlbumArtLayoutSettingsControl AlbumArtLayoutSettings="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.AlbumArtLayoutSettings, Mode=OneWay}" />
</controls:Case>
<!-- Lyrics style and effect -->
<controls:Case Value="Lyrics">
<uc:LyricsSettingsControl LyricsEffectSettings="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.LyricsEffectSettings, Mode=OneWay}" LyricsStyleSettings="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.LyricsStyleSettings, 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}">
<controls:SettingsCard x:Uid="SettingsPageShowInSwitchers" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xE7C4;}">
<ToggleSwitch IsOn="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.IsShownInSwitchers, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageClickThrough" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xE7C9;}">
<ToggleSwitch IsOn="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.IsClickThrough, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageBorderless" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xE8B2;}">
<ToggleSwitch IsOn="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.IsBorderless, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageDragArea" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=&#xEB41;}">
<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>
</controls:SettingsCard>
</StackPanel>
</Grid>
</ScrollViewer>
</controls:Case>
</controls:SwitchPresenter>
<Grid Padding="36,0" Style="{StaticResource SettingsGridStyle}">
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
<TextBlock x:Uid="LyricsWindowSettingsControlCurrentLyricsWindowConfig" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
<ListView
ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.HorizontalScrollMode="Enabled"
ScrollViewer.VerticalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollMode="Disabled"
SelectionChanged="ListView_SelectionChanged">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsStackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.Items>
<ListViewItem Tag="General">
<StackPanel Orientation="Horizontal" Spacing="6">
<FontIcon
FontFamily="{StaticResource IconFontFamily}"
FontSize="16"
Glyph="&#xECAA;" />
<TextBlock x:Uid="AppSettingsControlGeneral" VerticalAlignment="Center" />
</StackPanel>
</ListViewItem>
<ListViewItem Tag="AlbumArtStyle">
<StackPanel Orientation="Horizontal" Spacing="6">
<FontIcon
FontFamily="{StaticResource IconFontFamily}"
FontSize="16"
Glyph="&#xE93C;" />
<TextBlock x:Uid="SettingsPageAlbumStyle" VerticalAlignment="Center" />
</StackPanel>
</ListViewItem>
<ListViewItem Tag="Lyrics">
<StackPanel Orientation="Horizontal" Spacing="6">
<FontIcon
FontFamily="{StaticResource IconFontFamily}"
FontSize="16"
Glyph="&#xEDC6;" />
<TextBlock x:Uid="SettingsPageLyrics" VerticalAlignment="Center" />
</StackPanel>
</ListViewItem>
<ListViewItem Tag="LyricsBackground">
<StackPanel Orientation="Horizontal" Spacing="6">
<FontIcon
FontFamily="{StaticResource IconFontFamily}"
FontSize="16"
Glyph="&#xF5EF;" />
<TextBlock x:Uid="SettingsPageBackgroundOverlay" VerticalAlignment="Center" />
</StackPanel>
</ListViewItem>
<ListViewItem Tag="Advanced">
<StackPanel Orientation="Horizontal" Spacing="6">
<FontIcon
FontFamily="{StaticResource IconFontFamily}"
FontSize="16"
Glyph="&#xEC7A;" />
<TextBlock x:Uid="SettingsPageAdvanced" VerticalAlignment="Center" />
</StackPanel>
</ListViewItem>
</ListView.Items>
</ListView>
</StackPanel>
</Grid>
</Grid>
</Grid>
</UserControl>

View File

@@ -0,0 +1,84 @@
using BetterLyrics.WinUI3.Helper;
using BetterLyrics.WinUI3.Models;
using BetterLyrics.WinUI3.Models.Settings;
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.Controls.Primitives;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Navigation;
using NTextCat.Commons;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using static Vanara.PInvoke.ComCtl32;
// 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 LyricsWindowSettingsControl : UserControl
{
public LyricsWindowSettingsControlViewModel ViewModel => (LyricsWindowSettingsControlViewModel)DataContext;
private ISettingsService _settingsService;
public LyricsWindowSettingsControl()
{
InitializeComponent();
DataContext = Ioc.Default.GetRequiredService<LyricsWindowSettingsControlViewModel>();
_settingsService = Ioc.Default.GetRequiredService<ISettingsService>();
}
private void DeleteMenuFlyoutItem_Click(object sender, RoutedEventArgs e)
{
if (sender is MenuFlyoutItem menuFlyoutItem)
{
var data = menuFlyoutItem.DataContext as LyricsWindowStatus;
if (data != null)
{
ViewModel.AppSettings.WindowBoundsRecords.Remove(data);
}
}
}
private void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ViewModel?.ListViewSelectedItemTag = ((sender as ListView)!.SelectedItem as ListViewItem)!.Tag;
}
private void SetDefaultMenuFlyoutItem_Click(object sender, RoutedEventArgs e)
{
if (sender is MenuFlyoutItem menuFlyoutItem)
{
var data = menuFlyoutItem.DataContext as LyricsWindowStatus;
if (data != null)
{
ViewModel.AppSettings.WindowBoundsRecords.ForEach(x => x.IsDefault = false);
data.IsDefault = true;
}
}
}
private void StackPanel_RightTapped(object sender, RightTappedRoutedEventArgs e)
{
if (sender is StackPanel stackPanel)
{
if (stackPanel.DataContext is MenuBarItemFlyout menuBarItemFlyout)
{
menuBarItemFlyout.ShowAt(stackPanel);
}
}
}
}
}

View File

@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8" ?>
<UserControl
x:Class="BetterLyrics.WinUI3.Controls.LyricsWindowSwitchControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:CommunityToolkit.WinUI.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:uc="using:BetterLyrics.WinUI3.Controls"
xmlns:ui="using:CommunityToolkit.WinUI"
mc:Ignorable="d">
<Grid
HorizontalAlignment="Center"
VerticalAlignment="Center"
Background="{ThemeResource AcrylicInAppFillColorDefaultBrush}"
CornerRadius="12">
<Button
Margin="12"
HorizontalAlignment="Right"
VerticalAlignment="Top"
Click="Button_Click"
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
Glyph=&#xE653;}"
Style="{StaticResource GhostButtonStyle}" />
<ListView
Margin="48"
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>
</Grid>
</UserControl>

View File

@@ -1,4 +1,6 @@
using BetterLyrics.WinUI3.Helper;
using BetterLyrics.WinUI3.ViewModels;
using BetterLyrics.WinUI3.Views;
using CommunityToolkit.Mvvm.DependencyInjection;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
@@ -20,13 +22,24 @@ using Windows.Foundation.Collections;
namespace BetterLyrics.WinUI3.Controls
{
public sealed partial class AllLyricsSettingsControl : UserControl
public sealed partial class LyricsWindowSwitchControl : UserControl
{
public AllLyricsSettingsControlViewModel ViewModel => (AllLyricsSettingsControlViewModel)DataContext;
public AllLyricsSettingsControl()
public LyricsWindowSwitchControlViewModel ViewModel => (LyricsWindowSwitchControlViewModel)DataContext;
public LyricsWindowSwitchControl()
{
InitializeComponent();
DataContext = Ioc.Default.GetRequiredService<AllLyricsSettingsControlViewModel>();
DataContext = Ioc.Default.GetRequiredService<LyricsWindowSwitchControlViewModel>();
}
private void Grid_Tapped(object sender, TappedRoutedEventArgs e)
{
WindowHelper.HideWindow<LyricsWindowSwitchWindow>();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
WindowHelper.HideWindow<LyricsWindowSwitchWindow>();
}
}
}

View File

@@ -122,8 +122,15 @@
</StackPanel>
</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="Auto"
ScrollViewer.HorizontalScrollMode="Enabled"
@@ -138,6 +145,10 @@
<ListView.ItemTemplate>
<DataTemplate x:DataType="models:MediaSourceProviderInfo">
<StackPanel Orientation="Horizontal" Spacing="6">
<FontIcon
FontFamily="Segoe UI Symbol"
FontSize="12"
Glyph="&#x283F;" />
<ImageIcon Height="16" Source="{Binding Provider, Converter={StaticResource MediaSourceProviderToLogoUriConverter}, Mode=OneWay}" />
<TextBlock
MaxWidth="200"
@@ -162,6 +173,7 @@
</interactivity:DataTriggerBehavior>
</interactivity:Interaction.Behaviors>
</Grid>
<StackPanel
Grid.Column="0"
HorizontalAlignment="Center"
@@ -191,37 +203,16 @@
<ScrollViewer Style="{StaticResource SettingsScrollViewerStyle}">
<Grid Style="{StaticResource SettingsGridStyle}">
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
<!-- Last.fm -->
<TextBlock x:Uid="SettingsPageLastFM" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
<controls:SettingsExpander
x:Uid="SettingsPageLastFMManager"
HeaderIcon="{ui:BitmapIcon Source=ms-appx:///Assets/LastFM.png}"
IsExpanded="{x:Bind ViewModel.IsLastFMAuthenticated, Mode=OneWay}">
<StackPanel Orientation="Horizontal" Spacing="6">
<Button
x:Uid="SettingsPageLastFMAuth"
Command="{x:Bind ViewModel.LastFMAuthCommand}"
IsEnabled="{x:Bind ViewModel.IsLastFMAuthenticated, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}" />
<Button
x:Uid="SettingsPageLastFMUnAuth"
Command="{x:Bind ViewModel.LastFMUnAuthCommand}"
IsEnabled="{x:Bind ViewModel.IsLastFMAuthenticated, Mode=OneWay}" />
</StackPanel>
<controls:SettingsExpander.Items>
<controls:SettingsCard x:Uid="SettingsPageLastFMUsername" IsEnabled="{x:Bind ViewModel.IsLastFMAuthenticated, Mode=OneWay}">
<HyperlinkButton Content="{x:Bind ViewModel.LastFMUser.Name, Mode=OneWay}" NavigateUri="{x:Bind ViewModel.LastFMUser.Url, Mode=OneWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageLastFMPlaycount" IsEnabled="{x:Bind ViewModel.IsLastFMAuthenticated, Mode=OneWay}">
<TextBlock Text="{x:Bind ViewModel.LastFMUser.Playcount, Mode=OneWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageLastFMRegistered" IsEnabled="{x:Bind ViewModel.IsLastFMAuthenticated, Mode=OneWay}">
<TextBlock Text="{x:Bind ViewModel.LastFMUser.Registered.ToLongDateString(), Mode=OneWay}" />
</controls:SettingsCard>
<controls:SettingsCard IsEnabled="{x:Bind ViewModel.IsLastFMAuthenticated, Mode=OneWay}">
<Button x:Uid="SettingsPageLastFMRefresh" Command="{x:Bind ViewModel.LastFMRefreshCommand}" />
</controls:SettingsCard>
</controls:SettingsExpander.Items>
</controls:SettingsExpander>
<!-- Provider info -->
<TextBlock x:Uid="SettingsPageRealtimeStatus" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
<controls:SettingsCard x:Uid="LyricsPageLyricsProviderPrefix">
<TextBlock Foreground="{ThemeResource TextFillColorSecondaryBrush}" Text="{x:Bind ViewModel.LyricsSearchProvider, Mode=OneWay, Converter={StaticResource LyricsSearchProviderToDisplayNameConverter}}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="LyricsPageTranslationProviderPrefix">
<TextBlock Foreground="{ThemeResource TextFillColorSecondaryBrush}" Text="{x:Bind ViewModel.TranslationSearchProvider, Mode=OneWay, Converter={StaticResource TranslationSearchProviderToDisplayNameConverter}}" />
</controls:SettingsCard>
<!-- Lyrics translation -->
<TextBlock x:Uid="SettingsPageTranslation" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
<controls:SettingsExpander
@@ -232,37 +223,56 @@
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.TranslationSettings.IsTranslationEnabled, Mode=TwoWay}" />
<controls:SettingsExpander.Items>
<controls:SettingsCard x:Uid="SettingsPageTargetLanguage" IsEnabled="{x:Bind ViewModel.AppSettings.TranslationSettings.IsTranslationEnabled, Mode=OneWay}">
<ComboBox SelectedIndex="{x:Bind ViewModel.AppSettings.TranslationSettings.SelectedTargetLanguageIndex, Mode=TwoWay}">
<ComboBox SelectedIndex="{x:Bind ViewModel.SelectedTargetLanguageIndex, Mode=TwoWay}">
<ComboBoxItem Content="العربية" Tag="ar" />
<ComboBoxItem Content="Azərbaycan dili" Tag="az" />
<ComboBoxItem Content="中文" Tag="zh" />
<ComboBoxItem Content="Български" Tag="bg" />
<ComboBoxItem Content="বাংলা" Tag="bn" />
<ComboBoxItem Content="Català" Tag="ca" />
<ComboBoxItem Content="Čeština" Tag="cs" />
<ComboBoxItem Content="Dansk" Tag="da" />
<ComboBoxItem Content="Nederlands" Tag="nl" />
<ComboBoxItem Content="English" Tag="en" />
<ComboBoxItem Content="Esperanto" Tag="eo" />
<ComboBoxItem Content="Suomi" Tag="fi" />
<ComboBoxItem Content="Français" Tag="fr" />
<ComboBoxItem Content="Deutsch" Tag="de" />
<ComboBoxItem Content="Ελληνικά" Tag="el" />
<ComboBoxItem Content="English" Tag="en" />
<ComboBoxItem Content="Esperanto" Tag="eo" />
<ComboBoxItem Content="Español" Tag="es" />
<ComboBoxItem Content="Eesti" Tag="et" />
<ComboBoxItem Content="Euskara" Tag="eu" />
<ComboBoxItem Content="فارسی" Tag="fa" />
<ComboBoxItem Content="Suomi" Tag="fi" />
<ComboBoxItem Content="Français" Tag="fr" />
<ComboBoxItem Content="Gaeilge" Tag="ga" />
<ComboBoxItem Content="Galego" Tag="gl" />
<ComboBoxItem Content="עברית" Tag="he" />
<ComboBoxItem Content="हिन्दी" Tag="hi" />
<ComboBoxItem Content="Magyar" Tag="hu" />
<ComboBoxItem Content="Bahasa Indonesia" Tag="id" />
<ComboBoxItem Content="Gaeilge" Tag="ga" />
<ComboBoxItem Content="Italiano" Tag="it" />
<ComboBoxItem Content="日本語" Tag="ja" />
<ComboBoxItem Content="한국어" Tag="ko" />
<ComboBoxItem Content="فارسی" Tag="fa" />
<ComboBoxItem Content="Кыргызча" Tag="ky" />
<ComboBoxItem Content="Lietuvių" Tag="lt" />
<ComboBoxItem Content="Latviešu" Tag="lv" />
<ComboBoxItem Content="Bahasa Melayu" Tag="ms" />
<ComboBoxItem Content="Norsk bokmål" Tag="nb" />
<ComboBoxItem Content="Nederlands" Tag="nl" />
<ComboBoxItem Content="Português (Brasil)" Tag="pt-BR" />
<ComboBoxItem Content="Polski" Tag="pl" />
<ComboBoxItem Content="Português" Tag="pt" />
<ComboBoxItem Content="Română" Tag="ro" />
<ComboBoxItem Content="Русский" Tag="ru" />
<ComboBoxItem Content="Slovenčina" Tag="sk" />
<ComboBoxItem Content="Español" Tag="es" />
<ComboBoxItem Content="Slovenščina" Tag="sl" />
<ComboBoxItem Content="Shqip" Tag="sq" />
<ComboBoxItem Content="Српски" Tag="sr" />
<ComboBoxItem Content="Svenska" Tag="sv" />
<ComboBoxItem Content="ไทย" Tag="th" />
<ComboBoxItem Content="Filipino" Tag="tl" />
<ComboBoxItem Content="Türkçe" Tag="tr" />
<ComboBoxItem Content="Українська" Tag="uk" />
<ComboBoxItem Content="اردو" Tag="ur" />
<ComboBoxItem Content="Tiếng Việt" Tag="vi" />
<ComboBoxItem Content="中文" Tag="zh" />
</ComboBox>
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageTranslationConfig" IsEnabled="{x:Bind ViewModel.AppSettings.TranslationSettings.IsTranslationEnabled, Mode=OneWay}">
@@ -294,6 +304,7 @@
</controls:SettingsCard>
</controls:SettingsExpander.Items>
</controls:SettingsExpander>
<!-- Lyrics phonetic -->
<controls:SettingsExpander
x:Uid="SettingsPageChinese"
@@ -312,17 +323,44 @@
<controls:SettingsCard x:Uid="SettingsPageJapanese" IsEnabled="{x:Bind ViewModel.AppSettings.TranslationSettings.IsTranslationEnabled, Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.TranslationSettings.IsJapaneseRomanizationEnabled, Mode=TwoWay}" />
</controls:SettingsCard>
<!-- 中文简体繁体偏好 -->
<controls:SettingsCard x:Uid="SettingsPageChinesePreference">
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.TranslationSettings.IsTraditionalChineseEnabled, Mode=TwoWay}" />
</controls:SettingsCard>
<!-- Provider info -->
<controls:SettingsCard x:Uid="LyricsPageLyricsProviderPrefix">
<TextBlock Foreground="{ThemeResource TextFillColorSecondaryBrush}" Text="{x:Bind ViewModel.LyricsSearchProvider, Mode=OneWay, Converter={StaticResource LyricsSearchProviderToDisplayNameConverter}}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="LyricsPageTranslationProviderPrefix">
<TextBlock Foreground="{ThemeResource TextFillColorSecondaryBrush}" Text="{x:Bind ViewModel.TranslationSearchProvider, Mode=OneWay, Converter={StaticResource TranslationSearchProviderToDisplayNameConverter}}" />
</controls:SettingsCard>
<!-- Last.fm -->
<TextBlock x:Uid="SettingsPageLastFM" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
<controls:SettingsExpander
x:Uid="SettingsPageLastFMManager"
HeaderIcon="{ui:BitmapIcon Source=ms-appx:///Assets/LastFM.png}"
IsExpanded="{x:Bind ViewModel.IsLastFMAuthenticated, Mode=OneWay}">
<StackPanel Orientation="Horizontal" Spacing="6">
<Button
x:Uid="SettingsPageLastFMAuth"
Command="{x:Bind ViewModel.LastFMAuthCommand}"
IsEnabled="{x:Bind ViewModel.IsLastFMAuthenticated, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}" />
<Button
x:Uid="SettingsPageLastFMUnAuth"
Command="{x:Bind ViewModel.LastFMUnAuthCommand}"
IsEnabled="{x:Bind ViewModel.IsLastFMAuthenticated, Mode=OneWay}" />
</StackPanel>
<controls:SettingsExpander.Items>
<controls:SettingsCard x:Uid="SettingsPageLastFMUsername" IsEnabled="{x:Bind ViewModel.IsLastFMAuthenticated, Mode=OneWay}">
<HyperlinkButton Content="{x:Bind ViewModel.LastFMUser.Name, Mode=OneWay}" NavigateUri="{x:Bind ViewModel.LastFMUser.Url, Mode=OneWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageLastFMPlaycount" IsEnabled="{x:Bind ViewModel.IsLastFMAuthenticated, Mode=OneWay}">
<TextBlock Text="{x:Bind ViewModel.LastFMUser.Playcount, Mode=OneWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="SettingsPageLastFMRegistered" IsEnabled="{x:Bind ViewModel.IsLastFMAuthenticated, Mode=OneWay}">
<TextBlock Text="{x:Bind ViewModel.LastFMUser.Registered.ToLongDateString(), Mode=OneWay}" />
</controls:SettingsCard>
<controls:SettingsCard IsEnabled="{x:Bind ViewModel.IsLastFMAuthenticated, Mode=OneWay}">
<Button x:Uid="SettingsPageLastFMRefresh" Command="{x:Bind ViewModel.LastFMRefreshCommand}" />
</controls:SettingsCard>
</controls:SettingsExpander.Items>
</controls:SettingsExpander>
<!-- LX music server -->
<TextBlock x:Uid="SettingsPageLXMusicServer" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
<controls:SettingsCard>
@@ -337,6 +375,28 @@
IsEnabled="{x:Bind ViewModel.IsLXMusicServerTesting, Converter={StaticResource BoolNegationConverter}, Mode=OneWay}" />
</StackPanel>
</controls:SettingsCard>
<!-- Apple Music token -->
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" Text="media-user-token (for Apple Muisc)" />
<controls:SettingsCard
Background="{ThemeResource SystemFillColorCautionBackgroundBrush}"
Foreground="{ThemeResource SystemFillColorCautionBrush}"
Header="Use at your own risk">
<StackPanel Orientation="Horizontal" Spacing="6">
<TextBox
MaxWidth="250"
PlaceholderText="media-user-token"
Text="{x:Bind ViewModel.AppleMusicMediaUserToken, Mode=TwoWay}"
TextWrapping="Wrap" />
<Button
Command="{x:Bind ViewModel.SaveAppleMusicMediaUserTokenCommand}"
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
FontSize=12,
Glyph=&#xE8FB;}"
Style="{StaticResource GhostButtonStyle}" />
</StackPanel>
</controls:SettingsCard>
</StackPanel>
</Grid>
</ScrollViewer>

View File

@@ -41,5 +41,11 @@ namespace BetterLyrics.WinUI3.Controls
// <20><> LyricsSearchProvidersInfo <20><><EFBFBD><EFBFBD> CollectionChanged <20>¼<EFBFBD>
ViewModel.SelectedMediaSourceProvider?.LyricsSearchProvidersInfo?.Refresh();
}
private void MediaSourceProvidersListView_DragItemsCompleted(ListViewBase sender, DragItemsCompletedEventArgs args)
{
// <20><> MediaSourceProvidersInfo <20><><EFBFBD><EFBFBD> CollectionChanged <20>¼<EFBFBD>
ViewModel.AppSettings.MediaSourceProvidersInfo?.Refresh();
}
}
}

View File

@@ -50,12 +50,6 @@
Command="{x:Bind ViewModel.ResetWindowPositionCommand}"
Icon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
Glyph=&#xE923;}" />
<MenuFlyoutItem
x:Uid="SystemTrayUnlock"
Command="{x:Bind ViewModel.UnlockWindowCommand}"
Icon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
Glyph=&#xE785;}"
Visibility="{x:Bind ViewModel.IsLyricsWindowLocked, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}" />
<MenuFlyoutSeparator />
<MenuFlyoutItem
x:Uid="SystemTrayRestart"

View File

@@ -19,6 +19,7 @@ namespace BetterLyrics.WinUI3.Converter
LyricsSearchProvider.Netease => "网易云音乐",
LyricsSearchProvider.Kugou => "酷狗音乐",
LyricsSearchProvider.AmllTtmlDb => "amll-ttml-db",
LyricsSearchProvider.AppleMusic => "Apple Music",
LyricsSearchProvider.LocalLrcFile => App.ResourceLoader!.GetString("LyricsSearchProviderLocalLrcFile"),
LyricsSearchProvider.LocalMusicFile => App.ResourceLoader!.GetString("LyricsSearchProviderLocalMusicFile"),
LyricsSearchProvider.LocalEslrcFile => App.ResourceLoader!.GetString("LyricsSearchProviderEslrcFile"),

View File

@@ -33,6 +33,10 @@ namespace BetterLyrics.WinUI3.Converter
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,
};
}

View File

@@ -2,10 +2,6 @@
using BetterLyrics.WinUI3.Helper;
using Microsoft.UI.Xaml.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BetterLyrics.WinUI3.Converter
{
@@ -34,6 +30,10 @@ namespace BetterLyrics.WinUI3.Converter
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,
};
}

View File

@@ -19,6 +19,7 @@ namespace BetterLyrics.WinUI3.Converter
TranslationSearchProvider.Netease => "网易云音乐",
TranslationSearchProvider.Kugou => "酷狗音乐",
TranslationSearchProvider.AmllTtmlDb => "amll-ttml-db",
TranslationSearchProvider.AppleMusic => "Apple Music",
TranslationSearchProvider.LocalLrcFile => App.ResourceLoader!.GetString("LyricsSearchProviderLocalLrcFile"),
TranslationSearchProvider.LocalMusicFile => App.ResourceLoader!.GetString("LyricsSearchProviderLocalMusicFile"),
TranslationSearchProvider.LocalEslrcFile => App.ResourceLoader!.GetString("LyricsSearchProviderEslrcFile"),

View File

@@ -15,6 +15,7 @@ namespace BetterLyrics.WinUI3.Enums
LocalLrcFile,
LocalEslrcFile,
LocalTtmlFile,
AppleMusic,
}
public static class LyricsSearchProviderExtensions
@@ -28,6 +29,7 @@ namespace BetterLyrics.WinUI3.Enums
LyricsSearchProvider.Netease => PathHelper.NeteaseLyricsCacheDirectory,
LyricsSearchProvider.Kugou => PathHelper.KugouLyricsCacheDirectory,
LyricsSearchProvider.AmllTtmlDb => PathHelper.AmllTtmlDbLyricsCacheDirectory,
LyricsSearchProvider.AppleMusic => PathHelper.AppleMusicCacheDirectory,
_ => throw new System.ArgumentOutOfRangeException(nameof(provider)),
};
}
@@ -41,6 +43,7 @@ namespace BetterLyrics.WinUI3.Enums
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,
@@ -71,6 +74,7 @@ namespace BetterLyrics.WinUI3.Enums
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,

View File

@@ -1,12 +0,0 @@
// 2025/6/23 by Zhe Fang
namespace BetterLyrics.WinUI3.Enums
{
public enum LyricsWindowMode
{
StandardMode,
DockMode,
DesktopMode,
PictureInPictureMode,
}
}

View File

@@ -9,10 +9,9 @@ namespace BetterLyrics.WinUI3.Enums
public enum ShortcutID
{
LyricsWindowShowOrHide,
DesktopLockOrUnlock,
DesktopToggle,
DockToggle,
PictureInPictureToggle,
Borderless,
ClickThrough,
LyricsWindowSwitch,
PlayOrPauseSong,
NextSong,
PreviousSong,

View File

@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BetterLyrics.WinUI3.Enums
{
public enum TitleBarArea
{
None,
Top,
Whole,
}
}

View File

@@ -13,6 +13,7 @@ namespace BetterLyrics.WinUI3.Enums
Netease,
LrcLib,
AmllTtmlDb,
AppleMusic,
LocalMusicFile,
LocalLrcFile,
LocalEslrcFile,

View File

@@ -8,11 +8,11 @@ using Windows.UI;
namespace BetterLyrics.WinUI3.Events
{
public class AlbumArtChangedEventArgs(byte[]? bytes, SoftwareBitmap? albumArtSwBitmap, Color? albumArtLightAccentColor, Color? albumArtDarkAccentColor) : EventArgs
public class AlbumArtChangedEventArgs(byte[]? bytes, SoftwareBitmap? albumArtSwBitmap, List<Color> albumArtLightAccentColors, List<Color> albumArtDarkAccentColors) : EventArgs
{
public byte[]? Bytes { get; set; } = bytes;
public SoftwareBitmap? AlbumArtSwBitmap { get; set; } = albumArtSwBitmap;
public Color? AlbumArtLightAccentColor { get; set; } = albumArtLightAccentColor;
public Color? AlbumArtDarkAccentColor { get; set; } = albumArtDarkAccentColor;
public List<Color> AlbumArtLightAccentColors { get; set; } = albumArtLightAccentColors;
public List<Color> AlbumArtDarkAccentColors { get; set; } = albumArtDarkAccentColors;
}
}

View File

@@ -0,0 +1,126 @@
using BetterLyrics.WinUI3.Constants;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace BetterLyrics.WinUI3.Helper
{
public class AppleMusic
{
private readonly HttpClient _client;
private string _accessToken = "";
private string _storefront = "";
private string _language = "";
public AppleMusic()
{
_client = new HttpClient();
_client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36");
_client.DefaultRequestHeaders.Add("Accept", "application/json");
_client.DefaultRequestHeaders.Add("Origin", "https://music.apple.com");
_client.DefaultRequestHeaders.Add("Referer", "https://music.apple.com/");
}
public async Task<bool> InitAsync()
{
await GetAccessTokenAsync();
await SetMediaUserTokenAsync();
return
!string.IsNullOrEmpty(_accessToken) &&
!string.IsNullOrEmpty(PasswordVaultHelper.Get(Constants.App.AppName, Constants.AppleMusic.MediaUserTokenKey));
}
private async Task GetAccessTokenAsync()
{
var resp = await _client.GetStringAsync("https://music.apple.com/us/browse");
var jsMatch = Regex.Match(resp, "(?<=index)(.*?)(?=\\.js\")");
if (!jsMatch.Success) throw new Exception("Failed to find index.js");
var jsUrl = $"https://music.apple.com/assets/index{jsMatch.Value}.js";
var jsResp = await _client.GetStringAsync(jsUrl);
var tokenMatch = Regex.Match(jsResp, "(?=eyJh)(.*?)(?=\")");
if (!tokenMatch.Success) throw new Exception("Failed to find access token");
_accessToken = tokenMatch.Value;
_client.DefaultRequestHeaders.Remove("Authorization");
_client.DefaultRequestHeaders.Add("Authorization", $"Bearer {_accessToken}");
}
private async Task SetMediaUserTokenAsync()
{
_client.DefaultRequestHeaders.Remove("media-user-token");
_client.DefaultRequestHeaders.Add("media-user-token",
PasswordVaultHelper.Get(Constants.App.AppName, Constants.AppleMusic.MediaUserTokenKey));
var resp = await _client.GetStringAsync("https://amp-api.music.apple.com/v1/me/storefront");
var json = JsonSerializer.Deserialize(resp, Serialization.SourceGenerationContext.Default.JsonElement);
_storefront = json.GetProperty("data")[0].GetProperty("id").ToString();
_language = json.GetProperty("data")[0].GetProperty("attributes").GetProperty("defaultLanguageTag").ToString();
_client.DefaultRequestHeaders.Remove("Accept-Language");
_client.DefaultRequestHeaders.Add("Accept-Language", $"{_language},en;q=0.9");
}
public async Task<string?> GetLyricsAsync(string title, string artist)
{
string id = await SearchSongInfoAsync(artist, title);
var apiUrl = $"https://amp-api.music.apple.com/v1/catalog/{_storefront}/songs/{id}";
var url = apiUrl + $"?include[songs]=lyrics,syllable-lyrics&l={_language}";
var resp = await _client.GetStringAsync(url);
var json = JsonSerializer.Deserialize(resp, Serialization.SourceGenerationContext.Default.JsonElement);
var data = json.GetProperty("data");
if (data.GetArrayLength() == 0) return string.Empty;
var song = data[0];
if (!song.TryGetProperty("relationships", out var relationships))
return string.Empty;
if (relationships.TryGetProperty("syllable-lyrics", out var syllableLyrics) &&
syllableLyrics.GetProperty("data").GetArrayLength() > 0)
{
var syllableLyric = syllableLyrics.GetProperty("data")[0];
if (syllableLyric.TryGetProperty("attributes", out var attributes) &&
attributes.TryGetProperty("ttml", out var ttml))
{
string? raw = ttml.GetString();
if (raw != null && raw.Contains("begin=") && raw.Contains("end="))
{
return raw;
}
}
}
//if (relationships.TryGetProperty("lyrics", out var lyrics) &&
// lyrics.GetProperty("data").GetArrayLength() > 0)
//{
// var lyric = lyrics.GetProperty("data")[0];
// if (lyric.TryGetProperty("attributes", out var attributes) &&
// attributes.TryGetProperty("ttml", out var ttml))
// {
// return ttml.GetString();
// }
//}
return null;
}
private async Task<string> SearchSongInfoAsync(string artist, string title)
{
var query = $"{artist} {title}";
var apiUrl = $"https://amp-api.music.apple.com/v1/catalog/{_storefront}/search";
var url = apiUrl + $"?term={WebUtility.UrlEncode(query)}&types=songs&limit=1&l={_language}";
var resp = await _client.GetStringAsync(url);
var json = JsonSerializer.Deserialize(resp, Serialization.SourceGenerationContext.Default.JsonElement);
var results = json.GetProperty("results");
if (results.TryGetProperty("songs", out var songs) && songs.GetProperty("data").GetArrayLength() > 0)
{
var song = songs.GetProperty("data")[0];
return song.GetProperty("id").ToString();
}
return string.Empty;
}
}
}

View File

@@ -7,6 +7,7 @@ using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Numerics;
using Vanara.PInvoke;
using Windows.UI;
@@ -111,6 +112,11 @@ namespace BetterLyrics.WinUI3.Helper
return CommunityToolkit.WinUI.Helpers.ColorHelper.FromHsl(h, s, brightness);
}
public static Vector3 ToVector3RGB(this Color color)
{
return new Vector3((float)color.R / 0xff, (float)color.G / 0xff, (float)color.B / 0xff);
}
public static System.Drawing.Color GetAccentColor(IntPtr myHwnd, string monitorDeviceName, WindowPixelSampleMode mode)
{
if (!User32.GetWindowRect(myHwnd, out RECT myRect)) return System.Drawing.Color.Transparent;
@@ -125,7 +131,7 @@ namespace BetterLyrics.WinUI3.Helper
}
case WindowPixelSampleMode.AboveWindow:
{
return GetAverageColorFromScreenRegion(myRect.Left, myRect.Top - 3, screenWidth, 1);
return GetAverageColorFromScreenRegion(myRect.Left, myRect.Top - 2, screenWidth, 1);
}
case WindowPixelSampleMode.WindowArea:
{
@@ -143,49 +149,21 @@ namespace BetterLyrics.WinUI3.Helper
if (width <= 0 || height <= 0)
return System.Drawing.Color.Transparent;
var edgeThickness = new Thickness(36, 0, 36, 0);
var edgeThickness = new Thickness(36, 36, 36, 36);
List<System.Drawing.Color> edgeColors = [];
// Top edge
if (edgeThickness.Top > 0 && edgeThickness.Top < height)
edgeColors.Add(
GetAverageColorFromScreenRegion(
myRect.Left,
myRect.Top,
width,
(int)edgeThickness.Top
)
);
if (edgeThickness.Top > 0)
edgeColors.Add(GetAverageColorFromScreenRegion(myRect.Left, myRect.Top - (int)edgeThickness.Top, width, (int)edgeThickness.Top));
// Bottom edge
if (edgeThickness.Bottom > 0 && edgeThickness.Bottom < height)
edgeColors.Add(
GetAverageColorFromScreenRegion(
myRect.Left,
myRect.Bottom - (int)edgeThickness.Bottom,
width,
(int)edgeThickness.Bottom
)
);
if (edgeThickness.Bottom > 0)
edgeColors.Add(GetAverageColorFromScreenRegion(myRect.Left, myRect.Bottom, width, (int)edgeThickness.Bottom));
// Left edge
if (edgeThickness.Left > 0 && edgeThickness.Left < width)
edgeColors.Add(
GetAverageColorFromScreenRegion(
myRect.Left,
myRect.Top + (int)edgeThickness.Top,
(int)edgeThickness.Left,
height - (int)edgeThickness.Top - (int)edgeThickness.Bottom
)
);
if (edgeThickness.Left > 0)
edgeColors.Add(GetAverageColorFromScreenRegion(myRect.Left - (int)edgeThickness.Left, myRect.Top, (int)edgeThickness.Left, height));
// Right edge
if (edgeThickness.Right > 0 && edgeThickness.Right < width)
edgeColors.Add(
GetAverageColorFromScreenRegion(
myRect.Right - (int)edgeThickness.Right,
myRect.Top + (int)edgeThickness.Top,
(int)edgeThickness.Right,
height - (int)edgeThickness.Top - (int)edgeThickness.Bottom
)
);
if (edgeThickness.Right > 0)
edgeColors.Add(GetAverageColorFromScreenRegion(myRect.Right, myRect.Top, (int)edgeThickness.Right, height));
// 合并四边平均色
if (edgeColors.Count == 0)
@@ -247,6 +225,5 @@ namespace BetterLyrics.WinUI3.Helper
if (count == 0) return System.Drawing.Color.Transparent;
return System.Drawing.Color.FromArgb((int)(r / count), (int)(g / count), (int)(b / count));
}
}
}

View File

@@ -1,109 +0,0 @@
using BetterLyrics.WinUI3.Enums;
using BetterLyrics.WinUI3.Services.SettingsService;
using CommunityToolkit.Mvvm.DependencyInjection;
using Microsoft.UI.Windowing;
using Microsoft.UI.Xaml;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using Vanara.PInvoke;
using WinRT.Interop;
using WinUIEx;
namespace BetterLyrics.WinUI3.Helper
{
public static class DesktopModeHelper
{
private static readonly ISettingsService _settingsService = Ioc.Default.GetRequiredService<ISettingsService>();
private static readonly Dictionary<IntPtr, bool> _originalTopmostStates = [];
private static readonly Dictionary<IntPtr, (double X, double Y, double Width, double Height)> _originalWindowBounds = [];
private static readonly Dictionary<IntPtr, WindowStyle> _originalWindowStyles = [];
private delegate nint WndProcDelegate(nint hWnd, uint msg, nint wParam, nint lParam);
public static void Disable(Window window)
{
IntPtr hwnd = WindowNative.GetWindowHandle(window);
// <20>ָ<EFBFBD>TopMost״̬
if (_originalTopmostStates.TryGetValue(hwnd, out var wasTopMost))
{
window.SetIsAlwaysOnTop(wasTopMost);
_originalTopmostStates.Remove(hwnd);
}
// <20>ָ<EFBFBD><D6B8><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD>úʹ<C3BA>С
if (_originalWindowBounds.TryGetValue(hwnd, out var bounds))
{
window.AppWindow.MoveAndResize(
new Windows.Graphics.RectInt32(
(int)bounds.X,
(int)bounds.Y,
(int)bounds.Width,
(int)bounds.Height
)
);
_originalWindowBounds.Remove(hwnd);
}
window.SetIsShownInSwitchers(true);
}
public static void Enable(Window window)
{
IntPtr hwnd = WindowNative.GetWindowHandle(window);
// <20><>¼ԭʼ<D4AD><CABC><EFBFBD><EFBFBD>λ<EFBFBD>úʹ<C3BA>С
if (!_originalWindowBounds.ContainsKey(hwnd))
{
_originalWindowBounds[hwnd] = (
window.AppWindow.Position.X,
window.AppWindow.Position.Y,
window.AppWindow.Size.Width,
window.AppWindow.Size.Height
);
}
// <20><><EFBFBD>ô<EFBFBD><C3B4>ڴ<EFBFBD>С<EFBFBD><D0A1>λ<EFBFBD><CEBB>
window.AppWindow.MoveAndResize(_settingsService.AppSettings.DesktopModeSettings.WindowBounds.ToRectInt32());
// <20><><EFBFBD><EFBFBD>ԭTopMost״̬
if (!_originalTopmostStates.ContainsKey(hwnd))
_originalTopmostStates[hwnd] = window.GetIsAlwaysOnTop();
// <20><><EFBFBD>ô<EFBFBD><C3B4><EFBFBD><EFBFBD>ö<EFBFBD>
window.SetIsAlwaysOnTop(true);
window.SetIsShownInSwitchers(false);
}
public static void SetClickThrough(Window window, bool enable)
{
IntPtr hwnd = WindowNative.GetWindowHandle(window);
int exStyle = User32.GetWindowLong(hwnd, User32.WindowLongFlags.GWL_EXSTYLE);
if (enable)
{
// <20><><EFBFBD><EFBFBD>ԭ<EFBFBD><D4AD>ʽ
if (!_originalWindowStyles.ContainsKey(hwnd))
_originalWindowStyles[hwnd] = window.GetWindowStyle();
window.ToggleWindowStyle(true, WindowStyle.Popup | WindowStyle.Visible);
User32.SetWindowLong(hwnd, User32.WindowLongFlags.GWL_EXSTYLE, exStyle | (int)User32.WindowStylesEx.WS_EX_TRANSPARENT | (int)User32.WindowStylesEx.WS_EX_LAYERED);
}
else
{
User32.SetWindowLong(hwnd, User32.WindowLongFlags.GWL_EXSTYLE, exStyle & ~(int)User32.WindowStylesEx.WS_EX_TRANSPARENT);
// <20>ָ<EFBFBD><D6B8><EFBFBD>ʽ
if (_originalWindowStyles.TryGetValue(hwnd, out var style))
{
window.SetWindowStyle(style);
_originalWindowStyles.Remove(hwnd);
}
}
}
}
}

View File

@@ -1,205 +0,0 @@
using BetterLyrics.WinUI3.Enums;
using BetterLyrics.WinUI3.Services.SettingsService;
using CommunityToolkit.Mvvm.DependencyInjection;
using CommunityToolkit.WinUI;
using Microsoft.UI.Xaml;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using Vanara.PInvoke;
using WinRT.Interop;
using WinUIEx;
namespace BetterLyrics.WinUI3.Helper
{
public static class DockModeHelper
{
private static readonly ISettingsService _settingsService = Ioc.Default.GetRequiredService<ISettingsService>();
private static readonly HashSet<IntPtr> _registered = [];
private static readonly Dictionary<IntPtr, RECT> _originalPositions = [];
private static readonly Dictionary<IntPtr, WindowStyle> _originalWindowStyle = [];
public static bool IsEnabled(IntPtr hwnd)
{
return _registered.Contains(hwnd);
}
public static void Disable(Window window)
{
IntPtr hwnd = WindowNative.GetWindowHandle(window);
if (!_registered.Contains(hwnd)) return;
window.SetIsShownInSwitchers(true);
window.ExtendsContentIntoTitleBar = true;
window.SetIsAlwaysOnTop(false);
UnregisterAppBar(hwnd);
window.SetWindowStyle(_originalWindowStyle[hwnd]);
_originalWindowStyle.Remove(hwnd);
window.ExtendsContentIntoTitleBar = true;
if (_originalPositions.TryGetValue(hwnd, out var rect))
{
User32.SetWindowPos(
hwnd,
IntPtr.Zero,
rect.Left,
rect.Top,
rect.Right - rect.Left,
rect.Bottom - rect.Top,
User32.SetWindowPosFlags.SWP_SHOWWINDOW
);
_originalPositions.Remove(hwnd);
}
}
public static void Enable(Window window, string monitorDeviceName, int appBarHeight, DockPlacement dockPlacement)
{
window.SetIsShownInSwitchers(false);
window.SetIsAlwaysOnTop(true);
IntPtr hwnd = WindowNative.GetWindowHandle(window);
if (!_originalWindowStyle.ContainsKey(hwnd))
{
_originalWindowStyle[hwnd] = window.GetWindowStyle();
}
if (!_originalPositions.ContainsKey(hwnd))
{
if (User32.GetWindowRect(hwnd, out var rect))
{
_originalPositions[hwnd] = rect;
}
}
RegisterAppBar(hwnd, monitorDeviceName, appBarHeight, dockPlacement);
var monitorInfo = MonitorHelper.GetMonitorInfoExFromDeviceName(_settingsService.AppSettings.DockModeSettings.DockMonitorDeviceName);
int screenWidth = monitorInfo.rcMonitor.Width;
int screenHeight = monitorInfo.rcMonitor.Bottom - monitorInfo.rcMonitor.Top;
int y = dockPlacement == DockPlacement.Top ? monitorInfo.rcMonitor.Top : monitorInfo.rcMonitor.Bottom - appBarHeight;
User32.SetWindowPos(
hwnd,
IntPtr.Zero,
monitorInfo.rcMonitor.Left,
y,
screenWidth,
appBarHeight,
User32.SetWindowPosFlags.SWP_HIDEWINDOW
);
window.ExtendsContentIntoTitleBar = false;
window.ToggleWindowStyle(true, WindowStyle.Popup);
window.Show();
}
private static void RegisterAppBar(IntPtr hwnd, string monitorDeviceName, int height, DockPlacement dockPlacement)
{
if (_registered.Contains(hwnd)) return;
var uEdge = dockPlacement == DockPlacement.Top ? Shell32.ABE.ABE_TOP : Shell32.ABE.ABE_BOTTOM;
var monitorInfo = MonitorHelper.GetMonitorInfoExFromDeviceName(monitorDeviceName);
int top = dockPlacement == DockPlacement.Top ? monitorInfo.rcMonitor.Top : monitorInfo.rcMonitor.Bottom - height;
int bottom = dockPlacement == DockPlacement.Top ? monitorInfo.rcMonitor.Top + height : monitorInfo.rcMonitor.Bottom;
Shell32.APPBARDATA abd = new()
{
cbSize = (uint)Marshal.SizeOf<Shell32.APPBARDATA>(),
hWnd = hwnd,
uEdge = uEdge,
rc = new RECT
{
Left = monitorInfo.rcMonitor.Left,
Top = top,
Right = monitorInfo.rcMonitor.Right,
Bottom = bottom,
},
};
Shell32.SHAppBarMessage(Shell32.ABM.ABM_NEW, ref abd);
Shell32.SHAppBarMessage(Shell32.ABM.ABM_QUERYPOS, ref abd);
Shell32.SHAppBarMessage(Shell32.ABM.ABM_SETPOS, ref abd);
_registered.Add(hwnd);
}
private static void UnregisterAppBar(IntPtr hwnd)
{
if (!_registered.Contains(hwnd))
return;
Shell32.APPBARDATA abd = new()
{
cbSize = (uint)Marshal.SizeOf<Shell32.APPBARDATA>(),
hWnd = hwnd
};
Shell32.SHAppBarMessage(Shell32.ABM.ABM_REMOVE, ref abd);
_registered.Remove(hwnd);
}
public static void UpdateAppBarHeight(IntPtr hwnd, string monitorDeviceName, int newHeight, DockPlacement dockPlacement)
{
App.DispatcherQueueTimer?.Debounce(() =>
{
if (!_registered.Contains(hwnd))
return;
var uEdge = dockPlacement == DockPlacement.Top ? Shell32.ABE.ABE_TOP : Shell32.ABE.ABE_BOTTOM;
var monitorInfo = MonitorHelper.GetMonitorInfoExFromDeviceName(monitorDeviceName);
int screenWidth = monitorInfo.rcMonitor.Width;
int top = dockPlacement == DockPlacement.Top ? monitorInfo.rcMonitor.Top : monitorInfo.rcMonitor.Bottom - newHeight;
int bottom = dockPlacement == DockPlacement.Top ? monitorInfo.rcMonitor.Top + newHeight : monitorInfo.rcMonitor.Bottom;
Shell32.APPBARDATA abd = new()
{
cbSize = (uint)Marshal.SizeOf<Shell32.APPBARDATA>(),
hWnd = hwnd,
uEdge = uEdge,
rc = new RECT
{
Left = monitorInfo.rcMonitor.Left,
Top = top,
Right = monitorInfo.rcMonitor.Right,
Bottom = bottom,
},
};
Shell32.SHAppBarMessage(Shell32.ABM.ABM_QUERYPOS, ref abd);
Shell32.SHAppBarMessage(Shell32.ABM.ABM_SETPOS, ref abd);
// 同步窗口实际高度和位置
int y = dockPlacement == DockPlacement.Top ? monitorInfo.rcMonitor.Top : monitorInfo.rcMonitor.Bottom - newHeight;
int repeatCount = 2;
while (repeatCount > 0)
{
repeatCount--;
User32.SetWindowPos(
hwnd,
IntPtr.Zero,
monitorInfo.rcMonitor.Left,
y,
screenWidth,
newHeight,
newHeight == 0 ? User32.SetWindowPosFlags.SWP_HIDEWINDOW : User32.SetWindowPosFlags.SWP_SHOWWINDOW
);
}
}, TimeSpan.FromMilliseconds(100));
}
}
}

View File

@@ -17,7 +17,6 @@ namespace BetterLyrics.WinUI3.Helper
private readonly List<User32.HWINEVENTHOOK> _hooks = new();
private HWND _currentForeground = HWND.NULL;
private readonly IntPtr _selfHwnd;
private readonly ThrottleHelper _winEventProcThrottle = new(TimeSpan.FromSeconds(1));
public delegate void WindowChangedHandler(HWND hwnd);
private readonly WindowChangedHandler _onWindowChanged;
@@ -73,7 +72,7 @@ namespace BetterLyrics.WinUI3.Helper
_hooks.Clear();
_timer.Stop();
//_timer.Stop();
}
private void Timer_Tick(object? sender, object e)

View File

@@ -14,6 +14,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Numerics;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading.Tasks;
@@ -219,5 +220,68 @@ namespace BetterLyrics.WinUI3.Helper
}
return pixelData;
}
public static async Task<byte[]> DownloadImageAsByteArrayAsync(string url)
{
using var httpClient = new HttpClient();
return await httpClient.GetByteArrayAsync(url);
}
public static byte[]? DataUrlToByteArray(string dataUrl)
{
const string base64Marker = ";base64,";
int base64Index = dataUrl.IndexOf(base64Marker, StringComparison.OrdinalIgnoreCase);
if (base64Index >= 0)
{
string base64Data = dataUrl.Substring(base64Index + base64Marker.Length);
return Convert.FromBase64String(base64Data);
}
else
{
// 非 base64直接取逗号后内容并解码
int commaIndex = dataUrl.IndexOf(',');
if (commaIndex >= 0)
{
string rawData = dataUrl.Substring(commaIndex + 1);
return System.Text.Encoding.UTF8.GetBytes(Uri.UnescapeDataString(rawData));
}
else
{
return null;
}
}
}
public static async Task<byte[]?> GetImageBytesFromUrlAsync(string url)
{
if (string.IsNullOrWhiteSpace(url))
{
return null;
}
try
{
if (url.StartsWith("data:", StringComparison.OrdinalIgnoreCase))
{
// data URL直接解析
return DataUrlToByteArray(url);
}
else if (Uri.TryCreate(url, UriKind.Absolute, out var uri) &&
(uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps))
{
// 普通网络图片,下载
return await DownloadImageAsByteArrayAsync(url);
}
else
{
// 其他类型暂不支持
return null;
}
}
catch (Exception)
{
return null;
}
}
}
}

View File

@@ -1,14 +1,7 @@
using BetterLyrics.WinUI3.Helper;
using BetterLyrics.WinUI3.Services.SettingsService;
using CommunityToolkit.Mvvm.DependencyInjection;
using Lyricify.Lyrics.Helpers.General;
using NTextCat;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using TinyPinyin;
using Windows.Globalization;
namespace BetterLyrics.WinUI3.Services
@@ -18,38 +11,77 @@ namespace BetterLyrics.WinUI3.Services
private static readonly RankedLanguageIdentifierFactory _factory = new();
private static readonly RankedLanguageIdentifier _identifier;
public static List<Models.LanguageInfo> SupportedTargetLanguages =>
public static List<Models.LanguageInfo> SupportedTargetLanguages { get; set; } =
[
new Models.LanguageInfo("ar", "العربية"),
new Models.LanguageInfo("az", "Azərbaycan dili"),
new Models.LanguageInfo("zh", "中文"),
new Models.LanguageInfo("bg", "Български"),
new Models.LanguageInfo("bn", "বাংলা"),
new Models.LanguageInfo("ca", "Català"),
new Models.LanguageInfo("cs", "Čeština"),
new Models.LanguageInfo("da", "Dansk"),
new Models.LanguageInfo("nl", "Nederlands"),
new Models.LanguageInfo("de", "Deutsch"),
new Models.LanguageInfo("el", "Ελληνικά"),
new Models.LanguageInfo("en", "English"),
new Models.LanguageInfo("eo", "Esperanto"),
new Models.LanguageInfo("es", "Español"),
new Models.LanguageInfo("et", "Eesti"),
new Models.LanguageInfo("eu", "Euskara"),
new Models.LanguageInfo("fa", "فارسی"),
new Models.LanguageInfo("fi", "Suomi"),
new Models.LanguageInfo("fr", "Français"),
new Models.LanguageInfo("de", "Deutsch"),
new Models.LanguageInfo("el", "Ελληνικά"),
new Models.LanguageInfo("ga", "Gaeilge"),
new Models.LanguageInfo("gl", "Galego"),
new Models.LanguageInfo("he", "עברית"),
new Models.LanguageInfo("hi", "हिन्दी"),
new Models.LanguageInfo("hu", "Magyar"),
new Models.LanguageInfo("id", "Bahasa Indonesia"),
new Models.LanguageInfo("ga", "Gaeilge"),
new Models.LanguageInfo("it", "Italiano"),
new Models.LanguageInfo("ja", "日本語"),
new Models.LanguageInfo("ko", "한국어"),
new Models.LanguageInfo("fa", "فارسی"),
new Models.LanguageInfo("ky", "Кыргызча"),
new Models.LanguageInfo("lt", "Lietuvių"),
new Models.LanguageInfo("lv", "Latviešu"),
new Models.LanguageInfo("ms", "Bahasa Melayu"),
new Models.LanguageInfo("nb", "Norsk bokmål"),
new Models.LanguageInfo("nl", "Nederlands"),
new Models.LanguageInfo("pt-BR", "Português (Brasil)"),
new Models.LanguageInfo("pl", "Polski"),
new Models.LanguageInfo("pt", "Português"),
new Models.LanguageInfo("ro", "Română"),
new Models.LanguageInfo("ru", "Русский"),
new Models.LanguageInfo("sk", "Slovenčina"),
new Models.LanguageInfo("es", "Español"),
new Models.LanguageInfo("sl", "Slovenščina"),
new Models.LanguageInfo("sq", "Shqip"),
new Models.LanguageInfo("sr", "Српски"),
new Models.LanguageInfo("sv", "Svenska"),
new Models.LanguageInfo("th", "ไทย"),
new Models.LanguageInfo("tl", "Filipino"),
new Models.LanguageInfo("tr", "Türkçe"),
new Models.LanguageInfo("uk", "Українська"),
new Models.LanguageInfo("ur", "اردو"),
new Models.LanguageInfo("vi", "Tiếng Việt"),
new Models.LanguageInfo("zh", "中文"),
];
static LanguageHelper()
@@ -83,11 +115,17 @@ namespace BetterLyrics.WinUI3.Services
};
}
public static int GetDefaultTargetLanguageIndex()
public static string GetDefaultTargetLanguageCode()
{
int found = SupportedTargetLanguages.FindIndex(x => ApplicationLanguages.Languages.FirstOrDefault()?.Contains(x.Code) == true);
if (found == -1) found = 7; // 默认使用英语
return found;
var found = SupportedTargetLanguages.Find(x => ApplicationLanguages.Languages.FirstOrDefault()?.Contains(x.Code) == true);
if (found == null)
{
return "en";
}
else
{
return found.Code;
}
}
public static string GetOrderChar(string text)
@@ -97,9 +135,9 @@ namespace BetterLyrics.WinUI3.Services
if (char.IsLetter(c) && c < 128)
return char.ToUpper(c).ToString();
if (PinyinHelper.IsChinese(c))
if (Pinyin.Pinyin.Instance.IsHanzi(c.ToString()))
{
return PinyinHelper.GetPinyinInitials($"{c}");
return Pinyin.Pinyin.Instance.HanziToPinyin(c.ToString(), Pinyin.ManTone.Style.NORMAL).ToStr().ToUpper().FirstOrDefault().ToString();
}
return "#";
@@ -107,7 +145,7 @@ namespace BetterLyrics.WinUI3.Services
public static string ToRomaji(string text)
{
return string.Join(" ", RomajiConverter.Core.Helpers.RomajiHelper.SentenceToRomaji(text).Select(x=>x.Romaji));
return string.Join(" ", RomajiConverter.Core.Helpers.RomajiHelper.SentenceToRomaji(text).Select(x => x.Romaji));
}
}
}

View File

@@ -3,8 +3,8 @@
using BetterLyrics.WinUI3.Enums;
using BetterLyrics.WinUI3.Models;
using BetterLyrics.WinUI3.Services;
using Lyricify.Lyrics.Helpers.General;
using Lyricify.Lyrics.Models;
using Lyricify.Lyrics.Parsers;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -14,7 +14,7 @@ using LyricsData = BetterLyrics.WinUI3.Models.LyricsData;
namespace BetterLyrics.WinUI3.Helper
{
public class LyricsParser
public partial class LyricsParser
{
private List<LyricsData> _lyricsDataArr = [];
@@ -35,10 +35,10 @@ namespace BetterLyrics.WinUI3.Helper
ParseLrc(raw);
break;
case LyricsFormat.Qrc:
ParseQQNeteaseKugou(Lyricify.Lyrics.Parsers.QrcParser.Parse(raw).Lines);
ParseQQNeteaseKugou(QrcParser.Parse(raw).Lines);
break;
case LyricsFormat.Krc:
ParseQQNeteaseKugou(Lyricify.Lyrics.Parsers.KrcParser.Parse(raw).Lines);
ParseQQNeteaseKugou(KrcParser.Parse(raw).Lines);
break;
case LyricsFormat.Ttml:
ParseTtml(raw);
@@ -122,9 +122,7 @@ namespace BetterLyrics.WinUI3.Helper
new List<(int time, string text, List<(int time, string text)> syllables)>();
// 支持 [mm:ss.xx]字、<mm:ss.xx>字,毫秒两位或三位
var syllableRegex = new Regex(
@"(\[|\<)(\d{2}):(\d{2})\.(\d{2,3})(\]|\>)([^\[\]\<\>]*)"
);
var syllableRegex = SyllableRegex();
foreach (var line in lines)
{
@@ -141,7 +139,7 @@ namespace BetterLyrics.WinUI3.Helper
syllables.Add((totalMs, text));
}
if (syllables.Count > 0)
if (syllables.Count > 1)
{
lrcLines.Add(
(
@@ -154,18 +152,19 @@ namespace BetterLyrics.WinUI3.Helper
else
{
// 普通LRC行
var bracketRegex = new Regex(@"\[(\d{2}):(\d{2})\.(\d{2,3})\]");
Regex? bracketRegex = LrcRegex();
var bracketMatches = bracketRegex.Matches(line);
string content = line;
int? lineStartTime = null;
if (bracketMatches.Count > 0)
{
var m = bracketMatches[0];
var m = bracketMatches![0];
int min = int.Parse(m.Groups[1].Value);
int sec = int.Parse(m.Groups[2].Value);
int ms = int.Parse(m.Groups[3].Value.PadRight(3, '0'));
int ms = int.Parse(m.Groups[4].Value.PadRight(3, '0'));
lineStartTime = min * 60_000 + sec * 1000 + ms;
content = bracketRegex.Replace(line, "");
content = bracketRegex!.Replace(line, "");
lrcLines.Add((lineStartTime.Value, content, new List<(int, string)>()));
}
}
@@ -451,5 +450,10 @@ namespace BetterLyrics.WinUI3.Helper
_lyricsDataArr.Add(new LyricsData(lyricsLines));
}
[GeneratedRegex(@"\[(\d*):(\d*)(\.|\:)(\d*)\]")]
private static partial Regex LrcRegex();
[GeneratedRegex(@"(\[|\<)(\d*):(\d*)\.(\d*)(\]|\>)([^\[\]\<\>]*)")]
private static partial Regex SyllableRegex();
}
}

View File

@@ -34,6 +34,10 @@ namespace BetterLyrics.WinUI3.Helper
public static string PotPlayerLogoPath => Path.Combine(AssetsFolder, "PotPlayer.png");
public static string ChromeLogoPath => Path.Combine(AssetsFolder, "Chrome.png");
public static string EdgeLogoPath => Path.Combine(AssetsFolder, "Edge.png");
public static string SaltPlayerForWindowsLogoPath => Path.Combine(AssetsFolder, "SaltPlayerForWindows.png");
public static string MoeKoeMusicLogoPath => Path.Combine(AssetsFolder, "MoeKoeMusic.png");
public static string Listen1LogoPath => Path.Combine(AssetsFolder, "Listen1.png");
public static string UnknownPlayerLogoPath => Path.Combine(AssetsFolder, "Question.png");
public static string LogDirectory => Path.Combine(CacheFolder, "logs");
@@ -46,6 +50,7 @@ namespace BetterLyrics.WinUI3.Helper
public static string QQLyricsCacheDirectory => Path.Combine(LyricsCacheDirectory, "qq");
public static string KugouLyricsCacheDirectory => Path.Combine(LyricsCacheDirectory, "kugou");
public static string AmllTtmlDbLyricsCacheDirectory => Path.Combine(LyricsCacheDirectory, "amll-ttml-db");
public static string AppleMusicCacheDirectory => Path.Combine(LyricsCacheDirectory, "apple-music");
public static string AmllTtmlDbIndexPath => Path.Combine(LyricsCacheDirectory, "amll-ttml-db-index.json");
public static string AmllTtmlDbLastUpdatedPath => Path.Combine(LyricsCacheDirectory, "amll-ttml-db-last-updated.txt");
@@ -53,6 +58,7 @@ namespace BetterLyrics.WinUI3.Helper
public static string QQTranslationCacheDirectory => Path.Combine(TranslationCacheDirectory, "qq");
public static string NeteaseTranslationCacheDirectory => Path.Combine(TranslationCacheDirectory, "netease");
public static string KugouTranslationCacheDirectory => Path.Combine(TranslationCacheDirectory, "kugou");
public static string AlbumArtCacheDirectory => Path.Combine(CacheFolder, "album-art");
@@ -69,9 +75,11 @@ namespace BetterLyrics.WinUI3.Helper
Directory.CreateDirectory(KugouLyricsCacheDirectory);
Directory.CreateDirectory(NeteaseLyricsCacheDirectory);
Directory.CreateDirectory(AmllTtmlDbLyricsCacheDirectory);
Directory.CreateDirectory(AppleMusicCacheDirectory);
Directory.CreateDirectory(QQTranslationCacheDirectory);
Directory.CreateDirectory(NeteaseTranslationCacheDirectory);
Directory.CreateDirectory(KugouTranslationCacheDirectory);
Directory.CreateDirectory(iTunesAlbumArtCacheDirectory);
}

View File

@@ -0,0 +1,25 @@
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace BetterLyrics.WinUI3.Helper
{
public static class PlayerIdMatcher
{
private static readonly List<string> _neteaseFamilyRegex =
[
"cloudmusic.exe", //NetEaseCloudMusic
"^17588BrandonWong\\.LyricEase_", //LyricEase
"^48848aaaaaaccd\\.HyPlayer_" //HyPlayer
];
public static bool IsNeteaseFamily(string player)
{
foreach (var regex in _neteaseFamilyRegex)
{
var isMatch = Regex.IsMatch(player, regex);
if (isMatch) return true;
}
return false;
}
}
}

View File

@@ -18,5 +18,45 @@ namespace BetterLyrics.WinUI3.Helper
(int)rect.Height
);
}
public static Windows.Foundation.Rect WithHeight(this Windows.Foundation.Rect rect, double height)
{
return new Windows.Foundation.Rect(
rect.X,
rect.Y,
rect.Width,
height
);
}
public static Windows.Foundation.Rect WithWidth(this Windows.Foundation.Rect rect, double width)
{
return new Windows.Foundation.Rect(
rect.X,
rect.Y,
width,
rect.Height
);
}
public static Windows.Foundation.Rect WithX(this Windows.Foundation.Rect rect, double x)
{
return new Windows.Foundation.Rect(
x,
rect.Y,
rect.Width,
rect.Height
);
}
public static Windows.Foundation.Rect WithY(this Windows.Foundation.Rect rect, double y)
{
return new Windows.Foundation.Rect(
rect.X,
y,
rect.Width,
rect.Height
);
}
}
}

View File

@@ -0,0 +1,181 @@
using BetterLyrics.WinUI3.Models.Settings;
using NAudio.Dsp;
using NAudio.Wave;
using System;
using System.Diagnostics;
namespace BetterLyrics.WinUI3.Helper
{
public class SpectrumAnalyzer : IDisposable
{
private WasapiLoopbackCapture _capture;
private int _sampleRate = 48000;
private readonly int _fftLength = 2048;
private readonly float[] _fftLeftBuffer;
private readonly float[] _fftRightBuffer;
private readonly Complex[] _fftLeftData;
private readonly Complex[] _fftRightData;
private float[] _spectrumLeftData;
private float[] _spectrumRightData;
private float[] _spectrumData;
private bool _disposed = false;
private double[] _hammingWindow;
private float[] _currentSpectrum;
public float[] SmoothSpectrum { get; private set; }
public int BarCount { get; set; } = 32;
public int Sensitivity { get; set; } = 10;
public float SmoothingFactor { get; set; } = 0.95f;
public bool IsCapturing { get; private set; } = false;
public SpectrumAnalyzer()
{
_fftLeftBuffer = new float[_fftLength];
_fftLeftData = new Complex[_fftLength];
_fftRightBuffer = new float[_fftLength];
_fftRightData = new Complex[_fftLength];
_hammingWindow = new double[_fftLength];
//汉明窗
for (int i = 0; i < _fftLength; i++)
{
_hammingWindow[i] = 0.54 - 0.46 * Math.Cos((2 * Math.PI * i) / (_fftLength - 1));
}
}
public void StartCapture()
{
_currentSpectrum = new float[BarCount];
SmoothSpectrum = new float[BarCount];
try
{
_capture = new WasapiLoopbackCapture();
_sampleRate = _capture.WaveFormat.SampleRate;
_spectrumLeftData = new float[(int)(24000.0f / _sampleRate * _fftLength) / 2];
_spectrumRightData = new float[(int)(24000.0f / _sampleRate * _fftLength) / 2];
_spectrumData = new float[(int)(24000.0f / _sampleRate * _fftLength)];
_capture.DataAvailable += OnDataAvailable;
_capture.RecordingStopped += OnRecordingStopped;
_capture.StartRecording();
IsCapturing = true;
}
catch (Exception)
{
}
}
public void StopCapture()
{
_capture?.DataAvailable -= OnDataAvailable;
_capture?.RecordingStopped -= OnRecordingStopped;
_capture?.StopRecording();
IsCapturing = false;
}
private void OnDataAvailable(object? sender, WaveInEventArgs e)
{
if (_disposed || e.BytesRecorded == 0) return;
// 将字节转换为浮点数
int samples = e.BytesRecorded / 8;
if (samples < _fftLength) return;
for (int i = 0; i < _fftLength; i++)
{
_fftLeftBuffer[i] = BitConverter.ToSingle(e.Buffer, i * 8);
_fftRightBuffer[i] = BitConverter.ToSingle(e.Buffer, i * 8 + 4);
}
for (int i = 0; i < _fftLength; i++)
{
_fftLeftData[i].X = _fftLeftBuffer[i] * (float)_hammingWindow[i]; // Real part
_fftLeftData[i].Y = 0; // Imaginary part
_fftRightData[i].X = _fftRightBuffer[i] * (float)_hammingWindow[i];
_fftRightData[i].Y = 0;
}
// FFT
FastFourierTransform.FFT(true, (int)Math.Log(_fftLength, 2), _fftLeftData);
FastFourierTransform.FFT(true, (int)Math.Log(_fftLength, 2), _fftRightData);
for (int i = 0; i < _spectrumLeftData.Length; i++)
{
float real = (float)_fftLeftData[i].X;
float imaginary = (float)_fftLeftData[i].Y;
float magnitude = (float)Math.Sqrt(real * real + imaginary * imaginary);
float frequency = i * _sampleRate / _fftLength;
float compensationFactor = GetCompensationFactor(frequency);
_spectrumLeftData[i] = magnitude * compensationFactor;
_spectrumRightData[i] = (float)Math.Sqrt((float)_fftRightData[i].X * (float)_fftRightData[i].X + (float)_fftRightData[i].Y * (float)_fftRightData[i].Y) * compensationFactor;
for (int j = 0; j < _spectrumLeftData.Length; j++)
{
_spectrumData[j] = _spectrumLeftData[_spectrumLeftData.Length - 1 - j];
}
Array.Copy(_spectrumRightData, 0, _spectrumData, _spectrumLeftData.Length, _spectrumRightData.Length);
}
for (int i = 0; i < BarCount; i++)
{
int index = (int)((float)i / BarCount * _spectrumData.Length);
if (index < _spectrumData.Length)
{
_currentSpectrum[i] = _spectrumData[index] * 250f * Sensitivity;
}
}
}
public void UpdateSmoothSpectrum()
{
for (int i = 0; i < BarCount; i++)
{
SmoothSpectrum[i] = SmoothSpectrum[i] * SmoothingFactor +
_currentSpectrum[i] * (1 - SmoothingFactor);
}
}
private float GetCompensationFactor(float freq)
{
// 补偿曲线
float[] frequencies = { 20, 50, 100, 200, 500, 1000, 2000, 4000, 8000, 16000, 20000 };
float[] gains = { 0.5f, 0.3f, 0.4f, 0.6f, 0.8f, 1.0f, 1.2f, 1.3f, 1.1f, 0.9f, 0.8f };
if (freq <= frequencies[0])
{
return gains[0];
}
if (freq >= frequencies[frequencies.Length - 1])
{
return gains[gains.Length - 1];
}
int i = 0;
while (freq > frequencies[i + 1])
{
i++;
}
// 线性插值
float x1 = frequencies[i];
float y1 = gains[i];
float x2 = frequencies[i + 1];
float y2 = gains[i + 1];
return y1 + (freq - x1) * ((y2 - y1) / (x2 - x1));
}
private void OnRecordingStopped(object? sender, StoppedEventArgs e)
{
}
public void Dispose()
{
if (!_disposed)
{
_capture?.Dispose();
_disposed = true;
}
}
}
}

View File

@@ -1,12 +1,19 @@
// 2025/6/23 by Zhe Fang
using BetterLyrics.WinUI3.Enums;
using BetterLyrics.WinUI3.Services.LiveStatesService;
using BetterLyrics.WinUI3.Services.MediaSessionsService;
using BetterLyrics.WinUI3.Views;
using CommunityToolkit.Mvvm.DependencyInjection;
using CommunityToolkit.WinUI;
using Microsoft.UI.Windowing;
using Microsoft.UI.Xaml;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Vanara.PInvoke;
using Windows.ApplicationModel.Core;
using Windows.Foundation;
using WinRT.Interop;
using WinUIEx;
@@ -15,6 +22,22 @@ namespace BetterLyrics.WinUI3.Helper
public static class WindowHelper
{
private static List<object> _activeWindows = [];
private static List<object> _workAreas = [];
private static readonly Dictionary<HWND, WindowStyle> _defaultWindowStyle = [];
private static readonly Dictionary<HWND, ExtendedWindowStyle> _defaultExtendedWindowStyle = [];
private static readonly ILiveStatesService _liveStatesService = Ioc.Default.GetRequiredService<ILiveStatesService>();
private static readonly IMediaSessionsService _mediaSessionsService = Ioc.Default.GetRequiredService<IMediaSessionsService>();
public static void HideWindow<T>()
{
var window = _activeWindows.Find(w => w is T);
if (window is Window w)
{
w.Hide();
}
}
public static void CloseWindow<T>()
{
@@ -41,7 +64,8 @@ namespace BetterLyrics.WinUI3.Helper
}
return default;
}
public static void OpenWindow<T>()
public static void OpenOrShowWindow<T>()
{
var window = _activeWindows.Find(w => w is T);
if (window == null)
@@ -63,6 +87,10 @@ namespace BetterLyrics.WinUI3.Helper
{
window = new LyricsSearchWindow();
}
else if (typeof(T) == typeof(LyricsWindowSwitchWindow))
{
window = new LyricsWindowSwitchWindow();
}
else
{
throw new ArgumentException("Unsupported window type", nameof(T));
@@ -74,10 +102,14 @@ namespace BetterLyrics.WinUI3.Helper
if (typeof(T) == typeof(LyricsWindow))
{
var hwnd = WindowNative.GetWindowHandle(castedWindow);
_defaultWindowStyle.Add(hwnd, castedWindow.GetWindowStyle());
_defaultExtendedWindowStyle.Add(hwnd, castedWindow.GetExtendedWindowStyle());
var lyricsWindow = (LyricsWindow)window;
lyricsWindow.ViewModel.InitShortcuts();
lyricsWindow.AutoSelectLyricsMode();
lyricsWindow.ViewModel.SetIsAlwaysOnTop();
lyricsWindow.ViewModel.InitFgWindowWatcher();
lyricsWindow.ViewModel.RefreshLyricsWindowStatus();
}
}
else
@@ -124,11 +156,7 @@ namespace BetterLyrics.WinUI3.Helper
private static void EnsureDockModeReleased()
{
LyricsWindow? lyricsWindow = GetWindowByWindowType<LyricsWindow>();
if (lyricsWindow != null)
{
DockModeHelper.Disable(lyricsWindow);
}
SetIsWorkArea<LyricsWindow>(false);
}
private static void TrackWindow(object window)
@@ -146,7 +174,224 @@ namespace BetterLyrics.WinUI3.Helper
if (_activeWindows.Contains(sender))
{
_activeWindows.Remove(sender);
var hwnd = WindowNative.GetWindowHandle(sender);
_defaultWindowStyle.Remove(hwnd);
_defaultExtendedWindowStyle.Remove(hwnd);
}
}
public static void SetIsClickThrough<T>(bool enable)
{
Window? window = GetWindowByWindowType<T>() as Window;
if (window == null) return;
IntPtr hwnd = WindowNative.GetWindowHandle(window);
if (enable)
{
window.SetExtendedWindowStyle(_defaultExtendedWindowStyle[hwnd] | ExtendedWindowStyle.Transparent | ExtendedWindowStyle.Layered);
}
else
{
window.SetExtendedWindowStyle(_defaultExtendedWindowStyle[hwnd]);
}
}
public static void SetIsWorkArea<T>(bool enable)
{
Window? window = GetWindowByWindowType<T>() as Window;
if (window == null) return;
if (enable)
{
EnableWorkArea(window);
}
else
{
DisableWorkArea(window);
}
}
public static void SetIsBorderless<T>(bool enable)
{
var window = GetWindowByWindowType<T>() as Window;
if (window == null) return;
var hwnd = WindowNative.GetWindowHandle(window);
if (enable)
{
window.SetWindowStyle(WindowStyle.Popup | WindowStyle.Visible);
}
else
{
window.SetWindowStyle(_defaultWindowStyle[hwnd]);
}
}
public static void SetIsShowInSwitchers<T>(bool enable)
{
var window = GetWindowByWindowType<T>() as Window;
if (window == null) return;
window.AppWindow.IsShownInSwitchers = enable;
}
public static void SetIsAlwaysOnTop<T>(bool enable)
{
var window = GetWindowByWindowType<T>() as Window;
if (window == null) return;
if (window.AppWindow.Presenter is OverlappedPresenter presenter)
{
presenter.IsAlwaysOnTop = enable;
}
}
public static void MoveAndResize<T>(Rect rect)
{
var window = GetWindowByWindowType<T>() as Window;
if (window == null) return;
window.AppWindow.MoveAndResize(rect.ToRectInt32());
}
public static void SetTitleBarArea<T>(TitleBarArea titleBarArea)
{
if (typeof(T) == typeof(LyricsWindow))
{
LyricsWindow? lyricsWindow = GetWindowByWindowType<LyricsWindow>();
lyricsWindow?.SetTitleBarArea(titleBarArea);
}
else
{
throw new Exception($"Unsupported window type: {typeof(T).FullName}");
}
}
private static void DisableWorkArea(Window window)
{
IntPtr hwnd = WindowNative.GetWindowHandle(window);
if (!_workAreas.Contains(hwnd)) return;
UnregisterWorkArea(hwnd);
}
private static void EnableWorkArea(Window window)
{
IntPtr hwnd = WindowNative.GetWindowHandle(window);
if (_workAreas.Contains(hwnd)) return;
RegisterWorkArea(hwnd);
}
private static void RegisterWorkArea(IntPtr hwnd)
{
if (_workAreas.Contains(hwnd)) return;
var uEdge = _liveStatesService.LiveStates.LyricsWindowStatus.DockPlacement == DockPlacement.Top ? Shell32.ABE.ABE_TOP : Shell32.ABE.ABE_BOTTOM;
double top = _liveStatesService.LiveStates.LyricsWindowStatus.DockPlacement == DockPlacement.Top ? _liveStatesService.LiveStates.LyricsWindowStatus.MonitorBounds.Top : _liveStatesService.LiveStates.LyricsWindowStatus.MonitorBounds.Bottom - _liveStatesService.LiveStates.LyricsWindowStatus.DockHeight;
double bottom = top + _liveStatesService.LiveStates.LyricsWindowStatus.DockHeight;
Shell32.APPBARDATA abd = new()
{
cbSize = (uint)Marshal.SizeOf<Shell32.APPBARDATA>(),
hWnd = hwnd,
uEdge = uEdge,
rc = new RECT
{
Left = (int)_liveStatesService.LiveStates.LyricsWindowStatus.MonitorBounds.Left,
Top = (int)top,
Right = (int)_liveStatesService.LiveStates.LyricsWindowStatus.MonitorBounds.Right,
Bottom = (int)bottom,
},
};
Shell32.SHAppBarMessage(Shell32.ABM.ABM_NEW, ref abd);
Shell32.SHAppBarMessage(Shell32.ABM.ABM_QUERYPOS, ref abd);
Shell32.SHAppBarMessage(Shell32.ABM.ABM_SETPOS, ref abd);
_workAreas.Add(hwnd);
}
private static void UnregisterWorkArea(IntPtr hwnd)
{
if (!_workAreas.Contains(hwnd))
return;
Shell32.APPBARDATA abd = new()
{
cbSize = (uint)Marshal.SizeOf<Shell32.APPBARDATA>(),
hWnd = hwnd
};
Shell32.SHAppBarMessage(Shell32.ABM.ABM_REMOVE, ref abd);
_workAreas.Remove(hwnd);
}
public static void UpdateWorkArea<T>()
{
var window = GetWindowByWindowType<T>() as Window;
if (window == null) return;
var hwnd = WindowNative.GetWindowHandle(window);
if (!_workAreas.Contains(hwnd))
return;
var uEdge = _liveStatesService.LiveStates.LyricsWindowStatus.DockPlacement == DockPlacement.Top ? Shell32.ABE.ABE_TOP : Shell32.ABE.ABE_BOTTOM;
double top = _liveStatesService.LiveStates.LyricsWindowStatus.DockPlacement == DockPlacement.Top ?
_liveStatesService.LiveStates.LyricsWindowStatus.MonitorBounds.Top :
_liveStatesService.LiveStates.LyricsWindowStatus.MonitorBounds.Bottom - _liveStatesService.LiveStates.LyricsWindowStatus.DockHeight;
double bottom = top + _liveStatesService.LiveStates.LyricsWindowStatus.DockHeight;
Shell32.APPBARDATA abd = new()
{
cbSize = (uint)Marshal.SizeOf<Shell32.APPBARDATA>(),
hWnd = hwnd,
uEdge = uEdge,
rc = new RECT
{
Left = (int)_liveStatesService.LiveStates.LyricsWindowStatus.MonitorBounds.Left,
Top = (int)top,
Right = (int)_liveStatesService.LiveStates.LyricsWindowStatus.MonitorBounds.Right,
Bottom = (int)bottom,
},
};
Shell32.SHAppBarMessage(Shell32.ABM.ABM_QUERYPOS, ref abd);
Shell32.SHAppBarMessage(Shell32.ABM.ABM_SETPOS, ref abd);
}
public static void SetLyricsWindowVisibilityByPlayingStatus()
{
var window = GetWindowByWindowType<LyricsWindow>();
if (window == null) return;
if (_liveStatesService.LiveStates.LyricsWindowStatus.AutoShowOrHideWindow && !_mediaSessionsService.IsPlaying)
{
if (_liveStatesService.LiveStates.LyricsWindowStatus.IsWorkArea)
{
SetIsWorkArea<LyricsWindow>(false);
}
HideWindow<LyricsWindow>();
}
else if (_liveStatesService.LiveStates.LyricsWindowStatus.AutoShowOrHideWindow && _mediaSessionsService.IsPlaying)
{
if (_liveStatesService.LiveStates.LyricsWindowStatus.IsWorkArea)
{
SetIsWorkArea<LyricsWindow>(true);
}
OpenOrShowWindow<LyricsWindow>();
}
}
}
}

View File

@@ -1,14 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BetterLyrics.WinUI3.Models
{
public class LibInfo
{
public string Name { get; set; }
public string Url => $"https://www.nuget.org/packages/{Name}/";
}
}

View File

@@ -1,7 +1,9 @@
using BetterLyrics.WinUI3.Enums;
using BetterLyrics.WinUI3.Helper;
using BetterLyrics.WinUI3.Models.Settings;
using BetterLyrics.WinUI3.Views;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Messaging;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -14,63 +16,11 @@ namespace BetterLyrics.WinUI3.Models
{
public partial class LiveStates : ObservableRecipient
{
[ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsWindowMode LyricsWindowMode { get; set; }
[ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsDisplayType LyricsDisplayType { get; set; }
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsAlwaysOnTop { get; set; }
[ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsStyleSettings LyricsStyleSettings { get; set; }
[ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsEffectSettings LyricsEffectSettings { get; set; }
[ObservableProperty][NotifyPropertyChangedRecipients] public partial Rect LyricsWindowBounds { get; set; }
[ObservableProperty][NotifyPropertyChangedRecipients] public partial Rect LyricsWindowMonitorBounds { get; set; }
[ObservableProperty][NotifyPropertyChangedRecipients] public partial Rect DemoLyricsWindowBounds { get; set; }
[ObservableProperty][NotifyPropertyChangedRecipients] public partial Rect DemoLyricsWindowMonitorBounds { get; set; }
[ObservableProperty][NotifyPropertyChangedRecipients] public partial string LyricsWindowMonitorName { get; set; }
[ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsWindowStatus LyricsWindowStatus { get; set; }
public LiveStates(AppSettings appSettings)
public LiveStates()
{
LyricsWindowMode = LyricsWindowMode.StandardMode;
LyricsDisplayType = appSettings.StandardModeSettings.LyricsDisplayType;
LyricsStyleSettings = appSettings.StandardLyricsStyleSettings;
LyricsEffectSettings = appSettings.StandardLyricsEffectSettings;
IsAlwaysOnTop = false;
}
public void ToggleLyricsWindowMode(LyricsWindowMode mode)
{
if (LyricsWindowMode == mode)
{
LyricsWindowMode = LyricsWindowMode.StandardMode;
}
else
{
LyricsWindowMode = mode;
}
}
partial void OnLyricsWindowBoundsChanged(Rect value)
{
double factor = 0.1;
DemoLyricsWindowBounds = new Rect(
value.X * factor,
value.Y * factor,
value.Width * factor,
value.Height * factor
);
var lyricsWindow = WindowHelper.GetWindowByWindowType<Views.LyricsWindow>();
if (lyricsWindow == null) return;
var mointor = MonitorHelper.GetMonitorInfoExFromWindow(lyricsWindow);
LyricsWindowMonitorName = mointor.szDevice;
LyricsWindowMonitorBounds = new Rect(
mointor.rcMonitor.Left,
mointor.rcMonitor.Top,
mointor.rcMonitor.Width,
mointor.rcMonitor.Height
);
DemoLyricsWindowMonitorBounds = new Rect(
mointor.rcMonitor.Left * factor,
mointor.rcMonitor.Top * factor,
mointor.rcMonitor.Width * factor,
mointor.rcMonitor.Height * factor
);
LyricsWindowStatus = new LyricsWindowStatus();
}
}
}

View File

@@ -0,0 +1,283 @@
using BetterLyrics.WinUI3.Enums;
using BetterLyrics.WinUI3.Helper;
using BetterLyrics.WinUI3.Models.Settings;
using BetterLyrics.WinUI3.Views;
using CommunityToolkit.Mvvm.ComponentModel;
using Microsoft.UI.Windowing;
using System;
using Windows.Foundation;
namespace BetterLyrics.WinUI3.Models
{
public partial class LyricsWindowStatus : ObservableRecipient, ICloneable
{
[ObservableProperty][NotifyPropertyChangedRecipients] public partial string Name { get; set; } = string.Empty;
[ObservableProperty] public partial bool IsDefault { get; set; } = false;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial string MonitorDeviceName { get; set; } = string.Empty;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsWorkArea { get; set; } = false;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsBorderless { get; set; } = false;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsAlwaysOnTop { get; set; } = false;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsAlwaysOnTopPolling { get; set; } = false;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsShownInSwitchers { get; set; } = true;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsClickThrough { get; set; } = false;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsLayoutOrientation LyricsLayoutOrientation { get; set; } = LyricsLayoutOrientation.Horizontal;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsDisplayType LyricsDisplayType { get; set; } = LyricsDisplayType.SplitView;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial Rect WindowBounds { get; set; } = new Rect(100, 100, 800, 500);
[ObservableProperty][NotifyPropertyChangedRecipients] public partial double DockHeight { get; set; } = 64;
[ObservableProperty] public partial Rect DemoWindowBounds { get; set; }
[ObservableProperty] public partial Rect MonitorBounds { get; set; }
[ObservableProperty] public partial Rect DemoMonitorBounds { get; set; }
[ObservableProperty][NotifyPropertyChangedRecipients] public partial DockPlacement DockPlacement { get; set; } = DockPlacement.Top;
[ObservableProperty] public partial LyricsStyleSettings LyricsStyleSettings { get; set; } = new();
[ObservableProperty] public partial LyricsEffectSettings LyricsEffectSettings { get; set; } = new(500, 500, 500, EasingType.EaseInOutQuad);
[ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsBackgroundSettings LyricsBackgroundSettings { get; set; } = new();
[ObservableProperty][NotifyPropertyChangedRecipients] public partial AlbumArtLayoutSettings AlbumArtLayoutSettings { get; set; } = new();
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsAdaptToEnvironment { get; set; } = false;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial WindowPixelSampleMode EnvironmentSampleMode { get; set; } = WindowPixelSampleMode.WindowEdge;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool AutoShowOrHideWindow { get; set; } = false;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial TitleBarArea TitleBarArea { get; set; } = TitleBarArea.Top;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial double WindowX { get; set; } = 100;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial double WindowY { get; set; } = 100;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial double WindowWidth { get; set; } = 800;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial double WindowHeight { get; set; } = 500;
public LyricsWindowStatus()
{
UpdateMonitorNameAndBounds();
UpdateDemoWindowAndMonitorBounds();
}
partial void OnWindowXChanged(double value)
{
WindowBounds = WindowBounds.WithX(value);
}
partial void OnWindowYChanged(double value)
{
WindowBounds = WindowBounds.WithY(value);
}
partial void OnWindowWidthChanged(double value)
{
WindowBounds = WindowBounds.WithWidth(value);
}
partial void OnWindowHeightChanged(double value)
{
WindowBounds = WindowBounds.WithHeight(value);
}
partial void OnLyricsStyleSettingsChanged(LyricsStyleSettings oldValue, LyricsStyleSettings newValue)
{
oldValue.PropertyChanged -= OldLyricsStyleSettings_PropertyChanged;
newValue.PropertyChanged += OldLyricsStyleSettings_PropertyChanged;
}
partial void OnLyricsEffectSettingsChanged(LyricsEffectSettings oldValue, LyricsEffectSettings newValue)
{
oldValue.PropertyChanged -= OldLyricsEffectSettings_PropertyChanged;
newValue.PropertyChanged += OldLyricsEffectSettings_PropertyChanged;
}
partial void OnLyricsBackgroundSettingsChanged(LyricsBackgroundSettings oldValue, LyricsBackgroundSettings newValue)
{
oldValue.PropertyChanged -= OldLyricsBackgroundSettings_PropertyChanged;
newValue.PropertyChanged += OldLyricsBackgroundSettings_PropertyChanged;
}
partial void OnAlbumArtLayoutSettingsChanged(AlbumArtLayoutSettings oldValue, AlbumArtLayoutSettings newValue)
{
oldValue.PropertyChanged -= OldAlbumArtLayoutSettings_PropertyChanged;
newValue.PropertyChanged += OldAlbumArtLayoutSettings_PropertyChanged;
}
private void OldLyricsStyleSettings_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
{
this.OnPropertyChanged(nameof(LyricsStyleSettings));
}
private void OldLyricsEffectSettings_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
{
this.OnPropertyChanged(nameof(LyricsEffectSettings));
}
private void OldLyricsBackgroundSettings_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
{
this.OnPropertyChanged(nameof(LyricsBackgroundSettings));
}
private void OldAlbumArtLayoutSettings_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
{
this.OnPropertyChanged(nameof(AlbumArtLayoutSettings));
}
partial void OnWindowBoundsChanged(Rect value)
{
UpdateMonitorNameAndBounds();
UpdateDemoWindowAndMonitorBounds();
}
partial void OnAutoShowOrHideWindowChanged(bool value)
{
WindowHelper.SetLyricsWindowVisibilityByPlayingStatus();
}
public void UpdateMonitorNameAndBounds()
{
var lyricsWindow = WindowHelper.GetWindowByWindowType<LyricsWindow>();
if (lyricsWindow == null) return;
var mointor = MonitorHelper.GetMonitorInfoExFromWindow(lyricsWindow);
MonitorDeviceName = mointor.szDevice;
MonitorBounds = new Rect(
mointor.rcMonitor.Left,
mointor.rcMonitor.Top,
mointor.rcMonitor.Width,
mointor.rcMonitor.Height
);
}
public void UpdateDemoWindowAndMonitorBounds(double factor = 0.1)
{
DemoWindowBounds = new Rect(
(WindowBounds.X - MonitorBounds.Left) * factor,
(WindowBounds.Y - MonitorBounds.Top) * factor,
WindowBounds.Width * factor,
WindowBounds.Height * factor
);
DemoMonitorBounds = new Rect(
MonitorBounds.Left * factor,
MonitorBounds.Top * factor,
MonitorBounds.Width * factor,
MonitorBounds.Height * factor
);
}
public object Clone()
{
return new LyricsWindowStatus
{
Name = this.Name,
IsDefault = this.IsDefault,
MonitorDeviceName = this.MonitorDeviceName,
IsWorkArea = this.IsWorkArea,
IsBorderless = this.IsBorderless,
IsAlwaysOnTop = this.IsAlwaysOnTop,
IsAlwaysOnTopPolling = this.IsAlwaysOnTopPolling,
IsShownInSwitchers = this.IsShownInSwitchers,
IsClickThrough = this.IsClickThrough,
LyricsLayoutOrientation = this.LyricsLayoutOrientation,
LyricsDisplayType = this.LyricsDisplayType,
WindowBounds = this.WindowBounds,
DockHeight = this.DockHeight,
DemoWindowBounds = this.DemoWindowBounds,
MonitorBounds = this.MonitorBounds,
DemoMonitorBounds = this.DemoMonitorBounds,
LyricsStyleSettings = (LyricsStyleSettings)this.LyricsStyleSettings.Clone(),
LyricsEffectSettings = (LyricsEffectSettings)this.LyricsEffectSettings.Clone(),
LyricsBackgroundSettings = (LyricsBackgroundSettings)this.LyricsBackgroundSettings.Clone(),
AlbumArtLayoutSettings = (AlbumArtLayoutSettings)this.AlbumArtLayoutSettings.Clone(),
IsAdaptToEnvironment = this.IsAdaptToEnvironment,
EnvironmentSampleMode = this.EnvironmentSampleMode,
AutoShowOrHideWindow = this.AutoShowOrHideWindow,
TitleBarArea = this.TitleBarArea,
};
}
}
public static class LyricsWindowStatusExtensions
{
public static LyricsWindowStatus DesktopMode()
{
return new LyricsWindowStatus
{
Name = App.ResourceLoader!.GetString("DesktopMode"),
LyricsDisplayType = LyricsDisplayType.LyricsOnly,
WindowBounds = new Rect(100, 100, 600, 250),
IsAlwaysOnTop = true,
IsAlwaysOnTopPolling = true,
IsBorderless = true,
IsClickThrough = true,
IsAdaptToEnvironment = true,
EnvironmentSampleMode = WindowPixelSampleMode.WindowEdge,
LyricsStyleSettings = new()
{
LyricsFontSize = 20,
LyricsAlignmentType = TextAlignmentType.Center,
},
LyricsBackgroundSettings = new LyricsBackgroundSettings
{
IsPureColorOverlayEnabled = false,
IsCoverOverlayEnabled = false,
}
};
}
public static LyricsWindowStatus DockedMode()
{
return new LyricsWindowStatus
{
Name = App.ResourceLoader!.GetString("DockedMode"),
IsWorkArea = true,
IsAlwaysOnTop = true,
IsAlwaysOnTopPolling = true,
IsBorderless = true,
IsAdaptToEnvironment = true,
LyricsDisplayType = LyricsDisplayType.LyricsOnly,
EnvironmentSampleMode = WindowPixelSampleMode.BelowWindow,
TitleBarArea = TitleBarArea.None,
LyricsStyleSettings = new LyricsStyleSettings
{
LyricsAlignmentType = TextAlignmentType.Center,
LyricsFontSize = 18,
},
LyricsBackgroundSettings = new LyricsBackgroundSettings
{
IsCoverOverlayEnabled = false,
}
};
}
public static LyricsWindowStatus FullscreenMode(Rect monitorBounds)
{
return new LyricsWindowStatus
{
Name = App.ResourceLoader!.GetString("FullscreenMode"),
WindowBounds = monitorBounds,
IsAlwaysOnTop = true,
IsBorderless = true,
TitleBarArea = Enums.TitleBarArea.None,
LyricsLayoutOrientation = Enums.LyricsLayoutOrientation.Vertical,
LyricsStyleSettings = new LyricsStyleSettings
{
LyricsFontSize = 96,
LyricsAlignmentType = Enums.TextAlignmentType.Center,
},
AlbumArtLayoutSettings = new AlbumArtLayoutSettings
{
AutoAlbumArtSize = false,
AlbumArtSize = 148,
SongInfoFontSize = 48,
}
};
}
public static LyricsWindowStatus StandardMode()
{
return new LyricsWindowStatus
{
Name = App.ResourceLoader!.GetString("StandardMode"),
};
}
public static LyricsWindowStatus NarrowMode()
{
return new LyricsWindowStatus
{
Name = App.ResourceLoader!.GetString("NarrowMode"),
WindowBounds = new Rect(100, 100, 400, 800),
LyricsLayoutOrientation = LyricsLayoutOrientation.Vertical,
};
}
}
}

View File

@@ -36,8 +36,9 @@ namespace BetterLyrics.WinUI3.Models
PositionOffset = 0;
}
public MediaSourceProviderInfo(string provider) : base()
public MediaSourceProviderInfo(string provider, bool isEnable = true)
{
IsEnabled = isEnable;
switch (provider)
{
case Constants.PlayerID.AppleMusic:
@@ -53,6 +54,12 @@ namespace BetterLyrics.WinUI3.Models
}
Provider = provider;
AlbumArtSearchProvidersInfo.ItemPropertyChanged += AlbumArtSearchProvidersInfo_ItemPropertyChanged;
AlbumArtSearchProvidersInfo.CollectionChanged += AlbumArtSearchProvidersInfo_CollectionChanged;
LyricsSearchProvidersInfo.ItemPropertyChanged += LyricsSearchProvidersInfo_ItemPropertyChanged;
LyricsSearchProvidersInfo.CollectionChanged += LyricsSearchProvidersInfo_CollectionChanged;
}
partial void OnAlbumArtSearchProvidersInfoChanged(FullyObservableCollection<AlbumArtSearchProviderInfo> oldValue, FullyObservableCollection<AlbumArtSearchProviderInfo> newValue)

View File

@@ -8,13 +8,32 @@ using System.Threading.Tasks;
namespace BetterLyrics.WinUI3.Models.Settings
{
public partial class AlbumArtLayoutSettings : ObservableRecipient
public partial class AlbumArtLayoutSettings : ObservableRecipient, ICloneable
{
[ObservableProperty][NotifyPropertyChangedRecipients] public partial TextAlignmentType SongInfoAlignmentType { get; set; } = TextAlignmentType.Left;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int CoverImageRadius { get; set; } = 12; // 12 % of the cover image size
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int CoverImageShadowAmount { get; set; } = 12;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int SongInfoFontSize { get; set; } = 18;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool ShowTitle { get; set; } = true;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool ShowArtists { get; set; } = true;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int AlbumArtSize { get; set; } = 64;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool AutoAlbumArtSize { get; set; } = true;
public AlbumArtLayoutSettings() { }
public object Clone()
{
return new AlbumArtLayoutSettings
{
SongInfoAlignmentType = this.SongInfoAlignmentType,
CoverImageRadius = this.CoverImageRadius,
CoverImageShadowAmount = this.CoverImageShadowAmount,
SongInfoFontSize = this.SongInfoFontSize,
ShowTitle = this.ShowTitle,
ShowArtists = this.ShowArtists,
AlbumArtSize = this.AlbumArtSize,
AutoAlbumArtSize = this.AutoAlbumArtSize,
};
}
}
}

View File

@@ -10,23 +10,6 @@ namespace BetterLyrics.WinUI3.Models.Settings
{
public string Version { get; set; } = Helper.MetadataHelper.AppVersion;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsStyleSettings StandardLyricsStyleSettings { get; set; } = new LyricsStyleSettings(32, TextAlignmentType.Left, 0);
[ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsStyleSettings DesktopLyricsStyleSettings { get; set; } = new LyricsStyleSettings(28, TextAlignmentType.Center, 2);
[ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsStyleSettings DockLyricsStyleSettings { get; set; } = new LyricsStyleSettings(16, TextAlignmentType.Center, 0);
[ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsStyleSettings PictureInPictureLyricsStyleSettings { get; set; } = new LyricsStyleSettings(28, TextAlignmentType.Left, 0);
[ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsEffectSettings StandardLyricsEffectSettings { get; set; } = new LyricsEffectSettings(100, 500, 1000, EasingType.EaseInOutQuad);
[ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsEffectSettings DesktopLyricsEffectSettings { get; set; } = new LyricsEffectSettings(500, 500, 500, EasingType.EaseInOutQuad);
[ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsEffectSettings DockLyricsEffectSettings { get; set; } = new LyricsEffectSettings(500, 500, 500, EasingType.EaseInOutQuad);
[ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsEffectSettings PictureInPictureLyricsEffectSettings { get; set; } = new LyricsEffectSettings(500, 500, 500, EasingType.EaseInOutQuad);
[ObservableProperty][NotifyPropertyChangedRecipients] public partial StandardModeSettings StandardModeSettings { get; set; } = new StandardModeSettings();
[ObservableProperty][NotifyPropertyChangedRecipients] public partial DesktopModeSettings DesktopModeSettings { get; set; } = new DesktopModeSettings();
[ObservableProperty][NotifyPropertyChangedRecipients] public partial DockModeSettings DockModeSettings { get; set; } = new DockModeSettings();
[ObservableProperty][NotifyPropertyChangedRecipients] public partial PictureInPictureModeSettings PictureInPictureModeSettings { get; set; } = new PictureInPictureModeSettings();
[ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsBackgroundSettings LyricsBackgroundSettings { get; set; } = new LyricsBackgroundSettings();
[ObservableProperty][NotifyPropertyChangedRecipients] public partial AlbumArtLayoutSettings AlbumArtLayoutSettings { get; set; } = new AlbumArtLayoutSettings();
[ObservableProperty][NotifyPropertyChangedRecipients] public partial TranslationSettings TranslationSettings { get; set; } = new TranslationSettings();
[ObservableProperty][NotifyPropertyChangedRecipients] public partial GeneralSettings GeneralSettings { get; set; } = new GeneralSettings();
[ObservableProperty][NotifyPropertyChangedRecipients] public partial MusicGallerySettings MusicGallerySettings { get; set; } = new MusicGallerySettings();
@@ -35,7 +18,7 @@ namespace BetterLyrics.WinUI3.Models.Settings
[ObservableProperty][NotifyPropertyChangedRecipients] public partial FullyObservableCollection<LocalMediaFolder> LocalMediaFolders { get; set; } = [];
[ObservableProperty][NotifyPropertyChangedRecipients] public partial FullyObservableCollection<MediaSourceProviderInfo> MediaSourceProvidersInfo { get; set; } = [];
[ObservableProperty][NotifyPropertyChangedRecipients] public partial FullyObservableCollection<MappedSongSearchQuery> MappedSongSearchQueries { get; set; } = [];
[ObservableProperty][NotifyPropertyChangedRecipients] public partial FullyObservableCollection<WindowBoundsRecord> WindowBoundsRecords { get; set; } = [];
[ObservableProperty][NotifyPropertyChangedRecipients] public partial FullyObservableCollection<LyricsWindowStatus> WindowBoundsRecords { get; set; } = [];
public AppSettings() { }
}

View File

@@ -10,6 +10,5 @@ namespace BetterLyrics.WinUI3.Models.Settings
{
public partial class BaseModeSettings : ObservableRecipient
{
[ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsDisplayType LyricsDisplayType { get; set; }
}
}

View File

@@ -1,25 +0,0 @@
using CommunityToolkit.Mvvm.ComponentModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.Graphics;
namespace BetterLyrics.WinUI3.Models.Settings
{
public partial class DesktopModeSettings : BaseModeSettings
{
[ObservableProperty][NotifyPropertyChangedRecipients] public partial Rect WindowBounds { get; set; } = new Rect(100, 100, 400, 200);
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool AutoLockOnDesktopMode { get; set; } = false;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial List<string> LockShortcut { get; set; } = new List<string>() { "Ctrl", "Alt", "U" };
[ObservableProperty][NotifyPropertyChangedRecipients] public partial List<string> ToggleShortcut { get; set; } = new List<string>() { "Ctrl", "Alt", "D" };
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsAlwaysOnTop { get; set; } = true;
public DesktopModeSettings()
{
LyricsDisplayType = Enums.LyricsDisplayType.LyricsOnly;
}
}
}

View File

@@ -1,24 +0,0 @@
using BetterLyrics.WinUI3.Enums;
using BetterLyrics.WinUI3.Helper;
using CommunityToolkit.Mvvm.ComponentModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BetterLyrics.WinUI3.Models.Settings
{
public partial class DockModeSettings : BaseModeSettings
{
[ObservableProperty][NotifyPropertyChangedRecipients] public partial DockPlacement DockPlacement { get; set; } = DockPlacement.Top;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int DockWindowHeight { get; set; } = 64;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial string DockMonitorDeviceName { get; set; } = MonitorHelper.GetPrimaryMonitorDeviceName();
[ObservableProperty][NotifyPropertyChangedRecipients] public partial List<string> ToggleShortcut { get; set; } = new List<string> { "Ctrl", "Shift", "D" };
public DockModeSettings()
{
LyricsDisplayType = LyricsDisplayType.LyricsOnly;
}
}
}

View File

@@ -10,15 +10,14 @@ namespace BetterLyrics.WinUI3.Models.Settings
{
public partial class GeneralSettings : ObservableRecipient
{
[ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsWindowMode AutoStartWindowType { get; set; } = LyricsWindowMode.StandardMode;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial Language Language { get; set; } = Language.FollowSystem;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IgnoreFullscreenWindow { get; set; } = false;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial string LXMusicServer { get; set; } = string.Empty;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool HideWindowWhenNotPlaying { get; set; } = true;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial List<string> ShowOrHideLyricsWindowShortcut { get; set; } = new List<string> { "Ctrl", "Alt", "H" };
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsDragEverywhereEnabled { get; set; } = false;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsImmersiveMode { get; set; } = false;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool ExitOnLyricsWindowClosed { get; set; } = true;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool ExitOnLyricsWindowClosed { get; set; } = false;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool ListenOnNewPlaybackSource { get; set; } = true;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial List<string> BorderlessShortcut { get; set; } = new List<string>() { "Ctrl", "Alt", "B" };
[ObservableProperty][NotifyPropertyChangedRecipients] public partial List<string> ClickThroughShortcut { get; set; } = new List<string>() { "Ctrl", "Alt", "C" };
[ObservableProperty][NotifyPropertyChangedRecipients] public partial List<string> LyricsWindowSwitchShortcut { get; set; } = new List<string>() { "Ctrl", "Alt", "S" };
[ObservableProperty][NotifyPropertyChangedRecipients] public partial List<string> PlayOrPauseShortcut { get; set; } = new List<string> { "Ctrl", "Alt", "P" };
[ObservableProperty][NotifyPropertyChangedRecipients] public partial List<string> NextSongShortcut { get; set; } = new List<string> { "Ctrl", "Alt", "Right" };
[ObservableProperty][NotifyPropertyChangedRecipients] public partial List<string> PreviousSongShortcut { get; set; } = new List<string> { "Ctrl", "Alt", "Left" };

View File

@@ -1,4 +1,5 @@
using CommunityToolkit.Mvvm.ComponentModel;
using BetterLyrics.WinUI3.Enums;
using CommunityToolkit.Mvvm.ComponentModel;
using Microsoft.UI.Xaml;
using System;
using System.Collections.Generic;
@@ -8,15 +9,37 @@ using System.Threading.Tasks;
namespace BetterLyrics.WinUI3.Models.Settings
{
public partial class LyricsBackgroundSettings : ObservableRecipient
public partial class LyricsBackgroundSettings : ObservableRecipient, ICloneable
{
[ObservableProperty][NotifyPropertyChangedRecipients] public partial ElementTheme LyricsBackgroundTheme { get; set; } = ElementTheme.Dark;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsPureColorOverlayEnabled { get; set; } = true;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int PureColorOverlayOpacity { get; set; } = 100; // 100 % = 1.0
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsCoverOverlayEnabled { get; set; } = true;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int CoverOverlayBlurAmount { get; set; } = 100; // 100 % of the cover image size
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int CoverOverlayOpacity { get; set; } = 100; // 100 % = 1.0
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int PureColorOverlayOpacity { get; set; } = 100; // 100 % = 1.0
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int CoverOverlaySpeed { get; set; } = 50; // 50 % of the base rotate speed
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int CoverAcrylicEffectAmount { get; set; } = 0;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsFluidOverlayEnabled { get; set; } = false;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int FluidOverlayOpacity { get; set; } = 100;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsSpectrumOverlayEnabled { get; set; } = false;
public LyricsBackgroundSettings() { }
public object Clone()
{
return new LyricsBackgroundSettings
{
LyricsBackgroundTheme = this.LyricsBackgroundTheme,
CoverOverlayBlurAmount = this.CoverOverlayBlurAmount,
CoverOverlayOpacity = this.CoverOverlayOpacity,
PureColorOverlayOpacity = this.PureColorOverlayOpacity,
CoverOverlaySpeed = this.CoverOverlaySpeed,
CoverAcrylicEffectAmount = this.CoverAcrylicEffectAmount,
};
}
}
}

View File

@@ -8,7 +8,7 @@ using System.Threading.Tasks;
namespace BetterLyrics.WinUI3.Models.Settings
{
public partial class LyricsEffectSettings : ObservableRecipient
public partial class LyricsEffectSettings : ObservableRecipient, ICloneable
{
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int LyricsBlurAmount { get; set; } = 5;
@@ -47,5 +47,29 @@ namespace BetterLyrics.WinUI3.Models.Settings
LyricsScrollBottomDuration = lyricsScrollBottomDuration;
LyricsScrollEasingType = lyricsScrollEasingType;
}
public object Clone()
{
return new LyricsEffectSettings(this.LyricsScrollTopDuration, this.LyricsScrollDuration, this.LyricsScrollBottomDuration, this.LyricsScrollEasingType)
{
LyricsBlurAmount = this.LyricsBlurAmount,
IsLyricsLineFadeEnabled = this.IsLyricsLineFadeEnabled,
IsLyricsGlowEffectEnabled = this.IsLyricsGlowEffectEnabled,
LyricsGlowEffectScope = this.LyricsGlowEffectScope,
LyricsGlowEffectAmount = this.LyricsGlowEffectAmount,
IsLyricsShadowEnabled = this.IsLyricsShadowEnabled,
LyricsShadowScope = this.LyricsShadowScope,
LyricsShadowAmount = this.LyricsShadowAmount,
LyricsHighlightScope = this.LyricsHighlightScope,
LyricsHighlightAmount = this.LyricsHighlightAmount,
LyricsTranslationHighlightAmount = this.LyricsTranslationHighlightAmount,
IsLyricsFloatAnimationEnabled = this.IsLyricsFloatAnimationEnabled,
LyricsFloatAmount = this.LyricsFloatAmount,
LyricsScrollTopDelay = this.LyricsScrollTopDelay,
LyricsScrollBottomDelay = this.LyricsScrollBottomDelay,
LyricsVerticalEdgeOpacity = this.LyricsVerticalEdgeOpacity,
IsFanLyricsEnabled = this.IsFanLyricsEnabled
};
}
}
}

View File

@@ -11,13 +11,13 @@ using Windows.UI;
namespace BetterLyrics.WinUI3.Models.Settings
{
public partial class LyricsStyleSettings : ObservableRecipient
public partial class LyricsStyleSettings : ObservableRecipient, ICloneable
{
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsDynamicLyricsFontSize { get; set; } = false;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int LyricsFontSize { get; set; }
[ObservableProperty][NotifyPropertyChangedRecipients] public partial TextAlignmentType LyricsAlignmentType { get; set; }
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int LyricsFontSize { get; set; } = 24;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial TextAlignmentType LyricsAlignmentType { get; set; } = TextAlignmentType.Left;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int LyricsBgFontOpacity { get; set; } = 30; // 30% opacity
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int LyricsFontStrokeWidth { get; set; }
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int LyricsFontStrokeWidth { get; set; } = 0;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial Color LyricsCustomBgFontColor { get; set; } = Colors.White;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial Color LyricsCustomFgFontColor { get; set; } = Colors.White;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial Color LyricsCustomStrokeFontColor { get; set; } = Colors.White;
@@ -37,5 +37,27 @@ namespace BetterLyrics.WinUI3.Models.Settings
LyricsAlignmentType = lyricsAlignmentType;
LyricsFontStrokeWidth = lyricsFontStrokeWidth;
}
public object Clone()
{
return new LyricsStyleSettings
{
IsDynamicLyricsFontSize = this.IsDynamicLyricsFontSize,
LyricsFontSize = this.LyricsFontSize,
LyricsAlignmentType = this.LyricsAlignmentType,
LyricsBgFontOpacity = this.LyricsBgFontOpacity,
LyricsFontStrokeWidth = this.LyricsFontStrokeWidth,
LyricsCustomBgFontColor = this.LyricsCustomBgFontColor,
LyricsCustomFgFontColor = this.LyricsCustomFgFontColor,
LyricsCustomStrokeFontColor = this.LyricsCustomStrokeFontColor,
LyricsBgFontColorType = this.LyricsBgFontColorType,
LyricsFgFontColorType = this.LyricsFgFontColorType,
LyricsStrokeFontColorType = this.LyricsStrokeFontColorType,
LyricsFontWeight = this.LyricsFontWeight,
LyricsLineSpacingFactor = this.LyricsLineSpacingFactor,
LyricsTranslationSeparator = this.LyricsTranslationSeparator,
LyricsFontFamily = this.LyricsFontFamily
};
}
}
}

View File

@@ -1,21 +0,0 @@
using CommunityToolkit.Mvvm.ComponentModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Foundation;
namespace BetterLyrics.WinUI3.Models.Settings
{
public partial class PictureInPictureModeSettings : BaseModeSettings
{
[ObservableProperty][NotifyPropertyChangedRecipients] public partial Point WindowPosition { get; set; } = new Point(100, 100);
[ObservableProperty][NotifyPropertyChangedRecipients] public partial List<string> ToggleShortcut { get; set; } = new List<string>() { "Ctrl", "Shift", "P" };
public PictureInPictureModeSettings()
{
LyricsDisplayType = Enums.LyricsDisplayType.SplitView;
}
}
}

View File

@@ -1,24 +0,0 @@
using BetterLyrics.WinUI3.Enums;
using CommunityToolkit.Mvvm.ComponentModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.Graphics;
namespace BetterLyrics.WinUI3.Models.Settings
{
public partial class StandardModeSettings : BaseModeSettings
{
[ObservableProperty][NotifyPropertyChangedRecipients] public partial Rect WindowBounds { get; set; } = new Rect(100, 100, 1000, 600);
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsMaximized { get; set; } = false;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsAlwaysOnTop { get; set; } = false;
public StandardModeSettings()
{
LyricsDisplayType = LyricsDisplayType.SplitView;
}
}
}

View File

@@ -15,7 +15,7 @@ namespace BetterLyrics.WinUI3.Models.Settings
[ObservableProperty][NotifyPropertyChangedRecipients] public partial string LibreTranslateServer { get; set; } = string.Empty;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsTranslationEnabled { get; set; } = true;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool ShowTranslationOnly { get; set; } = false;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int SelectedTargetLanguageIndex { get; set; } = LanguageHelper.GetDefaultTargetLanguageIndex();
[ObservableProperty][NotifyPropertyChangedRecipients] public partial string SelectedTargetLanguageCode { get; set; } = LanguageHelper.GetDefaultTargetLanguageCode();
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsJyutpingEnabled { get; set; } = false;
[ObservableProperty][NotifyPropertyChangedRecipients] public partial ChineseRomanization ChineseRomanization { get; set; }
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsChineseRomanizationEnabled { get; set; } = false;

View File

@@ -21,11 +21,14 @@ namespace BetterLyrics.WinUI3.Models
public partial double? DurationMs { get; set; }
[ObservableProperty]
public partial string? SourceAppUserModelId { get; set; } = null;
public partial string? PlayerId { get; set; } = null;
[ObservableProperty]
public partial string Title { get; set; }
[ObservableProperty]
public partial string? SongId { get; set; } = null;
public SongInfo() { }
}
}

View File

@@ -1,19 +0,0 @@
using CommunityToolkit.Mvvm.ComponentModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Foundation;
namespace BetterLyrics.WinUI3.Models
{
public partial class WindowBoundsRecord : ObservableObject
{
[ObservableProperty] public partial string MonitorDeviceName { get; set; } = string.Empty;
[ObservableProperty] public partial Rect WindowBounds { get; set; }
[ObservableProperty] public partial Rect DemoWindowBounds { get; set; }
[ObservableProperty] public partial Rect MonitorBounds { get; set; }
[ObservableProperty] public partial Rect DemoMonitorBounds { get; set; }
}
}

View File

@@ -14,6 +14,7 @@
<Grid>
<canvas:CanvasAnimatedControl
x:Name="LyricsCanvas"
CreateResources="LyricsCanvas_CreateResources"
Draw="LyricsCanvas_Draw"
Update="LyricsCanvas_Update" />
</Grid>

View File

@@ -2,7 +2,11 @@
using BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel;
using CommunityToolkit.Mvvm.DependencyInjection;
using CommunityToolkit.WinUI;
using Microsoft.Graphics.Canvas.Effects;
using Microsoft.UI.Xaml.Controls;
using Windows.Storage;
using Windows.Storage.Streams;
namespace BetterLyrics.WinUI3.Renderer
{
@@ -31,5 +35,10 @@ namespace BetterLyrics.WinUI3.Renderer
LyricsCanvas.RemoveFromVisualTree();
LyricsCanvas = null;
}
private async void LyricsCanvas_CreateResources(Microsoft.Graphics.Canvas.UI.Xaml.CanvasAnimatedControl sender, Microsoft.Graphics.Canvas.UI.CanvasCreateResourcesEventArgs args)
{
await ViewModel.CreateResourcesAsync(sender);
}
}
}

View File

@@ -10,5 +10,6 @@ namespace BetterLyrics.WinUI3.Services.LiveStatesService
public interface ILiveStatesService
{
LiveStates LiveStates { get; set; }
void RefreshLyricsWindowStatus();
}
}

View File

@@ -1,139 +1,138 @@
using BetterLyrics.WinUI3.Enums;
using BetterLyrics.WinUI3.Helper;
using BetterLyrics.WinUI3.Models;
using BetterLyrics.WinUI3.Models.Settings;
using BetterLyrics.WinUI3.Services.SettingsService;
using BetterLyrics.WinUI3.ViewModels;
using CommunityToolkit.Mvvm.Messaging;
using CommunityToolkit.Mvvm.Messaging.Messages;
using System;
using System.Collections.Generic;
using BetterLyrics.WinUI3.Views;
using CommunityToolkit.WinUI.Controls;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BetterLyrics.WinUI3.Services.LiveStatesService
{
public class LiveStatesService : BaseViewModel, ILiveStatesService,
IRecipient<PropertyChangedMessage<LyricsWindowMode>>,
IRecipient<PropertyChangedMessage<LyricsDisplayType>>,
IRecipient<PropertyChangedMessage<bool>>
public partial class LiveStatesService : BaseViewModel, ILiveStatesService
{
private readonly ISettingsService _settingsService;
public LiveStates LiveStates { get; set; }
public LiveStates LiveStates { get; set; } = new();
public LiveStatesService(ISettingsService settingsService)
{
_settingsService = settingsService;
LiveStates = new LiveStates(_settingsService.AppSettings);
LiveStates.PropertyChanged += LiveStates_PropertyChanged;
LiveStates.PropertyChanging += LiveStates_PropertyChanging;
InitLyricsWindowStatus();
}
public void Receive(PropertyChangedMessage<LyricsWindowMode> message)
private void LiveStates_PropertyChanging(object? sender, System.ComponentModel.PropertyChangingEventArgs e)
{
if (message.Sender is LiveStates)
if (e.PropertyName == nameof(LiveStates.LyricsWindowStatus))
{
if (message.PropertyName == nameof(LiveStates.LyricsWindowMode))
{
switch (message.NewValue)
{
case LyricsWindowMode.StandardMode:
LiveStates.LyricsStyleSettings = _settingsService.AppSettings.StandardLyricsStyleSettings;
LiveStates.LyricsEffectSettings = _settingsService.AppSettings.StandardLyricsEffectSettings;
LiveStates.LyricsDisplayType = _settingsService.AppSettings.StandardModeSettings.LyricsDisplayType;
LiveStates.IsAlwaysOnTop = _settingsService.AppSettings.StandardModeSettings.IsAlwaysOnTop;
break;
case LyricsWindowMode.DockMode:
LiveStates.LyricsStyleSettings = _settingsService.AppSettings.DockLyricsStyleSettings;
LiveStates.LyricsEffectSettings = _settingsService.AppSettings.DockLyricsEffectSettings;
LiveStates.LyricsDisplayType = _settingsService.AppSettings.DockModeSettings.LyricsDisplayType;
LiveStates.IsAlwaysOnTop = true;
break;
case LyricsWindowMode.DesktopMode:
LiveStates.LyricsStyleSettings = _settingsService.AppSettings.DesktopLyricsStyleSettings;
LiveStates.LyricsEffectSettings = _settingsService.AppSettings.DesktopLyricsEffectSettings;
LiveStates.LyricsDisplayType = _settingsService.AppSettings.DesktopModeSettings.LyricsDisplayType;
LiveStates.IsAlwaysOnTop = _settingsService.AppSettings.DesktopModeSettings.IsAlwaysOnTop;
break;
case LyricsWindowMode.PictureInPictureMode:
LiveStates.LyricsStyleSettings = _settingsService.AppSettings.PictureInPictureLyricsStyleSettings;
LiveStates.LyricsEffectSettings = _settingsService.AppSettings.PictureInPictureLyricsEffectSettings;
LiveStates.LyricsDisplayType = _settingsService.AppSettings.PictureInPictureModeSettings.LyricsDisplayType;
// IsAlwaysOnTop 由系统托管
break;
default:
break;
}
}
LiveStates.LyricsWindowStatus.PropertyChanged -= LyricsWindowStatus_PropertyChanged;
}
}
public void Receive(PropertyChangedMessage<LyricsDisplayType> message)
private void LyricsWindowStatus_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (message.Sender is StandardModeSettings)
switch (e.PropertyName)
{
if (message.PropertyName == nameof(StandardModeSettings.LyricsDisplayType))
{
if (LiveStates.LyricsWindowMode == LyricsWindowMode.StandardMode)
case nameof(LyricsWindowStatus.IsWorkArea):
WindowHelper.SetIsWorkArea<LyricsWindow>(LiveStates.LyricsWindowStatus.IsWorkArea);
if (LiveStates.LyricsWindowStatus.IsWorkArea)
{
LiveStates.LyricsDisplayType = message.NewValue;
UpdateWindowBoundsWhenWorkArea();
}
}
}
else if (message.Sender is DockModeSettings)
{
if (message.PropertyName == nameof(DockModeSettings.LyricsDisplayType))
{
if (LiveStates.LyricsWindowMode == LyricsWindowMode.DockMode)
break;
case nameof(LyricsWindowStatus.DockHeight):
case nameof(LyricsWindowStatus.DockPlacement):
case nameof(LyricsWindowStatus.MonitorDeviceName):
WindowHelper.UpdateWorkArea<LyricsWindow>();
if (LiveStates.LyricsWindowStatus.IsWorkArea)
{
LiveStates.LyricsDisplayType = message.NewValue;
UpdateWindowBoundsWhenWorkArea();
}
}
}
else if (message.Sender is DesktopModeSettings)
{
if (message.PropertyName == nameof(DesktopModeSettings.LyricsDisplayType))
{
if (LiveStates.LyricsWindowMode == LyricsWindowMode.DesktopMode)
{
LiveStates.LyricsDisplayType = message.NewValue;
}
}
}
else if (message.Sender is PictureInPictureModeSettings)
{
if (message.PropertyName == nameof(PictureInPictureModeSettings.LyricsDisplayType))
{
if (LiveStates.LyricsWindowMode == LyricsWindowMode.PictureInPictureMode)
{
LiveStates.LyricsDisplayType = message.NewValue;
}
}
break;
case nameof(LyricsWindowStatus.IsShownInSwitchers):
WindowHelper.SetIsShowInSwitchers<LyricsWindow>(LiveStates.LyricsWindowStatus.IsShownInSwitchers);
break;
case nameof(LyricsWindowStatus.IsAlwaysOnTop):
WindowHelper.SetIsAlwaysOnTop<LyricsWindow>(LiveStates.LyricsWindowStatus.IsAlwaysOnTop);
break;
case nameof(LyricsWindowStatus.IsClickThrough):
WindowHelper.SetIsClickThrough<LyricsWindow>(LiveStates.LyricsWindowStatus.IsClickThrough);
break;
case nameof(LyricsWindowStatus.IsBorderless):
WindowHelper.SetIsBorderless<LyricsWindow>(LiveStates.LyricsWindowStatus.IsBorderless);
break;
case nameof(LyricsWindowStatus.WindowBounds):
WindowHelper.MoveAndResize<LyricsWindow>(LiveStates.LyricsWindowStatus.WindowBounds);
break;
case nameof(LyricsWindowStatus.TitleBarArea):
WindowHelper.SetTitleBarArea<LyricsWindow>(LiveStates.LyricsWindowStatus.TitleBarArea);
break;
default:
break;
}
}
public void Receive(PropertyChangedMessage<bool> message)
private void LiveStates_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (message.Sender is StandardModeSettings)
if (e.PropertyName == nameof(LiveStates.LyricsWindowStatus))
{
if (message.PropertyName == nameof(StandardModeSettings.IsAlwaysOnTop))
{
if (LiveStates.LyricsWindowMode == LyricsWindowMode.StandardMode)
{
LiveStates.IsAlwaysOnTop = message.NewValue;
}
}
LiveStates.LyricsWindowStatus.PropertyChanged += LyricsWindowStatus_PropertyChanged;
RefreshLyricsWindowStatus();
}
else if (message.Sender is DesktopModeSettings)
}
private void InitLyricsWindowStatus()
{
var defaultLyricsWindowStatus = _settingsService.AppSettings.WindowBoundsRecords.FirstOrDefault(x => x.IsDefault);
if (defaultLyricsWindowStatus == null)
{
if (message.PropertyName == nameof(DesktopModeSettings.IsAlwaysOnTop))
{
if (LiveStates.LyricsWindowMode == LyricsWindowMode.DesktopMode)
{
LiveStates.IsAlwaysOnTop = message.NewValue;
}
}
defaultLyricsWindowStatus = LyricsWindowStatusExtensions.StandardMode();
defaultLyricsWindowStatus.IsDefault = true;
_settingsService.AppSettings.WindowBoundsRecords.Add(defaultLyricsWindowStatus);
}
LiveStates.LyricsWindowStatus = defaultLyricsWindowStatus;
}
public void RefreshLyricsWindowStatus()
{
WindowHelper.SetIsWorkArea<LyricsWindow>(LiveStates.LyricsWindowStatus.IsWorkArea);
if (LiveStates.LyricsWindowStatus.IsWorkArea)
{
UpdateWindowBoundsWhenWorkArea();
}
WindowHelper.MoveAndResize<LyricsWindow>(LiveStates.LyricsWindowStatus.WindowBounds);
LiveStates.LyricsWindowStatus.UpdateMonitorNameAndBounds();
LiveStates.LyricsWindowStatus.UpdateDemoWindowAndMonitorBounds();
WindowHelper.SetIsShowInSwitchers<LyricsWindow>(LiveStates.LyricsWindowStatus.IsShownInSwitchers);
WindowHelper.SetIsAlwaysOnTop<LyricsWindow>(LiveStates.LyricsWindowStatus.IsAlwaysOnTop);
WindowHelper.SetIsClickThrough<LyricsWindow>(LiveStates.LyricsWindowStatus.IsClickThrough);
WindowHelper.SetIsBorderless<LyricsWindow>(LiveStates.LyricsWindowStatus.IsBorderless);
WindowHelper.SetLyricsWindowVisibilityByPlayingStatus();
WindowHelper.SetTitleBarArea<LyricsWindow>(LiveStates.LyricsWindowStatus.TitleBarArea);
}
private void UpdateWindowBoundsWhenWorkArea()
{
LiveStates.LyricsWindowStatus.WindowBounds = new Windows.Foundation.Rect(
LiveStates.LyricsWindowStatus.MonitorBounds.X,
LiveStates.LyricsWindowStatus.DockPlacement switch
{
Enums.DockPlacement.Top => LiveStates.LyricsWindowStatus.MonitorBounds.Top,
Enums.DockPlacement.Bottom => LiveStates.LyricsWindowStatus.MonitorBounds.Bottom - LiveStates.LyricsWindowStatus.DockHeight - 1,
_ => LiveStates.LyricsWindowStatus.MonitorBounds.Top,
},
LiveStates.LyricsWindowStatus.MonitorBounds.Width,
LiveStates.LyricsWindowStatus.DockPlacement switch
{
Enums.DockPlacement.Top => LiveStates.LyricsWindowStatus.DockHeight,
Enums.DockPlacement.Bottom => LiveStates.LyricsWindowStatus.DockHeight + 1,
_ => LiveStates.LyricsWindowStatus.DockHeight,
}
);
}
}
}

View File

@@ -11,7 +11,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
{
public interface ILyricsSearchService
{
Task<LyricsSearchResult> SearchSmartlyAsync(string mediaSessionId, string title, string artist, string album, double durationMs, CancellationToken token);
Task<LyricsSearchResult> SearchSmartlyAsync(string mediaSessionId, string title, string artist, string album, double durationMs, string? songId, CancellationToken token);
Task<List<LyricsSearchResult>> SearchAllAsync(string title, string artist, string album, double durationMs, CancellationToken token);
}

View File

@@ -28,6 +28,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
{
private readonly HttpClient _amllTtmlDbHttpClient;
private readonly HttpClient _lrcLibHttpClient;
private readonly AppleMusic _appleMusic;
private readonly ISettingsService _settingsService;
private readonly ILogger _logger;
@@ -43,6 +44,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
$"{Constants.App.AppName} {MetadataHelper.AppVersion} ({Constants.Link.GitHubUrl})"
);
_amllTtmlDbHttpClient = new();
_appleMusic = new AppleMusic();
}
private static bool IsAmllTtmlDbIndexInvalid()
@@ -89,7 +91,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
}
}
public async Task<LyricsSearchResult> SearchSmartlyAsync(string mediaSessionId, string title, string artist, string album, double durationMs, CancellationToken token)
public async Task<LyricsSearchResult> SearchSmartlyAsync(string mediaSessionId, string title, string artist, string album, double durationMs, string? songId, CancellationToken token)
{
var lyricsSearchResult = new LyricsSearchResult();
@@ -121,7 +123,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
var targetProvider = found.LyricsSearchProvider;
if (targetProvider != null)
{
return await SearchSingleAsync(targetProvider.Value, overridenTitle, overridenArtist, album, durationMs, token);
return await SearchSingleAsync(targetProvider.Value, overridenTitle, overridenArtist, album, durationMs, songId, token);
}
}
@@ -132,7 +134,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
continue;
}
lyricsSearchResult = await SearchSingleAsync(provider.Provider, overridenTitle, overridenArtist, album, durationMs, token);
lyricsSearchResult = await SearchSingleAsync(provider.Provider, overridenTitle, overridenArtist, album, durationMs, null, token);
if (lyricsSearchResult.IsFound)
{
@@ -149,13 +151,13 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
var results = new List<LyricsSearchResult>();
foreach (var provider in Enum.GetValues<LyricsSearchProvider>())
{
var searchResult = await SearchSingleAsync(provider, title, artist, album, durationMs, token);
var searchResult = await SearchSingleAsync(provider, title, artist, album, durationMs, null, token);
results.Add(searchResult);
}
return results;
}
private async Task<LyricsSearchResult> SearchSingleAsync(LyricsSearchProvider provider, string title, string artist, string album, double durationMs, CancellationToken token)
private async Task<LyricsSearchResult> SearchSingleAsync(LyricsSearchProvider provider, string title, string artist, string album, double durationMs, string? songId, CancellationToken token)
{
var lyricsSearchResult = new LyricsSearchResult
{
@@ -198,17 +200,20 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
lyricsSearchResult = await SearchLrcLibAsync(title, artist, album, (int)(durationMs / 1000));
break;
case LyricsSearchProvider.QQ:
lyricsSearchResult = await SearchQQNeteaseKugouAsync(title, artist, album, (int)durationMs, Searchers.QQMusic);
lyricsSearchResult = await SearchQQNeteaseKugouAsync(title, artist, album, (int)durationMs, songId, Searchers.QQMusic);
break;
case LyricsSearchProvider.Kugou:
lyricsSearchResult = await SearchQQNeteaseKugouAsync(title, artist, album, (int)durationMs, Searchers.Kugou);
lyricsSearchResult = await SearchQQNeteaseKugouAsync(title, artist, album, (int)durationMs, songId, Searchers.Kugou);
break;
case LyricsSearchProvider.Netease:
lyricsSearchResult = await SearchQQNeteaseKugouAsync(title, artist, album, (int)durationMs, Searchers.Netease);
lyricsSearchResult = await SearchQQNeteaseKugouAsync(title, artist, album, (int)durationMs, songId, Searchers.Netease);
break;
case LyricsSearchProvider.AmllTtmlDb:
lyricsSearchResult = await SearchAmllTtmlDbAsync(title, artist);
break;
case LyricsSearchProvider.AppleMusic:
lyricsSearchResult = await SearchAppleMusicAsync(title, artist, album, (int)durationMs);
break;
default:
break;
}
@@ -431,7 +436,7 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
return lyricsSearchResult;
}
private static async Task<LyricsSearchResult> SearchQQNeteaseKugouAsync(string title, string artist, string album, int durationMs, Searchers searchers)
private static async Task<LyricsSearchResult> SearchQQNeteaseKugouAsync(string title, string artist, string album, int durationMs, string? songId, Searchers searchers)
{
var lyricsSearchResult = new LyricsSearchResult();
@@ -452,15 +457,23 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
break;
}
var result = await SearchersHelper.GetSearcher(searchers).SearchForResult(
new Lyricify.Lyrics.Models.TrackMultiArtistMetadata()
{
DurationMs = durationMs,
Album = album,
Artists = [artist],
Title = title,
}
);
ISearchResult? result;
if (searchers == Searchers.Netease && songId != null)
{
result = new NeteaseSearchResult(title, [artist], album, null, durationMs, songId);
}
else
{
result = await SearchersHelper.GetSearcher(searchers).SearchForResult(
new Lyricify.Lyrics.Models.TrackMultiArtistMetadata()
{
DurationMs = durationMs,
Album = album,
Artists = [artist],
Title = title,
}
);
}
if (result is QQMusicSearchResult qqResult)
{
@@ -508,7 +521,21 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
string? original = null;
if (response?.Candidates.FirstOrDefault() is SearchLyricsResponse.Candidate candidate)
{
original = Lyricify.Lyrics.Decrypter.Krc.Helper.GetLyrics(candidate.Id, candidate.AccessKey);
original = await Lyricify.Lyrics.Decrypter.Krc.Helper.GetLyricsAsync(candidate.Id, candidate.AccessKey);
if (candidate.TransId != null)
{
string? translated = await Lyricify.Lyrics.Decrypter.Krc.Helper.GetLyricsAsync(candidate.TransId, candidate.AccessKey);
if (!string.IsNullOrEmpty(translated))
{
FileHelper.WriteLyricsCache(
title,
artist,
translated,
LyricsFormat.Lrc,
PathHelper.KugouTranslationCacheDirectory
);
}
}
}
lyricsSearchResult.Raw = original;
@@ -518,5 +545,24 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService
return lyricsSearchResult;
}
private async Task<LyricsSearchResult> SearchAppleMusicAsync(string title, string artist, string album, int durationMs)
{
var lyricsSearchResult = new LyricsSearchResult
{
Provider = LyricsSearchProvider.AppleMusic,
};
if (await _appleMusic.InitAsync())
{
var raw = await _appleMusic.GetLyricsAsync(title, artist);
_logger.LogInformation("Apple Music lyrics search result for {Title} - {Artist}: {Raw}", title, artist, raw ?? "null");
lyricsSearchResult.Raw = raw;
lyricsSearchResult.Title = title;
lyricsSearchResult.Artist = artist;
}
return lyricsSearchResult;
}
}
}

View File

@@ -27,6 +27,9 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
MediaSourceProviderInfo? GetCurrentMediaSourceProviderInfo();
void UpdateLyrics();
void UpdateTranslations();
bool IsPlaying { get; }
SongInfo? SongInfo { get; }
TimeSpan Position { get; }

View File

@@ -34,7 +34,7 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
}
byte[]? bytes = await Task.Run(async () => await _albumArtSearchService.SearchAsync(
SongInfo?.SourceAppUserModelId ?? "",
SongInfo?.PlayerId ?? "",
_cachedSongInfo.Title,
_cachedSongInfo.Artist,
_cachedSongInfo?.Album ?? string.Empty,
@@ -62,10 +62,10 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
albumArtSwBitmap = SoftwareBitmap.Copy(albumArtSwBitmap);
token.ThrowIfCancellationRequested();
var albumArtLightAccentColor = ImageHelper.GetAccentColorsFromByte(bytes, 1, false).FirstOrDefault();
var albumArtDarkAccentColor = ImageHelper.GetAccentColorsFromByte(bytes, 1, true).FirstOrDefault();
var albumArtLightAccentColors = ImageHelper.GetAccentColorsFromByte(bytes, 4, false);
var albumArtDarkAccentColors = ImageHelper.GetAccentColorsFromByte(bytes, 4, true);
AlbumArtChanged?.Invoke(this, new AlbumArtChangedEventArgs(null, albumArtSwBitmap, albumArtLightAccentColor, albumArtDarkAccentColor));
AlbumArtChanged?.Invoke(this, new AlbumArtChangedEventArgs(null, albumArtSwBitmap, albumArtLightAccentColors, albumArtDarkAccentColors));
}
}
}

View File

@@ -58,7 +58,7 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
private async Task SetDisplayedAlongWithTranslationsAsync(CancellationToken token)
{
_logger.LogInformation("Showing translation for lyrics...");
string targetLangCode = LanguageHelper.SupportedTargetLanguages[_settingsService.AppSettings.TranslationSettings.SelectedTargetLanguageIndex].Code;
string targetLangCode = _settingsService.AppSettings.TranslationSettings.SelectedTargetLanguageCode;
_logger.LogInformation("Target language code: {TargetLangCode}", targetLangCode);
string? originalText = _lyricsDataArr.FirstOrDefault()?.WrappedOriginalText;
if (originalText == null) return;
@@ -105,7 +105,7 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
}
else
{
_lyricsDataArr[0].SetDisplayedTextAlongWith(_lyricsDataArr[found], _liveStatesService.LiveStates.LyricsStyleSettings.LyricsTranslationSeparator, 50);
_lyricsDataArr[0].SetDisplayedTextAlongWith(_lyricsDataArr[found], _liveStatesService.LiveStates.LyricsWindowStatus.LyricsStyleSettings.LyricsTranslationSeparator, 50);
_langIndex = 0;
TranslationSearchProvider = LyricsSearchProvider.ToTranslationSearchProvider();
}
@@ -128,7 +128,7 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
}
else
{
_lyricsDataArr[0].SetDisplayedTextAlongWith(translated, _liveStatesService.LiveStates.LyricsStyleSettings.LyricsTranslationSeparator);
_lyricsDataArr[0].SetDisplayedTextAlongWith(translated, _liveStatesService.LiveStates.LyricsWindowStatus.LyricsStyleSettings.LyricsTranslationSeparator);
_langIndex = 0;
}
TranslationSearchProvider = Enums.TranslationSearchProvider.LibreTranslate;
@@ -156,11 +156,12 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
SongInfo.Title, SongInfo.Artist, SongInfo.Album, SongInfo.DurationMs);
var lyricsSearchResult = await Task.Run(async () => await _lyrcsSearchService.SearchSmartlyAsync(
SongInfo.SourceAppUserModelId ?? "",
SongInfo.PlayerId ?? "",
SongInfo.Title,
SongInfo.Artist,
SongInfo.Album ?? "",
SongInfo.DurationMs ?? 0,
SongInfo.SongId,
token
), token);
if (token.IsCancellationRequested) return;
@@ -208,6 +209,7 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
translationRaw = FileHelper.ReadLyricsCache(SongInfo!.Title, SongInfo.Artist, LyricsFormat.Lrc, PathHelper.QQTranslationCacheDirectory);
break;
case Enums.LyricsSearchProvider.Kugou:
translationRaw = FileHelper.ReadLyricsCache(SongInfo!.Title, SongInfo.Artist, LyricsFormat.Lrc, PathHelper.KugouTranslationCacheDirectory);
break;
case Enums.LyricsSearchProvider.Netease:
translationRaw = FileHelper.ReadLyricsCache(SongInfo!.Title, SongInfo.Artist, LyricsFormat.Lrc, PathHelper.NeteaseTranslationCacheDirectory);
@@ -248,12 +250,12 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
}
}
private void UpdateLyrics()
public void UpdateLyrics()
{
_refreshLyricsRunner.RunAsync(RefreshLyricsAsync);
}
private void UpdateTranslations()
public void UpdateTranslations()
{
_refreshTranslationRunner.RunAsync(RefreshTranslationAsync);
}

View File

@@ -7,7 +7,6 @@ using BetterLyrics.WinUI3.Helper;
using BetterLyrics.WinUI3.Models;
using BetterLyrics.WinUI3.Models.Settings;
using BetterLyrics.WinUI3.Services.AlbumArtSearchService;
using BetterLyrics.WinUI3.Services.LastFMService;
using BetterLyrics.WinUI3.Services.LibWatcherService;
using BetterLyrics.WinUI3.Services.LiveStatesService;
using BetterLyrics.WinUI3.Services.LyricsSearchService;
@@ -20,19 +19,12 @@ using CommunityToolkit.Mvvm.Messaging;
using CommunityToolkit.Mvvm.Messaging.Messages;
using EvtSource;
using Microsoft.Extensions.Logging;
using Microsoft.Graphics.Canvas;
using Microsoft.UI.Dispatching;
using SixLabors.ImageSharp.PixelFormats;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Windows.Graphics.Imaging;
using Windows.Media.Control;
using Windows.Storage.Streams;
using WindowsMediaController;
@@ -40,10 +32,9 @@ using WindowsMediaController;
namespace BetterLyrics.WinUI3.Services.MediaSessionsService
{
public partial class MediaSessionsService : BaseViewModel, IMediaSessionsService,
IRecipient<PropertyChangedMessage<int>>,
IRecipient<PropertyChangedMessage<bool>>,
IRecipient<PropertyChangedMessage<string>>,
IRecipient<PropertyChangedMessage<LyricsWindowMode>>,
IRecipient<PropertyChangedMessage<LyricsWindowStatus>>,
IRecipient<PropertyChangedMessage<ChineseRomanization>>,
IRecipient<PropertyChangedMessage<List<string>>>
{
@@ -57,6 +48,7 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
private double _lxMusicPositionSeconds = 0;
private double _lxMusicDurationSeconds = 0;
private byte[]? _lxMusicAlbumArtBytes = null;
private bool _cachedIsPlaying = false;
private TimeSpan _cachedPosition = TimeSpan.Zero;
@@ -292,21 +284,21 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
if (!_mediaManager.IsStarted) return;
if (mediaSession == null) return;
string id = mediaSession.Id;
string sessionId = mediaSession.Id;
var desiredSession = GetCurrentSession();
//RecordMediaSourceProviderInfo(mediaSession);
if (mediaSession != desiredSession) return;
if (!IsMediaSourceEnabled(id))
if (!IsMediaSourceEnabled(sessionId))
{
_cachedSongInfo = null;
_logger.LogInformation("Media properties changed: Title: {Title}, Artist: {Artist}, Album: {Album}",
mediaProperties.Title, mediaProperties.Artist, mediaProperties.AlbumTitle);
if (id == Constants.PlayerID.LXMusic)
if (sessionId == Constants.PlayerID.LXMusic)
{
StopSSE();
}
@@ -321,38 +313,35 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
currentMediaSourceProviderInfo?.PositionOffset = 0;
}
if (id == Constants.PlayerID.AppleMusic || id == Constants.PlayerID.AppleMusicAlternative)
{
string fixedArtist = mediaProperties.Artist.Split(" — ").FirstOrDefault() ?? mediaProperties.Artist;
string fixedAlbum = mediaProperties.Artist.Split(" — ").LastOrDefault() ?? mediaProperties.AlbumTitle;
string fixedArtist = mediaProperties.Artist;
string fixedAlbum = mediaProperties.AlbumTitle;
string? songId = null;
_cachedSongInfo = new SongInfo
{
Title = mediaProperties.Title,
Artist = fixedArtist,
Album = fixedAlbum,
DurationMs = mediaSession.ControlSession.GetTimelineProperties().EndTime.TotalMilliseconds,
SourceAppUserModelId = id,
};
}
else
if (sessionId == Constants.PlayerID.AppleMusic || sessionId == Constants.PlayerID.AppleMusicAlternative)
{
_cachedSongInfo = new SongInfo
{
Title = mediaProperties.Title,
Artist = mediaProperties.Artist,
Album = mediaProperties.AlbumTitle,
DurationMs = mediaSession.ControlSession.GetTimelineProperties().EndTime.TotalMilliseconds,
SourceAppUserModelId = id,
};
fixedArtist = mediaProperties.Artist.Split(" — ").FirstOrDefault() ?? mediaProperties.Artist;
fixedAlbum = mediaProperties.Artist.Split(" — ").LastOrDefault() ?? mediaProperties.AlbumTitle;
}
else if (PlayerIdMatcher.IsNeteaseFamily(sessionId))
{
songId = mediaProperties.Genres.FirstOrDefault()?.Replace("NCM-", "");
}
_cachedSongInfo = new SongInfo
{
Title = mediaProperties.Title,
Artist = fixedArtist,
Album = fixedAlbum,
DurationMs = mediaSession.ControlSession.GetTimelineProperties().EndTime.TotalMilliseconds,
PlayerId = sessionId,
SongId = songId
};
_cachedSongInfo.Duration = (int)(_cachedSongInfo.DurationMs / 1000f);
_logger.LogInformation("Media properties changed: Title: {Title}, Artist: {Artist}, Album: {Album}",
mediaProperties.Title, mediaProperties.Artist, mediaProperties.AlbumTitle);
if (id == Constants.PlayerID.LXMusic)
if (sessionId == Constants.PlayerID.LXMusic)
{
StartSSE();
}
@@ -361,7 +350,11 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
StopSSE();
}
if (mediaProperties.Thumbnail is IRandomAccessStreamReference streamReference)
if (sessionId == Constants.PlayerID.LXMusic && _lxMusicAlbumArtBytes != null)
{
_SMTCAlbumArtBytes = _lxMusicAlbumArtBytes;
}
else if (mediaProperties.Thumbnail is IRandomAccessStreamReference streamReference)
{
_SMTCAlbumArtBytes = await ImageHelper.ToByteArrayAsync(streamReference);
}
@@ -434,7 +427,7 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
var found = _settingsService.AppSettings.MediaSourceProvidersInfo.FirstOrDefault(x => x.Provider == id);
if (found == null)
{
_settingsService.AppSettings.MediaSourceProvidersInfo.Add(new MediaSourceProviderInfo(id));
_settingsService.AppSettings.MediaSourceProvidersInfo.Add(new MediaSourceProviderInfo(id, _settingsService.AppSettings.GeneralSettings.ListenOnNewPlaybackSource));
}
});
}
@@ -465,6 +458,11 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
private void StartSSE()
{
if (_sse != null)
{
return;
}
try
{
_sse = new EventSourceReader(new Uri($"{_settingsService.AppSettings.GeneralSettings.LXMusicServer}{Constants.LXMusic.QuerySuffix}")).Start();
@@ -504,9 +502,9 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
private void Sse_MessageReceived(object sender, EventSourceMessageEventArgs e)
{
_dispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, () =>
_dispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, async () =>
{
if (_cachedSongInfo?.SourceAppUserModelId == Constants.PlayerID.LXMusic)
if (_cachedSongInfo?.PlayerId == Constants.PlayerID.LXMusic)
{
var data = JsonSerializer.Deserialize(e.Message, Serialization.SourceGenerationContext.Default.JsonElement);
if (data.ValueKind == JsonValueKind.Number)
@@ -525,6 +523,20 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
TimelineChanged?.Invoke(this, new TimelineChangedEventArgs(TimeSpan.FromSeconds(_lxMusicPositionSeconds), TimeSpan.FromSeconds(_lxMusicDurationSeconds)));
}
}
else if (data.ValueKind == JsonValueKind.String)
{
if (e.Event == "picUrl")
{
string? picUrl = data.GetString();
if (picUrl != null)
{
_logger.LogInformation("LX Music Album Art URL: {url}", picUrl);
_lxMusicAlbumArtBytes = await ImageHelper.GetImageBytesFromUrlAsync(picUrl);
_SMTCAlbumArtBytes = _lxMusicAlbumArtBytes;
UpdateAlbumArt();
}
}
}
}
});
}
@@ -631,18 +643,6 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
}
}
public void Receive(PropertyChangedMessage<int> message)
{
if (message.Sender is TranslationSettings)
{
if (message.PropertyName == nameof(TranslationSettings.SelectedTargetLanguageIndex))
{
_logger.LogInformation("Target language index changed: {Index}", _settingsService.AppSettings.TranslationSettings.SelectedTargetLanguageIndex);
UpdateTranslations();
}
}
}
public void Receive(PropertyChangedMessage<string> message)
{
if (message.Sender is LyricsStyleSettings)
@@ -652,13 +652,22 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
UpdateTranslations();
}
}
else if (message.Sender is TranslationSettings)
{
if (message.PropertyName == nameof(TranslationSettings.SelectedTargetLanguageCode))
{
_logger.LogInformation("Target language code changed: {code}", _settingsService.AppSettings.TranslationSettings.SelectedTargetLanguageCode);
UpdateTranslations();
}
}
}
public void Receive(PropertyChangedMessage<LyricsWindowMode> message)
public void Receive(PropertyChangedMessage<LyricsWindowStatus> message)
{
if (message.Sender is LiveStates)
{
if (message.PropertyName == nameof(LiveStates.LyricsWindowMode))
if (message.PropertyName == nameof(LiveStates.LyricsWindowStatus))
{
UpdateTranslations();
}

View File

@@ -29,23 +29,6 @@ namespace BetterLyrics.WinUI3.Services.SettingsService
AppSettings.PropertyChanged += AppSettings_PropertyChanged;
AppSettings.StandardModeSettings.PropertyChanged += AppSettings_PropertyChanged;
AppSettings.DesktopModeSettings.PropertyChanged += AppSettings_PropertyChanged;
AppSettings.DockModeSettings.PropertyChanged += AppSettings_PropertyChanged;
AppSettings.PictureInPictureModeSettings.PropertyChanged += AppSettings_PropertyChanged;
AppSettings.StandardLyricsStyleSettings.PropertyChanged += AppSettings_PropertyChanged;
AppSettings.DesktopLyricsStyleSettings.PropertyChanged += AppSettings_PropertyChanged;
AppSettings.DockLyricsStyleSettings.PropertyChanged += AppSettings_PropertyChanged;
AppSettings.PictureInPictureLyricsStyleSettings.PropertyChanged += AppSettings_PropertyChanged;
AppSettings.StandardLyricsEffectSettings.PropertyChanged += AppSettings_PropertyChanged;
AppSettings.DesktopLyricsEffectSettings.PropertyChanged += AppSettings_PropertyChanged;
AppSettings.DockLyricsEffectSettings.PropertyChanged += AppSettings_PropertyChanged;
AppSettings.PictureInPictureLyricsEffectSettings.PropertyChanged += AppSettings_PropertyChanged;
AppSettings.LyricsBackgroundSettings.PropertyChanged += AppSettings_PropertyChanged;
AppSettings.AlbumArtLayoutSettings.PropertyChanged += AppSettings_PropertyChanged;
AppSettings.TranslationSettings.PropertyChanged += AppSettings_PropertyChanged;
AppSettings.GeneralSettings.PropertyChanged += AppSettings_PropertyChanged;
AppSettings.MusicGallerySettings.PropertyChanged += AppSettings_PropertyChanged;
@@ -122,10 +105,6 @@ namespace BetterLyrics.WinUI3.Services.SettingsService
{
switch (e.PropertyName)
{
case nameof(GeneralSettings.IsDragEverywhereEnabled):
LyricsWindow? lyricsWindow = WindowHelper.GetWindowByWindowType<LyricsWindow>();
lyricsWindow?.UpdateTitleBarArea();
break;
case nameof(GeneralSettings.Language):
switch (AppSettings.GeneralSettings.Language)
{

View File

@@ -123,27 +123,12 @@
<data name="AlbumArtSearchSMTCProvider" xml:space="preserve">
<value>Music player</value>
</data>
<data name="AllLyricsSettingsControlDesktop.Content" xml:space="preserve">
<value>Desktop mode</value>
</data>
<data name="AllLyricsSettingsControlDock.Content" xml:space="preserve">
<value>Dock mode</value>
</data>
<data name="AllLyricsSettingsControlPictureInPicture.Content" xml:space="preserve">
<value>Picture-in-picture mode</value>
</data>
<data name="AllLyricsSettingsControlStandard.Content" xml:space="preserve">
<value>Standard</value>
</data>
<data name="AppSettingsControlGeneral.Content" xml:space="preserve">
<data name="AppSettingsControlGeneral.Text" xml:space="preserve">
<value>General</value>
</data>
<data name="BaseWindowEnterFullScreenHint" xml:space="preserve">
<value>Press Esc to exit full screen mode</value>
</data>
<data name="BaseWindowFullScreenFlyoutItem.Text" xml:space="preserve">
<value>Full screen</value>
</data>
<data name="BaseWindowHostInfoBarCheckBox.Content" xml:space="preserve">
<value>Do not show this message again</value>
</data>
@@ -153,32 +138,38 @@
<data name="Cancel" xml:space="preserve">
<value>Cancel</value>
</data>
<data name="DemoWindowControlDefault.Text" xml:space="preserve">
<value>Default</value>
</data>
<data name="DependenciesSettingsExpander.Header" xml:space="preserve">
<value>Dependencies</value>
</data>
<data name="DesktopMode" xml:space="preserve">
<value>Desktop mode (transparent)</value>
</data>
<data name="DockedMode" xml:space="preserve">
<value>Docked mode</value>
</data>
<data name="ExportSettingsSuccess" xml:space="preserve">
<value>Export successful</value>
</data>
<data name="FailToStartLXMusicServer" xml:space="preserve">
<value>Unable to connect to LX Music server, please go to Settings - Advanced options to check if the link is entered correctly</value>
</data>
<data name="FullscreenMode" xml:space="preserve">
<value>Fullscreen mode</value>
</data>
<data name="HostWindowClickThroughButton.Content" xml:space="preserve">
<value>Lock</value>
</data>
<data name="HostWindowClickThroughFlyoutItem.Text" xml:space="preserve">
<value>Lock</value>
</data>
<data name="HostWindowDesktopFlyoutItem.Text" xml:space="preserve">
<value>Desktop mode</value>
</data>
<data name="HostWindowDockFlyoutItem.Text" xml:space="preserve">
<value>Dock mode</value>
</data>
<data name="HostWindowLockToolTip.Text" xml:space="preserve">
<value>Lock</value>
</data>
<data name="HostWindowMoreButtonToolTip.Content" xml:space="preserve">
<value>More</value>
<data name="HostWindowMusicGalleryButtonToolTip.Content" xml:space="preserve">
<value>Music gallery</value>
</data>
<data name="HostWindowSettingsFlyoutItem.Text" xml:space="preserve">
<value>Settings</value>
@@ -223,7 +214,7 @@
<value>Manually search lyrics</value>
</data>
<data name="LyricsPageLyricsSettingsButtonToolTip.Content" xml:space="preserve">
<value>Lyrics style and effect quick settings</value>
<value>Lyrics Window Management Shortcut Settings</value>
</data>
<data name="LyricsPagePlaybackSourceButtonToolTip.Content" xml:space="preserve">
<value>Play source shortcut settings</value>
@@ -303,11 +294,17 @@
<data name="LyricsWindowImmersiveButtonToolTip.Content" xml:space="preserve">
<value>Immersive mode</value>
</data>
<data name="MainPageAlbumArtOnly.Content" xml:space="preserve">
<value>Album art only</value>
<data name="LyricsWindowSettingsControlCurrentLyricsWindowConfig.Text" xml:space="preserve">
<value>Current lyrics window config</value>
</data>
<data name="MainPageDesktopLyricsToggler.ToolTipService.ToolTip" xml:space="preserve">
<value>Switch to desktop lyrics mode</value>
<data name="LyricsWindowSettingsControlLyricsWindowMode.Header" xml:space="preserve">
<value>Lyrics window mode</value>
</data>
<data name="LyricsWindowSettingsControlSetDefault.Text" xml:space="preserve">
<value>Set as default</value>
</data>
<data name="MainPageAlbumArtOnly.Content" xml:space="preserve">
<value>Album art area only</value>
</data>
<data name="MainPageEnterImmersiveModeHint" xml:space="preserve">
<value>Hover back again to show the toggle button</value>
@@ -442,15 +439,18 @@ If you encounter any problems, please go to the Settings page, About tab, and vi
<data name="MusicGalleryPageTitle" xml:space="preserve">
<value>Music gallery - BetterLyrics</value>
</data>
<data name="NarrowMode" xml:space="preserve">
<value>Narrow mode</value>
</data>
<data name="PictureInPictureMode" xml:space="preserve">
<value>Picture-in-picture mode</value>
</data>
<data name="SetingsPageDonation.Text" xml:space="preserve">
<value>Donation</value>
</data>
<data name="SetingsPageFeedback.Text" xml:space="preserve">
<value>Feedback</value>
</data>
<data name="SetingsPageRef.Text" xml:space="preserve">
<value>Library used</value>
</data>
<data name="SetingsPageThanks.Text" xml:space="preserve">
<value>If you like this project, please consider supporting it by donating. Your support will help keep the project alive and encourage further development.</value>
</data>
@@ -463,18 +463,33 @@ If you encounter any problems, please go to the Settings page, About tab, and vi
<data name="SettingsPageAcrylicThin.Content" xml:space="preserve">
<value>Acrylic Thin</value>
</data>
<data name="SettingsPageAdaptEnvColor.Description" xml:space="preserve">
<value>At the same time, set the pure color layer opacity and the album art layer opacity in the lyrics background to 0 to get the correct effect</value>
</data>
<data name="SettingsPageAdaptEnvColor.Header" xml:space="preserve">
<value>Adapt to environmental color</value>
</data>
<data name="SettingsPageAddFolder.Header" xml:space="preserve">
<value>Add a folder</value>
</data>
<data name="SettingsPageAddFolderButton.Content" xml:space="preserve">
<value>Add</value>
</data>
<data name="SettingsPageAdvanced.Text" xml:space="preserve">
<value>Advanced options</value>
</data>
<data name="SettingsPageAlbumArt.Text" xml:space="preserve">
<value>Album art</value>
</data>
<data name="SettingsPageAlbumArtLayer.Header" xml:space="preserve">
<value>Album art layer</value>
</data>
<data name="SettingsPageAlbumArtSearchProvidersConfig.Text" xml:space="preserve">
<value>Configure album cover source</value>
</data>
<data name="SettingsPageAlbumArtSize.Header" xml:space="preserve">
<value>Album art size</value>
</data>
<data name="SettingsPageAlbumLib.Content" xml:space="preserve">
<value>Album art source</value>
</data>
@@ -484,14 +499,14 @@ If you encounter any problems, please go to the Settings page, About tab, and vi
<data name="SettingsPageAlbumShadowAmount.Header" xml:space="preserve">
<value>How much the shadows are spreading</value>
</data>
<data name="SettingsPageAlbumStyle.Content" xml:space="preserve">
<data name="SettingsPageAlbumStyle.Text" xml:space="preserve">
<value>Album art area style</value>
</data>
<data name="SettingsPageAmount.Header" xml:space="preserve">
<value>Amount</value>
</data>
<data name="SettingsPageAOT.Header" xml:space="preserve">
<value>Always on top</value>
<value>Bring the lyrics window to the top</value>
</data>
<data name="SettingsPageApp.Content" xml:space="preserve">
<value>App appearance and behavior</value>
@@ -500,29 +515,17 @@ If you encounter any problems, please go to the Settings page, About tab, and vi
<value>App appearance</value>
</data>
<data name="SettingsPageAppBehavior.Text" xml:space="preserve">
<value>App behavior</value>
<value>General behavior</value>
</data>
<data name="SettingsPageApply.Content" xml:space="preserve">
<value>Apply</value>
</data>
<data name="SettingsPageAutoLock.Header" xml:space="preserve">
<value>Auto-lock when activating desktop mode</value>
<data name="SettingsPageAutoSize.Header" xml:space="preserve">
<value>Automatic resizing</value>
</data>
<data name="SettingsPageAutoStart.Header" xml:space="preserve">
<value>Automatic startup</value>
</data>
<data name="SettingsPageAutoStartDesktopLyrics.Content" xml:space="preserve">
<value>Activate desktop mode</value>
</data>
<data name="SettingsPageAutoStartDockLyrics.Content" xml:space="preserve">
<value>Activate dock mode</value>
</data>
<data name="SettingsPageAutoStartInAppLyrics.Content" xml:space="preserve">
<value>Activate standard mode</value>
</data>
<data name="SettingsPageAutoStartPIPLyrics.Content" xml:space="preserve">
<value>Start Picture-in-Picture Mode</value>
</data>
<data name="SettingsPageAutoStartWindow.Header" xml:space="preserve">
<value>When starting the app</value>
</data>
@@ -532,9 +535,18 @@ If you encounter any problems, please go to the Settings page, About tab, and vi
<data name="SettingsPageBackgroundAcrylicEffectAmount.Header" xml:space="preserve">
<value>Album Background Acrylic Effect Strength</value>
</data>
<data name="SettingsPageBackgroundOverlay.Content" xml:space="preserve">
<data name="SettingsPageBackgroundOverlay.Text" xml:space="preserve">
<value>Lyrics background</value>
</data>
<data name="SettingsPageBlurAmount.Header" xml:space="preserve">
<value>Blur amount</value>
</data>
<data name="SettingsPageBorderless.Header" xml:space="preserve">
<value>Borderless window</value>
</data>
<data name="SettingsPageBorderlessHotKey.Header" xml:space="preserve">
<value>Borderless lyrics window shortcut</value>
</data>
<data name="SettingsPageCache.Description" xml:space="preserve">
<value>Including log files, network lyrics cache</value>
</data>
@@ -547,9 +559,27 @@ If you encounter any problems, please go to the Settings page, About tab, and vi
<data name="SettingsPageChinesePreference.Header" xml:space="preserve">
<value>Convert Chinese to Traditional Chinese</value>
</data>
<data name="SettingsPageClickThrough.Header" xml:space="preserve">
<value>Click-through</value>
</data>
<data name="SettingsPageClickThroughHotKey.Header" xml:space="preserve">
<value>Click-through shortcut keys</value>
</data>
<data name="SettingsPageCompactTitleBar.Content" xml:space="preserve">
<value>Compact</value>
</data>
<data name="SettingsPageConfigName.Description" xml:space="preserve">
<value>Naming the recorded window states can help you distinguish them better</value>
</data>
<data name="SettingsPageConfigName.Header" xml:space="preserve">
<value>Configuration name</value>
</data>
<data name="SettingsPageCreateFromCurrent.Content" xml:space="preserve">
<value>Create from the current lyrics window status</value>
</data>
<data name="SettingsPageCreateFromTemplates.Content" xml:space="preserve">
<value>Create from templates</value>
</data>
<data name="SettingsPageCurrentLyricsWindowStatus.Text" xml:space="preserve">
<value>Current lyrics window status</value>
</data>
@@ -559,29 +589,29 @@ If you encounter any problems, please go to the Settings page, About tab, and vi
<data name="SettingsPageDebugOverlay.Header" xml:space="preserve">
<value>Show debug overlay</value>
</data>
<data name="SettingsPageDelete.Content" xml:space="preserve">
<data name="SettingsPageDelete.Text" xml:space="preserve">
<value>Delete</value>
</data>
<data name="SettingsPageDesktopAcrylic.Content" xml:space="preserve">
<value>Desktop Acrylic</value>
<data name="SettingsPageDesktopMode.Text" xml:space="preserve">
<value>Desktop mode (transparent)</value>
</data>
<data name="SettingsPageDev.Content" xml:space="preserve">
<value>Advanced options</value>
</data>
<data name="SettingsPageDisclaimer.Text" xml:space="preserve">
<data name="SettingsPageDisclaimer.Message" xml:space="preserve">
<value>This project is provided as is without warranty of any kind. All lyrics, fonts, icons, and other third-party resources are the property of their respective copyright holders. The author of this project does not claim ownership of such resources. This project is non-commercial and should not be used to infringe any rights. Users are responsible for ensuring their own use complies with applicable laws and licenses.</value>
</data>
<data name="SettingsPageDiscord.Content" xml:space="preserve">
<value>Discord</value>
</data>
<data name="SettingsPageDisplayTypeSwitcher.Header" xml:space="preserve">
<value>Lyrics album layout mode</value>
<value>Layout mode</value>
</data>
<data name="SettingsPageDockedMode.Text" xml:space="preserve">
<value>Docked mode</value>
</data>
<data name="SettingsPageDockMonitor.Header" xml:space="preserve">
<value>Target monitor</value>
</data>
<data name="SettingsPageDockPlacement.Header" xml:space="preserve">
<value>Dock mode placement</value>
<value>Work area placement</value>
</data>
<data name="SettingsPageDockPlacementBottom.Content" xml:space="preserve">
<value>Bottom</value>
@@ -592,6 +622,9 @@ If you encounter any problems, please go to the Settings page, About tab, and vi
<data name="SettingsPageDockWindowHeight.Header" xml:space="preserve">
<value>Window height</value>
</data>
<data name="SettingsPageDragArea.Header" xml:space="preserve">
<value>Draggable area</value>
</data>
<data name="SettingsPageDynamicLyricsFontSize.Header" xml:space="preserve">
<value>Automatic adjustment</value>
</data>
@@ -637,6 +670,21 @@ If you encounter any problems, please go to the Settings page, About tab, and vi
<data name="SettingsPageEN.Content" xml:space="preserve">
<value>English</value>
</data>
<data name="SettingsPageEnvColorSample.Header" xml:space="preserve">
<value>Environmental color sampe mode</value>
</data>
<data name="SettingsPageEnvColorSampleAbove.Content" xml:space="preserve">
<value>Above the window</value>
</data>
<data name="SettingsPageEnvColorSampleBelow.Content" xml:space="preserve">
<value>Below the window</value>
</data>
<data name="SettingsPageEnvColorSampleEdge.Content" xml:space="preserve">
<value>Window edges</value>
</data>
<data name="SettingsPageEnvColorSampleInner.Content" xml:space="preserve">
<value>Inside the window</value>
</data>
<data name="SettingsPageExitOnLyricsWindowClosed.Header" xml:space="preserve">
<value>Exit the program when you close the lyrics window</value>
</data>
@@ -655,30 +703,33 @@ If you encounter any problems, please go to the Settings page, About tab, and vi
<data name="SettingsPageFixedTimeStep.Header" xml:space="preserve">
<value>Fixed time step rendering</value>
</data>
<data name="SettingsPageFluidLayer.Header" xml:space="preserve">
<value>Fluid layer</value>
</data>
<data name="SettingsPageFollowSystem.Content" xml:space="preserve">
<value>Follow system</value>
</data>
<data name="SettingsPageForceAlwaysOnTop.Description" xml:space="preserve">
<value>Keep the lyrics window on top by polling</value>
</data>
<data name="SettingsPageForceAlwaysOnTop.Header" xml:space="preserve">
<value>Force on top</value>
</data>
<data name="SettingsPageFPS.Header" xml:space="preserve">
<value>Rendering frame rate</value>
</data>
<data name="SettingsPageGlobalDrag.Description" xml:space="preserve">
<value>Extend the title bar to the entire page so that the window can be dragged in any non-interactive area</value>
<data name="SettingsPageFullscreenMode.Text" xml:space="preserve">
<value>Fullscreen mode</value>
</data>
<data name="SettingsPageGlobalDrag.Header" xml:space="preserve">
<value>Global drag</value>
<data name="SettingsPageHeight.Header" xml:space="preserve">
<value>Height</value>
</data>
<data name="SettingsPageHideWindow.Description" xml:space="preserve">
<value>In docking mode or desktop mode, when no song is playing, the window will be automatically hidden; otherwise, the window will be automatically displayed.</value>
<value>Automatically hide/show lyric window when music is not playing</value>
</data>
<data name="SettingsPageHideWindow.Header" xml:space="preserve">
<value>Automatically hide/show windows</value>
</data>
<data name="SettingsPageIgnoreFullscreenWindow.Description" xml:space="preserve">
<value>Force this app to appear on top of full-screen apps when docked or desktop mode is enabled</value>
</data>
<data name="SettingsPageIgnoreFullscreenWindow.Header" xml:space="preserve">
<value>Always stay on top of fullscreen applications</value>
</data>
<data name="SettingsPageImportSettingsButton.Content" xml:space="preserve">
<value>Import settings</value>
</data>
@@ -730,14 +781,23 @@ If you encounter any problems, please go to the Settings page, About tab, and vi
<data name="SettingsPageLastFMUsername.Header" xml:space="preserve">
<value>Username</value>
</data>
<data name="SettingsPageLayoutOrientation.Header" xml:space="preserve">
<value>Layout orientation</value>
</data>
<data name="SettingsPageLayoutOrientationHorizontal.Content" xml:space="preserve">
<value>Horizontal</value>
</data>
<data name="SettingsPageLayoutOrientationVertical.Content" xml:space="preserve">
<value>Vertical</value>
</data>
<data name="SettingsPageLibreTranslateServer.Header" xml:space="preserve">
<value>Server address</value>
</data>
<data name="SettingsPageLight.Content" xml:space="preserve">
<value>Light</value>
</data>
<data name="SettingsPageLockHotKey.Header" xml:space="preserve">
<value>Unlock and lock shortcut keys</value>
<data name="SettingsPageListenNewSession.Header" xml:space="preserve">
<value>Enable monitoring for new playback sources</value>
</data>
<data name="SettingsPageLog.Header" xml:space="preserve">
<value>Log record</value>
@@ -745,7 +805,7 @@ If you encounter any problems, please go to the Settings page, About tab, and vi
<data name="SettingsPageLXMusicServer.Text" xml:space="preserve">
<value>LX Music Server</value>
</data>
<data name="SettingsPageLyrics.Content" xml:space="preserve">
<data name="SettingsPageLyrics.Text" xml:space="preserve">
<value>Lyrics style and effect</value>
</data>
<data name="SettingsPageLyricsAlignment.Header" xml:space="preserve">
@@ -754,15 +814,6 @@ If you encounter any problems, please go to the Settings page, About tab, and vi
<data name="SettingsPageLyricsBackground.Header" xml:space="preserve">
<value>Lyrics background</value>
</data>
<data name="SettingsPageLyricsBackgroundBlurAmount.Header" xml:space="preserve">
<value>Album background layer ambiguity</value>
</data>
<data name="SettingsPageLyricsBackgroundOpacity.Header" xml:space="preserve">
<value>Album background layer opacity</value>
</data>
<data name="SettingsPageLyricsBackgroundSpeed.Header" xml:space="preserve">
<value>Album Background Layer Motion Rate</value>
</data>
<data name="SettingsPageLyricsBgFontColor.Header" xml:space="preserve">
<value>Font color (Non-current playback area)</value>
</data>
@@ -862,9 +913,6 @@ If you encounter any problems, please go to the Settings page, About tab, and vi
<data name="SettingsPageLyricsNormal.Content" xml:space="preserve">
<value>Normal</value>
</data>
<data name="SettingsPageLyricsPureColorBgOpacity.Header" xml:space="preserve">
<value>Solid background layer opacity</value>
</data>
<data name="SettingsPageLyricsRendingScopeCurrentChar.Content" xml:space="preserve">
<value>Current char</value>
</data>
@@ -916,9 +964,15 @@ If you encounter any problems, please go to the Settings page, About tab, and vi
<data name="SettingsPageLyricsVerticalEdgeOpacity.Header" xml:space="preserve">
<value>Top and bottom edge opacity</value>
</data>
<data name="SettingsPageLyricsWindowManager.Header" xml:space="preserve">
<data name="SettingsPageLyricsWindowManager.Text" xml:space="preserve">
<value>Lyrics window manager</value>
</data>
<data name="SettingsPageLyricsWindowMgr.Content" xml:space="preserve">
<value>Lyrics window manager</value>
</data>
<data name="SettingsPageLyricsWindowSwitchHotKey.Header" xml:space="preserve">
<value>Lyrics window status switcher shortcut</value>
</data>
<data name="SettingsPageMediaLib.Content" xml:space="preserve">
<value>Media library</value>
</data>
@@ -943,13 +997,19 @@ If you encounter any problems, please go to the Settings page, About tab, and vi
<data name="SettingsPageMusicLibRealTimeWatch.Header" xml:space="preserve">
<value>Listen to file changes in real time</value>
</data>
<data name="SettingsPageNarrowMode.Text" xml:space="preserve">
<value>Narrow mode</value>
</data>
<data name="SettingsPageNextSongHotKey.Header" xml:space="preserve">
<value>Next track shortcut keys</value>
</data>
<data name="SettingsPageNoBackdrop.Content" xml:space="preserve">
<value>None</value>
</data>
<data name="SettingsPageOpenLogFolderButton.Content" xml:space="preserve">
<data name="SettingsPageOpacity.Header" xml:space="preserve">
<value>Opacity</value>
</data>
<data name="SettingsPageOpenFolderButton.Content" xml:space="preserve">
<value>Open in file explorer</value>
</data>
<data name="SettingsPagePathBeIncludedInfo" xml:space="preserve">
@@ -985,9 +1045,15 @@ If you encounter any problems, please go to the Settings page, About tab, and vi
<data name="SettingsPagePreviousSongHotKey.Header" xml:space="preserve">
<value>Shortcut keys for the previous track</value>
</data>
<data name="SettingsPagePureLayer.Header" xml:space="preserve">
<value>Pure color layer</value>
</data>
<data name="SettingsPageQQGroup.Content" xml:space="preserve">
<value>QQ feedback &amp; chat group</value>
</data>
<data name="SettingsPageRealtimeStatus.Text" xml:space="preserve">
<value>Realtime status</value>
</data>
<data name="SettingsPageRecord.Content" xml:space="preserve">
<value>Record</value>
</data>
@@ -1042,6 +1108,9 @@ If you encounter any problems, please go to the Settings page, About tab, and vi
<data name="SettingsPageServerTestSuccessInfo" xml:space="preserve">
<value>Server test successful</value>
</data>
<data name="SettingsPageSettings.Header" xml:space="preserve">
<value>Settings</value>
</data>
<data name="SettingsPageSettingsManager.Header" xml:space="preserve">
<value>Settings manager</value>
</data>
@@ -1051,9 +1120,21 @@ If you encounter any problems, please go to the Settings page, About tab, and vi
<data name="SettingsPageShortcutRegSuccessInfo" xml:space="preserve">
<value>This hotkey has been successfully registered</value>
</data>
<data name="SettingsPageShowArtists.Header" xml:space="preserve">
<value>Show artists</value>
</data>
<data name="SettingsPageShowHideHotKey.Header" xml:space="preserve">
<value>Lyrics window display and hide shortcut keys</value>
</data>
<data name="SettingsPageShowInSwitchers.Description" xml:space="preserve">
<value>e.g. Alt + Tab, Taskbar</value>
</data>
<data name="SettingsPageShowInSwitchers.Header" xml:space="preserve">
<value>Show in system environment</value>
</data>
<data name="SettingsPageShowTitle.Header" xml:space="preserve">
<value>Show title</value>
</data>
<data name="SettingsPageSliderPrefix.Text" xml:space="preserve">
<value>Current value: </value>
</data>
@@ -1072,6 +1153,15 @@ If you encounter any problems, please go to the Settings page, About tab, and vi
<data name="SettingsPageSongInfoRight.Content" xml:space="preserve">
<value>Right</value>
</data>
<data name="SettingsPageSpectrumLayer.Header" xml:space="preserve">
<value>Spectrum layer</value>
</data>
<data name="SettingsPageSpeed.Header" xml:space="preserve">
<value>Motion rate</value>
</data>
<data name="SettingsPageStandardMode.Text" xml:space="preserve">
<value>Standard mode</value>
</data>
<data name="SettingsPageSystemLanguage.Content" xml:space="preserve">
<value>Default</value>
</data>
@@ -1090,6 +1180,15 @@ If you encounter any problems, please go to the Settings page, About tab, and vi
<data name="SettingsPageTitle" xml:space="preserve">
<value>Settings - BetterLyrics</value>
</data>
<data name="SettingsPageTitleBarAreaNone.Content" xml:space="preserve">
<value>None</value>
</data>
<data name="SettingsPageTitleBarAreaTop.Content" xml:space="preserve">
<value>Top</value>
</data>
<data name="SettingsPageTitleBarAreaWhole.Content" xml:space="preserve">
<value>The whole window</value>
</data>
<data name="SettingsPageTitleBarType.Header" xml:space="preserve">
<value>Title bar size</value>
</data>
@@ -1111,6 +1210,24 @@ If you encounter any problems, please go to the Settings page, About tab, and vi
<data name="SettingsPageVersion.Text" xml:space="preserve">
<value>Version</value>
</data>
<data name="SettingsPageWidth.Header" xml:space="preserve">
<value>Width</value>
</data>
<data name="SettingsPageWindowBounds.Header" xml:space="preserve">
<value>Window bounds</value>
</data>
<data name="SettingsPageWorkArea.Description" xml:space="preserve">
<value>As a separate work area docked to the upper/lower edge of the screen</value>
</data>
<data name="SettingsPageWorkArea.Header" xml:space="preserve">
<value>As work area</value>
</data>
<data name="SettingsPageWorkAreaHeight.Header" xml:space="preserve">
<value>Work area height</value>
</data>
<data name="StandardMode" xml:space="preserve">
<value>Standard mode</value>
</data>
<data name="SystemTrayExit.Text" xml:space="preserve">
<value>Exit</value>
</data>
@@ -1132,9 +1249,6 @@ If you encounter any problems, please go to the Settings page, About tab, and vi
<data name="SystemTraySettings.Text" xml:space="preserve">
<value>Settings</value>
</data>
<data name="SystemTrayUnlock.Text" xml:space="preserve">
<value>Unlock the window</value>
</data>
<data name="TranslateServerNotSet" xml:space="preserve">
<value>Translate server is not set, please configure it in settings first</value>
</data>

View File

@@ -123,27 +123,12 @@
<data name="AlbumArtSearchSMTCProvider" xml:space="preserve">
<value>音楽プレーヤー</value>
</data>
<data name="AllLyricsSettingsControlDesktop.Content" xml:space="preserve">
<value>デスクトップモード</value>
</data>
<data name="AllLyricsSettingsControlDock.Content" xml:space="preserve">
<value>ドックモード</value>
</data>
<data name="AllLyricsSettingsControlPictureInPicture.Content" xml:space="preserve">
<value>ピクチャーインピクチャーモード</value>
</data>
<data name="AllLyricsSettingsControlStandard.Content" xml:space="preserve">
<value>標準モード</value>
</data>
<data name="AppSettingsControlGeneral.Content" xml:space="preserve">
<data name="AppSettingsControlGeneral.Text" xml:space="preserve">
<value>一般的な</value>
</data>
<data name="BaseWindowEnterFullScreenHint" xml:space="preserve">
<value>ESCを押して、フルスクリーンモードを終了します</value>
</data>
<data name="BaseWindowFullScreenFlyoutItem.Text" xml:space="preserve">
<value>全画面表示</value>
</data>
<data name="BaseWindowHostInfoBarCheckBox.Content" xml:space="preserve">
<value>このメッセージを二度と見せないでください</value>
</data>
@@ -153,32 +138,38 @@
<data name="Cancel" xml:space="preserve">
<value>キャンセル</value>
</data>
<data name="DemoWindowControlDefault.Text" xml:space="preserve">
<value>デフォルト</value>
</data>
<data name="DependenciesSettingsExpander.Header" xml:space="preserve">
<value>依存関係</value>
</data>
<data name="DesktopMode" xml:space="preserve">
<value>デスクトップモード(透明) </value>
</data>
<data name="DockedMode" xml:space="preserve">
<value>ドック式</value>
</data>
<data name="ExportSettingsSuccess" xml:space="preserve">
<value>エクスポートが成功しました</value>
</data>
<data name="FailToStartLXMusicServer" xml:space="preserve">
<value>LX Music Serverに接続できない場合は、設定に移動してください。リンクが正しく入力されているかどうかを確認するための高度なオプションに移動してください</value>
</data>
<data name="FullscreenMode" xml:space="preserve">
<value>フルスクリーンモード</value>
</data>
<data name="HostWindowClickThroughButton.Content" xml:space="preserve">
<value>ロック</value>
</data>
<data name="HostWindowClickThroughFlyoutItem.Text" xml:space="preserve">
<value>ロック</value>
</data>
<data name="HostWindowDesktopFlyoutItem.Text" xml:space="preserve">
<value>デスクトップモード</value>
</data>
<data name="HostWindowDockFlyoutItem.Text" xml:space="preserve">
<value>ドックモード</value>
</data>
<data name="HostWindowLockToolTip.Text" xml:space="preserve">
<value>ロック</value>
</data>
<data name="HostWindowMoreButtonToolTip.Content" xml:space="preserve">
<value>もっと</value>
<data name="HostWindowMusicGalleryButtonToolTip.Content" xml:space="preserve">
<value>ミュージックギャラリー</value>
</data>
<data name="HostWindowSettingsFlyoutItem.Text" xml:space="preserve">
<value>設定</value>
@@ -223,7 +214,7 @@
<value>手動で歌詞を検索します</value>
</data>
<data name="LyricsPageLyricsSettingsButtonToolTip.Content" xml:space="preserve">
<value>歌詞スタイルと効果クイック設定</value>
<value>歌詞ウィンドウ管理ショートカット設定</value>
</data>
<data name="LyricsPagePlaybackSourceButtonToolTip.Content" xml:space="preserve">
<value>再生ソースクイック設定</value>
@@ -303,11 +294,17 @@
<data name="LyricsWindowImmersiveButtonToolTip.Content" xml:space="preserve">
<value>没入モード</value>
</data>
<data name="MainPageAlbumArtOnly.Content" xml:space="preserve">
<value>アルバムアートのみ</value>
<data name="LyricsWindowSettingsControlCurrentLyricsWindowConfig.Text" xml:space="preserve">
<value>現在の歌詞ウィンドウ設定</value>
</data>
<data name="MainPageDesktopLyricsToggler.ToolTipService.ToolTip" xml:space="preserve">
<value>デスクトップ歌詞モードに切り替えます</value>
<data name="LyricsWindowSettingsControlLyricsWindowMode.Header" xml:space="preserve">
<value>歌詞ウィンドウモード</value>
</data>
<data name="LyricsWindowSettingsControlSetDefault.Text" xml:space="preserve">
<value>既定のブラウザーに設定する</value>
</data>
<data name="MainPageAlbumArtOnly.Content" xml:space="preserve">
<value>アルバムアートエリアのみ</value>
</data>
<data name="MainPageEnterImmersiveModeHint" xml:space="preserve">
<value>再びホバリングして、トグルボタンを表示します</value>
@@ -442,15 +439,18 @@
<data name="MusicGalleryPageTitle" xml:space="preserve">
<value>音楽ギャラリー - BetterLyrics</value>
</data>
<data name="NarrowMode" xml:space="preserve">
<value>狭い</value>
</data>
<data name="PictureInPictureMode" xml:space="preserve">
<value>ピクチャーインピクチャーモード</value>
</data>
<data name="SetingsPageDonation.Text" xml:space="preserve">
<value>寄付</value>
</data>
<data name="SetingsPageFeedback.Text" xml:space="preserve">
<value>フィードバック</value>
</data>
<data name="SetingsPageRef.Text" xml:space="preserve">
<value>使用されているライブラリ</value>
</data>
<data name="SetingsPageThanks.Text" xml:space="preserve">
<value>このプロジェクトが気に入っている場合は、寄付してサポートすることを検討してください。あなたのサポートは、プロジェクトを生かし続け、さらなる開発を促進するのに役立ちます。</value>
</data>
@@ -463,18 +463,33 @@
<data name="SettingsPageAcrylicThin.Content" xml:space="preserve">
<value>アクリル薄い</value>
</data>
<data name="SettingsPageAdaptEnvColor.Description" xml:space="preserve">
<value>同時に、歌詞の背景のピュアカラーレイヤーの不透明度とアルバムアートレイヤーの不透明度を0に設定して、正しい効果を得ます</value>
</data>
<data name="SettingsPageAdaptEnvColor.Header" xml:space="preserve">
<value>環境の色に適応しましょう</value>
</data>
<data name="SettingsPageAddFolder.Header" xml:space="preserve">
<value>フォルダーを追加します</value>
</data>
<data name="SettingsPageAddFolderButton.Content" xml:space="preserve">
<value>追加</value>
</data>
<data name="SettingsPageAdvanced.Text" xml:space="preserve">
<value>高度なオプション</value>
</data>
<data name="SettingsPageAlbumArt.Text" xml:space="preserve">
<value>アルバムアート</value>
</data>
<data name="SettingsPageAlbumArtLayer.Header" xml:space="preserve">
<value>アルバムアートレイヤー</value>
</data>
<data name="SettingsPageAlbumArtSearchProvidersConfig.Text" xml:space="preserve">
<value>アルバムカバーソースを構成します</value>
</data>
<data name="SettingsPageAlbumArtSize.Header" xml:space="preserve">
<value>アルバムアートサイズ</value>
</data>
<data name="SettingsPageAlbumLib.Content" xml:space="preserve">
<value>アルバムアートソース</value>
</data>
@@ -484,14 +499,14 @@
<data name="SettingsPageAlbumShadowAmount.Header" xml:space="preserve">
<value>影がどれだけ広がっているか</value>
</data>
<data name="SettingsPageAlbumStyle.Content" xml:space="preserve">
<data name="SettingsPageAlbumStyle.Text" xml:space="preserve">
<value>アルバムエリアスタイル</value>
</data>
<data name="SettingsPageAmount.Header" xml:space="preserve">
<value>量</value>
</data>
<data name="SettingsPageAOT.Header" xml:space="preserve">
<value>常にトップ</value>
<value>歌詞ウィンドウを一番上に表示します</value>
</data>
<data name="SettingsPageApp.Content" xml:space="preserve">
<value>アプリの外観と動作</value>
@@ -500,29 +515,17 @@
<value>アプリの外観</value>
</data>
<data name="SettingsPageAppBehavior.Text" xml:space="preserve">
<value>アプリの動作</value>
<value>一般的な行動</value>
</data>
<data name="SettingsPageApply.Content" xml:space="preserve">
<value>適用する</value>
</data>
<data name="SettingsPageAutoLock.Header" xml:space="preserve">
<value>デスクトップモードをアクティブにするときの自動ロック</value>
<data name="SettingsPageAutoSize.Header" xml:space="preserve">
<value>自動サイズ変更</value>
</data>
<data name="SettingsPageAutoStart.Header" xml:space="preserve">
<value>自動起動</value>
</data>
<data name="SettingsPageAutoStartDesktopLyrics.Content" xml:space="preserve">
<value>デスクトップモードを開始します</value>
</data>
<data name="SettingsPageAutoStartDockLyrics.Content" xml:space="preserve">
<value>ドックモードをアクティブにします</value>
</data>
<data name="SettingsPageAutoStartInAppLyrics.Content" xml:space="preserve">
<value>標準モードをアクティブにします</value>
</data>
<data name="SettingsPageAutoStartPIPLyrics.Content" xml:space="preserve">
<value>ピクチャーインピクチャーモードを開始します</value>
</data>
<data name="SettingsPageAutoStartWindow.Header" xml:space="preserve">
<value>アプリを起動するとき</value>
</data>
@@ -532,9 +535,18 @@
<data name="SettingsPageBackgroundAcrylicEffectAmount.Header" xml:space="preserve">
<value>アルバムの背景アクリル効果の強さ</value>
</data>
<data name="SettingsPageBackgroundOverlay.Content" xml:space="preserve">
<data name="SettingsPageBackgroundOverlay.Text" xml:space="preserve">
<value>歌詞の背景</value>
</data>
<data name="SettingsPageBlurAmount.Header" xml:space="preserve">
<value>ぼやけの量</value>
</data>
<data name="SettingsPageBorderless.Header" xml:space="preserve">
<value>ボーダーレスウィンドウ</value>
</data>
<data name="SettingsPageBorderlessHotKey.Header" xml:space="preserve">
<value>ボーダーレス歌詞ウィンドウショートカット</value>
</data>
<data name="SettingsPageCache.Description" xml:space="preserve">
<value>ログファイル、ネットワーク歌詞キャッシュを含む</value>
</data>
@@ -547,9 +559,27 @@
<data name="SettingsPageChinesePreference.Header" xml:space="preserve">
<value>中国人を伝統的な中国人に変換します</value>
</data>
<data name="SettingsPageClickThrough.Header" xml:space="preserve">
<value>クリックスルー</value>
</data>
<data name="SettingsPageClickThroughHotKey.Header" xml:space="preserve">
<value>クリックスルーショートカットキー</value>
</data>
<data name="SettingsPageCompactTitleBar.Content" xml:space="preserve">
<value>コンパクト</value>
</data>
<data name="SettingsPageConfigName.Description" xml:space="preserve">
<value>記録されたウィンドウの状態に名前を付けると、それらをよりよく区別するのに役立ちます</value>
</data>
<data name="SettingsPageConfigName.Header" xml:space="preserve">
<value>設定名</value>
</data>
<data name="SettingsPageCreateFromCurrent.Content" xml:space="preserve">
<value>現在の歌詞ウィンドウのステータスから作成</value>
</data>
<data name="SettingsPageCreateFromTemplates.Content" xml:space="preserve">
<value>テンプレートから作成</value>
</data>
<data name="SettingsPageCurrentLyricsWindowStatus.Text" xml:space="preserve">
<value>現在の歌詞ウィンドウステータス</value>
</data>
@@ -559,29 +589,29 @@
<data name="SettingsPageDebugOverlay.Header" xml:space="preserve">
<value>デバッグオーバーレイを表示します</value>
</data>
<data name="SettingsPageDelete.Content" xml:space="preserve">
<data name="SettingsPageDelete.Text" xml:space="preserve">
<value>消去</value>
</data>
<data name="SettingsPageDesktopAcrylic.Content" xml:space="preserve">
<value>デスクトップアクリル</value>
<data name="SettingsPageDesktopMode.Text" xml:space="preserve">
<value>デスクトップモード(透明) </value>
</data>
<data name="SettingsPageDev.Content" xml:space="preserve">
<value>高度なオプション</value>
</data>
<data name="SettingsPageDisclaimer.Text" xml:space="preserve">
<data name="SettingsPageDisclaimer.Message" xml:space="preserve">
<value>このプロジェクトは、いかなる種類の保証もなく現状のまま提供されています。すべての歌詞、フォント、アイコン、およびその他のサードパーティのリソースは、それぞれの著作権所有者の財産です。このプロジェクトの作成者は、そのようなリソースの所有権を主張していません。このプロジェクトは非営利的であり、いかなる権利も侵害するために使用すべきではありません。ユーザーは、自らの使用が適用される法律およびライセンスに準拠していることを確認する責任があります。</value>
</data>
<data name="SettingsPageDiscord.Content" xml:space="preserve">
<value>Discord</value>
</data>
<data name="SettingsPageDisplayTypeSwitcher.Header" xml:space="preserve">
<value>歌詞アルバムレイアウトモード</value>
<value>レイアウトモード</value>
</data>
<data name="SettingsPageDockedMode.Text" xml:space="preserve">
<value>ドック式</value>
</data>
<data name="SettingsPageDockMonitor.Header" xml:space="preserve">
<value>ターゲットモニター</value>
</data>
<data name="SettingsPageDockPlacement.Header" xml:space="preserve">
<value>ドックモード配置</value>
<value>作業エリアの配置</value>
</data>
<data name="SettingsPageDockPlacementBottom.Content" xml:space="preserve">
<value>底</value>
@@ -592,6 +622,9 @@
<data name="SettingsPageDockWindowHeight.Header" xml:space="preserve">
<value>窓の高さ</value>
</data>
<data name="SettingsPageDragArea.Header" xml:space="preserve">
<value>ドラッグ可能</value>
</data>
<data name="SettingsPageDynamicLyricsFontSize.Header" xml:space="preserve">
<value>自動調整</value>
</data>
@@ -637,6 +670,21 @@
<data name="SettingsPageEN.Content" xml:space="preserve">
<value>English</value>
</data>
<data name="SettingsPageEnvColorSample.Header" xml:space="preserve">
<value>環境カラーサンプモード</value>
</data>
<data name="SettingsPageEnvColorSampleAbove.Content" xml:space="preserve">
<value>窓の上</value>
</data>
<data name="SettingsPageEnvColorSampleBelow.Content" xml:space="preserve">
<value>窓の下</value>
</data>
<data name="SettingsPageEnvColorSampleEdge.Content" xml:space="preserve">
<value>ウィンドウエッジ</value>
</data>
<data name="SettingsPageEnvColorSampleInner.Content" xml:space="preserve">
<value>窓の中だ</value>
</data>
<data name="SettingsPageExitOnLyricsWindowClosed.Header" xml:space="preserve">
<value>歌詞ウィンドウを閉じてプログラムを終了してください</value>
</data>
@@ -655,30 +703,33 @@
<data name="SettingsPageFixedTimeStep.Header" xml:space="preserve">
<value>固定時間ステップレンダリング</value>
</data>
<data name="SettingsPageFluidLayer.Header" xml:space="preserve">
<value>流体層</value>
</data>
<data name="SettingsPageFollowSystem.Content" xml:space="preserve">
<value>システムをフォローします</value>
</data>
<data name="SettingsPageForceAlwaysOnTop.Description" xml:space="preserve">
<value>ポーリングで歌詞ウィンドウを一番上に保ちましょう</value>
</data>
<data name="SettingsPageForceAlwaysOnTop.Header" xml:space="preserve">
<value>強制的に上に</value>
</data>
<data name="SettingsPageFPS.Header" xml:space="preserve">
<value>レンダリングフレームレート</value>
</data>
<data name="SettingsPageGlobalDrag.Description" xml:space="preserve">
<value>タイトルバーをページ全体に拡張して、ウィンドウを非対話領域でドラッグできるようにします</value>
<data name="SettingsPageFullscreenMode.Text" xml:space="preserve">
<value>フルスクリーンモード</value>
</data>
<data name="SettingsPageGlobalDrag.Header" xml:space="preserve">
<value>グローバルドラッグ</value>
<data name="SettingsPageHeight.Header" xml:space="preserve">
<value>高さ</value>
</data>
<data name="SettingsPageHideWindow.Description" xml:space="preserve">
<value>ドッキングモードまたはデスクトップモードでは、曲が再生されていない場合、ウィンドウは自動的に非表示になります。それ以外の場合、ウィンドウが自動的に表示されます</value>
<value>音楽が再生されていないときに、自動的に歌詞ウィンドウを非表示/表示します</value>
</data>
<data name="SettingsPageHideWindow.Header" xml:space="preserve">
<value>Windowsを自動的に非表示/表示します</value>
</data>
<data name="SettingsPageIgnoreFullscreenWindow.Description" xml:space="preserve">
<value>このアプリは、ドッキングまたはデスクトップモードが有効になっているときにフルスクリーンアプリの上に表示されます</value>
</data>
<data name="SettingsPageIgnoreFullscreenWindow.Header" xml:space="preserve">
<value>常にフルスクリーンアプリケーションを常に把握してください</value>
</data>
<data name="SettingsPageImportSettingsButton.Content" xml:space="preserve">
<value>設定をインポートします</value>
</data>
@@ -730,14 +781,23 @@
<data name="SettingsPageLastFMUsername.Header" xml:space="preserve">
<value>ユーザー名</value>
</data>
<data name="SettingsPageLayoutOrientation.Header" xml:space="preserve">
<value>レイアウトの向き</value>
</data>
<data name="SettingsPageLayoutOrientationHorizontal.Content" xml:space="preserve">
<value>水平方向</value>
</data>
<data name="SettingsPageLayoutOrientationVertical.Content" xml:space="preserve">
<value>垂直方向</value>
</data>
<data name="SettingsPageLibreTranslateServer.Header" xml:space="preserve">
<value>サーバーアドレス</value>
</data>
<data name="SettingsPageLight.Content" xml:space="preserve">
<value>ライト</value>
</data>
<data name="SettingsPageLockHotKey.Header" xml:space="preserve">
<value>ショートカットキーのロックを解除およびロックします</value>
<data name="SettingsPageListenNewSession.Header" xml:space="preserve">
<value>新しい再生ソースの監視を有効にします</value>
</data>
<data name="SettingsPageLog.Header" xml:space="preserve">
<value>ログレコード</value>
@@ -745,7 +805,7 @@
<data name="SettingsPageLXMusicServer.Text" xml:space="preserve">
<value>LX Music Server</value>
</data>
<data name="SettingsPageLyrics.Content" xml:space="preserve">
<data name="SettingsPageLyrics.Text" xml:space="preserve">
<value>歌詞のスタイルと効果</value>
</data>
<data name="SettingsPageLyricsAlignment.Header" xml:space="preserve">
@@ -754,15 +814,6 @@
<data name="SettingsPageLyricsBackground.Header" xml:space="preserve">
<value>歌詞の背景</value>
</data>
<data name="SettingsPageLyricsBackgroundBlurAmount.Header" xml:space="preserve">
<value>アルバムの背景レイヤーの曖昧さ</value>
</data>
<data name="SettingsPageLyricsBackgroundOpacity.Header" xml:space="preserve">
<value>アルバムの背景レイヤーの不透明度</value>
</data>
<data name="SettingsPageLyricsBackgroundSpeed.Header" xml:space="preserve">
<value>アルバムの背景レイヤーのモーションレート</value>
</data>
<data name="SettingsPageLyricsBgFontColor.Header" xml:space="preserve">
<value>フォントカラー(非電流再生エリア)</value>
</data>
@@ -862,9 +913,6 @@
<data name="SettingsPageLyricsNormal.Content" xml:space="preserve">
<value>普通</value>
</data>
<data name="SettingsPageLyricsPureColorBgOpacity.Header" xml:space="preserve">
<value>無地の背景レイヤーの不透明度</value>
</data>
<data name="SettingsPageLyricsRendingScopeCurrentChar.Content" xml:space="preserve">
<value>現在の文字</value>
</data>
@@ -916,9 +964,15 @@
<data name="SettingsPageLyricsVerticalEdgeOpacity.Header" xml:space="preserve">
<value>上端と下端の不透明度</value>
</data>
<data name="SettingsPageLyricsWindowManager.Header" xml:space="preserve">
<data name="SettingsPageLyricsWindowManager.Text" xml:space="preserve">
<value>歌詞ウィンドウマネージャー</value>
</data>
<data name="SettingsPageLyricsWindowMgr.Content" xml:space="preserve">
<value>歌詞ウィンドウマネージャー</value>
</data>
<data name="SettingsPageLyricsWindowSwitchHotKey.Header" xml:space="preserve">
<value>歌詞ウィンドウステータススイッチャーショートカット</value>
</data>
<data name="SettingsPageMediaLib.Content" xml:space="preserve">
<value>メディアライブラリ</value>
</data>
@@ -943,13 +997,19 @@
<data name="SettingsPageMusicLibRealTimeWatch.Header" xml:space="preserve">
<value>ファイルの変更をリアルタイムで聞いてください</value>
</data>
<data name="SettingsPageNarrowMode.Text" xml:space="preserve">
<value>狭い</value>
</data>
<data name="SettingsPageNextSongHotKey.Header" xml:space="preserve">
<value>次のトラックショートカットキー</value>
</data>
<data name="SettingsPageNoBackdrop.Content" xml:space="preserve">
<value>なし</value>
</data>
<data name="SettingsPageOpenLogFolderButton.Content" xml:space="preserve">
<data name="SettingsPageOpacity.Header" xml:space="preserve">
<value>不透明度</value>
</data>
<data name="SettingsPageOpenFolderButton.Content" xml:space="preserve">
<value>ファイルエクスプローラーで開きます</value>
</data>
<data name="SettingsPagePathBeIncludedInfo" xml:space="preserve">
@@ -985,9 +1045,15 @@
<data name="SettingsPagePreviousSongHotKey.Header" xml:space="preserve">
<value>前のトラックのショートカットキー</value>
</data>
<data name="SettingsPagePureLayer.Header" xml:space="preserve">
<value>ピュアカラーレイヤー</value>
</data>
<data name="SettingsPageQQGroup.Content" xml:space="preserve">
<value>QQフィードバックチャットグループ</value>
</data>
<data name="SettingsPageRealtimeStatus.Text" xml:space="preserve">
<value>リアルタイムステータス</value>
</data>
<data name="SettingsPageRecord.Content" xml:space="preserve">
<value>記録</value>
</data>
@@ -1042,6 +1108,9 @@
<data name="SettingsPageServerTestSuccessInfo" xml:space="preserve">
<value>サーバーテストが成功しました</value>
</data>
<data name="SettingsPageSettings.Header" xml:space="preserve">
<value>設定</value>
</data>
<data name="SettingsPageSettingsManager.Header" xml:space="preserve">
<value>設定マネージャー</value>
</data>
@@ -1051,9 +1120,21 @@
<data name="SettingsPageShortcutRegSuccessInfo" xml:space="preserve">
<value>このホットキーは正常に登録されています</value>
</data>
<data name="SettingsPageShowArtists.Header" xml:space="preserve">
<value>アーティスト</value>
</data>
<data name="SettingsPageShowHideHotKey.Header" xml:space="preserve">
<value>歌詞ウィンドウディスプレイとショートカットキーを非表示にします</value>
</data>
<data name="SettingsPageShowInSwitchers.Description" xml:space="preserve">
<value>例Alt + Tab、タスクバー</value>
</data>
<data name="SettingsPageShowInSwitchers.Header" xml:space="preserve">
<value>システム環境に表示します</value>
</data>
<data name="SettingsPageShowTitle.Header" xml:space="preserve">
<value>タイトルを表示</value>
</data>
<data name="SettingsPageSliderPrefix.Text" xml:space="preserve">
<value>現在の値: </value>
</data>
@@ -1072,6 +1153,15 @@
<data name="SettingsPageSongInfoRight.Content" xml:space="preserve">
<value>右</value>
</data>
<data name="SettingsPageSpectrumLayer.Header" xml:space="preserve">
<value>スペクトラムレイヤー</value>
</data>
<data name="SettingsPageSpeed.Header" xml:space="preserve">
<value>モーション</value>
</data>
<data name="SettingsPageStandardMode.Text" xml:space="preserve">
<value>標準モード</value>
</data>
<data name="SettingsPageSystemLanguage.Content" xml:space="preserve">
<value>デフォルト</value>
</data>
@@ -1090,6 +1180,15 @@
<data name="SettingsPageTitle" xml:space="preserve">
<value>設定 - BetterLyrics</value>
</data>
<data name="SettingsPageTitleBarAreaNone.Content" xml:space="preserve">
<value>なし</value>
</data>
<data name="SettingsPageTitleBarAreaTop.Content" xml:space="preserve">
<value>トップ</value>
</data>
<data name="SettingsPageTitleBarAreaWhole.Content" xml:space="preserve">
<value>窓全体</value>
</data>
<data name="SettingsPageTitleBarType.Header" xml:space="preserve">
<value>タイトルバーサイズ</value>
</data>
@@ -1111,6 +1210,24 @@
<data name="SettingsPageVersion.Text" xml:space="preserve">
<value>バージョン</value>
</data>
<data name="SettingsPageWidth.Header" xml:space="preserve">
<value>幅</value>
</data>
<data name="SettingsPageWindowBounds.Header" xml:space="preserve">
<value>ウィンドウ境界</value>
</data>
<data name="SettingsPageWorkArea.Description" xml:space="preserve">
<value>画面の上下端にドッキングされた別の作業エリアとして</value>
</data>
<data name="SettingsPageWorkArea.Header" xml:space="preserve">
<value>kawasan kerja</value>
</data>
<data name="SettingsPageWorkAreaHeight.Header" xml:space="preserve">
<value>作業エリアの高さ</value>
</data>
<data name="StandardMode" xml:space="preserve">
<value>標準モード</value>
</data>
<data name="SystemTrayExit.Text" xml:space="preserve">
<value>プログラムを終了します</value>
</data>
@@ -1132,9 +1249,6 @@
<data name="SystemTraySettings.Text" xml:space="preserve">
<value>設定を開く</value>
</data>
<data name="SystemTrayUnlock.Text" xml:space="preserve">
<value>ウィンドウのロックを解除します</value>
</data>
<data name="TranslateServerNotSet" xml:space="preserve">
<value>翻訳サーバーは設定されていません。最初に設定で構成してください</value>
</data>

View File

@@ -123,27 +123,12 @@
<data name="AlbumArtSearchSMTCProvider" xml:space="preserve">
<value>음악 플레이어</value>
</data>
<data name="AllLyricsSettingsControlDesktop.Content" xml:space="preserve">
<value>데스크탑 모드</value>
</data>
<data name="AllLyricsSettingsControlDock.Content" xml:space="preserve">
<value>도크 모드</value>
</data>
<data name="AllLyricsSettingsControlPictureInPicture.Content" xml:space="preserve">
<value>사진 인당 모드</value>
</data>
<data name="AllLyricsSettingsControlStandard.Content" xml:space="preserve">
<value>표준 모드</value>
</data>
<data name="AppSettingsControlGeneral.Content" xml:space="preserve">
<data name="AppSettingsControlGeneral.Text" xml:space="preserve">
<value>일반적인</value>
</data>
<data name="BaseWindowEnterFullScreenHint" xml:space="preserve">
<value>ESC를 눌러 전체 화면 모드를 종료하십시오</value>
</data>
<data name="BaseWindowFullScreenFlyoutItem.Text" xml:space="preserve">
<value>전체 화면</value>
</data>
<data name="BaseWindowHostInfoBarCheckBox.Content" xml:space="preserve">
<value>이 메시지를 다시 표시하지 마십시오</value>
</data>
@@ -153,32 +138,38 @@
<data name="Cancel" xml:space="preserve">
<value>취소</value>
</data>
<data name="DemoWindowControlDefault.Text" xml:space="preserve">
<value>기본</value>
</data>
<data name="DependenciesSettingsExpander.Header" xml:space="preserve">
<value>의존성</value>
</data>
<data name="DesktopMode" xml:space="preserve">
<value>데스크톱 모드 (투명)</value>
</data>
<data name="DockedMode" xml:space="preserve">
<value>도킹 모드</value>
</data>
<data name="ExportSettingsSuccess" xml:space="preserve">
<value>수출 성공</value>
</data>
<data name="FailToStartLXMusicServer" xml:space="preserve">
<value>LX Music Server에 연결할 수 없습니다. 설정으로 이동하십시오 - 고급 옵션이 링크가 올바르게 입력되었는지 확인하십시오.</value>
</data>
<data name="FullscreenMode" xml:space="preserve">
<value>전체화면 모드</value>
</data>
<data name="HostWindowClickThroughButton.Content" xml:space="preserve">
<value>잠금</value>
</data>
<data name="HostWindowClickThroughFlyoutItem.Text" xml:space="preserve">
<value>잠금</value>
</data>
<data name="HostWindowDesktopFlyoutItem.Text" xml:space="preserve">
<value>데스크탑 모드</value>
</data>
<data name="HostWindowDockFlyoutItem.Text" xml:space="preserve">
<value>도크 모드</value>
</data>
<data name="HostWindowLockToolTip.Text" xml:space="preserve">
<value>잠금</value>
</data>
<data name="HostWindowMoreButtonToolTip.Content" xml:space="preserve">
<value></value>
<data name="HostWindowMusicGalleryButtonToolTip.Content" xml:space="preserve">
<value>음악 갤러리</value>
</data>
<data name="HostWindowSettingsFlyoutItem.Text" xml:space="preserve">
<value>설정</value>
@@ -223,7 +214,7 @@
<value>가사를 수동으로 검색합니다</value>
</data>
<data name="LyricsPageLyricsSettingsButtonToolTip.Content" xml:space="preserve">
<value>가사 스타일과 효과 빠른 설정</value>
<value>가사 창 관리 바로 가기 설정</value>
</data>
<data name="LyricsPagePlaybackSourceButtonToolTip.Content" xml:space="preserve">
<value>재생 소스 빠른 설정</value>
@@ -303,11 +294,17 @@
<data name="LyricsWindowImmersiveButtonToolTip.Content" xml:space="preserve">
<value>몰입 형 모드</value>
</data>
<data name="MainPageAlbumArtOnly.Content" xml:space="preserve">
<value>앨범 아트 만</value>
<data name="LyricsWindowSettingsControlCurrentLyricsWindowConfig.Text" xml:space="preserve">
<value>현재 가사 창 구성</value>
</data>
<data name="MainPageDesktopLyricsToggler.ToolTipService.ToolTip" xml:space="preserve">
<value>데스크탑 가사 모드로 전환하십시오</value>
<data name="LyricsWindowSettingsControlLyricsWindowMode.Header" xml:space="preserve">
<value>가사 창 모드</value>
</data>
<data name="LyricsWindowSettingsControlSetDefault.Text" xml:space="preserve">
<value>기본 값으로 설정</value>
</data>
<data name="MainPageAlbumArtOnly.Content" xml:space="preserve">
<value>앨범 아트 영역만</value>
</data>
<data name="MainPageEnterImmersiveModeHint" xml:space="preserve">
<value>토글 버튼을 표시하려면 다시 다시 가져옵니다</value>
@@ -442,15 +439,18 @@
<data name="MusicGalleryPageTitle" xml:space="preserve">
<value>음악 갤러리 - BetterLyrics</value>
</data>
<data name="NarrowMode" xml:space="preserve">
<value>협폭 조명</value>
</data>
<data name="PictureInPictureMode" xml:space="preserve">
<value>사진 인당 모드</value>
</data>
<data name="SetingsPageDonation.Text" xml:space="preserve">
<value>기부</value>
</data>
<data name="SetingsPageFeedback.Text" xml:space="preserve">
<value>피드백</value>
</data>
<data name="SetingsPageRef.Text" xml:space="preserve">
<value>사용 된 라이브러리</value>
</data>
<data name="SetingsPageThanks.Text" xml:space="preserve">
<value>이 프로젝트가 마음에 들면 기부하여 지원을 고려하십시오. 귀하의 지원은 프로젝트를 계속 유지하고 추가 개발을 장려하는 데 도움이 될 것입니다.</value>
</data>
@@ -463,18 +463,33 @@
<data name="SettingsPageAcrylicThin.Content" xml:space="preserve">
<value>아크릴 얇은</value>
</data>
<data name="SettingsPageAdaptEnvColor.Description" xml:space="preserve">
<value>동시에 가사 배경의 순수 컬러 레이어 불투명도와 앨범 아트 레이어 불투명도를 0으로 설정하면 정확한 효과를 얻을 수 있습니다</value>
</data>
<data name="SettingsPageAdaptEnvColor.Header" xml:space="preserve">
<value>환경 색상에 적응하세요</value>
</data>
<data name="SettingsPageAddFolder.Header" xml:space="preserve">
<value>폴더를 추가하십시오</value>
</data>
<data name="SettingsPageAddFolderButton.Content" xml:space="preserve">
<value>추가하다</value>
</data>
<data name="SettingsPageAdvanced.Text" xml:space="preserve">
<value>고급 옵션</value>
</data>
<data name="SettingsPageAlbumArt.Text" xml:space="preserve">
<value>앨범 아트</value>
</data>
<data name="SettingsPageAlbumArtLayer.Header" xml:space="preserve">
<value>앨범 아트 레이어</value>
</data>
<data name="SettingsPageAlbumArtSearchProvidersConfig.Text" xml:space="preserve">
<value>앨범 표지 소스를 구성합니다</value>
</data>
<data name="SettingsPageAlbumArtSize.Header" xml:space="preserve">
<value>앨범아트</value>
</data>
<data name="SettingsPageAlbumLib.Content" xml:space="preserve">
<value>앨범 아트 소스</value>
</data>
@@ -484,14 +499,14 @@
<data name="SettingsPageAlbumShadowAmount.Header" xml:space="preserve">
<value>그림자가 얼마나 퍼져나가는지</value>
</data>
<data name="SettingsPageAlbumStyle.Content" xml:space="preserve">
<data name="SettingsPageAlbumStyle.Text" xml:space="preserve">
<value>앨범 영역 스타일</value>
</data>
<data name="SettingsPageAmount.Header" xml:space="preserve">
<value>금액</value>
</data>
<data name="SettingsPageAOT.Header" xml:space="preserve">
<value>항상 위에</value>
<value>가사 창을 맨 위로 가져옵니다</value>
</data>
<data name="SettingsPageApp.Content" xml:space="preserve">
<value>앱 외관과 행동</value>
@@ -500,29 +515,17 @@
<value>앱 모양</value>
</data>
<data name="SettingsPageAppBehavior.Text" xml:space="preserve">
<value>앱 동작</value>
<value>일반적인 행동</value>
</data>
<data name="SettingsPageApply.Content" xml:space="preserve">
<value>적용하다</value>
</data>
<data name="SettingsPageAutoLock.Header" xml:space="preserve">
<value>데스크탑 모드를 활성화 할 때 자동 잠금</value>
<data name="SettingsPageAutoSize.Header" xml:space="preserve">
<value>자동 크기 조정</value>
</data>
<data name="SettingsPageAutoStart.Header" xml:space="preserve">
<value>자동 시작</value>
</data>
<data name="SettingsPageAutoStartDesktopLyrics.Content" xml:space="preserve">
<value>데스크탑 모드를 시작하십시오</value>
</data>
<data name="SettingsPageAutoStartDockLyrics.Content" xml:space="preserve">
<value>도크 모드를 활성화하십시오</value>
</data>
<data name="SettingsPageAutoStartInAppLyrics.Content" xml:space="preserve">
<value>표준 모드를 ​​활성화합니다</value>
</data>
<data name="SettingsPageAutoStartPIPLyrics.Content" xml:space="preserve">
<value>Picture-in-Picture 모드를 시작하십시오</value>
</data>
<data name="SettingsPageAutoStartWindow.Header" xml:space="preserve">
<value>앱을 시작할 때</value>
</data>
@@ -532,9 +535,18 @@
<data name="SettingsPageBackgroundAcrylicEffectAmount.Header" xml:space="preserve">
<value>앨범 배경 아크릴 효과 강도</value>
</data>
<data name="SettingsPageBackgroundOverlay.Content" xml:space="preserve">
<data name="SettingsPageBackgroundOverlay.Text" xml:space="preserve">
<value>가사 배경</value>
</data>
<data name="SettingsPageBlurAmount.Header" xml:space="preserve">
<value>흐림 금액</value>
</data>
<data name="SettingsPageBorderless.Header" xml:space="preserve">
<value>창문</value>
</data>
<data name="SettingsPageBorderlessHotKey.Header" xml:space="preserve">
<value>테두리 없는 가사 창 단축키</value>
</data>
<data name="SettingsPageCache.Description" xml:space="preserve">
<value>로그 파일, 네트워크 가사 캐시 포함</value>
</data>
@@ -547,9 +559,27 @@
<data name="SettingsPageChinesePreference.Header" xml:space="preserve">
<value>중국어를 전통적인 중국어로 전환합니다</value>
</data>
<data name="SettingsPageClickThrough.Header" xml:space="preserve">
<value>클릭률</value>
</data>
<data name="SettingsPageClickThroughHotKey.Header" xml:space="preserve">
<value>바로 가기 키를 클릭하세요</value>
</data>
<data name="SettingsPageCompactTitleBar.Content" xml:space="preserve">
<value>콤팩트</value>
</data>
<data name="SettingsPageConfigName.Description" xml:space="preserve">
<value>녹화된 창 상태에 이름을 지정하면 더 잘 구별할 수 있습니다</value>
</data>
<data name="SettingsPageConfigName.Header" xml:space="preserve">
<value>환경 설정</value>
</data>
<data name="SettingsPageCreateFromCurrent.Content" xml:space="preserve">
<value>현재 가사 창 상태에서 만들기</value>
</data>
<data name="SettingsPageCreateFromTemplates.Content" xml:space="preserve">
<value>템플릿에서 만들기</value>
</data>
<data name="SettingsPageCurrentLyricsWindowStatus.Text" xml:space="preserve">
<value>현재 가사 창 상태</value>
</data>
@@ -559,29 +589,29 @@
<data name="SettingsPageDebugOverlay.Header" xml:space="preserve">
<value>디버그 오버레이를 표시하십시오</value>
</data>
<data name="SettingsPageDelete.Content" xml:space="preserve">
<data name="SettingsPageDelete.Text" xml:space="preserve">
<value>삭제</value>
</data>
<data name="SettingsPageDesktopAcrylic.Content" xml:space="preserve">
<value>데스크탑 아크릴</value>
<data name="SettingsPageDesktopMode.Text" xml:space="preserve">
<value>데스크톱 모드 (투명)</value>
</data>
<data name="SettingsPageDev.Content" xml:space="preserve">
<value>고급 옵션</value>
</data>
<data name="SettingsPageDisclaimer.Text" xml:space="preserve">
<data name="SettingsPageDisclaimer.Message" xml:space="preserve">
<value>이 프로젝트는 어떠한 종류의 보증도 없이 그대로 제공됩니다. 모든 가사, 글꼴, 아이콘 및 기타 제3자 리소스는 해당 저작권 소유자의 재산입니다. 이 프로젝트의 저자는 그러한 자원의 소유권을 주장하지 않습니다. 이 프로젝트는 비상업적이기 때문에 어떠한 권리도 침해해서는 안 됩니다. 사용자는 자신의 사용이 관련 법률 및 라이센스를 준수하는지 확인할 책임이 있습니다.</value>
</data>
<data name="SettingsPageDiscord.Content" xml:space="preserve">
<value>Discord</value>
</data>
<data name="SettingsPageDisplayTypeSwitcher.Header" xml:space="preserve">
<value>가사 앨범 레이아웃 모드</value>
<value>레이아웃 모드</value>
</data>
<data name="SettingsPageDockedMode.Text" xml:space="preserve">
<value>도킹 모드</value>
</data>
<data name="SettingsPageDockMonitor.Header" xml:space="preserve">
<value>대상 모니터</value>
</data>
<data name="SettingsPageDockPlacement.Header" xml:space="preserve">
<value>도크 모드 배치</value>
<value>작업 영역 배치</value>
</data>
<data name="SettingsPageDockPlacementBottom.Content" xml:space="preserve">
<value>맨 아래</value>
@@ -592,6 +622,9 @@
<data name="SettingsPageDockWindowHeight.Header" xml:space="preserve">
<value>창 높이</value>
</data>
<data name="SettingsPageDragArea.Header" xml:space="preserve">
<value>드래그 가능</value>
</data>
<data name="SettingsPageDynamicLyricsFontSize.Header" xml:space="preserve">
<value>자동 조정</value>
</data>
@@ -637,6 +670,21 @@
<data name="SettingsPageEN.Content" xml:space="preserve">
<value>English</value>
</data>
<data name="SettingsPageEnvColorSample.Header" xml:space="preserve">
<value>환경 컬러 삼페 모드</value>
</data>
<data name="SettingsPageEnvColorSampleAbove.Content" xml:space="preserve">
<value>창문 너머</value>
</data>
<data name="SettingsPageEnvColorSampleBelow.Content" xml:space="preserve">
<value>창문 아래</value>
</data>
<data name="SettingsPageEnvColorSampleEdge.Content" xml:space="preserve">
<value>창 가장자리</value>
</data>
<data name="SettingsPageEnvColorSampleInner.Content" xml:space="preserve">
<value>창문 안쪽</value>
</data>
<data name="SettingsPageExitOnLyricsWindowClosed.Header" xml:space="preserve">
<value>가사 창을 닫으면 프로그램을 종료하세요</value>
</data>
@@ -655,30 +703,33 @@
<data name="SettingsPageFixedTimeStep.Header" xml:space="preserve">
<value>고정 시간 단계 렌더링</value>
</data>
<data name="SettingsPageFluidLayer.Header" xml:space="preserve">
<value>유체 층</value>
</data>
<data name="SettingsPageFollowSystem.Content" xml:space="preserve">
<value>시스템을 따르십시오</value>
</data>
<data name="SettingsPageForceAlwaysOnTop.Description" xml:space="preserve">
<value>투표를 통해 가사 창을 맨 위에 두세요</value>
</data>
<data name="SettingsPageForceAlwaysOnTop.Header" xml:space="preserve">
<value>꼭대기에 강제로</value>
</data>
<data name="SettingsPageFPS.Header" xml:space="preserve">
<value>렌더링 프레임 속도</value>
</data>
<data name="SettingsPageGlobalDrag.Description" xml:space="preserve">
<value>비 중과 영역에서 창을 드래그 할 수 있도록 제목 표시 줄을 전체 페이지로 확장하십시오.</value>
<data name="SettingsPageFullscreenMode.Text" xml:space="preserve">
<value>전체화면 모드</value>
</data>
<data name="SettingsPageGlobalDrag.Header" xml:space="preserve">
<value>글로벌 드래그</value>
<data name="SettingsPageHeight.Header" xml:space="preserve">
<value>신장</value>
</data>
<data name="SettingsPageHideWindow.Description" xml:space="preserve">
<value>도킹 모드 또는 데스크탑 모드에서는 노래가 재생되지 않으면 창이 자동으로 숨겨집니다. 그렇지 않으면 창이 자동으로 표시됩니다.</value>
<value>음악이 재생되지 않을 때 자동으로 가사 창 숨기기/표시</value>
</data>
<data name="SettingsPageHideWindow.Header" xml:space="preserve">
<value>Windows를 자동으로 숨기고 표시합니다</value>
</data>
<data name="SettingsPageIgnoreFullscreenWindow.Description" xml:space="preserve">
<value>도킹 또는 데스크탑 모드가 활성화 될 때이 앱이 전체 화면 앱 위에 나타나도록 강요</value>
</data>
<data name="SettingsPageIgnoreFullscreenWindow.Header" xml:space="preserve">
<value>항상 전체 화면 응용 프로그램 위에 머물러 있습니다</value>
</data>
<data name="SettingsPageImportSettingsButton.Content" xml:space="preserve">
<value>가져 오기 설정</value>
</data>
@@ -730,14 +781,23 @@
<data name="SettingsPageLastFMUsername.Header" xml:space="preserve">
<value>사용자 이름</value>
</data>
<data name="SettingsPageLayoutOrientation.Header" xml:space="preserve">
<value>레이아웃 방향</value>
</data>
<data name="SettingsPageLayoutOrientationHorizontal.Content" xml:space="preserve">
<value>수평</value>
</data>
<data name="SettingsPageLayoutOrientationVertical.Content" xml:space="preserve">
<value>세로</value>
</data>
<data name="SettingsPageLibreTranslateServer.Header" xml:space="preserve">
<value>서버 주소</value>
</data>
<data name="SettingsPageLight.Content" xml:space="preserve">
<value>빛</value>
</data>
<data name="SettingsPageLockHotKey.Header" xml:space="preserve">
<value>바로 가기 키를 잠금 해제하고 잠그십시오</value>
<data name="SettingsPageListenNewSession.Header" xml:space="preserve">
<value>새로운 재생 소스에 대한 모니터링을 활성화하십시오</value>
</data>
<data name="SettingsPageLog.Header" xml:space="preserve">
<value>로그 레코드</value>
@@ -745,7 +805,7 @@
<data name="SettingsPageLXMusicServer.Text" xml:space="preserve">
<value>LX 음악 서버</value>
</data>
<data name="SettingsPageLyrics.Content" xml:space="preserve">
<data name="SettingsPageLyrics.Text" xml:space="preserve">
<value>가사 스타일과 효과</value>
</data>
<data name="SettingsPageLyricsAlignment.Header" xml:space="preserve">
@@ -754,15 +814,6 @@
<data name="SettingsPageLyricsBackground.Header" xml:space="preserve">
<value>가사 배경</value>
</data>
<data name="SettingsPageLyricsBackgroundBlurAmount.Header" xml:space="preserve">
<value>앨범 배경 레이어 모호성</value>
</data>
<data name="SettingsPageLyricsBackgroundOpacity.Header" xml:space="preserve">
<value>앨범 배경 레이어 불투명도</value>
</data>
<data name="SettingsPageLyricsBackgroundSpeed.Header" xml:space="preserve">
<value>앨범 배경 레이어 모션 속도</value>
</data>
<data name="SettingsPageLyricsBgFontColor.Header" xml:space="preserve">
<value>글꼴 색상 (비 전류 재생 영역)</value>
</data>
@@ -862,9 +913,6 @@
<data name="SettingsPageLyricsNormal.Content" xml:space="preserve">
<value>정상</value>
</data>
<data name="SettingsPageLyricsPureColorBgOpacity.Header" xml:space="preserve">
<value>단단한 배경 레이어 불투명도</value>
</data>
<data name="SettingsPageLyricsRendingScopeCurrentChar.Content" xml:space="preserve">
<value>현재 숯</value>
</data>
@@ -916,9 +964,15 @@
<data name="SettingsPageLyricsVerticalEdgeOpacity.Header" xml:space="preserve">
<value>상단 및 하단 가장자리 불투명도</value>
</data>
<data name="SettingsPageLyricsWindowManager.Header" xml:space="preserve">
<data name="SettingsPageLyricsWindowManager.Text" xml:space="preserve">
<value>가사 창 관리자</value>
</data>
<data name="SettingsPageLyricsWindowMgr.Content" xml:space="preserve">
<value>가사 창 관리자</value>
</data>
<data name="SettingsPageLyricsWindowSwitchHotKey.Header" xml:space="preserve">
<value>가사 창 상태 전환기 바로 가기</value>
</data>
<data name="SettingsPageMediaLib.Content" xml:space="preserve">
<value>미디어 라이브러리</value>
</data>
@@ -943,13 +997,19 @@
<data name="SettingsPageMusicLibRealTimeWatch.Header" xml:space="preserve">
<value>실시간으로 파일 변경을 듣습니다</value>
</data>
<data name="SettingsPageNarrowMode.Text" xml:space="preserve">
<value>협폭 조명</value>
</data>
<data name="SettingsPageNextSongHotKey.Header" xml:space="preserve">
<value>다음 트랙 바로 가기 키</value>
</data>
<data name="SettingsPageNoBackdrop.Content" xml:space="preserve">
<value>없음</value>
</data>
<data name="SettingsPageOpenLogFolderButton.Content" xml:space="preserve">
<data name="SettingsPageOpacity.Header" xml:space="preserve">
<value>투명도</value>
</data>
<data name="SettingsPageOpenFolderButton.Content" xml:space="preserve">
<value>파일 탐색기에서 열립니다</value>
</data>
<data name="SettingsPagePathBeIncludedInfo" xml:space="preserve">
@@ -985,9 +1045,15 @@
<data name="SettingsPagePreviousSongHotKey.Header" xml:space="preserve">
<value>이전 트랙의 바로 가기 키</value>
</data>
<data name="SettingsPagePureLayer.Header" xml:space="preserve">
<value>순수한 컬러 레이어</value>
</data>
<data name="SettingsPageQQGroup.Content" xml:space="preserve">
<value>QQ 피드백 및 채팅 그룹</value>
</data>
<data name="SettingsPageRealtimeStatus.Text" xml:space="preserve">
<value>실시간 상태</value>
</data>
<data name="SettingsPageRecord.Content" xml:space="preserve">
<value>기록</value>
</data>
@@ -1042,6 +1108,9 @@
<data name="SettingsPageServerTestSuccessInfo" xml:space="preserve">
<value>서버 테스트 성공</value>
</data>
<data name="SettingsPageSettings.Header" xml:space="preserve">
<value>설정</value>
</data>
<data name="SettingsPageSettingsManager.Header" xml:space="preserve">
<value>설정 관리자</value>
</data>
@@ -1051,9 +1120,21 @@
<data name="SettingsPageShortcutRegSuccessInfo" xml:space="preserve">
<value>이 핫키는 성공적으로 등록되었습니다</value>
</data>
<data name="SettingsPageShowArtists.Header" xml:space="preserve">
<value>예술가</value>
</data>
<data name="SettingsPageShowHideHotKey.Header" xml:space="preserve">
<value>가사 창 디스플레이 및 바로 가기 키 숨기기</value>
</data>
<data name="SettingsPageShowInSwitchers.Description" xml:space="preserve">
<value>예: Alt + Tab, 작업 표시줄</value>
</data>
<data name="SettingsPageShowInSwitchers.Header" xml:space="preserve">
<value>시스템 환경에서 보여주세요</value>
</data>
<data name="SettingsPageShowTitle.Header" xml:space="preserve">
<value>제목 표시</value>
</data>
<data name="SettingsPageSliderPrefix.Text" xml:space="preserve">
<value>현재 가치 : </value>
</data>
@@ -1072,6 +1153,15 @@
<data name="SettingsPageSongInfoRight.Content" xml:space="preserve">
<value>오른쪽</value>
</data>
<data name="SettingsPageSpectrumLayer.Header" xml:space="preserve">
<value>스펙트럼 레이어</value>
</data>
<data name="SettingsPageSpeed.Header" xml:space="preserve">
<value>모션</value>
</data>
<data name="SettingsPageStandardMode.Text" xml:space="preserve">
<value>표준 모드</value>
</data>
<data name="SettingsPageSystemLanguage.Content" xml:space="preserve">
<value>기본</value>
</data>
@@ -1090,6 +1180,15 @@
<data name="SettingsPageTitle" xml:space="preserve">
<value>설정 - BetterLyrics</value>
</data>
<data name="SettingsPageTitleBarAreaNone.Content" xml:space="preserve">
<value>없음</value>
</data>
<data name="SettingsPageTitleBarAreaTop.Content" xml:space="preserve">
<value>맨 위</value>
</data>
<data name="SettingsPageTitleBarAreaWhole.Content" xml:space="preserve">
<value>창문 전체</value>
</data>
<data name="SettingsPageTitleBarType.Header" xml:space="preserve">
<value>제목 바 크기</value>
</data>
@@ -1111,6 +1210,24 @@
<data name="SettingsPageVersion.Text" xml:space="preserve">
<value>버전</value>
</data>
<data name="SettingsPageWidth.Header" xml:space="preserve">
<value>너비</value>
</data>
<data name="SettingsPageWindowBounds.Header" xml:space="preserve">
<value>창 범위</value>
</data>
<data name="SettingsPageWorkArea.Description" xml:space="preserve">
<value>화면의 상단/하단 가장자리에 고정된 별도의 작업 영역으로</value>
</data>
<data name="SettingsPageWorkArea.Header" xml:space="preserve">
<value>작업 구역</value>
</data>
<data name="SettingsPageWorkAreaHeight.Header" xml:space="preserve">
<value>작업 영역 높이</value>
</data>
<data name="StandardMode" xml:space="preserve">
<value>표준 모드</value>
</data>
<data name="SystemTrayExit.Text" xml:space="preserve">
<value>프로그램을 종료하십시오</value>
</data>
@@ -1132,9 +1249,6 @@
<data name="SystemTraySettings.Text" xml:space="preserve">
<value>열기 설정</value>
</data>
<data name="SystemTrayUnlock.Text" xml:space="preserve">
<value>창을 잠금 해제하십시오</value>
</data>
<data name="TranslateServerNotSet" xml:space="preserve">
<value>번역 서버가 설정되지 않았습니다. 먼저 설정으로 구성하십시오.</value>
</data>

View File

@@ -123,27 +123,12 @@
<data name="AlbumArtSearchSMTCProvider" xml:space="preserve">
<value>音乐播放器</value>
</data>
<data name="AllLyricsSettingsControlDesktop.Content" xml:space="preserve">
<value>桌面模式</value>
</data>
<data name="AllLyricsSettingsControlDock.Content" xml:space="preserve">
<value>停靠模式</value>
</data>
<data name="AllLyricsSettingsControlPictureInPicture.Content" xml:space="preserve">
<value>画中画模式</value>
</data>
<data name="AllLyricsSettingsControlStandard.Content" xml:space="preserve">
<value>标准模式</value>
</data>
<data name="AppSettingsControlGeneral.Content" xml:space="preserve">
<data name="AppSettingsControlGeneral.Text" xml:space="preserve">
<value>通用</value>
</data>
<data name="BaseWindowEnterFullScreenHint" xml:space="preserve">
<value>按 Esc 退出全屏模式</value>
</data>
<data name="BaseWindowFullScreenFlyoutItem.Text" xml:space="preserve">
<value>全屏</value>
</data>
<data name="BaseWindowHostInfoBarCheckBox.Content" xml:space="preserve">
<value>不再显示此消息</value>
</data>
@@ -153,32 +138,38 @@
<data name="Cancel" xml:space="preserve">
<value>取消</value>
</data>
<data name="DemoWindowControlDefault.Text" xml:space="preserve">
<value>默认</value>
</data>
<data name="DependenciesSettingsExpander.Header" xml:space="preserve">
<value>依赖</value>
</data>
<data name="DesktopMode" xml:space="preserve">
<value>桌面模式(透明)</value>
</data>
<data name="DockedMode" xml:space="preserve">
<value>停靠模式</value>
</data>
<data name="ExportSettingsSuccess" xml:space="preserve">
<value>导出成功</value>
</data>
<data name="FailToStartLXMusicServer" xml:space="preserve">
<value>无法连接到 LX 音乐服务器,请转到设置 - 高级选项以检查是否正确输入链接</value>
</data>
<data name="FullscreenMode" xml:space="preserve">
<value>全屏模式</value>
</data>
<data name="HostWindowClickThroughButton.Content" xml:space="preserve">
<value>锁定</value>
</data>
<data name="HostWindowClickThroughFlyoutItem.Text" xml:space="preserve">
<value>锁定</value>
</data>
<data name="HostWindowDesktopFlyoutItem.Text" xml:space="preserve">
<value>桌面模式</value>
</data>
<data name="HostWindowDockFlyoutItem.Text" xml:space="preserve">
<value>停靠模式</value>
</data>
<data name="HostWindowLockToolTip.Text" xml:space="preserve">
<value>锁定</value>
</data>
<data name="HostWindowMoreButtonToolTip.Content" xml:space="preserve">
<value>更多</value>
<data name="HostWindowMusicGalleryButtonToolTip.Content" xml:space="preserve">
<value>音乐库</value>
</data>
<data name="HostWindowSettingsFlyoutItem.Text" xml:space="preserve">
<value>设置</value>
@@ -223,7 +214,7 @@
<value>手动检索歌词</value>
</data>
<data name="LyricsPageLyricsSettingsButtonToolTip.Content" xml:space="preserve">
<value>歌词样式与效果快捷设置</value>
<value>歌词窗口管理快捷设置</value>
</data>
<data name="LyricsPagePlaybackSourceButtonToolTip.Content" xml:space="preserve">
<value>播放源快捷设置</value>
@@ -303,11 +294,17 @@
<data name="LyricsWindowImmersiveButtonToolTip.Content" xml:space="preserve">
<value>沉浸模式</value>
</data>
<data name="MainPageAlbumArtOnly.Content" xml:space="preserve">
<value>仅显示专辑封面</value>
<data name="LyricsWindowSettingsControlCurrentLyricsWindowConfig.Text" xml:space="preserve">
<value>当前歌词窗口配置</value>
</data>
<data name="MainPageDesktopLyricsToggler.ToolTipService.ToolTip" xml:space="preserve">
<value>切换到桌面歌词模式</value>
<data name="LyricsWindowSettingsControlLyricsWindowMode.Header" xml:space="preserve">
<value>歌词窗口模式</value>
</data>
<data name="LyricsWindowSettingsControlSetDefault.Text" xml:space="preserve">
<value>设为默认</value>
</data>
<data name="MainPageAlbumArtOnly.Content" xml:space="preserve">
<value>仅显示专辑区域</value>
</data>
<data name="MainPageEnterImmersiveModeHint" xml:space="preserve">
<value>再次悬停以显示切换按钮</value>
@@ -442,15 +439,18 @@
<data name="MusicGalleryPageTitle" xml:space="preserve">
<value>音乐库 - BetterLyrics</value>
</data>
<data name="NarrowMode" xml:space="preserve">
<value>窄屏模式</value>
</data>
<data name="PictureInPictureMode" xml:space="preserve">
<value>画中画模式</value>
</data>
<data name="SetingsPageDonation.Text" xml:space="preserve">
<value>捐贈</value>
</data>
<data name="SetingsPageFeedback.Text" xml:space="preserve">
<value>反馈</value>
</data>
<data name="SetingsPageRef.Text" xml:space="preserve">
<value>使用的库</value>
</data>
<data name="SetingsPageThanks.Text" xml:space="preserve">
<value>如果您喜欢这个项目,请考虑通过捐赠来支持它。您的支持将有助于保持项目的生命并鼓励进一步的发展。</value>
</data>
@@ -463,18 +463,33 @@
<data name="SettingsPageAcrylicThin.Content" xml:space="preserve">
<value>亚克力(薄层)</value>
</data>
<data name="SettingsPageAdaptEnvColor.Description" xml:space="preserve">
<value>同时,将歌词背景中的纯色图层不透明度和专辑美术图层不透明度设置为 0 ,以获得正确的效果</value>
</data>
<data name="SettingsPageAdaptEnvColor.Header" xml:space="preserve">
<value>适应环境色彩</value>
</data>
<data name="SettingsPageAddFolder.Header" xml:space="preserve">
<value>添加文件夹</value>
</data>
<data name="SettingsPageAddFolderButton.Content" xml:space="preserve">
<value>添加</value>
</data>
<data name="SettingsPageAdvanced.Text" xml:space="preserve">
<value>高级选项</value>
</data>
<data name="SettingsPageAlbumArt.Text" xml:space="preserve">
<value>专辑</value>
</data>
<data name="SettingsPageAlbumArtLayer.Header" xml:space="preserve">
<value>专辑艺术图层</value>
</data>
<data name="SettingsPageAlbumArtSearchProvidersConfig.Text" xml:space="preserve">
<value>配置专辑封面源</value>
</data>
<data name="SettingsPageAlbumArtSize.Header" xml:space="preserve">
<value>专辑封面</value>
</data>
<data name="SettingsPageAlbumLib.Content" xml:space="preserve">
<value>专辑封面源</value>
</data>
@@ -484,14 +499,14 @@
<data name="SettingsPageAlbumShadowAmount.Header" xml:space="preserve">
<value>阴影扩散程度</value>
</data>
<data name="SettingsPageAlbumStyle.Content" xml:space="preserve">
<data name="SettingsPageAlbumStyle.Text" xml:space="preserve">
<value>专辑区域样式</value>
</data>
<data name="SettingsPageAmount.Header" xml:space="preserve">
<value>量</value>
</data>
<data name="SettingsPageAOT.Header" xml:space="preserve">
<value>将应用置于顶层</value>
<value>将歌词窗口置于顶层</value>
</data>
<data name="SettingsPageApp.Content" xml:space="preserve">
<value>应用外观与行为</value>
@@ -500,29 +515,17 @@
<value>应用外观</value>
</data>
<data name="SettingsPageAppBehavior.Text" xml:space="preserve">
<value>应用行为</value>
<value>一般行为</value>
</data>
<data name="SettingsPageApply.Content" xml:space="preserve">
<value>应用</value>
</data>
<data name="SettingsPageAutoLock.Header" xml:space="preserve">
<value>启动桌面模式时随即锁定窗口</value>
<data name="SettingsPageAutoSize.Header" xml:space="preserve">
<value>自动调整尺寸</value>
</data>
<data name="SettingsPageAutoStart.Header" xml:space="preserve">
<value>自动启动</value>
</data>
<data name="SettingsPageAutoStartDesktopLyrics.Content" xml:space="preserve">
<value>启动桌面模式</value>
</data>
<data name="SettingsPageAutoStartDockLyrics.Content" xml:space="preserve">
<value>启动停靠模式</value>
</data>
<data name="SettingsPageAutoStartInAppLyrics.Content" xml:space="preserve">
<value>启动标准模式</value>
</data>
<data name="SettingsPageAutoStartPIPLyrics.Content" xml:space="preserve">
<value>启动画中画模式</value>
</data>
<data name="SettingsPageAutoStartWindow.Header" xml:space="preserve">
<value>启动应用时</value>
</data>
@@ -532,9 +535,18 @@
<data name="SettingsPageBackgroundAcrylicEffectAmount.Header" xml:space="preserve">
<value>专辑背景亚克力效果强度</value>
</data>
<data name="SettingsPageBackgroundOverlay.Content" xml:space="preserve">
<data name="SettingsPageBackgroundOverlay.Text" xml:space="preserve">
<value>歌词背景</value>
</data>
<data name="SettingsPageBlurAmount.Header" xml:space="preserve">
<value>模糊度</value>
</data>
<data name="SettingsPageBorderless.Header" xml:space="preserve">
<value>无边框窗口</value>
</data>
<data name="SettingsPageBorderlessHotKey.Header" xml:space="preserve">
<value>无边框歌词窗口快捷方式</value>
</data>
<data name="SettingsPageCache.Description" xml:space="preserve">
<value>包括日志文件,网络歌词缓存</value>
</data>
@@ -547,9 +559,27 @@
<data name="SettingsPageChinesePreference.Header" xml:space="preserve">
<value>中文转换为繁体</value>
</data>
<data name="SettingsPageClickThrough.Header" xml:space="preserve">
<value>点击穿透</value>
</data>
<data name="SettingsPageClickThroughHotKey.Header" xml:space="preserve">
<value>点击穿透快捷键</value>
</data>
<data name="SettingsPageCompactTitleBar.Content" xml:space="preserve">
<value>紧凑</value>
</data>
<data name="SettingsPageConfigName.Description" xml:space="preserve">
<value>命名记录的窗口状态可以帮助您更好地区分它们</value>
</data>
<data name="SettingsPageConfigName.Header" xml:space="preserve">
<value>配置名称</value>
</data>
<data name="SettingsPageCreateFromCurrent.Content" xml:space="preserve">
<value>从当前歌词窗口状态创建</value>
</data>
<data name="SettingsPageCreateFromTemplates.Content" xml:space="preserve">
<value>从模板创建</value>
</data>
<data name="SettingsPageCurrentLyricsWindowStatus.Text" xml:space="preserve">
<value>当前歌词窗口状态</value>
</data>
@@ -559,29 +589,29 @@
<data name="SettingsPageDebugOverlay.Header" xml:space="preserve">
<value>显示调试覆盖层</value>
</data>
<data name="SettingsPageDelete.Content" xml:space="preserve">
<data name="SettingsPageDelete.Text" xml:space="preserve">
<value>删除</value>
</data>
<data name="SettingsPageDesktopAcrylic.Content" xml:space="preserve">
<value>亚克力(桌面)</value>
<data name="SettingsPageDesktopMode.Text" xml:space="preserve">
<value>桌面模式(透明</value>
</data>
<data name="SettingsPageDev.Content" xml:space="preserve">
<value>高级选项</value>
</data>
<data name="SettingsPageDisclaimer.Text" xml:space="preserve">
<data name="SettingsPageDisclaimer.Message" xml:space="preserve">
<value>本项目按原样提供,不提供任何形式的保证。所有歌词、字体、图标和其他第三方资源均为其各自版权所有者的财产。本项目的作者不主张此类资源的所有权。本项目为非商业性项目,不得用于侵犯任何权利。用户有责任确保自己的使用符合适用的法律和许可。</value>
</data>
<data name="SettingsPageDiscord.Content" xml:space="preserve">
<value>Discord</value>
</data>
<data name="SettingsPageDisplayTypeSwitcher.Header" xml:space="preserve">
<value>歌词专辑布局模式</value>
<value>布局模式</value>
</data>
<data name="SettingsPageDockedMode.Text" xml:space="preserve">
<value>停靠模式</value>
</data>
<data name="SettingsPageDockMonitor.Header" xml:space="preserve">
<value>目标显示器</value>
</data>
<data name="SettingsPageDockPlacement.Header" xml:space="preserve">
<value>停靠模式位置</value>
<value>工作区域位置</value>
</data>
<data name="SettingsPageDockPlacementBottom.Content" xml:space="preserve">
<value>底部</value>
@@ -592,6 +622,9 @@
<data name="SettingsPageDockWindowHeight.Header" xml:space="preserve">
<value>窗口高度</value>
</data>
<data name="SettingsPageDragArea.Header" xml:space="preserve">
<value>可拖拽区域</value>
</data>
<data name="SettingsPageDynamicLyricsFontSize.Header" xml:space="preserve">
<value>自动调整</value>
</data>
@@ -637,6 +670,21 @@
<data name="SettingsPageEN.Content" xml:space="preserve">
<value>English</value>
</data>
<data name="SettingsPageEnvColorSample.Header" xml:space="preserve">
<value>环境色彩采样模式</value>
</data>
<data name="SettingsPageEnvColorSampleAbove.Content" xml:space="preserve">
<value>窗口上方</value>
</data>
<data name="SettingsPageEnvColorSampleBelow.Content" xml:space="preserve">
<value>窗口下方</value>
</data>
<data name="SettingsPageEnvColorSampleEdge.Content" xml:space="preserve">
<value>窗口边缘</value>
</data>
<data name="SettingsPageEnvColorSampleInner.Content" xml:space="preserve">
<value>窗口内部</value>
</data>
<data name="SettingsPageExitOnLyricsWindowClosed.Header" xml:space="preserve">
<value>关闭歌词窗口时退出程序</value>
</data>
@@ -655,30 +703,33 @@
<data name="SettingsPageFixedTimeStep.Header" xml:space="preserve">
<value>固定时间步长渲染</value>
</data>
<data name="SettingsPageFluidLayer.Header" xml:space="preserve">
<value>流体层</value>
</data>
<data name="SettingsPageFollowSystem.Content" xml:space="preserve">
<value>跟随系统</value>
</data>
<data name="SettingsPageForceAlwaysOnTop.Description" xml:space="preserve">
<value>通过轮询方式使歌词窗口保持置于顶层状态</value>
</data>
<data name="SettingsPageForceAlwaysOnTop.Header" xml:space="preserve">
<value>强制置于顶层</value>
</data>
<data name="SettingsPageFPS.Header" xml:space="preserve">
<value>渲染帧率</value>
</data>
<data name="SettingsPageGlobalDrag.Description" xml:space="preserve">
<value>将标题栏扩展至整个页面使得在任意非交互区域均可拖拽窗口</value>
<data name="SettingsPageFullscreenMode.Text" xml:space="preserve">
<value>全屏模式</value>
</data>
<data name="SettingsPageGlobalDrag.Header" xml:space="preserve">
<value>全局拖拽</value>
<data name="SettingsPageHeight.Header" xml:space="preserve">
<value>高度</value>
</data>
<data name="SettingsPageHideWindow.Description" xml:space="preserve">
<value>停靠模式或桌面模式下,无歌曲正在播放时自动隐藏窗口;反之自动显示窗口</value>
<value>音乐未播放/播放时自动隐藏/显示歌词窗口</value>
</data>
<data name="SettingsPageHideWindow.Header" xml:space="preserve">
<value>自动隐藏/显示窗口</value>
</data>
<data name="SettingsPageIgnoreFullscreenWindow.Description" xml:space="preserve">
<value>当启用停靠模式或桌面模式时强制将本应用显示在全屏应用的上方</value>
</data>
<data name="SettingsPageIgnoreFullscreenWindow.Header" xml:space="preserve">
<value>始终显示在全屏应用上方</value>
</data>
<data name="SettingsPageImportSettingsButton.Content" xml:space="preserve">
<value>导入设置</value>
</data>
@@ -730,14 +781,23 @@
<data name="SettingsPageLastFMUsername.Header" xml:space="preserve">
<value>用户名</value>
</data>
<data name="SettingsPageLayoutOrientation.Header" xml:space="preserve">
<value>布局方向</value>
</data>
<data name="SettingsPageLayoutOrientationHorizontal.Content" xml:space="preserve">
<value>横向</value>
</data>
<data name="SettingsPageLayoutOrientationVertical.Content" xml:space="preserve">
<value>垂直</value>
</data>
<data name="SettingsPageLibreTranslateServer.Header" xml:space="preserve">
<value>服务器地址</value>
</data>
<data name="SettingsPageLight.Content" xml:space="preserve">
<value>浅色</value>
</data>
<data name="SettingsPageLockHotKey.Header" xml:space="preserve">
<value>解锁和锁定快捷键</value>
<data name="SettingsPageListenNewSession.Header" xml:space="preserve">
<value>启用对新播放源的监听</value>
</data>
<data name="SettingsPageLog.Header" xml:space="preserve">
<value>日志记录</value>
@@ -745,7 +805,7 @@
<data name="SettingsPageLXMusicServer.Text" xml:space="preserve">
<value>LX 音乐服务器</value>
</data>
<data name="SettingsPageLyrics.Content" xml:space="preserve">
<data name="SettingsPageLyrics.Text" xml:space="preserve">
<value>歌词样式与动效</value>
</data>
<data name="SettingsPageLyricsAlignment.Header" xml:space="preserve">
@@ -754,15 +814,6 @@
<data name="SettingsPageLyricsBackground.Header" xml:space="preserve">
<value>歌词背景</value>
</data>
<data name="SettingsPageLyricsBackgroundBlurAmount.Header" xml:space="preserve">
<value>专辑背景层模糊度</value>
</data>
<data name="SettingsPageLyricsBackgroundOpacity.Header" xml:space="preserve">
<value>专辑背景层不透明度</value>
</data>
<data name="SettingsPageLyricsBackgroundSpeed.Header" xml:space="preserve">
<value>专辑背景层运动速率</value>
</data>
<data name="SettingsPageLyricsBgFontColor.Header" xml:space="preserve">
<value>字体颜色(非当前播放区域)</value>
</data>
@@ -862,9 +913,6 @@
<data name="SettingsPageLyricsNormal.Content" xml:space="preserve">
<value>常规</value>
</data>
<data name="SettingsPageLyricsPureColorBgOpacity.Header" xml:space="preserve">
<value>纯色背景层不透明度</value>
</data>
<data name="SettingsPageLyricsRendingScopeCurrentChar.Content" xml:space="preserve">
<value>当前字符</value>
</data>
@@ -916,9 +964,15 @@
<data name="SettingsPageLyricsVerticalEdgeOpacity.Header" xml:space="preserve">
<value>上下边缘不透明度</value>
</data>
<data name="SettingsPageLyricsWindowManager.Header" xml:space="preserve">
<data name="SettingsPageLyricsWindowManager.Text" xml:space="preserve">
<value>歌词窗口管理</value>
</data>
<data name="SettingsPageLyricsWindowMgr.Content" xml:space="preserve">
<value>歌词窗口管理</value>
</data>
<data name="SettingsPageLyricsWindowSwitchHotKey.Header" xml:space="preserve">
<value>歌词窗口状态切换器快捷方式</value>
</data>
<data name="SettingsPageMediaLib.Content" xml:space="preserve">
<value>媒体库</value>
</data>
@@ -943,13 +997,19 @@
<data name="SettingsPageMusicLibRealTimeWatch.Header" xml:space="preserve">
<value>实时监听文件变化</value>
</data>
<data name="SettingsPageNarrowMode.Text" xml:space="preserve">
<value>窄屏模式</value>
</data>
<data name="SettingsPageNextSongHotKey.Header" xml:space="preserve">
<value>下一首曲目快捷键</value>
</data>
<data name="SettingsPageNoBackdrop.Content" xml:space="preserve">
<value>无</value>
</data>
<data name="SettingsPageOpenLogFolderButton.Content" xml:space="preserve">
<data name="SettingsPageOpacity.Header" xml:space="preserve">
<value>不透明度</value>
</data>
<data name="SettingsPageOpenFolderButton.Content" xml:space="preserve">
<value>在文件资源管理器中打开</value>
</data>
<data name="SettingsPagePathBeIncludedInfo" xml:space="preserve">
@@ -985,9 +1045,15 @@
<data name="SettingsPagePreviousSongHotKey.Header" xml:space="preserve">
<value>上一首曲目快捷键</value>
</data>
<data name="SettingsPagePureLayer.Header" xml:space="preserve">
<value>纯色层</value>
</data>
<data name="SettingsPageQQGroup.Content" xml:space="preserve">
<value>QQ 反馈交流群</value>
</data>
<data name="SettingsPageRealtimeStatus.Text" xml:space="preserve">
<value>实时状态</value>
</data>
<data name="SettingsPageRecord.Content" xml:space="preserve">
<value>记录</value>
</data>
@@ -1042,6 +1108,9 @@
<data name="SettingsPageServerTestSuccessInfo" xml:space="preserve">
<value>服务器测试成功</value>
</data>
<data name="SettingsPageSettings.Header" xml:space="preserve">
<value>设置</value>
</data>
<data name="SettingsPageSettingsManager.Header" xml:space="preserve">
<value>设置管理器</value>
</data>
@@ -1051,9 +1120,21 @@
<data name="SettingsPageShortcutRegSuccessInfo" xml:space="preserve">
<value>该热键已成功注册</value>
</data>
<data name="SettingsPageShowArtists.Header" xml:space="preserve">
<value>显示艺术家</value>
</data>
<data name="SettingsPageShowHideHotKey.Header" xml:space="preserve">
<value>歌词窗口显示和隐藏快捷键</value>
</data>
<data name="SettingsPageShowInSwitchers.Description" xml:space="preserve">
<value>例如Alt + Tab任务栏</value>
</data>
<data name="SettingsPageShowInSwitchers.Header" xml:space="preserve">
<value>在系统环境中显示</value>
</data>
<data name="SettingsPageShowTitle.Header" xml:space="preserve">
<value>显示标题</value>
</data>
<data name="SettingsPageSliderPrefix.Text" xml:space="preserve">
<value>当前值: </value>
</data>
@@ -1072,6 +1153,15 @@
<data name="SettingsPageSongInfoRight.Content" xml:space="preserve">
<value>靠右</value>
</data>
<data name="SettingsPageSpectrumLayer.Header" xml:space="preserve">
<value>频谱层</value>
</data>
<data name="SettingsPageSpeed.Header" xml:space="preserve">
<value>运动速率</value>
</data>
<data name="SettingsPageStandardMode.Text" xml:space="preserve">
<value>标准模式</value>
</data>
<data name="SettingsPageSystemLanguage.Content" xml:space="preserve">
<value>默认</value>
</data>
@@ -1090,6 +1180,15 @@
<data name="SettingsPageTitle" xml:space="preserve">
<value>设置 - BetterLyrics</value>
</data>
<data name="SettingsPageTitleBarAreaNone.Content" xml:space="preserve">
<value>无</value>
</data>
<data name="SettingsPageTitleBarAreaTop.Content" xml:space="preserve">
<value>顶部</value>
</data>
<data name="SettingsPageTitleBarAreaWhole.Content" xml:space="preserve">
<value>整个窗口</value>
</data>
<data name="SettingsPageTitleBarType.Header" xml:space="preserve">
<value>标题栏大小</value>
</data>
@@ -1111,6 +1210,24 @@
<data name="SettingsPageVersion.Text" xml:space="preserve">
<value>版本号</value>
</data>
<data name="SettingsPageWidth.Header" xml:space="preserve">
<value>宽度</value>
</data>
<data name="SettingsPageWindowBounds.Header" xml:space="preserve">
<value>窗口边界</value>
</data>
<data name="SettingsPageWorkArea.Description" xml:space="preserve">
<value>作为一个独立的工作区域停靠在屏幕的上/下边缘</value>
</data>
<data name="SettingsPageWorkArea.Header" xml:space="preserve">
<value>工作区</value>
</data>
<data name="SettingsPageWorkAreaHeight.Header" xml:space="preserve">
<value>工作区高度</value>
</data>
<data name="StandardMode" xml:space="preserve">
<value>标准模式</value>
</data>
<data name="SystemTrayExit.Text" xml:space="preserve">
<value>退出程序</value>
</data>
@@ -1132,9 +1249,6 @@
<data name="SystemTraySettings.Text" xml:space="preserve">
<value>打开设置</value>
</data>
<data name="SystemTrayUnlock.Text" xml:space="preserve">
<value>解锁窗口</value>
</data>
<data name="TranslateServerNotSet" xml:space="preserve">
<value>未设置Translate服务器请先在设置中进行配置</value>
</data>

View File

@@ -123,27 +123,12 @@
<data name="AlbumArtSearchSMTCProvider" xml:space="preserve">
<value>音樂播放器</value>
</data>
<data name="AllLyricsSettingsControlDesktop.Content" xml:space="preserve">
<value>桌面模式</value>
</data>
<data name="AllLyricsSettingsControlDock.Content" xml:space="preserve">
<value>停靠模式</value>
</data>
<data name="AllLyricsSettingsControlPictureInPicture.Content" xml:space="preserve">
<value>畫中畫模式</value>
</data>
<data name="AllLyricsSettingsControlStandard.Content" xml:space="preserve">
<value>標準模式</value>
</data>
<data name="AppSettingsControlGeneral.Content" xml:space="preserve">
<data name="AppSettingsControlGeneral.Text" xml:space="preserve">
<value>一般</value>
</data>
<data name="BaseWindowEnterFullScreenHint" xml:space="preserve">
<value>按 Esc 退出全螢幕模式</value>
</data>
<data name="BaseWindowFullScreenFlyoutItem.Text" xml:space="preserve">
<value>全螢幕</value>
</data>
<data name="BaseWindowHostInfoBarCheckBox.Content" xml:space="preserve">
<value>不再顯示此訊息</value>
</data>
@@ -153,32 +138,38 @@
<data name="Cancel" xml:space="preserve">
<value>取消</value>
</data>
<data name="DemoWindowControlDefault.Text" xml:space="preserve">
<value>預設</value>
</data>
<data name="DependenciesSettingsExpander.Header" xml:space="preserve">
<value>依賴</value>
</data>
<data name="DesktopMode" xml:space="preserve">
<value>桌面模式(透明)</value>
</data>
<data name="DockedMode" xml:space="preserve">
<value>停靠模式</value>
</data>
<data name="ExportSettingsSuccess" xml:space="preserve">
<value>導出成功</value>
</data>
<data name="FailToStartLXMusicServer" xml:space="preserve">
<value>無法連接到 LX 音樂服務器,請轉到設置 - 高級選項以檢查是否正確輸入鏈接</value>
</data>
<data name="FullscreenMode" xml:space="preserve">
<value>全螢幕模式</value>
</data>
<data name="HostWindowClickThroughButton.Content" xml:space="preserve">
<value>鎖定</value>
</data>
<data name="HostWindowClickThroughFlyoutItem.Text" xml:space="preserve">
<value>鎖定</value>
</data>
<data name="HostWindowDesktopFlyoutItem.Text" xml:space="preserve">
<value>桌面模式</value>
</data>
<data name="HostWindowDockFlyoutItem.Text" xml:space="preserve">
<value>停靠模式</value>
</data>
<data name="HostWindowLockToolTip.Text" xml:space="preserve">
<value>鎖定</value>
</data>
<data name="HostWindowMoreButtonToolTip.Content" xml:space="preserve">
<value>更多</value>
<data name="HostWindowMusicGalleryButtonToolTip.Content" xml:space="preserve">
<value>音樂庫</value>
</data>
<data name="HostWindowSettingsFlyoutItem.Text" xml:space="preserve">
<value>設定</value>
@@ -223,7 +214,7 @@
<value>手動檢索歌詞</value>
</data>
<data name="LyricsPageLyricsSettingsButtonToolTip.Content" xml:space="preserve">
<value>歌詞樣式與效果快捷設</value>
<value>歌詞視窗管理快捷設</value>
</data>
<data name="LyricsPagePlaybackSourceButtonToolTip.Content" xml:space="preserve">
<value>播放源快捷設置</value>
@@ -303,11 +294,17 @@
<data name="LyricsWindowImmersiveButtonToolTip.Content" xml:space="preserve">
<value>沉浸模式</value>
</data>
<data name="MainPageAlbumArtOnly.Content" xml:space="preserve">
<value>僅顯示專輯封面</value>
<data name="LyricsWindowSettingsControlCurrentLyricsWindowConfig.Text" xml:space="preserve">
<value>目前歌詞視窗設定</value>
</data>
<data name="MainPageDesktopLyricsToggler.ToolTipService.ToolTip" xml:space="preserve">
<value>切換到桌面歌詞模式</value>
<data name="LyricsWindowSettingsControlLyricsWindowMode.Header" xml:space="preserve">
<value>歌詞視窗模式</value>
</data>
<data name="LyricsWindowSettingsControlSetDefault.Text" xml:space="preserve">
<value>設為預設</value>
</data>
<data name="MainPageAlbumArtOnly.Content" xml:space="preserve">
<value>僅限相簿藝術區域</value>
</data>
<data name="MainPageEnterImmersiveModeHint" xml:space="preserve">
<value>再次懸停以顯示切換按鈕</value>
@@ -442,15 +439,18 @@
<data name="MusicGalleryPageTitle" xml:space="preserve">
<value>音樂庫 - BetterLyrics</value>
</data>
<data name="NarrowMode" xml:space="preserve">
<value>窄螢幕模式</value>
</data>
<data name="PictureInPictureMode" xml:space="preserve">
<value>畫中畫模式</value>
</data>
<data name="SetingsPageDonation.Text" xml:space="preserve">
<value>捐贈</value>
</data>
<data name="SetingsPageFeedback.Text" xml:space="preserve">
<value>回饋</value>
</data>
<data name="SetingsPageRef.Text" xml:space="preserve">
<value>使用的庫</value>
</data>
<data name="SetingsPageThanks.Text" xml:space="preserve">
<value>如果您喜歡這個項目,請考慮通過捐贈來支持它。您的支持將有助於保持項目的生命並鼓勵進一步的發展。</value>
</data>
@@ -463,18 +463,33 @@
<data name="SettingsPageAcrylicThin.Content" xml:space="preserve">
<value>亞克力(薄層)</value>
</data>
<data name="SettingsPageAdaptEnvColor.Description" xml:space="preserve">
<value>同時,將歌詞背景中的純色圖層不透明度和專輯藝術圖層不透明度設置為 0 ,以獲得正確的效果</value>
</data>
<data name="SettingsPageAdaptEnvColor.Header" xml:space="preserve">
<value>適應環境色彩</value>
</data>
<data name="SettingsPageAddFolder.Header" xml:space="preserve">
<value>新增資料夾</value>
</data>
<data name="SettingsPageAddFolderButton.Content" xml:space="preserve">
<value>添加</value>
</data>
<data name="SettingsPageAdvanced.Text" xml:space="preserve">
<value>高級選項</value>
</data>
<data name="SettingsPageAlbumArt.Text" xml:space="preserve">
<value>專輯</value>
</data>
<data name="SettingsPageAlbumArtLayer.Header" xml:space="preserve">
<value>相簿藝術圖層</value>
</data>
<data name="SettingsPageAlbumArtSearchProvidersConfig.Text" xml:space="preserve">
<value>配置專輯封面源</value>
</data>
<data name="SettingsPageAlbumArtSize.Header" xml:space="preserve">
<value>專輯封面</value>
</data>
<data name="SettingsPageAlbumLib.Content" xml:space="preserve">
<value>專輯封面來源</value>
</data>
@@ -484,14 +499,14 @@
<data name="SettingsPageAlbumShadowAmount.Header" xml:space="preserve">
<value>陰影擴散程度</value>
</data>
<data name="SettingsPageAlbumStyle.Content" xml:space="preserve">
<data name="SettingsPageAlbumStyle.Text" xml:space="preserve">
<value>專輯區域樣式</value>
</data>
<data name="SettingsPageAmount.Header" xml:space="preserve">
<value>量</value>
</data>
<data name="SettingsPageAOT.Header" xml:space="preserve">
<value>將應用置於頂層</value>
<value>將歌詞視窗置於頂層</value>
</data>
<data name="SettingsPageApp.Content" xml:space="preserve">
<value>應用外觀與行為</value>
@@ -500,29 +515,17 @@
<value>應用外觀</value>
</data>
<data name="SettingsPageAppBehavior.Text" xml:space="preserve">
<value>應用行為</value>
<value>一般行爲</value>
</data>
<data name="SettingsPageApply.Content" xml:space="preserve">
<value>應用</value>
</data>
<data name="SettingsPageAutoLock.Header" xml:space="preserve">
<value>啟動桌面模式時隨即鎖定窗口</value>
<data name="SettingsPageAutoSize.Header" xml:space="preserve">
<value>自動調整大小</value>
</data>
<data name="SettingsPageAutoStart.Header" xml:space="preserve">
<value>自動啟動</value>
</data>
<data name="SettingsPageAutoStartDesktopLyrics.Content" xml:space="preserve">
<value>啟動桌面模式</value>
</data>
<data name="SettingsPageAutoStartDockLyrics.Content" xml:space="preserve">
<value>啟動停靠模式</value>
</data>
<data name="SettingsPageAutoStartInAppLyrics.Content" xml:space="preserve">
<value>啟動標準模式</value>
</data>
<data name="SettingsPageAutoStartPIPLyrics.Content" xml:space="preserve">
<value>啟動畫中畫模式</value>
</data>
<data name="SettingsPageAutoStartWindow.Header" xml:space="preserve">
<value>啟動應用程式時</value>
</data>
@@ -532,9 +535,18 @@
<data name="SettingsPageBackgroundAcrylicEffectAmount.Header" xml:space="preserve">
<value>專輯背景壓克力效果強度</value>
</data>
<data name="SettingsPageBackgroundOverlay.Content" xml:space="preserve">
<data name="SettingsPageBackgroundOverlay.Text" xml:space="preserve">
<value>歌詞背景</value>
</data>
<data name="SettingsPageBlurAmount.Header" xml:space="preserve">
<value>模糊度</value>
</data>
<data name="SettingsPageBorderless.Header" xml:space="preserve">
<value>無邊框窗口</value>
</data>
<data name="SettingsPageBorderlessHotKey.Header" xml:space="preserve">
<value>無邊框歌詞視窗捷徑</value>
</data>
<data name="SettingsPageCache.Description" xml:space="preserve">
<value>包括日誌文件,網絡歌詞緩存</value>
</data>
@@ -547,9 +559,27 @@
<data name="SettingsPageChinesePreference.Header" xml:space="preserve">
<value>中文轉換為繁體</value>
</data>
<data name="SettingsPageClickThrough.Header" xml:space="preserve">
<value>點擊穿透</value>
</data>
<data name="SettingsPageClickThroughHotKey.Header" xml:space="preserve">
<value>點選穿透快捷鍵</value>
</data>
<data name="SettingsPageCompactTitleBar.Content" xml:space="preserve">
<value>緊湊</value>
</data>
<data name="SettingsPageConfigName.Description" xml:space="preserve">
<value>命名錄製的視窗狀態可以幫助您更好地區分它們</value>
</data>
<data name="SettingsPageConfigName.Header" xml:space="preserve">
<value>配置名稱</value>
</data>
<data name="SettingsPageCreateFromCurrent.Content" xml:space="preserve">
<value>從目前的歌詞視窗狀態建立</value>
</data>
<data name="SettingsPageCreateFromTemplates.Content" xml:space="preserve">
<value>從範本建立</value>
</data>
<data name="SettingsPageCurrentLyricsWindowStatus.Text" xml:space="preserve">
<value>當前歌詞窗口狀態</value>
</data>
@@ -559,29 +589,29 @@
<data name="SettingsPageDebugOverlay.Header" xml:space="preserve">
<value>顯示調試覆蓋層</value>
</data>
<data name="SettingsPageDelete.Content" xml:space="preserve">
<data name="SettingsPageDelete.Text" xml:space="preserve">
<value>刪除</value>
</data>
<data name="SettingsPageDesktopAcrylic.Content" xml:space="preserve">
<value>亞克力(桌面)</value>
<data name="SettingsPageDesktopMode.Text" xml:space="preserve">
<value>桌面模式(透明</value>
</data>
<data name="SettingsPageDev.Content" xml:space="preserve">
<value>高級選項</value>
</data>
<data name="SettingsPageDisclaimer.Text" xml:space="preserve">
<data name="SettingsPageDisclaimer.Message" xml:space="preserve">
<value>本項目按原樣提供,不提供任何形式的保證。所有歌詞、字型、圖示和其他第三方資源均屬其各自的版權擁有者所有。此專案的作者並未聲明此類資源的所有權。此專案為非商業專案,不應用於侵犯任何權利。用戶有責任確保自己的使用符合適用的法律和許可證。</value>
</data>
<data name="SettingsPageDiscord.Content" xml:space="preserve">
<value>Discord</value>
</data>
<data name="SettingsPageDisplayTypeSwitcher.Header" xml:space="preserve">
<value>歌詞專輯佈局模式</value>
<value>局模式</value>
</data>
<data name="SettingsPageDockedMode.Text" xml:space="preserve">
<value>停靠模式</value>
</data>
<data name="SettingsPageDockMonitor.Header" xml:space="preserve">
<value>目標顯示器</value>
</data>
<data name="SettingsPageDockPlacement.Header" xml:space="preserve">
<value>停靠模式位置</value>
<value>工作區域位置</value>
</data>
<data name="SettingsPageDockPlacementBottom.Content" xml:space="preserve">
<value>底部</value>
@@ -592,6 +622,9 @@
<data name="SettingsPageDockWindowHeight.Header" xml:space="preserve">
<value>窗口高度</value>
</data>
<data name="SettingsPageDragArea.Header" xml:space="preserve">
<value>拖動</value>
</data>
<data name="SettingsPageDynamicLyricsFontSize.Header" xml:space="preserve">
<value>自動調整</value>
</data>
@@ -637,6 +670,21 @@
<data name="SettingsPageEN.Content" xml:space="preserve">
<value>English</value>
</data>
<data name="SettingsPageEnvColorSample.Header" xml:space="preserve">
<value>環境色彩採樣模式</value>
</data>
<data name="SettingsPageEnvColorSampleAbove.Content" xml:space="preserve">
<value>視窗上方</value>
</data>
<data name="SettingsPageEnvColorSampleBelow.Content" xml:space="preserve">
<value>視窗下方</value>
</data>
<data name="SettingsPageEnvColorSampleEdge.Content" xml:space="preserve">
<value>視窗邊緣</value>
</data>
<data name="SettingsPageEnvColorSampleInner.Content" xml:space="preserve">
<value>視窗內部</value>
</data>
<data name="SettingsPageExitOnLyricsWindowClosed.Header" xml:space="preserve">
<value>關閉歌詞視窗時退出程式</value>
</data>
@@ -655,30 +703,33 @@
<data name="SettingsPageFixedTimeStep.Header" xml:space="preserve">
<value>固定時間步長渲染</value>
</data>
<data name="SettingsPageFluidLayer.Header" xml:space="preserve">
<value>流體層</value>
</data>
<data name="SettingsPageFollowSystem.Content" xml:space="preserve">
<value>跟隨系統</value>
</data>
<data name="SettingsPageForceAlwaysOnTop.Description" xml:space="preserve">
<value>透過輪詢方式使歌詞視窗保持置於頂層狀態</value>
</data>
<data name="SettingsPageForceAlwaysOnTop.Header" xml:space="preserve">
<value>強制置於頂層</value>
</data>
<data name="SettingsPageFPS.Header" xml:space="preserve">
<value>渲染幀率</value>
</data>
<data name="SettingsPageGlobalDrag.Description" xml:space="preserve">
<value>將標題列擴展至整個頁面使得在任意非互動區域均可拖曳窗口</value>
<data name="SettingsPageFullscreenMode.Text" xml:space="preserve">
<value>全螢幕模式</value>
</data>
<data name="SettingsPageGlobalDrag.Header" xml:space="preserve">
<value>全域拖曳</value>
<data name="SettingsPageHeight.Header" xml:space="preserve">
<value>高度</value>
</data>
<data name="SettingsPageHideWindow.Description" xml:space="preserve">
<value>停靠模式或桌面模式下,無歌曲正在播放時自動隱藏窗口;反之自動顯示窗口</value>
<value>音樂未播放/播放時自動隱藏/顯示歌詞視窗</value>
</data>
<data name="SettingsPageHideWindow.Header" xml:space="preserve">
<value>自動隱藏/顯示窗口</value>
</data>
<data name="SettingsPageIgnoreFullscreenWindow.Description" xml:space="preserve">
<value>啟用停靠模式或桌面模式時強制將本應用程式顯示在全螢幕應用程式的上方</value>
</data>
<data name="SettingsPageIgnoreFullscreenWindow.Header" xml:space="preserve">
<value>始終顯示在全螢幕應用程式上方</value>
</data>
<data name="SettingsPageImportSettingsButton.Content" xml:space="preserve">
<value>導入設置</value>
</data>
@@ -730,14 +781,23 @@
<data name="SettingsPageLastFMUsername.Header" xml:space="preserve">
<value>使用者名稱</value>
</data>
<data name="SettingsPageLayoutOrientation.Header" xml:space="preserve">
<value>版面配置方向</value>
</data>
<data name="SettingsPageLayoutOrientationHorizontal.Content" xml:space="preserve">
<value>水平</value>
</data>
<data name="SettingsPageLayoutOrientationVertical.Content" xml:space="preserve">
<value>縱向</value>
</data>
<data name="SettingsPageLibreTranslateServer.Header" xml:space="preserve">
<value>服務器地址</value>
</data>
<data name="SettingsPageLight.Content" xml:space="preserve">
<value>淺色</value>
</data>
<data name="SettingsPageLockHotKey.Header" xml:space="preserve">
<value>解鎖和鎖定快捷鍵</value>
<data name="SettingsPageListenNewSession.Header" xml:space="preserve">
<value>啟用對新播放來源的監聽</value>
</data>
<data name="SettingsPageLog.Header" xml:space="preserve">
<value>日誌記錄</value>
@@ -745,7 +805,7 @@
<data name="SettingsPageLXMusicServer.Text" xml:space="preserve">
<value>LX 音樂服務器</value>
</data>
<data name="SettingsPageLyrics.Content" xml:space="preserve">
<data name="SettingsPageLyrics.Text" xml:space="preserve">
<value>歌詞樣式與動效</value>
</data>
<data name="SettingsPageLyricsAlignment.Header" xml:space="preserve">
@@ -754,15 +814,6 @@
<data name="SettingsPageLyricsBackground.Header" xml:space="preserve">
<value>歌詞背景</value>
</data>
<data name="SettingsPageLyricsBackgroundBlurAmount.Header" xml:space="preserve">
<value>專輯背景層模糊度</value>
</data>
<data name="SettingsPageLyricsBackgroundOpacity.Header" xml:space="preserve">
<value>專輯背景層不透明度</value>
</data>
<data name="SettingsPageLyricsBackgroundSpeed.Header" xml:space="preserve">
<value>專輯背景層運動速率</value>
</data>
<data name="SettingsPageLyricsBgFontColor.Header" xml:space="preserve">
<value>字體顏色(非當前播放區域)</value>
</data>
@@ -862,9 +913,6 @@
<data name="SettingsPageLyricsNormal.Content" xml:space="preserve">
<value>常規</value>
</data>
<data name="SettingsPageLyricsPureColorBgOpacity.Header" xml:space="preserve">
<value>純色背景層不透明度</value>
</data>
<data name="SettingsPageLyricsRendingScopeCurrentChar.Content" xml:space="preserve">
<value>目前字元</value>
</data>
@@ -916,9 +964,15 @@
<data name="SettingsPageLyricsVerticalEdgeOpacity.Header" xml:space="preserve">
<value>上下邊緣不透明度</value>
</data>
<data name="SettingsPageLyricsWindowManager.Header" xml:space="preserve">
<data name="SettingsPageLyricsWindowManager.Text" xml:space="preserve">
<value>歌詞視窗管理</value>
</data>
<data name="SettingsPageLyricsWindowMgr.Content" xml:space="preserve">
<value>歌詞視窗管理</value>
</data>
<data name="SettingsPageLyricsWindowSwitchHotKey.Header" xml:space="preserve">
<value>歌詞視窗狀態切換器捷徑</value>
</data>
<data name="SettingsPageMediaLib.Content" xml:space="preserve">
<value>媒體庫</value>
</data>
@@ -943,13 +997,19 @@
<data name="SettingsPageMusicLibRealTimeWatch.Header" xml:space="preserve">
<value>實時監聽文件變化</value>
</data>
<data name="SettingsPageNarrowMode.Text" xml:space="preserve">
<value>窄螢幕模式</value>
</data>
<data name="SettingsPageNextSongHotKey.Header" xml:space="preserve">
<value>下一首曲目快捷鍵</value>
</data>
<data name="SettingsPageNoBackdrop.Content" xml:space="preserve">
<value>無</value>
</data>
<data name="SettingsPageOpenLogFolderButton.Content" xml:space="preserve">
<data name="SettingsPageOpacity.Header" xml:space="preserve">
<value>專輯背景層不透明度</value>
</data>
<data name="SettingsPageOpenFolderButton.Content" xml:space="preserve">
<value>在檔案總管中開啟</value>
</data>
<data name="SettingsPagePathBeIncludedInfo" xml:space="preserve">
@@ -985,9 +1045,15 @@
<data name="SettingsPagePreviousSongHotKey.Header" xml:space="preserve">
<value>上一首曲目快捷鍵</value>
</data>
<data name="SettingsPagePureLayer.Header" xml:space="preserve">
<value>純淨的色彩層</value>
</data>
<data name="SettingsPageQQGroup.Content" xml:space="preserve">
<value>QQ 回饋交流群</value>
</data>
<data name="SettingsPageRealtimeStatus.Text" xml:space="preserve">
<value>即時狀態</value>
</data>
<data name="SettingsPageRecord.Content" xml:space="preserve">
<value>記錄</value>
</data>
@@ -1042,6 +1108,9 @@
<data name="SettingsPageServerTestSuccessInfo" xml:space="preserve">
<value>服務器測試成功</value>
</data>
<data name="SettingsPageSettings.Header" xml:space="preserve">
<value>設定</value>
</data>
<data name="SettingsPageSettingsManager.Header" xml:space="preserve">
<value>設置管理器</value>
</data>
@@ -1051,9 +1120,21 @@
<data name="SettingsPageShortcutRegSuccessInfo" xml:space="preserve">
<value>該熱鍵已成功註冊</value>
</data>
<data name="SettingsPageShowArtists.Header" xml:space="preserve">
<value>界面設計</value>
</data>
<data name="SettingsPageShowHideHotKey.Header" xml:space="preserve">
<value>歌詞窗口顯示和隱藏快捷鍵</value>
</data>
<data name="SettingsPageShowInSwitchers.Description" xml:space="preserve">
<value>例如Alt + Tab任務列</value>
</data>
<data name="SettingsPageShowInSwitchers.Header" xml:space="preserve">
<value>在系統環境中顯示</value>
</data>
<data name="SettingsPageShowTitle.Header" xml:space="preserve">
<value>顯示標題</value>
</data>
<data name="SettingsPageSliderPrefix.Text" xml:space="preserve">
<value>目前值: </value>
</data>
@@ -1072,6 +1153,15 @@
<data name="SettingsPageSongInfoRight.Content" xml:space="preserve">
<value>靠右</value>
</data>
<data name="SettingsPageSpectrumLayer.Header" xml:space="preserve">
<value>光譜層</value>
</data>
<data name="SettingsPageSpeed.Header" xml:space="preserve">
<value>動作速率</value>
</data>
<data name="SettingsPageStandardMode.Text" xml:space="preserve">
<value>標準模式</value>
</data>
<data name="SettingsPageSystemLanguage.Content" xml:space="preserve">
<value>預設</value>
</data>
@@ -1090,6 +1180,15 @@
<data name="SettingsPageTitle" xml:space="preserve">
<value>設定 - BetterLyrics</value>
</data>
<data name="SettingsPageTitleBarAreaNone.Content" xml:space="preserve">
<value>無</value>
</data>
<data name="SettingsPageTitleBarAreaTop.Content" xml:space="preserve">
<value>頂部</value>
</data>
<data name="SettingsPageTitleBarAreaWhole.Content" xml:space="preserve">
<value>整個視窗</value>
</data>
<data name="SettingsPageTitleBarType.Header" xml:space="preserve">
<value>標題列大小</value>
</data>
@@ -1111,6 +1210,24 @@
<data name="SettingsPageVersion.Text" xml:space="preserve">
<value>版本號</value>
</data>
<data name="SettingsPageWidth.Header" xml:space="preserve">
<value>寬度</value>
</data>
<data name="SettingsPageWindowBounds.Header" xml:space="preserve">
<value>窗戶邊界</value>
</data>
<data name="SettingsPageWorkArea.Description" xml:space="preserve">
<value>作為一個獨立的工作區域停靠在螢幕的上/下邊緣</value>
</data>
<data name="SettingsPageWorkArea.Header" xml:space="preserve">
<value>工作區區域</value>
</data>
<data name="SettingsPageWorkAreaHeight.Header" xml:space="preserve">
<value>工作區域高度</value>
</data>
<data name="StandardMode" xml:space="preserve">
<value>標準模式</value>
</data>
<data name="SystemTrayExit.Text" xml:space="preserve">
<value>退出程序</value>
</data>
@@ -1132,9 +1249,6 @@
<data name="SystemTraySettings.Text" xml:space="preserve">
<value>打開設置</value>
</data>
<data name="SystemTrayUnlock.Text" xml:space="preserve">
<value>解鎖窗口</value>
</data>
<data name="TranslateServerNotSet" xml:space="preserve">
<value>未設定翻譯伺服器,請先在設定中進行配置</value>
</data>

View File

@@ -1,25 +0,0 @@
using BetterLyrics.WinUI3.Models.Settings;
using BetterLyrics.WinUI3.Services.SettingsService;
using CommunityToolkit.Mvvm.ComponentModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BetterLyrics.WinUI3.ViewModels
{
public partial class AlbumArtLayoutSettingsControlViewModel : BaseViewModel
{
private readonly ISettingsService _settingsService;
[ObservableProperty]
public partial AppSettings AppSettings { get; set; }
public AlbumArtLayoutSettingsControlViewModel(ISettingsService settingsService)
{
_settingsService = settingsService;
AppSettings = _settingsService.AppSettings;
}
}
}

View File

@@ -1,46 +0,0 @@
using BetterLyrics.WinUI3.Enums;
using BetterLyrics.WinUI3.Models;
using BetterLyrics.WinUI3.Models.Settings;
using BetterLyrics.WinUI3.Services.LiveStatesService;
using BetterLyrics.WinUI3.Services.SettingsService;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Messaging;
using CommunityToolkit.Mvvm.Messaging.Messages;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BetterLyrics.WinUI3.ViewModels
{
public partial class AllLyricsSettingsControlViewModel : BaseViewModel,
IRecipient<PropertyChangedMessage<LyricsWindowMode>>
{
private readonly ISettingsService _settingsService;
[ObservableProperty]
public partial AppSettings AppSettings { get; set; }
[ObservableProperty]
public partial int SelectedTabIndex { get; set; } = 0;
public AllLyricsSettingsControlViewModel(ISettingsService settingsService)
{
_settingsService = settingsService;
AppSettings = _settingsService.AppSettings;
}
public void Receive(PropertyChangedMessage<LyricsWindowMode> message)
{
if (message.Sender is LiveStates)
{
if (message.PropertyName == nameof(LiveStates.LyricsWindowMode))
{
SelectedTabIndex = (int)message.NewValue;
}
}
}
}
}

View File

@@ -15,25 +15,14 @@ namespace BetterLyrics.WinUI3.ViewModels
public partial class AppSettingsControlViewModel : BaseViewModel
{
private readonly ISettingsService _settingsService;
private readonly ILiveStatesService _liveStatesService;
[ObservableProperty]
public partial AppSettings AppSettings { get; set; }
[ObservableProperty]
public partial LiveStates LiveStates { get; set; }
[ObservableProperty]
public partial ObservableCollection<string> MonitorDeviceNames { get; set; }
public AppSettingsControlViewModel(ISettingsService settingsService, ILiveStatesService liveStatesService)
public AppSettingsControlViewModel(ISettingsService settingsService)
{
_settingsService = settingsService;
_liveStatesService = liveStatesService;
MonitorDeviceNames = [.. MonitorHelper.GetAllMonitorDeviceNames()];
AppSettings = _settingsService.AppSettings;
LiveStates = _liveStatesService.LiveStates;
}
[RelayCommand]
@@ -42,26 +31,6 @@ namespace BetterLyrics.WinUI3.ViewModels
WindowHelper.RestartApp();
}
[RelayCommand]
private void RefreshMonitorDeviceNames()
{
MonitorDeviceNames = [.. MonitorHelper.GetAllMonitorDeviceNames()];
AppSettings.DockModeSettings.DockMonitorDeviceName = MonitorHelper.GetPrimaryMonitorDeviceName();
}
[RelayCommand]
private void RecordCurrentWindowBounds()
{
AppSettings.WindowBoundsRecords.Add(new WindowBoundsRecord
{
WindowBounds = LiveStates.LyricsWindowBounds,
MonitorDeviceName = LiveStates.LyricsWindowMonitorName,
MonitorBounds = LiveStates.LyricsWindowMonitorBounds,
DemoWindowBounds = LiveStates.DemoLyricsWindowBounds,
DemoMonitorBounds = LiveStates.DemoLyricsWindowMonitorBounds
});
}
public async Task<bool> ToggleAutoStartupAsync(bool target)
{
StartupTask startupTask = await StartupTask.GetAsync(Constants.App.AutoStartupTaskId);

View File

@@ -1,25 +0,0 @@
using BetterLyrics.WinUI3.Models.Settings;
using BetterLyrics.WinUI3.Services.SettingsService;
using CommunityToolkit.Mvvm.ComponentModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BetterLyrics.WinUI3.ViewModels
{
public partial class LyricsBackgroundSettingsControlViewModel : BaseViewModel
{
private readonly ISettingsService _settingsService;
[ObservableProperty]
public partial AppSettings AppSettings { get; set; }
public LyricsBackgroundSettingsControlViewModel(ISettingsService settingsService)
{
_settingsService = settingsService;
AppSettings = _settingsService.AppSettings;
}
}
}

View File

@@ -23,7 +23,6 @@ using System.Threading.Tasks;
namespace BetterLyrics.WinUI3.ViewModels
{
public partial class LyricsPageViewModel : BaseViewModel,
IRecipient<PropertyChangedMessage<bool>>,
IRecipient<PropertyChangedMessage<TimeSpan>>
{
private readonly IMediaSessionsService _mediaSessionsService;
@@ -39,10 +38,6 @@ namespace BetterLyrics.WinUI3.ViewModels
LiveStates = _liveStatesService.LiveStates;
IsImmersiveMode = _settingsService.AppSettings.GeneralSettings.IsImmersiveMode;
OnIsImmersiveModeChanged(IsImmersiveMode);
//Volume = SystemVolumeHelper.GetMasterVolume();
//SystemVolumeHelper.VolumeChanged += SystemVolumeHelper_VolumeChanged;
@@ -87,9 +82,6 @@ namespace BetterLyrics.WinUI3.ViewModels
[ObservableProperty]
public partial int Volume { get; set; }
[ObservableProperty]
public partial bool IsImmersiveMode { get; set; }
[ObservableProperty]
public partial double BottomCommandGridOpacity { get; set; }
@@ -111,21 +103,11 @@ namespace BetterLyrics.WinUI3.ViewModels
[ObservableProperty]
public partial double TimelineSliderThumbSeconds { get; set; } = 0;
public void Receive(PropertyChangedMessage<bool> message)
{
if (message.Sender is LyricsWindowViewModel)
{
if (message.PropertyName == nameof(LyricsWindowViewModel.IsImmersiveMode))
{
IsImmersiveMode = message.NewValue;
}
}
}
[RelayCommand]
private static void OpenSettingsWindow()
{
WindowHelper.OpenWindow<SettingsWindow>();
WindowHelper.OpenOrShowWindow<SettingsWindow>();
}
[RelayCommand]
@@ -152,20 +134,6 @@ namespace BetterLyrics.WinUI3.ViewModels
await _mediaSessionsService.NextAsync();
}
partial void OnIsImmersiveModeChanged(bool value)
{
if (value)
{
BottomCommandGridOpacity = 0f;
BottomCommandFlyoutTriggerOpacity = 0f;
}
else
{
BottomCommandGridOpacity = 1f;
BottomCommandFlyoutTriggerOpacity = 1f;
}
}
partial void OnTimelineSliderThumbSecondsChanged(double value)
{
TimelineSliderThumbLyricsLine = _mediaSessionsService.CurrentLyricsData?.GetLyricsLine(value);

View File

@@ -0,0 +1,37 @@
using BetterLyrics.WinUI3.Helper;
using CommunityToolkit.WinUI;
using Microsoft.Graphics.Canvas;
using Microsoft.Graphics.Canvas.Effects;
using Microsoft.UI;
using Microsoft.UI.Xaml.Controls;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Text;
using System.Threading.Tasks;
using Windows.Storage;
using Windows.Storage.Streams;
namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
{
public partial class LyricsRendererViewModel
{
private PixelShaderEffect? _effect;
public async Task CreateResourcesAsync(Microsoft.Graphics.Canvas.UI.Xaml.CanvasAnimatedControl control)
{
StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/effect.bin"));
IBuffer buffer = await FileIO.ReadBufferAsync(file);
var bytes = buffer.ToArray();
_effect = new PixelShaderEffect(bytes);
_effect.Properties["Width"] = Convert.ToSingle(control.ConvertDipsToPixels((float)control.Size.Width, CanvasDpiRounding.Round));
_effect.Properties["Height"] = Convert.ToSingle(control.ConvertDipsToPixels((float)control.Size.Height, CanvasDpiRounding.Round));
_effect.Properties["color1"] = Colors.Black.ToVector3RGB();
_effect.Properties["color2"] = Colors.Black.ToVector3RGB();
_effect.Properties["color3"] = Colors.Black.ToVector3RGB();
_effect.Properties["color4"] = Colors.Black.ToVector3RGB();
_effect.Properties["EnableLightWave"] = false;
}
}
}

View File

@@ -1,5 +1,7 @@
using BetterLyrics.WinUI3.Enums;
using BetterLyrics.WinUI3.Helper;
using CommunityToolkit.WinUI;
using Hqub.Lastfm;
using Microsoft.Graphics.Canvas;
using Microsoft.Graphics.Canvas.Brushes;
using Microsoft.Graphics.Canvas.Effects;
@@ -33,24 +35,22 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
using var combined = new CanvasCommandList(control);
using var combinedDs = combined.CreateDrawingSession();
switch (_liveStatesService.LiveStates.LyricsWindowMode)
if (_liveStatesService.LiveStates.LyricsWindowStatus.LyricsBackgroundSettings.IsPureColorOverlayEnabled)
{
case LyricsWindowMode.DockMode:
if (_liveStatesService.LiveStates.LyricsWindowStatus.IsAdaptToEnvironment)
{
FillBackground(control, combinedDs, _immersiveBgColorTransition.Value, 0f,
_immersiveBgOpacityTransition.Value * _settingsService.AppSettings.LyricsBackgroundSettings.PureColorOverlayOpacity / 100f);
break;
case LyricsWindowMode.DesktopMode:
FillBackground(control, combinedDs, _immersiveBgColorTransition.Value, 0f,
_immersiveBgOpacityTransition.Value * _settingsService.AppSettings.LyricsBackgroundSettings.PureColorOverlayOpacity / 100f);
break;
case LyricsWindowMode.StandardMode:
case LyricsWindowMode.PictureInPictureMode:
FillBackground(control, combinedDs, _albumArtAccentColorTransition.Value, 0f, _settingsService.AppSettings.LyricsBackgroundSettings.PureColorOverlayOpacity / 100.0);
DrawAlbumArtBackground(control, combinedDs);
break;
default:
break;
_immersiveBgOpacityTransition.Value * _liveStatesService.LiveStates.LyricsWindowStatus.LyricsBackgroundSettings.PureColorOverlayOpacity / 100f);
}
else
{
FillBackground(control, combinedDs, _albumArtAccentColor1Transition.Value, 0f,
_liveStatesService.LiveStates.LyricsWindowStatus.LyricsBackgroundSettings.PureColorOverlayOpacity / 100.0);
}
}
DrawAlbumArtBackground(control, combinedDs);
DrawFluidBackground(control, combinedDs);
DrawSpectrum(control, combinedDs);
combinedDs.DrawImage(blurredLyrics);
@@ -102,6 +102,88 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
}
}
public void DrawSpectrum(ICanvasAnimatedControl control, CanvasDrawingSession ds)
{
if (_spectrumAnalyzer != null && _liveStatesService.LiveStates.LyricsWindowStatus.LyricsBackgroundSettings.IsSpectrumOverlayEnabled)
{
var points = new Vector2[_spectrumAnalyzer.BarCount];
float pointSpacing = 0;
if (_spectrumAnalyzer.BarCount > 1)
{
pointSpacing = (float)_canvasWidth / (_spectrumAnalyzer.BarCount - 1);
}
for (int i = 0; i < _spectrumAnalyzer.BarCount; i++)
{
float x = i * pointSpacing;
float amplitude = _spectrumAnalyzer.SmoothSpectrum.Average() * 10 + _spectrumAnalyzer.SmoothSpectrum[i] * 0.5f;
float y = (float)_canvasHeight - amplitude;
points[i] = new Vector2(x, y);
}
// 用于填充的闭合路径
using var pathBuilder = new CanvasPathBuilder(ds);
pathBuilder.BeginFigure(points[0]);
if (_spectrumAnalyzer.BarCount > 2)
{
for (int i = 0; i < _spectrumAnalyzer.BarCount - 1; i++)
{
Vector2 p0 = points[Math.Max(i - 1, 0)];
Vector2 p1 = points[i];
Vector2 p2 = points[i + 1];
Vector2 p3 = points[Math.Min(i + 2, _spectrumAnalyzer.BarCount - 1)];
Vector2 cp1 = p1 + (p2 - p0) / 6.0f;
Vector2 cp2 = p2 - (p3 - p1) / 6.0f;
pathBuilder.AddCubicBezier(cp1, cp2, p2);
}
}
else
{
pathBuilder.AddLine(points[1]);
}
pathBuilder.AddLine(new Vector2(points[_spectrumAnalyzer.BarCount - 1].X, (float)_canvasHeight));
pathBuilder.AddLine(new Vector2(points[0].X, (float)_canvasHeight));
pathBuilder.EndFigure(CanvasFigureLoop.Closed);
using var geometry = CanvasGeometry.CreatePath(pathBuilder);
var gradientStops = new CanvasGradientStop[]
{
new() { Position = 0.0f, Color = _albumArtAccentColor1Transition.Value },
new() { Position = 1.0f, Color = Colors.Transparent }
};
using var gradientBrush = new CanvasLinearGradientBrush(ds, gradientStops);
gradientBrush.StartPoint = new Vector2((float)_canvasWidth / 2, (float)_canvasHeight);
gradientBrush.EndPoint = new Vector2((float)_canvasWidth / 2, points.Select(p => p.Y).Min());
// 使用渐变画刷填充
ds.FillGeometry(geometry, gradientBrush);
// 绘制轮廓线
// var lineColor = Colors.SkyBlue;
// float strokeWidth = 2f;
// session.DrawGeometry(geometry, lineColor, strokeWidth);
}
}
private void DrawFluidBackground(ICanvasAnimatedControl control, CanvasDrawingSession ds)
{
if (_effect != null && _liveStatesService.LiveStates.LyricsWindowStatus.LyricsBackgroundSettings.IsFluidOverlayEnabled)
{
ds.DrawImage(new OpacityEffect
{
Source = _effect,
Opacity = _liveStatesService.LiveStates.LyricsWindowStatus.LyricsBackgroundSettings.FluidOverlayOpacity / 100f
});
}
}
private void DrawBackgroundImgae(OpacityEffect effect, CanvasDrawingSession ds, CanvasBitmap canvasBitmap)
{
double imageWidth = (double)canvasBitmap.Size.Width;
@@ -118,22 +200,25 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
private void DrawAlbumArtBackground(ICanvasAnimatedControl control, CanvasDrawingSession ds)
{
ds.Transform = Matrix3x2.CreateRotation((float)_rotateAngle, control.Size.ToVector2() * 0.5f);
if (_albumArtBgEffect != null)
if (_liveStatesService.LiveStates.LyricsWindowStatus.LyricsBackgroundSettings.IsCoverOverlayEnabled)
{
ds.DrawImage(_albumArtBgEffect);
}
else if (_albumArtBgRenderTarget != null)
{
double targetSize = Math.Sqrt(Math.Pow(_canvasWidth, 2) + Math.Pow(_canvasHeight, 2));
float offsetX = (float)(_canvasWidth - targetSize) / 2;
float offsetY = (float)(_canvasHeight - targetSize) / 2;
ds.Transform = Matrix3x2.CreateRotation((float)_rotateAngle, control.Size.ToVector2() * 0.5f);
ds.DrawImage(_albumArtBgRenderTarget, new Vector2(offsetX, offsetY));
}
if (_albumArtBgEffect != null)
{
ds.DrawImage(_albumArtBgEffect);
}
else if (_albumArtBgRenderTarget != null)
{
double targetSize = Math.Sqrt(Math.Pow(_canvasWidth, 2) + Math.Pow(_canvasHeight, 2));
float offsetX = (float)(_canvasWidth - targetSize) / 2;
float offsetY = (float)(_canvasHeight - targetSize) / 2;
ds.Transform = Matrix3x2.Identity;
ds.DrawImage(_albumArtBgRenderTarget, new Vector2(offsetX, offsetY));
}
ds.Transform = Matrix3x2.Identity;
}
}
private void DrawAlbumArt(ICanvasAnimatedControl control, CanvasDrawingSession ds)
@@ -172,7 +257,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
private void DrawSingleTitleAndArtist(ICanvasAnimatedControl control, CanvasDrawingSession ds, string? title, string? artist, double opacity)
{
var maxWidth = _lyricsLayoutOrientation switch
var maxWidth = _liveStatesService.LiveStates.LyricsWindowStatus.LyricsLayoutOrientation switch
{
LyricsLayoutOrientation.Horizontal => _albumArtSize,
LyricsLayoutOrientation.Vertical => _canvasWidth - _leftMargin - _albumArtSize - _rightMargin,
@@ -191,14 +276,22 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
control, artist ?? string.Empty,
_artistTextFormat, (float)maxWidth, (float)_canvasHeight
);
ds.DrawTextLayout(
titleLayout,
new Vector2((float)_titleXTransition.Value, (float)_titleYTransition.Value),
_bgFontColor.WithAlpha((byte)(_albumArtOpacityTransition.Value * 255 * opacity)));
ds.DrawTextLayout(
artistLayout,
new Vector2((float)_titleXTransition.Value, (float)(_titleYTransition.Value + titleLayout.LayoutBounds.Height)),
_bgFontColor.WithAlpha((byte)(_albumArtOpacityTransition.Value * 128 * opacity)));
if (_liveStatesService.LiveStates.LyricsWindowStatus.AlbumArtLayoutSettings.ShowTitle)
{
ds.DrawTextLayout(
titleLayout,
new Vector2((float)_titleXTransition.Value, (float)_titleYTransition.Value),
_bgFontColor.WithAlpha((byte)(_albumArtOpacityTransition.Value * 255 * opacity)));
if (_liveStatesService.LiveStates.LyricsWindowStatus.AlbumArtLayoutSettings.ShowArtists)
{
ds.DrawTextLayout(
artistLayout,
new Vector2((float)_titleXTransition.Value, (float)(_titleYTransition.Value + titleLayout.LayoutBounds.Height)),
_bgFontColor.WithAlpha((byte)(_albumArtOpacityTransition.Value * 128 * opacity)));
}
}
}
private void DrawBlurredLyrics(ICanvasAnimatedControl control, CanvasDrawingSession ds)
@@ -236,7 +329,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
// 先铺一层带默认透明度的已经加了模糊效果的歌词作为最底层(背景歌词层次)
using var backgroundFontEffect = CanvasHelper.CreateFontEffect(line, control, _strokeFontColor,
_liveStatesService.LiveStates.LyricsStyleSettings.LyricsFontStrokeWidth, _bgFontColor);
_liveStatesService.LiveStates.LyricsWindowStatus.LyricsStyleSettings.LyricsFontStrokeWidth, _bgFontColor);
using var backgroundEffect = CanvasHelper.CreateBackgroundEffect(line, backgroundFontEffect, _lyricsOpacityTransition.Value);
combinedDs.DrawImage(backgroundEffect);
@@ -247,43 +340,43 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
using var charMask = CanvasHelper.CreateCharMask(control, line, charStartIndex, charLength, charProgress);
using var lineStartToCharMask = CanvasHelper.CreateLineStartToCharMask(control, line, charStartIndex, charLength, charProgress,
_liveStatesService.LiveStates.LyricsEffectSettings.IsLyricsLineFadeEnabled);
_liveStatesService.LiveStates.LyricsWindowStatus.LyricsEffectSettings.IsLyricsLineFadeEnabled);
using var lineMask = CanvasHelper.CreateLineMask(control, line);
using var foregroundFontEffect = CanvasHelper.CreateFontEffect(line, control, _strokeFontColor,
_liveStatesService.LiveStates.LyricsStyleSettings.LyricsFontStrokeWidth, _fgFontColor);
_liveStatesService.LiveStates.LyricsWindowStatus.LyricsStyleSettings.LyricsFontStrokeWidth, _fgFontColor);
using var effectLayer = new CanvasCommandList(control);
using var effectLayerDs = effectLayer.CreateDrawingSession();
if (line.OriginalText != line.DisplayedText && _liveStatesService.LiveStates.LyricsEffectSettings.LyricsTranslationHighlightAmount != 0)
if (line.OriginalText != line.DisplayedText && _liveStatesService.LiveStates.LyricsWindowStatus.LyricsEffectSettings.LyricsTranslationHighlightAmount != 0)
{
using var translationHighlightMask = CanvasHelper.CreateTranslationHighlightMask(control, line);
using var foregroundTranslationHighlightEffect = CanvasHelper.CreateForegroundHighlightEffect(foregroundFontEffect, translationHighlightMask,
_liveStatesService.LiveStates.LyricsEffectSettings.LyricsTranslationHighlightAmount / 100.0);
_liveStatesService.LiveStates.LyricsWindowStatus.LyricsEffectSettings.LyricsTranslationHighlightAmount / 100.0);
effectLayerDs.DrawImage(foregroundTranslationHighlightEffect);
}
if (_liveStatesService.LiveStates.LyricsEffectSettings.IsLyricsShadowEnabled)
if (_liveStatesService.LiveStates.LyricsWindowStatus.LyricsEffectSettings.IsLyricsShadowEnabled)
{
var shadowEffectMask = CanvasHelper.GetAlphaMask(control, charMask, lineStartToCharMask, lineMask,
_liveStatesService.LiveStates.LyricsEffectSettings.LyricsShadowScope);
_liveStatesService.LiveStates.LyricsWindowStatus.LyricsEffectSettings.LyricsShadowScope);
using var foregroundShadowEffect = CanvasHelper.CreateForegroundShadowEffect(foregroundFontEffect, shadowEffectMask,
_albumArtAccentColorTransition.Value, _liveStatesService.LiveStates.LyricsEffectSettings.LyricsShadowAmount);
_albumArtAccentColor1Transition.Value, _liveStatesService.LiveStates.LyricsWindowStatus.LyricsEffectSettings.LyricsShadowAmount);
effectLayerDs.DrawImage(foregroundShadowEffect);
}
if (_liveStatesService.LiveStates.LyricsEffectSettings.IsLyricsGlowEffectEnabled)
if (_liveStatesService.LiveStates.LyricsWindowStatus.LyricsEffectSettings.IsLyricsGlowEffectEnabled)
{
var blurEffectMask = CanvasHelper.GetAlphaMask(control, charMask, lineStartToCharMask, lineMask,
_liveStatesService.LiveStates.LyricsEffectSettings.LyricsGlowEffectScope);
_liveStatesService.LiveStates.LyricsWindowStatus.LyricsEffectSettings.LyricsGlowEffectScope);
using var foregroundBlurEffect = CanvasHelper.CreateForegroundBlurEffect(foregroundFontEffect, blurEffectMask,
_liveStatesService.LiveStates.LyricsEffectSettings.LyricsGlowEffectAmount);
_liveStatesService.LiveStates.LyricsWindowStatus.LyricsEffectSettings.LyricsGlowEffectAmount);
effectLayerDs.DrawImage(foregroundBlurEffect);
}
if (_liveStatesService.LiveStates.LyricsEffectSettings.LyricsHighlightAmount != 0)
if (_liveStatesService.LiveStates.LyricsWindowStatus.LyricsEffectSettings.LyricsHighlightAmount != 0)
{
var highlightEffectMask = CanvasHelper.GetAlphaMask(control, charMask, lineStartToCharMask, lineMask,
_liveStatesService.LiveStates.LyricsEffectSettings.LyricsHighlightScope);
_liveStatesService.LiveStates.LyricsWindowStatus.LyricsEffectSettings.LyricsHighlightScope);
using var foregroundHighlightEffect = CanvasHelper.CreateForegroundHighlightEffect(foregroundFontEffect, highlightEffectMask,
_liveStatesService.LiveStates.LyricsEffectSettings.LyricsHighlightAmount / 100.0);
_liveStatesService.LiveStates.LyricsWindowStatus.LyricsEffectSettings.LyricsHighlightAmount / 100.0);
effectLayerDs.DrawImage(foregroundHighlightEffect);
}
@@ -295,7 +388,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
if (i == _playingLineIndex)
{
if (_liveStatesService.LiveStates.LyricsEffectSettings.IsLyricsFloatAnimationEnabled)
if (_liveStatesService.LiveStates.LyricsWindowStatus.LyricsEffectSettings.IsLyricsFloatAnimationEnabled)
{
ds.DrawImage(new DisplacementMapEffect
{
@@ -303,7 +396,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
Displacement = lineStartToCharMask,
XChannelSelect = EffectChannelSelect.Red,
YChannelSelect = EffectChannelSelect.Alpha,
Amount = _liveStatesService.LiveStates.LyricsEffectSettings.LyricsFloatAmount,
Amount = _liveStatesService.LiveStates.LyricsWindowStatus.LyricsEffectSettings.LyricsFloatAmount,
});
}
else

View File

@@ -56,7 +56,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
double scaleFactor = _albumArtSize / Math.Min(imageWidth, imageHeight);
if (scaleFactor < 0.01f) return null;
double cornerRadius = _settingsService.AppSettings.AlbumArtLayoutSettings.CoverImageRadius / 100f * _albumArtSize / 2;
double cornerRadius = _liveStatesService.LiveStates.LyricsWindowStatus.AlbumArtLayoutSettings.CoverImageRadius / 100f * _albumArtSize / 2;
var cornerRadiusMask = new CanvasCommandList(control);
using var cornerRadiusMaskDs = cornerRadiusMask.CreateDrawingSession();
@@ -96,7 +96,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
/// <para><seealso cref="_isCoverAcrylicEffectAmountChanged"/> == true</para>
/// <para><seealso cref="_isAlbumArtBgOpacityChanged"/> == true</para>
/// <para><seealso cref="_albumArtBgTransition"/> 正在变化</para>
/// <para><seealso cref="_albumArtAccentColorTransition"/> 正在变化</para>
/// <para><seealso cref="_albumArtAccentColor1Transition"/> 正在变化</para>
/// 如果上述条件均不满足,需调用 <seealso cref="UpdateAlbumArtBgRenderTarget"/> 来更新渲染缓存
/// </summary>
/// <param name="control"></param>
@@ -120,7 +120,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
using var blurredCover = new GaussianBlurEffect
{
BlurAmount = _settingsService.AppSettings.LyricsBackgroundSettings.CoverOverlayBlurAmount,
BlurAmount = _liveStatesService.LiveStates.LyricsWindowStatus.LyricsBackgroundSettings.CoverOverlayBlurAmount,
Source = overlappedCovers,
BorderMode = EffectBorderMode.Soft,
Optimization = EffectOptimization.Speed,
@@ -129,7 +129,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
var combined = new CanvasCommandList(control);
using var combinedDs = combined.CreateDrawingSession();
if (_settingsService.AppSettings.LyricsBackgroundSettings.CoverAcrylicEffectAmount > 0 && _coverAcrylicNoiseCanvasBitmap != null)
if (_liveStatesService.LiveStates.LyricsWindowStatus.LyricsBackgroundSettings.CoverAcrylicEffectAmount > 0 && _coverAcrylicNoiseCanvasBitmap != null)
{
// 应用亚克力噪点效果
combinedDs.DrawImage(new BlendEffect
@@ -139,7 +139,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
Foreground = new OpacityEffect
{
Source = _coverAcrylicNoiseCanvasBitmap,
Opacity = _settingsService.AppSettings.LyricsBackgroundSettings.CoverAcrylicEffectAmount / 100f,
Opacity = _liveStatesService.LiveStates.LyricsWindowStatus.LyricsBackgroundSettings.CoverAcrylicEffectAmount / 100f,
},
});
}
@@ -150,7 +150,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
_albumArtBgEffect = new OpacityEffect
{
Opacity = _settingsService.AppSettings.LyricsBackgroundSettings.CoverOverlayOpacity / 100f,
Opacity = _liveStatesService.LiveStates.LyricsWindowStatus.LyricsBackgroundSettings.CoverOverlayOpacity / 100f,
Source = combined,
};
}
@@ -190,7 +190,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
/// <para><seealso cref="_albumArtChanged"/> == true</para>
/// <para><seealso cref="_isAlbumArtShadowAmountChanged"/> == true</para>
/// <para><seealso cref="_albumArtBgTransition"/> 正在变化</para>
/// <para><seealso cref="_albumArtAccentColorTransition"/> 正在变化</para>
/// <para><seealso cref="_albumArtAccentColor1Transition"/> 正在变化</para>
/// 如果上述条件均不满足,需调用 <seealso cref="UpdateAlbumArtRenderTarget"/> 来更新渲染缓存
/// </summary>
/// <param name="control"></param>
@@ -223,8 +223,8 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
combinedDs.DrawImage(new ShadowEffect
{
Source = overlappedCovers,
ShadowColor = _albumArtAccentColorTransition.Value,
BlurAmount = _settingsService.AppSettings.AlbumArtLayoutSettings.CoverImageShadowAmount,
ShadowColor = _albumArtAccentColor1Transition.Value,
BlurAmount = _liveStatesService.LiveStates.LyricsWindowStatus.AlbumArtLayoutSettings.CoverImageShadowAmount,
Optimization = EffectOptimization.Speed,
});
combinedDs.DrawImage(overlappedCovers);

View File

@@ -8,6 +8,7 @@ using Microsoft.Extensions.Logging;
using Microsoft.UI.Xaml;
using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Windows.UI;
@@ -20,14 +21,17 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
IRecipient<PropertyChangedMessage<double>>,
IRecipient<PropertyChangedMessage<bool>>,
IRecipient<PropertyChangedMessage<Color>>,
IRecipient<PropertyChangedMessage<LyricsWindowMode>>,
IRecipient<PropertyChangedMessage<LyricsDisplayType>>,
IRecipient<PropertyChangedMessage<LyricsLayoutOrientation>>,
IRecipient<PropertyChangedMessage<LyricsFontColorType>>,
IRecipient<PropertyChangedMessage<TextAlignmentType>>,
IRecipient<PropertyChangedMessage<LyricsFontWeight>>,
IRecipient<PropertyChangedMessage<LineRenderingType>>,
IRecipient<PropertyChangedMessage<ElementTheme>>,
IRecipient<PropertyChangedMessage<EasingType>>
IRecipient<PropertyChangedMessage<EasingType>>,
IRecipient<PropertyChangedMessage<AlbumArtLayoutSettings>>,
IRecipient<PropertyChangedMessage<LyricsBackgroundSettings>>,
IRecipient<PropertyChangedMessage<LyricsWindowStatus>>
{
public void Receive(PropertyChangedMessage<bool> message)
@@ -53,19 +57,6 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
{
}
}
else if (message.Sender is LyricsWindowViewModel)
{
if (message.PropertyName == nameof(LyricsWindowViewModel.IsLyricsWindowLocked))
{
_isLyricsWindowLocked = message.NewValue;
UpdateImmersiveBackgroundOpacity();
}
else if (message.PropertyName == nameof(LyricsWindowViewModel.IsMouseWithinWindow))
{
_isMouseWithinWindow = message.NewValue;
UpdateImmersiveBackgroundOpacity();
}
}
else if (message.Sender is MediaSourceProviderInfo)
{
if (message.PropertyName == nameof(MediaSourceProviderInfo.IsLastFMTrackEnabled))
@@ -80,13 +71,35 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
_isLayoutChanged = true;
}
}
else if (message.Sender is AlbumArtLayoutSettings)
{
if (message.PropertyName == nameof(AlbumArtLayoutSettings.ShowTitle))
{
_isSongTitleVisibilityChanged = true;
}
else if (message.PropertyName == nameof(AlbumArtLayoutSettings.ShowArtists))
{
_isSongArtistsVisibilityChanged = true;
}
else if (message.PropertyName == nameof(AlbumArtLayoutSettings.AutoAlbumArtSize))
{
_isAlbumArtSizeChanged = true;
}
}
else if (message.Sender is LyricsBackgroundSettings)
{
if (message.PropertyName == nameof(LyricsBackgroundSettings.IsSpectrumOverlayEnabled))
{
_isSpectrumOverlayEnabledChanged = true;
}
}
}
public void Receive(PropertyChangedMessage<Color> message)
{
if (message.Sender is LyricsWindowViewModel)
{
if (message.PropertyName == nameof(LyricsWindowViewModel.ActivatedWindowAccentColor))
if (message.PropertyName == nameof(LyricsWindowViewModel.BackdropAccentColor))
{
_immersiveBgColorTransition.StartTransition(message.NewValue);
_environmentalColor = message.NewValue;
@@ -137,6 +150,10 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
{
UpdateSongInfoFontSize();
}
else if (message.PropertyName == nameof(AlbumArtLayoutSettings.AlbumArtSize))
{
_isAlbumArtSizeChanged = true;
}
}
else if (message.Sender is LyricsBackgroundSettings)
{
@@ -244,22 +261,33 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
if (message.PropertyName == nameof(AlbumArtLayoutSettings.SongInfoAlignmentType))
{
_titleTextFormat.HorizontalAlignment = _artistTextFormat.HorizontalAlignment =
_settingsService.AppSettings.AlbumArtLayoutSettings.SongInfoAlignmentType.ToCanvasHorizontalAlignment();
_liveStatesService.LiveStates.LyricsWindowStatus.AlbumArtLayoutSettings.SongInfoAlignmentType.ToCanvasHorizontalAlignment();
}
}
}
public void Receive(PropertyChangedMessage<LyricsDisplayType> message)
{
if (message.Sender is LiveStates)
if (message.Sender is LyricsWindowStatus)
{
if (message.PropertyName == nameof(LiveStates.LyricsDisplayType))
if (message.PropertyName == nameof(LyricsWindowStatus.LyricsDisplayType))
{
_isDisplayTypeChanged = true;
}
}
}
public void Receive(PropertyChangedMessage<LyricsLayoutOrientation> message)
{
if (message.Sender is LyricsWindowStatus)
{
if (message.PropertyName == nameof(LyricsWindowStatus.LyricsLayoutOrientation))
{
_isLyricsLayoutOrientationChanged = true;
}
}
}
public void Receive(PropertyChangedMessage<LyricsFontColorType> message)
{
if (message.Sender is LyricsStyleSettings)
@@ -323,17 +351,45 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
}
}
public void Receive(PropertyChangedMessage<LyricsWindowMode> message)
public void Receive(PropertyChangedMessage<LyricsWindowStatus> message)
{
if (message.Sender is LiveStates)
{
if (message.PropertyName == nameof(LiveStates.LyricsWindowMode))
if (message.PropertyName == nameof(LiveStates.LyricsWindowStatus))
{
UpdateColorConfig();
UpdateImmersiveBackgroundOpacity();
UpdateSongInfoFontSize();
_isLayoutChanged = true;
}
}
}
public void Receive(PropertyChangedMessage<AlbumArtLayoutSettings> message)
{
if (message.Sender is LyricsWindowStatus)
{
if (message.PropertyName == nameof(LyricsWindowStatus.AlbumArtLayoutSettings))
{
_isAlbumArtCornerRadiusChanged = true;
_isAlbumArtShadowAmountChanged = true;
UpdateSongInfoFontSize();
}
}
}
public void Receive(PropertyChangedMessage<LyricsBackgroundSettings> message)
{
if (message.Sender is LyricsWindowStatus)
{
if (message.PropertyName == nameof(LyricsWindowStatus.LyricsBackgroundSettings))
{
_isAlbumArtBgOpacityChanged = true;
_isAlbumArtBgBlurAmountChanged = true;
_isCoverAcrylicEffectAmountChanged = true;
UpdateColorConfig();
}
}
}
}
}

View File

@@ -24,7 +24,25 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
interpolator: (from, to, progress) => Helper.ColorHelper.GetInterpolatedColor(progress, from, to)
);
private readonly ValueTransition<Color> _albumArtAccentColorTransition = new(
private readonly ValueTransition<Color> _albumArtAccentColor1Transition = new(
initialValue: Colors.Transparent,
durationSeconds: 0.3f,
interpolator: (from, to, progress) => Helper.ColorHelper.GetInterpolatedColor(progress, from, to)
);
private readonly ValueTransition<Color> _albumArtAccentColor2Transition = new(
initialValue: Colors.Transparent,
durationSeconds: 0.3f,
interpolator: (from, to, progress) => Helper.ColorHelper.GetInterpolatedColor(progress, from, to)
);
private readonly ValueTransition<Color> _albumArtAccentColor3Transition = new(
initialValue: Colors.Transparent,
durationSeconds: 0.3f,
interpolator: (from, to, progress) => Helper.ColorHelper.GetInterpolatedColor(progress, from, to)
);
private readonly ValueTransition<Color> _albumArtAccentColor4Transition = new(
initialValue: Colors.Transparent,
durationSeconds: 0.3f,
interpolator: (from, to, progress) => Helper.ColorHelper.GetInterpolatedColor(progress, from, to)

View File

@@ -1,6 +1,8 @@
using BetterLyrics.WinUI3.Enums;
using BetterLyrics.WinUI3.Constants;
using BetterLyrics.WinUI3.Enums;
using BetterLyrics.WinUI3.Helper;
using BetterLyrics.WinUI3.Models;
using CommunityToolkit.WinUI;
using Microsoft.Graphics.Canvas;
using Microsoft.Graphics.Canvas.Effects;
using Microsoft.Graphics.Canvas.Text;
@@ -46,6 +48,14 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
private bool _isAlbumArtBgEffectChanged = false;
private bool _isAlbumArtEffectChanged = false;
private bool _isSongTitleVisibilityChanged = false;
private bool _isSongArtistsVisibilityChanged = false;
private bool _isSongInfoFontSizeChanged = false;
private bool _isAlbumArtSizeChanged = false;
private bool _isSpectrumOverlayEnabledChanged = true;
public void Update(ICanvasAnimatedControl control, CanvasAnimatedUpdateEventArgs args)
{
_elapsedTime = args.Timing.ElapsedTime;
@@ -61,6 +71,32 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
}
}
//_effect?.Properties["iTime"] = Convert.ToSingle(TotalTime.TotalSeconds);
if (_effect != null)
{
var effectTime = Convert.ToSingle(_effect.Properties["iTime"]);
effectTime += Convert.ToSingle(_elapsedTime.TotalSeconds);
_effect.Properties["iTime"] = effectTime;
if (_albumArtAccentColor1Transition.IsTransitioning)
{
_effect.Properties["color1"] = _albumArtAccentColor1Transition.Value.ToVector3RGB();
}
if (_albumArtAccentColor2Transition.IsTransitioning)
{
_effect.Properties["color2"] = _albumArtAccentColor2Transition.Value.ToVector3RGB();
}
if (_albumArtAccentColor3Transition.IsTransitioning)
{
_effect.Properties["color3"] = _albumArtAccentColor3Transition.Value.ToVector3RGB();
}
if (_albumArtAccentColor4Transition.IsTransitioning)
{
_effect.Properties["color4"] = _albumArtAccentColor4Transition.Value.ToVector3RGB();
}
}
// 检测播放行变更
var playingLineIndex = GetCurrentPlayingLineIndex();
_isPlayingLineChanged = _playingLineIndex != playingLineIndex;
@@ -88,38 +124,86 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
_isDebugOverlayEnabledChanged = false;
}
_rotateAngle += _coverRotateBaseSpeed * _settingsService.AppSettings.LyricsBackgroundSettings.CoverOverlaySpeed / 100.0;
_rotateAngle += _coverRotateBaseSpeed * _liveStatesService.LiveStates.LyricsWindowStatus.LyricsBackgroundSettings.CoverOverlaySpeed / 100.0;
_rotateAngle %= Math.PI * 2;
if (_isCanvasWidthChanged)
if (_isSpectrumOverlayEnabledChanged)
{
if (_canvasWidth < 500)
if (_liveStatesService.LiveStates.LyricsWindowStatus.LyricsBackgroundSettings.IsSpectrumOverlayEnabled)
{
_lyricsLayoutOrientation = LyricsLayoutOrientation.Vertical;
_spectrumAnalyzer?.StartCapture();
}
else
{
_lyricsLayoutOrientation = LyricsLayoutOrientation.Horizontal;
_spectrumAnalyzer?.StopCapture();
}
_isSpectrumOverlayEnabledChanged = false;
}
if (_spectrumAnalyzer?.IsCapturing == true)
{
_spectrumAnalyzer?.UpdateSmoothSpectrum();
}
//if (_isCanvasWidthChanged)
//{
// if (_canvasWidth < 500)
// {
// _lyricsLayoutOrientation = LyricsLayoutOrientation.Vertical;
// }
// else
// {
// _lyricsLayoutOrientation = LyricsLayoutOrientation.Horizontal;
// }
//}
if (_isCanvasWidthChanged || _isCanvasHeightChanged)
{
_isCoverAcrylicEffectAmountChanged = true;
_effect?.Properties["Width"] = (float)control.ConvertDipsToPixels((float)_canvasWidth, CanvasDpiRounding.Round);
_effect?.Properties["Height"] = (float)control.ConvertDipsToPixels((float)_canvasHeight, CanvasDpiRounding.Round);
}
if (_isDisplayTypeChanged || _isCanvasWidthChanged || _isCanvasHeightChanged)
if (_isSongInfoFontSizeChanged || _isSongTitleVisibilityChanged || _isSongArtistsVisibilityChanged)
{
bool jumpTo = !_isDisplayTypeChanged && (_isCanvasWidthChanged || _isCanvasHeightChanged);
switch (_lyricsLayoutOrientation)
_songInfoHeight = 0;
if (_liveStatesService.LiveStates.LyricsWindowStatus.AlbumArtLayoutSettings.ShowTitle)
{
_songInfoHeight += (int)_titleTextFormat.FontSize;
if (_liveStatesService.LiveStates.LyricsWindowStatus.AlbumArtLayoutSettings.ShowArtists)
{
_songInfoHeight += (int)_artistTextFormat.FontSize;
}
}
}
if (_isDisplayTypeChanged || _isLyricsLayoutOrientationChanged || _isAlbumArtSizeChanged ||
_isSongInfoFontSizeChanged || _isSongTitleVisibilityChanged || _isSongArtistsVisibilityChanged ||
_isCanvasWidthChanged || _isCanvasHeightChanged ||
_isAlbumArtSizeChanged)
{
bool jumpTo = !_isDisplayTypeChanged && !_isLyricsLayoutOrientationChanged &&
(_isCanvasWidthChanged || _isCanvasHeightChanged);
switch (_liveStatesService.LiveStates.LyricsWindowStatus.LyricsLayoutOrientation)
{
case LyricsLayoutOrientation.Horizontal:
_albumArtSize = Math.Min((_canvasHeight - _topMargin - _bottomMargin) * 8.5 / 16.0, (_canvasWidth - _leftMargin - _middleMargin - _rightMargin) / 2.0);
_albumArtSize = Math.Max(0, _albumArtSize);
_albumArtYTransition.StartTransition((_canvasHeight - _albumArtSize * 1.05 - _titleTextFormat.FontSize - _artistTextFormat.FontSize) / 2.0, jumpTo);
if (_liveStatesService.LiveStates.LyricsWindowStatus.AlbumArtLayoutSettings.AutoAlbumArtSize)
{
_albumArtSize = Math.Min((_canvasHeight - _topMargin - _bottomMargin) * 8.5 / 16.0,
(_canvasWidth - _leftMargin - _middleMargin - _rightMargin) / 2.0);
_albumArtSize = Math.Max(0, _albumArtSize);
}
else
{
_albumArtSize = _liveStatesService.LiveStates.LyricsWindowStatus.AlbumArtLayoutSettings.AlbumArtSize;
}
//_albumArtYTransition.StartTransition((_canvasHeight - _albumArtSize * 1.05 - _songInfoHeight) / 2.0, jumpTo);
_albumArtYTransition.StartTransition((_canvasHeight - _albumArtSize - _songInfoHeight) / 2.0, jumpTo);
_titleYTransition.StartTransition(_albumArtYTransition.TargetValue + _albumArtSize * 1.05, jumpTo);
_lyricsYTransition.StartTransition(0, jumpTo);
switch (_liveStatesService.LiveStates.LyricsDisplayType)
switch (_liveStatesService.LiveStates.LyricsWindowStatus.LyricsDisplayType)
{
case LyricsDisplayType.AlbumArtOnly:
_lyricsOpacityTransition.StartTransition(0f, jumpTo);
@@ -144,11 +228,18 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
}
break;
case LyricsLayoutOrientation.Vertical:
_albumArtSize = 64;
if (_liveStatesService.LiveStates.LyricsWindowStatus.AlbumArtLayoutSettings.AutoAlbumArtSize)
{
_albumArtSize = 64;
}
else
{
_albumArtSize = _liveStatesService.LiveStates.LyricsWindowStatus.AlbumArtLayoutSettings.AlbumArtSize;
}
_lyricsXTransition.StartTransition(_leftMargin, jumpTo);
_albumArtXTransition.StartTransition(_leftMargin, jumpTo);
_titleXTransition.StartTransition(_leftMargin + _albumArtSize * 1.2, jumpTo);
switch (_liveStatesService.LiveStates.LyricsDisplayType)
switch (_liveStatesService.LiveStates.LyricsWindowStatus.LyricsDisplayType)
{
case LyricsDisplayType.AlbumArtOnly:
_lyricsOpacityTransition.StartTransition(0f, jumpTo);
@@ -166,7 +257,8 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
_titleYTransition.StartTransition(_topMargin, jumpTo);
_lyricsOpacityTransition.StartTransition(1f, jumpTo);
_albumArtOpacityTransition.StartTransition(1f, jumpTo);
_lyricsYTransition.StartTransition(_albumArtSize, jumpTo);
//_lyricsYTransition.StartTransition(_albumArtSize, jumpTo);
_lyricsYTransition.StartTransition(_topMargin, jumpTo);
break;
default:
break;
@@ -176,6 +268,10 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
break;
}
_isDisplayTypeChanged = false;
_isSongInfoFontSizeChanged = false;
_isSongTitleVisibilityChanged = false;
_isSongArtistsVisibilityChanged = false;
}
// 先重置这两个的变化状态
@@ -197,11 +293,12 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
}
}
// 背景图切换计算
// 背景图变动计算
// 将当前背景图放到 _lastAlbumArtSwBitmap 中 并设置不透明度为 1
// 将新的背景图放到 _albumArtSwBitmap 中 并设置不透明度为 0
// 这样可以实现背景图的连贯渐变效果
if (_albumArtChanged || _isCanvasHeightChanged || _isCanvasWidthChanged ||
if (_albumArtChanged || _isLyricsLayoutOrientationChanged || _isAlbumArtSizeChanged ||
_isCanvasHeightChanged || _isCanvasWidthChanged ||
_lyricsBgBrightnessTransition.IsTransitioning ||
_albumArtBgTransition.IsTransitioning)
{
@@ -237,6 +334,9 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
_isAlbumArtBgEffectChanged = true;
}
_isLyricsLayoutOrientationChanged = false;
_isAlbumArtSizeChanged = false;
if (_isCoverAcrylicEffectAmountChanged)
{
UpdateCoverAcrylicOverlay(control);
@@ -306,15 +406,24 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
_titleXTransition.Update(_elapsedTime);
_titleYTransition.Update(_elapsedTime);
_lyricsXTransition.Update(_elapsedTime);
_lyricsYTransition.Update(_elapsedTime);
_albumArtXTransition.Update(_elapsedTime);
_albumArtYTransition.Update(_elapsedTime);
_lyricsOpacityTransition.Update(_elapsedTime);
_albumArtOpacityTransition.Update(_elapsedTime);
_immersiveBgOpacityTransition.Update(_elapsedTime);
_immersiveBgColorTransition.Update(_elapsedTime);
_albumArtAccentColorTransition.Update(_elapsedTime);
_albumArtAccentColor1Transition.Update(_elapsedTime);
_albumArtAccentColor2Transition.Update(_elapsedTime);
_albumArtAccentColor3Transition.Update(_elapsedTime);
_albumArtAccentColor4Transition.Update(_elapsedTime);
_albumArtBgTransition.Update(_elapsedTime);
_lyricsBgBrightnessTransition.Update(_elapsedTime);
_songInfoOpacityTransition.Update(_elapsedTime);
@@ -326,19 +435,19 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
if (control == null)
return;
if (_liveStatesService.LiveStates.LyricsStyleSettings.IsDynamicLyricsFontSize)
if (_liveStatesService.LiveStates.LyricsWindowStatus.LyricsStyleSettings.IsDynamicLyricsFontSize)
{
_lyricsTextFormat.FontSize = (float)Math.Clamp(Math.Min(_canvasHeight, _canvasWidth) / 10, 12, 72);
}
else
{
_lyricsTextFormat.FontSize = _liveStatesService.LiveStates.LyricsStyleSettings.LyricsFontSize;
_lyricsTextFormat.FontSize = _liveStatesService.LiveStates.LyricsWindowStatus.LyricsStyleSettings.LyricsFontSize;
}
_lyricsTextFormat.FontWeight = _liveStatesService.LiveStates.LyricsStyleSettings.LyricsFontWeight.ToFontWeight();
_lyricsTextFormat.FontFamily = _artistTextFormat.FontFamily = _titleTextFormat.FontFamily = _liveStatesService.LiveStates.LyricsStyleSettings.LyricsFontFamily;
_lyricsTextFormat.FontWeight = _liveStatesService.LiveStates.LyricsWindowStatus.LyricsStyleSettings.LyricsFontWeight.ToFontWeight();
_lyricsTextFormat.FontFamily = _artistTextFormat.FontFamily = _titleTextFormat.FontFamily = _liveStatesService.LiveStates.LyricsWindowStatus.LyricsStyleSettings.LyricsFontFamily;
_canvasYScrollTransition.SetDuration(_liveStatesService.LiveStates.LyricsEffectSettings.LyricsScrollDuration / 1000.0);
_canvasYScrollTransition.SetEasingType(_liveStatesService.LiveStates.LyricsEffectSettings.LyricsScrollEasingType);
_canvasYScrollTransition.SetDuration(_liveStatesService.LiveStates.LyricsWindowStatus.LyricsEffectSettings.LyricsScrollDuration / 1000.0);
_canvasYScrollTransition.SetEasingType(_liveStatesService.LiveStates.LyricsWindowStatus.LyricsEffectSettings.LyricsScrollEasingType);
double y = 0;
@@ -353,15 +462,15 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
}
line.Position = new Vector2(0, (float)y);
line.RecreateTextLayout(control, _lyricsTextFormat, _maxLyricsWidth, _canvasHeight, _liveStatesService.LiveStates.LyricsStyleSettings.LyricsAlignmentType);
line.UpdateCenterPosition(_maxLyricsWidth, _liveStatesService.LiveStates.LyricsStyleSettings.LyricsAlignmentType);
line.RecreateTextLayout(control, _lyricsTextFormat, _maxLyricsWidth, _canvasHeight, _liveStatesService.LiveStates.LyricsWindowStatus.LyricsStyleSettings.LyricsAlignmentType);
line.UpdateCenterPosition(_maxLyricsWidth, _liveStatesService.LiveStates.LyricsWindowStatus.LyricsStyleSettings.LyricsAlignmentType);
line.RecreateTextGeometry();
y +=
(double)line.CanvasTextLayout!.LayoutBounds.Height
/ line.CanvasTextLayout.LineCount
* (line.CanvasTextLayout.LineCount + _liveStatesService.LiveStates.LyricsStyleSettings.LyricsLineSpacingFactor);
* (line.CanvasTextLayout.LineCount + _liveStatesService.LiveStates.LyricsWindowStatus.LyricsStyleSettings.LyricsLineSpacingFactor);
}
}
@@ -458,14 +567,13 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
private void UpdateColorConfig()
{
if (_liveStatesService.LiveStates.LyricsWindowMode == LyricsWindowMode.DesktopMode ||
_liveStatesService.LiveStates.LyricsWindowMode == LyricsWindowMode.DockMode)
if (_liveStatesService.LiveStates.LyricsWindowStatus.IsAdaptToEnvironment)
{
ThemeTypeSent = Helper.ColorHelper.GetElementThemeFromBackgroundColor(_environmentalColor);
}
else
{
ThemeTypeSent = _settingsService.AppSettings.LyricsBackgroundSettings.LyricsBackgroundTheme;
ThemeTypeSent = _liveStatesService.LiveStates.LyricsWindowStatus.LyricsBackgroundSettings.LyricsBackgroundTheme;
}
double brightness;
@@ -483,20 +591,25 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
_adaptiveGrayedFontColor = _darkColor;
brightness = 0.7f;
_grayedEnvironmentalColor = _lightColor;
_albumArtAccentColorTransition.StartTransition(_albumArtLightAccentColor);
_albumArtAccentColor1Transition.StartTransition(_albumArtLightAccentColors.ElementAtOrDefault(0));
_albumArtAccentColor2Transition.StartTransition(_albumArtLightAccentColors.ElementAtOrDefault(1));
_albumArtAccentColor3Transition.StartTransition(_albumArtLightAccentColors.ElementAtOrDefault(2));
_albumArtAccentColor4Transition.StartTransition(_albumArtLightAccentColors.ElementAtOrDefault(3));
}
else
{
_adaptiveGrayedFontColor = _lightColor;
brightness = 0.3f;
_grayedEnvironmentalColor = _darkColor;
_albumArtAccentColorTransition.StartTransition(_albumArtDarkAccentColor);
_albumArtAccentColor1Transition.StartTransition(_albumArtDarkAccentColors.ElementAtOrDefault(0));
_albumArtAccentColor2Transition.StartTransition(_albumArtDarkAccentColors.ElementAtOrDefault(1));
_albumArtAccentColor3Transition.StartTransition(_albumArtDarkAccentColors.ElementAtOrDefault(2));
_albumArtAccentColor4Transition.StartTransition(_albumArtDarkAccentColors.ElementAtOrDefault(3));
}
_lyricsBgBrightnessTransition.StartTransition(brightness);
if (_liveStatesService.LiveStates.LyricsWindowMode == LyricsWindowMode.DockMode ||
_liveStatesService.LiveStates.LyricsWindowMode == LyricsWindowMode.DesktopMode)
if (_liveStatesService.LiveStates.LyricsWindowStatus.IsAdaptToEnvironment)
{
_adaptiveColoredFontColor = Helper.ColorHelper.GetForegroundColor(_environmentalColor);
}
@@ -504,15 +617,15 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
{
if (isLight)
{
_adaptiveColoredFontColor = _albumArtDarkAccentColor;
_adaptiveColoredFontColor = _albumArtDarkAccentColors.FirstOrDefault();
}
else
{
_adaptiveColoredFontColor = _albumArtLightAccentColor;
_adaptiveColoredFontColor = _albumArtLightAccentColors.FirstOrDefault();
}
}
switch (_liveStatesService.LiveStates.LyricsStyleSettings.LyricsBgFontColorType)
switch (_liveStatesService.LiveStates.LyricsWindowStatus.LyricsStyleSettings.LyricsBgFontColorType)
{
case LyricsFontColorType.AdaptiveGrayed:
_bgFontColor = _adaptiveGrayedFontColor;
@@ -521,13 +634,13 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
_bgFontColor = _adaptiveColoredFontColor ?? _adaptiveGrayedFontColor;
break;
case LyricsFontColorType.Custom:
_bgFontColor = _liveStatesService.LiveStates.LyricsStyleSettings.LyricsCustomBgFontColor;
_bgFontColor = _liveStatesService.LiveStates.LyricsWindowStatus.LyricsStyleSettings.LyricsCustomBgFontColor;
break;
default:
break;
}
switch (_liveStatesService.LiveStates.LyricsStyleSettings.LyricsFgFontColorType)
switch (_liveStatesService.LiveStates.LyricsWindowStatus.LyricsStyleSettings.LyricsFgFontColorType)
{
case LyricsFontColorType.AdaptiveGrayed:
_fgFontColor = _adaptiveGrayedFontColor;
@@ -536,13 +649,13 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
_fgFontColor = _adaptiveColoredFontColor ?? _adaptiveGrayedFontColor;
break;
case LyricsFontColorType.Custom:
_fgFontColor = _liveStatesService.LiveStates.LyricsStyleSettings.LyricsCustomFgFontColor;
_fgFontColor = _liveStatesService.LiveStates.LyricsWindowStatus.LyricsStyleSettings.LyricsCustomFgFontColor;
break;
default:
break;
}
switch (_liveStatesService.LiveStates.LyricsStyleSettings.LyricsStrokeFontColorType)
switch (_liveStatesService.LiveStates.LyricsWindowStatus.LyricsStyleSettings.LyricsStrokeFontColorType)
{
case LyricsFontColorType.AdaptiveGrayed:
_strokeFontColor = _grayedEnvironmentalColor.WithBrightness(0.7);
@@ -551,7 +664,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
_strokeFontColor = _environmentalColor.WithBrightness(0.7);
break;
case LyricsFontColorType.Custom:
_strokeFontColor = _liveStatesService.LiveStates.LyricsStyleSettings.LyricsCustomStrokeFontColor;
_strokeFontColor = _liveStatesService.LiveStates.LyricsWindowStatus.LyricsStyleSettings.LyricsCustomStrokeFontColor;
break;
default:
break;
@@ -579,7 +692,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
double distanceFromPlayingLine = Math.Abs(line.Position.Y - currentPlayingLine.Position.Y);
double distanceFactor = Math.Clamp(distanceFromPlayingLine / (_canvasHeight / 2), 0, 1);
line.AngleTransition.StartTransition(_liveStatesService.LiveStates.LyricsEffectSettings.IsFanLyricsEnabled
line.AngleTransition.StartTransition(_liveStatesService.LiveStates.LyricsWindowStatus.LyricsEffectSettings.IsFanLyricsEnabled
? Math.PI
* (30.0 / 180.0)
* distanceFactor
@@ -587,12 +700,12 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
: 0
);
line.BlurAmountTransition.StartTransition(_liveStatesService.LiveStates.LyricsEffectSettings.LyricsBlurAmount * distanceFactor);
line.BlurAmountTransition.StartTransition(_liveStatesService.LiveStates.LyricsWindowStatus.LyricsEffectSettings.LyricsBlurAmount * distanceFactor);
line.ScaleTransition.StartTransition(_highlightedScale - distanceFactor * (_highlightedScale - _defaultScale));
line.OpacityTransition.StartTransition(
_liveStatesService.LiveStates.LyricsStyleSettings.LyricsBgFontOpacity / 100.0 -
distanceFactor * _liveStatesService.LiveStates.LyricsStyleSettings.LyricsBgFontOpacity / 100.0 *
(1 - _liveStatesService.LiveStates.LyricsEffectSettings.LyricsVerticalEdgeOpacity / 100.0));
_liveStatesService.LiveStates.LyricsWindowStatus.LyricsStyleSettings.LyricsBgFontOpacity / 100.0 -
distanceFactor * _liveStatesService.LiveStates.LyricsWindowStatus.LyricsStyleSettings.LyricsBgFontOpacity / 100.0 *
(1 - _liveStatesService.LiveStates.LyricsWindowStatus.LyricsEffectSettings.LyricsVerticalEdgeOpacity / 100.0));
line.HighlightOpacityTransition.StartTransition(i == _playingLineIndex ? 1f : 0f);
double yScrollDuration;
@@ -602,8 +715,8 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
{
yScrollDuration =
_canvasYScrollTransition.DurationSeconds +
distanceFactor * (_liveStatesService.LiveStates.LyricsEffectSettings.LyricsScrollTopDuration / 1000.0 - _canvasYScrollTransition.DurationSeconds);
yScrollDelay = distanceFactor * _liveStatesService.LiveStates.LyricsEffectSettings.LyricsScrollTopDelay / 1000.0;
distanceFactor * (_liveStatesService.LiveStates.LyricsWindowStatus.LyricsEffectSettings.LyricsScrollTopDuration / 1000.0 - _canvasYScrollTransition.DurationSeconds);
yScrollDelay = distanceFactor * _liveStatesService.LiveStates.LyricsWindowStatus.LyricsEffectSettings.LyricsScrollTopDelay / 1000.0;
}
else if (lineCountDelta == 0)
{
@@ -614,8 +727,8 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
{
yScrollDuration =
_canvasYScrollTransition.DurationSeconds +
distanceFactor * (_liveStatesService.LiveStates.LyricsEffectSettings.LyricsScrollBottomDuration / 1000.0 - _canvasYScrollTransition.DurationSeconds);
yScrollDelay = distanceFactor * _liveStatesService.LiveStates.LyricsEffectSettings.LyricsScrollBottomDelay / 1000.0;
distanceFactor * (_liveStatesService.LiveStates.LyricsWindowStatus.LyricsEffectSettings.LyricsScrollBottomDuration / 1000.0 - _canvasYScrollTransition.DurationSeconds);
yScrollDelay = distanceFactor * _liveStatesService.LiveStates.LyricsWindowStatus.LyricsEffectSettings.LyricsScrollBottomDelay / 1000.0;
}
line.YOffsetTransition.SetEasingType(_canvasYScrollTransition.EasingType ?? EasingType.Linear);
@@ -633,37 +746,9 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
}
}
private void UpdateImmersiveBackgroundOpacity()
{
double targetOpacity;
if (_liveStatesService.LiveStates.LyricsWindowMode == LyricsWindowMode.DesktopMode)
{
if (_isLyricsWindowLocked)
{
targetOpacity = 0;
}
else
{
if (_isMouseWithinWindow)
{
targetOpacity = 1f;
}
else
{
targetOpacity = 0f;
}
}
}
else
{
targetOpacity = 1f;
}
_immersiveBgOpacityTransition.StartTransition(targetOpacity);
}
private void UpdateCoverAcrylicOverlay(ICanvasAnimatedControl control)
{
if (_settingsService.AppSettings.LyricsBackgroundSettings.CoverAcrylicEffectAmount > 0)
if (_liveStatesService.LiveStates.LyricsWindowStatus.LyricsBackgroundSettings.CoverAcrylicEffectAmount > 0)
{
var ret = ImageHelper.GenerateNoiseBGRA((int)_canvasWidth, (int)_canvasHeight);
_coverAcrylicNoiseCanvasBitmap?.Dispose();
@@ -698,8 +783,10 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
private void UpdateSongInfoFontSize()
{
_titleTextFormat.FontSize = _settingsService.AppSettings.AlbumArtLayoutSettings.SongInfoFontSize;
_artistTextFormat.FontSize = _settingsService.AppSettings.AlbumArtLayoutSettings.SongInfoFontSize - 2;
_titleTextFormat.FontSize = _liveStatesService.LiveStates.LyricsWindowStatus.AlbumArtLayoutSettings.SongInfoFontSize;
_artistTextFormat.FontSize = _liveStatesService.LiveStates.LyricsWindowStatus.AlbumArtLayoutSettings.SongInfoFontSize - 2;
_isSongInfoFontSizeChanged = true;
}
}
}

View File

@@ -18,6 +18,7 @@ using CommunityToolkit.Mvvm.DependencyInjection;
using CommunityToolkit.WinUI;
using Microsoft.Extensions.Logging;
using Microsoft.Graphics.Canvas;
using Microsoft.Graphics.Canvas.Effects;
using Microsoft.Graphics.Canvas.Text;
using Microsoft.UI;
using Microsoft.UI.Text;
@@ -68,6 +69,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
private CanvasBitmap? _coverAcrylicNoiseCanvasBitmap = null;
private double _albumArtSize = 0f;
private int _songInfoHeight = 0;
private string? _lastSongTitle;
private string? _songTitle;
@@ -103,8 +105,8 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
private Color _adaptiveGrayedFontColor = Colors.Transparent;
private Color? _adaptiveColoredFontColor = null;
private Color _albumArtLightAccentColor = Colors.Transparent;
private Color _albumArtDarkAccentColor = Colors.Transparent;
private List<Color> _albumArtLightAccentColors = Enumerable.Repeat(Colors.Transparent, 4).ToList();
private List<Color> _albumArtDarkAccentColors = Enumerable.Repeat(Colors.Transparent, 4).ToList();
private Color _environmentalColor = Colors.Transparent;
private Color _grayedEnvironmentalColor = Colors.Transparent;
@@ -127,9 +129,6 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
[ObservableProperty]
public partial bool IsPlaying { get; set; } = false;
private bool _isLyricsWindowLocked = false;
private bool _isMouseWithinWindow = false;
private bool _isLayoutChanged = true;
private int _timelineSyncThreshold = 0;
@@ -164,7 +163,7 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
FontWeight = FontWeights.ExtraBlack,
};
private LyricsLayoutOrientation _lyricsLayoutOrientation;
//private LyricsLayoutOrientation _lyricsLayoutOrientation;
[ObservableProperty]
public partial SongInfo? SongInfo { get; set; }
@@ -173,6 +172,8 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
[NotifyPropertyChangedRecipients]
public partial ElementTheme ThemeTypeSent { get; set; }
private SpectrumAnalyzer? _spectrumAnalyzer;
public LyricsRendererViewModel(
ISettingsService settingsService,
IMediaSessionsService mediaSessionsService,
@@ -182,17 +183,15 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
_settingsService = settingsService;
_mediaSessionsService = mediaSessionsService;
_liveStatesService = liveStatesService;
_lastFMService = lastFMService;
_logger = Ioc.Default.GetRequiredService<ILogger<LyricsRendererViewModel>>();
AppSettings = _settingsService.AppSettings;
_titleTextFormat.HorizontalAlignment = _artistTextFormat.HorizontalAlignment = _settingsService.AppSettings.AlbumArtLayoutSettings.SongInfoAlignmentType.ToCanvasHorizontalAlignment();
_titleTextFormat.HorizontalAlignment = _artistTextFormat.HorizontalAlignment = _liveStatesService.LiveStates.LyricsWindowStatus.AlbumArtLayoutSettings.SongInfoAlignmentType.ToCanvasHorizontalAlignment();
UpdateSongInfoFontSize();
_timelineSyncThreshold = 0;
_mediaSessionsService.IsPlayingChanged += MediaSessionsService_IsPlayingChanged;
@@ -204,6 +203,8 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
IsPlaying = _mediaSessionsService.IsPlaying;
UpdateColorConfig();
_spectrumAnalyzer = new SpectrumAnalyzer();
}
private void MediaSessionsService_LyricsChanged(object? sender, LyricsChangedEventArgs e)
@@ -398,8 +399,8 @@ namespace BetterLyrics.WinUI3.ViewModels.LyricsRendererViewModel
_albumArtChanged = true;
_albumArtLightAccentColor = e.AlbumArtLightAccentColor ?? Colors.Transparent;
_albumArtDarkAccentColor = e.AlbumArtDarkAccentColor ?? Colors.Transparent;
_albumArtLightAccentColors = e.AlbumArtLightAccentColors;
_albumArtDarkAccentColors = e.AlbumArtDarkAccentColors;
UpdateColorConfig();
}

View File

@@ -0,0 +1,100 @@
using BetterLyrics.WinUI3.Helper;
using BetterLyrics.WinUI3.Models;
using BetterLyrics.WinUI3.Models.Settings;
using BetterLyrics.WinUI3.Services.LiveStatesService;
using BetterLyrics.WinUI3.Services.SettingsService;
using BetterLyrics.WinUI3.Views;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Microsoft.UI.Xaml.Controls;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static Vanara.PInvoke.User32.RAWINPUT;
namespace BetterLyrics.WinUI3.ViewModels
{
public partial class LyricsWindowSettingsControlViewModel : BaseViewModel
{
private readonly ISettingsService _settingsService;
private readonly ILiveStatesService _liveStatesService;
[ObservableProperty]
public partial LiveStates LiveStates { get; set; }
[ObservableProperty]
public partial AppSettings AppSettings { get; set; }
[ObservableProperty]
public partial object ListViewSelectedItemTag { get; set; } = "General";
[ObservableProperty]
public partial ObservableCollection<string> MonitorDeviceNames { get; set; }
public LyricsWindowSettingsControlViewModel(ISettingsService settingsService, ILiveStatesService liveStatesService)
{
_settingsService = settingsService;
_liveStatesService = liveStatesService;
AppSettings = _settingsService.AppSettings;
AppSettings.WindowBoundsRecords.CollectionChanged += WindowBoundsRecords_CollectionChanged;
LiveStates = _liveStatesService.LiveStates;
MonitorDeviceNames = [.. MonitorHelper.GetAllMonitorDeviceNames()];
}
private void WindowBoundsRecords_CollectionChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (!AppSettings.WindowBoundsRecords.Any(x => x == LiveStates.LyricsWindowStatus))
{
LiveStates.LyricsWindowStatus = AppSettings.WindowBoundsRecords.FirstOrDefault();
}
}
[RelayCommand]
private void RefreshMonitorDeviceNames()
{
MonitorDeviceNames = [.. MonitorHelper.GetAllMonitorDeviceNames()];
LiveStates.LyricsWindowStatus.MonitorDeviceName = MonitorHelper.GetPrimaryMonitorDeviceName();
}
[RelayCommand]
private void CreateStandardLyricsWindowStatus()
{
AppSettings.WindowBoundsRecords.Add(LyricsWindowStatusExtensions.StandardMode());
}
[RelayCommand]
private void CreateTransparentLyricsWindowStatus()
{
AppSettings.WindowBoundsRecords.Add(LyricsWindowStatusExtensions.DesktopMode());
}
[RelayCommand]
private void CreateDockedLyricsWindowStatus()
{
AppSettings.WindowBoundsRecords.Add(LyricsWindowStatusExtensions.DockedMode());
}
[RelayCommand]
private void CreateFullLyricsWindowStatus()
{
AppSettings.WindowBoundsRecords.Add(LyricsWindowStatusExtensions.FullscreenMode(LiveStates.LyricsWindowStatus.MonitorBounds));
}
[RelayCommand]
private void CreateNarrowLyricsWindowStatus()
{
AppSettings.WindowBoundsRecords.Add(LyricsWindowStatusExtensions.NarrowMode());
}
[RelayCommand]
private void CopyLyricsWindowStatus()
{
var data = (LyricsWindowStatus)LiveStates.LyricsWindowStatus.Clone();
data.IsDefault = false;
AppSettings.WindowBoundsRecords.Add(data);
}
}
}

View File

@@ -0,0 +1,36 @@
using BetterLyrics.WinUI3.Helper;
using BetterLyrics.WinUI3.Models;
using BetterLyrics.WinUI3.Models.Settings;
using BetterLyrics.WinUI3.Services.LiveStatesService;
using BetterLyrics.WinUI3.Services.SettingsService;
using CommunityToolkit.Mvvm.ComponentModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BetterLyrics.WinUI3.ViewModels
{
public partial class LyricsWindowSwitchControlViewModel : BaseViewModel
{
private readonly ISettingsService _settingsService;
private readonly ILiveStatesService _liveStatesService;
[ObservableProperty]
public partial LiveStates LiveStates { get; set; }
[ObservableProperty]
public partial AppSettings AppSettings { get; set; }
public LyricsWindowSwitchControlViewModel(ISettingsService settingsService, ILiveStatesService liveStatesService)
{
_settingsService = settingsService;
_liveStatesService = liveStatesService;
AppSettings = _settingsService.AppSettings;
LiveStates = _liveStatesService.LiveStates;
}
}
}

View File

@@ -21,6 +21,7 @@ using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using System.Collections.Generic;
using Vanara.PInvoke;
using Windows.Foundation;
using Windows.System;
using Windows.UI;
using WinRT.Interop;
@@ -30,24 +31,14 @@ namespace BetterLyrics.WinUI3
{
public partial class LyricsWindowViewModel
: BaseWindowViewModel,
IRecipient<PropertyChangedMessage<int>>,
IRecipient<PropertyChangedMessage<List<string>>>,
IRecipient<PropertyChangedMessage<bool>>,
IRecipient<PropertyChangedMessage<string>>,
IRecipient<PropertyChangedMessage<ElementTheme>>,
IRecipient<PropertyChangedMessage<DockPlacement>>
IRecipient<PropertyChangedMessage<ElementTheme>>
{
private readonly IMediaSessionsService _mediaSessionsService;
private readonly ISettingsService _settingsService;
private readonly ILiveStatesService _liveStatesService;
private ForegroundWindowWatcher? _windowWatcher = null;
private bool _ignoreFullscreenWindow;
private bool _hideWindowWhenNotPlaying;
private DockPlacement _dockPlacement;
private int _dockWindowHeight;
private string _dockMonitorDeviceName;
private ForegroundWindowWatcher? _fgWindowWatcher = null;
public LyricsWindowViewModel(ISettingsService settingsService, IMediaSessionsService mediaSessionsService, ILiveStatesService liveStatesService)
{
@@ -58,169 +49,37 @@ namespace BetterLyrics.WinUI3
AppSettings = _settingsService.AppSettings;
LiveStates = _liveStatesService.LiveStates;
_dockMonitorDeviceName = _settingsService.AppSettings.DockModeSettings.DockMonitorDeviceName;
_ignoreFullscreenWindow = _settingsService.AppSettings.GeneralSettings.IgnoreFullscreenWindow;
_hideWindowWhenNotPlaying = _settingsService.AppSettings.GeneralSettings.HideWindowWhenNotPlaying;
IsImmersiveMode = _settingsService.AppSettings.GeneralSettings.IsImmersiveMode;
_dockPlacement = _settingsService.AppSettings.DockModeSettings.DockPlacement;
_dockWindowHeight = _settingsService.AppSettings.DockModeSettings.DockWindowHeight;
OnIsImmersiveModeChanged(_settingsService.AppSettings.GeneralSettings.IsImmersiveMode);
_mediaSessionsService.IsPlayingChanged += PlaybackService_IsPlayingChanged;
}
private void PlaybackService_IsPlayingChanged(object? sender, Events.IsPlayingChangedEventArgs e)
{
UpdateDockOrDesktopWindow();
WindowHelper.SetLyricsWindowVisibilityByPlayingStatus();
}
[ObservableProperty]
public partial AppSettings AppSettings { get; set; }
[ObservableProperty] public partial AppSettings AppSettings { get; set; }
[ObservableProperty]
public partial LiveStates LiveStates { get; set; }
[ObservableProperty] public partial LiveStates LiveStates { get; set; }
[ObservableProperty]
[NotifyPropertyChangedRecipients]
public partial Color ActivatedWindowAccentColor { get; set; }
/// <summary>
/// 歌词窗口所在的背景主题色
/// </summary>
[ObservableProperty][NotifyPropertyChangedRecipients] public partial Color BackdropAccentColor { get; set; }
[ObservableProperty]
[NotifyPropertyChangedRecipients]
public partial bool IsLyricsWindowLocked { get; set; } = false;
[ObservableProperty] public partial double TopCommandGridOpacity { get; set; } = 0;
[ObservableProperty]
[NotifyPropertyChangedRecipients]
public partial bool IsImmersiveMode { get; set; }
[ObservableProperty] public partial ElementTheme ThemeType { get; set; } = ElementTheme.Default;
[ObservableProperty]
public partial double TopCommandGridOpacity { get; set; }
[ObservableProperty] public partial double TitleBarFontSize { get; set; } = 11;
[ObservableProperty]
public partial ElementTheme ThemeType { get; set; } = ElementTheme.Default;
[ObservableProperty]
public partial double TitleBarFontSize { get; set; } = 11;
[ObservableProperty]
[NotifyPropertyChangedRecipients]
public partial bool IsMouseWithinWindow { get; set; } = false;
[ObservableProperty] public partial Visibility FullScreenFlyoutItemVisibility { get; set; } = Visibility.Visible;
[ObservableProperty] public partial Visibility LockButtonVisibility { get; set; } = Visibility.Visible;
[ObservableProperty] public partial Visibility DesktopFlyoutItemVisibility { get; set; } = Visibility.Visible;
[ObservableProperty] public partial Visibility PIPFlyoutItemVisibility { get; set; } = Visibility.Visible;
[ObservableProperty] public partial Visibility DockFlyoutItemVisibility { get; set; } = Visibility.Visible;
[ObservableProperty] public partial bool IsFullScreenFlyoutItemChecked { get; set; } = false;
[ObservableProperty] public partial bool IsDesktopFlyoutItemChecked { get; set; } = false;
[ObservableProperty] public partial bool IsPIPFlyoutItemChecked { get; set; } = false;
[ObservableProperty] public partial bool IsDockFlyoutItemChecked { get; set; } = false;
private void UpdateDockOrDesktopWindow()
{
var window = WindowHelper.GetWindowByWindowType<LyricsWindow>();
if (window == null) return;
var hwnd = WindowNative.GetWindowHandle(window);
if (LiveStates.LyricsWindowMode == LyricsWindowMode.DockMode || LiveStates.LyricsWindowMode == LyricsWindowMode.DesktopMode)
{
if (_hideWindowWhenNotPlaying && !_mediaSessionsService.IsPlaying)
{
if (LiveStates.LyricsWindowMode == LyricsWindowMode.DockMode)
{
DockModeHelper.UpdateAppBarHeight(hwnd, _dockMonitorDeviceName, 0, _dockPlacement);
}
window.Hide();
}
else
{
if (LiveStates.LyricsWindowMode == LyricsWindowMode.DockMode)
{
DockModeHelper.UpdateAppBarHeight(hwnd, _dockMonitorDeviceName, _dockWindowHeight, _dockPlacement);
}
window.Show();
}
}
}
partial void OnIsImmersiveModeChanged(bool value)
{
if (value)
{
TopCommandGridOpacity = 0f;
}
else
{
TopCommandGridOpacity = 1f;
}
}
public void Receive(PropertyChangedMessage<bool> message)
{
if (message.Sender is SystemTrayViewModel)
{
if (message.PropertyName == nameof(SystemTrayViewModel.IsLyricsWindowLocked))
{
if (IsLyricsWindowLocked != message.NewValue)
{
IsLyricsWindowLocked = message.NewValue;
}
}
}
else if (message.Sender is GeneralSettings)
{
if (message.PropertyName == nameof(GeneralSettings.IgnoreFullscreenWindow))
{
_ignoreFullscreenWindow = message.NewValue;
SetIsAlwaysOnTop();
}
else if (message.PropertyName == nameof(GeneralSettings.HideWindowWhenNotPlaying))
{
_hideWindowWhenNotPlaying = message.NewValue;
UpdateDockOrDesktopWindow();
}
}
else if (message.Sender is LiveStates)
{
if (message.PropertyName == nameof(LiveStates.IsAlwaysOnTop))
{
SetIsAlwaysOnTop();
}
}
}
public void Receive(PropertyChangedMessage<ElementTheme> message)
{
if (message.Sender is LyricsRendererViewModel)
{
if (message.PropertyName == nameof(LyricsRendererViewModel.ThemeTypeSent))
{
ThemeType = message.NewValue;
}
}
}
public void Receive(PropertyChangedMessage<int> message)
{
if (message.Sender is DockModeSettings)
{
if (message.PropertyName == nameof(DockModeSettings.DockWindowHeight))
{
_dockWindowHeight = message.NewValue;
UpdateDockOrDesktopWindow();
}
}
}
[ObservableProperty] public partial Visibility CloseButtonVisibility { get; set; } = Visibility.Visible;
public void InitShortcuts()
{
UpdateDesktopLockUnlockShortcut();
UpdateDesktopToggleShortcut();
UpdateDockToggleShortcut();
UpdatePictureInPictureToggleShortcut();
UpdateLyricsWindowBorderlessShortcut();
UpdateLyricsWindowClickThroughShortcut();
UpdateLyricsWindowShowHideShortcut();
UpdateLyricsWindowSwitchShortcut();
}
private void UpdateLyricsWindowShowHideShortcut()
@@ -231,162 +90,87 @@ namespace BetterLyrics.WinUI3
{
var window = WindowHelper.GetWindowByWindowType<LyricsWindow>();
if (window == null) return;
if (window.Visible)
{
window.Hide();
}
else
{
WindowHelper.OpenWindow<LyricsWindow>();
WindowHelper.OpenOrShowWindow<LyricsWindow>();
}
}
);
}
private void UpdateDesktopLockUnlockShortcut()
private void UpdateLyricsWindowBorderlessShortcut()
{
GlobalHotKeyHelper.UpdateHotKey<LyricsWindow>(ShortcutID.DesktopLockOrUnlock,
_settingsService.AppSettings.DesktopModeSettings.LockShortcut,
GlobalHotKeyHelper.UpdateHotKey<LyricsWindow>(ShortcutID.Borderless,
_settingsService.AppSettings.GeneralSettings.BorderlessShortcut,
() =>
{
if (LiveStates.LyricsWindowMode == LyricsWindowMode.DesktopMode)
{
ToggleLockWindow();
}
LiveStates.LyricsWindowStatus.IsBorderless = !LiveStates.LyricsWindowStatus.IsBorderless;
}
);
}
private void UpdateDesktopToggleShortcut()
private void UpdateLyricsWindowClickThroughShortcut()
{
GlobalHotKeyHelper.UpdateHotKey<LyricsWindow>(ShortcutID.DesktopToggle,
_settingsService.AppSettings.DesktopModeSettings.ToggleShortcut,
GlobalHotKeyHelper.UpdateHotKey<LyricsWindow>(ShortcutID.ClickThrough,
_settingsService.AppSettings.GeneralSettings.ClickThroughShortcut,
() =>
{
if (LiveStates.LyricsWindowMode == LyricsWindowMode.DesktopMode ||
LiveStates.LyricsWindowMode == LyricsWindowMode.StandardMode)
{
ToggleDesktopMode();
}
LiveStates.LyricsWindowStatus.IsClickThrough = !LiveStates.LyricsWindowStatus.IsClickThrough;
}
);
}
private void UpdateDockToggleShortcut()
private void UpdateLyricsWindowSwitchShortcut()
{
GlobalHotKeyHelper.UpdateHotKey<LyricsWindow>(ShortcutID.DockToggle,
_settingsService.AppSettings.DockModeSettings.ToggleShortcut,
GlobalHotKeyHelper.UpdateHotKey<LyricsWindow>(ShortcutID.LyricsWindowSwitch,
_settingsService.AppSettings.GeneralSettings.LyricsWindowSwitchShortcut,
() =>
{
if (LiveStates.LyricsWindowMode == LyricsWindowMode.DockMode ||
LiveStates.LyricsWindowMode == LyricsWindowMode.StandardMode)
{
ToggleDockMode();
}
WindowHelper.OpenOrShowWindow<LyricsWindowSwitchWindow>();
}
);
}
private void UpdatePictureInPictureToggleShortcut()
{
GlobalHotKeyHelper.UpdateHotKey<LyricsWindow>(ShortcutID.PictureInPictureToggle,
_settingsService.AppSettings.PictureInPictureModeSettings.ToggleShortcut,
() =>
{
if (LiveStates.LyricsWindowMode == LyricsWindowMode.PictureInPictureMode ||
LiveStates.LyricsWindowMode == LyricsWindowMode.StandardMode)
{
TogglePictureInPictureMode();
}
}
);
}
private void SetFullscreenTitleBarControlsStatus()
{
LockButtonVisibility = DesktopFlyoutItemVisibility = PIPFlyoutItemVisibility = DockFlyoutItemVisibility = Visibility.Collapsed;
IsFullScreenFlyoutItemChecked = true;
IsImmersiveMode = true;
}
private void SetPIPModeTitleBarControlsStatus()
{
DesktopFlyoutItemVisibility = FullScreenFlyoutItemVisibility = DockFlyoutItemVisibility = LockButtonVisibility = Visibility.Collapsed;
IsImmersiveMode = true;
IsPIPFlyoutItemChecked = true;
}
private void SetDockModeTitleBarControlsStatus()
{
var window = WindowHelper.GetWindowByWindowType<LyricsWindow>();
if (window == null) return;
var overlappedPresenter = (OverlappedPresenter)window.AppWindow.Presenter;
overlappedPresenter.IsMinimizable = overlappedPresenter.IsMaximizable = false;
DesktopFlyoutItemVisibility = LockButtonVisibility = FullScreenFlyoutItemVisibility = PIPFlyoutItemVisibility = Visibility.Collapsed;
IsImmersiveMode = true;
IsDockFlyoutItemChecked = true;
}
private void SetDesktopModeTitleBarControlsStatus()
{
var window = WindowHelper.GetWindowByWindowType<LyricsWindow>();
if (window == null) return;
var overlappedPresenter = (OverlappedPresenter)window.AppWindow.Presenter;
overlappedPresenter.IsMinimizable = overlappedPresenter.IsMaximizable = false;
DockFlyoutItemVisibility = FullScreenFlyoutItemVisibility = PIPFlyoutItemVisibility = Visibility.Collapsed;
LockButtonVisibility = Visibility.Visible;
IsDesktopFlyoutItemChecked = true;
}
public void SetStandardModeTitleBarControlsStatus()
{
var window = WindowHelper.GetWindowByWindowType<LyricsWindow>();
if (window == null) return;
var overlappedPresenter = (OverlappedPresenter)window.AppWindow.Presenter;
overlappedPresenter.IsMinimizable = overlappedPresenter.IsMaximizable = true;
DesktopFlyoutItemVisibility = DockFlyoutItemVisibility = PIPFlyoutItemVisibility = FullScreenFlyoutItemVisibility = Visibility.Visible;
LockButtonVisibility = Visibility.Collapsed;
IsFullScreenFlyoutItemChecked = IsDesktopFlyoutItemChecked = IsDockFlyoutItemChecked = IsPIPFlyoutItemChecked = false;
IsImmersiveMode = _settingsService.AppSettings.GeneralSettings.IsImmersiveMode;
}
public void StartWatchWindowColorChange()
public void InitFgWindowWatcher()
{
var window = WindowHelper.GetWindowByWindowType<LyricsWindow>();
if (window == null) return;
var hwnd = WindowNative.GetWindowHandle(window);
_windowWatcher = new ForegroundWindowWatcher(
_fgWindowWatcher = new ForegroundWindowWatcher(
hwnd,
fgHwnd =>
{
_dispatcherQueueTimer.Debounce(() =>
{
if ((LiveStates.LyricsWindowMode == LyricsWindowMode.DockMode || LiveStates.LyricsWindowMode == LyricsWindowMode.DesktopMode) && _ignoreFullscreenWindow && window.AppWindow.Presenter is OverlappedPresenter presenter)
if (_liveStatesService.LiveStates.LyricsWindowStatus.IsAlwaysOnTop &&
_liveStatesService.LiveStates.LyricsWindowStatus.IsAlwaysOnTopPolling &&
window.AppWindow.Presenter is OverlappedPresenter presenter)
{
presenter.IsAlwaysOnTop = true;
}
UpdateAccentColor(hwnd);
if (_liveStatesService.LiveStates.LyricsWindowStatus.IsAdaptToEnvironment)
{
UpdateBackdropAccentColor(hwnd);
}
}, Constants.Time.DebounceTimeout);
}
);
_windowWatcher.Start();
UpdateAccentColor(hwnd);
_fgWindowWatcher.Start();
UpdateBackdropAccentColor(hwnd);
}
private void StopWatchWindowColorChange()
public void UpdateBackdropAccentColor(nint hwnd)
{
_windowWatcher?.Stop();
_windowWatcher = null;
}
public void UpdateAccentColor(nint hwnd)
{
WindowPixelSampleMode mode = LiveStates.LyricsWindowMode == LyricsWindowMode.DesktopMode ? WindowPixelSampleMode.WindowEdge : _dockPlacement.ToWindowPixelSampleMode();
ActivatedWindowAccentColor = ColorHelper.GetAccentColor(hwnd, _settingsService.AppSettings.DockModeSettings.DockMonitorDeviceName, mode).ToColor();
BackdropAccentColor = ColorHelper.GetAccentColor(
hwnd,
_liveStatesService.LiveStates.LyricsWindowStatus.MonitorDeviceName,
_liveStatesService.LiveStates.LyricsWindowStatus.EnvironmentSampleMode).ToColor();
}
public void ExitOrClose()
@@ -402,191 +186,25 @@ namespace BetterLyrics.WinUI3
}
}
public void ToggleLockWindow()
public void RefreshLyricsWindowStatus()
{
var window = WindowHelper.GetWindowByWindowType<LyricsWindow>();
if (window == null) return;
if (IsLyricsWindowLocked)
{
DesktopModeHelper.SetClickThrough(window, false);
IsLyricsWindowLocked = false;
IsImmersiveMode = _settingsService.AppSettings.GeneralSettings.IsImmersiveMode;
}
else
{
DesktopModeHelper.SetClickThrough(window, true);
IsLyricsWindowLocked = true;
IsImmersiveMode = true;
}
UpdateDockOrDesktopWindow();
}
public void ToggleDesktopMode()
{
var window = WindowHelper.GetWindowByWindowType<LyricsWindow>();
if (window == null) return;
StopWatchWindowColorChange();
LiveStates.ToggleLyricsWindowMode(LyricsWindowMode.DesktopMode);
if (LiveStates.LyricsWindowMode == LyricsWindowMode.DesktopMode)
{
DesktopModeHelper.Enable(window);
StartWatchWindowColorChange();
if (_settingsService.AppSettings.DesktopModeSettings.AutoLockOnDesktopMode)
{
ToggleLockWindow();
}
SetDesktopModeTitleBarControlsStatus();
}
else
{
if (IsLyricsWindowLocked)
{
ToggleLockWindow();
}
DesktopModeHelper.Disable(window);
SetStandardModeTitleBarControlsStatus();
}
SetIsAlwaysOnTop();
}
public void ToggleDockMode()
{
var window = WindowHelper.GetWindowByWindowType<LyricsWindow>();
if (window == null) return;
StopWatchWindowColorChange();
LiveStates.ToggleLyricsWindowMode(LyricsWindowMode.DockMode);
if (LiveStates.LyricsWindowMode == LyricsWindowMode.DockMode)
{
window.Restore();
DockModeHelper.Enable(window, _dockMonitorDeviceName, _dockWindowHeight, _dockPlacement);
StartWatchWindowColorChange();
SetDockModeTitleBarControlsStatus();
}
else
{
DockModeHelper.Disable(window);
SetStandardModeTitleBarControlsStatus();
}
UpdateDockOrDesktopWindow();
SetIsAlwaysOnTop();
}
public void TogglePictureInPictureMode()
{
var window = WindowHelper.GetWindowByWindowType<LyricsWindow>();
if (window == null) return;
LiveStates.ToggleLyricsWindowMode(LyricsWindowMode.PictureInPictureMode);
if (LiveStates.LyricsWindowMode == LyricsWindowMode.PictureInPictureMode)
{
window.AppWindow.SetPresenter(AppWindowPresenterKind.CompactOverlay);
window.AppWindow.Move(AppSettings.PictureInPictureModeSettings.WindowPosition.ToPointInt32());
SetPIPModeTitleBarControlsStatus();
}
else
{
window.AppWindow.SetPresenter(AppWindowPresenterKind.Overlapped);
SetStandardModeTitleBarControlsStatus();
}
SetIsAlwaysOnTop();
}
public void SetIsAlwaysOnTop()
{
var window = WindowHelper.GetWindowByWindowType<LyricsWindow>();
if (window == null) return;
if (window.AppWindow.Presenter is OverlappedPresenter presenter)
{
presenter.IsAlwaysOnTop = _liveStatesService.LiveStates.IsAlwaysOnTop;
}
}
public void ToggleFullscreen()
{
var window = WindowHelper.GetWindowByWindowType<LyricsWindow>();
if (window == null) return;
switch (window.AppWindow.Presenter.Kind)
{
case AppWindowPresenterKind.FullScreen:
window.AppWindow.SetPresenter(AppWindowPresenterKind.Overlapped);
SetStandardModeTitleBarControlsStatus();
break;
case AppWindowPresenterKind.Overlapped:
window.AppWindow.SetPresenter(AppWindowPresenterKind.FullScreen);
SetFullscreenTitleBarControlsStatus();
break;
default:
break;
}
}
[RelayCommand]
private void OnImmersiveToggleButtonEnabledChanged()
{
_settingsService.AppSettings.GeneralSettings.IsImmersiveMode = IsImmersiveMode;
}
public void Receive(PropertyChangedMessage<DockPlacement> message)
{
if (message.Sender is DockModeSettings)
{
if (message.PropertyName == nameof(DockModeSettings.DockPlacement))
{
_dockPlacement = message.NewValue;
UpdateDockOrDesktopWindow();
}
}
}
public void Receive(PropertyChangedMessage<string> message)
{
if (message.Sender is DockModeSettings)
{
if (message.PropertyName == nameof(DockModeSettings.DockMonitorDeviceName))
{
_dockMonitorDeviceName = message.NewValue;
UpdateDockOrDesktopWindow();
}
}
_liveStatesService.RefreshLyricsWindowStatus();
}
public void Receive(PropertyChangedMessage<List<string>> message)
{
if (message.Sender is DesktopModeSettings)
if (message.Sender is GeneralSettings)
{
if (message.PropertyName == nameof(DesktopModeSettings.LockShortcut))
if (message.PropertyName == nameof(GeneralSettings.ClickThroughShortcut))
{
UpdateDesktopLockUnlockShortcut();
UpdateLyricsWindowClickThroughShortcut();
}
}
else if (message.Sender is DockModeSettings)
else if (message.Sender is GeneralSettings)
{
if (message.PropertyName == nameof(DockModeSettings.ToggleShortcut))
if (message.PropertyName == nameof(GeneralSettings.BorderlessShortcut))
{
UpdateDockToggleShortcut();
}
}
else if (message.Sender is PictureInPictureModeSettings)
{
if (message.PropertyName == nameof(PictureInPictureModeSettings.ToggleShortcut))
{
UpdatePictureInPictureToggleShortcut();
}
}
else if (message.Sender is DesktopModeSettings)
{
if (message.PropertyName == nameof(DesktopModeSettings.ToggleShortcut))
{
UpdateDesktopToggleShortcut();
UpdateLyricsWindowBorderlessShortcut();
}
}
else if (message.Sender is GeneralSettings)
@@ -596,6 +214,24 @@ namespace BetterLyrics.WinUI3
UpdateLyricsWindowShowHideShortcut();
}
}
else if (message.Sender is GeneralSettings)
{
if (message.PropertyName == nameof(GeneralSettings.LyricsWindowSwitchShortcut))
{
UpdateLyricsWindowSwitchShortcut();
}
}
}
public void Receive(PropertyChangedMessage<ElementTheme> message)
{
if (message.Sender is LyricsRendererViewModel)
{
if (message.PropertyName == nameof(LyricsRendererViewModel.ThemeTypeSent))
{
ThemeType = message.NewValue;
}
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More