mirror of
https://github.com/jayfunc/BetterLyrics.git
synced 2026-01-13 03:34:55 +08:00
add: auto adaptive (immersive) background for desktop lyrics; fix: change get method (cached in memory if not changed) for settings viewmodel; fix: incorrect display position for desktop lyrics
This commit is contained in:
@@ -54,7 +54,7 @@ namespace BetterLyrics.WinUI3
|
||||
|
||||
_logger = Ioc.Default.GetService<ILogger<App>>()!;
|
||||
|
||||
// UnhandledException += App_UnhandledException;
|
||||
UnhandledException += App_UnhandledException;
|
||||
}
|
||||
|
||||
private static void ConfigureServices()
|
||||
@@ -72,24 +72,25 @@ namespace BetterLyrics.WinUI3
|
||||
loggingBuilder.ClearProviders();
|
||||
loggingBuilder.AddSerilog();
|
||||
})
|
||||
// Services
|
||||
// Services (Singleton)
|
||||
.AddSingleton<ISettingsService, SettingsService>()
|
||||
.AddSingleton<IDatabaseService, DatabaseService>()
|
||||
.AddSingleton<IPlaybackService, PlaybackService>()
|
||||
// Renderer
|
||||
.AddSingleton<AlbumArtRenderer>()
|
||||
.AddSingleton<InAppLyricsRenderer>()
|
||||
.AddSingleton<DesktopLyricsRenderer>()
|
||||
// ViewModels
|
||||
// ViewModels (Transient)
|
||||
.AddTransient<BaseSettingsViewModel>()
|
||||
.AddTransient<BaseLyricsViewModel>()
|
||||
// ViewModels (Singleton)
|
||||
.AddSingleton<HostViewModel>()
|
||||
.AddSingleton<AlbumArtViewModel>()
|
||||
.AddSingleton<MainViewModel>()
|
||||
.AddSingleton<BaseSettingsViewModel>()
|
||||
.AddSingleton<GlobalViewModel>()
|
||||
.AddSingleton<SettingsViewModel>()
|
||||
.AddSingleton<InAppLyricsViewModel>()
|
||||
.AddSingleton<DesktopLyricsViewModel>()
|
||||
.AddSingleton<AlbumArtOverlayViewModel>()
|
||||
// Renderer (Singleton)
|
||||
.AddSingleton<AlbumArtRenderer>()
|
||||
.AddSingleton<InAppLyricsRenderer>()
|
||||
.AddSingleton<DesktopLyricsRenderer>()
|
||||
.BuildServiceProvider()
|
||||
);
|
||||
}
|
||||
@@ -111,13 +112,9 @@ namespace BetterLyrics.WinUI3
|
||||
{
|
||||
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
||||
|
||||
var overlayWindow = new OverlayWindow();
|
||||
overlayWindow.Navigate(typeof(DesktopLyricsPage));
|
||||
Current.OverlayWindow = overlayWindow;
|
||||
|
||||
// Activate the window
|
||||
MainWindow = new HostWindow();
|
||||
MainWindow!.Navigate(typeof(MainPage));
|
||||
MainWindow!.Navigate(typeof(InAppLyricsPage));
|
||||
MainWindow.Activate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Remove="Controls\LyricsSettingsControl.xaml" />
|
||||
<None Remove="Views\DesktopLyricsPage.xaml" />
|
||||
<None Remove="Views\OverlayWindow.xaml" />
|
||||
</ItemGroup>
|
||||
@@ -24,6 +25,8 @@
|
||||
<PackageReference Include="CommunityToolkit.Labs.WinUI.OpacityMaskView" Version="0.1.250513-build.2126" />
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.Behaviors" Version="8.2.250402" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.Controls.Primitives" Version="8.2.250402" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.Controls.Segmented" Version="8.2.250402" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.Controls.SettingsControls" Version="8.2.250402" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.Converters" Version="8.2.250402" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.Extensions" Version="8.2.250402" />
|
||||
@@ -51,7 +54,9 @@
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Controls\" />
|
||||
<Page Update="Controls\LyricsSettingsControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Views\DesktopLyricsPage.xaml">
|
||||
@@ -86,7 +91,7 @@
|
||||
<InheritWinAppVersionFrom>AssemblyVersion</InheritWinAppVersionFrom>
|
||||
<PackageVersionSettings>AssemblyVersion.None.None</PackageVersionSettings>
|
||||
<Version>2025.6.0</Version>
|
||||
<AssemblyVersion>2025.6.13.2318</AssemblyVersion>
|
||||
<FileVersion>2025.6.13.2318</FileVersion>
|
||||
<AssemblyVersion>2025.6.14.1656</AssemblyVersion>
|
||||
<FileVersion>2025.6.14.1656</FileVersion>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<UserControl
|
||||
x:Class="BetterLyrics.WinUI3.Controls.LyricsSettingsControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:CommunityToolkit.WinUI.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
|
||||
xmlns:local="using:BetterLyrics.WinUI3.Controls"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid>
|
||||
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
|
||||
<controls:SettingsCard x:Uid="SettingsPageLyricsAlignment" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<ComboBox SelectedIndex="{x:Bind ViewModel.LyricsAlignmentType, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsLeft" />
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsCenter" />
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsRight" />
|
||||
</ComboBox>
|
||||
</controls:SettingsCard>
|
||||
|
||||
<controls:SettingsExpander x:Uid="SettingsPageLyricsFontColor" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<interactivity:Interaction.Behaviors>
|
||||
<interactivity:DataTriggerBehavior
|
||||
Binding="{x:Bind ViewModel.LyricsFontColorType, Mode=OneWay, Converter={StaticResource EnumToIntConverter}}"
|
||||
ComparisonCondition="Equal"
|
||||
Value="0">
|
||||
<interactivity:ChangePropertyAction PropertyName="IsExpanded" Value="False" />
|
||||
</interactivity:DataTriggerBehavior>
|
||||
<interactivity:DataTriggerBehavior
|
||||
Binding="{x:Bind ViewModel.LyricsFontColorType, Mode=OneWay, Converter={StaticResource EnumToIntConverter}}"
|
||||
ComparisonCondition="Equal"
|
||||
Value="1">
|
||||
<interactivity:ChangePropertyAction PropertyName="IsExpanded" Value="True" />
|
||||
</interactivity:DataTriggerBehavior>
|
||||
</interactivity:Interaction.Behaviors>
|
||||
<ComboBox SelectedIndex="{x:Bind ViewModel.LyricsFontColorType, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsFontColorDefault" />
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsFontColorDominant" />
|
||||
</ComboBox>
|
||||
<controls:SettingsExpander.Items>
|
||||
<controls:SettingsCard HorizontalContentAlignment="Left" ContentAlignment="Vertical">
|
||||
<interactivity:Interaction.Behaviors>
|
||||
<interactivity:DataTriggerBehavior
|
||||
Binding="{x:Bind ViewModel.LyricsFontColorType, Mode=OneWay, Converter={StaticResource EnumToIntConverter}}"
|
||||
ComparisonCondition="Equal"
|
||||
Value="0">
|
||||
<interactivity:ChangePropertyAction PropertyName="Visibility" Value="Collapsed" />
|
||||
</interactivity:DataTriggerBehavior>
|
||||
<interactivity:DataTriggerBehavior
|
||||
Binding="{x:Bind ViewModel.LyricsFontColorType, Mode=OneWay, Converter={StaticResource EnumToIntConverter}}"
|
||||
ComparisonCondition="Equal"
|
||||
Value="1">
|
||||
<interactivity:ChangePropertyAction PropertyName="Visibility" Value="Visible" />
|
||||
</interactivity:DataTriggerBehavior>
|
||||
</interactivity:Interaction.Behaviors>
|
||||
<GridView ItemsSource="{x:Bind ViewModel.CoverImageDominantColors, Mode=OneWay}" SelectedIndex="{x:Bind ViewModel.LyricsFontSelectedAccentColorIndex, Mode=TwoWay}">
|
||||
<GridView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<GridViewItem>
|
||||
<StackPanel>
|
||||
<Border
|
||||
Width="64"
|
||||
Height="64"
|
||||
CornerRadius="4">
|
||||
<Border.Background>
|
||||
<SolidColorBrush Color="{Binding}" />
|
||||
</Border.Background>
|
||||
<Border.BackgroundTransition>
|
||||
<BrushTransition />
|
||||
</Border.BackgroundTransition>
|
||||
</Border>
|
||||
<TextBlock
|
||||
Margin="4,0,4,4"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding Converter={StaticResource ColorToDisplayNameConverter}}"
|
||||
TextWrapping="WrapWholeWords" />
|
||||
</StackPanel>
|
||||
</GridViewItem>
|
||||
</DataTemplate>
|
||||
</GridView.ItemTemplate>
|
||||
</GridView>
|
||||
</controls:SettingsCard>
|
||||
</controls:SettingsExpander.Items>
|
||||
</controls:SettingsExpander>
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageLyricsFontSize" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock x:Uid="SettingsPageSliderPrefix" VerticalAlignment="Center" />
|
||||
<TextBlock
|
||||
Margin="0,0,14,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding ElementName=LyricsFontSizeSlider, Path=Value, Mode=OneWay}" />
|
||||
<Slider
|
||||
x:Name="LyricsFontSizeSlider"
|
||||
Maximum="96"
|
||||
Minimum="12"
|
||||
SnapsTo="Ticks"
|
||||
StepFrequency="2"
|
||||
TickFrequency="2"
|
||||
TickPlacement="Outside"
|
||||
Value="{x:Bind ViewModel.LyricsFontSize, Mode=TwoWay}" />
|
||||
</StackPanel>
|
||||
</controls:SettingsCard>
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageLyricsLineSpacingFactor" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock x:Uid="SettingsPageSliderPrefix" VerticalAlignment="Center" />
|
||||
<TextBlock VerticalAlignment="Center" Text="{Binding ElementName=LyricsLineSpacingFactorSlider, Path=Value, Mode=OneWay}" />
|
||||
<TextBlock
|
||||
x:Uid="SettingsPageLyricsLineSpacingFactorUnit"
|
||||
Margin="0,0,14,0"
|
||||
VerticalAlignment="Center" />
|
||||
<Slider
|
||||
x:Name="LyricsLineSpacingFactorSlider"
|
||||
Maximum="2"
|
||||
Minimum="0"
|
||||
SnapsTo="Ticks"
|
||||
StepFrequency="0.1"
|
||||
TickFrequency="0.1"
|
||||
TickPlacement="Outside"
|
||||
Value="{x:Bind ViewModel.LyricsLineSpacingFactor, Mode=TwoWay}" />
|
||||
</StackPanel>
|
||||
</controls:SettingsCard>
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageLyricsVerticalEdgeOpacity" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock x:Uid="SettingsPageSliderPrefix" VerticalAlignment="Center" />
|
||||
<TextBlock VerticalAlignment="Center" Text="{Binding ElementName=LyricsVerticalEdgeOpacitySlider, Path=Value, Mode=OneWay}" />
|
||||
<TextBlock
|
||||
Margin="0,0,14,0"
|
||||
VerticalAlignment="Center"
|
||||
Text=" %" />
|
||||
<Slider
|
||||
x:Name="LyricsVerticalEdgeOpacitySlider"
|
||||
Maximum="100"
|
||||
Minimum="0"
|
||||
SnapsTo="Ticks"
|
||||
StepFrequency="1"
|
||||
TickFrequency="1"
|
||||
TickPlacement="Outside"
|
||||
Value="{x:Bind ViewModel.LyricsVerticalEdgeOpacity, Mode=TwoWay}" />
|
||||
</StackPanel>
|
||||
</controls:SettingsCard>
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageLyricsBlurAmount" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<controls:SettingsCard.Description>
|
||||
<StackPanel>
|
||||
<TextBlock x:Uid="SettingsPageLyricsBlurHighGPUUsage" Foreground="{ThemeResource SystemFillColorCautionBrush}" />
|
||||
<TextBlock x:Uid="SettingsPageLyricsBlurAmountSideEffect" />
|
||||
</StackPanel>
|
||||
</controls:SettingsCard.Description>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock x:Uid="SettingsPageSliderPrefix" VerticalAlignment="Center" />
|
||||
<TextBlock
|
||||
Margin="0,0,14,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding ElementName=LyricsBlurAmountSlider, Path=Value, Mode=OneWay}" />
|
||||
<Slider
|
||||
x:Name="LyricsBlurAmountSlider"
|
||||
Maximum="10"
|
||||
Minimum="0"
|
||||
SnapsTo="Ticks"
|
||||
StepFrequency="1"
|
||||
TickFrequency="1"
|
||||
TickPlacement="Outside"
|
||||
Value="{x:Bind ViewModel.LyricsBlurAmount, Mode=TwoWay}" />
|
||||
</StackPanel>
|
||||
</controls:SettingsCard>
|
||||
|
||||
<controls:SettingsExpander
|
||||
x:Uid="SettingsPageLyricsGlowEffect"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
IsExpanded="True">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.IsLyricsGlowEffectEnabled, Mode=TwoWay}" />
|
||||
<controls:SettingsExpander.Items>
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageLyricsDynamicGlowEffect" IsEnabled="{x:Bind ViewModel.IsLyricsGlowEffectEnabled, Mode=OneWay}">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.IsLyricsDynamicGlowEffectEnabled, Mode=TwoWay}" />
|
||||
</controls:SettingsCard>
|
||||
|
||||
</controls:SettingsExpander.Items>
|
||||
</controls:SettingsExpander>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
using BetterLyrics.WinUI3.ViewModels.Lyrics;
|
||||
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 Windows.Foundation;
|
||||
using Windows.Foundation.Collections;
|
||||
|
||||
// To learn more about WinUI, the WinUI project structure,
|
||||
// and more about our project templates, see: http://aka.ms/winui-project-info.
|
||||
|
||||
namespace BetterLyrics.WinUI3.Controls
|
||||
{
|
||||
public sealed partial class LyricsSettingsControl : UserControl
|
||||
{
|
||||
public LyricsSettingsControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public ILyricsViewModel ViewModel
|
||||
{
|
||||
get => (ILyricsViewModel)GetValue(ViewModelProperty);
|
||||
set => SetValue(ViewModelProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(
|
||||
nameof(ViewModel),
|
||||
typeof(ILyricsViewModel),
|
||||
typeof(LyricsSettingsControl),
|
||||
new PropertyMetadata(null)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.UI;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Helper
|
||||
{
|
||||
public static class ColorHelper
|
||||
{
|
||||
public static Windows.UI.Color ToWindowsUIColor(this System.Drawing.Color color)
|
||||
{
|
||||
return Windows.UI.Color.FromArgb(color.A, color.R, color.G, color.B);
|
||||
}
|
||||
|
||||
public static Color GetInterpolatedColor(
|
||||
float progress,
|
||||
Color startColor,
|
||||
Color targetColor
|
||||
)
|
||||
{
|
||||
byte Lerp(byte a, byte b) => (byte)(a + (progress * (b - a)));
|
||||
return Color.FromArgb(
|
||||
Lerp(startColor.A, targetColor.A),
|
||||
Lerp(startColor.R, targetColor.R),
|
||||
Lerp(startColor.G, targetColor.G),
|
||||
Lerp(startColor.B, targetColor.B)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.UI.Xaml;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Helper
|
||||
{
|
||||
public class ForegroundWindowWatcherHelper
|
||||
{
|
||||
private readonly WinEventDelegate _winEventDelegate;
|
||||
private readonly List<IntPtr> _hooks = new();
|
||||
private IntPtr _currentForeground = IntPtr.Zero;
|
||||
private readonly IntPtr _selfHwnd;
|
||||
private readonly DispatcherTimer _pollingTimer;
|
||||
private DateTime _lastEventTime = DateTime.MinValue;
|
||||
private const int ThrottleIntervalMs = 100;
|
||||
|
||||
public delegate void WindowChangedHandler(IntPtr hwnd);
|
||||
private readonly WindowChangedHandler _onWindowChanged;
|
||||
|
||||
private const uint EVENT_SYSTEM_FOREGROUND = 0x0003;
|
||||
private const uint EVENT_SYSTEM_MINIMIZEEND = 0x0017;
|
||||
private const uint EVENT_OBJECT_LOCATIONCHANGE = 0x800B;
|
||||
private const uint WINEVENT_OUTOFCONTEXT = 0x0000;
|
||||
|
||||
public ForegroundWindowWatcherHelper(IntPtr selfHwnd, WindowChangedHandler onWindowChanged)
|
||||
{
|
||||
_selfHwnd = selfHwnd;
|
||||
_onWindowChanged = onWindowChanged;
|
||||
_winEventDelegate = new WinEventDelegate(WinEventProc);
|
||||
|
||||
_pollingTimer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(200) };
|
||||
_pollingTimer.Tick += (_, _) =>
|
||||
{
|
||||
if (_currentForeground != IntPtr.Zero && _currentForeground != _selfHwnd)
|
||||
_onWindowChanged?.Invoke(_currentForeground);
|
||||
};
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
// Hook: foreground changes and minimize end
|
||||
_hooks.Add(
|
||||
SetWinEventHook(
|
||||
EVENT_SYSTEM_FOREGROUND,
|
||||
EVENT_SYSTEM_MINIMIZEEND,
|
||||
IntPtr.Zero,
|
||||
_winEventDelegate,
|
||||
0,
|
||||
0,
|
||||
WINEVENT_OUTOFCONTEXT
|
||||
)
|
||||
);
|
||||
|
||||
// Hook: window move/resize (location change)
|
||||
_hooks.Add(
|
||||
SetWinEventHook(
|
||||
EVENT_OBJECT_LOCATIONCHANGE,
|
||||
EVENT_OBJECT_LOCATIONCHANGE,
|
||||
IntPtr.Zero,
|
||||
_winEventDelegate,
|
||||
0,
|
||||
0,
|
||||
WINEVENT_OUTOFCONTEXT
|
||||
)
|
||||
);
|
||||
|
||||
_pollingTimer.Start();
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
foreach (var hook in _hooks)
|
||||
UnhookWinEvent(hook);
|
||||
|
||||
_hooks.Clear();
|
||||
_pollingTimer.Stop();
|
||||
}
|
||||
|
||||
private void WinEventProc(
|
||||
IntPtr hWinEventHook,
|
||||
uint eventType,
|
||||
IntPtr hwnd,
|
||||
int idObject,
|
||||
int idChild,
|
||||
uint dwEventThread,
|
||||
uint dwmsEventTime
|
||||
)
|
||||
{
|
||||
if (hwnd == IntPtr.Zero || hwnd == _selfHwnd)
|
||||
return;
|
||||
|
||||
var now = DateTime.Now;
|
||||
if ((now - _lastEventTime).TotalMilliseconds < ThrottleIntervalMs)
|
||||
return;
|
||||
|
||||
_lastEventTime = now;
|
||||
|
||||
if (eventType == EVENT_SYSTEM_FOREGROUND)
|
||||
{
|
||||
_currentForeground = hwnd;
|
||||
_onWindowChanged?.Invoke(hwnd);
|
||||
}
|
||||
else if (
|
||||
(eventType == EVENT_OBJECT_LOCATIONCHANGE || eventType == EVENT_SYSTEM_MINIMIZEEND)
|
||||
&& hwnd == _currentForeground
|
||||
)
|
||||
{
|
||||
_onWindowChanged?.Invoke(hwnd);
|
||||
}
|
||||
}
|
||||
|
||||
#region WinAPI
|
||||
private delegate void WinEventDelegate(
|
||||
IntPtr hWinEventHook,
|
||||
uint eventType,
|
||||
IntPtr hwnd,
|
||||
int idObject,
|
||||
int idChild,
|
||||
uint dwEventThread,
|
||||
uint dwmsEventTime
|
||||
);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern IntPtr SetWinEventHook(
|
||||
uint eventMin,
|
||||
uint eventMax,
|
||||
IntPtr hmodWinEventProc,
|
||||
WinEventDelegate lpfnWinEventProc,
|
||||
uint idProcess,
|
||||
uint idThread,
|
||||
uint dwFlags
|
||||
);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern bool UnhookWinEvent(IntPtr hWinEventHook);
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -7,48 +7,30 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
{
|
||||
public static class WindowColorHelper
|
||||
{
|
||||
public static Color GetDominantColorBelow(
|
||||
IntPtr myHwnd,
|
||||
int sampleWidth = 64,
|
||||
int sampleHeight = 64
|
||||
)
|
||||
public static Color GetDominantColorBelow(IntPtr myHwnd)
|
||||
{
|
||||
// 获取屏幕坐标中,在窗口下方的某个点
|
||||
if (!GetWindowRect(myHwnd, out RECT myRect))
|
||||
return Color.Transparent;
|
||||
|
||||
POINT pt = new()
|
||||
{
|
||||
x = (myRect.Left + myRect.Right) / 2,
|
||||
y = myRect.Bottom + 1, // 紧贴窗口底部
|
||||
};
|
||||
int screenWidth = GetSystemMetrics(SystemMetric.SM_CXSCREEN);
|
||||
int sampleHeight = 1;
|
||||
int sampleY = myRect.Bottom + 1;
|
||||
|
||||
IntPtr hwndBelow = WindowFromPoint(pt);
|
||||
|
||||
if (hwndBelow == myHwnd || hwndBelow == IntPtr.Zero)
|
||||
return Color.Transparent;
|
||||
|
||||
return GetAverageColorFromWindow(hwndBelow, sampleWidth, sampleHeight);
|
||||
return GetAverageColorFromScreenRegion(0, sampleY, screenWidth, sampleHeight);
|
||||
}
|
||||
|
||||
private static Color GetAverageColorFromWindow(IntPtr hwnd, int width, int height)
|
||||
private static Color GetAverageColorFromScreenRegion(int x, int y, int width, int height)
|
||||
{
|
||||
if (!GetWindowRect(hwnd, out RECT rect))
|
||||
return Color.Transparent;
|
||||
|
||||
int w = Math.Min(width, rect.Right - rect.Left);
|
||||
int h = Math.Min(height, rect.Bottom - rect.Top);
|
||||
|
||||
using Bitmap bmp = new(w, h, PixelFormat.Format32bppArgb);
|
||||
using Bitmap bmp = new(width, height, PixelFormat.Format32bppArgb);
|
||||
using Graphics gDest = Graphics.FromImage(bmp);
|
||||
|
||||
IntPtr hdcDest = gDest.GetHdc();
|
||||
IntPtr hdcSrc = GetWindowDC(hwnd);
|
||||
IntPtr hdcSrc = GetDC(IntPtr.Zero); // Entire screen
|
||||
|
||||
BitBlt(hdcDest, 0, 0, w, h, hdcSrc, rect.Left, rect.Top, SRCCOPY);
|
||||
BitBlt(hdcDest, 0, 0, width, height, hdcSrc, x, y, SRCCOPY);
|
||||
|
||||
gDest.ReleaseHdc(hdcDest);
|
||||
ReleaseDC(hwnd, hdcSrc);
|
||||
ReleaseDC(IntPtr.Zero, hdcSrc);
|
||||
|
||||
return ComputeAverageColor(bmp);
|
||||
}
|
||||
@@ -80,14 +62,11 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
#region Win32 Imports & Structs
|
||||
private const int SRCCOPY = 0x00CC0020;
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern IntPtr WindowFromPoint(POINT Point);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern IntPtr GetWindowDC(IntPtr hWnd);
|
||||
private static extern IntPtr GetDC(IntPtr hWnd);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
|
||||
@@ -105,11 +84,13 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
int dwRop
|
||||
);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct POINT
|
||||
[DllImport("user32.dll")]
|
||||
private static extern int GetSystemMetrics(SystemMetric smIndex);
|
||||
|
||||
private enum SystemMetric
|
||||
{
|
||||
public int x;
|
||||
public int y;
|
||||
SM_CXSCREEN = 0,
|
||||
SM_CYSCREEN = 1,
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
|
||||
@@ -1,17 +1,29 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using BetterLyrics.WinUI3.Views;
|
||||
using Microsoft.UI.Composition.SystemBackdrops;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
using Windows.Storage;
|
||||
using WinRT.Interop;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Helper
|
||||
{
|
||||
public class WindowHelper
|
||||
{
|
||||
public static Window CreateWindow()
|
||||
public static HostWindow CreateHostWindow()
|
||||
{
|
||||
Window newWindow = new Window { SystemBackdrop = new MicaBackdrop() };
|
||||
HostWindow newWindow = new() { SystemBackdrop = new MicaBackdrop() };
|
||||
TrackWindow(newWindow);
|
||||
return newWindow;
|
||||
}
|
||||
|
||||
public static OverlayWindow CreateOverlayWindow()
|
||||
{
|
||||
OverlayWindow newWindow = new();
|
||||
TransparentAppBarHelper.Enable(newWindow, 48);
|
||||
|
||||
TrackWindow(newWindow);
|
||||
return newWindow;
|
||||
}
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
using CommunityToolkit.Mvvm.Messaging.Messages;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Messages
|
||||
{
|
||||
public class InAppLyricsRelayoutRequestedMessage() : ValueChangedMessage<object?>(null) { }
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
using CommunityToolkit.Mvvm.Messaging.Messages;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Messages
|
||||
{
|
||||
public class DesktopLyricsRelayoutRequestedMessage() : ValueChangedMessage<object?>(null) { }
|
||||
}
|
||||
14
BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/LyricsType.cs
Normal file
14
BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/LyricsType.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Models
|
||||
{
|
||||
public enum LyricsType
|
||||
{
|
||||
InAppLyrics,
|
||||
DesktopLyrics,
|
||||
}
|
||||
}
|
||||
@@ -158,7 +158,7 @@ namespace BetterLyrics.WinUI3.Rendering
|
||||
}
|
||||
}
|
||||
|
||||
if (_viewModel.IsDynamicCoverOverlay)
|
||||
if (_viewModel.IsDynamicCoverOverlayEnabled)
|
||||
{
|
||||
_rotateAngle += _coverRotateSpeed;
|
||||
_rotateAngle %= MathF.PI * 2;
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Threading.Tasks;
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using BetterLyrics.WinUI3.Messages;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
@@ -15,11 +13,8 @@ using Microsoft.Graphics.Canvas.Effects;
|
||||
using Microsoft.Graphics.Canvas.Text;
|
||||
using Microsoft.Graphics.Canvas.UI.Xaml;
|
||||
using Microsoft.UI;
|
||||
using Microsoft.UI.Dispatching;
|
||||
using Microsoft.UI.Text;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
using Microsoft.UI.Xaml.Shapes;
|
||||
using Windows.Foundation;
|
||||
using Windows.UI;
|
||||
|
||||
@@ -57,11 +52,43 @@ namespace BetterLyrics.WinUI3.Rendering
|
||||
|
||||
private readonly double _rightMargin = 36;
|
||||
|
||||
public double LimitedLineWidth { get; set; } = 0;
|
||||
private bool _isLimitedLineWidthUpdated = false;
|
||||
private double _limitedLineWidth = 0;
|
||||
public double LimitedLineWidth
|
||||
{
|
||||
get => _limitedLineWidth;
|
||||
set
|
||||
{
|
||||
if (_limitedLineWidth != value)
|
||||
{
|
||||
_limitedLineWidth = value;
|
||||
_isLimitedLineWidthUpdated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public TimeSpan CurrentTime { get; set; } = TimeSpan.Zero;
|
||||
|
||||
public List<LyricsLine> LyricsLines { get; set; } = [];
|
||||
private bool _isLyricsUpdated = true;
|
||||
|
||||
private List<LyricsLine> _lyricsLines = [];
|
||||
public List<LyricsLine> LyricsLines
|
||||
{
|
||||
get => _lyricsLines;
|
||||
set
|
||||
{
|
||||
if (_lyricsLines != value)
|
||||
{
|
||||
_lyricsLines = value;
|
||||
_isLyricsUpdated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool _isRelayoutNeeded = true;
|
||||
|
||||
private float _fontSize = 0;
|
||||
private float _lineSpacingFactor = 0;
|
||||
|
||||
private readonly ILyricsViewModel _viewModel;
|
||||
|
||||
@@ -394,6 +421,13 @@ namespace BetterLyrics.WinUI3.Rendering
|
||||
|
||||
// Draw the final composed layer
|
||||
ds.DrawImage(maskedCombinedBlurredLyrics);
|
||||
|
||||
ds.DrawText(
|
||||
$"{_fontSize}, {_lineSpacingFactor}, {_isRelayoutNeeded}",
|
||||
10,
|
||||
10,
|
||||
Colors.Red
|
||||
);
|
||||
}
|
||||
|
||||
private void DrawGradientOpacityMask(
|
||||
@@ -417,19 +451,12 @@ namespace BetterLyrics.WinUI3.Rendering
|
||||
ds.FillRectangle(new Rect(0, 0, control.Size.Width, control.Size.Height), maskBrush);
|
||||
}
|
||||
|
||||
public async Task ForceToScrollToCurrentPlayingLineAsync()
|
||||
{
|
||||
_forceToScroll = true;
|
||||
await Task.Delay(1);
|
||||
_forceToScroll = false;
|
||||
}
|
||||
|
||||
public async Task ReLayoutAsync(ICanvasAnimatedControl control)
|
||||
private void ReLayout(ICanvasAnimatedControl control)
|
||||
{
|
||||
if (control == null)
|
||||
return;
|
||||
|
||||
_textFormat.FontSize = _viewModel.LyricsFontSize;
|
||||
_textFormat.FontSize = _fontSize;
|
||||
|
||||
float y = 0;
|
||||
|
||||
@@ -451,14 +478,33 @@ namespace BetterLyrics.WinUI3.Rendering
|
||||
y +=
|
||||
(float)textLayout.LayoutBounds.Height
|
||||
/ textLayout.LineCount
|
||||
* (textLayout.LineCount + _viewModel.LyricsLineSpacingFactor);
|
||||
* (textLayout.LineCount + _lineSpacingFactor);
|
||||
}
|
||||
|
||||
await ForceToScrollToCurrentPlayingLineAsync();
|
||||
}
|
||||
|
||||
public void Calculate(ICanvasAnimatedControl control)
|
||||
{
|
||||
if (
|
||||
_isLyricsUpdated
|
||||
|| _isLimitedLineWidthUpdated
|
||||
|| _fontSize != _viewModel.LyricsFontSize
|
||||
|| _lineSpacingFactor != _viewModel.LyricsLineSpacingFactor
|
||||
)
|
||||
{
|
||||
_fontSize = _viewModel.LyricsFontSize;
|
||||
_lineSpacingFactor = _viewModel.LyricsLineSpacingFactor;
|
||||
_isRelayoutNeeded = true;
|
||||
_forceToScroll = true;
|
||||
}
|
||||
|
||||
if (_isRelayoutNeeded)
|
||||
{
|
||||
ReLayout(control);
|
||||
_isRelayoutNeeded = false;
|
||||
_isLyricsUpdated = false;
|
||||
_isLimitedLineWidthUpdated = false;
|
||||
}
|
||||
|
||||
int currentPlayingLineIndex = GetCurrentPlayingLineIndex();
|
||||
CalculateScaleAndOpacity(currentPlayingLineIndex);
|
||||
CalculatePosition(control, currentPlayingLineIndex);
|
||||
@@ -620,6 +666,7 @@ namespace BetterLyrics.WinUI3.Rendering
|
||||
if (_forceToScroll && Math.Abs(targetYScrollOffset) >= 1)
|
||||
{
|
||||
_totalYScroll = _lastTotalYScroll + targetYScrollOffset;
|
||||
_forceToScroll = false;
|
||||
}
|
||||
_lastTotalYScroll = _totalYScroll;
|
||||
}
|
||||
|
||||
@@ -3,15 +3,73 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.ViewModels;
|
||||
using BetterLyrics.WinUI3.ViewModels.Lyrics;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using CommunityToolkit.WinUI;
|
||||
using Microsoft.Graphics.Canvas;
|
||||
using Microsoft.Graphics.Canvas.UI.Xaml;
|
||||
using Windows.UI;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Rendering
|
||||
{
|
||||
public class DesktopLyricsRenderer : BaseLyricsRenderer
|
||||
{
|
||||
public DesktopLyricsRenderer(DesktopLyricsViewModel viewModel)
|
||||
: base(viewModel) { }
|
||||
private readonly GlobalViewModel _globalViewModel;
|
||||
|
||||
private Color _startColor;
|
||||
private Color _targetColor;
|
||||
private float _progress; // From 0 to 1
|
||||
private const float TransitionSeconds = 0.3f;
|
||||
private bool _isTransitioning;
|
||||
|
||||
public DesktopLyricsRenderer(
|
||||
DesktopLyricsViewModel viewModel,
|
||||
GlobalViewModel globalViewModel
|
||||
)
|
||||
: base(viewModel)
|
||||
{
|
||||
_globalViewModel = globalViewModel;
|
||||
_startColor = _targetColor =
|
||||
_globalViewModel.ActivatedWindowAccentColor.ToWindowsUIColor();
|
||||
_progress = 1f;
|
||||
}
|
||||
|
||||
public void UpdateTransition(float elapsedSeconds)
|
||||
{
|
||||
// Detect if the accent color has changed
|
||||
var currentAccent = _globalViewModel.ActivatedWindowAccentColor.ToWindowsUIColor();
|
||||
if (currentAccent != _targetColor)
|
||||
{
|
||||
_startColor = _isTransitioning
|
||||
? ColorHelper.GetInterpolatedColor(_progress, _startColor, _targetColor)
|
||||
: _targetColor;
|
||||
_targetColor = currentAccent;
|
||||
_progress = 0f;
|
||||
_isTransitioning = true;
|
||||
}
|
||||
|
||||
// Update the transition progress
|
||||
if (_isTransitioning)
|
||||
{
|
||||
_progress += elapsedSeconds / TransitionSeconds;
|
||||
if (_progress >= 1f)
|
||||
{
|
||||
_progress = 1f;
|
||||
_isTransitioning = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawBackground(ICanvasAnimatedControl control, CanvasDrawingSession ds)
|
||||
{
|
||||
var color = _isTransitioning
|
||||
? ColorHelper.GetInterpolatedColor(_progress, _startColor, _targetColor)
|
||||
: _targetColor;
|
||||
|
||||
ds.FillRectangle(control.Size.ToRect(), color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Services.Playback
|
||||
namespace BetterLyrics.WinUI3.Services.Playback
|
||||
{
|
||||
public interface IPlaybackService
|
||||
{
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
// Backdrop
|
||||
public const int BackdropType = 5; // Acrylic Base
|
||||
public const bool IsCoverOverlayEnabled = true;
|
||||
public const bool IsDynamicCoverOverlay = true;
|
||||
public const bool IsDynamicCoverOverlayEnabled = true;
|
||||
public const int CoverOverlayOpacity = 100; // 1.0
|
||||
public const int CoverOverlayBlurAmount = 200;
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace BetterLyrics.WinUI3.Services.Settings
|
||||
// Backdrop
|
||||
public const string BackdropType = "BackdropType";
|
||||
public const string IsCoverOverlayEnabled = "IsCoverOverlayEnabled";
|
||||
public const string IsDynamicCoverOverlay = "IsDynamicCoverOverlay";
|
||||
public const string IsDynamicCoverOverlayEnabled = "IsDynamicCoverOverlayEnabled";
|
||||
public const string CoverOverlayOpacity = "CoverOverlayOpacity";
|
||||
public const string CoverOverlayBlurAmount = "CoverOverlayBlurAmount";
|
||||
|
||||
|
||||
@@ -225,12 +225,9 @@
|
||||
<data name="SettingsPageTitle" xml:space="preserve">
|
||||
<value>Settings</value>
|
||||
</data>
|
||||
<data name="MainPageTitle" xml:space="preserve">
|
||||
<data name="InAppLyricsPageTitle" xml:space="preserve">
|
||||
<value>BetterLyrics</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsStyle.Text" xml:space="preserve">
|
||||
<value>Lyrics style</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsAlignment.Header" xml:space="preserve">
|
||||
<value>Alignment</value>
|
||||
</data>
|
||||
@@ -279,9 +276,6 @@
|
||||
<data name="MainWindowImmersiveMode.ToolTipService.ToolTip" xml:space="preserve">
|
||||
<value>Immersive mode</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsEffect.Text" xml:space="preserve">
|
||||
<value>Lyrics effect</value>
|
||||
</data>
|
||||
<data name="SettingsPageAlbumOverlay.Text" xml:space="preserve">
|
||||
<value>Album background</value>
|
||||
</data>
|
||||
@@ -396,4 +390,13 @@
|
||||
<data name="MainPageLyricsNotFound.Text" xml:space="preserve">
|
||||
<value>Lyrics not found</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyrics.Text" xml:space="preserve">
|
||||
<value>Lyrics style & effect</value>
|
||||
</data>
|
||||
<data name="SettingsPageInAppLyrics.Content" xml:space="preserve">
|
||||
<value>In-app lyrics</value>
|
||||
</data>
|
||||
<data name="SettingsPageDesktopLyrics.Content" xml:space="preserve">
|
||||
<value>Desktop lyrics</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -225,12 +225,9 @@
|
||||
<data name="SettingsPageTitle" xml:space="preserve">
|
||||
<value>设置</value>
|
||||
</data>
|
||||
<data name="MainPageTitle" xml:space="preserve">
|
||||
<data name="InAppLyricsPageTitle" xml:space="preserve">
|
||||
<value>BetterLyrics</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsStyle.Text" xml:space="preserve">
|
||||
<value>歌词样式</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsAlignment.Header" xml:space="preserve">
|
||||
<value>对齐方式</value>
|
||||
</data>
|
||||
@@ -279,9 +276,6 @@
|
||||
<data name="MainWindowImmersiveMode.ToolTipService.ToolTip" xml:space="preserve">
|
||||
<value>沉浸模式</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsEffect.Text" xml:space="preserve">
|
||||
<value>歌词效果</value>
|
||||
</data>
|
||||
<data name="SettingsPageAlbumOverlay.Text" xml:space="preserve">
|
||||
<value>专辑背景</value>
|
||||
</data>
|
||||
@@ -396,4 +390,13 @@
|
||||
<data name="MainPageLyricsNotFound.Text" xml:space="preserve">
|
||||
<value>未找到歌词</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyrics.Text" xml:space="preserve">
|
||||
<value>歌词样式与动效</value>
|
||||
</data>
|
||||
<data name="SettingsPageInAppLyrics.Content" xml:space="preserve">
|
||||
<value>应用内歌词</value>
|
||||
</data>
|
||||
<data name="SettingsPageDesktopLyrics.Content" xml:space="preserve">
|
||||
<value>桌面歌词</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -225,12 +225,9 @@
|
||||
<data name="SettingsPageTitle" xml:space="preserve">
|
||||
<value>設定</value>
|
||||
</data>
|
||||
<data name="MainPageTitle" xml:space="preserve">
|
||||
<data name="InAppLyricsPageTitle" xml:space="preserve">
|
||||
<value>BetterLyrics</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsStyle.Text" xml:space="preserve">
|
||||
<value>歌詞樣式</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsAlignment.Header" xml:space="preserve">
|
||||
<value>對齊方式</value>
|
||||
</data>
|
||||
@@ -279,9 +276,6 @@
|
||||
<data name="MainWindowImmersiveMode.ToolTipService.ToolTip" xml:space="preserve">
|
||||
<value>沉浸模式</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyricsEffect.Text" xml:space="preserve">
|
||||
<value>歌詞效果</value>
|
||||
</data>
|
||||
<data name="SettingsPageAlbumOverlay.Text" xml:space="preserve">
|
||||
<value>專輯背景</value>
|
||||
</data>
|
||||
@@ -396,4 +390,13 @@
|
||||
<data name="MainPageLyricsNotFound.Text" xml:space="preserve">
|
||||
<value>找不到歌詞</value>
|
||||
</data>
|
||||
<data name="SettingsPageLyrics.Text" xml:space="preserve">
|
||||
<value>歌詞樣式與動效</value>
|
||||
</data>
|
||||
<data name="SettingsPageInAppLyrics.Content" xml:space="preserve">
|
||||
<value>應用程式內歌詞</value>
|
||||
</data>
|
||||
<data name="SettingsPageDesktopLyrics.Content" xml:space="preserve">
|
||||
<value>桌面歌詞</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -7,37 +7,73 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
public AlbumArtOverlayViewModel(ISettingsService settingsService)
|
||||
: base(settingsService) { }
|
||||
|
||||
private bool? _isCoverOverlayEnabled = null;
|
||||
public bool IsCoverOverlayEnabled
|
||||
{
|
||||
get =>
|
||||
Get(
|
||||
get
|
||||
{
|
||||
_isCoverOverlayEnabled ??= Get(
|
||||
SettingsKeys.IsCoverOverlayEnabled,
|
||||
SettingsDefaultValues.IsCoverOverlayEnabled
|
||||
);
|
||||
set => Set(SettingsKeys.IsCoverOverlayEnabled, value);
|
||||
return _isCoverOverlayEnabled ?? false;
|
||||
}
|
||||
set
|
||||
{
|
||||
_isCoverOverlayEnabled = value;
|
||||
Set(SettingsKeys.IsCoverOverlayEnabled, value);
|
||||
}
|
||||
}
|
||||
public bool IsDynamicCoverOverlay
|
||||
private bool? _isDynamicCoverOverlayEnabled = null;
|
||||
public bool IsDynamicCoverOverlayEnabled
|
||||
{
|
||||
get =>
|
||||
Get(
|
||||
SettingsKeys.IsDynamicCoverOverlay,
|
||||
SettingsDefaultValues.IsDynamicCoverOverlay
|
||||
get
|
||||
{
|
||||
_isDynamicCoverOverlayEnabled ??= Get(
|
||||
SettingsKeys.IsDynamicCoverOverlayEnabled,
|
||||
SettingsDefaultValues.IsDynamicCoverOverlayEnabled
|
||||
);
|
||||
set => Set(SettingsKeys.IsDynamicCoverOverlay, value);
|
||||
return _isDynamicCoverOverlayEnabled ?? false;
|
||||
}
|
||||
set
|
||||
{
|
||||
_isDynamicCoverOverlayEnabled = value;
|
||||
Set(SettingsKeys.IsDynamicCoverOverlayEnabled, value);
|
||||
}
|
||||
}
|
||||
private int? _coverOverlayOpacity;
|
||||
public int CoverOverlayOpacity
|
||||
{
|
||||
get => Get(SettingsKeys.CoverOverlayOpacity, SettingsDefaultValues.CoverOverlayOpacity);
|
||||
set => Set(SettingsKeys.CoverOverlayOpacity, value);
|
||||
get
|
||||
{
|
||||
_coverOverlayOpacity ??= Get(
|
||||
SettingsKeys.CoverOverlayOpacity,
|
||||
SettingsDefaultValues.CoverOverlayOpacity
|
||||
);
|
||||
return _coverOverlayOpacity ?? 0;
|
||||
}
|
||||
set
|
||||
{
|
||||
_coverOverlayOpacity = value;
|
||||
Set(SettingsKeys.CoverOverlayOpacity, value);
|
||||
}
|
||||
}
|
||||
private int? _coverOverlayBlurAmount;
|
||||
public int CoverOverlayBlurAmount
|
||||
{
|
||||
get =>
|
||||
Get(
|
||||
get
|
||||
{
|
||||
_coverOverlayBlurAmount ??= Get(
|
||||
SettingsKeys.CoverOverlayBlurAmount,
|
||||
SettingsDefaultValues.CoverOverlayBlurAmount
|
||||
);
|
||||
set => Set(SettingsKeys.CoverOverlayBlurAmount, value);
|
||||
return _coverOverlayBlurAmount ?? 0;
|
||||
}
|
||||
set
|
||||
{
|
||||
_coverOverlayBlurAmount = value;
|
||||
Set(SettingsKeys.CoverOverlayBlurAmount, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,12 +11,21 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
{
|
||||
public class AlbumArtViewModel : BaseSettingsViewModel
|
||||
{
|
||||
private int? _coverImageRadius;
|
||||
public int CoverImageRadius
|
||||
{
|
||||
get => Get(SettingsKeys.CoverImageRadius, SettingsDefaultValues.CoverImageRadius);
|
||||
get
|
||||
{
|
||||
_coverImageRadius ??= Get(
|
||||
SettingsKeys.CoverImageRadius,
|
||||
SettingsDefaultValues.CoverImageRadius
|
||||
);
|
||||
return _coverImageRadius ?? 0;
|
||||
}
|
||||
set
|
||||
{
|
||||
Set(SettingsKeys.CoverImageRadius, value);
|
||||
_coverImageRadius = value;
|
||||
WeakReferenceMessenger.Default.Send(new AlbumArtCornerRadiusChangedMessage(value));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +53,9 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
[ObservableProperty]
|
||||
private bool _isPlaying = false;
|
||||
|
||||
[ObservableProperty]
|
||||
private System.Drawing.Color _activatedWindowAccentColor = System.Drawing.Color.Transparent;
|
||||
|
||||
public GlobalViewModel(ISettingsService settingsService)
|
||||
: base(settingsService)
|
||||
{
|
||||
|
||||
@@ -1,115 +1,203 @@
|
||||
using BetterLyrics.WinUI3.Messages;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.Services.Playback;
|
||||
using BetterLyrics.WinUI3.Services.Settings;
|
||||
using BetterLyrics.WinUI3.ViewModels.Lyrics;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using Microsoft.UI.Xaml.Documents;
|
||||
|
||||
namespace BetterLyrics.WinUI3.ViewModels
|
||||
{
|
||||
public partial class DesktopLyricsViewModel : BaseLyricsViewModel, ILyricsViewModel
|
||||
{
|
||||
private LyricsAlignmentType? _lyricsAlignmentType;
|
||||
public LyricsAlignmentType LyricsAlignmentType
|
||||
{
|
||||
get =>
|
||||
(LyricsAlignmentType)Get(
|
||||
get
|
||||
{
|
||||
_lyricsAlignmentType ??= (LyricsAlignmentType)Get(
|
||||
SettingsKeys.DesktopLyricsAlignmentType,
|
||||
SettingsDefaultValues.DesktopLyricsAlignmentType
|
||||
);
|
||||
set => Set(SettingsKeys.DesktopLyricsAlignmentType, (int)value);
|
||||
return _lyricsAlignmentType ?? 0;
|
||||
}
|
||||
set
|
||||
{
|
||||
Set(SettingsKeys.DesktopLyricsAlignmentType, (int)value);
|
||||
_lyricsAlignmentType = value;
|
||||
}
|
||||
}
|
||||
private int? _lyricsBlurAmount;
|
||||
public int LyricsBlurAmount
|
||||
{
|
||||
get =>
|
||||
Get(
|
||||
get
|
||||
{
|
||||
_lyricsBlurAmount ??= Get(
|
||||
SettingsKeys.DesktopLyricsBlurAmount,
|
||||
SettingsDefaultValues.DesktopLyricsBlurAmount
|
||||
);
|
||||
set => Set(SettingsKeys.DesktopLyricsBlurAmount, value);
|
||||
return _lyricsBlurAmount ?? 0;
|
||||
}
|
||||
set
|
||||
{
|
||||
Set(SettingsKeys.DesktopLyricsBlurAmount, value);
|
||||
_lyricsBlurAmount = value;
|
||||
}
|
||||
}
|
||||
|
||||
private int? _lyricsVerticalEdgeOpacity;
|
||||
public int LyricsVerticalEdgeOpacity
|
||||
{
|
||||
get =>
|
||||
Get(
|
||||
get
|
||||
{
|
||||
_lyricsVerticalEdgeOpacity ??= Get(
|
||||
SettingsKeys.DesktopLyricsVerticalEdgeOpacity,
|
||||
SettingsDefaultValues.DesktopLyricsVerticalEdgeOpacity
|
||||
);
|
||||
set => Set(SettingsKeys.DesktopLyricsVerticalEdgeOpacity, value);
|
||||
return _lyricsVerticalEdgeOpacity ?? 0;
|
||||
}
|
||||
set
|
||||
{
|
||||
Set(SettingsKeys.DesktopLyricsVerticalEdgeOpacity, value);
|
||||
_lyricsVerticalEdgeOpacity = value;
|
||||
}
|
||||
}
|
||||
|
||||
private float? _lyricsLineSpacingFactor;
|
||||
public float LyricsLineSpacingFactor
|
||||
{
|
||||
get =>
|
||||
Get(
|
||||
get
|
||||
{
|
||||
_lyricsLineSpacingFactor ??= Get(
|
||||
SettingsKeys.DesktopLyricsLineSpacingFactor,
|
||||
SettingsDefaultValues.DesktopLyricsLineSpacingFactor
|
||||
);
|
||||
return _lyricsLineSpacingFactor ?? 0;
|
||||
}
|
||||
set
|
||||
{
|
||||
Set(SettingsKeys.DesktopLyricsLineSpacingFactor, value);
|
||||
WeakReferenceMessenger.Default.Send(new DesktopLyricsRelayoutRequestedMessage());
|
||||
_lyricsLineSpacingFactor = value;
|
||||
}
|
||||
}
|
||||
|
||||
private int? _lyricsFontSize;
|
||||
public int LyricsFontSize
|
||||
{
|
||||
get =>
|
||||
Get(
|
||||
get
|
||||
{
|
||||
_lyricsFontSize ??= Get(
|
||||
SettingsKeys.DesktopLyricsFontSize,
|
||||
SettingsDefaultValues.DesktopLyricsFontSize
|
||||
);
|
||||
return _lyricsFontSize ?? 0;
|
||||
}
|
||||
set
|
||||
{
|
||||
Set(SettingsKeys.DesktopLyricsFontSize, value);
|
||||
WeakReferenceMessenger.Default.Send(new DesktopLyricsRelayoutRequestedMessage());
|
||||
_lyricsFontSize = value;
|
||||
}
|
||||
}
|
||||
|
||||
private bool? _isLyricsGlowEffectEnabled;
|
||||
public bool IsLyricsGlowEffectEnabled
|
||||
{
|
||||
get =>
|
||||
Get(
|
||||
get
|
||||
{
|
||||
_isLyricsGlowEffectEnabled ??= Get(
|
||||
SettingsKeys.IsDesktopLyricsGlowEffectEnabled,
|
||||
SettingsDefaultValues.IsDesktopLyricsGlowEffectEnabled
|
||||
);
|
||||
set => Set(SettingsKeys.IsDesktopLyricsGlowEffectEnabled, value);
|
||||
return _isLyricsGlowEffectEnabled ?? false;
|
||||
}
|
||||
set
|
||||
{
|
||||
Set(SettingsKeys.IsDesktopLyricsGlowEffectEnabled, value);
|
||||
_isLyricsGlowEffectEnabled = value;
|
||||
}
|
||||
}
|
||||
|
||||
private bool? _isLyricsDynamicGlowEffectEnabled;
|
||||
public bool IsLyricsDynamicGlowEffectEnabled
|
||||
{
|
||||
get =>
|
||||
Get(
|
||||
get
|
||||
{
|
||||
_isLyricsDynamicGlowEffectEnabled ??= Get(
|
||||
SettingsKeys.IsDesktopLyricsDynamicGlowEffectEnabled,
|
||||
SettingsDefaultValues.IsDesktopLyricsDynamicGlowEffectEnabled
|
||||
);
|
||||
set => Set(SettingsKeys.IsDesktopLyricsDynamicGlowEffectEnabled, value);
|
||||
return _isLyricsDynamicGlowEffectEnabled ?? false;
|
||||
}
|
||||
set
|
||||
{
|
||||
Set(SettingsKeys.IsDesktopLyricsDynamicGlowEffectEnabled, value);
|
||||
_isLyricsDynamicGlowEffectEnabled = value;
|
||||
}
|
||||
}
|
||||
|
||||
private LyricsFontColorType? _lyricsFontColorType;
|
||||
public LyricsFontColorType LyricsFontColorType
|
||||
{
|
||||
get =>
|
||||
(LyricsFontColorType)Get(
|
||||
get
|
||||
{
|
||||
_lyricsFontColorType ??= (LyricsFontColorType)Get(
|
||||
SettingsKeys.DesktopLyricsFontColorType,
|
||||
SettingsDefaultValues.DesktopLyricsFontColorType
|
||||
);
|
||||
return _lyricsFontColorType ?? 0;
|
||||
}
|
||||
set
|
||||
{
|
||||
Set(SettingsKeys.DesktopLyricsFontColorType, (int)value);
|
||||
_lyricsFontColorType = value;
|
||||
WeakReferenceMessenger.Default.Send(new LyricsFontColorChangedMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private int? _lyricsFontSelectedAccentColorIndex;
|
||||
public int LyricsFontSelectedAccentColorIndex
|
||||
{
|
||||
get =>
|
||||
Get(
|
||||
get
|
||||
{
|
||||
_lyricsFontSelectedAccentColorIndex ??= Get(
|
||||
SettingsKeys.DesktopLyricsFontSelectedAccentColorIndex,
|
||||
SettingsDefaultValues.DesktopLyricsFontSelectedAccentColorIndex
|
||||
);
|
||||
return _lyricsFontSelectedAccentColorIndex ?? 0;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value >= 0)
|
||||
{
|
||||
Set(SettingsKeys.DesktopLyricsFontSelectedAccentColorIndex, value);
|
||||
_lyricsFontSelectedAccentColorIndex = value;
|
||||
WeakReferenceMessenger.Default.Send(new LyricsFontColorChangedMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public DesktopLyricsViewModel(ISettingsService settingsService)
|
||||
: base(settingsService) { }
|
||||
[ObservableProperty]
|
||||
private bool _isSettingsPopupOpened = false;
|
||||
|
||||
[RelayCommand]
|
||||
private void ToggleSettingsPopup()
|
||||
{
|
||||
IsSettingsPopupOpened = !IsSettingsPopupOpened;
|
||||
}
|
||||
|
||||
private readonly IPlaybackService _playbackService;
|
||||
|
||||
public DesktopLyricsViewModel(
|
||||
ISettingsService settingsService,
|
||||
IPlaybackService playbackService
|
||||
)
|
||||
: base(settingsService)
|
||||
{
|
||||
_playbackService = playbackService;
|
||||
|
||||
_playbackService.ReSendingMessages();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,117 +1,283 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading.Tasks;
|
||||
using BetterLyrics.WinUI3;
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using BetterLyrics.WinUI3.Messages;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.Services.Playback;
|
||||
using BetterLyrics.WinUI3.Services.Settings;
|
||||
using BetterLyrics.WinUI3.ViewModels;
|
||||
using BetterLyrics.WinUI3.ViewModels.Lyrics;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using Microsoft.UI;
|
||||
using Windows.UI;
|
||||
using Microsoft.UI.Dispatching;
|
||||
using Microsoft.UI.Xaml.Media.Imaging;
|
||||
|
||||
namespace BetterInAppLyrics.WinUI3.ViewModels
|
||||
{
|
||||
public partial class InAppLyricsViewModel : BaseLyricsViewModel, ILyricsViewModel
|
||||
{
|
||||
private LyricsAlignmentType? _lyricsAlignmentType;
|
||||
public LyricsAlignmentType LyricsAlignmentType
|
||||
{
|
||||
get =>
|
||||
(LyricsAlignmentType)Get(
|
||||
get
|
||||
{
|
||||
_lyricsAlignmentType ??= (LyricsAlignmentType)Get(
|
||||
SettingsKeys.InAppLyricsAlignmentType,
|
||||
SettingsDefaultValues.InAppLyricsAlignmentType
|
||||
);
|
||||
set => Set(SettingsKeys.InAppLyricsAlignmentType, (int)value);
|
||||
return _lyricsAlignmentType ?? 0;
|
||||
}
|
||||
set
|
||||
{
|
||||
Set(SettingsKeys.InAppLyricsAlignmentType, (int)value);
|
||||
_lyricsAlignmentType = value;
|
||||
}
|
||||
}
|
||||
private int? _lyricsBlurAmount;
|
||||
public int LyricsBlurAmount
|
||||
{
|
||||
get =>
|
||||
Get(
|
||||
get
|
||||
{
|
||||
_lyricsBlurAmount ??= Get(
|
||||
SettingsKeys.InAppLyricsBlurAmount,
|
||||
SettingsDefaultValues.InAppLyricsBlurAmount
|
||||
);
|
||||
set => Set(SettingsKeys.InAppLyricsBlurAmount, value);
|
||||
return _lyricsBlurAmount ?? 0;
|
||||
}
|
||||
set
|
||||
{
|
||||
Set(SettingsKeys.InAppLyricsBlurAmount, value);
|
||||
_lyricsBlurAmount = value;
|
||||
}
|
||||
}
|
||||
|
||||
private int? _lyricsVerticalEdgeOpacity;
|
||||
public int LyricsVerticalEdgeOpacity
|
||||
{
|
||||
get =>
|
||||
Get(
|
||||
get
|
||||
{
|
||||
_lyricsVerticalEdgeOpacity ??= Get(
|
||||
SettingsKeys.InAppLyricsVerticalEdgeOpacity,
|
||||
SettingsDefaultValues.InAppLyricsVerticalEdgeOpacity
|
||||
);
|
||||
set => Set(SettingsKeys.InAppLyricsVerticalEdgeOpacity, value);
|
||||
return _lyricsVerticalEdgeOpacity ?? 0;
|
||||
}
|
||||
set
|
||||
{
|
||||
Set(SettingsKeys.InAppLyricsVerticalEdgeOpacity, value);
|
||||
_lyricsVerticalEdgeOpacity = value;
|
||||
}
|
||||
}
|
||||
|
||||
private float? _lyricsLineSpacingFactor;
|
||||
public float LyricsLineSpacingFactor
|
||||
{
|
||||
get =>
|
||||
Get(
|
||||
get
|
||||
{
|
||||
_lyricsLineSpacingFactor ??= Get(
|
||||
SettingsKeys.InAppLyricsLineSpacingFactor,
|
||||
SettingsDefaultValues.InAppLyricsLineSpacingFactor
|
||||
);
|
||||
return _lyricsLineSpacingFactor ?? 0;
|
||||
}
|
||||
set
|
||||
{
|
||||
Set(SettingsKeys.InAppLyricsLineSpacingFactor, value);
|
||||
WeakReferenceMessenger.Default.Send(new InAppLyricsRelayoutRequestedMessage());
|
||||
_lyricsLineSpacingFactor = value;
|
||||
}
|
||||
}
|
||||
|
||||
private int? _lyricsFontSize;
|
||||
public int LyricsFontSize
|
||||
{
|
||||
get => Get(SettingsKeys.InAppLyricsFontSize, SettingsDefaultValues.InAppLyricsFontSize);
|
||||
get
|
||||
{
|
||||
_lyricsFontSize ??= Get(
|
||||
SettingsKeys.InAppLyricsFontSize,
|
||||
SettingsDefaultValues.InAppLyricsFontSize
|
||||
);
|
||||
return _lyricsFontSize ?? 0;
|
||||
}
|
||||
set
|
||||
{
|
||||
Set(SettingsKeys.InAppLyricsFontSize, value);
|
||||
WeakReferenceMessenger.Default.Send(new InAppLyricsRelayoutRequestedMessage());
|
||||
_lyricsFontSize = value;
|
||||
}
|
||||
}
|
||||
|
||||
private bool? _isLyricsGlowEffectEnabled;
|
||||
public bool IsLyricsGlowEffectEnabled
|
||||
{
|
||||
get =>
|
||||
Get(
|
||||
get
|
||||
{
|
||||
_isLyricsGlowEffectEnabled ??= Get(
|
||||
SettingsKeys.IsInAppLyricsGlowEffectEnabled,
|
||||
SettingsDefaultValues.IsInAppLyricsGlowEffectEnabled
|
||||
);
|
||||
set => Set(SettingsKeys.IsInAppLyricsGlowEffectEnabled, value);
|
||||
return _isLyricsGlowEffectEnabled ?? false;
|
||||
}
|
||||
set
|
||||
{
|
||||
Set(SettingsKeys.IsInAppLyricsGlowEffectEnabled, value);
|
||||
_isLyricsGlowEffectEnabled = value;
|
||||
}
|
||||
}
|
||||
|
||||
private bool? _isLyricsDynamicGlowEffectEnabled;
|
||||
public bool IsLyricsDynamicGlowEffectEnabled
|
||||
{
|
||||
get =>
|
||||
Get(
|
||||
get
|
||||
{
|
||||
_isLyricsDynamicGlowEffectEnabled ??= Get(
|
||||
SettingsKeys.IsInAppLyricsDynamicGlowEffectEnabled,
|
||||
SettingsDefaultValues.IsInAppLyricsDynamicGlowEffectEnabled
|
||||
);
|
||||
set => Set(SettingsKeys.IsInAppLyricsDynamicGlowEffectEnabled, value);
|
||||
return _isLyricsDynamicGlowEffectEnabled ?? false;
|
||||
}
|
||||
set
|
||||
{
|
||||
Set(SettingsKeys.IsInAppLyricsDynamicGlowEffectEnabled, value);
|
||||
_isLyricsDynamicGlowEffectEnabled = value;
|
||||
}
|
||||
}
|
||||
|
||||
private LyricsFontColorType? _lyricsFontColorType;
|
||||
public LyricsFontColorType LyricsFontColorType
|
||||
{
|
||||
get =>
|
||||
(LyricsFontColorType)Get(
|
||||
get
|
||||
{
|
||||
_lyricsFontColorType ??= (LyricsFontColorType)Get(
|
||||
SettingsKeys.InAppLyricsFontColorType,
|
||||
SettingsDefaultValues.InAppLyricsFontColorType
|
||||
);
|
||||
return _lyricsFontColorType ?? 0;
|
||||
}
|
||||
set
|
||||
{
|
||||
Set(SettingsKeys.InAppLyricsFontColorType, (int)value);
|
||||
_lyricsFontColorType = value;
|
||||
WeakReferenceMessenger.Default.Send(new LyricsFontColorChangedMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private int? _lyricsFontSelectedAccentColorIndex;
|
||||
public int LyricsFontSelectedAccentColorIndex
|
||||
{
|
||||
get =>
|
||||
Get(
|
||||
get
|
||||
{
|
||||
_lyricsFontSelectedAccentColorIndex ??= Get(
|
||||
SettingsKeys.InAppLyricsFontSelectedAccentColorIndex,
|
||||
SettingsDefaultValues.InAppLyricsFontSelectedAccentColorIndex
|
||||
);
|
||||
return _lyricsFontSelectedAccentColorIndex ?? 0;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value >= 0)
|
||||
{
|
||||
Set(SettingsKeys.InAppLyricsFontSelectedAccentColorIndex, value);
|
||||
_lyricsFontSelectedAccentColorIndex = value;
|
||||
WeakReferenceMessenger.Default.Send(new LyricsFontColorChangedMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public InAppLyricsViewModel(ISettingsService settingsService)
|
||||
//
|
||||
|
||||
[ObservableProperty]
|
||||
private BitmapImage? _coverImage;
|
||||
|
||||
[ObservableProperty]
|
||||
private SongInfo? _songInfo = null;
|
||||
|
||||
private DisplayType? _preferredDisplayType = DisplayType.SplitView;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _aboutToUpdateUI;
|
||||
|
||||
private bool _isImmersiveMode = false;
|
||||
public bool IsImmersiveMode
|
||||
{
|
||||
get => _isImmersiveMode;
|
||||
set
|
||||
{
|
||||
_isImmersiveMode = value;
|
||||
OnPropertyChanged();
|
||||
WeakReferenceMessenger.Default.Send(new IsImmersiveModeChangedMessage(value));
|
||||
if (value)
|
||||
WeakReferenceMessenger.Default.Send(
|
||||
new ShowNotificatonMessage(
|
||||
new Notification(
|
||||
App.ResourceLoader!.GetString("MainPageEnterImmersiveModeHint"),
|
||||
isForeverDismissable: true,
|
||||
relatedSettingsKeyName: SettingsKeys.NeverShowEnterImmersiveModeMessage
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public InAppLyricsViewModel(
|
||||
ISettingsService settingsService,
|
||||
IPlaybackService playbackService
|
||||
)
|
||||
: base(settingsService) { }
|
||||
|
||||
public async Task UpdateSongInfoUI(SongInfo? songInfo)
|
||||
{
|
||||
AboutToUpdateUI = true;
|
||||
await Task.Delay(AnimationHelper.StoryboardDefaultDuration);
|
||||
|
||||
SongInfo = songInfo;
|
||||
|
||||
await Task.Delay(1);
|
||||
|
||||
CoverImage =
|
||||
(songInfo?.AlbumArt == null)
|
||||
? null
|
||||
: await ImageHelper.GetBitmapImageFromBytesAsync(songInfo.AlbumArt);
|
||||
|
||||
DisplayType displayType;
|
||||
|
||||
if (songInfo == null)
|
||||
{
|
||||
displayType = DisplayType.PlaceholderOnly;
|
||||
}
|
||||
else if (_preferredDisplayType is DisplayType preferredDisplayType)
|
||||
{
|
||||
displayType = preferredDisplayType;
|
||||
}
|
||||
else
|
||||
{
|
||||
displayType = DisplayType.SplitView;
|
||||
}
|
||||
|
||||
WeakReferenceMessenger.Default.Send(new DisplayTypeChangedMessage(displayType));
|
||||
|
||||
AboutToUpdateUI = false;
|
||||
}
|
||||
|
||||
public void OpenMatchedFileFolderInFileExplorer(string path)
|
||||
{
|
||||
Process.Start(
|
||||
new ProcessStartInfo
|
||||
{
|
||||
FileName = "explorer.exe",
|
||||
Arguments = $"/select,\"{path}\"",
|
||||
UseShellExecute = true,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void OnDisplayTypeChanged(object value)
|
||||
{
|
||||
int index = Convert.ToInt32(value);
|
||||
_preferredDisplayType = (DisplayType)index;
|
||||
WeakReferenceMessenger.Default.Send(new DisplayTypeChangedMessage((DisplayType)index));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading.Tasks;
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using BetterLyrics.WinUI3.Messages;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.Services.Playback;
|
||||
using BetterLyrics.WinUI3.Services.Settings;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using Microsoft.UI.Dispatching;
|
||||
using Microsoft.UI.Xaml.Media.Imaging;
|
||||
|
||||
namespace BetterLyrics.WinUI3.ViewModels
|
||||
{
|
||||
public partial class MainViewModel : ObservableObject
|
||||
{
|
||||
private readonly DispatcherQueue _dispatcherQueue = DispatcherQueue.GetForCurrentThread();
|
||||
|
||||
[ObservableProperty]
|
||||
private BitmapImage? _coverImage;
|
||||
|
||||
[ObservableProperty]
|
||||
private SongInfo? _songInfo = null;
|
||||
|
||||
private DisplayType? _preferredDisplayType = DisplayType.SplitView;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _aboutToUpdateUI;
|
||||
|
||||
private bool _isImmersiveMode = false;
|
||||
public bool IsImmersiveMode
|
||||
{
|
||||
get => _isImmersiveMode;
|
||||
set
|
||||
{
|
||||
_isImmersiveMode = value;
|
||||
OnPropertyChanged();
|
||||
WeakReferenceMessenger.Default.Send(new IsImmersiveModeChangedMessage(value));
|
||||
if (value)
|
||||
WeakReferenceMessenger.Default.Send(
|
||||
new ShowNotificatonMessage(
|
||||
new Notification(
|
||||
App.ResourceLoader!.GetString("MainPageEnterImmersiveModeHint"),
|
||||
isForeverDismissable: true,
|
||||
relatedSettingsKeyName: SettingsKeys.NeverShowEnterImmersiveModeMessage
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public MainViewModel(IPlaybackService playbackService)
|
||||
{
|
||||
WeakReferenceMessenger.Default.Register<MainViewModel, SongInfoChangedMessage>(
|
||||
this,
|
||||
(r, m) =>
|
||||
{
|
||||
_dispatcherQueue.TryEnqueue(
|
||||
DispatcherQueuePriority.High,
|
||||
async () => await UpdateSongInfoUI(m.Value)
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private async Task UpdateSongInfoUI(SongInfo? songInfo)
|
||||
{
|
||||
AboutToUpdateUI = true;
|
||||
await Task.Delay(AnimationHelper.StoryboardDefaultDuration);
|
||||
|
||||
SongInfo = songInfo;
|
||||
|
||||
await Task.Delay(1);
|
||||
|
||||
CoverImage =
|
||||
(songInfo?.AlbumArt == null)
|
||||
? null
|
||||
: await ImageHelper.GetBitmapImageFromBytesAsync(songInfo.AlbumArt);
|
||||
|
||||
DisplayType displayType;
|
||||
|
||||
if (songInfo == null)
|
||||
{
|
||||
displayType = DisplayType.PlaceholderOnly;
|
||||
}
|
||||
else if (_preferredDisplayType is DisplayType preferredDisplayType)
|
||||
{
|
||||
displayType = preferredDisplayType;
|
||||
}
|
||||
else
|
||||
{
|
||||
displayType = DisplayType.SplitView;
|
||||
}
|
||||
|
||||
WeakReferenceMessenger.Default.Send(new DisplayTypeChangedMessage(displayType));
|
||||
|
||||
AboutToUpdateUI = false;
|
||||
}
|
||||
|
||||
public void OpenMatchedFileFolderInFileExplorer(string path)
|
||||
{
|
||||
Process.Start(
|
||||
new ProcessStartInfo
|
||||
{
|
||||
FileName = "explorer.exe",
|
||||
Arguments = $"/select,\"{path}\"",
|
||||
UseShellExecute = true,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void OnDisplayTypeChanged(object value)
|
||||
{
|
||||
int index = Convert.ToInt32(value);
|
||||
_preferredDisplayType = (DisplayType)index;
|
||||
WeakReferenceMessenger.Default.Send(new DisplayTypeChangedMessage((DisplayType)index));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -128,13 +128,11 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
|
||||
picker.FileTypeFilter.Add("*");
|
||||
|
||||
var hwnd = WindowNative.GetWindowHandle(App.Current.MainWindow);
|
||||
var hwnd = WindowNative.GetWindowHandle(App.Current.SettingsWindow);
|
||||
InitializeWithWindow.Initialize(picker, hwnd);
|
||||
|
||||
var folder = await picker.PickSingleFolderAsync();
|
||||
|
||||
App.Current.SettingsWindow!.AppWindow.MoveInZOrderAtTop();
|
||||
|
||||
if (folder != null)
|
||||
{
|
||||
await AddFolderAsync(folder.Path);
|
||||
|
||||
@@ -5,8 +5,10 @@
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:canvas="using:Microsoft.Graphics.Canvas.UI.Xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
|
||||
xmlns:local="using:BetterLyrics.WinUI3.Views"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:uc="using:BetterLyrics.WinUI3.Controls"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid>
|
||||
@@ -19,5 +21,40 @@
|
||||
Draw="LyricsCanvas_Draw"
|
||||
Paused="{x:Bind GlobalSettingsViewModel.IsPlaying, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}"
|
||||
Update="LyricsCanvas_Update" />
|
||||
<Grid
|
||||
x:Name="RightCommandGrid"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
Opacity="0">
|
||||
<Grid.OpacityTransition>
|
||||
<ScalarTransition />
|
||||
</Grid.OpacityTransition>
|
||||
<Button
|
||||
x:Name="SettingsButton"
|
||||
Command="{x:Bind ViewModel.ToggleSettingsPopupCommand}"
|
||||
Style="{StaticResource GhostButtonStyle}">
|
||||
<FontIcon FontFamily="Segoe Fluent Icons" Glyph="" />
|
||||
</Button>
|
||||
<Popup
|
||||
x:Name="SettingsPopup"
|
||||
DesiredPlacement="Bottom"
|
||||
IsOpen="{x:Bind ViewModel.IsSettingsPopupOpened, Mode=OneWay}">
|
||||
<uc:LyricsSettingsControl ViewModel="{x:Bind ViewModel, Mode=OneWay}" />
|
||||
</Popup>
|
||||
<interactivity:Interaction.Behaviors>
|
||||
<interactivity:EventTriggerBehavior EventName="PointerEntered">
|
||||
<interactivity:ChangePropertyAction
|
||||
PropertyName="Opacity"
|
||||
TargetObject="{Binding ElementName=RightCommandGrid}"
|
||||
Value="1" />
|
||||
</interactivity:EventTriggerBehavior>
|
||||
<interactivity:EventTriggerBehavior EventName="PointerExited">
|
||||
<interactivity:ChangePropertyAction
|
||||
PropertyName="Opacity"
|
||||
TargetObject="{Binding ElementName=RightCommandGrid}"
|
||||
Value="0" />
|
||||
</interactivity:EventTriggerBehavior>
|
||||
</interactivity:Interaction.Behaviors>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Page>
|
||||
|
||||
@@ -1,19 +1,12 @@
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using BetterLyrics.WinUI3.Messages;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.Rendering;
|
||||
using BetterLyrics.WinUI3.ViewModels;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using Microsoft.Graphics.Canvas.UI.Xaml;
|
||||
using Microsoft.UI;
|
||||
using Microsoft.UI.Dispatching;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
using WinRT.Interop;
|
||||
|
||||
// To learn more about WinUI, the WinUI project structure,
|
||||
// and more about our project templates, see: http://aka.ms/winui-project-info.
|
||||
@@ -27,28 +20,18 @@ namespace BetterLyrics.WinUI3.Views
|
||||
{
|
||||
private readonly DispatcherQueue _dispatcherQueue = DispatcherQueue.GetForCurrentThread();
|
||||
|
||||
private double _limitedLineWidth = 0;
|
||||
|
||||
private readonly DesktopLyricsRenderer _lyricsRenderer =
|
||||
Ioc.Default.GetService<DesktopLyricsRenderer>()!;
|
||||
|
||||
public DesktopLyricsViewModel ViewModel => (DesktopLyricsViewModel)DataContext;
|
||||
|
||||
private GlobalViewModel GlobalSettingsViewModel { get; set; } =
|
||||
Ioc.Default.GetService<GlobalViewModel>()!;
|
||||
|
||||
public DesktopLyricsPage()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
|
||||
WeakReferenceMessenger.Default.Register<
|
||||
DesktopLyricsPage,
|
||||
DesktopLyricsRelayoutRequestedMessage
|
||||
>(
|
||||
this,
|
||||
async (r, m) =>
|
||||
{
|
||||
await _lyricsRenderer.ReLayoutAsync(LyricsCanvas);
|
||||
}
|
||||
);
|
||||
DataContext = Ioc.Default.GetService<DesktopLyricsViewModel>();
|
||||
|
||||
WeakReferenceMessenger.Default.Register<DesktopLyricsPage, SongInfoChangedMessage>(
|
||||
this,
|
||||
@@ -56,10 +39,9 @@ namespace BetterLyrics.WinUI3.Views
|
||||
{
|
||||
_dispatcherQueue.TryEnqueue(
|
||||
DispatcherQueuePriority.High,
|
||||
async () =>
|
||||
() =>
|
||||
{
|
||||
_lyricsRenderer.LyricsLines = m.Value?.LyricsLines ?? [];
|
||||
await _lyricsRenderer.ReLayoutAsync(LyricsCanvas);
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -86,6 +68,8 @@ namespace BetterLyrics.WinUI3.Views
|
||||
)
|
||||
{
|
||||
using var ds = args.DrawingSession;
|
||||
_lyricsRenderer.UpdateTransition((float)args.Timing.ElapsedTime.TotalSeconds);
|
||||
_lyricsRenderer.DrawBackground(sender, ds);
|
||||
_lyricsRenderer.Draw(sender, ds);
|
||||
}
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ namespace BetterLyrics.WinUI3.Views
|
||||
|
||||
private void UpdateBackdrop(BackdropType? backdropType)
|
||||
{
|
||||
if (RootFrame.SourcePageType == typeof(MainPage))
|
||||
if (RootFrame.SourcePageType == typeof(InAppLyricsPage))
|
||||
SystemBackdrop = SystemBackdropHelper.CreateSystemBackdrop(
|
||||
backdropType ?? GlobalSettingsViewModel.BackdropType
|
||||
);
|
||||
@@ -90,14 +90,7 @@ namespace BetterLyrics.WinUI3.Views
|
||||
|
||||
private void CloseButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (RootFrame.CurrentSourcePageType == typeof(MainPage))
|
||||
{
|
||||
App.Current.Exit();
|
||||
}
|
||||
else if (RootFrame.CurrentSourcePageType == typeof(SettingsPage))
|
||||
{
|
||||
App.Current.SettingsWindow!.AppWindow.Hide();
|
||||
}
|
||||
Close();
|
||||
}
|
||||
|
||||
private void MaximiseButton_Click(object sender, RoutedEventArgs e)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<Page
|
||||
x:Class="BetterLyrics.WinUI3.Views.MainPage"
|
||||
x:Class="BetterLyrics.WinUI3.Views.InAppLyricsPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:animatedvisuals="using:Microsoft.UI.Xaml.Controls.AnimatedVisuals"
|
||||
@@ -22,7 +22,6 @@
|
||||
x:Name="LyricsCanvas"
|
||||
Draw="LyricsCanvas_Draw"
|
||||
Foreground="{ThemeResource TextFillColorPrimaryBrush}"
|
||||
Loaded="LyricsCanvas_Loaded"
|
||||
Paused="{x:Bind GlobalSettingsViewModel.IsPlaying, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}"
|
||||
Update="LyricsCanvas_Update" />
|
||||
<Grid.OpacityTransition>
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using BetterInAppLyrics.WinUI3.ViewModels;
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using BetterLyrics.WinUI3.Messages;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
@@ -28,11 +29,11 @@ namespace BetterLyrics.WinUI3.Views
|
||||
/// <summary>
|
||||
/// An empty page that can be used on its own or navigated to within a Frame.
|
||||
/// </summary>
|
||||
public sealed partial class MainPage : Page
|
||||
public sealed partial class InAppLyricsPage : Page
|
||||
{
|
||||
private readonly DispatcherQueue _dispatcherQueue = DispatcherQueue.GetForCurrentThread();
|
||||
|
||||
public MainViewModel ViewModel => (MainViewModel)DataContext;
|
||||
public InAppLyricsViewModel ViewModel => (InAppLyricsViewModel)DataContext;
|
||||
|
||||
private GlobalViewModel GlobalSettingsViewModel { get; set; } =
|
||||
Ioc.Default.GetService<GlobalViewModel>()!;
|
||||
@@ -43,18 +44,20 @@ namespace BetterLyrics.WinUI3.Views
|
||||
private readonly AlbumArtRenderer _albumArtRenderer =
|
||||
Ioc.Default.GetService<AlbumArtRenderer>()!;
|
||||
|
||||
private readonly ILogger<MainPage> _logger = Ioc.Default.GetService<ILogger<MainPage>>()!;
|
||||
private readonly ILogger<InAppLyricsPage> _logger = Ioc.Default.GetService<
|
||||
ILogger<InAppLyricsPage>
|
||||
>()!;
|
||||
|
||||
public AlbumArtViewModel AlbumArtViewModel { get; set; } =
|
||||
Ioc.Default.GetService<AlbumArtViewModel>()!;
|
||||
|
||||
public MainPage()
|
||||
public InAppLyricsPage()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
|
||||
Debug.WriteLine("hashcode for InAppLyricsRenderer: " + _lyricsRenderer.GetHashCode());
|
||||
|
||||
DataContext = Ioc.Default.GetService<MainViewModel>();
|
||||
DataContext = Ioc.Default.GetService<InAppLyricsViewModel>();
|
||||
|
||||
// set lyrics font color
|
||||
|
||||
@@ -63,7 +66,10 @@ namespace BetterLyrics.WinUI3.Views
|
||||
WelcomeTeachingTip.IsOpen = true;
|
||||
}
|
||||
|
||||
WeakReferenceMessenger.Default.Register<MainPage, AlbumArtCornerRadiusChangedMessage>(
|
||||
WeakReferenceMessenger.Default.Register<
|
||||
InAppLyricsPage,
|
||||
AlbumArtCornerRadiusChangedMessage
|
||||
>(
|
||||
this,
|
||||
(r, m) =>
|
||||
{
|
||||
@@ -71,15 +77,7 @@ namespace BetterLyrics.WinUI3.Views
|
||||
}
|
||||
);
|
||||
|
||||
WeakReferenceMessenger.Default.Register<MainPage, InAppLyricsRelayoutRequestedMessage>(
|
||||
this,
|
||||
async (r, m) =>
|
||||
{
|
||||
await _lyricsRenderer.ReLayoutAsync(LyricsCanvas);
|
||||
}
|
||||
);
|
||||
|
||||
WeakReferenceMessenger.Default.Register<MainPage, SongInfoChangedMessage>(
|
||||
WeakReferenceMessenger.Default.Register<InAppLyricsPage, SongInfoChangedMessage>(
|
||||
this,
|
||||
(r, m) =>
|
||||
{
|
||||
@@ -87,14 +85,14 @@ namespace BetterLyrics.WinUI3.Views
|
||||
DispatcherQueuePriority.High,
|
||||
async () =>
|
||||
{
|
||||
await ViewModel.UpdateSongInfoUI(m.Value);
|
||||
_lyricsRenderer.LyricsLines = m.Value?.LyricsLines ?? [];
|
||||
await _lyricsRenderer.ReLayoutAsync(LyricsCanvas);
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
WeakReferenceMessenger.Default.Register<MainPage, PlayingPositionChangedMessage>(
|
||||
WeakReferenceMessenger.Default.Register<InAppLyricsPage, PlayingPositionChangedMessage>(
|
||||
this,
|
||||
(r, m) =>
|
||||
{
|
||||
@@ -154,22 +152,10 @@ namespace BetterLyrics.WinUI3.Views
|
||||
|
||||
private void SettingsButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (App.Current.SettingsWindow is null)
|
||||
{
|
||||
var settingsWindow = new HostWindow();
|
||||
settingsWindow.Navigate(typeof(SettingsPage));
|
||||
App.Current.SettingsWindow = settingsWindow;
|
||||
}
|
||||
|
||||
var settingsAppWindow = App.Current.SettingsWindow.AppWindow;
|
||||
|
||||
if (settingsAppWindow.Presenter is OverlappedPresenter presenter)
|
||||
{
|
||||
presenter.Restore();
|
||||
}
|
||||
|
||||
settingsAppWindow.Show();
|
||||
settingsAppWindow.MoveInZOrderAtTop();
|
||||
var settingsWindow = WindowHelper.CreateHostWindow();
|
||||
settingsWindow.Navigate(typeof(SettingsPage));
|
||||
settingsWindow.Activate();
|
||||
App.Current.SettingsWindow = settingsWindow;
|
||||
}
|
||||
|
||||
private void WelcomeTeachingTip_Closed(TeachingTip sender, TeachingTipClosedEventArgs args)
|
||||
@@ -203,10 +189,9 @@ namespace BetterLyrics.WinUI3.Views
|
||||
BottomCommandGrid.Opacity = 0;
|
||||
}
|
||||
|
||||
private async void LyricsPlaceholderGrid_SizeChanged(object sender, SizeChangedEventArgs e)
|
||||
private void LyricsPlaceholderGrid_SizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
_lyricsRenderer.LimitedLineWidth = e.NewSize.Width;
|
||||
await _lyricsRenderer.ReLayoutAsync(LyricsCanvas);
|
||||
}
|
||||
|
||||
private void OpenMatchedFileButton_Click(object sender, RoutedEventArgs e)
|
||||
@@ -221,49 +206,18 @@ namespace BetterLyrics.WinUI3.Views
|
||||
|
||||
private void DesktopLyricsToggleButton_Checked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
TransparentAppBarHelper.Enable(App.Current.OverlayWindow!, 48);
|
||||
|
||||
Color color = WindowColorHelper.GetDominantColorBelow(
|
||||
WindowNative.GetWindowHandle(App.Current.OverlayWindow!)
|
||||
);
|
||||
|
||||
var config = new SystemBackdropConfiguration
|
||||
{
|
||||
IsInputActive = true,
|
||||
Theme = SystemBackdropTheme.Default,
|
||||
};
|
||||
|
||||
var micaController = new MicaController();
|
||||
|
||||
micaController.TintColor = Windows.UI.Color.FromArgb(
|
||||
color.A,
|
||||
color.R,
|
||||
color.G,
|
||||
color.B
|
||||
); // 指定自定义颜色
|
||||
micaController.TintOpacity = 0.7f;
|
||||
micaController.FallbackColor = Colors.Black;
|
||||
|
||||
// 配置 Backdrop(假设你已经满足系统要求)
|
||||
micaController.AddSystemBackdropTarget(
|
||||
(
|
||||
App.Current.OverlayWindow!
|
||||
).As<Microsoft.UI.Composition.ICompositionSupportsSystemBackdrop>()
|
||||
);
|
||||
micaController.SetSystemBackdropConfiguration(config);
|
||||
var overlayWindow = WindowHelper.CreateOverlayWindow();
|
||||
overlayWindow.Navigate(typeof(DesktopLyricsPage));
|
||||
overlayWindow.Activate();
|
||||
App.Current.OverlayWindow = overlayWindow;
|
||||
}
|
||||
|
||||
private void DesktopLyricsToggleButton_Unchecked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var overlayAppWindow = App.Current.OverlayWindow!.AppWindow;
|
||||
overlayAppWindow.Hide();
|
||||
|
||||
TransparentAppBarHelper.Disable(App.Current.OverlayWindow);
|
||||
}
|
||||
|
||||
private async void LyricsCanvas_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
await _lyricsRenderer.ReLayoutAsync(LyricsCanvas);
|
||||
var overlayWindow = App.Current.OverlayWindow!;
|
||||
TransparentAppBarHelper.Disable(overlayWindow);
|
||||
overlayWindow.Close();
|
||||
App.Current.OverlayWindow = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,11 @@
|
||||
using System;
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.ViewModels;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using Microsoft.UI.Windowing;
|
||||
using Microsoft.UI.Xaml;
|
||||
using WinRT.Interop;
|
||||
using WinUIEx;
|
||||
|
||||
// To learn more about WinUI, the WinUI project structure,
|
||||
@@ -15,6 +18,9 @@ namespace BetterLyrics.WinUI3.Views
|
||||
/// </summary>
|
||||
public sealed partial class OverlayWindow : Window
|
||||
{
|
||||
private readonly GlobalViewModel _globalViewModel =
|
||||
Ioc.Default.GetService<GlobalViewModel>()!;
|
||||
|
||||
public OverlayWindow()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
@@ -33,6 +39,8 @@ namespace BetterLyrics.WinUI3.Views
|
||||
// Hide from taskbar and alt-tab
|
||||
this.SetIsShownInSwitchers(false);
|
||||
|
||||
SystemBackdrop = SystemBackdropHelper.CreateSystemBackdrop(BackdropType.Transparent);
|
||||
|
||||
// Transparent window
|
||||
// SystemBackdrop = SystemBackdropHelper.CreateSystemBackdrop(BackdropType.DesktopAcrylic);
|
||||
|
||||
@@ -44,6 +52,27 @@ namespace BetterLyrics.WinUI3.Views
|
||||
|
||||
// Always on top
|
||||
// ((OverlappedPresenter)AppWindow.Presenter).IsAlwaysOnTop = true;
|
||||
|
||||
var hwnd = WindowNative.GetWindowHandle(this);
|
||||
|
||||
var windowWatcher = new ForegroundWindowWatcherHelper(
|
||||
hwnd,
|
||||
onWindowChanged =>
|
||||
{
|
||||
UpdateAccentColor(hwnd);
|
||||
}
|
||||
);
|
||||
|
||||
windowWatcher.Start();
|
||||
|
||||
UpdateAccentColor(hwnd);
|
||||
}
|
||||
|
||||
private void UpdateAccentColor(nint hwnd)
|
||||
{
|
||||
_globalViewModel.ActivatedWindowAccentColor = WindowColorHelper.GetDominantColorBelow(
|
||||
hwnd
|
||||
);
|
||||
}
|
||||
|
||||
public void Navigate(Type type)
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
|
||||
xmlns:local="using:BetterLyrics.WinUI3.Views"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:uc="using:BetterLyrics.WinUI3.Controls"
|
||||
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||
xmlns:vm="using:BetterLyrics.WinUI3.ViewModels"
|
||||
mc:Ignorable="d">
|
||||
@@ -165,7 +166,7 @@
|
||||
<controls:SettingsExpander.Items>
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageDynamicCoverOverlay" IsEnabled="{x:Bind AlbumArtRendererSettingsViewModel.IsCoverOverlayEnabled, Mode=OneWay}">
|
||||
<ToggleSwitch IsOn="{x:Bind AlbumArtRendererSettingsViewModel.IsDynamicCoverOverlay, Mode=TwoWay}" />
|
||||
<ToggleSwitch IsOn="{x:Bind AlbumArtRendererSettingsViewModel.IsDynamicCoverOverlayEnabled, Mode=TwoWay}" />
|
||||
</controls:SettingsCard>
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageCoverOverlayOpacity" IsEnabled="{x:Bind AlbumArtRendererSettingsViewModel.IsCoverOverlayEnabled, Mode=OneWay}">
|
||||
@@ -229,177 +230,28 @@
|
||||
</StackPanel>
|
||||
</controls:SettingsCard>
|
||||
|
||||
<TextBlock x:Uid="SettingsPageLyricsStyle" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
<!-- Lyrics style & effect -->
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageLyricsAlignment" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<ComboBox SelectedIndex="{x:Bind LyricsRendererSettingsViewModel.LyricsAlignmentType, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsLeft" />
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsCenter" />
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsRight" />
|
||||
</ComboBox>
|
||||
</controls:SettingsCard>
|
||||
<TextBlock x:Uid="SettingsPageLyrics" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
|
||||
<controls:SettingsExpander x:Uid="SettingsPageLyricsFontColor" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<interactivity:Interaction.Behaviors>
|
||||
<interactivity:DataTriggerBehavior
|
||||
Binding="{x:Bind LyricsRendererSettingsViewModel.LyricsFontColorType, Mode=OneWay, Converter={StaticResource EnumToIntConverter}}"
|
||||
ComparisonCondition="Equal"
|
||||
Value="0">
|
||||
<interactivity:ChangePropertyAction PropertyName="IsExpanded" Value="False" />
|
||||
</interactivity:DataTriggerBehavior>
|
||||
<interactivity:DataTriggerBehavior
|
||||
Binding="{x:Bind LyricsRendererSettingsViewModel.LyricsFontColorType, Mode=OneWay, Converter={StaticResource EnumToIntConverter}}"
|
||||
ComparisonCondition="Equal"
|
||||
Value="1">
|
||||
<interactivity:ChangePropertyAction PropertyName="IsExpanded" Value="True" />
|
||||
</interactivity:DataTriggerBehavior>
|
||||
</interactivity:Interaction.Behaviors>
|
||||
<ComboBox SelectedIndex="{x:Bind LyricsRendererSettingsViewModel.LyricsFontColorType, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}">
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsFontColorDefault" />
|
||||
<ComboBoxItem x:Uid="SettingsPageLyricsFontColorDominant" />
|
||||
</ComboBox>
|
||||
<controls:SettingsExpander.Items>
|
||||
<controls:SettingsCard HorizontalContentAlignment="Left" ContentAlignment="Vertical">
|
||||
<interactivity:Interaction.Behaviors>
|
||||
<interactivity:DataTriggerBehavior
|
||||
Binding="{x:Bind LyricsRendererSettingsViewModel.LyricsFontColorType, Mode=OneWay, Converter={StaticResource EnumToIntConverter}}"
|
||||
ComparisonCondition="Equal"
|
||||
Value="0">
|
||||
<interactivity:ChangePropertyAction PropertyName="Visibility" Value="Collapsed" />
|
||||
</interactivity:DataTriggerBehavior>
|
||||
<interactivity:DataTriggerBehavior
|
||||
Binding="{x:Bind LyricsRendererSettingsViewModel.LyricsFontColorType, Mode=OneWay, Converter={StaticResource EnumToIntConverter}}"
|
||||
ComparisonCondition="Equal"
|
||||
Value="1">
|
||||
<interactivity:ChangePropertyAction PropertyName="Visibility" Value="Visible" />
|
||||
</interactivity:DataTriggerBehavior>
|
||||
</interactivity:Interaction.Behaviors>
|
||||
<GridView ItemsSource="{x:Bind LyricsRendererSettingsViewModel.CoverImageDominantColors, Mode=OneWay}" SelectedIndex="{x:Bind LyricsRendererSettingsViewModel.LyricsFontSelectedAccentColorIndex, Mode=TwoWay}">
|
||||
<GridView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<GridViewItem>
|
||||
<StackPanel>
|
||||
<Border
|
||||
Width="64"
|
||||
Height="64"
|
||||
CornerRadius="4">
|
||||
<Border.Background>
|
||||
<SolidColorBrush Color="{Binding}" />
|
||||
</Border.Background>
|
||||
<Border.BackgroundTransition>
|
||||
<BrushTransition />
|
||||
</Border.BackgroundTransition>
|
||||
</Border>
|
||||
<TextBlock
|
||||
Margin="4,0,4,4"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding Converter={StaticResource ColorToDisplayNameConverter}}"
|
||||
TextWrapping="WrapWholeWords" />
|
||||
</StackPanel>
|
||||
</GridViewItem>
|
||||
</DataTemplate>
|
||||
</GridView.ItemTemplate>
|
||||
</GridView>
|
||||
</controls:SettingsCard>
|
||||
</controls:SettingsExpander.Items>
|
||||
</controls:SettingsExpander>
|
||||
<controls:Segmented
|
||||
x:Name="LyricsSegmentedControl"
|
||||
Margin="0,0,0,4"
|
||||
HorizontalAlignment="Stretch"
|
||||
SelectedIndex="0">
|
||||
<controls:SegmentedItem x:Uid="SettingsPageInAppLyrics" Tag="InApp" />
|
||||
<controls:SegmentedItem x:Uid="SettingsPageDesktopLyrics" Tag="Desktop" />
|
||||
</controls:Segmented>
|
||||
<controls:SwitchPresenter Value="{Binding SelectedItem.Tag, ElementName=LyricsSegmentedControl}">
|
||||
<controls:Case Value="InApp">
|
||||
<uc:LyricsSettingsControl ViewModel="{x:Bind InAppLyricsViewModel, Mode=OneWay}" />
|
||||
</controls:Case>
|
||||
<controls:Case Value="Desktop">
|
||||
<uc:LyricsSettingsControl ViewModel="{x:Bind DesktopLyricsViewModel, Mode=OneWay}" />
|
||||
</controls:Case>
|
||||
</controls:SwitchPresenter>
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageLyricsFontSize" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock x:Uid="SettingsPageSliderPrefix" VerticalAlignment="Center" />
|
||||
<TextBlock
|
||||
Margin="0,0,14,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Bind LyricsRendererSettingsViewModel.LyricsFontSize, Mode=OneWay}" />
|
||||
<Slider
|
||||
Maximum="96"
|
||||
Minimum="12"
|
||||
SnapsTo="Ticks"
|
||||
StepFrequency="2"
|
||||
TickFrequency="2"
|
||||
TickPlacement="Outside"
|
||||
Value="{x:Bind LyricsRendererSettingsViewModel.LyricsFontSize, Mode=TwoWay}" />
|
||||
</StackPanel>
|
||||
</controls:SettingsCard>
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageLyricsLineSpacingFactor" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock x:Uid="SettingsPageSliderPrefix" VerticalAlignment="Center" />
|
||||
<TextBlock VerticalAlignment="Center" Text="{x:Bind LyricsRendererSettingsViewModel.LyricsLineSpacingFactor, Mode=OneWay}" />
|
||||
<TextBlock
|
||||
x:Uid="SettingsPageLyricsLineSpacingFactorUnit"
|
||||
Margin="0,0,14,0"
|
||||
VerticalAlignment="Center" />
|
||||
<Slider
|
||||
Maximum="2"
|
||||
Minimum="0"
|
||||
SnapsTo="Ticks"
|
||||
StepFrequency="0.1"
|
||||
TickFrequency="0.1"
|
||||
TickPlacement="Outside"
|
||||
Value="{x:Bind LyricsRendererSettingsViewModel.LyricsLineSpacingFactor, Mode=TwoWay}" />
|
||||
</StackPanel>
|
||||
</controls:SettingsCard>
|
||||
|
||||
<TextBlock x:Uid="SettingsPageLyricsEffect" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageLyricsVerticalEdgeOpacity" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock x:Uid="SettingsPageSliderPrefix" VerticalAlignment="Center" />
|
||||
<TextBlock VerticalAlignment="Center" Text="{x:Bind LyricsRendererSettingsViewModel.LyricsVerticalEdgeOpacity, Mode=OneWay}" />
|
||||
<TextBlock
|
||||
Margin="0,0,14,0"
|
||||
VerticalAlignment="Center"
|
||||
Text=" %" />
|
||||
<Slider
|
||||
Maximum="100"
|
||||
Minimum="0"
|
||||
SnapsTo="Ticks"
|
||||
StepFrequency="1"
|
||||
TickFrequency="1"
|
||||
TickPlacement="Outside"
|
||||
Value="{x:Bind LyricsRendererSettingsViewModel.LyricsVerticalEdgeOpacity, Mode=TwoWay}" />
|
||||
</StackPanel>
|
||||
</controls:SettingsCard>
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageLyricsBlurAmount" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<controls:SettingsCard.Description>
|
||||
<StackPanel>
|
||||
<TextBlock x:Uid="SettingsPageLyricsBlurHighGPUUsage" Foreground="{ThemeResource SystemFillColorCautionBrush}" />
|
||||
<TextBlock x:Uid="SettingsPageLyricsBlurAmountSideEffect" />
|
||||
</StackPanel>
|
||||
</controls:SettingsCard.Description>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock x:Uid="SettingsPageSliderPrefix" VerticalAlignment="Center" />
|
||||
<TextBlock
|
||||
Margin="0,0,14,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Bind LyricsRendererSettingsViewModel.LyricsBlurAmount, Mode=OneWay}" />
|
||||
<Slider
|
||||
Maximum="10"
|
||||
Minimum="0"
|
||||
SnapsTo="Ticks"
|
||||
StepFrequency="1"
|
||||
TickFrequency="1"
|
||||
TickPlacement="Outside"
|
||||
Value="{x:Bind LyricsRendererSettingsViewModel.LyricsBlurAmount, Mode=TwoWay}" />
|
||||
</StackPanel>
|
||||
</controls:SettingsCard>
|
||||
|
||||
<controls:SettingsExpander
|
||||
x:Uid="SettingsPageLyricsGlowEffect"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
IsExpanded="True">
|
||||
<ToggleSwitch IsOn="{x:Bind LyricsRendererSettingsViewModel.IsLyricsGlowEffectEnabled, Mode=TwoWay}" />
|
||||
<controls:SettingsExpander.Items>
|
||||
|
||||
<controls:SettingsCard x:Uid="SettingsPageLyricsDynamicGlowEffect" IsEnabled="{x:Bind LyricsRendererSettingsViewModel.IsLyricsGlowEffectEnabled, Mode=OneWay}">
|
||||
<ToggleSwitch IsOn="{x:Bind LyricsRendererSettingsViewModel.IsLyricsDynamicGlowEffectEnabled, Mode=TwoWay}" />
|
||||
</controls:SettingsCard>
|
||||
|
||||
</controls:SettingsExpander.Items>
|
||||
</controls:SettingsExpander>
|
||||
<!-- About -->
|
||||
|
||||
<TextBlock x:Uid="SettingsPageAbout" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
|
||||
|
||||
@@ -18,8 +18,10 @@ namespace BetterLyrics.WinUI3.Views
|
||||
public SettingsViewModel ViewModel => (SettingsViewModel)DataContext;
|
||||
public AlbumArtOverlayViewModel AlbumArtRendererSettingsViewModel =>
|
||||
Ioc.Default.GetService<AlbumArtOverlayViewModel>()!;
|
||||
public InAppLyricsViewModel LyricsRendererSettingsViewModel =>
|
||||
public InAppLyricsViewModel InAppLyricsViewModel =>
|
||||
Ioc.Default.GetService<InAppLyricsViewModel>()!;
|
||||
public DesktopLyricsViewModel DesktopLyricsViewModel =>
|
||||
Ioc.Default.GetService<DesktopLyricsViewModel>()!;
|
||||
public GlobalViewModel GlobalSettingsViewModel =>
|
||||
Ioc.Default.GetService<GlobalViewModel>()!;
|
||||
public AlbumArtViewModel AlbumArtViewModel => Ioc.Default.GetService<AlbumArtViewModel>()!;
|
||||
|
||||
Reference in New Issue
Block a user