Compare commits
133 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d25920c697 | ||
|
|
639c4171dd | ||
|
|
95a1d65c50 | ||
|
|
feb4f47db9 | ||
|
|
81f2c4e34a | ||
|
|
48176cce0f | ||
|
|
77d41c4813 | ||
|
|
8d1be745ac | ||
|
|
978702b6ae | ||
|
|
0e1f487ac1 | ||
|
|
3c8775d2cd | ||
|
|
7c39214f2d | ||
|
|
b7952f5eef | ||
|
|
8c0d3667e4 | ||
|
|
e1f900a9e6 | ||
|
|
212c1fbcdd | ||
|
|
2cb04fa1b7 | ||
|
|
8ab3a53a38 | ||
|
|
3b4d5b9668 | ||
|
|
2409165b91 | ||
|
|
fe1eb2882e | ||
|
|
51dd58fc74 | ||
|
|
0f5f663b32 | ||
|
|
4815c32dba | ||
|
|
3f5a0a0d73 | ||
|
|
1b34b28fbe | ||
|
|
fe4d67c1f1 | ||
|
|
1ae00257a1 | ||
|
|
814de1a4a5 | ||
|
|
28b568e7a4 | ||
|
|
786d23b320 | ||
|
|
a394527f80 | ||
|
|
80422376c3 | ||
|
|
5114c83843 | ||
|
|
835e0d34fc | ||
|
|
7ab833a53a | ||
|
|
d348a30237 | ||
|
|
d0b626c508 | ||
|
|
9debdc76f9 | ||
|
|
67a45e90fa | ||
|
|
b4c7655043 | ||
|
|
2adc2aced2 | ||
|
|
e638739638 | ||
|
|
c24213358e | ||
|
|
6e78f849c4 | ||
|
|
80444b69e0 | ||
|
|
78775e9bb3 | ||
|
|
78c81347c8 | ||
|
|
65941323eb | ||
|
|
aee79b9971 | ||
|
|
97df1c1891 | ||
|
|
8a831b17cc | ||
|
|
78076efe40 | ||
|
|
d0346bf422 | ||
|
|
7cb4172e84 | ||
|
|
1f2426f51b | ||
|
|
e122fdabe8 | ||
|
|
97078d966d | ||
|
|
c43b69b4cb | ||
|
|
94b22552e5 | ||
|
|
6deb16f6cb | ||
|
|
e467ab9c73 | ||
|
|
ea038c9c56 | ||
|
|
560250ad30 | ||
|
|
536acc69a5 | ||
|
|
0bbb379912 | ||
|
|
1f4d29e6f2 | ||
|
|
5d1d7476c9 | ||
|
|
e016baefe1 | ||
|
|
70b6194788 | ||
|
|
9f103b0ea3 | ||
|
|
2924140f95 | ||
|
|
3d3f168926 | ||
|
|
63b2285a36 | ||
|
|
780689fa05 | ||
|
|
01384717c4 | ||
|
|
e18d78170a | ||
|
|
023bf77afc | ||
|
|
2877ac2101 | ||
|
|
16d82109bb | ||
|
|
c703f04119 | ||
|
|
998853f9d2 | ||
|
|
f560735da0 | ||
|
|
ab9da73b49 | ||
|
|
dc364edf75 | ||
|
|
7fbc8fbfe7 | ||
|
|
4a00bb2ddf | ||
|
|
7472aa048f | ||
|
|
49b0f7a692 | ||
|
|
4d0602ebef | ||
|
|
626395d93a | ||
|
|
0ab5602569 | ||
|
|
37a7528762 | ||
|
|
3ca391a509 | ||
|
|
f5e542d2f3 | ||
|
|
107bdf8bee | ||
|
|
3e9e56f5cc | ||
|
|
b0fd43ead5 | ||
|
|
81c59495c0 | ||
|
|
7c5f1a804e | ||
|
|
13ee4227f7 | ||
|
|
c1360ac972 | ||
|
|
c72aa8a58f | ||
|
|
9545ed610b | ||
|
|
1c4515acb9 | ||
|
|
92a6fe46de | ||
|
|
2f9fa02214 | ||
|
|
c174363c07 | ||
|
|
8506062c9a | ||
|
|
52711cba1f | ||
|
|
7eda076920 | ||
|
|
282c2f5ac0 | ||
|
|
94e76a6ac9 | ||
|
|
516d388009 | ||
|
|
ad33eed57c | ||
|
|
64bf2dc3d9 | ||
|
|
b86e4a3d12 | ||
|
|
411506b9cd | ||
|
|
f681b43e96 | ||
|
|
133acf5592 | ||
|
|
cbaa81b9bb | ||
|
|
b834be49ce | ||
|
|
8abe6d7f01 | ||
|
|
8a73ba9e6a | ||
|
|
49a090b0c7 | ||
|
|
a47dd67056 | ||
|
|
900ecc9776 | ||
|
|
464742d7c5 | ||
|
|
5f3aad4e99 | ||
|
|
7b6eca6ff6 | ||
|
|
9fcb1ac869 | ||
|
|
74ebda2b6d | ||
|
|
e194dfaa70 |
2
.github/FUNDING.yml
vendored
@@ -12,4 +12,4 @@ lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cl
|
|||||||
polar: # Replace with a single Polar username
|
polar: # Replace with a single Polar username
|
||||||
buy_me_a_coffee: founchoo
|
buy_me_a_coffee: founchoo
|
||||||
thanks_dev: # Replace with a single thanks.dev username
|
thanks_dev: # Replace with a single thanks.dev username
|
||||||
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
custom: ['https://paypal.me/zhefangpay']
|
||||||
|
|||||||
@@ -1,150 +1,150 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
<PropertyGroup Condition="'$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' < '15.0'">
|
<PropertyGroup Condition="'$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' < '15.0'">
|
||||||
<VisualStudioVersion>15.0</VisualStudioVersion>
|
<VisualStudioVersion>15.0</VisualStudioVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup Label="ProjectConfigurations">
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
<ProjectConfiguration Include="Debug|x86">
|
<ProjectConfiguration Include="Debug|x86">
|
||||||
<Configuration>Debug</Configuration>
|
<Configuration>Debug</Configuration>
|
||||||
<Platform>x86</Platform>
|
<Platform>x86</Platform>
|
||||||
</ProjectConfiguration>
|
</ProjectConfiguration>
|
||||||
<ProjectConfiguration Include="Release|x86">
|
<ProjectConfiguration Include="Release|x86">
|
||||||
<Configuration>Release</Configuration>
|
<Configuration>Release</Configuration>
|
||||||
<Platform>x86</Platform>
|
<Platform>x86</Platform>
|
||||||
</ProjectConfiguration>
|
</ProjectConfiguration>
|
||||||
<ProjectConfiguration Include="Debug|x64">
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
<Configuration>Debug</Configuration>
|
<Configuration>Debug</Configuration>
|
||||||
<Platform>x64</Platform>
|
<Platform>x64</Platform>
|
||||||
</ProjectConfiguration>
|
</ProjectConfiguration>
|
||||||
<ProjectConfiguration Include="Release|x64">
|
<ProjectConfiguration Include="Release|x64">
|
||||||
<Configuration>Release</Configuration>
|
<Configuration>Release</Configuration>
|
||||||
<Platform>x64</Platform>
|
<Platform>x64</Platform>
|
||||||
</ProjectConfiguration>
|
</ProjectConfiguration>
|
||||||
<ProjectConfiguration Include="Debug|ARM64">
|
<ProjectConfiguration Include="Debug|ARM64">
|
||||||
<Configuration>Debug</Configuration>
|
<Configuration>Debug</Configuration>
|
||||||
<Platform>ARM64</Platform>
|
<Platform>ARM64</Platform>
|
||||||
</ProjectConfiguration>
|
</ProjectConfiguration>
|
||||||
<ProjectConfiguration Include="Release|ARM64">
|
<ProjectConfiguration Include="Release|ARM64">
|
||||||
<Configuration>Release</Configuration>
|
<Configuration>Release</Configuration>
|
||||||
<Platform>ARM64</Platform>
|
<Platform>ARM64</Platform>
|
||||||
</ProjectConfiguration>
|
</ProjectConfiguration>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<WapProjPath Condition="'$(WapProjPath)'==''">$(MSBuildExtensionsPath)\Microsoft\DesktopBridge\</WapProjPath>
|
<WapProjPath Condition="'$(WapProjPath)'==''">$(MSBuildExtensionsPath)\Microsoft\DesktopBridge\</WapProjPath>
|
||||||
<PathToXAMLWinRTImplementations>BetterLyrics.WinUI3\</PathToXAMLWinRTImplementations>
|
<PathToXAMLWinRTImplementations>BetterLyrics.WinUI3\</PathToXAMLWinRTImplementations>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<Import Project="$(WapProjPath)\Microsoft.DesktopBridge.props" />
|
<Import Project="$(WapProjPath)\Microsoft.DesktopBridge.props" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<ProjectGuid>6576cd19-ef92-4099-b37d-e2d8ebdb6bf5</ProjectGuid>
|
<ProjectGuid>6576cd19-ef92-4099-b37d-e2d8ebdb6bf5</ProjectGuid>
|
||||||
<TargetPlatformVersion>10.0.26100.0</TargetPlatformVersion>
|
<TargetPlatformVersion>10.0.26100.0</TargetPlatformVersion>
|
||||||
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
|
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
|
||||||
<AssetTargetFallback>net8.0-windows$(TargetPlatformVersion);$(AssetTargetFallback)</AssetTargetFallback>
|
<AssetTargetFallback>net8.0-windows$(TargetPlatformVersion);$(AssetTargetFallback)</AssetTargetFallback>
|
||||||
<DefaultLanguage>zh-CN</DefaultLanguage>
|
<DefaultLanguage>zh-CN</DefaultLanguage>
|
||||||
<AppxPackageSigningEnabled>True</AppxPackageSigningEnabled>
|
<AppxPackageSigningEnabled>True</AppxPackageSigningEnabled>
|
||||||
<EntryPointProjectUniqueName>..\BetterLyrics.WinUI3\BetterLyrics.WinUI3.csproj</EntryPointProjectUniqueName>
|
<EntryPointProjectUniqueName>..\BetterLyrics.WinUI3\BetterLyrics.WinUI3.csproj</EntryPointProjectUniqueName>
|
||||||
<GenerateAppInstallerFile>False</GenerateAppInstallerFile>
|
<GenerateAppInstallerFile>False</GenerateAppInstallerFile>
|
||||||
<AppxPackageSigningTimestampDigestAlgorithm>SHA256</AppxPackageSigningTimestampDigestAlgorithm>
|
<AppxPackageSigningTimestampDigestAlgorithm>SHA256</AppxPackageSigningTimestampDigestAlgorithm>
|
||||||
<AppxAutoIncrementPackageRevision>False</AppxAutoIncrementPackageRevision>
|
<AppxAutoIncrementPackageRevision>False</AppxAutoIncrementPackageRevision>
|
||||||
<GenerateTestArtifacts>True</GenerateTestArtifacts>
|
<GenerateTestArtifacts>True</GenerateTestArtifacts>
|
||||||
<AppxBundlePlatforms>x86|x64</AppxBundlePlatforms>
|
<AppxBundlePlatforms>x86|x64</AppxBundlePlatforms>
|
||||||
<GenerateTemporaryStoreCertificate>True</GenerateTemporaryStoreCertificate>
|
<GenerateTemporaryStoreCertificate>True</GenerateTemporaryStoreCertificate>
|
||||||
<HoursBetweenUpdateChecks>0</HoursBetweenUpdateChecks>
|
<HoursBetweenUpdateChecks>0</HoursBetweenUpdateChecks>
|
||||||
<PackageCertificateKeyFile>BetterLyrics.WinUI3 %28Package%29_TemporaryKey.pfx</PackageCertificateKeyFile>
|
<PackageCertificateKeyFile>BetterLyrics.WinUI3 %28Package%29_TemporaryKey.pfx</PackageCertificateKeyFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
<AppxBundle>Always</AppxBundle>
|
<AppxBundle>Always</AppxBundle>
|
||||||
<DefaultLanguage>en-US</DefaultLanguage>
|
<DefaultLanguage>en-US</DefaultLanguage>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x86'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x86'">
|
||||||
<AppxBundle>Always</AppxBundle>
|
<AppxBundle>Always</AppxBundle>
|
||||||
<DefaultLanguage>en-US</DefaultLanguage>
|
<DefaultLanguage>en-US</DefaultLanguage>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x86'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x86'">
|
||||||
<AppxBundle>Always</AppxBundle>
|
<AppxBundle>Always</AppxBundle>
|
||||||
<DefaultLanguage>en-US</DefaultLanguage>
|
<DefaultLanguage>en-US</DefaultLanguage>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
<AppxBundle>Always</AppxBundle>
|
<AppxBundle>Always</AppxBundle>
|
||||||
<DefaultLanguage>en-US</DefaultLanguage>
|
<DefaultLanguage>en-US</DefaultLanguage>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
|
||||||
<AppxBundle>Always</AppxBundle>
|
<AppxBundle>Always</AppxBundle>
|
||||||
<DefaultLanguage>en-US</DefaultLanguage>
|
<DefaultLanguage>en-US</DefaultLanguage>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
|
||||||
<AppxBundle>Always</AppxBundle>
|
<AppxBundle>Always</AppxBundle>
|
||||||
<DefaultLanguage>en-US</DefaultLanguage>
|
<DefaultLanguage>en-US</DefaultLanguage>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<AppxManifest Include="Package.appxmanifest">
|
<AppxManifest Include="Package.appxmanifest">
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
</AppxManifest>
|
</AppxManifest>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="BetterLyrics.WinUI3 %28Package%29_TemporaryKey.pfx" />
|
<None Include="BetterLyrics.WinUI3 %28Package%29_TemporaryKey.pfx" />
|
||||||
<Content Include="Images\LargeTile.scale-100.png" />
|
<Content Include="Images\LargeTile.scale-100.png" />
|
||||||
<Content Include="Images\LargeTile.scale-125.png" />
|
<Content Include="Images\LargeTile.scale-125.png" />
|
||||||
<Content Include="Images\LargeTile.scale-150.png" />
|
<Content Include="Images\LargeTile.scale-150.png" />
|
||||||
<Content Include="Images\LargeTile.scale-200.png" />
|
<Content Include="Images\LargeTile.scale-200.png" />
|
||||||
<Content Include="Images\LargeTile.scale-400.png" />
|
<Content Include="Images\LargeTile.scale-400.png" />
|
||||||
<Content Include="Images\SmallTile.scale-100.png" />
|
<Content Include="Images\SmallTile.scale-100.png" />
|
||||||
<Content Include="Images\SmallTile.scale-125.png" />
|
<Content Include="Images\SmallTile.scale-125.png" />
|
||||||
<Content Include="Images\SmallTile.scale-150.png" />
|
<Content Include="Images\SmallTile.scale-150.png" />
|
||||||
<Content Include="Images\SmallTile.scale-200.png" />
|
<Content Include="Images\SmallTile.scale-200.png" />
|
||||||
<Content Include="Images\SmallTile.scale-400.png" />
|
<Content Include="Images\SmallTile.scale-400.png" />
|
||||||
<Content Include="Images\SplashScreen.scale-100.png" />
|
<Content Include="Images\SplashScreen.scale-100.png" />
|
||||||
<Content Include="Images\SplashScreen.scale-125.png" />
|
<Content Include="Images\SplashScreen.scale-125.png" />
|
||||||
<Content Include="Images\SplashScreen.scale-150.png" />
|
<Content Include="Images\SplashScreen.scale-150.png" />
|
||||||
<Content Include="Images\SplashScreen.scale-200.png" />
|
<Content Include="Images\SplashScreen.scale-200.png" />
|
||||||
<Content Include="Images\LockScreenLogo.scale-200.png" />
|
<Content Include="Images\LockScreenLogo.scale-200.png" />
|
||||||
<Content Include="Images\SplashScreen.scale-400.png" />
|
<Content Include="Images\SplashScreen.scale-400.png" />
|
||||||
<Content Include="Images\Square150x150Logo.scale-100.png" />
|
<Content Include="Images\Square150x150Logo.scale-100.png" />
|
||||||
<Content Include="Images\Square150x150Logo.scale-125.png" />
|
<Content Include="Images\Square150x150Logo.scale-125.png" />
|
||||||
<Content Include="Images\Square150x150Logo.scale-150.png" />
|
<Content Include="Images\Square150x150Logo.scale-150.png" />
|
||||||
<Content Include="Images\Square150x150Logo.scale-200.png" />
|
<Content Include="Images\Square150x150Logo.scale-200.png" />
|
||||||
<Content Include="Images\Square150x150Logo.scale-400.png" />
|
<Content Include="Images\Square150x150Logo.scale-400.png" />
|
||||||
<Content Include="Images\Square44x44Logo.altform-lightunplated_targetsize-16.png" />
|
<Content Include="Images\Square44x44Logo.altform-lightunplated_targetsize-16.png" />
|
||||||
<Content Include="Images\Square44x44Logo.altform-lightunplated_targetsize-24.png" />
|
<Content Include="Images\Square44x44Logo.altform-lightunplated_targetsize-24.png" />
|
||||||
<Content Include="Images\Square44x44Logo.altform-lightunplated_targetsize-256.png" />
|
<Content Include="Images\Square44x44Logo.altform-lightunplated_targetsize-256.png" />
|
||||||
<Content Include="Images\Square44x44Logo.altform-lightunplated_targetsize-32.png" />
|
<Content Include="Images\Square44x44Logo.altform-lightunplated_targetsize-32.png" />
|
||||||
<Content Include="Images\Square44x44Logo.altform-lightunplated_targetsize-48.png" />
|
<Content Include="Images\Square44x44Logo.altform-lightunplated_targetsize-48.png" />
|
||||||
<Content Include="Images\Square44x44Logo.altform-unplated_targetsize-16.png" />
|
<Content Include="Images\Square44x44Logo.altform-unplated_targetsize-16.png" />
|
||||||
<Content Include="Images\Square44x44Logo.altform-unplated_targetsize-256.png" />
|
<Content Include="Images\Square44x44Logo.altform-unplated_targetsize-256.png" />
|
||||||
<Content Include="Images\Square44x44Logo.altform-unplated_targetsize-32.png" />
|
<Content Include="Images\Square44x44Logo.altform-unplated_targetsize-32.png" />
|
||||||
<Content Include="Images\Square44x44Logo.altform-unplated_targetsize-48.png" />
|
<Content Include="Images\Square44x44Logo.altform-unplated_targetsize-48.png" />
|
||||||
<Content Include="Images\Square44x44Logo.scale-100.png" />
|
<Content Include="Images\Square44x44Logo.scale-100.png" />
|
||||||
<Content Include="Images\Square44x44Logo.scale-125.png" />
|
<Content Include="Images\Square44x44Logo.scale-125.png" />
|
||||||
<Content Include="Images\Square44x44Logo.scale-150.png" />
|
<Content Include="Images\Square44x44Logo.scale-150.png" />
|
||||||
<Content Include="Images\Square44x44Logo.scale-200.png" />
|
<Content Include="Images\Square44x44Logo.scale-200.png" />
|
||||||
<Content Include="Images\Square44x44Logo.scale-400.png" />
|
<Content Include="Images\Square44x44Logo.scale-400.png" />
|
||||||
<Content Include="Images\Square44x44Logo.targetsize-16.png" />
|
<Content Include="Images\Square44x44Logo.targetsize-16.png" />
|
||||||
<Content Include="Images\Square44x44Logo.targetsize-24.png" />
|
<Content Include="Images\Square44x44Logo.targetsize-24.png" />
|
||||||
<Content Include="Images\Square44x44Logo.targetsize-24_altform-unplated.png" />
|
<Content Include="Images\Square44x44Logo.targetsize-24_altform-unplated.png" />
|
||||||
<Content Include="Images\Square44x44Logo.targetsize-256.png" />
|
<Content Include="Images\Square44x44Logo.targetsize-256.png" />
|
||||||
<Content Include="Images\Square44x44Logo.targetsize-32.png" />
|
<Content Include="Images\Square44x44Logo.targetsize-32.png" />
|
||||||
<Content Include="Images\Square44x44Logo.targetsize-48.png" />
|
<Content Include="Images\Square44x44Logo.targetsize-48.png" />
|
||||||
<Content Include="Images\StoreLogo.scale-100.png" />
|
<Content Include="Images\StoreLogo.scale-100.png" />
|
||||||
<Content Include="Images\StoreLogo.scale-125.png" />
|
<Content Include="Images\StoreLogo.scale-125.png" />
|
||||||
<Content Include="Images\StoreLogo.scale-150.png" />
|
<Content Include="Images\StoreLogo.scale-150.png" />
|
||||||
<Content Include="Images\StoreLogo.scale-200.png" />
|
<Content Include="Images\StoreLogo.scale-200.png" />
|
||||||
<Content Include="Images\StoreLogo.scale-400.png" />
|
<Content Include="Images\StoreLogo.scale-400.png" />
|
||||||
<Content Include="Images\Wide310x150Logo.scale-100.png" />
|
<Content Include="Images\Wide310x150Logo.scale-100.png" />
|
||||||
<Content Include="Images\Wide310x150Logo.scale-125.png" />
|
<Content Include="Images\Wide310x150Logo.scale-125.png" />
|
||||||
<Content Include="Images\Wide310x150Logo.scale-150.png" />
|
<Content Include="Images\Wide310x150Logo.scale-150.png" />
|
||||||
<Content Include="Images\Wide310x150Logo.scale-200.png" />
|
<Content Include="Images\Wide310x150Logo.scale-200.png" />
|
||||||
<Content Include="Images\Wide310x150Logo.scale-400.png" />
|
<Content Include="Images\Wide310x150Logo.scale-400.png" />
|
||||||
<None Include="Package.StoreAssociation.xml" />
|
<None Include="Package.StoreAssociation.xml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\BetterLyrics.WinUI3\BetterLyrics.WinUI3.csproj">
|
<ProjectReference Include="..\BetterLyrics.WinUI3\BetterLyrics.WinUI3.csproj">
|
||||||
<EnableMsixTooling>true</EnableMsixTooling>
|
<EnableMsixTooling>true</EnableMsixTooling>
|
||||||
<SkipGetTargetFrameworkProperties>True</SkipGetTargetFrameworkProperties>
|
<SkipGetTargetFrameworkProperties>True</SkipGetTargetFrameworkProperties>
|
||||||
<PublishProfile>Properties\PublishProfiles\win-$(Platform).pubxml</PublishProfile>
|
<PublishProfile>Properties\PublishProfiles\win-$(Platform).pubxml</PublishProfile>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.4654" />
|
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.6584" />
|
||||||
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.7.250606001" />
|
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.8.251003001" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(WapProjPath)\Microsoft.DesktopBridge.targets" />
|
<Import Project="$(WapProjPath)\Microsoft.DesktopBridge.targets" />
|
||||||
</Project>
|
</Project>
|
||||||
@@ -12,13 +12,13 @@
|
|||||||
<Identity
|
<Identity
|
||||||
Name="37412.BetterLyrics"
|
Name="37412.BetterLyrics"
|
||||||
Publisher="CN=E1428B0E-DC1D-4EA4-ACB1-4556569D5BA9"
|
Publisher="CN=E1428B0E-DC1D-4EA4-ACB1-4556569D5BA9"
|
||||||
Version="1.0.46.0" />
|
Version="1.0.85.0" />
|
||||||
|
|
||||||
<mp:PhoneIdentity PhoneProductId="ca4a4830-fc19-40d9-b823-53e2bff3d816" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
|
<mp:PhoneIdentity PhoneProductId="ca4a4830-fc19-40d9-b823-53e2bff3d816" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
|
||||||
|
|
||||||
<Properties>
|
<Properties>
|
||||||
<DisplayName>BetterLyrics</DisplayName>
|
<DisplayName>BetterLyrics</DisplayName>
|
||||||
<PublisherDisplayName>founchoo</PublisherDisplayName>
|
<PublisherDisplayName>Zhe Fang</PublisherDisplayName>
|
||||||
<Logo>Images\StoreLogo.png</Logo>
|
<Logo>Images\StoreLogo.png</Logo>
|
||||||
</Properties>
|
</Properties>
|
||||||
|
|
||||||
|
|||||||
@@ -10,10 +10,10 @@
|
|||||||
<Application.Resources>
|
<Application.Resources>
|
||||||
<ResourceDictionary>
|
<ResourceDictionary>
|
||||||
<ResourceDictionary.MergedDictionaries>
|
<ResourceDictionary.MergedDictionaries>
|
||||||
|
<!-- Merged dictionaries here -->
|
||||||
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
|
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
|
||||||
<ResourceDictionary Source="ms-appx:///CommunityToolkit.WinUI.Controls.SettingsControls/SettingsExpander/SettingsExpander.xaml" />
|
<ResourceDictionary Source="ms-appx:///CommunityToolkit.WinUI.Controls.SettingsControls/SettingsExpander/SettingsExpander.xaml" />
|
||||||
<ResourceDictionary Source="ms-appx:///CommunityToolkit.WinUI.Controls.Segmented/Segmented/Segmented.xaml" />
|
<ResourceDictionary Source="ms-appx:///CommunityToolkit.WinUI.Controls.Segmented/Segmented/Segmented.xaml" />
|
||||||
<!-- Other merged dictionaries here -->
|
|
||||||
</ResourceDictionary.MergedDictionaries>
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
|
||||||
<!-- Theme -->
|
<!-- Theme -->
|
||||||
@@ -51,8 +51,15 @@
|
|||||||
<converter:TranslationSearchProviderToDisplayNameConverter x:Key="TranslationSearchProviderToDisplayNameConverter" />
|
<converter:TranslationSearchProviderToDisplayNameConverter x:Key="TranslationSearchProviderToDisplayNameConverter" />
|
||||||
<converter:AlbumArtSearchProviderToDisplayNameConverter x:Key="AlbumArtSearchProviderToDisplayNameConverter" />
|
<converter:AlbumArtSearchProviderToDisplayNameConverter x:Key="AlbumArtSearchProviderToDisplayNameConverter" />
|
||||||
<converter:SecondsToFormattedTimeConverter x:Key="SecondsToFormattedTimeConverter" />
|
<converter:SecondsToFormattedTimeConverter x:Key="SecondsToFormattedTimeConverter" />
|
||||||
|
<converter:MillisecondsToFormattedTimeConverter x:Key="MillisecondsToFormattedTimeConverter" />
|
||||||
<converter:MediaSourceProviderToLogoUriConverter x:Key="MediaSourceProviderToLogoUriConverter" />
|
<converter:MediaSourceProviderToLogoUriConverter x:Key="MediaSourceProviderToLogoUriConverter" />
|
||||||
<converter:MediaSourceProviderToDisplayedNameConverter x:Key="MediaSourceProviderToDisplayedNameConverter" />
|
<converter:MediaSourceProviderToDisplayedNameConverter x:Key="MediaSourceProviderToDisplayedNameConverter" />
|
||||||
|
<converter:FPSToTimeSpanConverter x:Key="FPSToTimeSpanConverter" />
|
||||||
|
<converter:ShortcutToStringConverter x:Key="ShortcutToStringConverter" />
|
||||||
|
<converter:BoolNegationToVisibilityConverter x:Key="BoolNegationToVisibilityConverter" />
|
||||||
|
<converter:BoolToOpacityConverter x:Key="BoolToOpacityConverter" />
|
||||||
|
<converter:RectToMarginConverter x:Key="RectToMarginConverter" />
|
||||||
|
|
||||||
<converters:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
|
<converters:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
|
||||||
<converters:BoolNegationConverter x:Key="BoolNegationConverter" />
|
<converters:BoolNegationConverter x:Key="BoolNegationConverter" />
|
||||||
<converters:ColorToDisplayNameConverter x:Key="ColorToDisplayNameConverter" />
|
<converters:ColorToDisplayNameConverter x:Key="ColorToDisplayNameConverter" />
|
||||||
@@ -308,6 +315,18 @@
|
|||||||
<Setter Property="Padding" Value="0,0,0,36" />
|
<Setter Property="Padding" Value="0,0,0,36" />
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
|
<Style
|
||||||
|
x:Key="FlyoutPageStyle"
|
||||||
|
BasedOn="{StaticResource DefaultFlyoutPresenterStyle}"
|
||||||
|
TargetType="FlyoutPresenter">
|
||||||
|
<Setter Property="Opacity" Value="0.9" />
|
||||||
|
<Setter Property="MinWidth" Value="850" />
|
||||||
|
<Setter Property="Padding" Value="0" />
|
||||||
|
<Setter Property="ScrollViewer.VerticalScrollMode" Value="Disabled" />
|
||||||
|
<Setter Property="ScrollViewer.HorizontalScrollMode" Value="Disabled" />
|
||||||
|
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Hidden" />
|
||||||
|
</Style>
|
||||||
|
|
||||||
<StaticResource x:Key="ToggleButtonBackgroundChecked" ResourceKey="TextFillColorPrimaryBrush" />
|
<StaticResource x:Key="ToggleButtonBackgroundChecked" ResourceKey="TextFillColorPrimaryBrush" />
|
||||||
<StaticResource x:Key="ToggleButtonBackgroundCheckedPointerOver" ResourceKey="TextFillColorPrimaryBrush" />
|
<StaticResource x:Key="ToggleButtonBackgroundCheckedPointerOver" ResourceKey="TextFillColorPrimaryBrush" />
|
||||||
<StaticResource x:Key="ToggleButtonBackgroundCheckedPressed" ResourceKey="TextFillColorPrimaryBrush" />
|
<StaticResource x:Key="ToggleButtonBackgroundCheckedPressed" ResourceKey="TextFillColorPrimaryBrush" />
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using BetterLyrics.WinUI3.Services;
|
|||||||
using BetterLyrics.WinUI3.Services.AlbumArtSearchService;
|
using BetterLyrics.WinUI3.Services.AlbumArtSearchService;
|
||||||
using BetterLyrics.WinUI3.Services.LastFMService;
|
using BetterLyrics.WinUI3.Services.LastFMService;
|
||||||
using BetterLyrics.WinUI3.Services.LibWatcherService;
|
using BetterLyrics.WinUI3.Services.LibWatcherService;
|
||||||
|
using BetterLyrics.WinUI3.Services.LiveStatesService;
|
||||||
using BetterLyrics.WinUI3.Services.LyricsSearchService;
|
using BetterLyrics.WinUI3.Services.LyricsSearchService;
|
||||||
using BetterLyrics.WinUI3.Services.MediaSessionsService;
|
using BetterLyrics.WinUI3.Services.MediaSessionsService;
|
||||||
using BetterLyrics.WinUI3.Services.SettingsService;
|
using BetterLyrics.WinUI3.Services.SettingsService;
|
||||||
@@ -83,14 +84,7 @@ namespace BetterLyrics.WinUI3
|
|||||||
|
|
||||||
protected override void OnLaunched(LaunchActivatedEventArgs args)
|
protected override void OnLaunched(LaunchActivatedEventArgs args)
|
||||||
{
|
{
|
||||||
WindowHelper.OpenWindow<LyricsWindow>();
|
WindowHelper.OpenOrShowWindow<LyricsWindow>();
|
||||||
|
|
||||||
var lyricsWindow = WindowHelper.GetWindowByWindowType<LyricsWindow>();
|
|
||||||
if (lyricsWindow != null)
|
|
||||||
{
|
|
||||||
lyricsWindow.ViewModel.InitLockHotKey();
|
|
||||||
lyricsWindow.AutoSelectLyricsMode();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ConfigureServices()
|
private static void ConfigureServices()
|
||||||
@@ -109,6 +103,7 @@ namespace BetterLyrics.WinUI3
|
|||||||
loggingBuilder.AddSerilog();
|
loggingBuilder.AddSerilog();
|
||||||
})
|
})
|
||||||
// Services
|
// Services
|
||||||
|
.AddSingleton<ILiveStatesService, LiveStatesService>()
|
||||||
.AddSingleton<ISettingsService, SettingsService>()
|
.AddSingleton<ISettingsService, SettingsService>()
|
||||||
.AddSingleton<IMediaSessionsService, MediaSessionsService>()
|
.AddSingleton<IMediaSessionsService, MediaSessionsService>()
|
||||||
.AddSingleton<IAlbumArtSearchService, AlbumArtSearchService>()
|
.AddSingleton<IAlbumArtSearchService, AlbumArtSearchService>()
|
||||||
@@ -118,11 +113,12 @@ namespace BetterLyrics.WinUI3
|
|||||||
.AddSingleton<ILastFMService, LastFMService>()
|
.AddSingleton<ILastFMService, LastFMService>()
|
||||||
// ViewModels
|
// ViewModels
|
||||||
.AddSingleton<AppSettingsControlViewModel>()
|
.AddSingleton<AppSettingsControlViewModel>()
|
||||||
.AddSingleton<LyricsBackgroundSettingsControlViewModel>()
|
|
||||||
.AddSingleton<AlbumArtLayoutSettingsControlViewModel>()
|
|
||||||
.AddSingleton<PlaybackSettingsControlViewModel>()
|
.AddSingleton<PlaybackSettingsControlViewModel>()
|
||||||
.AddSingleton<MediaSettingsControlViewModel>()
|
.AddSingleton<MediaSettingsControlViewModel>()
|
||||||
.AddSingleton<AllLyricsSettingsControlViewModel>()
|
.AddSingleton<LyricsSearchControlViewModel>()
|
||||||
|
.AddSingleton<LyricsWindowSettingsControlViewModel>()
|
||||||
|
.AddSingleton<LyricsWindowSwitchControlViewModel>()
|
||||||
|
.AddSingleton<LyricsWindowSwitchWindowViewModel>()
|
||||||
.AddSingleton<LyricsWindowViewModel>()
|
.AddSingleton<LyricsWindowViewModel>()
|
||||||
.AddSingleton<SettingsWindowViewModel>()
|
.AddSingleton<SettingsWindowViewModel>()
|
||||||
.AddSingleton<SystemTrayViewModel>()
|
.AddSingleton<SystemTrayViewModel>()
|
||||||
|
|||||||
BIN
BetterLyrics.WinUI3/BetterLyrics.WinUI3/Assets/Alipay.jpg
Normal file
|
After Width: | Height: | Size: 140 KiB |
BIN
BetterLyrics.WinUI3/BetterLyrics.WinUI3/Assets/Cover.jpg
Normal file
|
After Width: | Height: | Size: 84 KiB |
|
Before Width: | Height: | Size: 14 KiB |
BIN
BetterLyrics.WinUI3/BetterLyrics.WinUI3/Assets/Empty.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
BetterLyrics.WinUI3/BetterLyrics.WinUI3/Assets/Listen1.png
Normal file
|
After Width: | Height: | Size: 879 B |
BIN
BetterLyrics.WinUI3/BetterLyrics.WinUI3/Assets/MoeKoeMusic.png
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
BIN
BetterLyrics.WinUI3/BetterLyrics.WinUI3/Assets/Page.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 166 KiB |
|
After Width: | Height: | Size: 8.9 KiB |
|
Before Width: | Height: | Size: 192 KiB |
BIN
BetterLyrics.WinUI3/BetterLyrics.WinUI3/Assets/WeChatReward.png
Normal file
|
After Width: | Height: | Size: 209 KiB |
BIN
BetterLyrics.WinUI3/BetterLyrics.WinUI3/Assets/effect.bin
Normal file
@@ -20,17 +20,23 @@
|
|||||||
<PRIResource Remove="ViewModels\Lyrics\**" />
|
<PRIResource Remove="ViewModels\Lyrics\**" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<None Remove="Assets\effect.bin" />
|
||||||
<None Remove="Assets\Segoe Fluent Icons.ttf" />
|
<None Remove="Assets\Segoe Fluent Icons.ttf" />
|
||||||
<None Remove="Assets\Wiki82.profile.xml" />
|
<None Remove="Assets\Wiki82.profile.xml" />
|
||||||
<None Remove="Controls\AlbumArtLayoutSettingsControl.xaml" />
|
<None Remove="Controls\AlbumArtLayoutSettingsControl.xaml" />
|
||||||
<None Remove="Controls\AllLyricsSettingsControl.xaml" />
|
|
||||||
<None Remove="Controls\AppSettingsControl.xaml" />
|
<None Remove="Controls\AppSettingsControl.xaml" />
|
||||||
|
<None Remove="Controls\DemoWindowGrid.xaml" />
|
||||||
<None Remove="Controls\ExtendedSlider.xaml" />
|
<None Remove="Controls\ExtendedSlider.xaml" />
|
||||||
<None Remove="Controls\LyricsBavkgroundSettingsControl.xaml" />
|
<None Remove="Controls\LyricsSearchControl.xaml" />
|
||||||
<None Remove="Controls\LyricsSettingsControl.xaml" />
|
<None Remove="Controls\LyricsSettingsControl.xaml" />
|
||||||
|
<None Remove="Controls\LyricsWindowSettingsControl.xaml" />
|
||||||
|
<None Remove="Controls\LyricsWindowSwitchControl.xaml" />
|
||||||
<None Remove="Controls\MediaSettingsControl.xaml" />
|
<None Remove="Controls\MediaSettingsControl.xaml" />
|
||||||
<None Remove="Controls\PlaybackSettingsControl.xaml" />
|
<None Remove="Controls\PlaybackSettingsControl.xaml" />
|
||||||
|
<None Remove="Controls\ShortcutTextBox.xaml" />
|
||||||
<None Remove="Controls\SystemTray.xaml" />
|
<None Remove="Controls\SystemTray.xaml" />
|
||||||
|
<None Remove="Views\LyricsSearchWindow.xaml" />
|
||||||
|
<None Remove="Views\LyricsWindowSwitchWindow.xaml" />
|
||||||
<None Remove="Views\MusicGalleryPage.xaml" />
|
<None Remove="Views\MusicGalleryPage.xaml" />
|
||||||
<None Remove="Views\MusicGalleryWindow.xaml" />
|
<None Remove="Views\MusicGalleryWindow.xaml" />
|
||||||
<None Remove="Views\SettingsWindow.xaml" />
|
<None Remove="Views\SettingsWindow.xaml" />
|
||||||
@@ -43,7 +49,6 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="3v.EvtSource" Version="2.0.0" />
|
<PackageReference Include="3v.EvtSource" Version="2.0.0" />
|
||||||
<PackageReference Include="ColorThief.ImageSharp" Version="1.0.0" />
|
|
||||||
<PackageReference Include="CommunityToolkit.Labs.WinUI.MarqueeText" Version="0.1.230830" />
|
<PackageReference Include="CommunityToolkit.Labs.WinUI.MarqueeText" Version="0.1.230830" />
|
||||||
<PackageReference Include="CommunityToolkit.Labs.WinUI.OpacityMaskView" Version="0.1.250703-build.2173" />
|
<PackageReference Include="CommunityToolkit.Labs.WinUI.OpacityMaskView" Version="0.1.250703-build.2173" />
|
||||||
<PackageReference Include="CommunityToolkit.Labs.WinUI.Shimmer" Version="0.1.250703-build.2173" />
|
<PackageReference Include="CommunityToolkit.Labs.WinUI.Shimmer" Version="0.1.250703-build.2173" />
|
||||||
@@ -58,38 +63,39 @@
|
|||||||
<PackageReference Include="CommunityToolkit.WinUI.Extensions" Version="8.2.250402" />
|
<PackageReference Include="CommunityToolkit.WinUI.Extensions" Version="8.2.250402" />
|
||||||
<PackageReference Include="CommunityToolkit.WinUI.Helpers" Version="8.2.250402" />
|
<PackageReference Include="CommunityToolkit.WinUI.Helpers" Version="8.2.250402" />
|
||||||
<PackageReference Include="CommunityToolkit.WinUI.Media" Version="8.2.250402" />
|
<PackageReference Include="CommunityToolkit.WinUI.Media" Version="8.2.250402" />
|
||||||
|
<PackageReference Include="csharp-pinyin" Version="1.0.1" />
|
||||||
<PackageReference Include="Dubya.WindowsMediaController" Version="2.5.5" />
|
<PackageReference Include="Dubya.WindowsMediaController" Version="2.5.5" />
|
||||||
<PackageReference Include="H.NotifyIcon.WinUI" Version="2.3.0" />
|
<PackageReference Include="H.NotifyIcon.WinUI" Version="2.3.2" />
|
||||||
|
<PackageReference Include="Hqub.Last.fm" Version="2.5.1" />
|
||||||
<PackageReference Include="Lyricify.Lyrics.Helper-NativeAot" Version="0.1.4-alpha.5" />
|
<PackageReference Include="Lyricify.Lyrics.Helper-NativeAot" Version="0.1.4-alpha.5" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.8" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.10" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.8" />
|
<PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.10" />
|
||||||
<PackageReference Include="Microsoft.Graphics.Win2D" Version="1.3.2" />
|
<PackageReference Include="Microsoft.Graphics.Win2D" Version="1.3.2" />
|
||||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.4654" />
|
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.6584" />
|
||||||
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.7.250606001" />
|
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.8.251003001" />
|
||||||
|
<PackageReference Include="NAudio.Wasapi" Version="2.2.1" />
|
||||||
<PackageReference Include="Nito.AsyncEx" Version="5.1.2" />
|
<PackageReference Include="Nito.AsyncEx" Version="5.1.2" />
|
||||||
<PackageReference Include="Nito.AsyncEx.Tasks" Version="5.1.2" />
|
<PackageReference Include="Nito.AsyncEx.Tasks" Version="5.1.2" />
|
||||||
<PackageReference Include="NTextCat" Version="0.3.65" />
|
<PackageReference Include="NTextCat" Version="0.3.65" />
|
||||||
|
<PackageReference Include="RomajiConverter.Core" Version="1.0.9" />
|
||||||
<PackageReference Include="Serilog.Extensions.Logging" Version="9.0.3-dev-02320" />
|
<PackageReference Include="Serilog.Extensions.Logging" Version="9.0.3-dev-02320" />
|
||||||
<PackageReference Include="Serilog.Sinks.File" Version="7.0.0" />
|
<PackageReference Include="Serilog.Sinks.File" Version="7.0.0" />
|
||||||
<PackageReference Include="ShadowViewer.Controls.Notification" Version="1.2.1" />
|
<PackageReference Include="ShadowViewer.Controls.Notification" Version="1.2.1" />
|
||||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.11" />
|
<PackageReference Include="System.Drawing.Common" Version="9.0.10" />
|
||||||
<PackageReference Include="System.Drawing.Common" Version="9.0.8" />
|
<PackageReference Include="System.Text.Encoding.CodePages" Version="9.0.10" />
|
||||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="9.0.8" />
|
|
||||||
<PackageReference Include="TagLibSharp" Version="2.3.0" />
|
<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="Ude.NetStandard" Version="1.2.0" />
|
||||||
<PackageReference Include="Vanara.PInvoke.CoreAudio" Version="4.1.6" />
|
<PackageReference Include="Vanara.PInvoke.CoreAudio" Version="4.2.1" />
|
||||||
<PackageReference Include="Vanara.PInvoke.DwmApi" Version="4.1.6" />
|
<PackageReference Include="Vanara.PInvoke.DwmApi" Version="4.2.1" />
|
||||||
<PackageReference Include="Vanara.PInvoke.Gdi32" Version="4.1.6" />
|
<PackageReference Include="Vanara.PInvoke.Gdi32" Version="4.2.1" />
|
||||||
<PackageReference Include="Vanara.PInvoke.Shell32" Version="4.1.6" />
|
<PackageReference Include="Vanara.PInvoke.Shell32" Version="4.2.1" />
|
||||||
<PackageReference Include="Vanara.PInvoke.User32" Version="4.1.6" />
|
<PackageReference Include="Vanara.PInvoke.User32" Version="4.2.1" />
|
||||||
<PackageReference Include="WinUIEx" Version="2.6.0" />
|
<PackageReference Include="WinUIEx" Version="2.9.0" />
|
||||||
<PackageReference Include="z440.atl.core" Version="7.2.0" />
|
<PackageReference Include="z440.atl.core" Version="7.5.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="Hqub.Lastfm">
|
<ProjectReference Include="..\..\ColorThief.WinUI3\ColorThief.WinUI3.csproj" />
|
||||||
<HintPath>..\..\..\Last.fm\src\Hqub.Lastfm\bin\Release\netstandard2.0\Hqub.Lastfm.dll</HintPath>
|
<ProjectReference Include="..\..\Impressionist\Impressionist\Impressionist.csproj" />
|
||||||
</Reference>
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Page Update="Rendering\InAppLyricsRenderer.xaml">
|
<Page Update="Rendering\InAppLyricsRenderer.xaml">
|
||||||
@@ -115,10 +121,13 @@
|
|||||||
<Content Update="Assets\Chrome.png">
|
<Content Update="Assets\Chrome.png">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
<Content Update="Assets\Discord.png">
|
<Content Update="Assets\Edge.png">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
<Content Update="Assets\Edge.png">
|
<Content Update="Assets\effect.bin">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="Assets\Empty.png">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
<Content Update="Assets\EmptyBox.png">
|
<Content Update="Assets\EmptyBox.png">
|
||||||
@@ -142,6 +151,9 @@
|
|||||||
<Content Update="Assets\Leaf.png">
|
<Content Update="Assets\Leaf.png">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
<Content Update="Assets\Listen1.png">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
<Content Update="Assets\Logo.ico">
|
<Content Update="Assets\Logo.ico">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
@@ -154,16 +166,19 @@
|
|||||||
<Content Update="Assets\MediaPlayerWindows11.png">
|
<Content Update="Assets\MediaPlayerWindows11.png">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
<Content Update="Assets\MoeKoeMusic.png">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
<Content Update="Assets\MusicBee.png">
|
<Content Update="Assets\MusicBee.png">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
<Content Update="Assets\NetEaseCloudMusic.png">
|
<Content Update="Assets\NetEaseCloudMusic.png">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
<Content Update="Assets\PotPlayer.png">
|
<Content Update="Assets\Page.png">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
<Content Update="Assets\QQ.png">
|
<Content Update="Assets\PotPlayer.png">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
<Content Update="Assets\QQMusic.png">
|
<Content Update="Assets\QQMusic.png">
|
||||||
@@ -172,26 +187,56 @@
|
|||||||
<Content Update="Assets\Question.png">
|
<Content Update="Assets\Question.png">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
<Content Update="Assets\SaltPlayerForWindows.png">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
<Content Update="Assets\Segoe Fluent Icons.ttf">
|
<Content Update="Assets\Segoe Fluent Icons.ttf">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
<Content Update="Assets\Spotify.png">
|
<Content Update="Assets\Spotify.png">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
<Content Update="Assets\Telegram.png">
|
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Update="Assets\Wiki82.profile.xml">
|
<Content Update="Assets\Wiki82.profile.xml">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Page Update="Controls\ExtendedSlider.xaml">
|
<Page Update="Views\LyricsWindowSwitchWindow.xaml">
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
</Page>
|
</Page>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Page Update="Controls\AllLyricsSettingsControl.xaml">
|
<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>
|
||||||
|
</Page>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Page Update="Controls\LyricsSearchControl.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Page Update="Controls\ShortcutTextBox.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Page Update="Controls\ExtendedSlider.xaml">
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
</Page>
|
</Page>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
@@ -216,7 +261,7 @@
|
|||||||
</Page>
|
</Page>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Page Update="Controls\LyricsBavkgroundSettingsControl.xaml">
|
<Page Update="Controls\LyricsBackgroundSettingsControl.xaml">
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
</Page>
|
</Page>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
@@ -245,6 +290,11 @@
|
|||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
</Page>
|
</Page>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PRIResource Update="Strings\en-US\Resources.resw">
|
||||||
|
<Generator></Generator>
|
||||||
|
</PRIResource>
|
||||||
|
</ItemGroup>
|
||||||
<!-- Publish Properties -->
|
<!-- Publish Properties -->
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<PublishReadyToRun Condition="'$(Configuration)' == 'Debug'">False</PublishReadyToRun>
|
<PublishReadyToRun Condition="'$(Configuration)' == 'Debug'">False</PublishReadyToRun>
|
||||||
|
|||||||
@@ -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";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,6 +8,6 @@ namespace BetterLyrics.WinUI3.Constants
|
|||||||
{
|
{
|
||||||
public static class LXMusic
|
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";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ namespace BetterLyrics.WinUI3.Constants
|
|||||||
{
|
{
|
||||||
public static class Link
|
public static class Link
|
||||||
{
|
{
|
||||||
public const string GithubUrl = "https://github.com/jayfunc/BetterLyrics";
|
public const string GitHubUrl = "https://github.com/jayfunc/BetterLyrics";
|
||||||
|
public const string FAQUrl = $"{GitHubUrl}/blob/dev/FAQ/index.md";
|
||||||
public const string QQGroupUrl = "https://qun.qq.com/universal-share/share?ac=1&authKey=4Q%2BYTq3wZldYpF5SbS5c19ECFsiYoLZFAIcBNNzYpBUtiEjaZ8sZ%2F%2BnFN0qw3lad&busi_data=eyJncm91cENvZGUiOiIxMDU0NzAwMzg4IiwidG9rZW4iOiJiVnhqemVYN0N5QVc3b1ZkR24wWmZOTUtvUkJoWm1JRWlaWW5iZnlBcXJtZUtGc2FFTHNlUlFZMi9iRm03cWF5IiwidWluIjoiMTM5NTczOTY2MCJ9&data=39UmAihyH_o6CZaOs7nk2mO_lz2ruODoDou6pxxh7utcxP4WF5sbDBDOPvZ_Wqfzeey4441anegsLYQJxkrBAA&svctype=4&tempid=h5_group_info";
|
public const string QQGroupUrl = "https://qun.qq.com/universal-share/share?ac=1&authKey=4Q%2BYTq3wZldYpF5SbS5c19ECFsiYoLZFAIcBNNzYpBUtiEjaZ8sZ%2F%2BnFN0qw3lad&busi_data=eyJncm91cENvZGUiOiIxMDU0NzAwMzg4IiwidG9rZW4iOiJiVnhqemVYN0N5QVc3b1ZkR24wWmZOTUtvUkJoWm1JRWlaWW5iZnlBcXJtZUtGc2FFTHNlUlFZMi9iRm03cWF5IiwidWluIjoiMTM5NTczOTY2MCJ9&data=39UmAihyH_o6CZaOs7nk2mO_lz2ruODoDou6pxxh7utcxP4WF5sbDBDOPvZ_Wqfzeey4441anegsLYQJxkrBAA&svctype=4&tempid=h5_group_info";
|
||||||
public const string DiscordUrl = "https://discord.gg/5yAQPnyCKv";
|
public const string DiscordUrl = "https://discord.gg/5yAQPnyCKv";
|
||||||
public const string TelegramUrl = "https://t.me/+svhSLZ7awPsxNGY1";
|
public const string TelegramUrl = "https://t.me/+svhSLZ7awPsxNGY1";
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ namespace BetterLyrics.WinUI3.Constants
|
|||||||
public const string PotPlayer = "PotPlayerMini64.exe";
|
public const string PotPlayer = "PotPlayerMini64.exe";
|
||||||
public const string Spotify = "Spotify.exe";
|
public const string Spotify = "Spotify.exe";
|
||||||
public const string AppleMusic = "AppleInc.AppleMusicWin_nzyj5cx40ttqa!App";
|
public const string AppleMusic = "AppleInc.AppleMusicWin_nzyj5cx40ttqa!App";
|
||||||
|
public const string AppleMusicAlternative = "AppleMusic.exe";
|
||||||
public const string NetEaseCloudMusic = "cloudmusic.exe";
|
public const string NetEaseCloudMusic = "cloudmusic.exe";
|
||||||
public const string KugouMusic = "kugou";
|
public const string KugouMusic = "kugou";
|
||||||
public const string QQMusic = "QQMusic.exe";
|
public const string QQMusic = "QQMusic.exe";
|
||||||
@@ -25,5 +26,9 @@ namespace BetterLyrics.WinUI3.Constants
|
|||||||
public const string Edge = "MSEdge";
|
public const string Edge = "MSEdge";
|
||||||
public const string BetterLyrics = "37412.BetterLyrics_rd1g0rsrrtxw8!App";
|
public const string BetterLyrics = "37412.BetterLyrics_rd1g0rsrrtxw8!App";
|
||||||
public const string BetterLyricsDebug = "37412.BetterLyrics_c8mj3v9sysxb4!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";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ namespace BetterLyrics.WinUI3.Constants
|
|||||||
public const string PotPlayer = "PotPlayer";
|
public const string PotPlayer = "PotPlayer";
|
||||||
public const string Spotify = "Spotify";
|
public const string Spotify = "Spotify";
|
||||||
public const string AppleMusic = "Apple Music";
|
public const string AppleMusic = "Apple Music";
|
||||||
|
public const string AppleMusicAlternative = "Apple Music";
|
||||||
public const string NetEaseCloudMusic = "网易云音乐";
|
public const string NetEaseCloudMusic = "网易云音乐";
|
||||||
public const string KugouMusic = "酷狗音乐";
|
public const string KugouMusic = "酷狗音乐";
|
||||||
public const string QQMusic = "QQ 音乐";
|
public const string QQMusic = "QQ 音乐";
|
||||||
@@ -24,5 +25,8 @@ namespace BetterLyrics.WinUI3.Constants
|
|||||||
public const string Edge = "Microsoft Edge";
|
public const string Edge = "Microsoft Edge";
|
||||||
public const string BetterLyrics = "BetterLyrics";
|
public const string BetterLyrics = "BetterLyrics";
|
||||||
public const string BetterLyricsDebug = "BetterLyrics (Debug)";
|
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";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,29 +17,92 @@
|
|||||||
|
|
||||||
<TextBlock x:Uid="SettingsPageAlbumArt" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
<TextBlock x:Uid="SettingsPageAlbumArt" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||||
|
|
||||||
<controls:SettingsCard x:Uid="SettingsPageAlbumRadius" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
<controls:SettingsExpander
|
||||||
|
x:Uid="SettingsPageAlbumArtSize"
|
||||||
|
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||||
|
Glyph=}"
|
||||||
|
IsExpanded="True">
|
||||||
|
<controls:SettingsExpander.Items>
|
||||||
|
<controls:SettingsCard x:Uid="SettingsPageAutoAdjust">
|
||||||
|
<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=}">
|
||||||
<local:ExtendedSlider
|
<local:ExtendedSlider
|
||||||
Default="12"
|
Default="12"
|
||||||
Frequency="1"
|
Frequency="1"
|
||||||
Maximum="100"
|
Maximum="100"
|
||||||
Minimum="0"
|
Minimum="0"
|
||||||
Unit="%"
|
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=}">
|
||||||
|
<local:ExtendedSlider
|
||||||
|
Default="12"
|
||||||
|
Frequency="1"
|
||||||
|
Maximum="64"
|
||||||
|
Minimum="0"
|
||||||
|
Value="{x:Bind AlbumArtLayoutSettings.CoverImageShadowAmount, Mode=TwoWay}" />
|
||||||
</controls:SettingsCard>
|
</controls:SettingsCard>
|
||||||
|
|
||||||
<TextBlock x:Uid="SettingsPageSongInfo" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
<TextBlock x:Uid="SettingsPageSongInfo" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||||
|
|
||||||
<controls:SettingsCard x:Uid="SettingsPageSongInfoAlignment" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
<controls:SettingsCard x:Uid="SettingsPageSongInfoAlignment" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||||
<ComboBox SelectedIndex="{x:Bind ViewModel.AppSettings.AlbumArtLayoutSettings.SongInfoAlignmentType, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
<ComboBox SelectedIndex="{x:Bind AlbumArtLayoutSettings.SongInfoAlignmentType, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||||
<ComboBoxItem x:Uid="SettingsPageSongInfoLeft" />
|
<ComboBoxItem x:Uid="SettingsPageSongInfoLeft" />
|
||||||
<ComboBoxItem x:Uid="SettingsPageSongInfoCenter" />
|
<ComboBoxItem x:Uid="SettingsPageSongInfoCenter" />
|
||||||
<ComboBoxItem x:Uid="SettingsPageSongInfoRight" />
|
<ComboBoxItem x:Uid="SettingsPageSongInfoRight" />
|
||||||
</ComboBox>
|
</ComboBox>
|
||||||
</controls:SettingsCard>
|
</controls:SettingsCard>
|
||||||
|
|
||||||
|
<controls:SettingsExpander
|
||||||
|
x:Uid="SettingsPageLyricsFontSize"
|
||||||
|
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||||
|
Glyph=}"
|
||||||
|
IsExpanded="True">
|
||||||
|
<controls:SettingsExpander.Items>
|
||||||
|
<controls:SettingsCard x:Uid="SettingsPageAutoAdjust">
|
||||||
|
<ToggleSwitch IsOn="{x:Bind AlbumArtLayoutSettings.IsAutoSongInfoFontSize, Mode=TwoWay}" />
|
||||||
|
</controls:SettingsCard>
|
||||||
|
<controls:SettingsCard>
|
||||||
|
<local:ExtendedSlider
|
||||||
|
Default="18"
|
||||||
|
Frequency="2"
|
||||||
|
IsEnabled="{x:Bind AlbumArtLayoutSettings.IsAutoSongInfoFontSize, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}"
|
||||||
|
Maximum="72"
|
||||||
|
Minimum="8"
|
||||||
|
Value="{x:Bind AlbumArtLayoutSettings.SongInfoFontSize, Mode=TwoWay}" />
|
||||||
|
</controls:SettingsCard>
|
||||||
|
</controls:SettingsExpander.Items>
|
||||||
|
</controls:SettingsExpander>
|
||||||
|
|
||||||
|
<controls:SettingsExpander
|
||||||
|
x:Uid="SettingsPageShowTitle"
|
||||||
|
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||||
|
Glyph=}"
|
||||||
|
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>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using BetterLyrics.WinUI3.Models.Settings;
|
||||||
using BetterLyrics.WinUI3.ViewModels;
|
using BetterLyrics.WinUI3.ViewModels;
|
||||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||||
using Microsoft.UI.Xaml;
|
using Microsoft.UI.Xaml;
|
||||||
@@ -22,11 +23,18 @@ namespace BetterLyrics.WinUI3.Controls
|
|||||||
{
|
{
|
||||||
public sealed partial class AlbumArtLayoutSettingsControl : UserControl
|
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()
|
public AlbumArtLayoutSettingsControl()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
DataContext = Ioc.Default.GetRequiredService<AlbumArtLayoutSettingsControlViewModel>();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,36 +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:SwitchPresenter>
|
|
||||||
<controls:Segmented
|
|
||||||
x:Name="LyricsSettingsSegmentedControl"
|
|
||||||
Margin="36,36,36,0"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
VerticalAlignment="Top"
|
|
||||||
SelectedIndex="0">
|
|
||||||
<controls:SegmentedItem x:Uid="AllLyricsSettingsControlStandard" Tag="Standard" />
|
|
||||||
<controls:SegmentedItem x:Uid="AllLyricsSettingsControlDesktop" Tag="Desktop" />
|
|
||||||
<controls:SegmentedItem x:Uid="AllLyricsSettingsControlDock" Tag="Dock" />
|
|
||||||
</controls:Segmented>
|
|
||||||
</Grid>
|
|
||||||
</UserControl>
|
|
||||||
@@ -50,102 +50,44 @@
|
|||||||
Unloaded="AutoStartupToggleSwitch_Unloaded" />
|
Unloaded="AutoStartupToggleSwitch_Unloaded" />
|
||||||
</controls:SettingsCard>
|
</controls:SettingsCard>
|
||||||
|
|
||||||
<controls:SettingsCard x:Uid="SettingsPageAutoStartWindow" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
<controls:SettingsCard x:Uid="SettingsPageExitOnLyricsWindowClosed" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||||
<ComboBox SelectedIndex="{x:Bind ViewModel.AppSettings.GeneralSettings.AutoStartWindowType, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.GeneralSettings.ExitOnLyricsWindowClosed, Mode=TwoWay}" />
|
||||||
<ComboBoxItem x:Uid="SettingsPageAutoStartInAppLyrics" />
|
|
||||||
<ComboBoxItem x:Uid="SettingsPageAutoStartDockLyrics" />
|
|
||||||
<ComboBoxItem x:Uid="SettingsPageAutoStartDesktopLyrics" />
|
|
||||||
</ComboBox>
|
|
||||||
</controls:SettingsCard>
|
</controls:SettingsCard>
|
||||||
|
|
||||||
<controls:SettingsCard x:Uid="SettingsPageIgnoreFullscreenWindow" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
<controls:SettingsCard x:Uid="SettingsPageListenNewSession" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||||
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.GeneralSettings.IgnoreFullscreenWindow, Mode=TwoWay}" />
|
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.GeneralSettings.ListenOnNewPlaybackSource, Mode=TwoWay}" />
|
||||||
</controls:SettingsCard>
|
</controls:SettingsCard>
|
||||||
|
|
||||||
<controls:SettingsCard x:Uid="SettingsPageHideWindow" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
<controls:SettingsCard x:Uid="SettingsPageShowHideHotKey" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||||
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.GeneralSettings.HideWindowWhenNotPlaying, Mode=TwoWay}" />
|
<local:ShortcutTextBox Shortcut="{x:Bind ViewModel.AppSettings.GeneralSettings.ShowOrHideLyricsWindowShortcut, Mode=TwoWay}" />
|
||||||
</controls:SettingsCard>
|
</controls:SettingsCard>
|
||||||
|
|
||||||
<controls:SettingsCard x:Uid="SettingsPageGlobalDrag" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
<controls:SettingsCard x:Uid="SettingsPageBorderlessHotKey" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||||
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.GeneralSettings.IsDragEverywhereEnabled, Mode=TwoWay}" />
|
<local:ShortcutTextBox Shortcut="{x:Bind ViewModel.AppSettings.GeneralSettings.BorderlessShortcut, Mode=TwoWay}" />
|
||||||
</controls:SettingsCard>
|
</controls:SettingsCard>
|
||||||
|
|
||||||
<!-- Desktop mode -->
|
<controls:SettingsCard x:Uid="SettingsPageClickThroughHotKey" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||||
|
<local:ShortcutTextBox Shortcut="{x:Bind ViewModel.AppSettings.GeneralSettings.ClickThroughShortcut, Mode=TwoWay}" />
|
||||||
<TextBlock x:Uid="SettingsPageAppDesktop" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
|
||||||
|
|
||||||
<controls:SettingsCard x:Uid="SettingsPageAutoLock" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
|
||||||
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.DesktopModeSettings.AutoLockOnDesktopMode, Mode=TwoWay}" />
|
|
||||||
</controls:SettingsCard>
|
</controls:SettingsCard>
|
||||||
|
|
||||||
<controls:SettingsCard x:Uid="SettingsPageLockHotKey" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
<controls:SettingsCard x:Uid="SettingsPageLyricsWindowSwitchHotKey" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
<local:ShortcutTextBox Shortcut="{x:Bind ViewModel.AppSettings.GeneralSettings.LyricsWindowSwitchShortcut, Mode=TwoWay}" />
|
||||||
<TextBlock
|
|
||||||
Margin="0,0,0,2"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Text="Ctrl + Alt + " />
|
|
||||||
<ComboBox SelectedIndex="{x:Bind ViewModel.AppSettings.DesktopModeSettings.LockHotKeyIndex, Mode=TwoWay}">
|
|
||||||
<ComboBoxItem Content="A" />
|
|
||||||
<ComboBoxItem Content="B" />
|
|
||||||
<ComboBoxItem Content="C" />
|
|
||||||
<ComboBoxItem Content="D" />
|
|
||||||
<ComboBoxItem Content="E" />
|
|
||||||
<ComboBoxItem Content="F" />
|
|
||||||
<ComboBoxItem Content="G" />
|
|
||||||
<ComboBoxItem Content="H" />
|
|
||||||
<ComboBoxItem Content="I" />
|
|
||||||
<ComboBoxItem Content="J" />
|
|
||||||
<ComboBoxItem Content="K" />
|
|
||||||
<ComboBoxItem Content="L" />
|
|
||||||
<ComboBoxItem Content="M" />
|
|
||||||
<ComboBoxItem Content="N" />
|
|
||||||
<ComboBoxItem Content="O" />
|
|
||||||
<ComboBoxItem Content="P" />
|
|
||||||
<ComboBoxItem Content="Q" />
|
|
||||||
<ComboBoxItem Content="R" />
|
|
||||||
<ComboBoxItem Content="S" />
|
|
||||||
<ComboBoxItem Content="T" />
|
|
||||||
<ComboBoxItem Content="U" />
|
|
||||||
<ComboBoxItem Content="V" />
|
|
||||||
<ComboBoxItem Content="W" />
|
|
||||||
<ComboBoxItem Content="X" />
|
|
||||||
<ComboBoxItem Content="Y" />
|
|
||||||
<ComboBoxItem Content="Z" />
|
|
||||||
</ComboBox>
|
|
||||||
</StackPanel>
|
|
||||||
</controls:SettingsCard>
|
</controls:SettingsCard>
|
||||||
|
|
||||||
<!-- Dock mode -->
|
<!-- Playback shortcut -->
|
||||||
|
|
||||||
<TextBlock x:Uid="SettingsPageAppDock" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
<TextBlock x:Uid="SettingsPagePlaybackShortcut" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||||
|
|
||||||
<controls:SettingsCard x:Uid="SettingsPageDockMonitor" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
<controls:SettingsCard x:Uid="SettingsPagePlayOrPauseSongHotKey" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
<local:ShortcutTextBox Shortcut="{x:Bind ViewModel.AppSettings.GeneralSettings.PlayOrPauseShortcut, Mode=TwoWay}" />
|
||||||
<ComboBox ItemsSource="{x:Bind ViewModel.MonitorDeviceNames, Mode=OneWay}" SelectedItem="{x:Bind ViewModel.AppSettings.DockModeSettings.DockMonitorDeviceName, Mode=TwoWay}" />
|
|
||||||
<Button
|
|
||||||
Command="{x:Bind ViewModel.RefreshMonitorDeviceNamesCommand}"
|
|
||||||
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
|
||||||
FontSize=12,
|
|
||||||
Glyph=}"
|
|
||||||
Style="{StaticResource GhostButtonStyle}" />
|
|
||||||
</StackPanel>
|
|
||||||
</controls:SettingsCard>
|
</controls:SettingsCard>
|
||||||
|
|
||||||
<controls:SettingsCard x:Uid="SettingsPageDockWindowHeight" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
<controls:SettingsCard x:Uid="SettingsPageNextSongHotKey" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||||
<local:ExtendedSlider
|
<local:ShortcutTextBox Shortcut="{x:Bind ViewModel.AppSettings.GeneralSettings.NextSongShortcut, Mode=TwoWay}" />
|
||||||
Default="64"
|
|
||||||
Frequency="1"
|
|
||||||
Maximum="200"
|
|
||||||
Minimum="64"
|
|
||||||
Unit="px"
|
|
||||||
Value="{x:Bind ViewModel.AppSettings.DockModeSettings.DockWindowHeight, Mode=TwoWay}" />
|
|
||||||
</controls:SettingsCard>
|
</controls:SettingsCard>
|
||||||
|
|
||||||
<controls:SettingsCard x:Uid="SettingsPageDockPlacement" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
<controls:SettingsCard x:Uid="SettingsPagePreviousSongHotKey" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||||
<ComboBox SelectedIndex="{x:Bind ViewModel.AppSettings.DockModeSettings.DockPlacement, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
<local:ShortcutTextBox Shortcut="{x:Bind ViewModel.AppSettings.GeneralSettings.PreviousSongShortcut, Mode=TwoWay}" />
|
||||||
<ComboBoxItem x:Uid="SettingsPageDockPlacementTop" />
|
|
||||||
<ComboBoxItem x:Uid="SettingsPageDockPlacementBottom" />
|
|
||||||
</ComboBox>
|
|
||||||
</controls:SettingsCard>
|
</controls:SettingsCard>
|
||||||
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
|
using BetterLyrics.WinUI3.Helper;
|
||||||
|
using BetterLyrics.WinUI3.Models;
|
||||||
using BetterLyrics.WinUI3.Models.Settings;
|
using BetterLyrics.WinUI3.Models.Settings;
|
||||||
using BetterLyrics.WinUI3.ViewModels;
|
using BetterLyrics.WinUI3.ViewModels;
|
||||||
|
using BetterLyrics.WinUI3.Views;
|
||||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||||
using Microsoft.UI.Xaml;
|
using Microsoft.UI.Xaml;
|
||||||
using Microsoft.UI.Xaml.Controls;
|
using Microsoft.UI.Xaml.Controls;
|
||||||
|
|||||||
@@ -0,0 +1,88 @@
|
|||||||
|
<?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}"
|
||||||
|
CornerRadius="4" />
|
||||||
|
<!-- 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="" />
|
||||||
|
<FontIcon
|
||||||
|
FontFamily="{StaticResource IconFontFamily}"
|
||||||
|
FontSize="12"
|
||||||
|
Glyph=""
|
||||||
|
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>
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,54 +4,58 @@
|
|||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
|
||||||
xmlns:local="using:BetterLyrics.WinUI3.Controls"
|
xmlns:local="using:BetterLyrics.WinUI3.Controls"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:ui="using:CommunityToolkit.WinUI"
|
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
|
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel>
|
||||||
<TextBlock
|
|
||||||
Margin="6,0,2,0"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Text="{x:Bind Value, Mode=OneWay}" />
|
|
||||||
<TextBlock
|
|
||||||
Margin="0,0,14,0"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Text="{x:Bind Unit, Mode=OneWay}" />
|
|
||||||
<Slider
|
<Slider
|
||||||
Maximum="{x:Bind Maximum, Mode=OneWay}"
|
Maximum="{x:Bind Maximum, Mode=OneWay}"
|
||||||
Minimum="{x:Bind Minimum, Mode=OneWay}"
|
Minimum="{x:Bind Minimum, Mode=OneWay}"
|
||||||
SnapsTo="Ticks"
|
SnapsTo="Ticks"
|
||||||
StepFrequency="{x:Bind Frequency, Mode=OneWay}"
|
StepFrequency="{x:Bind Frequency, Mode=OneWay}"
|
||||||
TickFrequency="{x:Bind Frequency, Mode=OneWay}"
|
TickFrequency="{x:Bind Frequency, Mode=OneWay}"
|
||||||
TickPlacement="Outside"
|
TickPlacement="None"
|
||||||
Value="{x:Bind Value, Mode=TwoWay}" />
|
Value="{x:Bind Value, Mode=TwoWay}" />
|
||||||
<Button
|
|
||||||
Margin="3,0,0,0"
|
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
|
||||||
VerticalAlignment="Center"
|
<Button
|
||||||
Click="ResetButton_Click"
|
VerticalAlignment="Center"
|
||||||
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
Click="ResetButton_Click"
|
||||||
FontSize=12,
|
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||||
Glyph=}"
|
FontSize=12,
|
||||||
Style="{StaticResource GhostButtonStyle}"
|
Glyph=}"
|
||||||
Visibility="{x:Bind ResetButtonVisibility, Mode=OneWay}" />
|
Style="{StaticResource GhostButtonStyle}"
|
||||||
<Button
|
Visibility="{x:Bind ResetButtonVisibility, Mode=OneWay}" />
|
||||||
x:Name="SubtractButton"
|
<Button
|
||||||
Margin="3,0,0,0"
|
x:Name="SubtractButton"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Click="SubtractButton_Click"
|
Click="SubtractButton_Click"
|
||||||
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||||
FontSize=12,
|
FontSize=12,
|
||||||
Glyph=}"
|
Glyph=}"
|
||||||
Style="{StaticResource GhostButtonStyle}" />
|
Style="{StaticResource GhostButtonStyle}" />
|
||||||
<Button
|
|
||||||
x:Name="AddButton"
|
<StackPanel
|
||||||
Margin="3,0,0,0"
|
Margin="3,-2,3,0"
|
||||||
VerticalAlignment="Center"
|
Orientation="Horizontal"
|
||||||
Click="AddButton_Click"
|
Spacing="2">
|
||||||
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
<TextBlock VerticalAlignment="Center" Text="{x:Bind RoundedValue, Mode=OneWay}" />
|
||||||
FontSize=12,
|
<TextBlock VerticalAlignment="Center" Text="{x:Bind Unit, Mode=OneWay}" />
|
||||||
Glyph=}"
|
</StackPanel>
|
||||||
Style="{StaticResource GhostButtonStyle}" />
|
|
||||||
|
<Button
|
||||||
|
x:Name="AddButton"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Click="AddButton_Click"
|
||||||
|
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||||
|
FontSize=12,
|
||||||
|
Glyph=}"
|
||||||
|
Style="{StaticResource GhostButtonStyle}" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
|||||||
@@ -68,6 +68,8 @@ namespace BetterLyrics.WinUI3.Controls
|
|||||||
DependencyProperty.Register(nameof(Maximum), typeof(double), typeof(ExtendedSlider), new PropertyMetadata(default));
|
DependencyProperty.Register(nameof(Maximum), typeof(double), typeof(ExtendedSlider), new PropertyMetadata(default));
|
||||||
public static readonly DependencyProperty ValueProperty =
|
public static readonly DependencyProperty ValueProperty =
|
||||||
DependencyProperty.Register(nameof(Value), typeof(double), typeof(ExtendedSlider), new PropertyMetadata(default));
|
DependencyProperty.Register(nameof(Value), typeof(double), typeof(ExtendedSlider), new PropertyMetadata(default));
|
||||||
|
private static readonly DependencyProperty RoundedValueProperty =
|
||||||
|
DependencyProperty.Register(nameof(Value), typeof(string), typeof(ExtendedSlider), new PropertyMetadata(default));
|
||||||
public static readonly DependencyProperty DefaultProperty =
|
public static readonly DependencyProperty DefaultProperty =
|
||||||
DependencyProperty.Register(nameof(Default), typeof(double), typeof(ExtendedSlider), new PropertyMetadata(default));
|
DependencyProperty.Register(nameof(Default), typeof(double), typeof(ExtendedSlider), new PropertyMetadata(default));
|
||||||
public static readonly DependencyProperty ResetButtonVisibilityProperty =
|
public static readonly DependencyProperty ResetButtonVisibilityProperty =
|
||||||
@@ -93,7 +95,16 @@ namespace BetterLyrics.WinUI3.Controls
|
|||||||
public double Value
|
public double Value
|
||||||
{
|
{
|
||||||
get => (double)GetValue(ValueProperty);
|
get => (double)GetValue(ValueProperty);
|
||||||
set => SetValue(ValueProperty, value);
|
set
|
||||||
|
{
|
||||||
|
SetValue(ValueProperty, value);
|
||||||
|
SetValue(RoundedValueProperty, value.ToString("F1").Replace(".0", ""));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private string RoundedValue
|
||||||
|
{
|
||||||
|
get => (string)GetValue(RoundedValueProperty);
|
||||||
|
set => SetValue(RoundedValueProperty, value);
|
||||||
}
|
}
|
||||||
public double Default
|
public double Default
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,139 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<UserControl
|
||||||
|
x:Class="BetterLyrics.WinUI3.Controls.LyricsBackgroundSettingsControl"
|
||||||
|
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:enums="using:BetterLyrics.WinUI3.Enums"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:uc="using:BetterLyrics.WinUI3.Controls"
|
||||||
|
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
|
||||||
|
<Grid>
|
||||||
|
<ScrollViewer Style="{StaticResource SettingsScrollViewerStyle}">
|
||||||
|
<Grid Style="{StaticResource SettingsGridStyle}">
|
||||||
|
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
|
||||||
|
|
||||||
|
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||||
|
|
||||||
|
<controls:SettingsCard x:Uid="SettingsPageTheme" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||||
|
<ComboBox x:Name="ThemeComboBox" SelectedIndex="{x:Bind LyricsBackgroundSettings.LyricsBackgroundTheme, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||||
|
<ComboBoxItem x:Uid="SettingsPageFollowSystem" />
|
||||||
|
<ComboBoxItem x:Uid="SettingsPageLight" />
|
||||||
|
<ComboBoxItem x:Uid="SettingsPageDark" />
|
||||||
|
</ComboBox>
|
||||||
|
</controls:SettingsCard>
|
||||||
|
|
||||||
|
<controls:SettingsExpander
|
||||||
|
x:Uid="SettingsPagePureLayer"
|
||||||
|
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||||
|
Glyph=}"
|
||||||
|
IsExpanded="{x:Bind LyricsBackgroundSettings.IsPureColorOverlayEnabled, Mode=OneWay}">
|
||||||
|
<ToggleSwitch IsOn="{x:Bind LyricsBackgroundSettings.IsPureColorOverlayEnabled, Mode=TwoWay}" />
|
||||||
|
<controls:SettingsExpander.Items>
|
||||||
|
|
||||||
|
<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:SettingsExpander.Items>
|
||||||
|
</controls:SettingsExpander>
|
||||||
|
|
||||||
|
<controls:SettingsExpander
|
||||||
|
x:Uid="SettingsPageAlbumArtLayer"
|
||||||
|
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||||
|
Glyph=}"
|
||||||
|
IsExpanded="{x:Bind LyricsBackgroundSettings.IsCoverOverlayEnabled, Mode=OneWay}">
|
||||||
|
<ToggleSwitch IsOn="{x:Bind LyricsBackgroundSettings.IsCoverOverlayEnabled, Mode=TwoWay}" />
|
||||||
|
<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=}"
|
||||||
|
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:SettingsCard x:Uid="SettingsPagePaletteGeneratorType">
|
||||||
|
<ComboBox SelectedIndex="{x:Bind LyricsBackgroundSettings.PaletteGeneratorType, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||||
|
<ComboBoxItem x:Uid="SettingsPageMedianCut" />
|
||||||
|
<ComboBoxItem x:Uid="SettingsPageOctTree" />
|
||||||
|
</ComboBox>
|
||||||
|
</controls:SettingsCard>
|
||||||
|
|
||||||
|
</controls:SettingsExpander.Items>
|
||||||
|
</controls:SettingsExpander>
|
||||||
|
|
||||||
|
<controls:SettingsExpander
|
||||||
|
x:Uid="SettingsPageSpectrumLayer"
|
||||||
|
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||||
|
Glyph=}"
|
||||||
|
IsExpanded="{x:Bind LyricsBackgroundSettings.IsSpectrumOverlayEnabled, Mode=OneWay}">
|
||||||
|
<ToggleSwitch IsOn="{x:Bind LyricsBackgroundSettings.IsSpectrumOverlayEnabled, Mode=TwoWay}" />
|
||||||
|
</controls:SettingsExpander>
|
||||||
|
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</ScrollViewer>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using BetterLyrics.WinUI3.Models.Settings;
|
||||||
using BetterLyrics.WinUI3.ViewModels;
|
using BetterLyrics.WinUI3.ViewModels;
|
||||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||||
using Microsoft.UI.Xaml;
|
using Microsoft.UI.Xaml;
|
||||||
@@ -20,14 +21,20 @@ using Windows.Foundation.Collections;
|
|||||||
|
|
||||||
namespace BetterLyrics.WinUI3.Controls
|
namespace BetterLyrics.WinUI3.Controls
|
||||||
{
|
{
|
||||||
public sealed partial class LyricsBavkgroundSettingsControl : UserControl
|
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 LyricsBavkgroundSettingsControl()
|
public LyricsBackgroundSettings LyricsBackgroundSettings
|
||||||
|
{
|
||||||
|
get => (LyricsBackgroundSettings)GetValue(LyricsBackgroundSettingsProperty);
|
||||||
|
set => SetValue(LyricsBackgroundSettingsProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LyricsBackgroundSettingsControl()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
DataContext = Ioc.Default.GetRequiredService<LyricsBackgroundSettingsControlViewModel>();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8" ?>
|
|
||||||
<UserControl
|
|
||||||
x:Class="BetterLyrics.WinUI3.Controls.LyricsBavkgroundSettingsControl"
|
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
xmlns:controls="using:CommunityToolkit.WinUI.Controls"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
|
||||||
xmlns:uc="using:BetterLyrics.WinUI3.Controls"
|
|
||||||
xmlns:ui="using:CommunityToolkit.WinUI"
|
|
||||||
mc:Ignorable="d">
|
|
||||||
|
|
||||||
<Grid>
|
|
||||||
<ScrollViewer Style="{StaticResource SettingsScrollViewerStyle}">
|
|
||||||
<Grid Style="{StaticResource SettingsGridStyle}">
|
|
||||||
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
|
|
||||||
|
|
||||||
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
|
||||||
|
|
||||||
<controls:SettingsCard x:Uid="SettingsPageTheme" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
|
||||||
<ComboBox x:Name="ThemeComboBox" SelectedIndex="{x:Bind ViewModel.AppSettings.LyricsBackgroundSettings.LyricsBackgroundTheme, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
|
||||||
<ComboBoxItem x:Uid="SettingsPageFollowSystem" />
|
|
||||||
<ComboBoxItem x:Uid="SettingsPageLight" />
|
|
||||||
<ComboBoxItem x:Uid="SettingsPageDark" />
|
|
||||||
</ComboBox>
|
|
||||||
</controls:SettingsCard>
|
|
||||||
|
|
||||||
<controls:SettingsCard x:Uid="SettingsPageLyricsPureColorBgOpacity" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
|
||||||
<uc:ExtendedSlider
|
|
||||||
Default="100"
|
|
||||||
Frequency="1"
|
|
||||||
Maximum="100"
|
|
||||||
Minimum="0"
|
|
||||||
Unit="%"
|
|
||||||
Value="{x:Bind ViewModel.AppSettings.LyricsBackgroundSettings.PureColorOverlayOpacity, Mode=TwoWay}" />
|
|
||||||
</controls:SettingsCard>
|
|
||||||
|
|
||||||
<controls:SettingsCard x:Uid="SettingsPageLyricsBackgroundOpacity" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
|
||||||
<uc:ExtendedSlider
|
|
||||||
Default="100"
|
|
||||||
Frequency="1"
|
|
||||||
Maximum="100"
|
|
||||||
Minimum="0"
|
|
||||||
Unit="%"
|
|
||||||
Value="{x:Bind ViewModel.AppSettings.LyricsBackgroundSettings.CoverOverlayOpacity, Mode=TwoWay}" />
|
|
||||||
</controls:SettingsCard>
|
|
||||||
|
|
||||||
<controls:SettingsCard x:Uid="SettingsPageLyricsBackgroundSpeed" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
|
||||||
<uc:ExtendedSlider
|
|
||||||
Default="50"
|
|
||||||
Frequency="1"
|
|
||||||
Maximum="100"
|
|
||||||
Minimum="0"
|
|
||||||
Unit="%"
|
|
||||||
Value="{x:Bind ViewModel.AppSettings.LyricsBackgroundSettings.CoverOverlaySpeed, Mode=TwoWay}" />
|
|
||||||
</controls:SettingsCard>
|
|
||||||
|
|
||||||
<controls:SettingsCard x:Uid="SettingsPageLyricsBackgroundBlurAmount" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
|
||||||
<uc:ExtendedSlider
|
|
||||||
Default="100"
|
|
||||||
Frequency="1"
|
|
||||||
Maximum="100"
|
|
||||||
Minimum="0"
|
|
||||||
Value="{x:Bind ViewModel.AppSettings.LyricsBackgroundSettings.CoverOverlayBlurAmount, Mode=TwoWay}" />
|
|
||||||
</controls:SettingsCard>
|
|
||||||
|
|
||||||
<controls:SettingsCard x:Uid="SettingsPageBackgroundAcrylicEffectAmount" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
|
||||||
<uc:ExtendedSlider
|
|
||||||
Default="0"
|
|
||||||
Frequency="1"
|
|
||||||
Maximum="10"
|
|
||||||
Minimum="0"
|
|
||||||
Value="{x:Bind ViewModel.AppSettings.LyricsBackgroundSettings.CoverAcrylicEffectAmount, Mode=TwoWay}" />
|
|
||||||
</controls:SettingsCard>
|
|
||||||
</StackPanel>
|
|
||||||
</Grid>
|
|
||||||
</ScrollViewer>
|
|
||||||
</Grid>
|
|
||||||
</UserControl>
|
|
||||||
@@ -0,0 +1,227 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<UserControl
|
||||||
|
x:Class="BetterLyrics.WinUI3.Controls.LyricsSearchControl"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:controls="using:CommunityToolkit.WinUI.Controls"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
|
||||||
|
xmlns:local="using:BetterLyrics.WinUI3.Controls"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
|
||||||
|
<Grid Padding="16" RowSpacing="6">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid Grid.Row="0">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Grid Grid.Column="0">
|
||||||
|
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
|
||||||
|
<controls:SettingsExpander x:Uid="LyricsSearchControlSongInfoMapping" IsExpanded="True">
|
||||||
|
<controls:SettingsExpander.Items>
|
||||||
|
<controls:SettingsCard x:Uid="LyricsSearchControlTitle" Description="{x:Bind ViewModel.MappedSongSearchQuery.OriginalTitle, Mode=OneWay}">
|
||||||
|
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||||
|
<TextBlock x:Uid="LyricsSearchControlMappedAs" VerticalAlignment="Center" />
|
||||||
|
<TextBox Text="{x:Bind ViewModel.MappedSongSearchQuery.MappedTitle, Mode=TwoWay}" TextWrapping="Wrap" />
|
||||||
|
<Button
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Command="{x:Bind ViewModel.ResetMappedTitleCommand}"
|
||||||
|
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||||
|
FontSize=12,
|
||||||
|
Glyph=}"
|
||||||
|
Style="{StaticResource GhostButtonStyle}" />
|
||||||
|
</StackPanel>
|
||||||
|
</controls:SettingsCard>
|
||||||
|
<controls:SettingsCard x:Uid="LyricsSearchControlArtist" Description="{x:Bind ViewModel.MappedSongSearchQuery.OriginalArtist, Mode=OneWay}">
|
||||||
|
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||||
|
<TextBlock x:Uid="LyricsSearchControlMappedAs" VerticalAlignment="Center" />
|
||||||
|
<TextBox Text="{x:Bind ViewModel.MappedSongSearchQuery.MappedArtist, Mode=TwoWay}" TextWrapping="Wrap" />
|
||||||
|
<Button
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Command="{x:Bind ViewModel.ResetMappedArtistCommand}"
|
||||||
|
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||||
|
FontSize=12,
|
||||||
|
Glyph=}"
|
||||||
|
Style="{StaticResource GhostButtonStyle}" />
|
||||||
|
</StackPanel>
|
||||||
|
</controls:SettingsCard>
|
||||||
|
<controls:SettingsCard>
|
||||||
|
<CheckBox x:Uid="LyricsSearchControlMarkAsPureMusic" IsChecked="{x:Bind ViewModel.MappedSongSearchQuery.IsMarkedAsPureMusic, Mode=TwoWay}" />
|
||||||
|
</controls:SettingsCard>
|
||||||
|
</controls:SettingsExpander.Items>
|
||||||
|
</controls:SettingsExpander>
|
||||||
|
|
||||||
|
<controls:SettingsCard x:Uid="LyricsSearchControlTargetSearchProvider">
|
||||||
|
<Button
|
||||||
|
x:Uid="LyricsSearchControlSearch"
|
||||||
|
Command="{x:Bind ViewModel.SearchCommand}"
|
||||||
|
Style="{StaticResource AccentButtonStyle}" />
|
||||||
|
</controls:SettingsCard>
|
||||||
|
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
<Grid Grid.Column="1">
|
||||||
|
<ListView ItemsSource="{x:Bind ViewModel.LyricsSearchResults, Mode=OneWay}" SelectedItem="{x:Bind ViewModel.SelectedLyricsSearchResult, Mode=TwoWay}">
|
||||||
|
<ListView.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<ListViewItem IsEnabled="{Binding IsFound}">
|
||||||
|
<Grid Opacity="{Binding IsFound, Converter={StaticResource BoolToOpacityConverter}}">
|
||||||
|
<RelativePanel Padding="0,6">
|
||||||
|
<TextBlock
|
||||||
|
x:Name="SearchedTitle"
|
||||||
|
RelativePanel.AlignLeftWithPanel="True"
|
||||||
|
Text="{Binding Title}"
|
||||||
|
Visibility="{Binding IsFound, Converter={StaticResource BoolToVisibilityConverter}}" />
|
||||||
|
<TextBlock
|
||||||
|
x:Name="SearchedArtists"
|
||||||
|
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||||
|
RelativePanel.AlignLeftWithPanel="True"
|
||||||
|
RelativePanel.Below="SearchedTitle"
|
||||||
|
Text="{Binding Artist}"
|
||||||
|
Visibility="{Binding IsFound, Converter={StaticResource BoolToVisibilityConverter}}" />
|
||||||
|
<TextBlock
|
||||||
|
x:Name="SearchedProvider"
|
||||||
|
RelativePanel.AlignRightWithPanel="True"
|
||||||
|
RelativePanel.AlignVerticalCenterWithPanel="True"
|
||||||
|
Text="{Binding Provider, Converter={StaticResource LyricsSearchProviderToDisplayNameConverter}}" />
|
||||||
|
</RelativePanel>
|
||||||
|
<TextBlock
|
||||||
|
x:Uid="LyricsSearchControlNotFound"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="Not found"
|
||||||
|
Visibility="{Binding IsFound, Converter={StaticResource BoolNegationToVisibilityConverter}}" />
|
||||||
|
</Grid>
|
||||||
|
</ListViewItem>
|
||||||
|
</DataTemplate>
|
||||||
|
</ListView.ItemTemplate>
|
||||||
|
<interactivity:Interaction.Behaviors>
|
||||||
|
<interactivity:DataTriggerBehavior
|
||||||
|
Binding="{x:Bind ViewModel.LyricsSearchResults.Count, Mode=OneWay}"
|
||||||
|
ComparisonCondition="Equal"
|
||||||
|
Value="0">
|
||||||
|
<interactivity:ChangePropertyAction PropertyName="Visibility" Value="Collapsed" />
|
||||||
|
</interactivity:DataTriggerBehavior>
|
||||||
|
<interactivity:DataTriggerBehavior
|
||||||
|
Binding="{x:Bind ViewModel.LyricsSearchResults.Count, Mode=OneWay}"
|
||||||
|
ComparisonCondition="NotEqual"
|
||||||
|
Value="0">
|
||||||
|
<interactivity:ChangePropertyAction PropertyName="Visibility" Value="Visible" />
|
||||||
|
</interactivity:DataTriggerBehavior>
|
||||||
|
</interactivity:Interaction.Behaviors>
|
||||||
|
</ListView>
|
||||||
|
<StackPanel
|
||||||
|
Padding="0,36"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Spacing="12">
|
||||||
|
<Image MaxWidth="100" Source="/Assets/Empty.png" />
|
||||||
|
<interactivity:Interaction.Behaviors>
|
||||||
|
<interactivity:DataTriggerBehavior
|
||||||
|
Binding="{x:Bind ViewModel.LyricsSearchResults.Count, Mode=OneWay}"
|
||||||
|
ComparisonCondition="NotEqual"
|
||||||
|
Value="0">
|
||||||
|
<interactivity:ChangePropertyAction PropertyName="Visibility" Value="Collapsed" />
|
||||||
|
</interactivity:DataTriggerBehavior>
|
||||||
|
<interactivity:DataTriggerBehavior
|
||||||
|
Binding="{x:Bind ViewModel.LyricsSearchResults.Count, Mode=OneWay}"
|
||||||
|
ComparisonCondition="Equal"
|
||||||
|
Value="0">
|
||||||
|
<interactivity:ChangePropertyAction PropertyName="Visibility" Value="Visible" />
|
||||||
|
</interactivity:DataTriggerBehavior>
|
||||||
|
</interactivity:Interaction.Behaviors>
|
||||||
|
</StackPanel>
|
||||||
|
<ProgressBar
|
||||||
|
VerticalAlignment="Top"
|
||||||
|
IsIndeterminate="True"
|
||||||
|
ShowError="False"
|
||||||
|
ShowPaused="False"
|
||||||
|
Visibility="{x:Bind ViewModel.IsSearching, Converter={StaticResource BoolToVisibilityConverter}, Mode=OneWay}" />
|
||||||
|
</Grid>
|
||||||
|
<Grid Grid.Column="2">
|
||||||
|
<ListView ItemsSource="{x:Bind ViewModel.LyricsData.LyricsLines, Mode=OneWay}" SelectedItem="{x:Bind ViewModel.SelectedLyricsLine, Mode=TwoWay}">
|
||||||
|
<interactivity:Interaction.Behaviors>
|
||||||
|
<interactivity:DataTriggerBehavior
|
||||||
|
Binding="{x:Bind ViewModel.LyricsData, Mode=OneWay}"
|
||||||
|
ComparisonCondition="Equal"
|
||||||
|
Value="{x:Null}">
|
||||||
|
<interactivity:ChangePropertyAction PropertyName="Visibility" Value="Collapsed" />
|
||||||
|
</interactivity:DataTriggerBehavior>
|
||||||
|
<interactivity:DataTriggerBehavior
|
||||||
|
Binding="{x:Bind ViewModel.LyricsData, Mode=OneWay}"
|
||||||
|
ComparisonCondition="NotEqual"
|
||||||
|
Value="{x:Null}">
|
||||||
|
<interactivity:ChangePropertyAction PropertyName="Visibility" Value="Visible" />
|
||||||
|
</interactivity:DataTriggerBehavior>
|
||||||
|
</interactivity:Interaction.Behaviors>
|
||||||
|
<ListView.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBlock Foreground="{ThemeResource SystemFillColorNeutralBrush}" Text="{Binding StartMs, Converter={StaticResource MillisecondsToFormattedTimeConverter}}" />
|
||||||
|
<TextBlock
|
||||||
|
Margin="1,0"
|
||||||
|
Foreground="{ThemeResource SystemFillColorNeutralBrush}"
|
||||||
|
Text="-" />
|
||||||
|
<TextBlock Foreground="{ThemeResource SystemFillColorNeutralBrush}" Text="{Binding EndMs, Converter={StaticResource MillisecondsToFormattedTimeConverter}}" />
|
||||||
|
<TextBlock Margin="6,0" Text="{Binding OriginalText}" />
|
||||||
|
</StackPanel>
|
||||||
|
</DataTemplate>
|
||||||
|
</ListView.ItemTemplate>
|
||||||
|
</ListView>
|
||||||
|
<StackPanel
|
||||||
|
Padding="0,36"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Spacing="12">
|
||||||
|
<Image MaxWidth="100" Source="/Assets/Page.png" />
|
||||||
|
<interactivity:Interaction.Behaviors>
|
||||||
|
<interactivity:DataTriggerBehavior
|
||||||
|
Binding="{x:Bind ViewModel.LyricsData, Mode=OneWay}"
|
||||||
|
ComparisonCondition="NotEqual"
|
||||||
|
Value="{x:Null}">
|
||||||
|
<interactivity:ChangePropertyAction PropertyName="Visibility" Value="Collapsed" />
|
||||||
|
</interactivity:DataTriggerBehavior>
|
||||||
|
<interactivity:DataTriggerBehavior
|
||||||
|
Binding="{x:Bind ViewModel.LyricsData, Mode=OneWay}"
|
||||||
|
ComparisonCondition="Equal"
|
||||||
|
Value="{x:Null}">
|
||||||
|
<interactivity:ChangePropertyAction PropertyName="Visibility" Value="Visible" />
|
||||||
|
</interactivity:DataTriggerBehavior>
|
||||||
|
</interactivity:Interaction.Behaviors>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
<Grid Grid.Row="1">
|
||||||
|
<RelativePanel>
|
||||||
|
<TextBlock
|
||||||
|
x:Uid="LyricsSearchControlHelp"
|
||||||
|
Margin="0,0,24,0"
|
||||||
|
FontSize="12"
|
||||||
|
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||||
|
RelativePanel.AlignVerticalCenterWithPanel="True"
|
||||||
|
RelativePanel.LeftOf="Reset"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
|
<Button
|
||||||
|
x:Name="Reset"
|
||||||
|
x:Uid="LyricsSearchControlReset"
|
||||||
|
Margin="0,0,6,0"
|
||||||
|
Command="{x:Bind ViewModel.ResetCommand}"
|
||||||
|
RelativePanel.AlignVerticalCenterWithPanel="True"
|
||||||
|
RelativePanel.LeftOf="SaveChanges" />
|
||||||
|
<Button
|
||||||
|
x:Name="SaveChanges"
|
||||||
|
x:Uid="LyricsSearchControlSaveChanges"
|
||||||
|
Command="{x:Bind ViewModel.SaveCommand}"
|
||||||
|
RelativePanel.AlignRightWithPanel="True"
|
||||||
|
RelativePanel.AlignVerticalCenterWithPanel="True"
|
||||||
|
Style="{StaticResource AccentButtonStyle}" />
|
||||||
|
</RelativePanel>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using BetterLyrics.WinUI3.Models;
|
||||||
using BetterLyrics.WinUI3.ViewModels;
|
using BetterLyrics.WinUI3.ViewModels;
|
||||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||||
using Microsoft.UI.Xaml;
|
using Microsoft.UI.Xaml;
|
||||||
@@ -12,6 +13,7 @@ using System.Collections.Generic;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.InteropServices.WindowsRuntime;
|
using System.Runtime.InteropServices.WindowsRuntime;
|
||||||
|
using Ude.Core;
|
||||||
using Windows.Foundation;
|
using Windows.Foundation;
|
||||||
using Windows.Foundation.Collections;
|
using Windows.Foundation.Collections;
|
||||||
|
|
||||||
@@ -20,13 +22,14 @@ using Windows.Foundation.Collections;
|
|||||||
|
|
||||||
namespace BetterLyrics.WinUI3.Controls
|
namespace BetterLyrics.WinUI3.Controls
|
||||||
{
|
{
|
||||||
public sealed partial class AllLyricsSettingsControl : UserControl
|
public sealed partial class LyricsSearchControl : UserControl
|
||||||
{
|
{
|
||||||
public AllLyricsSettingsControlViewModel ViewModel => (AllLyricsSettingsControlViewModel)DataContext;
|
public LyricsSearchControlViewModel ViewModel => (LyricsSearchControlViewModel)DataContext;
|
||||||
public AllLyricsSettingsControl()
|
|
||||||
|
public LyricsSearchControl()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
DataContext = Ioc.Default.GetRequiredService<AllLyricsSettingsControlViewModel>();
|
DataContext = Ioc.Default.GetRequiredService<LyricsSearchControlViewModel>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
</controls:SettingsCard>
|
</controls:SettingsCard>
|
||||||
|
|
||||||
<controls:SettingsCard x:Uid="SettingsPageLyricsFontFamily" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
<controls:SettingsCard x:Uid="SettingsPageLyricsFontFamily" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||||
<ComboBox ItemsSource="{x:Bind SystemFontNames, Mode=OneWay}" SelectedIndex="{x:Bind LyricsStyleSettings.SelectedFontFamilyIndex, Mode=TwoWay}">
|
<ComboBox ItemsSource="{x:Bind SystemFontNames, Mode=OneWay}" SelectedItem="{x:Bind LyricsStyleSettings.LyricsFontFamily, Mode=TwoWay}">
|
||||||
<ComboBox.ItemTemplate>
|
<ComboBox.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<TextBlock Text="{Binding}" />
|
<TextBlock Text="{Binding}" />
|
||||||
@@ -54,7 +54,7 @@
|
|||||||
</ComboBox>
|
</ComboBox>
|
||||||
</controls:SettingsCard>
|
</controls:SettingsCard>
|
||||||
|
|
||||||
<controls:SettingsCard x:Uid="SettingsPageLyricsBgFontOpacity" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
<controls:SettingsCard x:Uid="SettingsPageLyricsBgFontOpacity" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||||
<local:ExtendedSlider
|
<local:ExtendedSlider
|
||||||
Default="30"
|
Default="30"
|
||||||
Frequency="1"
|
Frequency="1"
|
||||||
@@ -175,14 +175,25 @@
|
|||||||
</interactivity:Interaction.Behaviors>
|
</interactivity:Interaction.Behaviors>
|
||||||
</ColorPicker>
|
</ColorPicker>
|
||||||
|
|
||||||
<controls:SettingsCard x:Uid="SettingsPageLyricsFontSize" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
<controls:SettingsExpander
|
||||||
<local:ExtendedSlider
|
x:Uid="SettingsPageLyricsFontSize"
|
||||||
Frequency="2"
|
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||||
Maximum="96"
|
Glyph=}"
|
||||||
Minimum="12"
|
IsExpanded="True">
|
||||||
ResetButtonVisibility="Collapsed"
|
<controls:SettingsExpander.Items>
|
||||||
Value="{x:Bind LyricsStyleSettings.LyricsFontSize, Mode=TwoWay}" />
|
<controls:SettingsCard x:Uid="SettingsPageAutoAdjust">
|
||||||
</controls:SettingsCard>
|
<ToggleSwitch IsOn="{x:Bind LyricsStyleSettings.IsDynamicLyricsFontSize, Mode=TwoWay}" />
|
||||||
|
</controls:SettingsCard>
|
||||||
|
<controls:SettingsCard IsEnabled="{x:Bind LyricsStyleSettings.IsDynamicLyricsFontSize, Converter={StaticResource BoolNegationConverter}, Mode=OneWay}">
|
||||||
|
<local:ExtendedSlider
|
||||||
|
Frequency="2"
|
||||||
|
Maximum="96"
|
||||||
|
Minimum="12"
|
||||||
|
ResetButtonVisibility="Collapsed"
|
||||||
|
Value="{x:Bind LyricsStyleSettings.LyricsFontSize, Mode=TwoWay}" />
|
||||||
|
</controls:SettingsCard>
|
||||||
|
</controls:SettingsExpander.Items>
|
||||||
|
</controls:SettingsExpander>
|
||||||
|
|
||||||
<controls:SettingsCard x:Uid="SettingsPageLyricsLineSpacingFactor" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
<controls:SettingsCard x:Uid="SettingsPageLyricsLineSpacingFactor" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||||
<local:ExtendedSlider
|
<local:ExtendedSlider
|
||||||
@@ -195,7 +206,7 @@
|
|||||||
Value="{x:Bind LyricsStyleSettings.LyricsLineSpacingFactor, Mode=TwoWay}" />
|
Value="{x:Bind LyricsStyleSettings.LyricsLineSpacingFactor, Mode=TwoWay}" />
|
||||||
</controls:SettingsCard>
|
</controls:SettingsCard>
|
||||||
|
|
||||||
<controls:SettingsCard x:Uid="SettingsPageLyricsTranslationSeparator" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
<controls:SettingsCard x:Uid="SettingsPageLyricsTranslationSeparator" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||||
<TextBox AcceptsReturn="True" Text="{x:Bind LyricsStyleSettings.LyricsTranslationSeparator, Mode=TwoWay}" />
|
<TextBox AcceptsReturn="True" Text="{x:Bind LyricsStyleSettings.LyricsTranslationSeparator, Mode=TwoWay}" />
|
||||||
<Button Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, FontSize=12, Glyph=}" Style="{StaticResource GhostButtonStyle}" />
|
<Button Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, FontSize=12, Glyph=}" Style="{StaticResource GhostButtonStyle}" />
|
||||||
@@ -209,7 +220,7 @@
|
|||||||
Style="{StaticResource SettingsSectionHeaderTextBlockStyle}"
|
Style="{StaticResource SettingsSectionHeaderTextBlockStyle}"
|
||||||
Text="Effect" />
|
Text="Effect" />
|
||||||
|
|
||||||
<controls:SettingsCard x:Uid="SettingsPageLyricsVerticalEdgeOpacity" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
<controls:SettingsCard x:Uid="SettingsPageLyricsVerticalEdgeOpacity" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||||
<local:ExtendedSlider
|
<local:ExtendedSlider
|
||||||
x:Uid="SettingsPageLyricsVerticalEdgeOpacitySlider"
|
x:Uid="SettingsPageLyricsVerticalEdgeOpacitySlider"
|
||||||
Default="0"
|
Default="0"
|
||||||
@@ -230,14 +241,78 @@
|
|||||||
Value="{x:Bind LyricsEffectSettings.LyricsBlurAmount, Mode=TwoWay}" />
|
Value="{x:Bind LyricsEffectSettings.LyricsBlurAmount, Mode=TwoWay}" />
|
||||||
</controls:SettingsCard>
|
</controls:SettingsCard>
|
||||||
|
|
||||||
<controls:SettingsCard x:Uid="SettingsPageLyricsHighlightScope" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
<controls:SettingsCard x:Uid="SettingsPageLyricsLineFade" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||||
|
<ToggleSwitch IsOn="{x:Bind LyricsEffectSettings.IsLyricsLineFadeEnabled, Mode=TwoWay}" />
|
||||||
|
</controls:SettingsCard>
|
||||||
|
|
||||||
|
<!-- 译文高亮 -->
|
||||||
|
<controls:SettingsExpander
|
||||||
|
x:Uid="SettingsPageLyricsTranslationHighlight"
|
||||||
|
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||||
|
Glyph=}"
|
||||||
|
IsExpanded="True">
|
||||||
|
<controls:SettingsExpander.Items>
|
||||||
|
<controls:SettingsCard x:Uid="SettingsPageAmount">
|
||||||
|
<local:ExtendedSlider
|
||||||
|
Default="60"
|
||||||
|
Frequency="5"
|
||||||
|
Maximum="100"
|
||||||
|
Minimum="0"
|
||||||
|
Value="{x:Bind LyricsEffectSettings.LyricsTranslationHighlightAmount, Mode=TwoWay}" />
|
||||||
|
</controls:SettingsCard>
|
||||||
|
</controls:SettingsExpander.Items>
|
||||||
|
</controls:SettingsExpander>
|
||||||
|
|
||||||
|
<!-- 原文高亮 -->
|
||||||
|
<controls:SettingsExpander
|
||||||
|
x:Uid="SettingsPageLyricsHighlightScope"
|
||||||
|
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||||
|
Glyph=}"
|
||||||
|
IsExpanded="True">
|
||||||
<ComboBox SelectedIndex="{x:Bind LyricsEffectSettings.LyricsHighlightScope, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
<ComboBox SelectedIndex="{x:Bind LyricsEffectSettings.LyricsHighlightScope, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||||
<ComboBoxItem x:Uid="SettingsPageLyricsRendingScopeCurrentChar" />
|
<ComboBoxItem x:Uid="SettingsPageLyricsRendingScopeCurrentChar" />
|
||||||
<ComboBoxItem x:Uid="SettingsPageLyricsRendingScopeLineStartToCurrentChar" />
|
<ComboBoxItem x:Uid="SettingsPageLyricsRendingScopeLineStartToCurrentChar" />
|
||||||
<ComboBoxItem x:Uid="SettingsPageLyricsRendingScopeCurrentLine" />
|
<ComboBoxItem x:Uid="SettingsPageLyricsRendingScopeCurrentLine" />
|
||||||
</ComboBox>
|
</ComboBox>
|
||||||
</controls:SettingsCard>
|
<controls:SettingsExpander.Items>
|
||||||
|
<controls:SettingsCard x:Uid="SettingsPageAmount">
|
||||||
|
<local:ExtendedSlider
|
||||||
|
Default="100"
|
||||||
|
Frequency="5"
|
||||||
|
Maximum="100"
|
||||||
|
Minimum="0"
|
||||||
|
Value="{x:Bind LyricsEffectSettings.LyricsHighlightAmount, Mode=TwoWay}" />
|
||||||
|
</controls:SettingsCard>
|
||||||
|
</controls:SettingsExpander.Items>
|
||||||
|
</controls:SettingsExpander>
|
||||||
|
|
||||||
|
<!-- 阴影 -->
|
||||||
|
<controls:SettingsExpander
|
||||||
|
x:Uid="SettingsPageLyricsShadow"
|
||||||
|
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||||
|
Glyph=}"
|
||||||
|
IsExpanded="{x:Bind LyricsEffectSettings.IsLyricsShadowEnabled, Mode=OneWay}">
|
||||||
|
<ToggleSwitch IsOn="{x:Bind LyricsEffectSettings.IsLyricsShadowEnabled, Mode=TwoWay}" />
|
||||||
|
<controls:SettingsExpander.Items>
|
||||||
|
<controls:SettingsCard x:Uid="SettingsPageScope" IsEnabled="{x:Bind LyricsEffectSettings.IsLyricsShadowEnabled, Mode=OneWay}">
|
||||||
|
<ComboBox SelectedIndex="{x:Bind LyricsEffectSettings.LyricsShadowScope, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||||
|
<ComboBoxItem x:Uid="SettingsPageLyricsRendingScopeCurrentChar" />
|
||||||
|
<ComboBoxItem x:Uid="SettingsPageLyricsRendingScopeLineStartToCurrentChar" />
|
||||||
|
<ComboBoxItem x:Uid="SettingsPageLyricsRendingScopeCurrentLine" />
|
||||||
|
</ComboBox>
|
||||||
|
</controls:SettingsCard>
|
||||||
|
<controls:SettingsCard x:Uid="SettingsPageAmount" IsEnabled="{x:Bind LyricsEffectSettings.IsLyricsShadowEnabled, Mode=OneWay}">
|
||||||
|
<local:ExtendedSlider
|
||||||
|
Default="8"
|
||||||
|
Frequency="1"
|
||||||
|
Maximum="20"
|
||||||
|
Minimum="1"
|
||||||
|
Value="{x:Bind LyricsEffectSettings.LyricsShadowAmount, Mode=TwoWay}" />
|
||||||
|
</controls:SettingsCard>
|
||||||
|
</controls:SettingsExpander.Items>
|
||||||
|
</controls:SettingsExpander>
|
||||||
|
|
||||||
|
<!-- 辉光效果 -->
|
||||||
<controls:SettingsExpander
|
<controls:SettingsExpander
|
||||||
x:Uid="SettingsPageLyricsGlowEffect"
|
x:Uid="SettingsPageLyricsGlowEffect"
|
||||||
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||||
@@ -252,17 +327,42 @@
|
|||||||
<ComboBoxItem x:Uid="SettingsPageLyricsRendingScopeCurrentLine" />
|
<ComboBoxItem x:Uid="SettingsPageLyricsRendingScopeCurrentLine" />
|
||||||
</ComboBox>
|
</ComboBox>
|
||||||
</controls:SettingsCard>
|
</controls:SettingsCard>
|
||||||
|
<controls:SettingsCard x:Uid="SettingsPageAmount" IsEnabled="{x:Bind LyricsEffectSettings.IsLyricsGlowEffectEnabled, Mode=OneWay}">
|
||||||
|
<local:ExtendedSlider
|
||||||
|
Default="8"
|
||||||
|
Frequency="1"
|
||||||
|
Maximum="20"
|
||||||
|
Minimum="1"
|
||||||
|
Value="{x:Bind LyricsEffectSettings.LyricsGlowEffectAmount, Mode=TwoWay}" />
|
||||||
|
</controls:SettingsCard>
|
||||||
</controls:SettingsExpander.Items>
|
</controls:SettingsExpander.Items>
|
||||||
</controls:SettingsExpander>
|
</controls:SettingsExpander>
|
||||||
|
|
||||||
<controls:SettingsCard x:Uid="SettingsPageLyricsFloatAnimation" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
<!-- 浮动动画 -->
|
||||||
|
<controls:SettingsExpander
|
||||||
|
x:Uid="SettingsPageLyricsFloatAnimation"
|
||||||
|
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||||
|
Glyph=}"
|
||||||
|
IsExpanded="True">
|
||||||
<ToggleSwitch IsOn="{x:Bind LyricsEffectSettings.IsLyricsFloatAnimationEnabled, Mode=TwoWay}" />
|
<ToggleSwitch IsOn="{x:Bind LyricsEffectSettings.IsLyricsFloatAnimationEnabled, Mode=TwoWay}" />
|
||||||
</controls:SettingsCard>
|
<controls:SettingsExpander.Items>
|
||||||
|
<controls:SettingsCard x:Uid="SettingsPageAmount" IsEnabled="{x:Bind LyricsEffectSettings.IsLyricsGlowEffectEnabled, Mode=OneWay}">
|
||||||
|
<local:ExtendedSlider
|
||||||
|
Default="1"
|
||||||
|
Frequency="1"
|
||||||
|
Maximum="4"
|
||||||
|
Minimum="1"
|
||||||
|
Value="{x:Bind LyricsEffectSettings.LyricsFloatAmount, Mode=TwoWay}" />
|
||||||
|
</controls:SettingsCard>
|
||||||
|
</controls:SettingsExpander.Items>
|
||||||
|
</controls:SettingsExpander>
|
||||||
|
|
||||||
|
<!-- 扇形歌词 -->
|
||||||
<controls:SettingsCard x:Uid="SettingsPageFan" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
<controls:SettingsCard x:Uid="SettingsPageFan" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||||
<ToggleSwitch IsOn="{x:Bind LyricsEffectSettings.IsFanLyricsEnabled, Mode=TwoWay}" />
|
<ToggleSwitch IsOn="{x:Bind LyricsEffectSettings.IsFanLyricsEnabled, Mode=TwoWay}" />
|
||||||
</controls:SettingsCard>
|
</controls:SettingsCard>
|
||||||
|
|
||||||
|
<!-- 滚动动画 -->
|
||||||
<controls:SettingsExpander
|
<controls:SettingsExpander
|
||||||
x:Uid="SettingsPageScrollEasing"
|
x:Uid="SettingsPageScrollEasing"
|
||||||
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||||
@@ -285,7 +385,6 @@
|
|||||||
<controls:SettingsExpander.Items>
|
<controls:SettingsExpander.Items>
|
||||||
<controls:SettingsCard x:Uid="SettingsPageScrollTopDuration">
|
<controls:SettingsCard x:Uid="SettingsPageScrollTopDuration">
|
||||||
<local:ExtendedSlider
|
<local:ExtendedSlider
|
||||||
x:Uid="SettingsPageLyricsScrollTopDurationExtendedSlider"
|
|
||||||
Default="500"
|
Default="500"
|
||||||
Frequency="50"
|
Frequency="50"
|
||||||
Maximum="1000"
|
Maximum="1000"
|
||||||
@@ -295,7 +394,6 @@
|
|||||||
</controls:SettingsCard>
|
</controls:SettingsCard>
|
||||||
<controls:SettingsCard x:Uid="SettingsPageScrollDuration">
|
<controls:SettingsCard x:Uid="SettingsPageScrollDuration">
|
||||||
<local:ExtendedSlider
|
<local:ExtendedSlider
|
||||||
x:Uid="SettingsPageLyricsScrollDurationExtendedSlider"
|
|
||||||
Default="500"
|
Default="500"
|
||||||
Frequency="50"
|
Frequency="50"
|
||||||
Maximum="1000"
|
Maximum="1000"
|
||||||
@@ -305,7 +403,6 @@
|
|||||||
</controls:SettingsCard>
|
</controls:SettingsCard>
|
||||||
<controls:SettingsCard x:Uid="SettingsPageScrollBottomDuration">
|
<controls:SettingsCard x:Uid="SettingsPageScrollBottomDuration">
|
||||||
<local:ExtendedSlider
|
<local:ExtendedSlider
|
||||||
x:Uid="SettingsPageLyricsScrollBottomDurationExtendedSlider"
|
|
||||||
Default="500"
|
Default="500"
|
||||||
Frequency="50"
|
Frequency="50"
|
||||||
Maximum="1000"
|
Maximum="1000"
|
||||||
@@ -313,6 +410,24 @@
|
|||||||
Unit="ms"
|
Unit="ms"
|
||||||
Value="{x:Bind LyricsEffectSettings.LyricsScrollBottomDuration, Mode=TwoWay}" />
|
Value="{x:Bind LyricsEffectSettings.LyricsScrollBottomDuration, Mode=TwoWay}" />
|
||||||
</controls:SettingsCard>
|
</controls:SettingsCard>
|
||||||
|
<controls:SettingsCard x:Uid="SettingsPageScrollTopDelay">
|
||||||
|
<local:ExtendedSlider
|
||||||
|
Default="0"
|
||||||
|
Frequency="50"
|
||||||
|
Maximum="2000"
|
||||||
|
Minimum="0"
|
||||||
|
Unit="ms"
|
||||||
|
Value="{x:Bind LyricsEffectSettings.LyricsScrollTopDelay, Mode=TwoWay}" />
|
||||||
|
</controls:SettingsCard>
|
||||||
|
<controls:SettingsCard x:Uid="SettingsPageScrollBottomDelay">
|
||||||
|
<local:ExtendedSlider
|
||||||
|
Default="0"
|
||||||
|
Frequency="50"
|
||||||
|
Maximum="2000"
|
||||||
|
Minimum="0"
|
||||||
|
Unit="ms"
|
||||||
|
Value="{x:Bind LyricsEffectSettings.LyricsScrollBottomDelay, Mode=TwoWay}" />
|
||||||
|
</controls:SettingsCard>
|
||||||
</controls:SettingsExpander.Items>
|
</controls:SettingsExpander.Items>
|
||||||
</controls:SettingsExpander>
|
</controls:SettingsExpander>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,391 @@
|
|||||||
|
<?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=}">
|
||||||
|
<StackPanel
|
||||||
|
Margin="0,6,0,0"
|
||||||
|
Orientation="Horizontal"
|
||||||
|
Spacing="6">
|
||||||
|
<TextBox Text="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.Name, Mode=TwoWay}" TextWrapping="Wrap" />
|
||||||
|
<Button Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, FontSize=12, Glyph=}" Style="{StaticResource GhostButtonStyle}" />
|
||||||
|
</StackPanel>
|
||||||
|
</controls:SettingsCard>
|
||||||
|
|
||||||
|
<controls:SettingsExpander
|
||||||
|
x:Uid="SettingsPageDisplayTypeSwitcher"
|
||||||
|
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||||
|
Glyph=}"
|
||||||
|
IsExpanded="True">
|
||||||
|
<ComboBox SelectedIndex="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.LyricsDisplayType, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||||
|
<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=}"
|
||||||
|
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"
|
||||||
|
IsEnabled="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.IsAdaptToEnvironment, Mode=OneWay}">
|
||||||
|
<ComboBox SelectedIndex="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.EnvironmentSampleMode, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||||
|
<ComboBoxItem x:Uid="SettingsPageEnvColorSampleBelow" />
|
||||||
|
<ComboBoxItem x:Uid="SettingsPageEnvColorSampleAbove" />
|
||||||
|
<ComboBoxItem x:Uid="SettingsPageEnvColorSampleInner" />
|
||||||
|
<ComboBoxItem x:Uid="SettingsPageEnvColorSampleEdge" />
|
||||||
|
</ComboBox>
|
||||||
|
</controls:SettingsCard>
|
||||||
|
</controls:SettingsExpander.Items>
|
||||||
|
</controls:SettingsExpander>
|
||||||
|
|
||||||
|
<controls:SettingsCard x:Uid="SettingsPageDockMonitor" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||||
|
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||||
|
<ComboBox ItemsSource="{x:Bind ViewModel.MonitorDeviceNames, Mode=OneWay}" SelectedItem="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.MonitorDeviceName, Mode=TwoWay}" />
|
||||||
|
<Button
|
||||||
|
Command="{x:Bind ViewModel.RefreshMonitorDeviceNamesCommand}"
|
||||||
|
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||||
|
FontSize=12,
|
||||||
|
Glyph=}"
|
||||||
|
Style="{StaticResource GhostButtonStyle}" />
|
||||||
|
</StackPanel>
|
||||||
|
</controls:SettingsCard>
|
||||||
|
|
||||||
|
<controls:SettingsExpander
|
||||||
|
x:Uid="SettingsPageWindowBounds"
|
||||||
|
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||||
|
Glyph=}"
|
||||||
|
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=}"
|
||||||
|
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=}"
|
||||||
|
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=}">
|
||||||
|
<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=}">
|
||||||
|
<ToggleSwitch IsOn="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.IsShownInSwitchers, Mode=TwoWay}" />
|
||||||
|
</controls:SettingsCard>
|
||||||
|
|
||||||
|
<controls:SettingsCard x:Uid="SettingsPageClickThrough" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||||
|
<ToggleSwitch IsOn="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.IsClickThrough, Mode=TwoWay}" />
|
||||||
|
</controls:SettingsCard>
|
||||||
|
|
||||||
|
<controls:SettingsCard x:Uid="SettingsPageBorderless" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||||
|
<ToggleSwitch IsOn="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.IsBorderless, Mode=TwoWay}" />
|
||||||
|
</controls:SettingsCard>
|
||||||
|
|
||||||
|
<controls:SettingsCard x:Uid="SettingsPageDragArea" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}">
|
||||||
|
<ComboBox SelectedIndex="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.TitleBarArea, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||||
|
<ComboBoxItem x:Uid="SettingsPageTitleBarAreaNone" />
|
||||||
|
<ComboBoxItem x:Uid="SettingsPageTitleBarAreaTop" />
|
||||||
|
<ComboBoxItem x:Uid="SettingsPageTitleBarAreaWhole" />
|
||||||
|
</ComboBox>
|
||||||
|
</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="Hidden"
|
||||||
|
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="" />
|
||||||
|
<TextBlock x:Uid="AppSettingsControlGeneral" VerticalAlignment="Center" />
|
||||||
|
</StackPanel>
|
||||||
|
</ListViewItem>
|
||||||
|
|
||||||
|
<ListViewItem Tag="AlbumArtStyle">
|
||||||
|
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||||
|
<FontIcon
|
||||||
|
FontFamily="{StaticResource IconFontFamily}"
|
||||||
|
FontSize="16"
|
||||||
|
Glyph="" />
|
||||||
|
<TextBlock x:Uid="SettingsPageAlbumStyle" VerticalAlignment="Center" />
|
||||||
|
</StackPanel>
|
||||||
|
</ListViewItem>
|
||||||
|
|
||||||
|
<ListViewItem Tag="Lyrics">
|
||||||
|
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||||
|
<FontIcon
|
||||||
|
FontFamily="{StaticResource IconFontFamily}"
|
||||||
|
FontSize="16"
|
||||||
|
Glyph="" />
|
||||||
|
<TextBlock x:Uid="SettingsPageLyrics" VerticalAlignment="Center" />
|
||||||
|
</StackPanel>
|
||||||
|
</ListViewItem>
|
||||||
|
|
||||||
|
<ListViewItem Tag="LyricsBackground">
|
||||||
|
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||||
|
<FontIcon
|
||||||
|
FontFamily="{StaticResource IconFontFamily}"
|
||||||
|
FontSize="16"
|
||||||
|
Glyph="" />
|
||||||
|
<TextBlock x:Uid="SettingsPageBackgroundOverlay" VerticalAlignment="Center" />
|
||||||
|
</StackPanel>
|
||||||
|
</ListViewItem>
|
||||||
|
|
||||||
|
<ListViewItem Tag="Advanced">
|
||||||
|
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||||
|
<FontIcon
|
||||||
|
FontFamily="{StaticResource IconFontFamily}"
|
||||||
|
FontSize="16"
|
||||||
|
Glyph="" />
|
||||||
|
<TextBlock x:Uid="SettingsPageAdvanced" VerticalAlignment="Center" />
|
||||||
|
</StackPanel>
|
||||||
|
</ListViewItem>
|
||||||
|
|
||||||
|
</ListView.Items>
|
||||||
|
|
||||||
|
</ListView>
|
||||||
|
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
<?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">
|
||||||
|
<FontIcon
|
||||||
|
Margin="20"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
VerticalAlignment="Top"
|
||||||
|
FontFamily="{StaticResource IconFontFamily}"
|
||||||
|
Glyph="" />
|
||||||
|
<Button
|
||||||
|
Margin="12"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
VerticalAlignment="Top"
|
||||||
|
Click="Button_Click"
|
||||||
|
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||||
|
Glyph=}"
|
||||||
|
Style="{StaticResource GhostButtonStyle}">
|
||||||
|
<Button.KeyboardAccelerators>
|
||||||
|
<KeyboardAccelerator Key="Escape" />
|
||||||
|
</Button.KeyboardAccelerators>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<ListView
|
||||||
|
Margin="48,56"
|
||||||
|
ItemsSource="{x:Bind ViewModel.AppSettings.WindowBoundsRecords, Mode=OneWay}"
|
||||||
|
SelectedItem="{x:Bind ViewModel.LiveStates.LyricsWindowStatus, Mode=TwoWay}">
|
||||||
|
<ItemsControl.ItemsPanel>
|
||||||
|
<ItemsPanelTemplate>
|
||||||
|
<controls:WrapPanel HorizontalSpacing="0" VerticalSpacing="0" />
|
||||||
|
</ItemsPanelTemplate>
|
||||||
|
</ItemsControl.ItemsPanel>
|
||||||
|
<ListView.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<Grid
|
||||||
|
Margin="0,10"
|
||||||
|
Padding="5"
|
||||||
|
AllowFocusOnInteraction="True"
|
||||||
|
CornerRadius="4"
|
||||||
|
Tapped="Grid_Tapped">
|
||||||
|
<uc:DemoWindowGrid LyricsWindowStatus="{Binding}" />
|
||||||
|
</Grid>
|
||||||
|
</DataTemplate>
|
||||||
|
</ListView.ItemTemplate>
|
||||||
|
</ListView>
|
||||||
|
|
||||||
|
<StackPanel
|
||||||
|
Margin="20"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
VerticalAlignment="Bottom"
|
||||||
|
Orientation="Horizontal"
|
||||||
|
Spacing="6">
|
||||||
|
<FontIcon
|
||||||
|
Margin="0,1,0,0"
|
||||||
|
FontFamily="{StaticResource IconFontFamily}"
|
||||||
|
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||||
|
Glyph="" />
|
||||||
|
<TextBlock x:Uid="LyricsWindowSwitchWindowHelp" Foreground="{ThemeResource TextFillColorSecondaryBrush}" />
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
</UserControl>
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
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;
|
||||||
|
using Microsoft.UI.Xaml.Controls.Primitives;
|
||||||
|
using Microsoft.UI.Xaml.Data;
|
||||||
|
using Microsoft.UI.Xaml.Input;
|
||||||
|
using Microsoft.UI.Xaml.Media;
|
||||||
|
using Microsoft.UI.Xaml.Navigation;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices.WindowsRuntime;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Windows.Foundation;
|
||||||
|
using Windows.Foundation.Collections;
|
||||||
|
|
||||||
|
// To learn more about WinUI, the WinUI project structure,
|
||||||
|
// and more about our project templates, see: http://aka.ms/winui-project-info.
|
||||||
|
|
||||||
|
namespace BetterLyrics.WinUI3.Controls
|
||||||
|
{
|
||||||
|
public sealed partial class LyricsWindowSwitchControl : UserControl
|
||||||
|
{
|
||||||
|
public LyricsWindowSwitchControlViewModel ViewModel => (LyricsWindowSwitchControlViewModel)DataContext;
|
||||||
|
|
||||||
|
public LyricsWindowSwitchControl()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
DataContext = Ioc.Default.GetRequiredService<LyricsWindowSwitchControlViewModel>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void Grid_Tapped(object sender, TappedRoutedEventArgs e)
|
||||||
|
{
|
||||||
|
await HideAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void Button_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
await HideAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task HideAsync()
|
||||||
|
{
|
||||||
|
var lyricsWindowSwitchWindow = WindowHelper.GetWindowByWindowType<LyricsWindowSwitchWindow>();
|
||||||
|
lyricsWindowSwitchWindow?.ViewModel.RootGridOpacity = 0;
|
||||||
|
await Task.Delay(300);
|
||||||
|
WindowHelper.HideWindow<LyricsWindowSwitchWindow>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,71 +14,74 @@
|
|||||||
<Grid>
|
<Grid>
|
||||||
<ScrollViewer Style="{StaticResource SettingsScrollViewerStyle}">
|
<ScrollViewer Style="{StaticResource SettingsScrollViewerStyle}">
|
||||||
<Grid Style="{StaticResource SettingsGridStyle}">
|
<Grid Style="{StaticResource SettingsGridStyle}">
|
||||||
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
|
<StackPanel>
|
||||||
|
|
||||||
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||||
<controls:SettingsExpander
|
|
||||||
x:Uid="SettingsPageMusicLib"
|
<controls:SettingsCard x:Uid="SettingsPageMusicLib" HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}" />
|
||||||
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
|
||||||
Glyph=}"
|
<InfoBar
|
||||||
IsExpanded="True"
|
x:Uid="SettingsPageRemoveInfo"
|
||||||
ItemsSource="{x:Bind ViewModel.AppSettings.LocalMediaFolders, Mode=OneWay}">
|
BorderThickness="0"
|
||||||
<controls:SettingsExpander.ItemTemplate>
|
CornerRadius="0"
|
||||||
|
IsClosable="False"
|
||||||
|
IsOpen="True"
|
||||||
|
Severity="Success">
|
||||||
|
<interactivity:Interaction.Behaviors>
|
||||||
|
<interactivity:DataTriggerBehavior
|
||||||
|
Binding="{x:Bind ViewModel.AppSettings.LocalMediaFolders.Count, Mode=OneWay}"
|
||||||
|
ComparisonCondition="Equal"
|
||||||
|
Value="0">
|
||||||
|
<interactivity:ChangePropertyAction PropertyName="Visibility" Value="Collapsed" />
|
||||||
|
</interactivity:DataTriggerBehavior>
|
||||||
|
<interactivity:DataTriggerBehavior
|
||||||
|
Binding="{x:Bind ViewModel.AppSettings.LocalMediaFolders.Count, Mode=OneWay}"
|
||||||
|
ComparisonCondition="NotEqual"
|
||||||
|
Value="0">
|
||||||
|
<interactivity:ChangePropertyAction PropertyName="Visibility" Value="Visible" />
|
||||||
|
</interactivity:DataTriggerBehavior>
|
||||||
|
</interactivity:Interaction.Behaviors>
|
||||||
|
</InfoBar>
|
||||||
|
|
||||||
|
<ListView
|
||||||
|
ItemContainerStyle="{StaticResource ListViewStretchedItemContainerStyle}"
|
||||||
|
ItemsSource="{x:Bind ViewModel.AppSettings.LocalMediaFolders, Mode=OneWay}"
|
||||||
|
SelectionMode="None">
|
||||||
|
<ListView.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<controls:SettingsCard>
|
<controls:SettingsExpander>
|
||||||
<controls:SettingsCard.Header>
|
<controls:SettingsExpander.Header>
|
||||||
<HyperlinkButton
|
<HyperlinkButton
|
||||||
Click="LocalFolderHyperlinkButton_Click"
|
Click="LocalFolderHyperlinkButton_Click"
|
||||||
Content="{Binding Path, Mode=OneWay}"
|
Content="{Binding Path, Mode=OneWay}"
|
||||||
Tag="{Binding Path, Mode=OneWay}" />
|
Tag="{Binding Path, Mode=OneWay}" />
|
||||||
</controls:SettingsCard.Header>
|
</controls:SettingsExpander.Header>
|
||||||
<StackPanel Orientation="Horizontal">
|
<ToggleSwitch IsOn="{Binding IsEnabled, Mode=TwoWay}" />
|
||||||
<HyperlinkButton
|
<controls:SettingsExpander.Items>
|
||||||
x:Uid="SettingsPageRemovePath"
|
<controls:SettingsCard>
|
||||||
Click="SettingsPageRemovePathButton_Click"
|
<controls:SettingsCard.Header>
|
||||||
Tag="{Binding}" />
|
<HyperlinkButton
|
||||||
<ToggleSwitch DataContext="{Binding}" IsOn="{Binding IsEnabled, Mode=TwoWay}" />
|
x:Uid="SettingsPageRemovePath"
|
||||||
</StackPanel>
|
Click="SettingsPageRemovePathButton_Click"
|
||||||
</controls:SettingsCard>
|
Tag="{Binding}" />
|
||||||
|
</controls:SettingsCard.Header>
|
||||||
|
</controls:SettingsCard>
|
||||||
|
<controls:SettingsCard x:Uid="SettingsPageMusicLibRealTimeWatch">
|
||||||
|
<ToggleSwitch IsOn="{Binding IsRealTimeWatchEnabled, Mode=TwoWay}" />
|
||||||
|
</controls:SettingsCard>
|
||||||
|
</controls:SettingsExpander.Items>
|
||||||
|
</controls:SettingsExpander>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</controls:SettingsExpander.ItemTemplate>
|
</ListView.ItemTemplate>
|
||||||
<controls:SettingsExpander.ItemsHeader>
|
</ListView>
|
||||||
<InfoBar
|
|
||||||
x:Uid="SettingsPageRemoveInfo"
|
|
||||||
BorderThickness="0"
|
|
||||||
CornerRadius="0"
|
|
||||||
IsClosable="False"
|
|
||||||
IsOpen="True"
|
|
||||||
Severity="Success">
|
|
||||||
|
|
||||||
<interactivity:Interaction.Behaviors>
|
<controls:SettingsCard x:Uid="SettingsPageAddFolder" Style="{StaticResource DefaultSettingsExpanderItemStyle}">
|
||||||
|
<Button
|
||||||
|
x:Uid="SettingsPageAddFolderButton"
|
||||||
|
Command="{x:Bind ViewModel.SelectAndAddFolderCommand}"
|
||||||
|
CommandParameter="{Binding ElementName=RootGrid}" />
|
||||||
|
</controls:SettingsCard>
|
||||||
|
|
||||||
<interactivity:DataTriggerBehavior
|
|
||||||
Binding="{x:Bind ViewModel.AppSettings.LocalMediaFolders.Count, Mode=OneWay}"
|
|
||||||
ComparisonCondition="Equal"
|
|
||||||
Value="0">
|
|
||||||
<interactivity:ChangePropertyAction PropertyName="Visibility" Value="Collapsed" />
|
|
||||||
</interactivity:DataTriggerBehavior>
|
|
||||||
<interactivity:DataTriggerBehavior
|
|
||||||
Binding="{x:Bind ViewModel.AppSettings.LocalMediaFolders.Count, Mode=OneWay}"
|
|
||||||
ComparisonCondition="NotEqual"
|
|
||||||
Value="0">
|
|
||||||
<interactivity:ChangePropertyAction PropertyName="Visibility" Value="Visible" />
|
|
||||||
</interactivity:DataTriggerBehavior>
|
|
||||||
|
|
||||||
</interactivity:Interaction.Behaviors>
|
|
||||||
|
|
||||||
</InfoBar>
|
|
||||||
</controls:SettingsExpander.ItemsHeader>
|
|
||||||
<controls:SettingsExpander.ItemsFooter>
|
|
||||||
<controls:SettingsCard x:Uid="SettingsPageAddFolder" Style="{StaticResource DefaultSettingsExpanderItemStyle}">
|
|
||||||
<Button
|
|
||||||
x:Uid="SettingsPageAddFolderButton"
|
|
||||||
Command="{x:Bind ViewModel.SelectAndAddFolderCommand}"
|
|
||||||
CommandParameter="{Binding ElementName=RootGrid}" />
|
|
||||||
</controls:SettingsCard>
|
|
||||||
</controls:SettingsExpander.ItemsFooter>
|
|
||||||
</controls:SettingsExpander>
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
|
|||||||
@@ -18,31 +18,6 @@
|
|||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<Grid Grid.Column="0">
|
<Grid Grid.Column="0">
|
||||||
<NavigationView
|
|
||||||
VerticalAlignment="Top"
|
|
||||||
Background="Transparent"
|
|
||||||
IsBackButtonVisible="Collapsed"
|
|
||||||
IsBackEnabled="False"
|
|
||||||
IsSettingsVisible="False"
|
|
||||||
MenuItemsSource="{x:Bind ViewModel.AppSettings.MediaSourceProvidersInfo, Mode=OneWay}"
|
|
||||||
PaneDisplayMode="Top"
|
|
||||||
SelectedItem="{x:Bind ViewModel.SelectedMediaSourceProvider, Mode=TwoWay}">
|
|
||||||
<NavigationView.MenuItemTemplate>
|
|
||||||
<DataTemplate x:DataType="models:MediaSourceProviderInfo">
|
|
||||||
<NavigationViewItem>
|
|
||||||
<NavigationViewItem.Icon>
|
|
||||||
<ImageIcon Source="{Binding Provider, Converter={StaticResource MediaSourceProviderToLogoUriConverter}, Mode=OneWay}" />
|
|
||||||
</NavigationViewItem.Icon>
|
|
||||||
<NavigationViewItem.Content>
|
|
||||||
<TextBlock
|
|
||||||
MaxWidth="200"
|
|
||||||
Text="{Binding Provider, Converter={StaticResource MediaSourceProviderToDisplayedNameConverter}, Mode=OneWay}"
|
|
||||||
TextWrapping="Wrap" />
|
|
||||||
</NavigationViewItem.Content>
|
|
||||||
</NavigationViewItem>
|
|
||||||
</DataTemplate>
|
|
||||||
</NavigationView.MenuItemTemplate>
|
|
||||||
</NavigationView>
|
|
||||||
<ScrollViewer Margin="0,72,0,0" Style="{StaticResource SettingsScrollViewerStyle}">
|
<ScrollViewer Margin="0,72,0,0" Style="{StaticResource SettingsScrollViewerStyle}">
|
||||||
<Grid Style="{StaticResource SettingsGridStyle}">
|
<Grid Style="{StaticResource SettingsGridStyle}">
|
||||||
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
|
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
|
||||||
@@ -56,16 +31,20 @@
|
|||||||
</controls:SettingsCard>
|
</controls:SettingsCard>
|
||||||
|
|
||||||
<!-- 时间轴相关配置 -->
|
<!-- 时间轴相关配置 -->
|
||||||
<controls:SettingsCard x:Uid="SettingsPageLyricsTimelineThreshold">
|
<controls:SettingsExpander x:Uid="SettingsPageLyricsTimeline" IsExpanded="True">
|
||||||
<local:ExtendedSlider
|
<ToggleSwitch IsOn="{x:Bind ViewModel.SelectedMediaSourceProvider.IsTimelineSyncEnabled, Mode=TwoWay}" />
|
||||||
x:Uid="SettingsPageLyricsTimelineThresholdReset"
|
<controls:SettingsExpander.Items>
|
||||||
Frequency="100"
|
<controls:SettingsCard x:Uid="SettingsPageLyricsTimelineThreshold" IsEnabled="{x:Bind ViewModel.SelectedMediaSourceProvider.IsTimelineSyncEnabled, Mode=OneWay}">
|
||||||
Maximum="1000"
|
<local:ExtendedSlider
|
||||||
Minimum="0"
|
Frequency="100"
|
||||||
ResetButtonVisibility="Collapsed"
|
Maximum="1000"
|
||||||
Unit="ms"
|
Minimum="0"
|
||||||
Value="{x:Bind ViewModel.SelectedMediaSourceProvider.TimelineSyncThreshold, Mode=TwoWay}" />
|
ResetButtonVisibility="Collapsed"
|
||||||
</controls:SettingsCard>
|
Unit="ms"
|
||||||
|
Value="{x:Bind ViewModel.SelectedMediaSourceProvider.TimelineSyncThreshold, Mode=TwoWay}" />
|
||||||
|
</controls:SettingsCard>
|
||||||
|
</controls:SettingsExpander.Items>
|
||||||
|
</controls:SettingsExpander>
|
||||||
<controls:SettingsExpander x:Uid="MainPagePositionOffsetSlider" IsExpanded="True">
|
<controls:SettingsExpander x:Uid="MainPagePositionOffsetSlider" IsExpanded="True">
|
||||||
<local:ExtendedSlider
|
<local:ExtendedSlider
|
||||||
x:Uid="SettingsPagePositionOffsetReset"
|
x:Uid="SettingsPagePositionOffsetReset"
|
||||||
@@ -143,6 +122,42 @@
|
|||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
|
|
||||||
|
<!-- 播放源列表 -->
|
||||||
|
<ListView
|
||||||
|
x:Name="MediaSourceProvidersListView"
|
||||||
|
VerticalAlignment="Top"
|
||||||
|
AllowDrop="True"
|
||||||
|
CanDragItems="True"
|
||||||
|
CanReorderItems="True"
|
||||||
|
DragItemsCompleted="MediaSourceProvidersListView_DragItemsCompleted"
|
||||||
|
ItemsSource="{x:Bind ViewModel.AppSettings.MediaSourceProvidersInfo, Mode=OneWay}"
|
||||||
|
ScrollViewer.HorizontalScrollBarVisibility="Hidden"
|
||||||
|
ScrollViewer.HorizontalScrollMode="Enabled"
|
||||||
|
ScrollViewer.VerticalScrollBarVisibility="Disabled"
|
||||||
|
ScrollViewer.VerticalScrollMode="Disabled"
|
||||||
|
SelectedItem="{x:Bind ViewModel.SelectedMediaSourceProvider, Mode=TwoWay}">
|
||||||
|
<ListView.ItemsPanel>
|
||||||
|
<ItemsPanelTemplate>
|
||||||
|
<ItemsStackPanel Orientation="Horizontal" />
|
||||||
|
</ItemsPanelTemplate>
|
||||||
|
</ListView.ItemsPanel>
|
||||||
|
<ListView.ItemTemplate>
|
||||||
|
<DataTemplate x:DataType="models:MediaSourceProviderInfo">
|
||||||
|
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||||
|
<FontIcon
|
||||||
|
FontFamily="Segoe UI Symbol"
|
||||||
|
FontSize="12"
|
||||||
|
Glyph="⠿" />
|
||||||
|
<ImageIcon Height="16" Source="{Binding Provider, Converter={StaticResource MediaSourceProviderToLogoUriConverter}, Mode=OneWay}" />
|
||||||
|
<TextBlock
|
||||||
|
MaxWidth="200"
|
||||||
|
Text="{Binding Provider, Converter={StaticResource MediaSourceProviderToDisplayedNameConverter}, Mode=OneWay}"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
</DataTemplate>
|
||||||
|
</ListView.ItemTemplate>
|
||||||
|
</ListView>
|
||||||
<interactivity:Interaction.Behaviors>
|
<interactivity:Interaction.Behaviors>
|
||||||
<interactivity:DataTriggerBehavior
|
<interactivity:DataTriggerBehavior
|
||||||
Binding="{x:Bind ViewModel.AppSettings.MediaSourceProvidersInfo.Count, Mode=OneWay}"
|
Binding="{x:Bind ViewModel.AppSettings.MediaSourceProvidersInfo.Count, Mode=OneWay}"
|
||||||
@@ -158,6 +173,7 @@
|
|||||||
</interactivity:DataTriggerBehavior>
|
</interactivity:DataTriggerBehavior>
|
||||||
</interactivity:Interaction.Behaviors>
|
</interactivity:Interaction.Behaviors>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<StackPanel
|
<StackPanel
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
@@ -187,6 +203,132 @@
|
|||||||
<ScrollViewer Style="{StaticResource SettingsScrollViewerStyle}">
|
<ScrollViewer Style="{StaticResource SettingsScrollViewerStyle}">
|
||||||
<Grid Style="{StaticResource SettingsGridStyle}">
|
<Grid Style="{StaticResource SettingsGridStyle}">
|
||||||
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
|
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
|
||||||
|
|
||||||
|
<!-- 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
|
||||||
|
x:Uid="LyricsPageTranslationEnabled"
|
||||||
|
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||||
|
Glyph=}"
|
||||||
|
IsExpanded="True">
|
||||||
|
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.TranslationSettings.IsTranslationEnabled, Mode=TwoWay}" />
|
||||||
|
<controls:SettingsExpander.Items>
|
||||||
|
<controls:SettingsCard x:Uid="SettingsPageTargetLanguage" IsEnabled="{x:Bind ViewModel.AppSettings.TranslationSettings.IsTranslationEnabled, Mode=OneWay}">
|
||||||
|
<ComboBox SelectedIndex="{x:Bind ViewModel.SelectedTargetLanguageIndex, Mode=TwoWay}">
|
||||||
|
<ComboBoxItem Content="العربية" Tag="ar" />
|
||||||
|
<ComboBoxItem Content="Azərbaycan dili" Tag="az" />
|
||||||
|
<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="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="Italiano" Tag="it" />
|
||||||
|
<ComboBoxItem Content="日本語" Tag="ja" />
|
||||||
|
<ComboBoxItem Content="한국어" Tag="ko" />
|
||||||
|
<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="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}">
|
||||||
|
<controls:SettingsCard.Description>
|
||||||
|
<HyperlinkButton Margin="0,6,0,0" NavigateUri="https://github.com/LibreTranslate/LibreTranslate">
|
||||||
|
<TextBlock
|
||||||
|
x:Uid="SettingsPageTranslationInfoLink"
|
||||||
|
FontSize="14"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
|
</HyperlinkButton>
|
||||||
|
</controls:SettingsCard.Description>
|
||||||
|
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.TranslationSettings.IsLibreTranslateEnabled, Mode=TwoWay}" />
|
||||||
|
</controls:SettingsCard>
|
||||||
|
<controls:SettingsCard x:Uid="SettingsPageLibreTranslateServer" IsEnabled="{x:Bind ViewModel.AppSettings.TranslationSettings.IsLibreTranslateEnabled, Mode=OneWay}">
|
||||||
|
<StackPanel Orientation="Horizontal" Spacing="12">
|
||||||
|
<TextBox
|
||||||
|
x:Name="LibreTranslateServerTextBox"
|
||||||
|
IsEnabled="{x:Bind ViewModel.IsLibreTranslateServerTesting, Converter={StaticResource BoolNegationConverter}, Mode=OneWay}"
|
||||||
|
PlaceholderText="http://localhost:5000"
|
||||||
|
Text="{x:Bind ViewModel.AppSettings.TranslationSettings.LibreTranslateServer, Mode=TwoWay}" />
|
||||||
|
<Button
|
||||||
|
x:Uid="SettingsPageServerTestButton"
|
||||||
|
Command="{x:Bind ViewModel.LibreTranslateServerTestCommand}"
|
||||||
|
IsEnabled="{x:Bind ViewModel.IsLibreTranslateServerTesting, Converter={StaticResource BoolNegationConverter}, Mode=OneWay}" />
|
||||||
|
</StackPanel>
|
||||||
|
</controls:SettingsCard>
|
||||||
|
<controls:SettingsCard x:Uid="LyricsPageTranslationOnly" IsEnabled="{x:Bind ViewModel.AppSettings.TranslationSettings.IsTranslationEnabled, Mode=OneWay}">
|
||||||
|
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.TranslationSettings.ShowTranslationOnly, Mode=TwoWay}" />
|
||||||
|
</controls:SettingsCard>
|
||||||
|
</controls:SettingsExpander.Items>
|
||||||
|
</controls:SettingsExpander>
|
||||||
|
|
||||||
|
<!-- Lyrics phonetic -->
|
||||||
|
<controls:SettingsExpander
|
||||||
|
x:Uid="SettingsPageChinese"
|
||||||
|
IsEnabled="{x:Bind ViewModel.AppSettings.TranslationSettings.IsTranslationEnabled, Mode=OneWay}"
|
||||||
|
IsExpanded="True">
|
||||||
|
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.TranslationSettings.IsChineseRomanizationEnabled, Mode=TwoWay}" />
|
||||||
|
<controls:SettingsExpander.Items>
|
||||||
|
<controls:SettingsCard>
|
||||||
|
<ComboBox SelectedIndex="{x:Bind ViewModel.AppSettings.TranslationSettings.ChineseRomanization, Converter={StaticResource EnumToIntConverter}, Mode=TwoWay}">
|
||||||
|
<ComboBoxItem x:Uid="SettingsPagePinyin" />
|
||||||
|
<ComboBoxItem x:Uid="SettingsPageJyutping" />
|
||||||
|
</ComboBox>
|
||||||
|
</controls:SettingsCard>
|
||||||
|
</controls:SettingsExpander.Items>
|
||||||
|
</controls:SettingsExpander>
|
||||||
|
<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>
|
||||||
|
|
||||||
<!-- Last.fm -->
|
<!-- Last.fm -->
|
||||||
<TextBlock x:Uid="SettingsPageLastFM" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
<TextBlock x:Uid="SettingsPageLastFM" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||||
<controls:SettingsExpander
|
<controls:SettingsExpander
|
||||||
@@ -218,85 +360,7 @@
|
|||||||
</controls:SettingsCard>
|
</controls:SettingsCard>
|
||||||
</controls:SettingsExpander.Items>
|
</controls:SettingsExpander.Items>
|
||||||
</controls:SettingsExpander>
|
</controls:SettingsExpander>
|
||||||
<!-- Lyrics translation -->
|
|
||||||
<TextBlock x:Uid="SettingsPageTranslation" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
|
||||||
<controls:SettingsExpander
|
|
||||||
x:Uid="LyricsPageTranslationEnabled"
|
|
||||||
HeaderIcon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
|
||||||
Glyph=}"
|
|
||||||
IsExpanded="True">
|
|
||||||
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.TranslationSettings.IsTranslationEnabled, Mode=TwoWay}" />
|
|
||||||
<controls:SettingsExpander.Items>
|
|
||||||
<controls:SettingsCard x:Uid="SettingsPageTargetLanguage">
|
|
||||||
<ComboBox SelectedIndex="{x:Bind ViewModel.AppSettings.TranslationSettings.SelectedTargetLanguageIndex, Mode=TwoWay}">
|
|
||||||
<ComboBoxItem Content="العربية" Tag="ar" />
|
|
||||||
<ComboBoxItem Content="Azərbaycan dili" Tag="az" />
|
|
||||||
<ComboBoxItem Content="简体中文" Tag="zh-Hans" />
|
|
||||||
<ComboBoxItem Content="繁體中文" Tag="zh-Hant" />
|
|
||||||
<ComboBoxItem Content="Čeština" Tag="cs" />
|
|
||||||
<ComboBoxItem Content="Dansk" Tag="da" />
|
|
||||||
<ComboBoxItem Content="Nederlands" Tag="nl" />
|
|
||||||
<ComboBoxItem Content="English" Tag="en" />
|
|
||||||
<ComboBoxItem Content="Esperanto" Tag="eo" />
|
|
||||||
<ComboBoxItem Content="Suomi" Tag="fi" />
|
|
||||||
<ComboBoxItem Content="Français" Tag="fr" />
|
|
||||||
<ComboBoxItem Content="Deutsch" Tag="de" />
|
|
||||||
<ComboBoxItem Content="Ελληνικά" Tag="el" />
|
|
||||||
<ComboBoxItem Content="עברית" Tag="he" />
|
|
||||||
<ComboBoxItem Content="हिन्दी" Tag="hi" />
|
|
||||||
<ComboBoxItem Content="Magyar" Tag="hu" />
|
|
||||||
<ComboBoxItem Content="Bahasa Indonesia" Tag="id" />
|
|
||||||
<ComboBoxItem Content="Gaeilge" Tag="ga" />
|
|
||||||
<ComboBoxItem Content="Italiano" Tag="it" />
|
|
||||||
<ComboBoxItem Content="日本語" Tag="ja" />
|
|
||||||
<ComboBoxItem Content="한국어" Tag="ko" />
|
|
||||||
<ComboBoxItem Content="فارسی" Tag="fa" />
|
|
||||||
<ComboBoxItem Content="Polski" Tag="pl" />
|
|
||||||
<ComboBoxItem Content="Português" Tag="pt" />
|
|
||||||
<ComboBoxItem Content="Русский" Tag="ru" />
|
|
||||||
<ComboBoxItem Content="Slovenčina" Tag="sk" />
|
|
||||||
<ComboBoxItem Content="Español" Tag="es" />
|
|
||||||
<ComboBoxItem Content="Svenska" Tag="sv" />
|
|
||||||
<ComboBoxItem Content="Türkçe" Tag="tr" />
|
|
||||||
<ComboBoxItem Content="Українська" Tag="uk" />
|
|
||||||
<ComboBoxItem Content="Tiếng Việt" Tag="vi" />
|
|
||||||
</ComboBox>
|
|
||||||
</controls:SettingsCard>
|
|
||||||
<controls:SettingsCard x:Uid="SettingsPageTranslationConfig">
|
|
||||||
<controls:SettingsCard.Description>
|
|
||||||
<HyperlinkButton Margin="0,6,0,0" NavigateUri="https://github.com/LibreTranslate/LibreTranslate">
|
|
||||||
<TextBlock
|
|
||||||
x:Uid="SettingsPageTranslationInfoLink"
|
|
||||||
FontSize="14"
|
|
||||||
TextWrapping="Wrap" />
|
|
||||||
</HyperlinkButton>
|
|
||||||
</controls:SettingsCard.Description>
|
|
||||||
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.TranslationSettings.IsLibreTranslateEnabled, Mode=TwoWay}" />
|
|
||||||
</controls:SettingsCard>
|
|
||||||
<controls:SettingsCard x:Uid="SettingsPageLibreTranslateServer" IsEnabled="{x:Bind ViewModel.AppSettings.TranslationSettings.IsLibreTranslateEnabled, Mode=OneWay}">
|
|
||||||
<StackPanel Orientation="Horizontal" Spacing="12">
|
|
||||||
<TextBox
|
|
||||||
x:Name="LibreTranslateServerTextBox"
|
|
||||||
IsEnabled="{x:Bind ViewModel.IsLibreTranslateServerTesting, Converter={StaticResource BoolNegationConverter}, Mode=OneWay}"
|
|
||||||
PlaceholderText="http://localhost:5000"
|
|
||||||
Text="{x:Bind ViewModel.AppSettings.TranslationSettings.LibreTranslateServer, Mode=TwoWay}" />
|
|
||||||
<Button
|
|
||||||
x:Uid="SettingsPageServerTestButton"
|
|
||||||
Command="{x:Bind ViewModel.LibreTranslateServerTestCommand}"
|
|
||||||
IsEnabled="{x:Bind ViewModel.IsLibreTranslateServerTesting, Converter={StaticResource BoolNegationConverter}, Mode=OneWay}" />
|
|
||||||
</StackPanel>
|
|
||||||
</controls:SettingsCard>
|
|
||||||
<controls:SettingsCard x:Uid="LyricsPageTranslationOnly" IsEnabled="{x:Bind ViewModel.AppSettings.TranslationSettings.IsTranslationEnabled, Mode=OneWay}">
|
|
||||||
<ToggleSwitch IsOn="{x:Bind ViewModel.AppSettings.TranslationSettings.ShowTranslationOnly, Mode=TwoWay}" />
|
|
||||||
</controls:SettingsCard>
|
|
||||||
</controls:SettingsExpander.Items>
|
|
||||||
</controls:SettingsExpander>
|
|
||||||
<controls:SettingsCard x:Uid="LyricsPageLyricsProviderPrefix">
|
|
||||||
<TextBlock Foreground="{ThemeResource TextFillColorSecondaryBrush}" Text="{x:Bind ViewModel.LyricsSearchProvider, Mode=OneWay, Converter={StaticResource LyricsSearchProviderToDisplayNameConverter}}" />
|
|
||||||
</controls:SettingsCard>
|
|
||||||
<controls:SettingsCard x:Uid="LyricsPageTranslationProviderPrefix">
|
|
||||||
<TextBlock Foreground="{ThemeResource TextFillColorSecondaryBrush}" Text="{x:Bind ViewModel.TranslationSearchProvider, Mode=OneWay, Converter={StaticResource TranslationSearchProviderToDisplayNameConverter}}" />
|
|
||||||
</controls:SettingsCard>
|
|
||||||
<!-- LX music server -->
|
<!-- LX music server -->
|
||||||
<TextBlock x:Uid="SettingsPageLXMusicServer" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
<TextBlock x:Uid="SettingsPageLXMusicServer" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||||
<controls:SettingsCard>
|
<controls:SettingsCard>
|
||||||
@@ -311,6 +375,28 @@
|
|||||||
IsEnabled="{x:Bind ViewModel.IsLXMusicServerTesting, Converter={StaticResource BoolNegationConverter}, Mode=OneWay}" />
|
IsEnabled="{x:Bind ViewModel.IsLXMusicServerTesting, Converter={StaticResource BoolNegationConverter}, Mode=OneWay}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</controls:SettingsCard>
|
</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=}"
|
||||||
|
Style="{StaticResource GhostButtonStyle}" />
|
||||||
|
</StackPanel>
|
||||||
|
</controls:SettingsCard>
|
||||||
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
|
|||||||
@@ -41,5 +41,11 @@ namespace BetterLyrics.WinUI3.Controls
|
|||||||
// <20><> LyricsSearchProvidersInfo <20><><EFBFBD><EFBFBD> CollectionChanged <20>¼<EFBFBD>
|
// <20><> LyricsSearchProvidersInfo <20><><EFBFBD><EFBFBD> CollectionChanged <20>¼<EFBFBD>
|
||||||
ViewModel.SelectedMediaSourceProvider?.LyricsSearchProvidersInfo?.Refresh();
|
ViewModel.SelectedMediaSourceProvider?.LyricsSearchProvidersInfo?.Refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void MediaSourceProvidersListView_DragItemsCompleted(ListViewBase sender, DragItemsCompletedEventArgs args)
|
||||||
|
{
|
||||||
|
// <20><> MediaSourceProvidersInfo <20><><EFBFBD><EFBFBD> CollectionChanged <20>¼<EFBFBD>
|
||||||
|
ViewModel.AppSettings.MediaSourceProvidersInfo?.Refresh();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<UserControl
|
||||||
|
x:Class="BetterLyrics.WinUI3.Controls.ShortcutTextBox"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:local="using:BetterLyrics.WinUI3.Controls"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
|
||||||
|
<Grid>
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBox
|
||||||
|
x:Name="TextBox"
|
||||||
|
IsReadOnly="True"
|
||||||
|
KeyDown="TextBox_KeyDown"
|
||||||
|
Loaded="TextBox_Loaded" />
|
||||||
|
<Button
|
||||||
|
Margin="3,0,0,0"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
Click="ClearButton_Click"
|
||||||
|
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||||
|
FontSize=12,
|
||||||
|
Glyph=}"
|
||||||
|
Style="{StaticResource GhostButtonStyle}" />
|
||||||
|
<Button
|
||||||
|
Margin="3,0,0,0"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
Click="CheckButton_Click"
|
||||||
|
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||||
|
FontSize=12,
|
||||||
|
Glyph=}"
|
||||||
|
Style="{StaticResource GhostButtonStyle}" />
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
using BetterLyrics.WinUI3.Helper;
|
||||||
|
using Microsoft.UI.Input;
|
||||||
|
using Microsoft.UI.Xaml;
|
||||||
|
using Microsoft.UI.Xaml.Controls;
|
||||||
|
using Microsoft.UI.Xaml.Controls.Primitives;
|
||||||
|
using Microsoft.UI.Xaml.Data;
|
||||||
|
using Microsoft.UI.Xaml.Input;
|
||||||
|
using Microsoft.UI.Xaml.Media;
|
||||||
|
using Microsoft.UI.Xaml.Navigation;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices.WindowsRuntime;
|
||||||
|
using Windows.Foundation;
|
||||||
|
using Windows.Foundation.Collections;
|
||||||
|
using Windows.UI.Core;
|
||||||
|
|
||||||
|
// 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 ShortcutTextBox : UserControl
|
||||||
|
{
|
||||||
|
public ShortcutTextBox()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static readonly DependencyProperty ShortcutProperty =
|
||||||
|
DependencyProperty.Register(nameof(Shortcut), typeof(List<string>), typeof(ShortcutTextBox), new PropertyMetadata(default));
|
||||||
|
|
||||||
|
public List<string> Shortcut
|
||||||
|
{
|
||||||
|
get => (List<string>)GetValue(ShortcutProperty);
|
||||||
|
set => SetValue(ShortcutProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TextBox_KeyDown(object sender, KeyRoutedEventArgs e)
|
||||||
|
{
|
||||||
|
List<string> shortcut = [];
|
||||||
|
|
||||||
|
bool ctrl = InputKeyboardSource.GetKeyStateForCurrentThread(Windows.System.VirtualKey.Control).HasFlag(CoreVirtualKeyStates.Down);
|
||||||
|
bool shift = InputKeyboardSource.GetKeyStateForCurrentThread(Windows.System.VirtualKey.Shift).HasFlag(CoreVirtualKeyStates.Down);
|
||||||
|
bool alt = InputKeyboardSource.GetKeyStateForCurrentThread(Windows.System.VirtualKey.Menu).HasFlag(CoreVirtualKeyStates.Down);
|
||||||
|
bool win = InputKeyboardSource.GetKeyStateForCurrentThread(Windows.System.VirtualKey.LeftWindows).HasFlag(CoreVirtualKeyStates.Down) ||
|
||||||
|
InputKeyboardSource.GetKeyStateForCurrentThread(Windows.System.VirtualKey.RightWindows).HasFlag(CoreVirtualKeyStates.Down);
|
||||||
|
|
||||||
|
if (ctrl)
|
||||||
|
{
|
||||||
|
shortcut.Add("Ctrl");
|
||||||
|
}
|
||||||
|
if (shift)
|
||||||
|
{
|
||||||
|
shortcut.Add("Shift");
|
||||||
|
}
|
||||||
|
if (alt)
|
||||||
|
{
|
||||||
|
shortcut.Add("Alt");
|
||||||
|
}
|
||||||
|
if (win)
|
||||||
|
{
|
||||||
|
shortcut.Add("Win");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.Key != Windows.System.VirtualKey.Control &&
|
||||||
|
e.Key != Windows.System.VirtualKey.Shift &&
|
||||||
|
e.Key != Windows.System.VirtualKey.Menu &&
|
||||||
|
e.Key != Windows.System.VirtualKey.LeftWindows &&
|
||||||
|
e.Key != Windows.System.VirtualKey.RightWindows)
|
||||||
|
{
|
||||||
|
shortcut.Add(e.Key.ToString());
|
||||||
|
}
|
||||||
|
Shortcut = shortcut;
|
||||||
|
|
||||||
|
UpdateTextBox();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateTextBox()
|
||||||
|
{
|
||||||
|
TextBox.Text = string.Join(" + ", Shortcut);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TextBox_Loaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
UpdateTextBox();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ClearButton_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Shortcut = [];
|
||||||
|
UpdateTextBox();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CheckButton_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
bool registered = GlobalHotKeyHelper.IsHotKeyRegistered(Shortcut);
|
||||||
|
if (registered)
|
||||||
|
{
|
||||||
|
App.Current.SettingsWindowNotificationPanel?.Notify(
|
||||||
|
App.ResourceLoader!.GetString("SettingsPageShortcutRegSuccessInfo"),
|
||||||
|
InfoBarSeverity.Success);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
App.Current.SettingsWindowNotificationPanel?.Notify(
|
||||||
|
App.ResourceLoader!.GetString("SettingsPageShortcutRegFailInfo"),
|
||||||
|
InfoBarSeverity.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,9 +14,9 @@
|
|||||||
x:Name="TrayIcon"
|
x:Name="TrayIcon"
|
||||||
x:FieldModifier="public"
|
x:FieldModifier="public"
|
||||||
ContextMenuMode="SecondWindow"
|
ContextMenuMode="SecondWindow"
|
||||||
DoubleClickCommand="{x:Bind ViewModel.OpenLyricsWindowCommand}"
|
DoubleClickCommand="{x:Bind ViewModel.OpenLyricsCommand}"
|
||||||
IconSource="ms-appx:///Assets/Logo.ico"
|
IconSource="ms-appx:///Assets/Logo.ico"
|
||||||
LeftClickCommand="{x:Bind ViewModel.OpenLyricsWindowCommand}"
|
LeftClickCommand="{x:Bind ViewModel.OpenLyricsCommand}"
|
||||||
NoLeftClickDelay="True"
|
NoLeftClickDelay="True"
|
||||||
ToolTipText="{x:Bind ViewModel.ToolTipText, Mode=OneWay}">
|
ToolTipText="{x:Bind ViewModel.ToolTipText, Mode=OneWay}">
|
||||||
<tb:TaskbarIcon.ContextFlyout>
|
<tb:TaskbarIcon.ContextFlyout>
|
||||||
@@ -24,15 +24,46 @@
|
|||||||
AreOpenCloseAnimationsEnabled="True"
|
AreOpenCloseAnimationsEnabled="True"
|
||||||
LightDismissOverlayMode="On"
|
LightDismissOverlayMode="On"
|
||||||
ShowMode="TransientWithDismissOnPointerMoveAway">
|
ShowMode="TransientWithDismissOnPointerMoveAway">
|
||||||
<MenuFlyoutItem x:Uid="SystemTrayMusicGallery" Command="{x:Bind ViewModel.OpenMusicGalleryCommand}" />
|
<MenuFlyout.MenuFlyoutPresenterStyle>
|
||||||
<MenuFlyoutItem x:Uid="SystemTraySettings" Command="{x:Bind ViewModel.OpenSettingsCommand}" />
|
<Style BasedOn="{StaticResource DefaultMenuFlyoutPresenterStyle}" TargetType="MenuFlyoutPresenter">
|
||||||
<MenuFlyoutItem x:Uid="SystemTrayResetWindowPosition" Command="{x:Bind ViewModel.ResetWindowPositionCommand}" />
|
<Setter Property="MinWidth" Value="600" />
|
||||||
<MenuFlyoutItem x:Uid="SystemTrayRestart" Command="{x:Bind ViewModel.RestartAppCommand}" />
|
</Style>
|
||||||
<MenuFlyoutItem x:Uid="SystemTrayExit" Command="{x:Bind ViewModel.ExitAppCommand}" />
|
</MenuFlyout.MenuFlyoutPresenterStyle>
|
||||||
<MenuFlyoutItem
|
<MenuFlyoutItem
|
||||||
x:Uid="SystemTrayUnlock"
|
x:Uid="SystemTraySwitch"
|
||||||
Command="{x:Bind ViewModel.UnlockWindowCommand}"
|
Command="{x:Bind ViewModel.OpenLyricsWindowSwitchCommand}"
|
||||||
Visibility="{x:Bind ViewModel.IsLyricsWindowLocked, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}" />
|
Icon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||||
|
Glyph=}" />
|
||||||
|
<MenuFlyoutItem
|
||||||
|
x:Uid="SystemTrayLyrics"
|
||||||
|
Command="{x:Bind ViewModel.OpenLyricsCommand}"
|
||||||
|
Icon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||||
|
Glyph=}" />
|
||||||
|
<MenuFlyoutItem
|
||||||
|
x:Uid="SystemTrayMusicGallery"
|
||||||
|
Command="{x:Bind ViewModel.OpenMusicGalleryCommand}"
|
||||||
|
Icon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||||
|
Glyph=}" />
|
||||||
|
<MenuFlyoutItem
|
||||||
|
x:Uid="SystemTraySettings"
|
||||||
|
Command="{x:Bind ViewModel.OpenSettingsCommand}"
|
||||||
|
Icon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||||
|
Glyph=}" />
|
||||||
|
<MenuFlyoutItem
|
||||||
|
x:Uid="SystemTrayResetWindowPosition"
|
||||||
|
Command="{x:Bind ViewModel.ResetWindowPositionCommand}"
|
||||||
|
Icon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||||
|
Glyph=}" />
|
||||||
|
<MenuFlyoutItem
|
||||||
|
x:Uid="SystemTrayRestart"
|
||||||
|
Command="{x:Bind ViewModel.RestartAppCommand}"
|
||||||
|
Icon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||||
|
Glyph=}" />
|
||||||
|
<MenuFlyoutItem
|
||||||
|
x:Uid="SystemTrayExit"
|
||||||
|
Command="{x:Bind ViewModel.ExitAppCommand}"
|
||||||
|
Icon="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||||
|
Glyph=}" />
|
||||||
</MenuFlyout>
|
</MenuFlyout>
|
||||||
</tb:TaskbarIcon.ContextFlyout>
|
</tb:TaskbarIcon.ContextFlyout>
|
||||||
</tb:TaskbarIcon>
|
</tb:TaskbarIcon>
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
using Microsoft.UI.Xaml;
|
||||||
|
using Microsoft.UI.Xaml.Data;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace BetterLyrics.WinUI3.Converter
|
||||||
|
{
|
||||||
|
public partial class BoolNegationToVisibilityConverter : IValueConverter
|
||||||
|
{
|
||||||
|
public object Convert(object value, Type targetType, object parameter, string language)
|
||||||
|
{
|
||||||
|
if (value is bool boolValue)
|
||||||
|
{
|
||||||
|
return boolValue ? Visibility.Collapsed : Visibility.Visible;
|
||||||
|
}
|
||||||
|
return Visibility.Visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
using Microsoft.UI.Xaml.Data;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace BetterLyrics.WinUI3.Converter
|
||||||
|
{
|
||||||
|
public class BoolToOpacityConverter : IValueConverter
|
||||||
|
{
|
||||||
|
public object Convert(object value, Type targetType, object parameter, string language)
|
||||||
|
{
|
||||||
|
if (value is bool boolValue)
|
||||||
|
{
|
||||||
|
return boolValue ? 1.0 : 0.3;
|
||||||
|
}
|
||||||
|
return 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
using Microsoft.UI.Xaml.Data;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace BetterLyrics.WinUI3.Converter
|
||||||
|
{
|
||||||
|
public class FPSToTimeSpanConverter : IValueConverter
|
||||||
|
{
|
||||||
|
public object Convert(object value, Type targetType, object parameter, string language)
|
||||||
|
{
|
||||||
|
if (value is int fps)
|
||||||
|
{
|
||||||
|
return TimeSpan.FromSeconds(1.0 / fps);
|
||||||
|
}
|
||||||
|
return TimeSpan.FromSeconds(1.0 / 60);
|
||||||
|
}
|
||||||
|
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,6 +19,7 @@ namespace BetterLyrics.WinUI3.Converter
|
|||||||
LyricsSearchProvider.Netease => "网易云音乐",
|
LyricsSearchProvider.Netease => "网易云音乐",
|
||||||
LyricsSearchProvider.Kugou => "酷狗音乐",
|
LyricsSearchProvider.Kugou => "酷狗音乐",
|
||||||
LyricsSearchProvider.AmllTtmlDb => "amll-ttml-db",
|
LyricsSearchProvider.AmllTtmlDb => "amll-ttml-db",
|
||||||
|
LyricsSearchProvider.AppleMusic => "Apple Music",
|
||||||
LyricsSearchProvider.LocalLrcFile => App.ResourceLoader!.GetString("LyricsSearchProviderLocalLrcFile"),
|
LyricsSearchProvider.LocalLrcFile => App.ResourceLoader!.GetString("LyricsSearchProviderLocalLrcFile"),
|
||||||
LyricsSearchProvider.LocalMusicFile => App.ResourceLoader!.GetString("LyricsSearchProviderLocalMusicFile"),
|
LyricsSearchProvider.LocalMusicFile => App.ResourceLoader!.GetString("LyricsSearchProviderLocalMusicFile"),
|
||||||
LyricsSearchProvider.LocalEslrcFile => App.ResourceLoader!.GetString("LyricsSearchProviderEslrcFile"),
|
LyricsSearchProvider.LocalEslrcFile => App.ResourceLoader!.GetString("LyricsSearchProviderEslrcFile"),
|
||||||
|
|||||||
@@ -33,6 +33,10 @@ namespace BetterLyrics.WinUI3.Converter
|
|||||||
PlayerID.Edge => PlayerName.Edge,
|
PlayerID.Edge => PlayerName.Edge,
|
||||||
PlayerID.BetterLyrics => PlayerName.BetterLyrics,
|
PlayerID.BetterLyrics => PlayerName.BetterLyrics,
|
||||||
PlayerID.BetterLyricsDebug => PlayerName.BetterLyricsDebug,
|
PlayerID.BetterLyricsDebug => PlayerName.BetterLyricsDebug,
|
||||||
|
PlayerID.SaltPlayerForWindows => PlayerName.SaltPlayerForWindows,
|
||||||
|
PlayerID.MoeKoeMusic => PlayerName.MoeKoeMusic,
|
||||||
|
PlayerID.MoeKoeMusicAlternative => PlayerName.MoeKoeMusic,
|
||||||
|
PlayerID.Listen1 => PlayerName.Listen1,
|
||||||
_ => provider,
|
_ => provider,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,10 +2,6 @@
|
|||||||
using BetterLyrics.WinUI3.Helper;
|
using BetterLyrics.WinUI3.Helper;
|
||||||
using Microsoft.UI.Xaml.Data;
|
using Microsoft.UI.Xaml.Data;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace BetterLyrics.WinUI3.Converter
|
namespace BetterLyrics.WinUI3.Converter
|
||||||
{
|
{
|
||||||
@@ -19,6 +15,7 @@ namespace BetterLyrics.WinUI3.Converter
|
|||||||
{
|
{
|
||||||
PlayerID.Spotify => PathHelper.SpotifyLogoPath,
|
PlayerID.Spotify => PathHelper.SpotifyLogoPath,
|
||||||
PlayerID.AppleMusic => PathHelper.AppleMusicLogoPath,
|
PlayerID.AppleMusic => PathHelper.AppleMusicLogoPath,
|
||||||
|
PlayerID.AppleMusicAlternative => PathHelper.AppleMusicLogoPath,
|
||||||
PlayerID.iTunes => PathHelper.iTunesLogoPath,
|
PlayerID.iTunes => PathHelper.iTunesLogoPath,
|
||||||
PlayerID.KugouMusic => PathHelper.KugouMusicLogoPath,
|
PlayerID.KugouMusic => PathHelper.KugouMusicLogoPath,
|
||||||
PlayerID.NetEaseCloudMusic => PathHelper.NetEaseCloudMusicLogoPath,
|
PlayerID.NetEaseCloudMusic => PathHelper.NetEaseCloudMusicLogoPath,
|
||||||
@@ -33,6 +30,10 @@ namespace BetterLyrics.WinUI3.Converter
|
|||||||
PlayerID.Edge => PathHelper.EdgeLogoPath,
|
PlayerID.Edge => PathHelper.EdgeLogoPath,
|
||||||
PlayerID.BetterLyrics => PathHelper.LogoPath,
|
PlayerID.BetterLyrics => PathHelper.LogoPath,
|
||||||
PlayerID.BetterLyricsDebug => PathHelper.LogoPath,
|
PlayerID.BetterLyricsDebug => PathHelper.LogoPath,
|
||||||
|
PlayerID.SaltPlayerForWindows => PathHelper.SaltPlayerForWindowsLogoPath,
|
||||||
|
PlayerID.MoeKoeMusic => PathHelper.MoeKoeMusicLogoPath,
|
||||||
|
PlayerID.MoeKoeMusicAlternative => PathHelper.MoeKoeMusicLogoPath,
|
||||||
|
PlayerID.Listen1 => PathHelper.Listen1LogoPath,
|
||||||
_ => PathHelper.UnknownPlayerLogoPath,
|
_ => PathHelper.UnknownPlayerLogoPath,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
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
|
||||||
|
{
|
||||||
|
public class MillisecondsToFormattedTimeConverter : IValueConverter
|
||||||
|
{
|
||||||
|
public object Convert(object value, Type targetType, object parameter, string language)
|
||||||
|
{
|
||||||
|
if (value is int milliseconds)
|
||||||
|
{
|
||||||
|
return TimeSpan.FromMilliseconds(milliseconds).ToString(@"mm\:ss\.fff");
|
||||||
|
}
|
||||||
|
else if (value is double doubleMilliseconds)
|
||||||
|
{
|
||||||
|
return TimeSpan.FromMilliseconds(doubleMilliseconds).ToString(@"mm\:ss\.fff");
|
||||||
|
}
|
||||||
|
return value?.ToString() ?? "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
using Microsoft.UI.Xaml.Data;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace BetterLyrics.WinUI3.Converter
|
||||||
|
{
|
||||||
|
public class RectToMarginConverter : IValueConverter
|
||||||
|
{
|
||||||
|
public object Convert(object value, Type targetType, object parameter, string language)
|
||||||
|
{
|
||||||
|
if (value is Windows.Foundation.Rect rect)
|
||||||
|
{
|
||||||
|
return new Microsoft.UI.Xaml.Thickness(rect.X, rect.Y, 0, 0);
|
||||||
|
}
|
||||||
|
return new Microsoft.UI.Xaml.Thickness(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
using Microsoft.UI.Xaml.Data;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace BetterLyrics.WinUI3.Converter
|
||||||
|
{
|
||||||
|
public class ShortcutToStringConverter : IValueConverter
|
||||||
|
{
|
||||||
|
public object Convert(object value, Type targetType, object parameter, string language)
|
||||||
|
{
|
||||||
|
if (value is List<string> shortcut)
|
||||||
|
{
|
||||||
|
return string.Join(" + ", shortcut);
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,6 +19,7 @@ namespace BetterLyrics.WinUI3.Converter
|
|||||||
TranslationSearchProvider.Netease => "网易云音乐",
|
TranslationSearchProvider.Netease => "网易云音乐",
|
||||||
TranslationSearchProvider.Kugou => "酷狗音乐",
|
TranslationSearchProvider.Kugou => "酷狗音乐",
|
||||||
TranslationSearchProvider.AmllTtmlDb => "amll-ttml-db",
|
TranslationSearchProvider.AmllTtmlDb => "amll-ttml-db",
|
||||||
|
TranslationSearchProvider.AppleMusic => "Apple Music",
|
||||||
TranslationSearchProvider.LocalLrcFile => App.ResourceLoader!.GetString("LyricsSearchProviderLocalLrcFile"),
|
TranslationSearchProvider.LocalLrcFile => App.ResourceLoader!.GetString("LyricsSearchProviderLocalLrcFile"),
|
||||||
TranslationSearchProvider.LocalMusicFile => App.ResourceLoader!.GetString("LyricsSearchProviderLocalMusicFile"),
|
TranslationSearchProvider.LocalMusicFile => App.ResourceLoader!.GetString("LyricsSearchProviderLocalMusicFile"),
|
||||||
TranslationSearchProvider.LocalEslrcFile => App.ResourceLoader!.GetString("LyricsSearchProviderEslrcFile"),
|
TranslationSearchProvider.LocalEslrcFile => App.ResourceLoader!.GetString("LyricsSearchProviderEslrcFile"),
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
// 2025/6/23 by Zhe Fang
|
|
||||||
|
|
||||||
namespace BetterLyrics.WinUI3.Enums
|
|
||||||
{
|
|
||||||
public enum AutoStartWindowType
|
|
||||||
{
|
|
||||||
StandardMode,
|
|
||||||
DockMode,
|
|
||||||
DesktopMode,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace BetterLyrics.WinUI3.Enums
|
||||||
|
{
|
||||||
|
public enum ChineseRomanization
|
||||||
|
{
|
||||||
|
Pinyin,
|
||||||
|
Jyutping,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -67,5 +67,16 @@ namespace BetterLyrics.WinUI3.Enums
|
|||||||
_ => ".*",
|
_ => ".*",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static LyricsSearchProvider? ToLyricsSearchProvider(this LyricsFormat format)
|
||||||
|
{
|
||||||
|
return format switch
|
||||||
|
{
|
||||||
|
LyricsFormat.Lrc => LyricsSearchProvider.LocalLrcFile,
|
||||||
|
LyricsFormat.Eslrc => LyricsSearchProvider.LocalEslrcFile,
|
||||||
|
LyricsFormat.Ttml => LyricsSearchProvider.LocalTtmlFile,
|
||||||
|
_ => null,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ namespace BetterLyrics.WinUI3.Enums
|
|||||||
LocalLrcFile,
|
LocalLrcFile,
|
||||||
LocalEslrcFile,
|
LocalEslrcFile,
|
||||||
LocalTtmlFile,
|
LocalTtmlFile,
|
||||||
|
AppleMusic,
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class LyricsSearchProviderExtensions
|
public static class LyricsSearchProviderExtensions
|
||||||
@@ -28,6 +29,7 @@ namespace BetterLyrics.WinUI3.Enums
|
|||||||
LyricsSearchProvider.Netease => PathHelper.NeteaseLyricsCacheDirectory,
|
LyricsSearchProvider.Netease => PathHelper.NeteaseLyricsCacheDirectory,
|
||||||
LyricsSearchProvider.Kugou => PathHelper.KugouLyricsCacheDirectory,
|
LyricsSearchProvider.Kugou => PathHelper.KugouLyricsCacheDirectory,
|
||||||
LyricsSearchProvider.AmllTtmlDb => PathHelper.AmllTtmlDbLyricsCacheDirectory,
|
LyricsSearchProvider.AmllTtmlDb => PathHelper.AmllTtmlDbLyricsCacheDirectory,
|
||||||
|
LyricsSearchProvider.AppleMusic => PathHelper.AppleMusicCacheDirectory,
|
||||||
_ => throw new System.ArgumentOutOfRangeException(nameof(provider)),
|
_ => throw new System.ArgumentOutOfRangeException(nameof(provider)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -41,6 +43,7 @@ namespace BetterLyrics.WinUI3.Enums
|
|||||||
LyricsSearchProvider.Kugou => LyricsFormat.Krc,
|
LyricsSearchProvider.Kugou => LyricsFormat.Krc,
|
||||||
LyricsSearchProvider.Netease => LyricsFormat.Lrc,
|
LyricsSearchProvider.Netease => LyricsFormat.Lrc,
|
||||||
LyricsSearchProvider.AmllTtmlDb => LyricsFormat.Ttml,
|
LyricsSearchProvider.AmllTtmlDb => LyricsFormat.Ttml,
|
||||||
|
LyricsSearchProvider.AppleMusic => LyricsFormat.Ttml,
|
||||||
LyricsSearchProvider.LocalLrcFile => LyricsFormat.Lrc,
|
LyricsSearchProvider.LocalLrcFile => LyricsFormat.Lrc,
|
||||||
LyricsSearchProvider.LocalEslrcFile => LyricsFormat.Eslrc,
|
LyricsSearchProvider.LocalEslrcFile => LyricsFormat.Eslrc,
|
||||||
LyricsSearchProvider.LocalTtmlFile => LyricsFormat.Ttml,
|
LyricsSearchProvider.LocalTtmlFile => LyricsFormat.Ttml,
|
||||||
@@ -71,6 +74,7 @@ namespace BetterLyrics.WinUI3.Enums
|
|||||||
LyricsSearchProvider.Kugou => TranslationSearchProvider.Kugou,
|
LyricsSearchProvider.Kugou => TranslationSearchProvider.Kugou,
|
||||||
LyricsSearchProvider.Netease => TranslationSearchProvider.Netease,
|
LyricsSearchProvider.Netease => TranslationSearchProvider.Netease,
|
||||||
LyricsSearchProvider.AmllTtmlDb => TranslationSearchProvider.AmllTtmlDb,
|
LyricsSearchProvider.AmllTtmlDb => TranslationSearchProvider.AmllTtmlDb,
|
||||||
|
LyricsSearchProvider.AppleMusic => TranslationSearchProvider.AppleMusic,
|
||||||
LyricsSearchProvider.LocalMusicFile => TranslationSearchProvider.LocalMusicFile,
|
LyricsSearchProvider.LocalMusicFile => TranslationSearchProvider.LocalMusicFile,
|
||||||
LyricsSearchProvider.LocalLrcFile => TranslationSearchProvider.LocalLrcFile,
|
LyricsSearchProvider.LocalLrcFile => TranslationSearchProvider.LocalLrcFile,
|
||||||
LyricsSearchProvider.LocalEslrcFile => TranslationSearchProvider.LocalEslrcFile,
|
LyricsSearchProvider.LocalEslrcFile => TranslationSearchProvider.LocalEslrcFile,
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace BetterLyrics.WinUI3.Enums
|
||||||
|
{
|
||||||
|
public enum PaletteGeneratorType
|
||||||
|
{
|
||||||
|
MedianCut,
|
||||||
|
OctTree
|
||||||
|
}
|
||||||
|
}
|
||||||
19
BetterLyrics.WinUI3/BetterLyrics.WinUI3/Enums/ShortcutID.cs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace BetterLyrics.WinUI3.Enums
|
||||||
|
{
|
||||||
|
public enum ShortcutID
|
||||||
|
{
|
||||||
|
LyricsWindowShowOrHide,
|
||||||
|
Borderless,
|
||||||
|
ClickThrough,
|
||||||
|
LyricsWindowSwitch,
|
||||||
|
PlayOrPauseSong,
|
||||||
|
NextSong,
|
||||||
|
PreviousSong,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,6 +13,7 @@ namespace BetterLyrics.WinUI3.Enums
|
|||||||
Netease,
|
Netease,
|
||||||
LrcLib,
|
LrcLib,
|
||||||
AmllTtmlDb,
|
AmllTtmlDb,
|
||||||
|
AppleMusic,
|
||||||
LocalMusicFile,
|
LocalMusicFile,
|
||||||
LocalLrcFile,
|
LocalLrcFile,
|
||||||
LocalEslrcFile,
|
LocalEslrcFile,
|
||||||
|
|||||||
@@ -8,11 +8,11 @@ using Windows.UI;
|
|||||||
|
|
||||||
namespace BetterLyrics.WinUI3.Events
|
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 byte[]? Bytes { get; set; } = bytes;
|
||||||
public SoftwareBitmap? AlbumArtSwBitmap { get; set; } = albumArtSwBitmap;
|
public SoftwareBitmap? AlbumArtSwBitmap { get; set; } = albumArtSwBitmap;
|
||||||
public Color? AlbumArtLightAccentColor { get; set; } = albumArtLightAccentColor;
|
public List<Color> AlbumArtLightAccentColors { get; set; } = albumArtLightAccentColors;
|
||||||
public Color? AlbumArtDarkAccentColor { get; set; } = albumArtDarkAccentColor;
|
public List<Color> AlbumArtDarkAccentColors { get; set; } = albumArtDarkAccentColors;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
using BetterLyrics.WinUI3.Models;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace BetterLyrics.WinUI3.Events
|
||||||
|
{
|
||||||
|
public class LyricsChangedEventArgs(LyricsData? lyricsData) : EventArgs
|
||||||
|
{
|
||||||
|
public LyricsData? LyricsData { get; } = lyricsData;
|
||||||
|
}
|
||||||
|
}
|
||||||
126
BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/AppleMusic.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,19 @@
|
|||||||
using Microsoft.Graphics.Canvas.Brushes;
|
using BetterLyrics.WinUI3.Enums;
|
||||||
|
using BetterLyrics.WinUI3.Models;
|
||||||
|
using Microsoft.Graphics.Canvas;
|
||||||
|
using Microsoft.Graphics.Canvas.Brushes;
|
||||||
|
using Microsoft.Graphics.Canvas.Effects;
|
||||||
|
using Microsoft.Graphics.Canvas.Text;
|
||||||
using Microsoft.Graphics.Canvas.UI.Xaml;
|
using Microsoft.Graphics.Canvas.UI.Xaml;
|
||||||
|
using Microsoft.UI;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Windows.Foundation;
|
||||||
|
using Windows.Graphics.Effects;
|
||||||
using Windows.UI;
|
using Windows.UI;
|
||||||
|
|
||||||
namespace BetterLyrics.WinUI3.Helper
|
namespace BetterLyrics.WinUI3.Helper
|
||||||
@@ -29,5 +37,324 @@ namespace BetterLyrics.WinUI3.Helper
|
|||||||
EndPoint = new Vector2((float)(startX + width), 0),
|
EndPoint = new Vector2((float)(startX + width), 0),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 背景层
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="lyricsLayerOpacity">_lyricsOpacityTransition.Value</param>
|
||||||
|
public static OpacityEffect CreateBackgroundEffect(LyricsLine lyricsLine, CanvasCommandList backgroundFontEffect, double lyricsLayerOpacity)
|
||||||
|
{
|
||||||
|
if (lyricsLine.BlurAmountTransition.Value == 0)
|
||||||
|
{
|
||||||
|
return new OpacityEffect
|
||||||
|
{
|
||||||
|
Source = backgroundFontEffect,
|
||||||
|
Opacity = (float)(lyricsLine.OpacityTransition.Value * lyricsLayerOpacity),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new OpacityEffect
|
||||||
|
{
|
||||||
|
Source = new GaussianBlurEffect
|
||||||
|
{
|
||||||
|
Source = backgroundFontEffect,
|
||||||
|
BlurAmount = (float)lyricsLine.BlurAmountTransition.Value,
|
||||||
|
BorderMode = EffectBorderMode.Soft,
|
||||||
|
Optimization = EffectOptimization.Speed,
|
||||||
|
},
|
||||||
|
Opacity = (float)(lyricsLine.OpacityTransition.Value * lyricsLayerOpacity),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CanvasCommandList CreateFontEffect(LyricsLine lyricsLine, ICanvasAnimatedControl control, Color strokeColor, int strokeWidth, Color fontColor)
|
||||||
|
{
|
||||||
|
CanvasCommandList list = new(control);
|
||||||
|
using var ds = list.CreateDrawingSession();
|
||||||
|
if (strokeWidth > 0)
|
||||||
|
{
|
||||||
|
if (lyricsLine.TextGeometry == null)
|
||||||
|
{
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
ds.DrawGeometry(lyricsLine.TextGeometry, lyricsLine.Position, strokeColor, strokeWidth); // 描边
|
||||||
|
}
|
||||||
|
if (lyricsLine.CanvasTextLayout == null)
|
||||||
|
{
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
ds.DrawTextLayout(lyricsLine.CanvasTextLayout, lyricsLine.Position, fontColor); // 绘制文本(填充)
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建辉光效果层
|
||||||
|
/// 仅需在布局重构 (Relayout) 时调用
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="lineRenderingType">_lyricsGlowEffectScope</param>
|
||||||
|
/// <param name="glowEffectAmount">_lyricsGlowEffectAmount</param>
|
||||||
|
public static GaussianBlurEffect CreateForegroundBlurEffect(CanvasCommandList foregroundFontEffect, IGraphicsEffectSource mask, double glowEffectAmount)
|
||||||
|
{
|
||||||
|
return new GaussianBlurEffect
|
||||||
|
{
|
||||||
|
Source = new AlphaMaskEffect
|
||||||
|
{
|
||||||
|
Source = foregroundFontEffect,
|
||||||
|
AlphaMask = mask,
|
||||||
|
},
|
||||||
|
BlurAmount = (float)glowEffectAmount,
|
||||||
|
Optimization = EffectOptimization.Speed,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CanvasCommandList CreateCharMask(ICanvasAnimatedControl control, LyricsLine lyricsLine, int charStartIndex, int charLength, double charProgress)
|
||||||
|
{
|
||||||
|
var mask = new CanvasCommandList(control);
|
||||||
|
using var ds = mask.CreateDrawingSession();
|
||||||
|
|
||||||
|
if (lyricsLine.CanvasTextLayout == null)
|
||||||
|
{
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
var highlightRegion = lyricsLine.CanvasTextLayout.GetCharacterRegions(charStartIndex, charLength).FirstOrDefault();
|
||||||
|
|
||||||
|
double highlightTotalWidth = (double)highlightRegion.LayoutBounds.Width;
|
||||||
|
// Draw the highlight for the current character
|
||||||
|
double highlightWidth = highlightTotalWidth * charProgress;
|
||||||
|
|
||||||
|
double fadingWidth = (double)highlightRegion.LayoutBounds.Height / 2;
|
||||||
|
|
||||||
|
// Rects
|
||||||
|
var highlightRect = new Rect(
|
||||||
|
highlightRegion.LayoutBounds.X,
|
||||||
|
highlightRegion.LayoutBounds.Y + lyricsLine.Position.Y,
|
||||||
|
highlightWidth,
|
||||||
|
highlightRegion.LayoutBounds.Height
|
||||||
|
);
|
||||||
|
|
||||||
|
var fadeInRect = new Rect(
|
||||||
|
highlightRect.Right - fadingWidth,
|
||||||
|
highlightRegion.LayoutBounds.Y + lyricsLine.Position.Y,
|
||||||
|
fadingWidth,
|
||||||
|
highlightRegion.LayoutBounds.Height
|
||||||
|
);
|
||||||
|
var fadeOutRect = new Rect(
|
||||||
|
highlightRect.Right,
|
||||||
|
highlightRegion.LayoutBounds.Y + lyricsLine.Position.Y,
|
||||||
|
fadingWidth,
|
||||||
|
highlightRegion.LayoutBounds.Height
|
||||||
|
);
|
||||||
|
|
||||||
|
// Brushes
|
||||||
|
using var fadeInBrush = CanvasHelper.CreateHorizontalFillBrush(
|
||||||
|
control,
|
||||||
|
[(0f, 0f), (1f, 1f)],
|
||||||
|
(double)highlightRect.Right - fadingWidth,
|
||||||
|
fadingWidth
|
||||||
|
);
|
||||||
|
using var fadeOutBrush = CanvasHelper.CreateHorizontalFillBrush(
|
||||||
|
control,
|
||||||
|
[(0f, 1f), (1f, 0f)],
|
||||||
|
(double)highlightRect.Right,
|
||||||
|
fadingWidth
|
||||||
|
);
|
||||||
|
|
||||||
|
ds.FillRectangle(fadeInRect, fadeInBrush);
|
||||||
|
ds.FillRectangle(fadeOutRect, fadeOutBrush);
|
||||||
|
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CanvasCommandList CreateLineStartToCharMask(ICanvasAnimatedControl control, LyricsLine lyricsLine, int charStartIndex, int charLength, double charProgress, bool fade)
|
||||||
|
{
|
||||||
|
var mask = new CanvasCommandList(control);
|
||||||
|
|
||||||
|
if (lyricsLine.CanvasTextLayout == null)
|
||||||
|
{
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
using var ds = mask.CreateDrawingSession();
|
||||||
|
|
||||||
|
var regions = lyricsLine.CanvasTextLayout.GetCharacterRegions(0, charStartIndex);
|
||||||
|
var highlightRegion = lyricsLine.CanvasTextLayout
|
||||||
|
.GetCharacterRegions(charStartIndex, charLength)
|
||||||
|
.FirstOrDefault();
|
||||||
|
if (regions.Length > 0)
|
||||||
|
{
|
||||||
|
// Draw the mask for the current line
|
||||||
|
for (int j = 0; j < regions.Length; j++)
|
||||||
|
{
|
||||||
|
var region = regions[j];
|
||||||
|
var rect = new Rect(
|
||||||
|
region.LayoutBounds.X,
|
||||||
|
region.LayoutBounds.Y + lyricsLine.Position.Y,
|
||||||
|
region.LayoutBounds.Width,
|
||||||
|
region.LayoutBounds.Height
|
||||||
|
);
|
||||||
|
ds.FillRectangle(rect, Color.FromArgb(255, 128, 128, 128));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double highlightTotalWidth = (double)highlightRegion.LayoutBounds.Width;
|
||||||
|
// Draw the highlight for the current character
|
||||||
|
double highlightWidth = highlightTotalWidth * charProgress;
|
||||||
|
|
||||||
|
double fadingWidth = (double)highlightRegion.LayoutBounds.Height / 2;
|
||||||
|
|
||||||
|
// Rects
|
||||||
|
var highlightRect = new Rect(
|
||||||
|
highlightRegion.LayoutBounds.X,
|
||||||
|
highlightRegion.LayoutBounds.Y + lyricsLine.Position.Y,
|
||||||
|
highlightWidth,
|
||||||
|
highlightRegion.LayoutBounds.Height
|
||||||
|
);
|
||||||
|
|
||||||
|
var fadeInRect = new Rect(
|
||||||
|
highlightRect.Right - fadingWidth,
|
||||||
|
highlightRegion.LayoutBounds.Y + lyricsLine.Position.Y,
|
||||||
|
fadingWidth,
|
||||||
|
highlightRegion.LayoutBounds.Height
|
||||||
|
);
|
||||||
|
|
||||||
|
ds.FillRectangle(highlightRect, Color.FromArgb(255, 128, 128, 128));
|
||||||
|
|
||||||
|
if (fade)
|
||||||
|
{
|
||||||
|
var fadeOutRect = new Rect(
|
||||||
|
highlightRect.Right,
|
||||||
|
highlightRegion.LayoutBounds.Y + lyricsLine.Position.Y,
|
||||||
|
fadingWidth,
|
||||||
|
highlightRegion.LayoutBounds.Height
|
||||||
|
);
|
||||||
|
using var fadeOutBrush = CreateHorizontalFillBrush(
|
||||||
|
control,
|
||||||
|
[(0f, 1f), (1f, 0f)],
|
||||||
|
(double)highlightRect.Right,
|
||||||
|
fadingWidth
|
||||||
|
);
|
||||||
|
ds.FillRectangle(fadeOutRect, fadeOutBrush);
|
||||||
|
}
|
||||||
|
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CanvasCommandList CreateLineMask(ICanvasAnimatedControl control, LyricsLine lyricsLine)
|
||||||
|
{
|
||||||
|
var mask = new CanvasCommandList(control);
|
||||||
|
using var ds = mask.CreateDrawingSession();
|
||||||
|
|
||||||
|
if (lyricsLine.CanvasTextLayout == null)
|
||||||
|
{
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
var regions = lyricsLine.CanvasTextLayout.GetCharacterRegions(0, lyricsLine.OriginalText.Length);
|
||||||
|
if (regions.Length > 0)
|
||||||
|
{
|
||||||
|
for (int j = 0; j < regions.Length; j++)
|
||||||
|
{
|
||||||
|
var region = regions[j];
|
||||||
|
var rect = new Rect(
|
||||||
|
region.LayoutBounds.X,
|
||||||
|
region.LayoutBounds.Y + lyricsLine.Position.Y,
|
||||||
|
region.LayoutBounds.Width,
|
||||||
|
region.LayoutBounds.Height
|
||||||
|
);
|
||||||
|
ds.FillRectangle(rect, Colors.White);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CanvasCommandList CreateTranslationHighlightMask(ICanvasAnimatedControl control, LyricsLine lyricsLine)
|
||||||
|
{
|
||||||
|
var mask = new CanvasCommandList(control);
|
||||||
|
using var ds = mask.CreateDrawingSession();
|
||||||
|
|
||||||
|
if (lyricsLine.CanvasTextLayout == null)
|
||||||
|
{
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
var regions = lyricsLine.CanvasTextLayout.GetCharacterRegions(lyricsLine.OriginalText.Length, lyricsLine.DisplayedText.Length - lyricsLine.OriginalText.Length);
|
||||||
|
if (regions.Length > 0)
|
||||||
|
{
|
||||||
|
for (int j = 0; j < regions.Length; j++)
|
||||||
|
{
|
||||||
|
var region = regions[j];
|
||||||
|
var rect = new Rect(
|
||||||
|
region.LayoutBounds.X,
|
||||||
|
region.LayoutBounds.Y + lyricsLine.Position.Y,
|
||||||
|
region.LayoutBounds.Width,
|
||||||
|
region.LayoutBounds.Height
|
||||||
|
);
|
||||||
|
ds.FillRectangle(rect, Colors.White);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建高亮效果层
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="control"></param>
|
||||||
|
/// <param name="lineRenderingType"></param>
|
||||||
|
public static OpacityEffect CreateForegroundHighlightEffect(CanvasCommandList foregroundFontEffect, IGraphicsEffectSource mask, double opacity)
|
||||||
|
{
|
||||||
|
return new OpacityEffect
|
||||||
|
{
|
||||||
|
Source = new AlphaMaskEffect
|
||||||
|
{
|
||||||
|
Source = foregroundFontEffect,
|
||||||
|
AlphaMask = mask,
|
||||||
|
},
|
||||||
|
Opacity = (float)opacity,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ShadowEffect CreateForegroundShadowEffect(CanvasCommandList foregroundFontEffect, IGraphicsEffectSource mask, Color shadowColor, double shadowAmount)
|
||||||
|
{
|
||||||
|
return new ShadowEffect
|
||||||
|
{
|
||||||
|
Source = new AlphaMaskEffect
|
||||||
|
{
|
||||||
|
Source = foregroundFontEffect,
|
||||||
|
AlphaMask = mask,
|
||||||
|
},
|
||||||
|
ShadowColor = shadowColor,
|
||||||
|
BlurAmount = (float)shadowAmount,
|
||||||
|
Optimization = EffectOptimization.Speed,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static OpacityEffect CreateForegroundTranslationEffect(CanvasCommandList foregroundFontEffect, IGraphicsEffectSource mask, double opacity)
|
||||||
|
{
|
||||||
|
return new OpacityEffect
|
||||||
|
{
|
||||||
|
Source = new AlphaMaskEffect
|
||||||
|
{
|
||||||
|
Source = foregroundFontEffect,
|
||||||
|
AlphaMask = mask,
|
||||||
|
},
|
||||||
|
Opacity = (float)opacity,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IGraphicsEffectSource GetAlphaMask(ICanvasAnimatedControl control, IGraphicsEffectSource charMask, IGraphicsEffectSource lineStartToCharMask, IGraphicsEffectSource lineMask, LineRenderingType lineRenderingType)
|
||||||
|
{
|
||||||
|
var result = lineRenderingType switch
|
||||||
|
{
|
||||||
|
LineRenderingType.CurrentChar => charMask,
|
||||||
|
LineRenderingType.LineStartToCurrentChar => lineStartToCharMask,
|
||||||
|
LineRenderingType.CurrentLine => lineMask,
|
||||||
|
_ => new CanvasCommandList(control),
|
||||||
|
};
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Drawing.Imaging;
|
using System.Drawing.Imaging;
|
||||||
|
using System.Numerics;
|
||||||
using Vanara.PInvoke;
|
using Vanara.PInvoke;
|
||||||
using Windows.UI;
|
using Windows.UI;
|
||||||
|
|
||||||
@@ -94,6 +95,11 @@ namespace BetterLyrics.WinUI3.Helper
|
|||||||
return Color.FromArgb(alpha, color.R, color.G, color.B);
|
return Color.FromArgb(alpha, color.R, color.G, color.B);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Color WithOpacity(this Color color, float opacity)
|
||||||
|
{
|
||||||
|
return Color.FromArgb((byte)(opacity * 255), color.R, color.G, color.B);
|
||||||
|
}
|
||||||
|
|
||||||
public static Color WithBrightness(this Color color, double brightness)
|
public static Color WithBrightness(this Color color, double brightness)
|
||||||
{
|
{
|
||||||
// 确保亮度因子在合理范围内
|
// 确保亮度因子在合理范围内
|
||||||
@@ -106,6 +112,11 @@ namespace BetterLyrics.WinUI3.Helper
|
|||||||
return CommunityToolkit.WinUI.Helpers.ColorHelper.FromHsl(h, s, brightness);
|
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)
|
public static System.Drawing.Color GetAccentColor(IntPtr myHwnd, string monitorDeviceName, WindowPixelSampleMode mode)
|
||||||
{
|
{
|
||||||
if (!User32.GetWindowRect(myHwnd, out RECT myRect)) return System.Drawing.Color.Transparent;
|
if (!User32.GetWindowRect(myHwnd, out RECT myRect)) return System.Drawing.Color.Transparent;
|
||||||
@@ -116,15 +127,11 @@ namespace BetterLyrics.WinUI3.Helper
|
|||||||
{
|
{
|
||||||
case WindowPixelSampleMode.BelowWindow:
|
case WindowPixelSampleMode.BelowWindow:
|
||||||
{
|
{
|
||||||
int sampleHeight = 1;
|
return GetAverageColorFromScreenRegion(myRect.Left, myRect.Bottom + 2, screenWidth, 1);
|
||||||
int sampleY = myRect.Bottom + 1;
|
|
||||||
return GetAverageColorFromScreenRegion(myRect.Left, sampleY, screenWidth, sampleHeight);
|
|
||||||
}
|
}
|
||||||
case WindowPixelSampleMode.AboveWindow:
|
case WindowPixelSampleMode.AboveWindow:
|
||||||
{
|
{
|
||||||
int sampleHeight = 1;
|
return GetAverageColorFromScreenRegion(myRect.Left, myRect.Top - 2, screenWidth, 1);
|
||||||
int sampleY = myRect.Top - 1;
|
|
||||||
return GetAverageColorFromScreenRegion(myRect.Left, sampleY, screenWidth, sampleHeight);
|
|
||||||
}
|
}
|
||||||
case WindowPixelSampleMode.WindowArea:
|
case WindowPixelSampleMode.WindowArea:
|
||||||
{
|
{
|
||||||
@@ -142,49 +149,21 @@ namespace BetterLyrics.WinUI3.Helper
|
|||||||
if (width <= 0 || height <= 0)
|
if (width <= 0 || height <= 0)
|
||||||
return System.Drawing.Color.Transparent;
|
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 = [];
|
List<System.Drawing.Color> edgeColors = [];
|
||||||
|
|
||||||
// Top edge
|
// Top edge
|
||||||
if (edgeThickness.Top > 0 && edgeThickness.Top < height)
|
if (edgeThickness.Top > 0)
|
||||||
edgeColors.Add(
|
edgeColors.Add(GetAverageColorFromScreenRegion(myRect.Left, myRect.Top - (int)edgeThickness.Top, width, (int)edgeThickness.Top));
|
||||||
GetAverageColorFromScreenRegion(
|
|
||||||
myRect.Left,
|
|
||||||
myRect.Top,
|
|
||||||
width,
|
|
||||||
(int)edgeThickness.Top
|
|
||||||
)
|
|
||||||
);
|
|
||||||
// Bottom edge
|
// Bottom edge
|
||||||
if (edgeThickness.Bottom > 0 && edgeThickness.Bottom < height)
|
if (edgeThickness.Bottom > 0)
|
||||||
edgeColors.Add(
|
edgeColors.Add(GetAverageColorFromScreenRegion(myRect.Left, myRect.Bottom, width, (int)edgeThickness.Bottom));
|
||||||
GetAverageColorFromScreenRegion(
|
|
||||||
myRect.Left,
|
|
||||||
myRect.Bottom - (int)edgeThickness.Bottom,
|
|
||||||
width,
|
|
||||||
(int)edgeThickness.Bottom
|
|
||||||
)
|
|
||||||
);
|
|
||||||
// Left edge
|
// Left edge
|
||||||
if (edgeThickness.Left > 0 && edgeThickness.Left < width)
|
if (edgeThickness.Left > 0)
|
||||||
edgeColors.Add(
|
edgeColors.Add(GetAverageColorFromScreenRegion(myRect.Left - (int)edgeThickness.Left, myRect.Top, (int)edgeThickness.Left, height));
|
||||||
GetAverageColorFromScreenRegion(
|
|
||||||
myRect.Left,
|
|
||||||
myRect.Top + (int)edgeThickness.Top,
|
|
||||||
(int)edgeThickness.Left,
|
|
||||||
height - (int)edgeThickness.Top - (int)edgeThickness.Bottom
|
|
||||||
)
|
|
||||||
);
|
|
||||||
// Right edge
|
// Right edge
|
||||||
if (edgeThickness.Right > 0 && edgeThickness.Right < width)
|
if (edgeThickness.Right > 0)
|
||||||
edgeColors.Add(
|
edgeColors.Add(GetAverageColorFromScreenRegion(myRect.Right, myRect.Top, (int)edgeThickness.Right, height));
|
||||||
GetAverageColorFromScreenRegion(
|
|
||||||
myRect.Right - (int)edgeThickness.Right,
|
|
||||||
myRect.Top + (int)edgeThickness.Top,
|
|
||||||
(int)edgeThickness.Right,
|
|
||||||
height - (int)edgeThickness.Top - (int)edgeThickness.Bottom
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
// 合并四边平均色
|
// 合并四边平均色
|
||||||
if (edgeColors.Count == 0)
|
if (edgeColors.Count == 0)
|
||||||
@@ -246,6 +225,5 @@ namespace BetterLyrics.WinUI3.Helper
|
|||||||
if (count == 0) return System.Drawing.Color.Transparent;
|
if (count == 0) return System.Drawing.Color.Transparent;
|
||||||
return System.Drawing.Color.FromArgb((int)(r / count), (int)(g / count), (int)(b / count));
|
return System.Drawing.Color.FromArgb((int)(r / count), (int)(g / count), (int)(b / count));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace BetterLyrics.WinUI3.Helper
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace BetterLyrics.WinUI3.Helper
|
||||||
|
{
|
||||||
|
public class DirectoryHelper
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 递归查找指定文件夹下所有文件(包括子文件夹)。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="folderPath">要查找的文件夹路径</param>
|
||||||
|
/// <returns>所有文件的完整路径列表</returns>
|
||||||
|
public static List<string> GetAllFiles(string folderPath, string searchPattern = "*")
|
||||||
|
{
|
||||||
|
var files = new List<string>();
|
||||||
|
if (!Directory.Exists(folderPath))
|
||||||
|
return files;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
files.AddRange(Directory.GetFiles(folderPath, searchPattern));
|
||||||
|
foreach (var dir in Directory.GetDirectories(folderPath))
|
||||||
|
{
|
||||||
|
files.AddRange(GetAllFiles(dir, searchPattern));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
// 可根据需要处理异常,如权限不足等
|
||||||
|
}
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,200 +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 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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,7 +2,9 @@
|
|||||||
|
|
||||||
using BetterLyrics.WinUI3.Enums;
|
using BetterLyrics.WinUI3.Enums;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Ude;
|
using Ude;
|
||||||
|
|
||||||
@@ -78,5 +80,13 @@ namespace BetterLyrics.WinUI3.Helper
|
|||||||
|| normFileName == normQ2 + normQ1;
|
|| normFileName == normQ2 + normQ1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static readonly string[] MusicExtensions = {
|
||||||
|
".mp3", ".aac", ".m4a", ".ogg", ".opus", ".wma", ".amr",
|
||||||
|
".flac", ".alac", ".ape", ".wv", ".tak",
|
||||||
|
".wav", ".aiff", ".aif", ".pcm", ".cda", ".dsf", ".dff", ".au", ".snd",
|
||||||
|
".mid", ".midi", ".mod", ".xm", ".it", ".s3m"
|
||||||
|
};
|
||||||
|
|
||||||
|
public static string MusicSearchPattern => string.Join("|", MusicExtensions.Select(x => $"*{x}"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,10 +11,6 @@ namespace BetterLyrics.WinUI3.Helper
|
|||||||
{
|
{
|
||||||
public static class FontHelper
|
public static class FontHelper
|
||||||
{
|
{
|
||||||
private static readonly ISettingsService _settingsService = Ioc.Default.GetRequiredService<ISettingsService>();
|
public static string[] SystemFontFamilies => CanvasTextFormat.GetSystemFontFamilies().Order().ToArray();
|
||||||
|
|
||||||
public static string[] SystemFontFamilies => CanvasTextFormat.GetSystemFontFamilies();
|
|
||||||
|
|
||||||
public static string GetUserPreferredFontFamily() => SystemFontFamilies.ElementAtOrDefault(_settingsService.AppSettings.StandardLyricsStyleSettings.SelectedFontFamilyIndex) ?? "Segoe UI";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ namespace BetterLyrics.WinUI3.Helper
|
|||||||
private readonly List<User32.HWINEVENTHOOK> _hooks = new();
|
private readonly List<User32.HWINEVENTHOOK> _hooks = new();
|
||||||
private HWND _currentForeground = HWND.NULL;
|
private HWND _currentForeground = HWND.NULL;
|
||||||
private readonly IntPtr _selfHwnd;
|
private readonly IntPtr _selfHwnd;
|
||||||
private readonly ThrottleHelper _winEventProcThrottle = new(TimeSpan.FromSeconds(1));
|
|
||||||
|
|
||||||
public delegate void WindowChangedHandler(HWND hwnd);
|
public delegate void WindowChangedHandler(HWND hwnd);
|
||||||
private readonly WindowChangedHandler _onWindowChanged;
|
private readonly WindowChangedHandler _onWindowChanged;
|
||||||
@@ -73,7 +72,7 @@ namespace BetterLyrics.WinUI3.Helper
|
|||||||
|
|
||||||
_hooks.Clear();
|
_hooks.Clear();
|
||||||
|
|
||||||
_timer.Stop();
|
//_timer.Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Timer_Tick(object? sender, object e)
|
private void Timer_Tick(object? sender, object e)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Microsoft.UI.Xaml;
|
using BetterLyrics.WinUI3.Enums;
|
||||||
|
using Microsoft.UI.Xaml;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -12,30 +13,92 @@ namespace BetterLyrics.WinUI3.Helper
|
|||||||
{
|
{
|
||||||
public class GlobalHotKeyHelper
|
public class GlobalHotKeyHelper
|
||||||
{
|
{
|
||||||
private static Dictionary<int, Action> _hotKeyActions = [];
|
private static Dictionary<int, Action> _actions = [];
|
||||||
private static int _nextId = 0;
|
private static Dictionary<int, List<string>> _keys = [];
|
||||||
|
|
||||||
public static void RegisterHotKey(Window window, User32.HotKeyModifiers modifiers, uint key, Action action)
|
/// <summary>
|
||||||
|
/// Register a global hotkey for a specific window type
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">Target window type</typeparam>
|
||||||
|
/// <param name="id"></param>
|
||||||
|
/// <param name="keys"></param>
|
||||||
|
/// <param name="action"></param>
|
||||||
|
private static void RegisterHotKey<T>(ShortcutID id, List<string> keys, Action action)
|
||||||
{
|
{
|
||||||
|
if (keys.Count == 0) return;
|
||||||
|
|
||||||
|
var window = WindowHelper.GetWindowByWindowType<T>();
|
||||||
|
if (window == null) return;
|
||||||
|
|
||||||
HWND hwnd = WindowNative.GetWindowHandle(window);
|
HWND hwnd = WindowNative.GetWindowHandle(window);
|
||||||
int id = _nextId++;
|
User32.HotKeyModifiers modifiers = User32.HotKeyModifiers.MOD_NONE;
|
||||||
User32.RegisterHotKey(hwnd, id, modifiers, key);
|
VirtualKey key = VirtualKey.None;
|
||||||
_hotKeyActions[id] = action;
|
foreach (var item in keys)
|
||||||
|
{
|
||||||
|
if (item == "Ctrl")
|
||||||
|
{
|
||||||
|
modifiers |= User32.HotKeyModifiers.MOD_CONTROL;
|
||||||
|
}
|
||||||
|
else if (item == "Shift")
|
||||||
|
{
|
||||||
|
modifiers |= User32.HotKeyModifiers.MOD_SHIFT;
|
||||||
|
}
|
||||||
|
else if (item == "Alt")
|
||||||
|
{
|
||||||
|
modifiers |= User32.HotKeyModifiers.MOD_ALT;
|
||||||
|
}
|
||||||
|
else if (item == "Win")
|
||||||
|
{
|
||||||
|
modifiers |= User32.HotKeyModifiers.MOD_WIN;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
key = (VirtualKey)Enum.Parse(typeof(VirtualKey), item, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool success = User32.RegisterHotKey(hwnd, (int)id, modifiers, (uint)key);
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
_actions[(int)id] = action;
|
||||||
|
_keys[(int)id] = keys;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void UnregisterAllHotKeys(Window window)
|
private static void UnregisterHotKey<T>(ShortcutID id)
|
||||||
{
|
{
|
||||||
|
var window = WindowHelper.GetWindowByWindowType<T>();
|
||||||
|
if (window == null) return;
|
||||||
|
|
||||||
HWND hwnd = WindowNative.GetWindowHandle(window);
|
HWND hwnd = WindowNative.GetWindowHandle(window);
|
||||||
foreach (var id in _hotKeyActions.Keys.ToList())
|
User32.UnregisterHotKey(hwnd, (int)id);
|
||||||
{
|
_actions.Remove((int)id);
|
||||||
User32.UnregisterHotKey(hwnd, id);
|
_keys.Remove((int)id);
|
||||||
_hotKeyActions.Remove(id);
|
}
|
||||||
}
|
|
||||||
|
public static void UpdateHotKey<T>(ShortcutID id, List<string> keys, Action action)
|
||||||
|
{
|
||||||
|
UnregisterHotKey<T>(id);
|
||||||
|
RegisterHotKey<T>(id, keys, action);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsHotKeyRegistered(ShortcutID id)
|
||||||
|
{
|
||||||
|
return _actions.ContainsKey((int)id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsHotKeyRegistered(List<string> keys)
|
||||||
|
{
|
||||||
|
return _keys.ContainsValue(keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool TryInvokeAction(ShortcutID id)
|
||||||
|
{
|
||||||
|
return TryInvokeAction((int)id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool TryInvokeAction(int id)
|
public static bool TryInvokeAction(int id)
|
||||||
{
|
{
|
||||||
if (_hotKeyActions.TryGetValue(id, out var action))
|
if (_actions.TryGetValue(id, out var action))
|
||||||
{
|
{
|
||||||
action?.Invoke();
|
action?.Invoke();
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -1,25 +1,26 @@
|
|||||||
// 2025/6/23 by Zhe Fang
|
// 2025/6/23 by Zhe Fang
|
||||||
|
|
||||||
|
using BetterLyrics.WinUI3.Enums;
|
||||||
|
using BetterLyrics.WinUI3.Models.Settings;
|
||||||
using CommunityToolkit.WinUI.Helpers;
|
using CommunityToolkit.WinUI.Helpers;
|
||||||
|
using Impressionist.Abstractions;
|
||||||
|
using Impressionist.Implementations;
|
||||||
using Microsoft.Graphics.Canvas;
|
using Microsoft.Graphics.Canvas;
|
||||||
using Microsoft.Graphics.Canvas.Text;
|
using Microsoft.Graphics.Canvas.Text;
|
||||||
using Microsoft.UI;
|
using Microsoft.UI;
|
||||||
using Microsoft.UI.Xaml.Media.Imaging;
|
using Microsoft.UI.Xaml.Media.Imaging;
|
||||||
using SixLabors.ImageSharp;
|
|
||||||
using SixLabors.ImageSharp.Formats.Jpeg;
|
|
||||||
using SixLabors.ImageSharp.Formats.Png;
|
|
||||||
using SixLabors.ImageSharp.PixelFormats;
|
|
||||||
using SixLabors.ImageSharp.Processing;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Net.Http;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Runtime.InteropServices.WindowsRuntime;
|
using System.Runtime.InteropServices.WindowsRuntime;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Windows.Graphics.Imaging;
|
using Windows.Graphics.Imaging;
|
||||||
using Windows.Storage.Streams;
|
using Windows.Storage.Streams;
|
||||||
using Windows.UI;
|
using Windows.UI;
|
||||||
|
using static Vanara.PInvoke.Ole32;
|
||||||
|
|
||||||
namespace BetterLyrics.WinUI3.Helper
|
namespace BetterLyrics.WinUI3.Helper
|
||||||
{
|
{
|
||||||
@@ -45,7 +46,7 @@ namespace BetterLyrics.WinUI3.Helper
|
|||||||
return RandomAccessStreamReference.CreateFromStream(stream);
|
return RandomAccessStreamReference.CreateFromStream(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<byte[]> CreateTextPlaceholderBytesAsync(int width, int height)
|
public static async Task<IRandomAccessStream> CreateTextPlaceholderBytesAsync(int width, int height)
|
||||||
{
|
{
|
||||||
using var device = CanvasDevice.GetSharedDevice();
|
using var device = CanvasDevice.GetSharedDevice();
|
||||||
using var renderTarget = new CanvasRenderTarget(device, width, height, 96);
|
using var renderTarget = new CanvasRenderTarget(device, width, height, 96);
|
||||||
@@ -75,31 +76,58 @@ namespace BetterLyrics.WinUI3.Helper
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 保存为 PNG 并转为 byte[]
|
// 保存为 PNG 并转为 byte[]
|
||||||
using var stream = new InMemoryRandomAccessStream();
|
var stream = new InMemoryRandomAccessStream();
|
||||||
await renderTarget.SaveAsync(stream, CanvasBitmapFileFormat.Png);
|
await renderTarget.SaveAsync(stream, CanvasBitmapFileFormat.Png);
|
||||||
var buffer = new byte[stream.Size];
|
stream.Seek(0);
|
||||||
using (var reader = new DataReader(stream.GetInputStreamAt(0)))
|
return stream;
|
||||||
{
|
|
||||||
await reader.LoadAsync((uint)stream.Size);
|
|
||||||
reader.ReadBytes(buffer);
|
|
||||||
}
|
|
||||||
return buffer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<Windows.UI.Color> GetAccentColorsFromByte(byte[] bytes, int count, bool? isDark = null)
|
|
||||||
|
public static Task<ThemeColorResult> GetAccentColorAsync(BitmapDecoder decoder, PaletteGeneratorType generatorType)
|
||||||
{
|
{
|
||||||
using var image = Image.Load<Rgba32>(bytes);
|
return generatorType switch
|
||||||
var colorThief = new ColorThief.ImageSharp.ColorThief();
|
{
|
||||||
var mainColor = colorThief.GetColor(image, 10, false);
|
PaletteGeneratorType.OctTree => PaletteHelper.OctTreeGetAccentColorFromByteAsync(decoder),
|
||||||
var palette = colorThief.GetPalette(image, 255, 10, false);
|
PaletteGeneratorType.MedianCut => PaletteHelper.MedianCutGetAccentColorFromByteAsync(decoder),
|
||||||
var topColors = palette
|
_ => throw new ArgumentOutOfRangeException(nameof(generatorType)),
|
||||||
.OrderByDescending(x => x.Population)
|
};
|
||||||
.Where(x => x.IsDark == (isDark ?? mainColor.IsDark))
|
}
|
||||||
.Select(x => Windows.UI.Color.FromArgb(x.Color.A, x.Color.R, x.Color.G, x.Color.B))
|
|
||||||
.Take(count)
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
return topColors;
|
public static Task<PaletteResult> GetAccentColorsAsync(BitmapDecoder decoder, int count, PaletteGeneratorType generatorType, bool? isDark = null)
|
||||||
|
{
|
||||||
|
return generatorType switch
|
||||||
|
{
|
||||||
|
PaletteGeneratorType.OctTree => PaletteHelper.OctTreeGetAccentColorsFromByteAsync(decoder, count, isDark),
|
||||||
|
PaletteGeneratorType.MedianCut => PaletteHelper.MedianCutGetAccentColorsFromByteAsync(decoder, count, isDark),
|
||||||
|
_ => throw new ArgumentOutOfRangeException(nameof(generatorType)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<Dictionary<Vector3, int>> GetPixelColor(BitmapDecoder bitmapDecoder)
|
||||||
|
{
|
||||||
|
var pixelDataProvider = await bitmapDecoder.GetPixelDataAsync();
|
||||||
|
var pixels = pixelDataProvider.DetachPixelData();
|
||||||
|
var count = bitmapDecoder.PixelWidth * bitmapDecoder.PixelHeight;
|
||||||
|
var vector = new Dictionary<Vector3, int>();
|
||||||
|
for (int i = 0; i < count; i += 10)
|
||||||
|
{
|
||||||
|
var offset = i * 4;
|
||||||
|
var b = pixels[offset];
|
||||||
|
var g = pixels[offset + 1];
|
||||||
|
var r = pixels[offset + 2];
|
||||||
|
var a = pixels[offset + 3];
|
||||||
|
if (a == 0) continue;
|
||||||
|
var color = new Vector3(r, g, b);
|
||||||
|
if (vector.ContainsKey(color))
|
||||||
|
{
|
||||||
|
vector[color]++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vector[color] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return vector;
|
||||||
}
|
}
|
||||||
|
|
||||||
//public static async Task<BitmapImage> GetBitmapImageFromBytesAsync(byte[] imageBytes)
|
//public static async Task<BitmapImage> GetBitmapImageFromBytesAsync(byte[] imageBytes)
|
||||||
@@ -128,13 +156,12 @@ namespace BetterLyrics.WinUI3.Helper
|
|||||||
// return stream;
|
// return stream;
|
||||||
//}
|
//}
|
||||||
|
|
||||||
public static async Task<byte[]> ToByteArrayAsync(IRandomAccessStreamReference streamRef)
|
public static async Task<IBuffer> ToBufferAsync(IRandomAccessStreamReference streamRef)
|
||||||
{
|
{
|
||||||
using IRandomAccessStream stream = await streamRef.OpenReadAsync();
|
using IRandomAccessStream stream = await streamRef.OpenReadAsync();
|
||||||
using var reader = new DataReader(stream);
|
stream.Seek(0);
|
||||||
await reader.LoadAsync((uint)stream.Size);
|
var buffer = new Windows.Storage.Streams.Buffer((uint)stream.Size);
|
||||||
byte[] buffer = new byte[stream.Size];
|
await stream.ReadAsync(buffer, (uint)stream.Size, InputStreamOptions.None);
|
||||||
reader.ReadBytes(buffer);
|
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,53 +182,105 @@ namespace BetterLyrics.WinUI3.Helper
|
|||||||
return (double)(sum / (pixels.Length / 4));
|
return (double)(sum / (pixels.Length / 4));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] MakeSquareWithThemeColor(byte[] imageBytes)
|
public static async Task<BitmapDecoder> MakeSquareWithThemeColor(IBuffer buffer, PaletteGeneratorType generatorType)
|
||||||
{
|
{
|
||||||
using var image = Image.Load<Rgba32>(imageBytes);
|
|
||||||
|
|
||||||
if (image.Width == image.Height)
|
using var stream = new InMemoryRandomAccessStream();
|
||||||
|
await stream.WriteAsync(buffer);
|
||||||
|
var decoder = await BitmapDecoder.CreateAsync(stream);
|
||||||
|
|
||||||
|
if (decoder.PixelWidth == decoder.PixelHeight)
|
||||||
{
|
{
|
||||||
// 已经是正方形,直接返回
|
// 已经是正方形,直接返回
|
||||||
return imageBytes;
|
return decoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
int size = Math.Max(image.Width, image.Height);
|
using var device = CanvasDevice.GetSharedDevice();
|
||||||
|
using var canvasBitmap = await CanvasBitmap.LoadAsync(device, stream);
|
||||||
|
var size = Math.Max(decoder.PixelWidth, decoder.PixelHeight);
|
||||||
|
|
||||||
var themeColor = Rgba32.ParseHex(GetAccentColorsFromByte(imageBytes, 1).FirstOrDefault().ToHex());
|
var result = await GetAccentColorAsync(decoder, generatorType);
|
||||||
|
var color = Windows.UI.Color.FromArgb(255, (byte)result.Color.X, (byte)result.Color.Y, (byte)result.Color.Z);
|
||||||
|
using var renderTarget = new CanvasRenderTarget(device, size, size, 96);
|
||||||
|
|
||||||
using var square = new Image<Rgba32>(size, size, themeColor);
|
int offsetX = (int)(size - decoder.PixelWidth) / 2;
|
||||||
|
int offsetY = (int)(size - decoder.PixelHeight) / 2;
|
||||||
|
using (var ds = renderTarget.CreateDrawingSession())
|
||||||
|
{
|
||||||
|
ds.FillRectangle(0, 0, size, size, color);
|
||||||
|
ds.DrawImage(canvasBitmap, offsetX, offsetY);
|
||||||
|
}
|
||||||
|
|
||||||
int offsetX = (size - image.Width) / 2;
|
// 保存为 PNG 并转为 byte[]
|
||||||
int offsetY = (size - image.Height) / 2;
|
stream.Seek(0);
|
||||||
|
stream.Size = 0;
|
||||||
|
await renderTarget.SaveAsync(stream, CanvasBitmapFileFormat.Png);
|
||||||
|
stream.Seek(0);
|
||||||
|
var newDecoder = await BitmapDecoder.CreateAsync(stream);
|
||||||
|
return newDecoder;
|
||||||
|
|
||||||
square.Mutate(ctx => ctx.DrawImage(image, new Point(offsetX, offsetY), 1f));
|
|
||||||
|
|
||||||
using var ms = new MemoryStream();
|
|
||||||
square.Save(ms, new JpegEncoder());
|
|
||||||
return ms.ToArray();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] Resize(byte[] imageBytes, int size)
|
public static async Task<IBuffer> Resize(IBuffer buffer, int size)
|
||||||
{
|
{
|
||||||
using (Image image = Image.Load(imageBytes))
|
using var stream = new InMemoryRandomAccessStream();
|
||||||
|
await stream.WriteAsync(buffer);
|
||||||
|
var decoder = await BitmapDecoder.CreateAsync(stream);
|
||||||
|
|
||||||
|
var factor = Math.Max((double)size / decoder.PixelWidth, (double)size / decoder.PixelHeight);
|
||||||
|
|
||||||
|
var width = (uint)(decoder.PixelWidth * factor);
|
||||||
|
var height = (uint)(decoder.PixelHeight * factor);
|
||||||
|
|
||||||
|
if (factor > 1)
|
||||||
{
|
{
|
||||||
var factor = Math.Max((double)size / image.Width, (double)size / image.Height);
|
var transform = new BitmapTransform()
|
||||||
|
|
||||||
int width = (int)(image.Width * factor);
|
|
||||||
int height = (int)(image.Height * factor);
|
|
||||||
|
|
||||||
if (factor > 1)
|
|
||||||
{
|
{
|
||||||
image.Mutate(x => x.Resize(width, height, KnownResamplers.Welch));
|
ScaledWidth = width,
|
||||||
}
|
ScaledHeight = height,
|
||||||
else
|
InterpolationMode = BitmapInterpolationMode.Fant
|
||||||
{
|
};
|
||||||
image.Mutate(x => x.Resize(width, height, KnownResamplers.NearestNeighbor));
|
var pixelData = await decoder.GetPixelDataAsync(
|
||||||
}
|
BitmapPixelFormat.Rgba8,
|
||||||
|
BitmapAlphaMode.Straight,
|
||||||
|
transform, ExifOrientationMode.RespectExifOrientation,
|
||||||
|
ColorManagementMode.ColorManageToSRgb);
|
||||||
|
var pixels = pixelData.DetachPixelData();
|
||||||
|
|
||||||
using var ms = new MemoryStream();
|
stream.Seek(0);
|
||||||
image.Save(ms, new JpegEncoder());
|
stream.Size = 0;
|
||||||
return ms.ToArray();
|
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, stream);
|
||||||
|
encoder.SetPixelData(BitmapPixelFormat.Rgba8, BitmapAlphaMode.Straight, width, height, 96, 96, pixels);
|
||||||
|
await encoder.FlushAsync();
|
||||||
|
var output = new Windows.Storage.Streams.Buffer((uint)stream.Size);
|
||||||
|
stream.Seek(0);
|
||||||
|
await stream.ReadAsync(output, (uint)stream.Size, InputStreamOptions.None);
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var transform = new BitmapTransform()
|
||||||
|
{
|
||||||
|
ScaledWidth = (uint)width,
|
||||||
|
ScaledHeight = (uint)height,
|
||||||
|
InterpolationMode = BitmapInterpolationMode.NearestNeighbor
|
||||||
|
};
|
||||||
|
var pixelData = await decoder.GetPixelDataAsync(
|
||||||
|
BitmapPixelFormat.Rgba8,
|
||||||
|
BitmapAlphaMode.Straight,
|
||||||
|
transform, ExifOrientationMode.RespectExifOrientation,
|
||||||
|
ColorManagementMode.ColorManageToSRgb);
|
||||||
|
var pixels = pixelData.DetachPixelData();
|
||||||
|
|
||||||
|
stream.Seek(0);
|
||||||
|
stream.Size = 0;
|
||||||
|
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, stream);
|
||||||
|
encoder.SetPixelData(BitmapPixelFormat.Rgba8, BitmapAlphaMode.Straight, width, height, 96, 96, pixels);
|
||||||
|
await encoder.FlushAsync();
|
||||||
|
var output = new Windows.Storage.Streams.Buffer((uint)stream.Size);
|
||||||
|
stream.Seek(0);
|
||||||
|
await stream.ReadAsync(output, (uint)stream.Size, InputStreamOptions.None);
|
||||||
|
return output;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,5 +298,68 @@ namespace BetterLyrics.WinUI3.Helper
|
|||||||
}
|
}
|
||||||
return pixelData;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,7 @@
|
|||||||
using BetterLyrics.WinUI3.Helper;
|
using BetterLyrics.WinUI3.Helper;
|
||||||
using BetterLyrics.WinUI3.Services.SettingsService;
|
|
||||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
|
||||||
using Lyricify.Lyrics.Helpers.General;
|
|
||||||
using NTextCat;
|
using NTextCat;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using TinyPinyin;
|
|
||||||
using Windows.Globalization;
|
using Windows.Globalization;
|
||||||
|
|
||||||
namespace BetterLyrics.WinUI3.Services
|
namespace BetterLyrics.WinUI3.Services
|
||||||
@@ -16,46 +10,84 @@ namespace BetterLyrics.WinUI3.Services
|
|||||||
{
|
{
|
||||||
private static readonly RankedLanguageIdentifierFactory _factory = new();
|
private static readonly RankedLanguageIdentifierFactory _factory = new();
|
||||||
private static readonly RankedLanguageIdentifier _identifier;
|
private static readonly RankedLanguageIdentifier _identifier;
|
||||||
private static readonly ISettingsService _settingsService = Ioc.Default.GetRequiredService<ISettingsService>();
|
|
||||||
|
|
||||||
public static List<Models.LanguageInfo> SupportedTargetLanguages =>
|
public static List<Models.LanguageInfo> SupportedTargetLanguages { get; set; } =
|
||||||
[
|
[
|
||||||
new Models.LanguageInfo("ar", "العربية"),
|
new Models.LanguageInfo("ar", "العربية"),
|
||||||
new Models.LanguageInfo("az", "Azərbaycan dili"),
|
new Models.LanguageInfo("az", "Azərbaycan dili"),
|
||||||
new Models.LanguageInfo("zh-Hans", "简体中文"),
|
|
||||||
new Models.LanguageInfo("zh-Hant", "繁體中文"),
|
new Models.LanguageInfo("bg", "Български"),
|
||||||
|
new Models.LanguageInfo("bn", "বাংলা"),
|
||||||
|
|
||||||
|
new Models.LanguageInfo("ca", "Català"),
|
||||||
new Models.LanguageInfo("cs", "Čeština"),
|
new Models.LanguageInfo("cs", "Čeština"),
|
||||||
|
|
||||||
new Models.LanguageInfo("da", "Dansk"),
|
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("en", "English"),
|
||||||
new Models.LanguageInfo("eo", "Esperanto"),
|
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("fi", "Suomi"),
|
||||||
new Models.LanguageInfo("fr", "Français"),
|
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("he", "עברית"),
|
||||||
new Models.LanguageInfo("hi", "हिन्दी"),
|
new Models.LanguageInfo("hi", "हिन्दी"),
|
||||||
new Models.LanguageInfo("hu", "Magyar"),
|
new Models.LanguageInfo("hu", "Magyar"),
|
||||||
|
|
||||||
new Models.LanguageInfo("id", "Bahasa Indonesia"),
|
new Models.LanguageInfo("id", "Bahasa Indonesia"),
|
||||||
new Models.LanguageInfo("ga", "Gaeilge"),
|
|
||||||
new Models.LanguageInfo("it", "Italiano"),
|
new Models.LanguageInfo("it", "Italiano"),
|
||||||
|
|
||||||
new Models.LanguageInfo("ja", "日本語"),
|
new Models.LanguageInfo("ja", "日本語"),
|
||||||
|
|
||||||
new Models.LanguageInfo("ko", "한국어"),
|
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("pl", "Polski"),
|
||||||
new Models.LanguageInfo("pt", "Português"),
|
new Models.LanguageInfo("pt", "Português"),
|
||||||
|
|
||||||
|
new Models.LanguageInfo("ro", "Română"),
|
||||||
new Models.LanguageInfo("ru", "Русский"),
|
new Models.LanguageInfo("ru", "Русский"),
|
||||||
|
|
||||||
new Models.LanguageInfo("sk", "Slovenčina"),
|
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("sv", "Svenska"),
|
||||||
|
|
||||||
|
new Models.LanguageInfo("th", "ไทย"),
|
||||||
|
new Models.LanguageInfo("tl", "Filipino"),
|
||||||
new Models.LanguageInfo("tr", "Türkçe"),
|
new Models.LanguageInfo("tr", "Türkçe"),
|
||||||
|
|
||||||
new Models.LanguageInfo("uk", "Українська"),
|
new Models.LanguageInfo("uk", "Українська"),
|
||||||
|
new Models.LanguageInfo("ur", "اردو"),
|
||||||
|
|
||||||
new Models.LanguageInfo("vi", "Tiếng Việt"),
|
new Models.LanguageInfo("vi", "Tiếng Việt"),
|
||||||
|
|
||||||
|
new Models.LanguageInfo("zh", "中文"),
|
||||||
];
|
];
|
||||||
|
|
||||||
static LanguageHelper()
|
static LanguageHelper()
|
||||||
{
|
{
|
||||||
_identifier = _factory.Load(PathHelper.LanguageProfilePath);
|
_identifier = _factory.Load(PathHelper.LanguageProfilePath);
|
||||||
|
RomajiConverter.Core.Helpers.RomajiHelper.Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string? DetectLanguageCode(string? text)
|
public static string? DetectLanguageCode(string? text)
|
||||||
@@ -67,9 +99,8 @@ namespace BetterLyrics.WinUI3.Services
|
|||||||
code = code switch
|
code = code switch
|
||||||
{
|
{
|
||||||
"simple" => "en",
|
"simple" => "en",
|
||||||
"zh_classical" => "zh-Hant",
|
"zh_classical" => "zh",
|
||||||
"zh_yue" => "zh-Hant",
|
"zh_yue" => "zh",
|
||||||
"zh" => "zh-Hans",
|
|
||||||
_ => code
|
_ => code
|
||||||
};
|
};
|
||||||
return code;
|
return code;
|
||||||
@@ -84,31 +115,17 @@ namespace BetterLyrics.WinUI3.Services
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string ConvertToCountryCode(string? languageCode)
|
public static string GetDefaultTargetLanguageCode()
|
||||||
{
|
{
|
||||||
if (languageCode == null) return "us";
|
var found = SupportedTargetLanguages.Find(x => ApplicationLanguages.Languages.FirstOrDefault()?.Contains(x.Code) == true);
|
||||||
|
if (found == null)
|
||||||
return languageCode switch
|
|
||||||
{
|
{
|
||||||
"zh" => "cn",
|
return "en";
|
||||||
"zh-Hans" => "cn",
|
}
|
||||||
"zh-Hant" => "tw",
|
else
|
||||||
"ja" => "jp",
|
{
|
||||||
"ko" => "kr",
|
return found.Code;
|
||||||
_ => "us"
|
}
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GetUserTargetLanguageCode()
|
|
||||||
{
|
|
||||||
return SupportedTargetLanguages[_settingsService.AppSettings.TranslationSettings.SelectedTargetLanguageIndex].Code;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int GetDefaultTargetLanguageIndex()
|
|
||||||
{
|
|
||||||
int found = SupportedTargetLanguages.FindIndex(x => ApplicationLanguages.Languages.FirstOrDefault()?.Contains(x.Code) == true);
|
|
||||||
if (found == -1) found = 7; // 默认使用英语
|
|
||||||
return found;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetOrderChar(string text)
|
public static string GetOrderChar(string text)
|
||||||
@@ -118,12 +135,17 @@ namespace BetterLyrics.WinUI3.Services
|
|||||||
if (char.IsLetter(c) && c < 128)
|
if (char.IsLetter(c) && c < 128)
|
||||||
return char.ToUpper(c).ToString();
|
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 "#";
|
return "#";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string ToRomaji(string text)
|
||||||
|
{
|
||||||
|
return string.Join(" ", RomajiConverter.Core.Helpers.RomajiHelper.SentenceToRomaji(text).Select(x => x.Romaji));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using Nito.AsyncEx;
|
using System;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@@ -10,33 +9,25 @@ namespace BetterLyrics.WinUI3.Helper
|
|||||||
{
|
{
|
||||||
public class LatestOnlyTaskRunner
|
public class LatestOnlyTaskRunner
|
||||||
{
|
{
|
||||||
private readonly AsyncLock _mutex = new();
|
private CancellationTokenSource? _cts;
|
||||||
private CancellationTokenSource _cts;
|
|
||||||
|
|
||||||
public async Task RunAsync(Func<CancellationToken, Task> action)
|
public async Task RunAsync(Func<CancellationToken, Task> taskFactory)
|
||||||
{
|
{
|
||||||
CancellationTokenSource oldCts;
|
_cts?.Cancel();
|
||||||
|
_cts?.Dispose();
|
||||||
|
|
||||||
// 使用 AsyncLock 保证线程安全
|
_cts = new CancellationTokenSource();
|
||||||
using (await _mutex.LockAsync())
|
var token = _cts.Token;
|
||||||
{
|
|
||||||
// 取消旧的
|
|
||||||
oldCts = _cts;
|
|
||||||
_cts = new CancellationTokenSource();
|
|
||||||
}
|
|
||||||
|
|
||||||
oldCts?.Cancel();
|
|
||||||
oldCts?.Dispose();
|
|
||||||
|
|
||||||
CancellationToken token = _cts.Token;
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await action(token);
|
await taskFactory(token);
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
{
|
{
|
||||||
// 可以选择忽略取消异常
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,17 +4,17 @@ using BetterLyrics.WinUI3.Enums;
|
|||||||
using BetterLyrics.WinUI3.Models;
|
using BetterLyrics.WinUI3.Models;
|
||||||
using BetterLyrics.WinUI3.Services;
|
using BetterLyrics.WinUI3.Services;
|
||||||
using Lyricify.Lyrics.Models;
|
using Lyricify.Lyrics.Models;
|
||||||
|
using Lyricify.Lyrics.Parsers;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
using Windows.Globalization.Fonts;
|
|
||||||
using LyricsData = BetterLyrics.WinUI3.Models.LyricsData;
|
using LyricsData = BetterLyrics.WinUI3.Models.LyricsData;
|
||||||
|
|
||||||
namespace BetterLyrics.WinUI3.Helper
|
namespace BetterLyrics.WinUI3.Helper
|
||||||
{
|
{
|
||||||
public class LyricsParser
|
public partial class LyricsParser
|
||||||
{
|
{
|
||||||
private List<LyricsData> _lyricsDataArr = [];
|
private List<LyricsData> _lyricsDataArr = [];
|
||||||
|
|
||||||
@@ -35,10 +35,10 @@ namespace BetterLyrics.WinUI3.Helper
|
|||||||
ParseLrc(raw);
|
ParseLrc(raw);
|
||||||
break;
|
break;
|
||||||
case LyricsFormat.Qrc:
|
case LyricsFormat.Qrc:
|
||||||
ParseQQNeteaseKugou(Lyricify.Lyrics.Parsers.QrcParser.Parse(raw).Lines);
|
ParseQQNeteaseKugou(QrcParser.Parse(raw).Lines);
|
||||||
break;
|
break;
|
||||||
case LyricsFormat.Krc:
|
case LyricsFormat.Krc:
|
||||||
ParseQQNeteaseKugou(Lyricify.Lyrics.Parsers.KrcParser.Parse(raw).Lines);
|
ParseQQNeteaseKugou(KrcParser.Parse(raw).Lines);
|
||||||
break;
|
break;
|
||||||
case LyricsFormat.Ttml:
|
case LyricsFormat.Ttml:
|
||||||
ParseTtml(raw);
|
ParseTtml(raw);
|
||||||
@@ -47,10 +47,74 @@ namespace BetterLyrics.WinUI3.Helper
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
FillRomanizationLyricsData();
|
||||||
_lyricsDataArr.Add(new LyricsData()); // 为机翻预留
|
_lyricsDataArr.Add(new LyricsData()); // 为机翻预留
|
||||||
return _lyricsDataArr;
|
return _lyricsDataArr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void FillRomanizationLyricsData()
|
||||||
|
{
|
||||||
|
var chinese = _lyricsDataArr.Where(x => x.LanguageCode == "zh").FirstOrDefault();
|
||||||
|
if (chinese != null)
|
||||||
|
{
|
||||||
|
_lyricsDataArr.Add(new LyricsData
|
||||||
|
{
|
||||||
|
LanguageCode = "pinyin",
|
||||||
|
LyricsLines = chinese.LyricsLines.Select(line => new LyricsLine
|
||||||
|
{
|
||||||
|
StartMs = line.StartMs,
|
||||||
|
EndMs = line.EndMs,
|
||||||
|
OriginalText = Pinyin.Pinyin.Instance.HanziToPinyin(line.OriginalText).ToStr(),
|
||||||
|
LyricsChars = line.LyricsChars.Select(c => new LyricsChar
|
||||||
|
{
|
||||||
|
StartMs = c.StartMs,
|
||||||
|
EndMs = c.EndMs,
|
||||||
|
Text = Pinyin.Pinyin.Instance.HanziToPinyin(c.Text).ToStr(),
|
||||||
|
StartIndex = c.StartIndex
|
||||||
|
}).ToList()
|
||||||
|
}).ToList()
|
||||||
|
});
|
||||||
|
_lyricsDataArr.Add(new LyricsData
|
||||||
|
{
|
||||||
|
LanguageCode = "jyutping",
|
||||||
|
LyricsLines = chinese.LyricsLines.Select(line => new LyricsLine
|
||||||
|
{
|
||||||
|
StartMs = line.StartMs,
|
||||||
|
EndMs = line.EndMs,
|
||||||
|
OriginalText = Pinyin.Jyutping.Instance.HanziToPinyin(line.OriginalText).ToStr(),
|
||||||
|
LyricsChars = line.LyricsChars.Select(c => new LyricsChar
|
||||||
|
{
|
||||||
|
StartMs = c.StartMs,
|
||||||
|
EndMs = c.EndMs,
|
||||||
|
Text = Pinyin.Jyutping.Instance.HanziToPinyin(c.Text).ToStr(),
|
||||||
|
StartIndex = c.StartIndex
|
||||||
|
}).ToList()
|
||||||
|
}).ToList()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
var japanese = _lyricsDataArr.Where(x => x.LanguageCode == "ja").FirstOrDefault();
|
||||||
|
if (japanese != null)
|
||||||
|
{
|
||||||
|
_lyricsDataArr.Add(new LyricsData
|
||||||
|
{
|
||||||
|
LanguageCode = "romaji",
|
||||||
|
LyricsLines = japanese.LyricsLines.Select(line => new LyricsLine
|
||||||
|
{
|
||||||
|
StartMs = line.StartMs,
|
||||||
|
EndMs = line.EndMs,
|
||||||
|
OriginalText = LanguageHelper.ToRomaji(line.OriginalText),
|
||||||
|
LyricsChars = line.LyricsChars.Select(c => new LyricsChar
|
||||||
|
{
|
||||||
|
StartMs = c.StartMs,
|
||||||
|
EndMs = c.EndMs,
|
||||||
|
Text = LanguageHelper.ToRomaji(c.Text),
|
||||||
|
StartIndex = c.StartIndex
|
||||||
|
}).ToList()
|
||||||
|
}).ToList()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void ParseLrc(string raw)
|
private void ParseLrc(string raw)
|
||||||
{
|
{
|
||||||
var lines = raw.Split(["\r\n", "\n"], StringSplitOptions.RemoveEmptyEntries);
|
var lines = raw.Split(["\r\n", "\n"], StringSplitOptions.RemoveEmptyEntries);
|
||||||
@@ -58,9 +122,7 @@ namespace BetterLyrics.WinUI3.Helper
|
|||||||
new List<(int time, string text, List<(int time, string text)> syllables)>();
|
new List<(int time, string text, List<(int time, string text)> syllables)>();
|
||||||
|
|
||||||
// 支持 [mm:ss.xx]字、<mm:ss.xx>字,毫秒两位或三位
|
// 支持 [mm:ss.xx]字、<mm:ss.xx>字,毫秒两位或三位
|
||||||
var syllableRegex = new Regex(
|
var syllableRegex = SyllableRegex();
|
||||||
@"(\[|\<)(\d{2}):(\d{2})\.(\d{2,3})(\]|\>)([^\[\]\<\>]*)"
|
|
||||||
);
|
|
||||||
|
|
||||||
foreach (var line in lines)
|
foreach (var line in lines)
|
||||||
{
|
{
|
||||||
@@ -77,7 +139,7 @@ namespace BetterLyrics.WinUI3.Helper
|
|||||||
|
|
||||||
syllables.Add((totalMs, text));
|
syllables.Add((totalMs, text));
|
||||||
}
|
}
|
||||||
if (syllables.Count > 0)
|
if (syllables.Count > 1)
|
||||||
{
|
{
|
||||||
lrcLines.Add(
|
lrcLines.Add(
|
||||||
(
|
(
|
||||||
@@ -90,18 +152,19 @@ namespace BetterLyrics.WinUI3.Helper
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// 普通LRC行
|
// 普通LRC行
|
||||||
var bracketRegex = new Regex(@"\[(\d{2}):(\d{2})\.(\d{2,3})\]");
|
Regex? bracketRegex = LrcRegex();
|
||||||
var bracketMatches = bracketRegex.Matches(line);
|
var bracketMatches = bracketRegex.Matches(line);
|
||||||
|
|
||||||
string content = line;
|
string content = line;
|
||||||
int? lineStartTime = null;
|
int? lineStartTime = null;
|
||||||
if (bracketMatches.Count > 0)
|
if (bracketMatches.Count > 0)
|
||||||
{
|
{
|
||||||
var m = bracketMatches[0];
|
var m = bracketMatches![0];
|
||||||
int min = int.Parse(m.Groups[1].Value);
|
int min = int.Parse(m.Groups[1].Value);
|
||||||
int sec = int.Parse(m.Groups[2].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;
|
lineStartTime = min * 60_000 + sec * 1000 + ms;
|
||||||
content = bracketRegex.Replace(line, "");
|
content = bracketRegex!.Replace(line, "");
|
||||||
lrcLines.Add((lineStartTime.Value, content, new List<(int, string)>()));
|
lrcLines.Add((lineStartTime.Value, content, new List<(int, string)>()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -182,10 +245,11 @@ namespace BetterLyrics.WinUI3.Helper
|
|||||||
int pStartMs = ParseTtmlTime(pBegin);
|
int pStartMs = ParseTtmlTime(pBegin);
|
||||||
int pEndMs = ParseTtmlTime(pEnd);
|
int pEndMs = ParseTtmlTime(pEnd);
|
||||||
|
|
||||||
// 只获取一级span,且排除ttm:role="x-bg"的span
|
// 只获取一级span,且排除 ttm:role="x-bg" 的 span 和 ttm:role="x-roman"
|
||||||
var spans = p.Elements()
|
var spans = p.Elements()
|
||||||
.Where(s => s.Name.LocalName == "span" &&
|
.Where(s => s.Name.LocalName == "span" &&
|
||||||
s.Attribute(XName.Get("role", "http://www.w3.org/ns/ttml#metadata"))?.Value != "x-bg")
|
s.Attribute(XName.Get("role", "http://www.w3.org/ns/ttml#metadata"))?.Value != "x-bg" &&
|
||||||
|
s.Attribute(XName.Get("role", "http://www.w3.org/ns/ttml#metadata"))?.Value != "x-roman")
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
// 原文和翻译分离
|
// 原文和翻译分离
|
||||||
@@ -386,5 +450,10 @@ namespace BetterLyrics.WinUI3.Helper
|
|||||||
|
|
||||||
_lyricsDataArr.Add(new LyricsData(lyricsLines));
|
_lyricsDataArr.Add(new LyricsData(lyricsLines));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[GeneratedRegex(@"\[(\d*):(\d*)(\.|\:)(\d*)\]")]
|
||||||
|
private static partial Regex LrcRegex();
|
||||||
|
[GeneratedRegex(@"(\[|\<)(\d*):(\d*)\.(\d*)(\]|\>)([^\[\]\<\>]*)")]
|
||||||
|
private static partial Regex SyllableRegex();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,9 @@
|
|||||||
// 2025/6/23 by Zhe Fang
|
// 2025/6/23 by Zhe Fang
|
||||||
|
|
||||||
|
using Windows.ApplicationModel;
|
||||||
|
|
||||||
namespace BetterLyrics.WinUI3.Helper
|
namespace BetterLyrics.WinUI3.Helper
|
||||||
{
|
{
|
||||||
using BetterLyrics.WinUI3.Models;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Windows.ApplicationModel;
|
|
||||||
using Windows.Storage;
|
|
||||||
using Windows.Storage.FileProperties;
|
|
||||||
|
|
||||||
public static class MetadataHelper
|
public static class MetadataHelper
|
||||||
{
|
{
|
||||||
public static string AppVersion
|
public static string AppVersion
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using Microsoft.UI.Xaml;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
@@ -6,6 +7,7 @@ using System.Text;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Vanara.PInvoke;
|
using Vanara.PInvoke;
|
||||||
|
using WinRT.Interop;
|
||||||
|
|
||||||
namespace BetterLyrics.WinUI3.Helper
|
namespace BetterLyrics.WinUI3.Helper
|
||||||
{
|
{
|
||||||
@@ -60,5 +62,14 @@ namespace BetterLyrics.WinUI3.Helper
|
|||||||
var primaryMonitorInfo = GetPrimaryMonitorInfoEx();
|
var primaryMonitorInfo = GetPrimaryMonitorInfoEx();
|
||||||
return primaryMonitorInfo.szDevice;
|
return primaryMonitorInfo.szDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static User32.MONITORINFOEX GetMonitorInfoExFromWindow(Window window)
|
||||||
|
{
|
||||||
|
var hwnd = WindowNative.GetWindowHandle(window);
|
||||||
|
var hMonitor = User32.MonitorFromWindow(hwnd, User32.MonitorFlags.MONITOR_DEFAULTTONEAREST);
|
||||||
|
User32.MONITORINFOEX monitorInfoEx = new() { cbSize = (uint)Marshal.SizeOf<User32.MONITORINFOEX>() };
|
||||||
|
User32.GetMonitorInfo(hMonitor, ref monitorInfoEx);
|
||||||
|
return monitorInfoEx;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,83 @@
|
|||||||
|
using ColorThiefDotNet;
|
||||||
|
using Impressionist.Abstractions;
|
||||||
|
using Impressionist.Implementations;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Runtime.InteropServices.WindowsRuntime;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Windows.Graphics.Imaging;
|
||||||
|
using Windows.Storage.Streams;
|
||||||
|
|
||||||
|
namespace BetterLyrics.WinUI3.Helper
|
||||||
|
{
|
||||||
|
public static class PaletteHelper
|
||||||
|
{
|
||||||
|
private static ColorThief colorThief = new();
|
||||||
|
public static async Task<PaletteResult> OctTreeGetAccentColorsFromByteAsync(BitmapDecoder decoder, int count, bool? isDark = null)
|
||||||
|
{
|
||||||
|
var colors = await GetPixelColor(decoder);
|
||||||
|
var palette = await PaletteGenerators.OctTreePaletteGenerator.CreatePalette(colors, count, false, isDark);
|
||||||
|
return palette;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<ThemeColorResult> OctTreeGetAccentColorFromByteAsync(BitmapDecoder decoder)
|
||||||
|
{
|
||||||
|
var colors = await GetPixelColor(decoder);
|
||||||
|
var theme = await PaletteGenerators.OctTreePaletteGenerator.CreateThemeColor(colors, false);
|
||||||
|
return theme;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<ThemeColorResult> MedianCutGetAccentColorFromByteAsync(BitmapDecoder decoder)
|
||||||
|
{
|
||||||
|
var mainColor = await colorThief.GetColor(decoder, 10, false);
|
||||||
|
var theme = new ThemeColorResult(new Vector3(mainColor.Color.R, mainColor.Color.G, mainColor.Color.B), mainColor.IsDark);
|
||||||
|
return theme;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<PaletteResult> MedianCutGetAccentColorsFromByteAsync(BitmapDecoder decoder, int count, bool? isDark = null)
|
||||||
|
{
|
||||||
|
var mainColor = await colorThief.GetColor(decoder, 10, false);
|
||||||
|
var theme = new ThemeColorResult(new Vector3(mainColor.Color.R, mainColor.Color.G, mainColor.Color.B), mainColor.IsDark);
|
||||||
|
var palette = await colorThief.GetPalette(decoder, 255, 10, false);
|
||||||
|
var topColors = palette
|
||||||
|
.Where(x => x.IsDark == (isDark ?? mainColor.IsDark))
|
||||||
|
.OrderByDescending(x => x.Population)
|
||||||
|
.Select(x => new Vector3(x.Color.R, x.Color.G, x.Color.B))
|
||||||
|
.Take(count)
|
||||||
|
.ToList();
|
||||||
|
var paletteResult = new PaletteResult(topColors, mainColor.IsDark, theme);
|
||||||
|
|
||||||
|
return paletteResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<Dictionary<Vector3, int>> GetPixelColor(BitmapDecoder bitmapDecoder)
|
||||||
|
{
|
||||||
|
var pixelDataProvider = await bitmapDecoder.GetPixelDataAsync();
|
||||||
|
var pixels = pixelDataProvider.DetachPixelData();
|
||||||
|
var count = bitmapDecoder.PixelWidth * bitmapDecoder.PixelHeight;
|
||||||
|
var vector = new Dictionary<Vector3, int>();
|
||||||
|
for (int i = 0; i < count; i += 10)
|
||||||
|
{
|
||||||
|
var offset = i * 4;
|
||||||
|
var b = pixels[offset];
|
||||||
|
var g = pixels[offset + 1];
|
||||||
|
var r = pixels[offset + 2];
|
||||||
|
var a = pixels[offset + 3];
|
||||||
|
if (a == 0) continue;
|
||||||
|
var color = new Vector3(r, g, b);
|
||||||
|
if (vector.ContainsKey(color))
|
||||||
|
{
|
||||||
|
vector[color]++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vector[color] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return vector;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -34,6 +34,10 @@ namespace BetterLyrics.WinUI3.Helper
|
|||||||
public static string PotPlayerLogoPath => Path.Combine(AssetsFolder, "PotPlayer.png");
|
public static string PotPlayerLogoPath => Path.Combine(AssetsFolder, "PotPlayer.png");
|
||||||
public static string ChromeLogoPath => Path.Combine(AssetsFolder, "Chrome.png");
|
public static string ChromeLogoPath => Path.Combine(AssetsFolder, "Chrome.png");
|
||||||
public static string EdgeLogoPath => Path.Combine(AssetsFolder, "Edge.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 UnknownPlayerLogoPath => Path.Combine(AssetsFolder, "Question.png");
|
||||||
|
|
||||||
public static string LogDirectory => Path.Combine(CacheFolder, "logs");
|
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 QQLyricsCacheDirectory => Path.Combine(LyricsCacheDirectory, "qq");
|
||||||
public static string KugouLyricsCacheDirectory => Path.Combine(LyricsCacheDirectory, "kugou");
|
public static string KugouLyricsCacheDirectory => Path.Combine(LyricsCacheDirectory, "kugou");
|
||||||
public static string AmllTtmlDbLyricsCacheDirectory => Path.Combine(LyricsCacheDirectory, "amll-ttml-db");
|
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 AmllTtmlDbIndexPath => Path.Combine(LyricsCacheDirectory, "amll-ttml-db-index.json");
|
||||||
public static string AmllTtmlDbLastUpdatedPath => Path.Combine(LyricsCacheDirectory, "amll-ttml-db-last-updated.txt");
|
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 QQTranslationCacheDirectory => Path.Combine(TranslationCacheDirectory, "qq");
|
||||||
public static string NeteaseTranslationCacheDirectory => Path.Combine(TranslationCacheDirectory, "netease");
|
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");
|
public static string AlbumArtCacheDirectory => Path.Combine(CacheFolder, "album-art");
|
||||||
|
|
||||||
@@ -69,9 +75,11 @@ namespace BetterLyrics.WinUI3.Helper
|
|||||||
Directory.CreateDirectory(KugouLyricsCacheDirectory);
|
Directory.CreateDirectory(KugouLyricsCacheDirectory);
|
||||||
Directory.CreateDirectory(NeteaseLyricsCacheDirectory);
|
Directory.CreateDirectory(NeteaseLyricsCacheDirectory);
|
||||||
Directory.CreateDirectory(AmllTtmlDbLyricsCacheDirectory);
|
Directory.CreateDirectory(AmllTtmlDbLyricsCacheDirectory);
|
||||||
|
Directory.CreateDirectory(AppleMusicCacheDirectory);
|
||||||
|
|
||||||
Directory.CreateDirectory(QQTranslationCacheDirectory);
|
Directory.CreateDirectory(QQTranslationCacheDirectory);
|
||||||
Directory.CreateDirectory(NeteaseTranslationCacheDirectory);
|
Directory.CreateDirectory(NeteaseTranslationCacheDirectory);
|
||||||
|
Directory.CreateDirectory(KugouTranslationCacheDirectory);
|
||||||
|
|
||||||
Directory.CreateDirectory(iTunesAlbumArtCacheDirectory);
|
Directory.CreateDirectory(iTunesAlbumArtCacheDirectory);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
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.Helper
|
||||||
|
{
|
||||||
|
public static class PointHelper
|
||||||
|
{
|
||||||
|
public static PointInt32 ToPointInt32(this Point point)
|
||||||
|
{
|
||||||
|
return new PointInt32((int)point.X, (int)point.Y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,5 +18,45 @@ namespace BetterLyrics.WinUI3.Helper
|
|||||||
(int)rect.Height
|
(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
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
// 2025/6/23 by Zhe Fang
|
// 2025/6/23 by Zhe Fang
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
|
||||||
using BetterLyrics.WinUI3.Enums;
|
using BetterLyrics.WinUI3.Enums;
|
||||||
|
|
||||||
namespace BetterLyrics.WinUI3.Helper
|
namespace BetterLyrics.WinUI3.Helper
|
||||||
@@ -11,6 +10,8 @@ namespace BetterLyrics.WinUI3.Helper
|
|||||||
{
|
{
|
||||||
private T _currentValue;
|
private T _currentValue;
|
||||||
private double _durationSeconds;
|
private double _durationSeconds;
|
||||||
|
private double _delaySeconds;
|
||||||
|
private double _delayRemaining;
|
||||||
private EasingType? _easingType;
|
private EasingType? _easingType;
|
||||||
private Func<T, T, double, T> _interpolator;
|
private Func<T, T, double, T> _interpolator;
|
||||||
private bool _isTransitioning;
|
private bool _isTransitioning;
|
||||||
@@ -19,18 +20,21 @@ namespace BetterLyrics.WinUI3.Helper
|
|||||||
private T _targetValue;
|
private T _targetValue;
|
||||||
|
|
||||||
public double DurationSeconds => _durationSeconds;
|
public double DurationSeconds => _durationSeconds;
|
||||||
|
public double DelaySeconds => _delaySeconds;
|
||||||
|
|
||||||
public bool IsTransitioning => _isTransitioning;
|
public bool IsTransitioning => _isTransitioning;
|
||||||
public T Value => _currentValue;
|
public T Value => _currentValue;
|
||||||
public T TargetValue => _targetValue;
|
public T TargetValue => _targetValue;
|
||||||
public EasingType? EasingType => _easingType;
|
public EasingType? EasingType => _easingType;
|
||||||
|
|
||||||
public ValueTransition(T initialValue, double durationSeconds, Func<T, T, double, T>? interpolator = null, EasingType? easingType = null)
|
public ValueTransition(T initialValue, double durationSeconds, Func<T, T, double, T>? interpolator = null, EasingType? easingType = null, double delaySeconds = 0)
|
||||||
{
|
{
|
||||||
_currentValue = initialValue;
|
_currentValue = initialValue;
|
||||||
_startValue = initialValue;
|
_startValue = initialValue;
|
||||||
_targetValue = initialValue;
|
_targetValue = initialValue;
|
||||||
_durationSeconds = durationSeconds;
|
_durationSeconds = durationSeconds;
|
||||||
|
_delaySeconds = delaySeconds;
|
||||||
|
_delayRemaining = 0;
|
||||||
_progress = 1f;
|
_progress = 1f;
|
||||||
_isTransitioning = false;
|
_isTransitioning = false;
|
||||||
|
|
||||||
@@ -46,7 +50,7 @@ namespace BetterLyrics.WinUI3.Helper
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_easingType = Enums.EasingType.Linear;
|
_easingType = Enums.EasingType.EaseInOutQuad;
|
||||||
_interpolator = GetInterpolatorByEasingType(_easingType.Value);
|
_interpolator = GetInterpolatorByEasingType(_easingType.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -58,12 +62,18 @@ namespace BetterLyrics.WinUI3.Helper
|
|||||||
_durationSeconds = seconds;
|
_durationSeconds = seconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetDelay(double seconds)
|
||||||
|
{
|
||||||
|
_delaySeconds = seconds;
|
||||||
|
}
|
||||||
|
|
||||||
private void JumpTo(T value)
|
private void JumpTo(T value)
|
||||||
{
|
{
|
||||||
_currentValue = value;
|
_currentValue = value;
|
||||||
_startValue = value;
|
_startValue = value;
|
||||||
_targetValue = value;
|
_targetValue = value;
|
||||||
_progress = 1f;
|
_progress = 1f;
|
||||||
|
_delayRemaining = 0;
|
||||||
_isTransitioning = false;
|
_isTransitioning = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,6 +83,7 @@ namespace BetterLyrics.WinUI3.Helper
|
|||||||
_startValue = value;
|
_startValue = value;
|
||||||
_targetValue = value;
|
_targetValue = value;
|
||||||
_progress = 0f;
|
_progress = 0f;
|
||||||
|
_delayRemaining = 0;
|
||||||
_isTransitioning = false;
|
_isTransitioning = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,6 +100,7 @@ namespace BetterLyrics.WinUI3.Helper
|
|||||||
_startValue = _currentValue;
|
_startValue = _currentValue;
|
||||||
_targetValue = targetValue;
|
_targetValue = targetValue;
|
||||||
_progress = 0f;
|
_progress = 0f;
|
||||||
|
_delayRemaining = _delaySeconds;
|
||||||
_isTransitioning = true;
|
_isTransitioning = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -103,7 +115,24 @@ namespace BetterLyrics.WinUI3.Helper
|
|||||||
{
|
{
|
||||||
if (!_isTransitioning) return;
|
if (!_isTransitioning) return;
|
||||||
|
|
||||||
_progress += (double)(elapsedTime / TimeSpan.FromSeconds(_durationSeconds));
|
if (_delayRemaining > 0)
|
||||||
|
{
|
||||||
|
double consume = Math.Min(_delayRemaining, elapsedTime.TotalSeconds);
|
||||||
|
_delayRemaining -= consume;
|
||||||
|
if (_delayRemaining > 0)
|
||||||
|
return;
|
||||||
|
elapsedTime = TimeSpan.FromSeconds(elapsedTime.TotalSeconds - consume);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_durationSeconds <= 0)
|
||||||
|
{
|
||||||
|
_progress = 1f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_progress += elapsedTime.TotalSeconds / _durationSeconds;
|
||||||
|
}
|
||||||
|
|
||||||
if (_progress >= 1f)
|
if (_progress >= 1f)
|
||||||
{
|
{
|
||||||
_progress = 1f;
|
_progress = 1f;
|
||||||
@@ -178,4 +207,4 @@ namespace BetterLyrics.WinUI3.Helper
|
|||||||
_interpolator = GetInterpolatorByEasingType(easingType);
|
_interpolator = GetInterpolatorByEasingType(easingType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,20 @@
|
|||||||
// 2025/6/23 by Zhe Fang
|
// 2025/6/23 by Zhe Fang
|
||||||
|
|
||||||
using BetterLyrics.WinUI3.Enums;
|
using BetterLyrics.WinUI3.Enums;
|
||||||
|
using BetterLyrics.WinUI3.Services.LiveStatesService;
|
||||||
|
using BetterLyrics.WinUI3.Services.MediaSessionsService;
|
||||||
using BetterLyrics.WinUI3.Views;
|
using BetterLyrics.WinUI3.Views;
|
||||||
|
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||||
|
using CommunityToolkit.WinUI;
|
||||||
using Microsoft.UI.Windowing;
|
using Microsoft.UI.Windowing;
|
||||||
using Microsoft.UI.Xaml;
|
using Microsoft.UI.Xaml;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Vanara.PInvoke;
|
||||||
using Windows.ApplicationModel.Core;
|
using Windows.ApplicationModel.Core;
|
||||||
|
using Windows.Foundation;
|
||||||
using WinRT.Interop;
|
using WinRT.Interop;
|
||||||
using WinUIEx;
|
using WinUIEx;
|
||||||
|
|
||||||
@@ -15,9 +23,27 @@ namespace BetterLyrics.WinUI3.Helper
|
|||||||
public static class WindowHelper
|
public static class WindowHelper
|
||||||
{
|
{
|
||||||
private static List<object> _activeWindows = [];
|
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);
|
||||||
|
var castedWindow = window as Window;
|
||||||
|
castedWindow?.Hide();
|
||||||
|
}
|
||||||
|
|
||||||
public static void CloseWindow<T>()
|
public static void CloseWindow<T>()
|
||||||
{
|
{
|
||||||
|
if (typeof(T) == typeof(LyricsWindow))
|
||||||
|
{
|
||||||
|
EnsureDockModeReleased();
|
||||||
|
}
|
||||||
var window = _activeWindows.Find(w => w is T);
|
var window = _activeWindows.Find(w => w is T);
|
||||||
if (window is Window w)
|
if (window is Window w)
|
||||||
{
|
{
|
||||||
@@ -37,7 +63,8 @@ namespace BetterLyrics.WinUI3.Helper
|
|||||||
}
|
}
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
public static void OpenWindow<T>()
|
|
||||||
|
public static void OpenOrShowWindow<T>()
|
||||||
{
|
{
|
||||||
var window = _activeWindows.Find(w => w is T);
|
var window = _activeWindows.Find(w => w is T);
|
||||||
if (window == null)
|
if (window == null)
|
||||||
@@ -55,15 +82,49 @@ namespace BetterLyrics.WinUI3.Helper
|
|||||||
{
|
{
|
||||||
window = new MusicGalleryWindow();
|
window = new MusicGalleryWindow();
|
||||||
}
|
}
|
||||||
|
else if (typeof(T) == typeof(LyricsSearchWindow))
|
||||||
|
{
|
||||||
|
window = new LyricsSearchWindow();
|
||||||
|
}
|
||||||
|
else if (typeof(T) == typeof(LyricsWindowSwitchWindow))
|
||||||
|
{
|
||||||
|
window = new LyricsWindowSwitchWindow();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Unsupported window type", nameof(T));
|
throw new ArgumentException("Unsupported window type", nameof(T));
|
||||||
}
|
}
|
||||||
TrackWindow(window);
|
TrackWindow(window);
|
||||||
|
var castedWindow = (Window)window;
|
||||||
|
castedWindow.Restore();
|
||||||
|
castedWindow.Activate();
|
||||||
|
|
||||||
|
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.ViewModel.InitFgWindowWatcher();
|
||||||
|
lyricsWindow.ViewModel.RefreshLyricsWindowStatus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var castedWindow = (Window)window;
|
||||||
|
if (typeof(T) == typeof(LyricsWindow))
|
||||||
|
{
|
||||||
|
var lyricsWindow = (LyricsWindow)window;
|
||||||
|
lyricsWindow.Show();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
castedWindow.Restore();
|
||||||
|
castedWindow.Activate();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
var castedWindow = (Window)window;
|
|
||||||
castedWindow.Restore();
|
|
||||||
castedWindow.Activate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void RestartApp(string args = "")
|
public static void RestartApp(string args = "")
|
||||||
@@ -88,14 +149,15 @@ namespace BetterLyrics.WinUI3.Helper
|
|||||||
|
|
||||||
public static void ExitApp()
|
public static void ExitApp()
|
||||||
{
|
{
|
||||||
LyricsWindow? lyricsWindow = WindowHelper.GetWindowByWindowType<LyricsWindow>();
|
EnsureDockModeReleased();
|
||||||
if (lyricsWindow != null)
|
|
||||||
{
|
|
||||||
DockModeHelper.Disable(lyricsWindow);
|
|
||||||
}
|
|
||||||
Environment.Exit(0);
|
Environment.Exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void EnsureDockModeReleased()
|
||||||
|
{
|
||||||
|
SetIsWorkArea<LyricsWindow>(false);
|
||||||
|
}
|
||||||
|
|
||||||
private static void TrackWindow(object window)
|
private static void TrackWindow(object window)
|
||||||
{
|
{
|
||||||
if (!_activeWindows.Contains(window))
|
if (!_activeWindows.Contains(window))
|
||||||
@@ -111,7 +173,224 @@ namespace BetterLyrics.WinUI3.Helper
|
|||||||
if (_activeWindows.Contains(sender))
|
if (_activeWindows.Contains(sender))
|
||||||
{
|
{
|
||||||
_activeWindows.Remove(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>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
26
BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/LiveStates.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
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;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Vanara.PInvoke;
|
||||||
|
using Windows.Foundation;
|
||||||
|
|
||||||
|
namespace BetterLyrics.WinUI3.Models
|
||||||
|
{
|
||||||
|
public partial class LiveStates : ObservableRecipient
|
||||||
|
{
|
||||||
|
[ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsWindowStatus LyricsWindowStatus { get; set; }
|
||||||
|
|
||||||
|
public LiveStates()
|
||||||
|
{
|
||||||
|
LyricsWindowStatus = new LyricsWindowStatus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,15 +6,15 @@ namespace BetterLyrics.WinUI3.Models
|
|||||||
{
|
{
|
||||||
public partial class LocalMediaFolder : ObservableRecipient
|
public partial class LocalMediaFolder : ObservableRecipient
|
||||||
{
|
{
|
||||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsEnabled { get; set; }
|
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsEnabled { get; set; } = true;
|
||||||
|
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsRealTimeWatchEnabled { get; set; } = false;
|
||||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial string Path { get; set; }
|
[ObservableProperty][NotifyPropertyChangedRecipients] public partial string Path { get; set; }
|
||||||
|
|
||||||
public LocalMediaFolder() { }
|
public LocalMediaFolder() { }
|
||||||
|
|
||||||
public LocalMediaFolder(string path, bool isEnabled)
|
public LocalMediaFolder(string path)
|
||||||
{
|
{
|
||||||
Path = path;
|
Path = path;
|
||||||
IsEnabled = isEnabled;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using BetterLyrics.WinUI3.Helper;
|
using BetterLyrics.WinUI3.Enums;
|
||||||
|
using BetterLyrics.WinUI3.Helper;
|
||||||
using BetterLyrics.WinUI3.Services;
|
using BetterLyrics.WinUI3.Services;
|
||||||
using Lyricify.Lyrics.Helpers.General;
|
using Lyricify.Lyrics.Helpers.General;
|
||||||
using System;
|
using System;
|
||||||
@@ -13,7 +14,12 @@ namespace BetterLyrics.WinUI3.Models
|
|||||||
public class LyricsData
|
public class LyricsData
|
||||||
{
|
{
|
||||||
public List<LyricsLine> LyricsLines { get; set; }
|
public List<LyricsLine> LyricsLines { get; set; }
|
||||||
public string? LanguageCode => LanguageHelper.DetectLanguageCode(WrappedOriginalText);
|
private string? _languageCode;
|
||||||
|
public string? LanguageCode
|
||||||
|
{
|
||||||
|
get => _languageCode ?? LanguageHelper.DetectLanguageCode(WrappedOriginalText);
|
||||||
|
set => _languageCode = value;
|
||||||
|
}
|
||||||
public string WrappedOriginalText => string.Join(StringHelper.NewLine, LyricsLines.Select(line => line.OriginalText));
|
public string WrappedOriginalText => string.Join(StringHelper.NewLine, LyricsLines.Select(line => line.OriginalText));
|
||||||
|
|
||||||
public LyricsData()
|
public LyricsData()
|
||||||
@@ -36,23 +42,7 @@ namespace BetterLyrics.WinUI3.Models
|
|||||||
|
|
||||||
if (transLine != null)
|
if (transLine != null)
|
||||||
{
|
{
|
||||||
if (translationData.LanguageCode?.StartsWith("zh") == true)
|
line.DisplayedText = $"{line.OriginalText}{separator}{transLine.OriginalText}";
|
||||||
{
|
|
||||||
string tmp = "";
|
|
||||||
if (LanguageHelper.GetUserTargetLanguageCode() == "zh-Hant")
|
|
||||||
{
|
|
||||||
tmp = ChineseConverter.ConvertToTraditionalChinese(transLine.OriginalText);
|
|
||||||
}
|
|
||||||
else if (LanguageHelper.GetUserTargetLanguageCode() == "zh-Hans")
|
|
||||||
{
|
|
||||||
tmp = ChineseConverter.ConvertToSimplifiedChinese(transLine.OriginalText);
|
|
||||||
}
|
|
||||||
line.DisplayedText = $"{line.OriginalText}{separator}{tmp}";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
line.DisplayedText = $"{line.OriginalText}{separator}{transLine.OriginalText}";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -136,5 +126,18 @@ namespace BetterLyrics.WinUI3.Models
|
|||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LyricsLine? GetLyricsLine(double sec)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < LyricsLines.Count; i++)
|
||||||
|
{
|
||||||
|
var line = LyricsLines[i];
|
||||||
|
if (line.StartMs > sec * 1000)
|
||||||
|
{
|
||||||
|
return LyricsLines.ElementAtOrDefault(i - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,32 +25,32 @@ namespace BetterLyrics.WinUI3.Models
|
|||||||
public ValueTransition<double> AngleTransition { get; set; } = new(
|
public ValueTransition<double> AngleTransition { get; set; } = new(
|
||||||
initialValue: 0,
|
initialValue: 0,
|
||||||
durationSeconds: _animationDuration,
|
durationSeconds: _animationDuration,
|
||||||
easingType: EasingType.EaseInOutSine
|
easingType: EasingType.EaseInOutQuad
|
||||||
);
|
);
|
||||||
public ValueTransition<double> BlurAmountTransition { get; set; } = new(
|
public ValueTransition<double> BlurAmountTransition { get; set; } = new(
|
||||||
initialValue: 0,
|
initialValue: 0,
|
||||||
durationSeconds: _animationDuration,
|
durationSeconds: _animationDuration,
|
||||||
easingType: EasingType.EaseInOutSine
|
easingType: EasingType.EaseInOutQuad
|
||||||
);
|
);
|
||||||
public ValueTransition<double> HighlightOpacityTransition { get; set; } = new(
|
public ValueTransition<double> HighlightOpacityTransition { get; set; } = new(
|
||||||
initialValue: 0,
|
initialValue: 0,
|
||||||
durationSeconds: _animationDuration,
|
durationSeconds: _animationDuration,
|
||||||
easingType: EasingType.EaseInOutSine
|
easingType: EasingType.EaseInOutQuad
|
||||||
);
|
);
|
||||||
public ValueTransition<double> OpacityTransition { get; set; } = new(
|
public ValueTransition<double> OpacityTransition { get; set; } = new(
|
||||||
initialValue: 0,
|
initialValue: 0,
|
||||||
durationSeconds: _animationDuration,
|
durationSeconds: _animationDuration,
|
||||||
easingType: EasingType.EaseInOutSine
|
easingType: EasingType.EaseInOutQuad
|
||||||
);
|
);
|
||||||
public ValueTransition<double> ScaleTransition { get; set; } = new(
|
public ValueTransition<double> ScaleTransition { get; set; } = new(
|
||||||
initialValue: 0.75,
|
initialValue: 0.75,
|
||||||
durationSeconds: _animationDuration,
|
durationSeconds: _animationDuration,
|
||||||
easingType: EasingType.EaseInOutSine
|
easingType: EasingType.EaseInOutQuad
|
||||||
);
|
);
|
||||||
public ValueTransition<double> YOffsetTransition { get; set; } = new(
|
public ValueTransition<double> YOffsetTransition { get; set; } = new(
|
||||||
initialValue: 0,
|
initialValue: 0,
|
||||||
durationSeconds: 0.5,
|
durationSeconds: 0.5,
|
||||||
easingType: EasingType.EaseInOutSine
|
easingType: EasingType.EaseInOutQuad
|
||||||
);
|
);
|
||||||
|
|
||||||
public CanvasTextLayout? CanvasTextLayout { get; private set; }
|
public CanvasTextLayout? CanvasTextLayout { get; private set; }
|
||||||
@@ -69,39 +69,6 @@ namespace BetterLyrics.WinUI3.Models
|
|||||||
|
|
||||||
public CanvasGeometry? TextGeometry { get; private set; }
|
public CanvasGeometry? TextGeometry { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 背景文字层(底字)
|
|
||||||
/// </summary>
|
|
||||||
public CanvasCommandList? BackgroundFontEffect { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 背景层
|
|
||||||
/// </summary>
|
|
||||||
public OpacityEffect? BackgroundEffect { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 辉光层
|
|
||||||
/// </summary>
|
|
||||||
public GaussianBlurEffect? ForegroundBlurEffect { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 高亮层
|
|
||||||
/// </summary>
|
|
||||||
public AlphaMaskEffect? ForegroundHighlightEffect { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 前景文字层
|
|
||||||
/// </summary>
|
|
||||||
public CanvasCommandList? ForegroundFontEffect { get; private set; }
|
|
||||||
|
|
||||||
public CanvasCommandList? ComposedLineEffect { get; private set; }
|
|
||||||
|
|
||||||
public CanvasCommandList? CurrentCharMask { get; private set; }
|
|
||||||
public CanvasCommandList? LineStartToCurrentCharMask { get; private set; }
|
|
||||||
public CanvasCommandList? CurrentLineMask { get; private set; }
|
|
||||||
|
|
||||||
public CanvasCommandList? PlaceholderEffect { get; private set; }
|
|
||||||
|
|
||||||
public void UpdateCenterPosition(double maxWidth, TextAlignmentType type)
|
public void UpdateCenterPosition(double maxWidth, TextAlignmentType type)
|
||||||
{
|
{
|
||||||
if (CanvasTextLayout == null)
|
if (CanvasTextLayout == null)
|
||||||
@@ -118,10 +85,15 @@ namespace BetterLyrics.WinUI3.Models
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RecreateTextLayout(ICanvasAnimatedControl control, CanvasTextFormat textFormat, double maxWidth, double maxHeight, TextAlignmentType type)
|
public void DisposeTextLayout()
|
||||||
{
|
{
|
||||||
CanvasTextLayout?.Dispose();
|
CanvasTextLayout?.Dispose();
|
||||||
CanvasTextLayout = null;
|
CanvasTextLayout = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RecreateTextLayout(ICanvasAnimatedControl control, CanvasTextFormat textFormat, double maxWidth, double maxHeight, TextAlignmentType type)
|
||||||
|
{
|
||||||
|
DisposeTextLayout();
|
||||||
CanvasTextLayout = new CanvasTextLayout(control, DisplayedText, textFormat, (float)maxWidth, (float)maxHeight);
|
CanvasTextLayout = new CanvasTextLayout(control, DisplayedText, textFormat, (float)maxWidth, (float)maxHeight);
|
||||||
CanvasTextLayout.HorizontalAlignment = type.ToCanvasHorizontalAlignment();
|
CanvasTextLayout.HorizontalAlignment = type.ToCanvasHorizontalAlignment();
|
||||||
}
|
}
|
||||||
@@ -141,392 +113,5 @@ namespace BetterLyrics.WinUI3.Models
|
|||||||
}
|
}
|
||||||
TextGeometry = CanvasGeometry.CreateText(CanvasTextLayout);
|
TextGeometry = CanvasGeometry.CreateText(CanvasTextLayout);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DisposeFontEffects()
|
|
||||||
{
|
|
||||||
BackgroundFontEffect?.Dispose();
|
|
||||||
BackgroundFontEffect = null;
|
|
||||||
ForegroundFontEffect?.Dispose();
|
|
||||||
ForegroundFontEffect = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RecreateFontEffect(ICanvasAnimatedControl control, Color strokeColor, int strokeWidth, Color bgFontColor, Color fgFontColor)
|
|
||||||
{
|
|
||||||
DisposeFontEffects();
|
|
||||||
if (TextGeometry == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
BackgroundFontEffect = new CanvasCommandList(control);
|
|
||||||
using var bgFontEffectDs = BackgroundFontEffect.CreateDrawingSession();
|
|
||||||
ForegroundFontEffect = new CanvasCommandList(control);
|
|
||||||
using var fgFontEffectDs = ForegroundFontEffect.CreateDrawingSession();
|
|
||||||
// 大于 0 才描边,避免不必要的资源浪费
|
|
||||||
if (strokeWidth > 0)
|
|
||||||
{
|
|
||||||
bgFontEffectDs.DrawGeometry(TextGeometry, Position, strokeColor, strokeWidth); // 描边
|
|
||||||
fgFontEffectDs.DrawGeometry(TextGeometry, Position, strokeColor, strokeWidth); // 描边
|
|
||||||
}
|
|
||||||
bgFontEffectDs.FillGeometry(TextGeometry, Position, bgFontColor); // 填充
|
|
||||||
fgFontEffectDs.FillGeometry(TextGeometry, Position, fgFontColor); // 填充
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 背景层
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="lyricsLayerOpacity">_lyricsOpacityTransition.Value</param>
|
|
||||||
public void RecreateBackgroundEffect(double lyricsLayerOpacity)
|
|
||||||
{
|
|
||||||
BackgroundEffect?.Dispose();
|
|
||||||
BackgroundEffect = null;
|
|
||||||
if (BackgroundFontEffect == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
BackgroundEffect = new OpacityEffect
|
|
||||||
{
|
|
||||||
Source = new GaussianBlurEffect
|
|
||||||
{
|
|
||||||
Source = BackgroundFontEffect,
|
|
||||||
BlurAmount = (float)BlurAmountTransition.Value,
|
|
||||||
BorderMode = EffectBorderMode.Soft,
|
|
||||||
Optimization = EffectOptimization.Speed,
|
|
||||||
},
|
|
||||||
Opacity = (float)(OpacityTransition.Value * lyricsLayerOpacity),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UpdateBackgroundEffect(double lyricsLayerOpacity)
|
|
||||||
{
|
|
||||||
BackgroundEffect?.Opacity = (float)(OpacityTransition.Value * lyricsLayerOpacity);
|
|
||||||
GaussianBlurEffect? blurEffect = (GaussianBlurEffect?)(BackgroundEffect?.Source);
|
|
||||||
blurEffect?.BlurAmount = (float)BlurAmountTransition.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private IGraphicsEffectSource GetAlphaMask(ICanvasAnimatedControl control, LineRenderingType lineRenderingType)
|
|
||||||
{
|
|
||||||
if (PlaceholderEffect == null)
|
|
||||||
{
|
|
||||||
RecreatePlaceholder(control);
|
|
||||||
}
|
|
||||||
|
|
||||||
var result = lineRenderingType switch
|
|
||||||
{
|
|
||||||
LineRenderingType.CurrentChar => CurrentCharMask,
|
|
||||||
LineRenderingType.LineStartToCurrentChar => LineStartToCurrentCharMask,
|
|
||||||
// Here, cuz AlphaMask only takes care of alpha channel
|
|
||||||
// so ForegroundFontEffect can be a mask for CurrentLine
|
|
||||||
// And we don't need to create a new mask for CurrentLine
|
|
||||||
LineRenderingType.CurrentLine => CurrentLineMask,
|
|
||||||
_ => PlaceholderEffect
|
|
||||||
};
|
|
||||||
return result ?? PlaceholderEffect!;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 销毁并重新创建辉光效果层
|
|
||||||
/// 仅需在布局重构 (Relayout) 时调用
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="lineRenderingType">_lyricsGlowEffectScope</param>
|
|
||||||
/// <param name="glowEffectAmount">_lyricsGlowEffectAmount</param>
|
|
||||||
public void RecreateForegroundBlurEffect(ICanvasAnimatedControl control, LineRenderingType lineRenderingType, double glowEffectAmount)
|
|
||||||
{
|
|
||||||
ForegroundBlurEffect?.Dispose();
|
|
||||||
ForegroundBlurEffect = null;
|
|
||||||
if (ForegroundFontEffect == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var mask = GetAlphaMask(control, lineRenderingType);
|
|
||||||
if (mask == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ForegroundBlurEffect = new GaussianBlurEffect
|
|
||||||
{
|
|
||||||
Source = new AlphaMaskEffect
|
|
||||||
{
|
|
||||||
Source = ForegroundFontEffect,
|
|
||||||
AlphaMask = mask,
|
|
||||||
},
|
|
||||||
BlurAmount = (float)glowEffectAmount,
|
|
||||||
Optimization = EffectOptimization.Speed,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 仅当前行需要调用此方法(每次 Update 都调用一次)
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="control"></param>
|
|
||||||
/// <param name="lineRenderingType"></param>
|
|
||||||
/// <param name="glowEffectAmount"></param>
|
|
||||||
public void UpdateForegroundBlurEffect(ICanvasAnimatedControl control, LineRenderingType lineRenderingType, double glowEffectAmount)
|
|
||||||
{
|
|
||||||
if (ForegroundBlurEffect == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (ForegroundFontEffect == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var mask = GetAlphaMask(control, lineRenderingType);
|
|
||||||
if (mask == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ForegroundBlurEffect.BlurAmount = (float)glowEffectAmount;
|
|
||||||
var alphaMaskEffect = (AlphaMaskEffect)ForegroundBlurEffect.Source;
|
|
||||||
alphaMaskEffect.Source = ForegroundFontEffect;
|
|
||||||
alphaMaskEffect.AlphaMask = mask;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 销毁并重新创建高亮效果层
|
|
||||||
/// 仅需在布局重构 (Relayout) 时调用
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="control"></param>
|
|
||||||
/// <param name="lineRenderingType"></param>
|
|
||||||
public void RecreateForegroundHighlightEffect(ICanvasAnimatedControl control, LineRenderingType lineRenderingType)
|
|
||||||
{
|
|
||||||
ForegroundHighlightEffect?.Dispose();
|
|
||||||
ForegroundHighlightEffect = null;
|
|
||||||
|
|
||||||
if (ForegroundFontEffect == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var mask = GetAlphaMask(control, lineRenderingType);
|
|
||||||
if (mask == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ForegroundHighlightEffect = new AlphaMaskEffect
|
|
||||||
{
|
|
||||||
Source = ForegroundFontEffect,
|
|
||||||
AlphaMask = mask,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 仅当前行需要调用此方法(每次 Update 都调用一次)
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="control"></param>
|
|
||||||
/// <param name="lineRenderingType"></param>
|
|
||||||
public void UpdateForegroundHighlightEffect(ICanvasAnimatedControl control, LineRenderingType lineRenderingType)
|
|
||||||
{
|
|
||||||
if (ForegroundHighlightEffect == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ForegroundFontEffect == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var mask = GetAlphaMask(control, lineRenderingType);
|
|
||||||
if (mask == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ForegroundHighlightEffect.Source = ForegroundFontEffect;
|
|
||||||
ForegroundHighlightEffect.AlphaMask = mask;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 仅当前播放行需要调用此方法(每次 Update 都调用一次)
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="control"></param>
|
|
||||||
/// <param name="playingLineIndex"></param>
|
|
||||||
/// <param name="charStartIndex"></param>
|
|
||||||
/// <param name="charLength"></param>
|
|
||||||
/// <param name="charProgress"></param>
|
|
||||||
public void RecreateCurrentCharMask(ICanvasAnimatedControl control, int charStartIndex, int charLength, double charProgress)
|
|
||||||
{
|
|
||||||
CurrentCharMask?.Dispose();
|
|
||||||
CurrentCharMask = null;
|
|
||||||
CurrentCharMask = new CanvasCommandList(control);
|
|
||||||
|
|
||||||
if (CanvasTextLayout == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
using var ds = CurrentCharMask.CreateDrawingSession();
|
|
||||||
|
|
||||||
var highlightRegion = CanvasTextLayout
|
|
||||||
.GetCharacterRegions(charStartIndex, charLength)
|
|
||||||
.FirstOrDefault();
|
|
||||||
|
|
||||||
double highlightTotalWidth = (double)highlightRegion.LayoutBounds.Width;
|
|
||||||
// Draw the highlight for the current character
|
|
||||||
double highlightWidth = highlightTotalWidth * charProgress;
|
|
||||||
|
|
||||||
double fadingWidth = (double)highlightRegion.LayoutBounds.Height / 2;
|
|
||||||
|
|
||||||
// Rects
|
|
||||||
var highlightRect = new Rect(
|
|
||||||
highlightRegion.LayoutBounds.X,
|
|
||||||
highlightRegion.LayoutBounds.Y + Position.Y,
|
|
||||||
highlightWidth,
|
|
||||||
highlightRegion.LayoutBounds.Height
|
|
||||||
);
|
|
||||||
|
|
||||||
var fadeInRect = new Rect(
|
|
||||||
highlightRect.Right - fadingWidth,
|
|
||||||
highlightRegion.LayoutBounds.Y + Position.Y,
|
|
||||||
fadingWidth,
|
|
||||||
highlightRegion.LayoutBounds.Height
|
|
||||||
);
|
|
||||||
var fadeOutRect = new Rect(
|
|
||||||
highlightRect.Right,
|
|
||||||
highlightRegion.LayoutBounds.Y + Position.Y,
|
|
||||||
fadingWidth,
|
|
||||||
highlightRegion.LayoutBounds.Height
|
|
||||||
);
|
|
||||||
|
|
||||||
// Brushes
|
|
||||||
using var fadeInBrush = CanvasHelper.CreateHorizontalFillBrush(
|
|
||||||
control,
|
|
||||||
[(0f, 0f), (1f, 1f)],
|
|
||||||
(double)highlightRect.Right - fadingWidth,
|
|
||||||
fadingWidth
|
|
||||||
);
|
|
||||||
using var fadeOutBrush = CanvasHelper.CreateHorizontalFillBrush(
|
|
||||||
control,
|
|
||||||
[(0f, 1f), (1f, 0f)],
|
|
||||||
(double)highlightRect.Right,
|
|
||||||
fadingWidth
|
|
||||||
);
|
|
||||||
|
|
||||||
ds.FillRectangle(fadeInRect, fadeInBrush);
|
|
||||||
ds.FillRectangle(fadeOutRect, fadeOutBrush);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 仅当前播放行需要调用此方法(每次 Update 都调用一次)
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="control"></param>
|
|
||||||
/// <param name="playingLineIndex"></param>
|
|
||||||
/// <param name="charStartIndex"></param>
|
|
||||||
/// <param name="charLength"></param>
|
|
||||||
/// <param name="charProgress"></param>
|
|
||||||
public void RecreateLineStartToCurrentCharMask(ICanvasAnimatedControl control, int charStartIndex, int charLength, double charProgress)
|
|
||||||
{
|
|
||||||
LineStartToCurrentCharMask?.Dispose();
|
|
||||||
LineStartToCurrentCharMask = null;
|
|
||||||
LineStartToCurrentCharMask = new CanvasCommandList(control);
|
|
||||||
|
|
||||||
if (CanvasTextLayout == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
using var ds = LineStartToCurrentCharMask.CreateDrawingSession();
|
|
||||||
|
|
||||||
var regions = CanvasTextLayout.GetCharacterRegions(0, charStartIndex);
|
|
||||||
var highlightRegion = CanvasTextLayout
|
|
||||||
.GetCharacterRegions(charStartIndex, charLength)
|
|
||||||
.FirstOrDefault();
|
|
||||||
if (regions.Length > 0)
|
|
||||||
{
|
|
||||||
// Draw the mask for the current line
|
|
||||||
for (int j = 0; j < regions.Length; j++)
|
|
||||||
{
|
|
||||||
var region = regions[j];
|
|
||||||
var rect = new Rect(
|
|
||||||
region.LayoutBounds.X,
|
|
||||||
region.LayoutBounds.Y + Position.Y,
|
|
||||||
region.LayoutBounds.Width,
|
|
||||||
region.LayoutBounds.Height
|
|
||||||
);
|
|
||||||
ds.FillRectangle(rect, Color.FromArgb(255, 128, 128, 128));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
double highlightTotalWidth = (double)highlightRegion.LayoutBounds.Width;
|
|
||||||
// Draw the highlight for the current character
|
|
||||||
double highlightWidth = highlightTotalWidth * charProgress;
|
|
||||||
|
|
||||||
double fadingWidth = (double)highlightRegion.LayoutBounds.Height / 2;
|
|
||||||
|
|
||||||
// Rects
|
|
||||||
var highlightRect = new Rect(
|
|
||||||
highlightRegion.LayoutBounds.X,
|
|
||||||
highlightRegion.LayoutBounds.Y + Position.Y,
|
|
||||||
highlightWidth,
|
|
||||||
highlightRegion.LayoutBounds.Height
|
|
||||||
);
|
|
||||||
|
|
||||||
var fadeInRect = new Rect(
|
|
||||||
highlightRect.Right - fadingWidth,
|
|
||||||
highlightRegion.LayoutBounds.Y + Position.Y,
|
|
||||||
fadingWidth,
|
|
||||||
highlightRegion.LayoutBounds.Height
|
|
||||||
);
|
|
||||||
var fadeOutRect = new Rect(
|
|
||||||
highlightRect.Right,
|
|
||||||
highlightRegion.LayoutBounds.Y + Position.Y,
|
|
||||||
fadingWidth,
|
|
||||||
highlightRegion.LayoutBounds.Height
|
|
||||||
);
|
|
||||||
|
|
||||||
// Brushes
|
|
||||||
using var fadeOutBrush = CanvasHelper.CreateHorizontalFillBrush(
|
|
||||||
control,
|
|
||||||
[(0f, 1f), (1f, 0f)],
|
|
||||||
(double)highlightRect.Right,
|
|
||||||
fadingWidth
|
|
||||||
);
|
|
||||||
|
|
||||||
ds.FillRectangle(highlightRect, Color.FromArgb(255, 128, 128, 128));
|
|
||||||
ds.FillRectangle(fadeOutRect, fadeOutBrush);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 重建当前行遮罩
|
|
||||||
/// 仅需在布局重构 (Relayout) 时调用
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="control"></param>
|
|
||||||
public void RecreateCurrentLineMask(ICanvasAnimatedControl control)
|
|
||||||
{
|
|
||||||
CurrentLineMask?.Dispose();
|
|
||||||
CurrentLineMask = null;
|
|
||||||
|
|
||||||
if (CanvasTextLayout == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
CurrentLineMask = new CanvasCommandList(control);
|
|
||||||
using var ds = CurrentLineMask.CreateDrawingSession();
|
|
||||||
|
|
||||||
var regions = CanvasTextLayout.GetCharacterRegions(0, OriginalText.Length);
|
|
||||||
if (regions.Length > 0)
|
|
||||||
{
|
|
||||||
for (int j = 0; j < regions.Length; j++)
|
|
||||||
{
|
|
||||||
var region = regions[j];
|
|
||||||
var rect = new Rect(
|
|
||||||
region.LayoutBounds.X,
|
|
||||||
region.LayoutBounds.Y + Position.Y,
|
|
||||||
region.LayoutBounds.Width,
|
|
||||||
region.LayoutBounds.Height
|
|
||||||
);
|
|
||||||
ds.FillRectangle(rect, Colors.White);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RecreatePlaceholder(ICanvasAnimatedControl control)
|
|
||||||
{
|
|
||||||
PlaceholderEffect?.Dispose();
|
|
||||||
PlaceholderEffect = null;
|
|
||||||
PlaceholderEffect = new CanvasCommandList(control);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
using BetterLyrics.WinUI3.Enums;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace BetterLyrics.WinUI3.Models
|
||||||
|
{
|
||||||
|
public class LyricsSearchResult
|
||||||
|
{
|
||||||
|
public bool IsFound => !string.IsNullOrEmpty(Raw);
|
||||||
|
public LyricsSearchProvider? Provider { get; set; }
|
||||||
|
|
||||||
|
public string? Raw { get; set; }
|
||||||
|
|
||||||
|
public string? Title { get; set; }
|
||||||
|
public string? Artist { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,286 @@
|
|||||||
|
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,
|
||||||
|
IsShownInSwitchers = false,
|
||||||
|
EnvironmentSampleMode = WindowPixelSampleMode.WindowEdge,
|
||||||
|
LyricsStyleSettings = new()
|
||||||
|
{
|
||||||
|
LyricsFontSize = 20,
|
||||||
|
LyricsAlignmentType = TextAlignmentType.Center,
|
||||||
|
},
|
||||||
|
LyricsBackgroundSettings = new LyricsBackgroundSettings
|
||||||
|
{
|
||||||
|
IsFluidOverlayEnabled = false,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LyricsWindowStatus DockedMode()
|
||||||
|
{
|
||||||
|
return new LyricsWindowStatus
|
||||||
|
{
|
||||||
|
Name = App.ResourceLoader!.GetString("DockedMode"),
|
||||||
|
IsWorkArea = true,
|
||||||
|
IsAlwaysOnTop = true,
|
||||||
|
IsAlwaysOnTopPolling = true,
|
||||||
|
IsBorderless = true,
|
||||||
|
IsAdaptToEnvironment = true,
|
||||||
|
IsShownInSwitchers = false,
|
||||||
|
LyricsDisplayType = LyricsDisplayType.LyricsOnly,
|
||||||
|
EnvironmentSampleMode = WindowPixelSampleMode.BelowWindow,
|
||||||
|
TitleBarArea = TitleBarArea.None,
|
||||||
|
LyricsStyleSettings = new LyricsStyleSettings
|
||||||
|
{
|
||||||
|
LyricsAlignmentType = TextAlignmentType.Center,
|
||||||
|
LyricsFontSize = 18,
|
||||||
|
},
|
||||||
|
LyricsBackgroundSettings = new LyricsBackgroundSettings
|
||||||
|
{
|
||||||
|
IsFluidOverlayEnabled = false,
|
||||||
|
IsPureColorOverlayEnabled = true,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LyricsWindowStatus FullscreenMode(Rect monitorBounds)
|
||||||
|
{
|
||||||
|
return new LyricsWindowStatus
|
||||||
|
{
|
||||||
|
Name = App.ResourceLoader!.GetString("FullscreenMode"),
|
||||||
|
WindowBounds = monitorBounds,
|
||||||
|
IsAlwaysOnTop = true,
|
||||||
|
IsBorderless = true,
|
||||||
|
IsShownInSwitchers = false,
|
||||||
|
TitleBarArea = Enums.TitleBarArea.None,
|
||||||
|
LyricsLayoutOrientation = Enums.LyricsLayoutOrientation.Vertical,
|
||||||
|
LyricsStyleSettings = new LyricsStyleSettings
|
||||||
|
{
|
||||||
|
LyricsFontSize = 72,
|
||||||
|
LyricsAlignmentType = Enums.TextAlignmentType.Center,
|
||||||
|
},
|
||||||
|
AlbumArtLayoutSettings = new AlbumArtLayoutSettings
|
||||||
|
{
|
||||||
|
AutoAlbumArtSize = false,
|
||||||
|
AlbumArtSize = 128,
|
||||||
|
SongInfoFontSize = 36,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
using BetterLyrics.WinUI3.Enums;
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace BetterLyrics.WinUI3.Models
|
||||||
|
{
|
||||||
|
public partial class MappedSongSearchQuery : ObservableRecipient
|
||||||
|
{
|
||||||
|
[ObservableProperty][NotifyPropertyChangedRecipients] public partial string OriginalTitle { get; set; } = string.Empty;
|
||||||
|
[ObservableProperty][NotifyPropertyChangedRecipients] public partial string OriginalArtist { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty][NotifyPropertyChangedRecipients] public partial string MappedTitle { get; set; } = string.Empty;
|
||||||
|
[ObservableProperty][NotifyPropertyChangedRecipients] public partial string MappedArtist { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsMarkedAsPureMusic { get; set; } = false;
|
||||||
|
|
||||||
|
[ObservableProperty][NotifyPropertyChangedRecipients] public partial LyricsSearchProvider? LyricsSearchProvider { get; set; }
|
||||||
|
|
||||||
|
public MappedSongSearchQuery Clone()
|
||||||
|
{
|
||||||
|
return new MappedSongSearchQuery
|
||||||
|
{
|
||||||
|
OriginalTitle = this.OriginalTitle,
|
||||||
|
OriginalArtist = this.OriginalArtist,
|
||||||
|
MappedTitle = this.MappedTitle,
|
||||||
|
MappedArtist = this.MappedArtist,
|
||||||
|
IsMarkedAsPureMusic = this.IsMarkedAsPureMusic,
|
||||||
|
LyricsSearchProvider = this.LyricsSearchProvider
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,26 +12,33 @@ namespace BetterLyrics.WinUI3.Models
|
|||||||
{
|
{
|
||||||
public partial class MediaSourceProviderInfo : ObservableRecipient
|
public partial class MediaSourceProviderInfo : ObservableRecipient
|
||||||
{
|
{
|
||||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsEnabled { get; set; }
|
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsEnabled { get; set; } = true;
|
||||||
|
|
||||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial string Provider { get; set; }
|
[ObservableProperty][NotifyPropertyChangedRecipients] public partial string Provider { get; set; }
|
||||||
|
|
||||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsLastFMTrackEnabled { get; set; }
|
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsLastFMTrackEnabled { get; set; } = false;
|
||||||
|
|
||||||
|
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsTimelineSyncEnabled { get; set; } = true;
|
||||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int TimelineSyncThreshold { get; set; }
|
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int TimelineSyncThreshold { get; set; }
|
||||||
|
|
||||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int PositionOffset { get; set; }
|
[ObservableProperty][NotifyPropertyChangedRecipients] public partial int PositionOffset { get; set; }
|
||||||
|
|
||||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool ResetPositionOffsetOnSongChanged { get; set; }
|
[ObservableProperty][NotifyPropertyChangedRecipients] public partial bool ResetPositionOffsetOnSongChanged { get; set; } = false;
|
||||||
|
|
||||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial FullyObservableCollection<LyricsSearchProviderInfo> LyricsSearchProvidersInfo { get; set; }
|
[ObservableProperty][NotifyPropertyChangedRecipients] public partial FullyObservableCollection<LyricsSearchProviderInfo> LyricsSearchProvidersInfo { get; set; } = [.. Enum.GetValues<LyricsSearchProvider>().Select(p => new LyricsSearchProviderInfo(p, true))];
|
||||||
|
|
||||||
[ObservableProperty][NotifyPropertyChangedRecipients] public partial FullyObservableCollection<AlbumArtSearchProviderInfo> AlbumArtSearchProvidersInfo { get; set; }
|
[ObservableProperty][NotifyPropertyChangedRecipients] public partial FullyObservableCollection<AlbumArtSearchProviderInfo> AlbumArtSearchProvidersInfo { get; set; } = [.. Enum.GetValues<AlbumArtSearchProvider>().Select(p => new AlbumArtSearchProviderInfo(p, true))];
|
||||||
|
|
||||||
public MediaSourceProviderInfo() { }
|
public MediaSourceProviderInfo()
|
||||||
|
|
||||||
public MediaSourceProviderInfo(string provider) : base()
|
|
||||||
{
|
{
|
||||||
|
Provider = string.Empty;
|
||||||
|
TimelineSyncThreshold = 0;
|
||||||
|
PositionOffset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MediaSourceProviderInfo(string provider, bool isEnable = true)
|
||||||
|
{
|
||||||
|
IsEnabled = isEnable;
|
||||||
switch (provider)
|
switch (provider)
|
||||||
{
|
{
|
||||||
case Constants.PlayerID.AppleMusic:
|
case Constants.PlayerID.AppleMusic:
|
||||||
@@ -40,18 +47,19 @@ namespace BetterLyrics.WinUI3.Models
|
|||||||
PositionOffset = 1000;
|
PositionOffset = 1000;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// 设置 100 以防不必要的重复同步
|
// 设置 300 以防不必要的重复同步
|
||||||
TimelineSyncThreshold = 100;
|
TimelineSyncThreshold = 300;
|
||||||
PositionOffset = 0;
|
PositionOffset = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Provider = provider;
|
Provider = provider;
|
||||||
IsEnabled = true;
|
|
||||||
IsLastFMTrackEnabled = false;
|
AlbumArtSearchProvidersInfo.ItemPropertyChanged += AlbumArtSearchProvidersInfo_ItemPropertyChanged;
|
||||||
ResetPositionOffsetOnSongChanged = false;
|
AlbumArtSearchProvidersInfo.CollectionChanged += AlbumArtSearchProvidersInfo_CollectionChanged;
|
||||||
LyricsSearchProvidersInfo = [.. Enum.GetValues<LyricsSearchProvider>().Select(p => new LyricsSearchProviderInfo(p, true))];
|
|
||||||
AlbumArtSearchProvidersInfo = [.. Enum.GetValues<AlbumArtSearchProvider>().Select(p => new AlbumArtSearchProviderInfo(p, true))];
|
LyricsSearchProvidersInfo.ItemPropertyChanged += LyricsSearchProvidersInfo_ItemPropertyChanged;
|
||||||
|
LyricsSearchProvidersInfo.CollectionChanged += LyricsSearchProvidersInfo_CollectionChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
partial void OnAlbumArtSearchProvidersInfoChanged(FullyObservableCollection<AlbumArtSearchProviderInfo> oldValue, FullyObservableCollection<AlbumArtSearchProviderInfo> newValue)
|
partial void OnAlbumArtSearchProvidersInfoChanged(FullyObservableCollection<AlbumArtSearchProviderInfo> oldValue, FullyObservableCollection<AlbumArtSearchProviderInfo> newValue)
|
||||||
|
|||||||