mirror of
https://github.com/jayfunc/BetterLyrics.git
synced 2026-01-12 10:54:55 +08:00
Compare commits
2 Commits
8b4748df1b
...
abca9ae5fb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
abca9ae5fb | ||
|
|
a062897e1a |
@@ -3,8 +3,6 @@
|
||||
x:Class="BetterLyrics.WinUI3.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:converter="using:BetterLyrics.WinUI3.Converter"
|
||||
xmlns:converters="using:CommunityToolkit.WinUI.Converters"
|
||||
xmlns:globalization="using:Windows.Globalization"
|
||||
xmlns:local="using:BetterLyrics.WinUI3"
|
||||
xmlns:media="using:CommunityToolkit.WinUI.Media">
|
||||
@@ -13,8 +11,14 @@
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<!-- Merged dictionaries here -->
|
||||
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
|
||||
|
||||
<ResourceDictionary Source="ms-appx:///CommunityToolkit.WinUI.Controls.Segmented/Segmented/Segmented.xaml" />
|
||||
<ResourceDictionary Source="ms-appx:///DevWinUI.Controls/Themes/Generic.xaml" />
|
||||
|
||||
<ResourceDictionary Source="/Styles/Converters.xaml" />
|
||||
<ResourceDictionary Source="/Styles/InteractiveListViewHeaderStyle.xaml" />
|
||||
<ResourceDictionary Source="/Styles/GhostSliderStyle.xaml" />
|
||||
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<!-- Theme -->
|
||||
@@ -42,48 +46,6 @@
|
||||
<ExponentialEase x:Key="EaseOut" EasingMode="EaseOut" />
|
||||
<ExponentialEase x:Key="EaseIn" EasingMode="EaseIn" />
|
||||
|
||||
<!-- Converter -->
|
||||
<converter:EnumToIntConverter x:Key="EnumToIntConverter" />
|
||||
<converter:ColorToBrushConverter x:Key="ColorToBrushConverter" />
|
||||
<converter:MatchedLocalFilesPathToVisibilityConverter x:Key="MatchedLocalFilesPathToVisibilityConverter" />
|
||||
<converter:IntToCornerRadius x:Key="IntToCornerRadius" />
|
||||
<converter:CornerRadiusToDoubleConverter x:Key="CornerRadiusToDoubleConverter" />
|
||||
<converter:LyricsSearchProviderToDisplayNameConverter x:Key="LyricsSearchProviderToDisplayNameConverter" />
|
||||
<converter:TranslationSearchProviderToDisplayNameConverter x:Key="TranslationSearchProviderToDisplayNameConverter" />
|
||||
<converter:TransliterationSearchProviderToDisplayNameConverter x:Key="TransliterationSearchProviderToDisplayNameConverter" />
|
||||
<converter:AlbumArtSearchProviderToDisplayNameConverter x:Key="AlbumArtSearchProviderToDisplayNameConverter" />
|
||||
<converter:SecondsToFormattedTimeConverter x:Key="SecondsToFormattedTimeConverter" />
|
||||
<converter:MillisecondsToFormattedTimeConverter x:Key="MillisecondsToFormattedTimeConverter" />
|
||||
<converter:FPSToTimeSpanConverter x:Key="FPSToTimeSpanConverter" />
|
||||
<converter:ShortcutToStringConverter x:Key="ShortcutToStringConverter" />
|
||||
<converter:BoolNegationToVisibilityConverter x:Key="BoolNegationToVisibilityConverter" />
|
||||
<converter:BoolToOpacityConverter x:Key="BoolToOpacityConverter" />
|
||||
<converter:BoolToPartialOpacityConverter x:Key="BoolToPartialOpacityConverter" />
|
||||
<converter:BoolNegationToOpacityConverter x:Key="BoolNegationToOpacityConverter" />
|
||||
<converter:RectToMarginConverter x:Key="RectToMarginConverter" />
|
||||
<converter:LanguageCodeToDisplayedNameConverter x:Key="LanguageCodeToDisplayedNameConverter" />
|
||||
<converter:ByteArrayToImageConverter x:Key="ByteArrayToImageConverter" />
|
||||
<converter:DisplayLanguageCodeToIndexConverter x:Key="DisplayLanguageCodeToIndexConverter" />
|
||||
<converter:PathToParentFolderConverter x:Key="PathToParentFolderConverter" />
|
||||
<converter:IntToBoolConverter x:Key="IntToBoolConverter" />
|
||||
<converter:IndexToDisplayConverter x:Key="IndexToDisplayConverter" />
|
||||
<converter:IntToDoubleConverter x:Key="IntToDoubleConverter" />
|
||||
<converter:MillisecondsToSecondsConverter x:Key="MillisecondsToSecondsConverter" />
|
||||
<converter:PictureInfosToImageSourceConverter x:Key="PictureInfosToImageSourceConverter" />
|
||||
<converter:LyricsFontWeightToFontWeightConverter x:Key="LyricsFontWeightToFontWeightConverter" />
|
||||
<converter:TextAlignmentTypeToHorizontalAlignmentConverter x:Key="TextAlignmentTypeToHorizontalAlignmentConverter" />
|
||||
<converter:LyricsLayoutOrientationToOrientationConverter x:Key="LyricsLayoutOrientationToOrientationConverter" />
|
||||
<converter:LyricsLayoutOrientationNegationToOrientationConverter x:Key="LyricsLayoutOrientationNegationToOrientationConverter" />
|
||||
<converter:FileSourceTypeToIconConverter x:Key="FileSourceTypeToIconConverter" />
|
||||
<converter:PathToImageConverter x:Key="PathToImageConverter" />
|
||||
<converter:DoubleToDecimalConverter x:Key="DoubleToDecimalConverter" />
|
||||
<converter:UriStringToDecodedAbsoluteUri x:Key="UriStringToDecodedAbsoluteUri" />
|
||||
|
||||
<converters:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
|
||||
<converters:BoolNegationConverter x:Key="BoolNegationConverter" />
|
||||
<converters:ColorToDisplayNameConverter x:Key="ColorToDisplayNameConverter" />
|
||||
<converters:CollectionVisibilityConverter x:Key="CollectionVisibilityConverter" />
|
||||
|
||||
<x:Double x:Key="SettingsCardSpacing">4</x:Double>
|
||||
|
||||
<!-- Style -->
|
||||
@@ -111,7 +73,7 @@
|
||||
</Style>
|
||||
<Style
|
||||
x:Key="TitleBarToggleButtonStyle"
|
||||
BasedOn="{StaticResource ToggleButtonRevealStyle}"
|
||||
BasedOn="{StaticResource DefaultToggleButtonStyle}"
|
||||
TargetType="ToggleButton">
|
||||
<Setter Property="VerticalAlignment" Value="Top" />
|
||||
<Setter Property="CornerRadius" Value="4" />
|
||||
@@ -119,7 +81,10 @@
|
||||
<Setter Property="Padding" Value="14,6,14,9" />
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
</Style>
|
||||
<Style x:Key="GhostToggleButtonStyle" TargetType="ToggleButton">
|
||||
<Style
|
||||
x:Key="GhostToggleButtonStyle"
|
||||
BasedOn="{StaticResource DefaultToggleButtonStyle}"
|
||||
TargetType="ToggleButton">
|
||||
<Setter Property="CornerRadius" Value="4" />
|
||||
<Setter Property="VerticalAlignment" Value="Stretch" />
|
||||
<Setter Property="BorderThickness" Value="0" />
|
||||
@@ -133,190 +98,6 @@
|
||||
<Setter Property="CornerRadius" Value="6" />
|
||||
</Style>
|
||||
|
||||
<Style x:Key="GhostSliderStyle" TargetType="Slider">
|
||||
<Setter Property="Background" Value="{ThemeResource ControlStrokeColorOnAccentDefaultBrush}" />
|
||||
<Setter Property="BorderThickness" Value="{ThemeResource SliderBorderThemeThickness}" />
|
||||
<Setter Property="Foreground" Value="{ThemeResource TextFillColorPrimaryBrush}" />
|
||||
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
|
||||
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
|
||||
<Setter Property="ManipulationMode" Value="None" />
|
||||
<Setter Property="UseSystemFocusVisuals" Value="{StaticResource UseSystemFocusVisuals}" />
|
||||
<Setter Property="FocusVisualMargin" Value="-7,0,-7,0" />
|
||||
<Setter Property="IsFocusEngagementEnabled" Value="True" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Slider">
|
||||
<Grid Margin="{TemplateBinding Padding}">
|
||||
<Grid.Resources>
|
||||
<Style x:Key="SliderThumbStyle" TargetType="Thumb">
|
||||
<Setter Property="BorderThickness" Value="0" />
|
||||
<Setter Property="Background" Value="{ThemeResource TextFillColorPrimaryBrush}" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Thumb">
|
||||
<Border
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
CornerRadius="0,1,1,0" />
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</Grid.Resources>
|
||||
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<ContentPresenter
|
||||
x:Name="HeaderContentPresenter"
|
||||
Grid.Row="0"
|
||||
Margin="{ThemeResource SliderTopHeaderMargin}"
|
||||
x:DeferLoadStrategy="Lazy"
|
||||
Content="{TemplateBinding Header}"
|
||||
ContentTemplate="{TemplateBinding HeaderTemplate}"
|
||||
FontWeight="{ThemeResource SliderHeaderThemeFontWeight}"
|
||||
Foreground="{ThemeResource SliderHeaderForeground}"
|
||||
TextWrapping="Wrap"
|
||||
Visibility="Collapsed" />
|
||||
<Grid
|
||||
x:Name="SliderContainer"
|
||||
Grid.Row="1"
|
||||
Background="{ThemeResource SliderContainerBackground}"
|
||||
Control.IsTemplateFocusTarget="True">
|
||||
<Grid x:Name="HorizontalTemplate" MinHeight="{ThemeResource SliderHorizontalHeight}">
|
||||
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="{ThemeResource SliderPreContentMargin}" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="{ThemeResource SliderPostContentMargin}" />
|
||||
</Grid.RowDefinitions>
|
||||
<Rectangle
|
||||
x:Name="HorizontalTrackRect"
|
||||
Grid.Row="1"
|
||||
Grid.ColumnSpan="3"
|
||||
Height="2"
|
||||
Fill="{TemplateBinding Background}" />
|
||||
<Rectangle
|
||||
x:Name="HorizontalDecreaseRect"
|
||||
Grid.Row="1"
|
||||
Fill="{TemplateBinding Foreground}" />
|
||||
<TickBar
|
||||
x:Name="TopTickBar"
|
||||
Grid.ColumnSpan="3"
|
||||
Height="{ThemeResource SliderOutsideTickBarThemeHeight}"
|
||||
Margin="0,0,0,4"
|
||||
VerticalAlignment="Bottom"
|
||||
Fill="{ThemeResource SliderTickBarFill}"
|
||||
Visibility="Collapsed" />
|
||||
<TickBar
|
||||
x:Name="HorizontalInlineTickBar"
|
||||
Grid.Row="1"
|
||||
Grid.ColumnSpan="3"
|
||||
Height="2"
|
||||
Fill="{ThemeResource SliderInlineTickBarFill}"
|
||||
Visibility="Collapsed" />
|
||||
<TickBar
|
||||
x:Name="BottomTickBar"
|
||||
Grid.Row="2"
|
||||
Grid.ColumnSpan="3"
|
||||
Height="{ThemeResource SliderOutsideTickBarThemeHeight}"
|
||||
Margin="0,4,0,0"
|
||||
VerticalAlignment="Top"
|
||||
Fill="{ThemeResource SliderTickBarFill}"
|
||||
Visibility="Collapsed" />
|
||||
<Thumb
|
||||
x:Name="HorizontalThumb"
|
||||
Grid.Row="0"
|
||||
Grid.RowSpan="3"
|
||||
Grid.Column="1"
|
||||
Width="2"
|
||||
Height="2"
|
||||
AutomationProperties.AccessibilityView="Raw"
|
||||
DataContext="{TemplateBinding Value}"
|
||||
FocusVisualMargin="-14,-6,-14,-6"
|
||||
Style="{StaticResource SliderThumbStyle}" />
|
||||
</Grid>
|
||||
<Grid
|
||||
x:Name="VerticalTemplate"
|
||||
MinWidth="{ThemeResource SliderVerticalWidth}"
|
||||
Visibility="Collapsed">
|
||||
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="{ThemeResource SliderPreContentMargin}" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="{ThemeResource SliderPostContentMargin}" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Rectangle
|
||||
x:Name="VerticalTrackRect"
|
||||
Grid.RowSpan="3"
|
||||
Grid.Column="1"
|
||||
Width="{ThemeResource SliderTrackThemeHeight}"
|
||||
Fill="{TemplateBinding Background}" />
|
||||
<Rectangle
|
||||
x:Name="VerticalDecreaseRect"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Fill="{TemplateBinding Foreground}" />
|
||||
<TickBar
|
||||
x:Name="LeftTickBar"
|
||||
Grid.RowSpan="3"
|
||||
Width="{ThemeResource SliderOutsideTickBarThemeHeight}"
|
||||
Margin="0,0,4,0"
|
||||
HorizontalAlignment="Right"
|
||||
Fill="{ThemeResource SliderTickBarFill}"
|
||||
Visibility="Collapsed" />
|
||||
<TickBar
|
||||
x:Name="VerticalInlineTickBar"
|
||||
Grid.RowSpan="3"
|
||||
Grid.Column="1"
|
||||
Width="{ThemeResource SliderTrackThemeHeight}"
|
||||
Fill="{ThemeResource SliderInlineTickBarFill}"
|
||||
Visibility="Collapsed" />
|
||||
<TickBar
|
||||
x:Name="RightTickBar"
|
||||
Grid.RowSpan="3"
|
||||
Grid.Column="2"
|
||||
Width="{ThemeResource SliderOutsideTickBarThemeHeight}"
|
||||
Margin="4,0,0,0"
|
||||
HorizontalAlignment="Left"
|
||||
Fill="{ThemeResource SliderTickBarFill}"
|
||||
Visibility="Collapsed" />
|
||||
<Thumb
|
||||
x:Name="VerticalThumb"
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="3"
|
||||
Width="24"
|
||||
Height="8"
|
||||
AutomationProperties.AccessibilityView="Raw"
|
||||
DataContext="{TemplateBinding Value}"
|
||||
FocusVisualMargin="-6,-14,-6,-14"
|
||||
Style="{StaticResource SliderThumbStyle}" />
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style
|
||||
x:Key="ListViewStretchedItemContainerStyle"
|
||||
BasedOn="{StaticResource DefaultListViewItemStyle}"
|
||||
@@ -360,10 +141,6 @@
|
||||
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Hidden" />
|
||||
</Style>
|
||||
|
||||
<StaticResource x:Key="ToggleButtonBackgroundChecked" ResourceKey="TextFillColorPrimaryBrush" />
|
||||
<StaticResource x:Key="ToggleButtonBackgroundCheckedPointerOver" ResourceKey="TextFillColorPrimaryBrush" />
|
||||
<StaticResource x:Key="ToggleButtonBackgroundCheckedPressed" ResourceKey="TextFillColorPrimaryBrush" />
|
||||
|
||||
<!-- Dimensions -->
|
||||
|
||||
<!-- Fonts -->
|
||||
|
||||
@@ -4,12 +4,13 @@ using BetterLyrics.WinUI3.Models.Db;
|
||||
using BetterLyrics.WinUI3.Services.AlbumArtSearchService;
|
||||
using BetterLyrics.WinUI3.Services.DiscordService;
|
||||
using BetterLyrics.WinUI3.Services.FileSystemService;
|
||||
using BetterLyrics.WinUI3.Services.GSMTCService;
|
||||
using BetterLyrics.WinUI3.Services.LastFMService;
|
||||
using BetterLyrics.WinUI3.Services.LocalizationService;
|
||||
using BetterLyrics.WinUI3.Services.LyricsSearchService;
|
||||
using BetterLyrics.WinUI3.Services.MediaSessionsService;
|
||||
using BetterLyrics.WinUI3.Services.PlayHistoryService;
|
||||
using BetterLyrics.WinUI3.Services.SettingsService;
|
||||
using BetterLyrics.WinUI3.Services.SMTCService;
|
||||
using BetterLyrics.WinUI3.Services.TranslationService;
|
||||
using BetterLyrics.WinUI3.Services.TransliterationService;
|
||||
using BetterLyrics.WinUI3.ViewModels;
|
||||
@@ -19,7 +20,6 @@ using Microsoft.Data.Sqlite;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.UI.Dispatching; // 关键:用于线程调度
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.Windows.AppLifecycle; // 关键:App生命周期管理
|
||||
using Serilog;
|
||||
@@ -278,7 +278,8 @@ namespace BetterLyrics.WinUI3
|
||||
|
||||
// Services
|
||||
.AddSingleton<ISettingsService, SettingsService>()
|
||||
.AddSingleton<IMediaSessionsService, MediaSessionsService>()
|
||||
.AddSingleton<ISMTCService, SMTCService>()
|
||||
.AddSingleton<IGSMTCService, GSMTCService>()
|
||||
.AddSingleton<IAlbumArtSearchService, AlbumArtSearchService>()
|
||||
.AddSingleton<ILyricsSearchService, LyricsSearchService>()
|
||||
.AddSingleton<ITranslationService, TranslationService>()
|
||||
@@ -304,6 +305,7 @@ namespace BetterLyrics.WinUI3
|
||||
.AddSingleton<AboutControlViewModel>()
|
||||
.AddSingleton<MusicGalleryWindowViewModel>()
|
||||
.AddSingleton<StatsDashboardControlViewModel>()
|
||||
.AddSingleton<PlayQueueViewModel>()
|
||||
|
||||
.AddTransient<NowPlayingWindowViewModel>()
|
||||
.AddTransient<NowPlayingPageViewModel>()
|
||||
|
||||
@@ -43,12 +43,15 @@
|
||||
<None Remove="Controls\MediaSettingsControl.xaml" />
|
||||
<None Remove="Controls\NowPlayingBar.xaml" />
|
||||
<None Remove="Controls\PlaybackSettingsControl.xaml" />
|
||||
<None Remove="Controls\PlayQueue.xaml" />
|
||||
<None Remove="Controls\PropertyRow.xaml" />
|
||||
<None Remove="Controls\RemoteServerConfigControl.xaml" />
|
||||
<None Remove="Controls\ShortcutTextBox.xaml" />
|
||||
<None Remove="Controls\StatsDashboardControl.xaml" />
|
||||
<None Remove="Controls\SystemTray.xaml" />
|
||||
<None Remove="Controls\WindowSettingsControl.xaml" />
|
||||
<None Remove="Styles\GhostSliderStyle.xaml" />
|
||||
<None Remove="Styles\InteractiveListViewHeaderStyle.xaml" />
|
||||
<None Remove="Views\LyricsSearchWindow.xaml" />
|
||||
<None Remove="Views\LyricsWindowSwitchWindow.xaml" />
|
||||
<None Remove="Views\MusicGalleryPage.xaml" />
|
||||
@@ -259,6 +262,21 @@
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Styles\GhostSliderStyle.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Styles\Converters.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\PlayQueue.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\StatsDashboardControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
@@ -409,6 +427,11 @@
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Styles\InteractiveListViewHeaderStyle.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<!-- Publish Properties -->
|
||||
<PropertyGroup>
|
||||
<PublishReadyToRun Condition="'$(Configuration)' == 'Debug'">False</PublishReadyToRun>
|
||||
|
||||
@@ -8,7 +8,7 @@ using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.Models.Settings;
|
||||
using BetterLyrics.WinUI3.Renderer;
|
||||
using BetterLyrics.WinUI3.Services.LastFMService;
|
||||
using BetterLyrics.WinUI3.Services.MediaSessionsService;
|
||||
using BetterLyrics.WinUI3.Services.GSMTCService;
|
||||
using BetterLyrics.WinUI3.Services.SettingsService;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
@@ -41,7 +41,7 @@ namespace BetterLyrics.WinUI3.Controls
|
||||
IRecipient<PropertyChangedMessage<IRandomAccessStream?>>
|
||||
{
|
||||
private readonly ISettingsService _settingsService = Ioc.Default.GetRequiredService<ISettingsService>();
|
||||
private readonly IMediaSessionsService _mediaSessionsService = Ioc.Default.GetRequiredService<IMediaSessionsService>();
|
||||
private readonly IGSMTCService _gsmtcService = Ioc.Default.GetRequiredService<IGSMTCService>();
|
||||
|
||||
private readonly LyricsRenderer _lyricsRenderer = new();
|
||||
private readonly FluidBackgroundRenderer _fluidRenderer = new();
|
||||
@@ -98,8 +98,6 @@ namespace BetterLyrics.WinUI3.Controls
|
||||
|
||||
private TimeSpan _songPositionWithOffset;
|
||||
private TimeSpan _songPosition; // <20><>ǰ<EFBFBD><C7B0><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1>
|
||||
private TimeSpan _totalPlayedTime; // <20><>ǰ<EFBFBD><C7B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ػ<EFBFBD><D8BB>ظ<EFBFBD><D8B8><EFBFBD><EFBFBD>ŵ<EFBFBD>ʱ<EFBFBD>䣩
|
||||
private bool _isLastFMTracked = false;
|
||||
|
||||
private double _renderLyricsStartX = 0;
|
||||
private double _renderLyricsStartY = 0;
|
||||
@@ -345,7 +343,7 @@ namespace BetterLyrics.WinUI3.Controls
|
||||
var lyricsStyle = _lyricsWindowStatus.LyricsStyleSettings;
|
||||
var lyricsEffect = _lyricsWindowStatus.LyricsEffectSettings;
|
||||
|
||||
double songDuration = _mediaSessionsService.CurrentSongInfo?.DurationMs ?? 0;
|
||||
double songDuration = _gsmtcService.CurrentSongInfo?.DurationMs ?? 0;
|
||||
bool isForceWordByWord = _settingsService.AppSettings.GeneralSettings.IsForceWordByWordEffect;
|
||||
|
||||
Color overlayColor;
|
||||
@@ -459,7 +457,7 @@ namespace BetterLyrics.WinUI3.Controls
|
||||
var lyricsBg = _lyricsWindowStatus.LyricsBackgroundSettings;
|
||||
var lyricsStyle = _lyricsWindowStatus.LyricsStyleSettings;
|
||||
var lyricsEffect = _lyricsWindowStatus.LyricsEffectSettings;
|
||||
var lyricsData = _mediaSessionsService.CurrentLyricsData;
|
||||
var lyricsData = _gsmtcService.CurrentLyricsData;
|
||||
|
||||
TimeSpan elapsedTime = args.Timing.ElapsedTime;
|
||||
|
||||
@@ -654,25 +652,22 @@ namespace BetterLyrics.WinUI3.Controls
|
||||
|
||||
private void UpdatePlaybackState(TimeSpan elapsedTime)
|
||||
{
|
||||
if (_mediaSessionsService.CurrentIsPlaying)
|
||||
if (_gsmtcService.CurrentIsPlaying)
|
||||
{
|
||||
_songPosition += elapsedTime;
|
||||
_totalPlayedTime += elapsedTime;
|
||||
_songPositionWithOffset = _songPosition + TimeSpan.FromMilliseconds(_mediaSessionsService.CurrentMediaSourceProviderInfo?.PositionOffset ?? 0);
|
||||
_songPositionWithOffset = _songPosition + TimeSpan.FromMilliseconds(_gsmtcService.CurrentMediaSourceProviderInfo?.PositionOffset ?? 0);
|
||||
}
|
||||
}
|
||||
|
||||
private void ResetPlaybackState()
|
||||
{
|
||||
_songPosition = TimeSpan.Zero;
|
||||
_totalPlayedTime = TimeSpan.Zero;
|
||||
_isLastFMTracked = false;
|
||||
}
|
||||
|
||||
private void UpdateRenderLyricsLines()
|
||||
{
|
||||
_renderLyricsLines = null;
|
||||
_renderLyricsLines = _mediaSessionsService.CurrentLyricsData?.LyricsLines.Select(x => new RenderLyricsLine()
|
||||
_renderLyricsLines = _gsmtcService.CurrentLyricsData?.LyricsLines.Select(x => new RenderLyricsLine()
|
||||
{
|
||||
LyricsSyllables = x.LyricsSyllables,
|
||||
StartMs = x.StartMs,
|
||||
@@ -685,7 +680,7 @@ namespace BetterLyrics.WinUI3.Controls
|
||||
|
||||
private async Task ReloadCoverBackgroundResourcesAsync()
|
||||
{
|
||||
if (_mediaSessionsService.AlbumArtBitmapStream is IRandomAccessStream stream)
|
||||
if (_gsmtcService.AlbumArtBitmapStream is IRandomAccessStream stream)
|
||||
{
|
||||
stream.Seek(0);
|
||||
CanvasBitmap bitmap = await CanvasBitmap.LoadAsync(Canvas, stream);
|
||||
@@ -695,26 +690,19 @@ namespace BetterLyrics.WinUI3.Controls
|
||||
|
||||
public void Receive(PropertyChangedMessage<TimeSpan> message)
|
||||
{
|
||||
if (message.Sender is IMediaSessionsService)
|
||||
if (message.Sender is IGSMTCService)
|
||||
{
|
||||
if (message.PropertyName == nameof(IMediaSessionsService.CurrentPosition))
|
||||
if (message.PropertyName == nameof(IGSMTCService.CurrentPosition))
|
||||
{
|
||||
var realPosition = message.NewValue;
|
||||
|
||||
var diff = Math.Abs(_songPosition.TotalMilliseconds - realPosition.TotalMilliseconds);
|
||||
var timelineSyncThreshold = _mediaSessionsService.CurrentMediaSourceProviderInfo?.TimelineSyncThreshold ?? 0;
|
||||
var timelineSyncThreshold = _gsmtcService.CurrentMediaSourceProviderInfo?.TimelineSyncThreshold ?? 0;
|
||||
|
||||
// ƫ<><C6AB> or seek
|
||||
if (diff >= timelineSyncThreshold)
|
||||
{
|
||||
_songPosition = realPosition;
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˿<EFBFBD>ͷ<EFBFBD><CDB7><EFBFBD><EFBFBD><EFBFBD><EFBFBD> LastFM ͳ<><CDB3>״̬
|
||||
if (_songPosition.TotalSeconds <= 1)
|
||||
{
|
||||
_totalPlayedTime = TimeSpan.Zero;
|
||||
_isLastFMTracked = false;
|
||||
}
|
||||
}
|
||||
|
||||
// <20>϶<EFBFBD><CFB6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȴ<EFBFBD><C8B4><EFBFBD><EFBFBD><EFBFBD>
|
||||
@@ -728,9 +716,9 @@ namespace BetterLyrics.WinUI3.Controls
|
||||
|
||||
public void Receive(PropertyChangedMessage<LyricsData?> message)
|
||||
{
|
||||
if (message.Sender is IMediaSessionsService)
|
||||
if (message.Sender is IGSMTCService)
|
||||
{
|
||||
if (message.PropertyName == nameof(IMediaSessionsService.CurrentLyricsData))
|
||||
if (message.PropertyName == nameof(IGSMTCService.CurrentLyricsData))
|
||||
{
|
||||
UpdateRenderLyricsLines();
|
||||
_isLayoutChanged = true;
|
||||
@@ -740,9 +728,9 @@ namespace BetterLyrics.WinUI3.Controls
|
||||
|
||||
public void Receive(PropertyChangedMessage<SongInfo?> message)
|
||||
{
|
||||
if (message.Sender is IMediaSessionsService)
|
||||
if (message.Sender is IGSMTCService)
|
||||
{
|
||||
if (message.PropertyName == nameof(IMediaSessionsService.CurrentSongInfo))
|
||||
if (message.PropertyName == nameof(IGSMTCService.CurrentSongInfo))
|
||||
{
|
||||
ResetPlaybackState();
|
||||
}
|
||||
@@ -895,9 +883,9 @@ namespace BetterLyrics.WinUI3.Controls
|
||||
|
||||
public void Receive(PropertyChangedMessage<IRandomAccessStream?> message)
|
||||
{
|
||||
if (message.Sender is IMediaSessionsService)
|
||||
if (message.Sender is IGSMTCService)
|
||||
{
|
||||
if (message.PropertyName == nameof(IMediaSessionsService.AlbumArtBitmapStream))
|
||||
if (message.PropertyName == nameof(IGSMTCService.AlbumArtBitmapStream))
|
||||
{
|
||||
_ = ReloadCoverBackgroundResourcesAsync();
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:dev="using:DevWinUI"
|
||||
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
|
||||
xmlns:local="using:BetterLyrics.WinUI3.Controls"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
@@ -176,13 +177,13 @@
|
||||
Style="{StaticResource GhostButtonStyle}">
|
||||
<interactivity:Interaction.Behaviors>
|
||||
<interactivity:DataTriggerBehavior
|
||||
Binding="{x:Bind ViewModel.MediaSessionsService.CurrentIsPlaying, Mode=OneWay}"
|
||||
Binding="{x:Bind ViewModel.GSMTCService.CurrentIsPlaying, Mode=OneWay}"
|
||||
ComparisonCondition="Equal"
|
||||
Value="True">
|
||||
<interactivity:ChangePropertyAction PropertyName="Visibility" Value="Visible" />
|
||||
</interactivity:DataTriggerBehavior>
|
||||
<interactivity:DataTriggerBehavior
|
||||
Binding="{x:Bind ViewModel.MediaSessionsService.CurrentIsPlaying, Mode=OneWay}"
|
||||
Binding="{x:Bind ViewModel.GSMTCService.CurrentIsPlaying, Mode=OneWay}"
|
||||
ComparisonCondition="Equal"
|
||||
Value="False">
|
||||
<interactivity:ChangePropertyAction PropertyName="Visibility" Value="Collapsed" />
|
||||
@@ -196,13 +197,13 @@
|
||||
Style="{StaticResource GhostButtonStyle}">
|
||||
<interactivity:Interaction.Behaviors>
|
||||
<interactivity:DataTriggerBehavior
|
||||
Binding="{x:Bind ViewModel.MediaSessionsService.CurrentIsPlaying, Mode=OneWay}"
|
||||
Binding="{x:Bind ViewModel.GSMTCService.CurrentIsPlaying, Mode=OneWay}"
|
||||
ComparisonCondition="Equal"
|
||||
Value="True">
|
||||
<interactivity:ChangePropertyAction PropertyName="Visibility" Value="Collapsed" />
|
||||
</interactivity:DataTriggerBehavior>
|
||||
<interactivity:DataTriggerBehavior
|
||||
Binding="{x:Bind ViewModel.MediaSessionsService.CurrentIsPlaying, Mode=OneWay}"
|
||||
Binding="{x:Bind ViewModel.GSMTCService.CurrentIsPlaying, Mode=OneWay}"
|
||||
ComparisonCondition="Equal"
|
||||
Value="False">
|
||||
<interactivity:ChangePropertyAction PropertyName="Visibility" Value="Visible" />
|
||||
@@ -215,12 +216,16 @@
|
||||
Glyph=}"
|
||||
Style="{StaticResource GhostButtonStyle}" />
|
||||
<!-- 播放队列按钮 -->
|
||||
<ToggleButton
|
||||
<Button
|
||||
Click="PlayingQueueButton_Click"
|
||||
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}"
|
||||
Style="{StaticResource GhostToggleButtonStyle}"
|
||||
Visibility="{x:Bind ShowPlayingQueueButton, Converter={StaticResource BoolToVisibilityConverter}, Mode=OneWay}" />
|
||||
Style="{StaticResource GhostButtonStyle}"
|
||||
Visibility="{x:Bind ShowPlayingQueueButton, Converter={StaticResource BoolToVisibilityConverter}, Mode=OneWay}">
|
||||
<ToolTipService.ToolTip>
|
||||
<TextBlock x:Uid="MusicGalleryPagePlayingQueue" />
|
||||
</ToolTipService.ToolTip>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
@@ -231,6 +236,19 @@
|
||||
Orientation="Horizontal"
|
||||
Spacing="3">
|
||||
|
||||
<!-- Stop media session -->
|
||||
<Button
|
||||
Command="{x:Bind ViewModel.StopTrackCommand}"
|
||||
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
FontSize=16,
|
||||
Glyph=}"
|
||||
Style="{StaticResource GhostButtonStyle}"
|
||||
Visibility="{x:Bind ShowStopButton, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
<ToolTipService.ToolTip>
|
||||
<TextBlock x:Uid="MusicGalleryPageStopTrack" />
|
||||
</ToolTipService.ToolTip>
|
||||
</Button>
|
||||
|
||||
<!-- Volume -->
|
||||
<Button Click="VolumeButton_Click" Style="{StaticResource GhostButtonStyle}">
|
||||
<Grid>
|
||||
@@ -402,7 +420,7 @@
|
||||
Margin="0,-14,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Top"
|
||||
Maximum="{x:Bind ViewModel.MediaSessionsService.CurrentSongInfo.DurationMs, Mode=OneWay, Converter={StaticResource MillisecondsToSecondsConverter}}"
|
||||
Maximum="{x:Bind ViewModel.GSMTCService.CurrentSongInfo.DurationMs, Mode=OneWay, Converter={StaticResource MillisecondsToSecondsConverter}}"
|
||||
Minimum="0"
|
||||
Style="{StaticResource GhostSliderStyle}"
|
||||
ThumbToolTipValueConverter="{StaticResource SecondsToFormattedTimeConverter}" />
|
||||
|
||||
@@ -2,7 +2,7 @@ using BetterLyrics.WinUI3.Enums;
|
||||
using BetterLyrics.WinUI3.Hooks;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.Models.Settings;
|
||||
using BetterLyrics.WinUI3.Services.MediaSessionsService;
|
||||
using BetterLyrics.WinUI3.Services.GSMTCService;
|
||||
using BetterLyrics.WinUI3.ViewModels;
|
||||
using BetterLyrics.WinUI3.Views;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
@@ -30,6 +30,7 @@ public sealed partial class NowPlayingBar : UserControl,
|
||||
|
||||
public event EventHandler? SongInfoTapped;
|
||||
public event EventHandler? TimeTapped;
|
||||
public event EventHandler? PlayQueueButtonClick;
|
||||
|
||||
public bool ShowTime
|
||||
{
|
||||
@@ -64,6 +65,15 @@ public sealed partial class NowPlayingBar : UserControl,
|
||||
set { SetValue(ShowPlaybackOrderButtonProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ShowStopButtonProperty =
|
||||
DependencyProperty.Register(nameof(ShowStopButton), typeof(bool), typeof(NowPlayingBar), new PropertyMetadata(false));
|
||||
|
||||
public bool ShowStopButton
|
||||
{
|
||||
get { return (bool)GetValue(ShowStopButtonProperty); }
|
||||
set { SetValue(ShowStopButtonProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ShowPlaybackOrderButtonProperty =
|
||||
DependencyProperty.Register(nameof(ShowPlaybackOrderButton), typeof(bool), typeof(NowPlayingBar), new PropertyMetadata(false));
|
||||
|
||||
@@ -76,15 +86,6 @@ public sealed partial class NowPlayingBar : UserControl,
|
||||
public static readonly DependencyProperty PlaybackOrderProperty =
|
||||
DependencyProperty.Register(nameof(PlaybackOrder), typeof(PlaybackOrder), typeof(NowPlayingBar), new PropertyMetadata(PlaybackOrder.RepeatAll));
|
||||
|
||||
public bool IsPlayingQueueOpened
|
||||
{
|
||||
get { return (bool)GetValue(IsPlayingQueueOpenedProperty); }
|
||||
set { SetValue(IsPlayingQueueOpenedProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsPlayingQueueOpenedProperty =
|
||||
DependencyProperty.Register(nameof(IsPlayingQueueOpened), typeof(bool), typeof(NowPlayingBar), new PropertyMetadata(false));
|
||||
|
||||
public bool IsCompactMode
|
||||
{
|
||||
get { return (bool)GetValue(IsCompactModeProperty); }
|
||||
@@ -206,7 +207,7 @@ public sealed partial class NowPlayingBar : UserControl,
|
||||
var grid = (Grid)sender;
|
||||
var pos = e.GetCurrentPoint(grid).Position;
|
||||
var ratio = pos.X / grid.ActualWidth;
|
||||
ViewModel.MediaSessionsService.ChangePosition(TimelineSlider.Maximum * ratio);
|
||||
ViewModel.GSMTCService.ChangePosition(TimelineSlider.Maximum * ratio);
|
||||
}
|
||||
|
||||
private void TimelineSliderOverlay_PointerMoved(object sender, Microsoft.UI.Xaml.Input.PointerRoutedEventArgs e)
|
||||
@@ -303,7 +304,7 @@ public sealed partial class NowPlayingBar : UserControl,
|
||||
|
||||
private void PlayingQueueButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
IsPlayingQueueOpened = !IsPlayingQueueOpened;
|
||||
PlayQueueButtonClick?.Invoke(sender, EventArgs.Empty);
|
||||
}
|
||||
|
||||
private void PlaybackOrderButton_Click(object sender, RoutedEventArgs e)
|
||||
@@ -313,9 +314,9 @@ public sealed partial class NowPlayingBar : UserControl,
|
||||
|
||||
public void Receive(PropertyChangedMessage<SongInfo?> message)
|
||||
{
|
||||
if (message.Sender is IMediaSessionsService)
|
||||
if (message.Sender is IGSMTCService)
|
||||
{
|
||||
if (message.PropertyName == nameof(IMediaSessionsService.CurrentSongInfo))
|
||||
if (message.PropertyName == nameof(IGSMTCService.CurrentSongInfo))
|
||||
{
|
||||
TitleTextBlock.Text = message.NewValue?.Title;
|
||||
ArtistsTextBlock.Text = message.NewValue?.DisplayArtists;
|
||||
@@ -324,9 +325,9 @@ public sealed partial class NowPlayingBar : UserControl,
|
||||
}
|
||||
public void Receive(PropertyChangedMessage<BitmapImage?> message)
|
||||
{
|
||||
if (message.Sender is IMediaSessionsService)
|
||||
if (message.Sender is IGSMTCService)
|
||||
{
|
||||
if (message.PropertyName == nameof(IMediaSessionsService.AlbumArtBitmapImage))
|
||||
if (message.PropertyName == nameof(IGSMTCService.AlbumArtBitmapImage))
|
||||
{
|
||||
AlbumArtImageSwitcher.Source = message.NewValue;
|
||||
}
|
||||
@@ -335,9 +336,9 @@ public sealed partial class NowPlayingBar : UserControl,
|
||||
|
||||
public void Receive(PropertyChangedMessage<TimeSpan> message)
|
||||
{
|
||||
if (message.Sender is IMediaSessionsService)
|
||||
if (message.Sender is IGSMTCService)
|
||||
{
|
||||
if (message.PropertyName == nameof(IMediaSessionsService.CurrentPosition))
|
||||
if (message.PropertyName == nameof(IGSMTCService.CurrentPosition))
|
||||
{
|
||||
TimelineSlider.Value = message.NewValue.TotalSeconds;
|
||||
}
|
||||
|
||||
142
BetterLyrics.WinUI3/BetterLyrics.WinUI3/Controls/PlayQueue.xaml
Normal file
142
BetterLyrics.WinUI3/BetterLyrics.WinUI3/Controls/PlayQueue.xaml
Normal file
@@ -0,0 +1,142 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<UserControl
|
||||
x:Class="BetterLyrics.WinUI3.Controls.PlayQueue"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
|
||||
xmlns:local="using:BetterLyrics.WinUI3.Controls"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid>
|
||||
<Grid.TranslationTransition>
|
||||
<Vector3Transition />
|
||||
</Grid.TranslationTransition>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid Grid.Row="0" Margin="12,12,12,0">
|
||||
<TextBlock
|
||||
x:Uid="MusicGalleryPagePlayingQueue"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource BodyStrongTextBlockStyle}" />
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Row="1" Margin="12,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<StackPanel
|
||||
Grid.Column="0"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Center"
|
||||
Orientation="Horizontal">
|
||||
<TextBlock Foreground="{ThemeResource TextFillColorSecondaryBrush}" Text="{x:Bind ViewModel.AppSettings.MusicGallerySettings.PlayQueueIndex, Mode=OneWay, Converter={StaticResource IndexToDisplayConverter}}" />
|
||||
<TextBlock Foreground="{ThemeResource TextFillColorSecondaryBrush}" Text="/" />
|
||||
<TextBlock Text="{x:Bind ViewModel.SMTCService.TrackPlayingQueue.Count, Mode=OneWay}" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Scroll to playing item -->
|
||||
<Button
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Right"
|
||||
Click="ScrollToPlayingItemButton_Click"
|
||||
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
FontSize=16,
|
||||
Glyph=}"
|
||||
Style="{StaticResource GhostButtonStyle}">
|
||||
<ToolTipService.ToolTip>
|
||||
<TextBlock x:Uid="MusicGalleryPageScrollToPlayingItem" />
|
||||
</ToolTipService.ToolTip>
|
||||
</Button>
|
||||
<!-- Empty play queue -->
|
||||
<Button
|
||||
Grid.Column="2"
|
||||
HorizontalAlignment="Right"
|
||||
Click="EmptyPlayingQueueButton_Click"
|
||||
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
FontSize=16,
|
||||
Glyph=}"
|
||||
Style="{StaticResource GhostButtonStyle}">
|
||||
<ToolTipService.ToolTip>
|
||||
<TextBlock x:Uid="MusicGalleryPageEmptyPlayingQueue" />
|
||||
</ToolTipService.ToolTip>
|
||||
</Button>
|
||||
|
||||
</Grid>
|
||||
|
||||
<NavigationViewItemSeparator Grid.Row="2" />
|
||||
|
||||
<ListView
|
||||
x:Name="PlayingQueueListView"
|
||||
Grid.Row="3"
|
||||
ItemsSource="{x:Bind ViewModel.SMTCService.TrackPlayingQueue, Mode=OneWay}"
|
||||
SelectedIndex="{x:Bind ViewModel.AppSettings.MusicGallerySettings.PlayQueueIndex, Mode=TwoWay}">
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid Padding="0,6">
|
||||
<Grid Tapped="PlayingQueueListVireItemGrid_Tapped">
|
||||
<StackPanel Margin="0,0,36,0">
|
||||
<TextBlock Text="{Binding Track.Title}" TextWrapping="Wrap" />
|
||||
<TextBlock
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
Text="{Binding Track.Artist}"
|
||||
TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<Grid HorizontalAlignment="Right">
|
||||
<Button
|
||||
VerticalAlignment="Center"
|
||||
Click="RemoveFromPlayingQueueButton_Click"
|
||||
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
FontSize=16,
|
||||
Glyph=}"
|
||||
Style="{StaticResource GhostButtonStyle}">
|
||||
<ToolTipService.ToolTip>
|
||||
<TextBlock x:Uid="MusicGalleryPageRemoveFromPlayingQueue" />
|
||||
</ToolTipService.ToolTip>
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
|
||||
<Grid Grid.Row="3">
|
||||
<interactivity:Interaction.Behaviors>
|
||||
<interactivity:DataTriggerBehavior
|
||||
Binding="{x:Bind ViewModel.SMTCService.TrackPlayingQueue.Count, Mode=OneWay}"
|
||||
ComparisonCondition="Equal"
|
||||
Value="0">
|
||||
<interactivity:ChangePropertyAction PropertyName="Visibility" Value="Visible" />
|
||||
</interactivity:DataTriggerBehavior>
|
||||
<interactivity:DataTriggerBehavior
|
||||
Binding="{x:Bind ViewModel.SMTCService.TrackPlayingQueue.Count, Mode=OneWay}"
|
||||
ComparisonCondition="NotEqual"
|
||||
Value="0">
|
||||
<interactivity:ChangePropertyAction PropertyName="Visibility" Value="Collapsed" />
|
||||
</interactivity:DataTriggerBehavior>
|
||||
</interactivity:Interaction.Behaviors>
|
||||
<StackPanel
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Spacing="12">
|
||||
<Image MaxWidth="100" Source="/Assets/EmptyBox.png" />
|
||||
<TextBlock
|
||||
x:Uid="MusicGalleryPagePlayingQueueEmpty"
|
||||
HorizontalAlignment="Center"
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
</UserControl>
|
||||
@@ -0,0 +1,103 @@
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.Models.Settings;
|
||||
using BetterLyrics.WinUI3.ViewModels;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using CommunityToolkit.Mvvm.Messaging.Messages;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Controls.Primitives;
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
using Microsoft.UI.Xaml.Input;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
using Windows.Foundation;
|
||||
using Windows.Foundation.Collections;
|
||||
|
||||
// To learn more about WinUI, the WinUI project structure,
|
||||
// and more about our project templates, see: http://aka.ms/winui-project-info.
|
||||
|
||||
namespace BetterLyrics.WinUI3.Controls
|
||||
{
|
||||
public sealed partial class PlayQueue : UserControl, IRecipient<PropertyChangedMessage<int>>
|
||||
{
|
||||
public PlayQueueViewModel ViewModel => (PlayQueueViewModel)DataContext;
|
||||
public PlayQueue()
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContext = Ioc.Default.GetRequiredService<PlayQueueViewModel>();
|
||||
WeakReferenceMessenger.Default.RegisterAll(this);
|
||||
}
|
||||
|
||||
private void ScrollToPlayingItem()
|
||||
{
|
||||
if (PlayingQueueListView == null) return;
|
||||
|
||||
var targetItem = ViewModel.SMTCService.TrackPlayingQueue
|
||||
.ElementAtOrDefault(ViewModel.AppSettings.MusicGallerySettings.PlayQueueIndex);
|
||||
if (targetItem == null) return;
|
||||
|
||||
PlayingQueueListView.ScrollIntoView(targetItem);
|
||||
}
|
||||
|
||||
private void ScrollToPlayingItemButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ScrollToPlayingItem();
|
||||
}
|
||||
|
||||
private async void PlayingQueueListVireItemGrid_Tapped(object sender, TappedRoutedEventArgs e)
|
||||
{
|
||||
var item = (PlayQueueItem)((FrameworkElement)sender).DataContext;
|
||||
await ViewModel.SMTCService.PlayTrackAsync(item);
|
||||
}
|
||||
|
||||
private async void RemoveFromPlayingQueueButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
bool playNext = false;
|
||||
var item = (PlayQueueItem)((FrameworkElement)sender).DataContext;
|
||||
int index = ViewModel.SMTCService.TrackPlayingQueue.IndexOf(item);
|
||||
if (item == PlayingQueueListView.SelectedItem)
|
||||
{
|
||||
playNext = true;
|
||||
}
|
||||
ViewModel.SMTCService.TrackPlayingQueue.Remove(item);
|
||||
if (playNext)
|
||||
{
|
||||
if (ViewModel.SMTCService.TrackPlayingQueue.Count == 0)
|
||||
{
|
||||
index = -1;
|
||||
}
|
||||
else if (index >= ViewModel.SMTCService.TrackPlayingQueue.Count)
|
||||
{
|
||||
index = ViewModel.SMTCService.TrackPlayingQueue.Count - 1;
|
||||
}
|
||||
ViewModel.AppSettings.MusicGallerySettings.PlayQueueIndex = index;
|
||||
await ViewModel.SMTCService.PlayTrackAtAsync(ViewModel.AppSettings.MusicGallerySettings.PlayQueueIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private async void EmptyPlayingQueueButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ViewModel.SMTCService.TrackPlayingQueue.Clear();
|
||||
ViewModel.AppSettings.MusicGallerySettings.PlayQueueIndex = -1;
|
||||
await ViewModel.SMTCService.PlayTrackAtAsync(ViewModel.AppSettings.MusicGallerySettings.PlayQueueIndex);
|
||||
}
|
||||
|
||||
public void Receive(PropertyChangedMessage<int> message)
|
||||
{
|
||||
if (message.Sender is MusicGallerySettings)
|
||||
{
|
||||
if (message.PropertyName == nameof(MusicGallerySettings.PlayQueueIndex))
|
||||
{
|
||||
ScrollToPlayingItem();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -314,8 +314,8 @@
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Left">
|
||||
<StackPanel Spacing="6">
|
||||
<local:PropertyRow x:Uid="SettingsPagePlaybackSource" Value="{x:Bind ViewModel.MediaSessionsService.CurrentMediaSourceProviderInfo.DisplayName, Mode=OneWay}" />
|
||||
<local:PropertyRow x:Uid="SettingsPagePlaybackSourceID" Value="{x:Bind ViewModel.MediaSessionsService.CurrentSongInfo.PlayerId, TargetNullValue=N/A, Mode=OneWay}" />
|
||||
<local:PropertyRow x:Uid="SettingsPagePlaybackSource" Value="{x:Bind ViewModel.GSMTCService.CurrentMediaSourceProviderInfo.DisplayName, Mode=OneWay}" />
|
||||
<local:PropertyRow x:Uid="SettingsPagePlaybackSourceID" Value="{x:Bind ViewModel.GSMTCService.CurrentSongInfo.PlayerId, TargetNullValue=N/A, Mode=OneWay}" />
|
||||
</StackPanel>
|
||||
</Expander>
|
||||
|
||||
@@ -325,10 +325,10 @@
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Left">
|
||||
<StackPanel Spacing="6">
|
||||
<local:PropertyRow x:Uid="SettingsPageSongTitle" Value="{x:Bind ViewModel.MediaSessionsService.CurrentSongInfo.Title, TargetNullValue=N/A, Mode=OneWay}" />
|
||||
<local:PropertyRow x:Uid="SettingsPageArtist" Value="{x:Bind ViewModel.MediaSessionsService.CurrentSongInfo.DisplayArtists, TargetNullValue=N/A, Mode=OneWay}" />
|
||||
<local:PropertyRow x:Uid="SettingsPageAlbum" Value="{x:Bind ViewModel.MediaSessionsService.CurrentSongInfo.Album, TargetNullValue=N/A, Mode=OneWay}" />
|
||||
<local:PropertyRow x:Uid="LyricsSearchControlDurauion" Value="{x:Bind ViewModel.MediaSessionsService.CurrentSongInfo.DurationMs, TargetNullValue=N/A, Converter={StaticResource MillisecondsToFormattedTimeConverter}, Mode=OneWay}" />
|
||||
<local:PropertyRow x:Uid="SettingsPageSongTitle" Value="{x:Bind ViewModel.GSMTCService.CurrentSongInfo.Title, TargetNullValue=N/A, Mode=OneWay}" />
|
||||
<local:PropertyRow x:Uid="SettingsPageArtist" Value="{x:Bind ViewModel.GSMTCService.CurrentSongInfo.DisplayArtists, TargetNullValue=N/A, Mode=OneWay}" />
|
||||
<local:PropertyRow x:Uid="SettingsPageAlbum" Value="{x:Bind ViewModel.GSMTCService.CurrentSongInfo.Album, TargetNullValue=N/A, Mode=OneWay}" />
|
||||
<local:PropertyRow x:Uid="LyricsSearchControlDurauion" Value="{x:Bind ViewModel.GSMTCService.CurrentSongInfo.DurationMs, TargetNullValue=N/A, Converter={StaticResource MillisecondsToFormattedTimeConverter}, Mode=OneWay}" />
|
||||
</StackPanel>
|
||||
</Expander>
|
||||
|
||||
@@ -338,26 +338,26 @@
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Left">
|
||||
<StackPanel Spacing="6">
|
||||
<local:PropertyRow x:Uid="SettingsPageSongTitle" Value="{x:Bind ViewModel.MediaSessionsService.CurrentLyricsSearchResult.Title, TargetNullValue=N/A, Mode=OneWay}" />
|
||||
<local:PropertyRow x:Uid="SettingsPageArtist" Value="{x:Bind ViewModel.MediaSessionsService.CurrentLyricsSearchResult.DisplayArtists, TargetNullValue=N/A, Mode=OneWay}" />
|
||||
<local:PropertyRow x:Uid="SettingsPageAlbum" Value="{x:Bind ViewModel.MediaSessionsService.CurrentLyricsSearchResult.Album, TargetNullValue=N/A, Mode=OneWay}" />
|
||||
<local:PropertyRow x:Uid="LyricsSearchControlDurauion" Value="{x:Bind ViewModel.MediaSessionsService.CurrentLyricsSearchResult.Duration, Converter={StaticResource SecondsToFormattedTimeConverter}, TargetNullValue=N/A, Mode=OneWay}" />
|
||||
<local:PropertyRow x:Uid="LyricsPageLanguageCode" Value="{x:Bind ViewModel.MediaSessionsService.CurrentLyricsData.LanguageCode, TargetNullValue=N/A, Mode=OneWay, Converter={StaticResource LanguageCodeToDisplayedNameConverter}}" />
|
||||
<local:PropertyRow x:Uid="SettingsPageSongTitle" Value="{x:Bind ViewModel.GSMTCService.CurrentLyricsSearchResult.Title, TargetNullValue=N/A, Mode=OneWay}" />
|
||||
<local:PropertyRow x:Uid="SettingsPageArtist" Value="{x:Bind ViewModel.GSMTCService.CurrentLyricsSearchResult.DisplayArtists, TargetNullValue=N/A, Mode=OneWay}" />
|
||||
<local:PropertyRow x:Uid="SettingsPageAlbum" Value="{x:Bind ViewModel.GSMTCService.CurrentLyricsSearchResult.Album, TargetNullValue=N/A, Mode=OneWay}" />
|
||||
<local:PropertyRow x:Uid="LyricsSearchControlDurauion" Value="{x:Bind ViewModel.GSMTCService.CurrentLyricsSearchResult.Duration, Converter={StaticResource SecondsToFormattedTimeConverter}, TargetNullValue=N/A, Mode=OneWay}" />
|
||||
<local:PropertyRow x:Uid="LyricsPageLanguageCode" Value="{x:Bind ViewModel.GSMTCService.CurrentLyricsData.LanguageCode, TargetNullValue=N/A, Mode=OneWay, Converter={StaticResource LanguageCodeToDisplayedNameConverter}}" />
|
||||
<local:PropertyRow
|
||||
x:Uid="LyricsPageLyricsProviderPrefix"
|
||||
Link="{x:Bind ViewModel.MediaSessionsService.CurrentLyricsSearchResult.Reference, Mode=OneWay, Converter={StaticResource UriStringToDecodedAbsoluteUri}}"
|
||||
ToolTipService.ToolTip="{x:Bind ViewModel.MediaSessionsService.CurrentLyricsSearchResult.Reference, TargetNullValue=N/A, Mode=OneWay, Converter={StaticResource UriStringToDecodedAbsoluteUri}}"
|
||||
Value="{x:Bind ViewModel.MediaSessionsService.CurrentLyricsSearchResult.ProviderIfFound, Mode=OneWay, Converter={StaticResource LyricsSearchProviderToDisplayNameConverter}}" />
|
||||
<local:PropertyRow x:Uid="LyricsPageTransliterationProviderPrefix" Value="{x:Bind ViewModel.MediaSessionsService.CurrentLyricsSearchResult.TransliterationProvider, Mode=OneWay, Converter={StaticResource TransliterationSearchProviderToDisplayNameConverter}}" />
|
||||
<local:PropertyRow x:Uid="LyricsPageTranslationProviderPrefix" Value="{x:Bind ViewModel.MediaSessionsService.CurrentLyricsSearchResult.TranslationProvider, Mode=OneWay, Converter={StaticResource TranslationSearchProviderToDisplayNameConverter}}" />
|
||||
Link="{x:Bind ViewModel.GSMTCService.CurrentLyricsSearchResult.Reference, Mode=OneWay, Converter={StaticResource UriStringToDecodedAbsoluteUri}}"
|
||||
ToolTipService.ToolTip="{x:Bind ViewModel.GSMTCService.CurrentLyricsSearchResult.Reference, TargetNullValue=N/A, Mode=OneWay, Converter={StaticResource UriStringToDecodedAbsoluteUri}}"
|
||||
Value="{x:Bind ViewModel.GSMTCService.CurrentLyricsSearchResult.ProviderIfFound, Mode=OneWay, Converter={StaticResource LyricsSearchProviderToDisplayNameConverter}}" />
|
||||
<local:PropertyRow x:Uid="LyricsPageTransliterationProviderPrefix" Value="{x:Bind ViewModel.GSMTCService.CurrentLyricsSearchResult.TransliterationProvider, Mode=OneWay, Converter={StaticResource TransliterationSearchProviderToDisplayNameConverter}}" />
|
||||
<local:PropertyRow x:Uid="LyricsPageTranslationProviderPrefix" Value="{x:Bind ViewModel.GSMTCService.CurrentLyricsSearchResult.TranslationProvider, Mode=OneWay, Converter={StaticResource TranslationSearchProviderToDisplayNameConverter}}" />
|
||||
<local:PropertyRow
|
||||
x:Uid="LyricsPageMatchPercentage"
|
||||
Unit="%"
|
||||
Value="{x:Bind ViewModel.MediaSessionsService.CurrentLyricsSearchResult.MatchPercentage, Mode=OneWay}" />
|
||||
Value="{x:Bind ViewModel.GSMTCService.CurrentLyricsSearchResult.MatchPercentage, Mode=OneWay}" />
|
||||
<local:PropertyRow
|
||||
x:Uid="LyricsPageCachePath"
|
||||
Link="{x:Bind ViewModel.MediaSessionsService.CurrentLyricsSearchResult.SelfPath, TargetNullValue=N/A, Mode=OneWay, Converter={StaticResource UriStringToDecodedAbsoluteUri}}"
|
||||
ToolTipService.ToolTip="{x:Bind ViewModel.MediaSessionsService.CurrentLyricsSearchResult.SelfPath, TargetNullValue=N/A, Mode=OneWay, Converter={StaticResource UriStringToDecodedAbsoluteUri}}" />
|
||||
Link="{x:Bind ViewModel.GSMTCService.CurrentLyricsSearchResult.SelfPath, TargetNullValue=N/A, Mode=OneWay, Converter={StaticResource UriStringToDecodedAbsoluteUri}}"
|
||||
ToolTipService.ToolTip="{x:Bind ViewModel.GSMTCService.CurrentLyricsSearchResult.SelfPath, TargetNullValue=N/A, Mode=OneWay, Converter={StaticResource UriStringToDecodedAbsoluteUri}}" />
|
||||
</StackPanel>
|
||||
</Expander>
|
||||
|
||||
|
||||
@@ -105,14 +105,13 @@ namespace BetterLyrics.WinUI3.Models
|
||||
|
||||
public ExtendedTrack() : base() { }
|
||||
|
||||
public ExtendedTrack(string uriString) : base()
|
||||
public ExtendedTrack(string decodedUriString) : base()
|
||||
{
|
||||
Uri = uriString;
|
||||
|
||||
string atlPath = uriString;
|
||||
string atlPath = decodedUriString;
|
||||
try
|
||||
{
|
||||
var u = new Uri(uriString);
|
||||
var u = new Uri(decodedUriString);
|
||||
Uri = u.AbsoluteUri;
|
||||
if (u.IsFile) atlPath = u.LocalPath;
|
||||
}
|
||||
catch { }
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Models.Settings
|
||||
|
||||
@@ -39,6 +39,8 @@ namespace BetterLyrics.WinUI3.Renderer
|
||||
var blur = line.BlurAmountTransition.Value;
|
||||
var bounds = line.PhoneticCanvasTextLayout.LayoutBounds;
|
||||
|
||||
if (double.IsNaN(opacity)) return;
|
||||
|
||||
var destRect = new Rect(
|
||||
bounds.X + line.PhoneticPosition.X,
|
||||
bounds.Y + line.PhoneticPosition.Y,
|
||||
@@ -71,6 +73,8 @@ namespace BetterLyrics.WinUI3.Renderer
|
||||
var blur = line.BlurAmountTransition.Value;
|
||||
var bounds = line.TranslatedCanvasTextLayout.LayoutBounds;
|
||||
|
||||
if (double.IsNaN(opacity)) return;
|
||||
|
||||
var destRect = new Rect(
|
||||
bounds.X + line.TranslatedPosition.X,
|
||||
bounds.Y + line.TranslatedPosition.Y,
|
||||
|
||||
@@ -31,8 +31,6 @@ namespace BetterLyrics.WinUI3.Services.FileSystemService
|
||||
|
||||
private readonly IDbContextFactory<FilesIndexDbContext> _contextFactory;
|
||||
|
||||
private bool _isInitialized = false;
|
||||
|
||||
// 定时器字典
|
||||
private readonly ConcurrentDictionary<string, CancellationTokenSource> _folderTimerTokens = new();
|
||||
// 当前正在执行的扫描任务字典
|
||||
@@ -460,6 +458,17 @@ namespace BetterLyrics.WinUI3.Services.FileSystemService
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<List<FilesIndexItem>> GetParsedFilesAsync()
|
||||
{
|
||||
using var context = await _contextFactory.CreateDbContextAsync();
|
||||
|
||||
// SQL: SELECT * FROM FileCache WHERE IsMetadataParsed = 1 AND MediaFolderId IN (...)
|
||||
return await context.FilesIndex
|
||||
.AsNoTracking()
|
||||
.Where(x => x.IsMetadataParsed)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<List<FilesIndexItem>> GetParsedFilesAsync(IEnumerable<string> enabledConfigIds)
|
||||
{
|
||||
if (enabledConfigIds == null || !enabledConfigIds.Any())
|
||||
|
||||
@@ -50,7 +50,13 @@ namespace BetterLyrics.WinUI3.Services.FileSystemService
|
||||
Task ScanMediaFolderAsync(MediaFolder folder, CancellationToken token = default);
|
||||
|
||||
/// <summary>
|
||||
/// 从数据库拉取
|
||||
/// 从数据库拉取全部已解析的数据
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<List<FilesIndexItem>> GetParsedFilesAsync();
|
||||
|
||||
/// <summary>
|
||||
/// 从数据库拉取全部已解析的且其所属的 MediaFolder 在应用内处于开启状态的数据
|
||||
/// </summary>
|
||||
/// <param name="enabledConfigIds"></param>
|
||||
/// <returns></returns>
|
||||
|
||||
@@ -17,9 +17,9 @@ using Windows.Graphics.Imaging;
|
||||
using Windows.Storage.Streams;
|
||||
using Windows.UI;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Services.MediaSessionsService
|
||||
namespace BetterLyrics.WinUI3.Services.GSMTCService
|
||||
{
|
||||
public partial class MediaSessionsService : IMediaSessionsService
|
||||
public partial class GSMTCService : IGSMTCService
|
||||
{
|
||||
private readonly LatestOnlyTaskRunner _albumArtRefreshRunner = new();
|
||||
|
||||
@@ -7,9 +7,9 @@ using Microsoft.Extensions.Logging;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Services.MediaSessionsService
|
||||
namespace BetterLyrics.WinUI3.Services.GSMTCService
|
||||
{
|
||||
public partial class MediaSessionsService : IMediaSessionsService
|
||||
public partial class GSMTCService : IGSMTCService
|
||||
{
|
||||
private LatestOnlyTaskRunner _refreshLyricsRunner = new();
|
||||
|
||||
@@ -38,9 +38,9 @@ using Windows.Media.Control;
|
||||
using Windows.Storage.Streams;
|
||||
using WindowsMediaController;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Services.MediaSessionsService
|
||||
namespace BetterLyrics.WinUI3.Services.GSMTCService
|
||||
{
|
||||
public partial class MediaSessionsService : BaseViewModel, IMediaSessionsService,
|
||||
public partial class GSMTCService : BaseViewModel, IGSMTCService,
|
||||
IRecipient<PropertyChangedMessage<bool>>,
|
||||
IRecipient<PropertyChangedMessage<string>>,
|
||||
IRecipient<PropertyChangedMessage<ChineseRomanization>>,
|
||||
@@ -58,7 +58,7 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
|
||||
private readonly IDiscordService _discordService;
|
||||
private readonly IPlayHistoryService _playHistoryService;
|
||||
private readonly ILastFMService _lastFMService;
|
||||
private readonly ILogger<MediaSessionsService> _logger;
|
||||
private readonly ILogger<GSMTCService> _logger;
|
||||
|
||||
private double _lxMusicPositionSeconds = 0;
|
||||
private byte[]? _lxMusicAlbumArtBytes = null;
|
||||
@@ -73,7 +73,7 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
|
||||
|
||||
[ObservableProperty] public partial MediaSourceProviderInfo? CurrentMediaSourceProviderInfo { get; set; }
|
||||
|
||||
public MediaSessionsService(
|
||||
public GSMTCService(
|
||||
ISettingsService settingsService,
|
||||
IAlbumArtSearchService albumArtSearchService,
|
||||
ILyricsSearchService lyricsSearchService,
|
||||
@@ -82,7 +82,7 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
|
||||
ITransliterationService transliterationService,
|
||||
IPlayHistoryService playHistoryService,
|
||||
ILastFMService lastFMService,
|
||||
ILogger<MediaSessionsService> logger)
|
||||
ILogger<GSMTCService> logger)
|
||||
{
|
||||
_settingsService = settingsService;
|
||||
_albumArtSearchService = albumArtSearchService;
|
||||
@@ -198,7 +198,7 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
|
||||
|
||||
private void MediaManager_OnAnyTimelinePropertyChanged(MediaManager.MediaSession? mediaSession, GlobalSystemMediaTransportControlsSessionTimelineProperties? timelineProperties)
|
||||
{
|
||||
_dispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, () =>
|
||||
_dispatcherQueue.TryEnqueue(() =>
|
||||
{
|
||||
if (!_mediaManager.IsStarted) return;
|
||||
if (mediaSession == null)
|
||||
@@ -230,7 +230,7 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
|
||||
|
||||
private void MediaManager_OnAnyPlaybackStateChanged(MediaManager.MediaSession? mediaSession, GlobalSystemMediaTransportControlsSessionPlaybackInfo? playbackInfo)
|
||||
{
|
||||
_dispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, (() =>
|
||||
_dispatcherQueue.TryEnqueue(() =>
|
||||
{
|
||||
if (!_mediaManager.IsStarted) return;
|
||||
if (mediaSession == null)
|
||||
@@ -264,14 +264,14 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
|
||||
{
|
||||
_scrobbleStopwatch.Stop();
|
||||
}
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
private void MediaManager_OnAnyMediaPropertyChanged(MediaManager.MediaSession? mediaSession, GlobalSystemMediaTransportControlsSessionMediaProperties? mediaProperties)
|
||||
{
|
||||
_onMediaPropsChangedTimer?.Debounce(() =>
|
||||
{
|
||||
_dispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, async () =>
|
||||
_dispatcherQueue.TryEnqueue(async () =>
|
||||
{
|
||||
if (!_mediaManager.IsStarted) return;
|
||||
if (mediaSession == null)
|
||||
@@ -333,7 +333,7 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
|
||||
.Replace(ExtendedGenreFiled.FileName, "");
|
||||
|
||||
// 写入播放记录
|
||||
if (CurrentSongInfo != null && CurrentSongInfo.Title != "N/A")
|
||||
if (CurrentSongInfo != null && !string.IsNullOrWhiteSpace(CurrentSongInfo.Title) && CurrentSongInfo.Title != "N/A")
|
||||
{
|
||||
// 必须捕获一个副本给异步任务,因为 CurrentSongInfo 马上就要变了
|
||||
var lastSong = CurrentSongInfo;
|
||||
@@ -419,13 +419,13 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService
|
||||
}
|
||||
}
|
||||
|
||||
private void MediaManager_OnAnySessionOpened(MediaManager.MediaSession mediaSession)
|
||||
private async void MediaManager_OnAnySessionOpened(MediaManager.MediaSession mediaSession)
|
||||
{
|
||||
if (!_mediaManager.IsStarted) return;
|
||||
if (mediaSession == null) return;
|
||||
|
||||
RecordMediaSourceProviderInfo(mediaSession);
|
||||
SendFocusedMessagesAsync().ConfigureAwait(false);
|
||||
await SendFocusedMessagesAsync();
|
||||
}
|
||||
|
||||
private MediaManager.MediaSession? GetCurrentSession()
|
||||
@@ -8,9 +8,12 @@ using System.Threading.Tasks;
|
||||
using Windows.Storage.Streams;
|
||||
using Windows.UI;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Services.MediaSessionsService
|
||||
namespace BetterLyrics.WinUI3.Services.GSMTCService
|
||||
{
|
||||
public interface IMediaSessionsService : INotifyPropertyChanged
|
||||
/// <summary>
|
||||
/// Interface for GlobalSystemMediaTransportControlsSession Service
|
||||
/// </summary>
|
||||
public interface IGSMTCService : INotifyPropertyChanged
|
||||
{
|
||||
Task PlayAsync();
|
||||
Task PauseAsync();
|
||||
@@ -0,0 +1,21 @@
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Services.SMTCService
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface for SystemMediaTransportControlsSession Service
|
||||
/// </summary>
|
||||
public interface ISMTCService
|
||||
{
|
||||
public ObservableCollection<PlayQueueItem> TrackPlayingQueue { get; set; }
|
||||
public ExtendedTrack? PlayingTrack { get; set; }
|
||||
|
||||
Task PlayTrackAsync(PlayQueueItem? playQueueItem);
|
||||
Task PlayTrackAtAsync(int index);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,330 @@
|
||||
using BetterLyrics.WinUI3.Constants;
|
||||
using BetterLyrics.WinUI3.Enums;
|
||||
using BetterLyrics.WinUI3.Extensions;
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.Models.Settings;
|
||||
using BetterLyrics.WinUI3.Services.FileSystemService;
|
||||
using BetterLyrics.WinUI3.Services.GSMTCService;
|
||||
using BetterLyrics.WinUI3.Services.SettingsService;
|
||||
using BetterLyrics.WinUI3.ViewModels;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Microsoft.UI.Dispatching;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.ApplicationModel;
|
||||
using Windows.Media;
|
||||
using Windows.Media.Core;
|
||||
using Windows.Media.Playback;
|
||||
using Windows.Storage;
|
||||
using Windows.Storage.Streams;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Services.SMTCService
|
||||
{
|
||||
public partial class SMTCService : BaseViewModel, ISMTCService
|
||||
{
|
||||
private readonly MediaPlayer _mediaPlayer;
|
||||
private readonly MediaTimelineController _timelineController;
|
||||
private readonly SystemMediaTransportControls _smtc;
|
||||
|
||||
private IRandomAccessStream? _currentStream;
|
||||
private Stream? _currentNetStream;
|
||||
private IUnifiedFileSystem? _currentProvider;
|
||||
|
||||
private readonly ISettingsService _settingsService;
|
||||
private readonly IFileSystemService _fileSystemService;
|
||||
|
||||
[ObservableProperty] public partial ObservableCollection<PlayQueueItem> TrackPlayingQueue { get; set; } = [];
|
||||
[ObservableProperty] public partial ExtendedTrack? PlayingTrack { get; set; }
|
||||
|
||||
public SMTCService(ISettingsService settingsService, IFileSystemService fileSystemService)
|
||||
{
|
||||
_settingsService = settingsService;
|
||||
_fileSystemService = fileSystemService;
|
||||
|
||||
_mediaPlayer = new MediaPlayer();
|
||||
_mediaPlayer.MediaOpened += MediaPlayer_MediaOpened;
|
||||
_mediaPlayer.MediaEnded += MediaPlayer_MediaEnded;
|
||||
_mediaPlayer.CommandManager.IsEnabled = false;
|
||||
|
||||
_timelineController = _mediaPlayer.TimelineController = new();
|
||||
_timelineController.PositionChanged += TimelineController_PositionChanged;
|
||||
|
||||
_smtc = _mediaPlayer.SystemMediaTransportControls;
|
||||
_smtc.IsPlayEnabled = true;
|
||||
_smtc.IsPauseEnabled = true;
|
||||
_smtc.IsNextEnabled = true;
|
||||
_smtc.IsPreviousEnabled = true;
|
||||
_smtc.ButtonPressed += Smtc_ButtonPressed;
|
||||
_smtc.PlaybackPositionChangeRequested += Smtc_PlaybackPositionChangeRequested;
|
||||
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
var parsedFiles = await _fileSystemService.GetParsedFilesAsync();
|
||||
var playQueue = _settingsService.AppSettings.MusicGallerySettings.PlayQueuePaths
|
||||
.Where(x => !string.IsNullOrWhiteSpace(x))
|
||||
.Select(x =>
|
||||
{
|
||||
var encodedUri = new Uri(x).AbsoluteUri;
|
||||
return new PlayQueueItem(new ExtendedTrack(parsedFiles.FirstOrDefault(y => y.Uri == encodedUri)));
|
||||
});
|
||||
_dispatcherQueue.TryEnqueue(() =>
|
||||
{
|
||||
TrackPlayingQueue = [.. playQueue];
|
||||
TrackPlayingQueue.CollectionChanged += TrackPlayingQueue_CollectionChanged;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private void Smtc_ButtonPressed(SystemMediaTransportControls sender, SystemMediaTransportControlsButtonPressedEventArgs args)
|
||||
{
|
||||
switch (args.Button)
|
||||
{
|
||||
case SystemMediaTransportControlsButton.Play:
|
||||
_smtc.PlaybackStatus = MediaPlaybackStatus.Playing;
|
||||
_timelineController.Resume();
|
||||
break;
|
||||
case SystemMediaTransportControlsButton.Pause:
|
||||
_smtc.PlaybackStatus = MediaPlaybackStatus.Paused;
|
||||
_timelineController.Pause();
|
||||
break;
|
||||
case SystemMediaTransportControlsButton.Next:
|
||||
PlayNextTrack();
|
||||
break;
|
||||
case SystemMediaTransportControlsButton.Previous:
|
||||
PlayPreviousTrack();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void Smtc_PlaybackPositionChangeRequested(SystemMediaTransportControls sender, PlaybackPositionChangeRequestedEventArgs args)
|
||||
{
|
||||
_timelineController.Position = args.RequestedPlaybackPosition;
|
||||
}
|
||||
|
||||
private void MediaPlayer_MediaOpened(MediaPlayer sender, object args)
|
||||
{
|
||||
_timelineController.Start();
|
||||
_smtc.PlaybackStatus = MediaPlaybackStatus.Playing;
|
||||
}
|
||||
|
||||
private void MediaPlayer_MediaEnded(MediaPlayer sender, object args)
|
||||
{
|
||||
PlayNextTrack();
|
||||
}
|
||||
|
||||
private void TimelineController_PositionChanged(MediaTimelineController sender, object args)
|
||||
{
|
||||
_smtc.UpdateTimelineProperties(new SystemMediaTransportControlsTimelineProperties()
|
||||
{
|
||||
Position = sender.Position,
|
||||
EndTime = _mediaPlayer.PlaybackSession.NaturalDuration
|
||||
});
|
||||
}
|
||||
|
||||
private void TrackPlayingQueue_CollectionChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
_settingsService.AppSettings.MusicGallerySettings.PlayQueuePaths = [.. TrackPlayingQueue.Select(x => x.Track.Uri.ToDecodedAbsoluteUri())];
|
||||
}
|
||||
|
||||
private string GetMimeType(string path)
|
||||
{
|
||||
var ext = Path.GetExtension(path).ToLower();
|
||||
return ext switch
|
||||
{
|
||||
".mp3" => "audio/mpeg",
|
||||
".flac" => "audio/flac",
|
||||
".wav" => "audio/wav",
|
||||
".m4a" => "audio/mp4",
|
||||
".aac" => "audio/aac",
|
||||
".ogg" => "audio/ogg",
|
||||
".wma" => "audio/x-ms-wma",
|
||||
_ => "application/octet-stream"
|
||||
};
|
||||
}
|
||||
|
||||
private void PlayNextTrack()
|
||||
{
|
||||
var musicGallerySettings = _settingsService.AppSettings.MusicGallerySettings;
|
||||
_dispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, async () =>
|
||||
{
|
||||
switch (musicGallerySettings.PlaybackOrder)
|
||||
{
|
||||
case PlaybackOrder.RepeatAll:
|
||||
if (musicGallerySettings.PlayQueueIndex < TrackPlayingQueue.Count - 1)
|
||||
{
|
||||
musicGallerySettings.PlayQueueIndex++;
|
||||
}
|
||||
else
|
||||
{
|
||||
musicGallerySettings.PlayQueueIndex = 0;
|
||||
}
|
||||
break;
|
||||
case PlaybackOrder.RepeatOne:
|
||||
//_timelineController.Position = TimeSpan.Zero;
|
||||
break;
|
||||
case PlaybackOrder.Shuffle:
|
||||
if (TrackPlayingQueue.Count > 0)
|
||||
{
|
||||
musicGallerySettings.PlayQueueIndex = new Random().Next(0, TrackPlayingQueue.Count);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
await PlayTrackAtAsync(musicGallerySettings.PlayQueueIndex);
|
||||
});
|
||||
}
|
||||
|
||||
private void PlayPreviousTrack()
|
||||
{
|
||||
var musicGallerySettings = _settingsService.AppSettings.MusicGallerySettings;
|
||||
_dispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, async () =>
|
||||
{
|
||||
switch (musicGallerySettings.PlaybackOrder)
|
||||
{
|
||||
case PlaybackOrder.RepeatAll:
|
||||
if (musicGallerySettings.PlayQueueIndex > 0)
|
||||
{
|
||||
musicGallerySettings.PlayQueueIndex--;
|
||||
}
|
||||
else
|
||||
{
|
||||
musicGallerySettings.PlayQueueIndex = TrackPlayingQueue.Count - 1;
|
||||
}
|
||||
break;
|
||||
case PlaybackOrder.RepeatOne:
|
||||
//_timelineController.Position = TimeSpan.Zero;
|
||||
break;
|
||||
case PlaybackOrder.Shuffle:
|
||||
if (TrackPlayingQueue.Count > 0)
|
||||
{
|
||||
musicGallerySettings.PlayQueueIndex = new Random().Next(0, TrackPlayingQueue.Count);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
await PlayTrackAtAsync(musicGallerySettings.PlayQueueIndex);
|
||||
});
|
||||
}
|
||||
|
||||
public async Task PlayTrackAsync(PlayQueueItem? playQueueItem)
|
||||
{
|
||||
_timelineController.Pause();
|
||||
_mediaPlayer.Source = null;
|
||||
|
||||
// 清理旧资源
|
||||
_currentStream?.Dispose();
|
||||
_currentNetStream?.Dispose();
|
||||
_currentStream = null;
|
||||
_currentNetStream = null;
|
||||
|
||||
if (playQueueItem == null)
|
||||
{
|
||||
_smtc.IsEnabled = false;
|
||||
_smtc.DisplayUpdater.ClearAll();
|
||||
}
|
||||
else
|
||||
{
|
||||
PlayingTrack = playQueueItem.Track;
|
||||
_smtc.IsEnabled = true;
|
||||
|
||||
try
|
||||
{
|
||||
var targetFolder = _settingsService.AppSettings.LocalMediaFolders.FirstOrDefault(f =>
|
||||
{
|
||||
var fUri = f.GetStandardUri().AbsoluteUri;
|
||||
return PlayingTrack.Uri.StartsWith(fUri, StringComparison.OrdinalIgnoreCase);
|
||||
});
|
||||
|
||||
if (targetFolder == null)
|
||||
{
|
||||
throw new FileNotFoundException(null, PlayingTrack.Uri.ToDecodedAbsoluteUri());
|
||||
}
|
||||
|
||||
_currentProvider = targetFolder.CreateFileSystem();
|
||||
if (_currentProvider == null) return;
|
||||
|
||||
await _currentProvider.ConnectAsync();
|
||||
|
||||
var fileCacheStub = new FilesIndexItem
|
||||
{
|
||||
Uri = PlayingTrack.Uri
|
||||
};
|
||||
|
||||
var sourceStream = await _fileSystemService.OpenFileAsync(_currentProvider, fileCacheStub);
|
||||
|
||||
if (sourceStream == null)
|
||||
{
|
||||
throw new FileNotFoundException(null, fileCacheStub.Uri);
|
||||
}
|
||||
|
||||
if (sourceStream.CanSeek)
|
||||
{
|
||||
_currentNetStream = sourceStream;
|
||||
}
|
||||
else
|
||||
{
|
||||
var memStream = new MemoryStream();
|
||||
|
||||
await sourceStream.CopyToAsync(memStream);
|
||||
memStream.Position = 0;
|
||||
|
||||
sourceStream.Dispose();
|
||||
|
||||
_currentNetStream = memStream;
|
||||
}
|
||||
|
||||
_currentStream = _currentNetStream.AsRandomAccessStream();
|
||||
|
||||
string contentType = GetMimeType(PlayingTrack.FileName);
|
||||
var mediaSource = MediaSource.CreateFromStream(_currentStream, contentType);
|
||||
|
||||
_mediaPlayer.Source = mediaSource;
|
||||
|
||||
var updater = _smtc.DisplayUpdater;
|
||||
updater.Type = MediaPlaybackType.Music;
|
||||
|
||||
updater.MusicProperties.Title = PlayingTrack.Title ?? PlayingTrack.FileName;
|
||||
updater.MusicProperties.Artist = PlayingTrack.Artist ?? "";
|
||||
updater.MusicProperties.AlbumTitle = PlayingTrack.Album ?? "";
|
||||
|
||||
updater.MusicProperties.Genres.Clear();
|
||||
updater.MusicProperties.Genres.Add($"{ExtendedGenreFiled.FileName}{Path.GetFileNameWithoutExtension(PlayingTrack.FileName)}");
|
||||
|
||||
updater.AppMediaId = Package.Current.Id.FullName;
|
||||
|
||||
if (!string.IsNullOrEmpty(PlayingTrack.LocalAlbumArtPath) && File.Exists(PlayingTrack.LocalAlbumArtPath))
|
||||
{
|
||||
var storageFile = await StorageFile.GetFileFromPathAsync(PlayingTrack.LocalAlbumArtPath);
|
||||
updater.Thumbnail = RandomAccessStreamReference.CreateFromFile(storageFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
updater.Thumbnail = null;
|
||||
}
|
||||
|
||||
updater.Update();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ToastHelper.ShowToast("Error", ex.Message, InfoBarSeverity.Error);
|
||||
_timelineController.Pause();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task PlayTrackAtAsync(int index)
|
||||
{
|
||||
await PlayTrackAsync(TrackPlayingQueue.ElementAtOrDefault(index));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:bwc="using:BetterLyrics.WinUI3.Converter"
|
||||
xmlns:cwc="using:CommunityToolkit.WinUI.Converters">
|
||||
|
||||
<bwc:EnumToIntConverter x:Key="EnumToIntConverter" />
|
||||
<bwc:ColorToBrushConverter x:Key="ColorToBrushConverter" />
|
||||
<bwc:MatchedLocalFilesPathToVisibilityConverter x:Key="MatchedLocalFilesPathToVisibilityConverter" />
|
||||
<bwc:IntToCornerRadius x:Key="IntToCornerRadius" />
|
||||
<bwc:CornerRadiusToDoubleConverter x:Key="CornerRadiusToDoubleConverter" />
|
||||
<bwc:LyricsSearchProviderToDisplayNameConverter x:Key="LyricsSearchProviderToDisplayNameConverter" />
|
||||
<bwc:TranslationSearchProviderToDisplayNameConverter x:Key="TranslationSearchProviderToDisplayNameConverter" />
|
||||
<bwc:TransliterationSearchProviderToDisplayNameConverter x:Key="TransliterationSearchProviderToDisplayNameConverter" />
|
||||
<bwc:AlbumArtSearchProviderToDisplayNameConverter x:Key="AlbumArtSearchProviderToDisplayNameConverter" />
|
||||
<bwc:SecondsToFormattedTimeConverter x:Key="SecondsToFormattedTimeConverter" />
|
||||
<bwc:MillisecondsToFormattedTimeConverter x:Key="MillisecondsToFormattedTimeConverter" />
|
||||
<bwc:FPSToTimeSpanConverter x:Key="FPSToTimeSpanConverter" />
|
||||
<bwc:ShortcutToStringConverter x:Key="ShortcutToStringConverter" />
|
||||
<bwc:BoolNegationToVisibilityConverter x:Key="BoolNegationToVisibilityConverter" />
|
||||
<bwc:BoolToOpacityConverter x:Key="BoolToOpacityConverter" />
|
||||
<bwc:BoolToPartialOpacityConverter x:Key="BoolToPartialOpacityConverter" />
|
||||
<bwc:BoolNegationToOpacityConverter x:Key="BoolNegationToOpacityConverter" />
|
||||
<bwc:RectToMarginConverter x:Key="RectToMarginConverter" />
|
||||
<bwc:LanguageCodeToDisplayedNameConverter x:Key="LanguageCodeToDisplayedNameConverter" />
|
||||
<bwc:ByteArrayToImageConverter x:Key="ByteArrayToImageConverter" />
|
||||
<bwc:DisplayLanguageCodeToIndexConverter x:Key="DisplayLanguageCodeToIndexConverter" />
|
||||
<bwc:PathToParentFolderConverter x:Key="PathToParentFolderConverter" />
|
||||
<bwc:IntToBoolConverter x:Key="IntToBoolConverter" />
|
||||
<bwc:IndexToDisplayConverter x:Key="IndexToDisplayConverter" />
|
||||
<bwc:IntToDoubleConverter x:Key="IntToDoubleConverter" />
|
||||
<bwc:MillisecondsToSecondsConverter x:Key="MillisecondsToSecondsConverter" />
|
||||
<bwc:PictureInfosToImageSourceConverter x:Key="PictureInfosToImageSourceConverter" />
|
||||
<bwc:LyricsFontWeightToFontWeightConverter x:Key="LyricsFontWeightToFontWeightConverter" />
|
||||
<bwc:TextAlignmentTypeToHorizontalAlignmentConverter x:Key="TextAlignmentTypeToHorizontalAlignmentConverter" />
|
||||
<bwc:LyricsLayoutOrientationToOrientationConverter x:Key="LyricsLayoutOrientationToOrientationConverter" />
|
||||
<bwc:LyricsLayoutOrientationNegationToOrientationConverter x:Key="LyricsLayoutOrientationNegationToOrientationConverter" />
|
||||
<bwc:FileSourceTypeToIconConverter x:Key="FileSourceTypeToIconConverter" />
|
||||
<bwc:PathToImageConverter x:Key="PathToImageConverter" />
|
||||
<bwc:DoubleToDecimalConverter x:Key="DoubleToDecimalConverter" />
|
||||
<bwc:UriStringToDecodedAbsoluteUri x:Key="UriStringToDecodedAbsoluteUri" />
|
||||
|
||||
<cwc:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
|
||||
<cwc:BoolNegationConverter x:Key="BoolNegationConverter" />
|
||||
<cwc:ColorToDisplayNameConverter x:Key="ColorToDisplayNameConverter" />
|
||||
<cwc:CollectionVisibilityConverter x:Key="CollectionVisibilityConverter" />
|
||||
|
||||
</ResourceDictionary>
|
||||
@@ -0,0 +1,188 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
|
||||
<Style x:Key="GhostSliderStyle" TargetType="Slider">
|
||||
<Setter Property="Background" Value="{ThemeResource ControlStrokeColorOnAccentDefaultBrush}" />
|
||||
<Setter Property="BorderThickness" Value="{ThemeResource SliderBorderThemeThickness}" />
|
||||
<Setter Property="Foreground" Value="{ThemeResource TextFillColorPrimaryBrush}" />
|
||||
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
|
||||
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
|
||||
<Setter Property="ManipulationMode" Value="None" />
|
||||
<Setter Property="UseSystemFocusVisuals" Value="{StaticResource UseSystemFocusVisuals}" />
|
||||
<Setter Property="FocusVisualMargin" Value="-7,0,-7,0" />
|
||||
<Setter Property="IsFocusEngagementEnabled" Value="True" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Slider">
|
||||
<Grid Margin="{TemplateBinding Padding}">
|
||||
<Grid.Resources>
|
||||
<Style x:Key="SliderThumbStyle" TargetType="Thumb">
|
||||
<Setter Property="BorderThickness" Value="0" />
|
||||
<Setter Property="Background" Value="{ThemeResource TextFillColorPrimaryBrush}" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Thumb">
|
||||
<Border
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
CornerRadius="0,1,1,0" />
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</Grid.Resources>
|
||||
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<ContentPresenter
|
||||
x:Name="HeaderContentPresenter"
|
||||
Grid.Row="0"
|
||||
Margin="{ThemeResource SliderTopHeaderMargin}"
|
||||
x:DeferLoadStrategy="Lazy"
|
||||
Content="{TemplateBinding Header}"
|
||||
ContentTemplate="{TemplateBinding HeaderTemplate}"
|
||||
FontWeight="{ThemeResource SliderHeaderThemeFontWeight}"
|
||||
Foreground="{ThemeResource SliderHeaderForeground}"
|
||||
TextWrapping="Wrap"
|
||||
Visibility="Collapsed" />
|
||||
<Grid
|
||||
x:Name="SliderContainer"
|
||||
Grid.Row="1"
|
||||
Background="{ThemeResource SliderContainerBackground}"
|
||||
Control.IsTemplateFocusTarget="True">
|
||||
<Grid x:Name="HorizontalTemplate" MinHeight="{ThemeResource SliderHorizontalHeight}">
|
||||
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="{ThemeResource SliderPreContentMargin}" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="{ThemeResource SliderPostContentMargin}" />
|
||||
</Grid.RowDefinitions>
|
||||
<Rectangle
|
||||
x:Name="HorizontalTrackRect"
|
||||
Grid.Row="1"
|
||||
Grid.ColumnSpan="3"
|
||||
Height="2"
|
||||
Fill="{TemplateBinding Background}" />
|
||||
<Rectangle
|
||||
x:Name="HorizontalDecreaseRect"
|
||||
Grid.Row="1"
|
||||
Fill="{TemplateBinding Foreground}" />
|
||||
<TickBar
|
||||
x:Name="TopTickBar"
|
||||
Grid.ColumnSpan="3"
|
||||
Height="{ThemeResource SliderOutsideTickBarThemeHeight}"
|
||||
Margin="0,0,0,4"
|
||||
VerticalAlignment="Bottom"
|
||||
Fill="{ThemeResource SliderTickBarFill}"
|
||||
Visibility="Collapsed" />
|
||||
<TickBar
|
||||
x:Name="HorizontalInlineTickBar"
|
||||
Grid.Row="1"
|
||||
Grid.ColumnSpan="3"
|
||||
Height="2"
|
||||
Fill="{ThemeResource SliderInlineTickBarFill}"
|
||||
Visibility="Collapsed" />
|
||||
<TickBar
|
||||
x:Name="BottomTickBar"
|
||||
Grid.Row="2"
|
||||
Grid.ColumnSpan="3"
|
||||
Height="{ThemeResource SliderOutsideTickBarThemeHeight}"
|
||||
Margin="0,4,0,0"
|
||||
VerticalAlignment="Top"
|
||||
Fill="{ThemeResource SliderTickBarFill}"
|
||||
Visibility="Collapsed" />
|
||||
<Thumb
|
||||
x:Name="HorizontalThumb"
|
||||
Grid.Row="0"
|
||||
Grid.RowSpan="3"
|
||||
Grid.Column="1"
|
||||
Width="2"
|
||||
Height="2"
|
||||
AutomationProperties.AccessibilityView="Raw"
|
||||
DataContext="{TemplateBinding Value}"
|
||||
FocusVisualMargin="-14,-6,-14,-6"
|
||||
Style="{StaticResource SliderThumbStyle}" />
|
||||
</Grid>
|
||||
<Grid
|
||||
x:Name="VerticalTemplate"
|
||||
MinWidth="{ThemeResource SliderVerticalWidth}"
|
||||
Visibility="Collapsed">
|
||||
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="{ThemeResource SliderPreContentMargin}" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="{ThemeResource SliderPostContentMargin}" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Rectangle
|
||||
x:Name="VerticalTrackRect"
|
||||
Grid.RowSpan="3"
|
||||
Grid.Column="1"
|
||||
Width="{ThemeResource SliderTrackThemeHeight}"
|
||||
Fill="{TemplateBinding Background}" />
|
||||
<Rectangle
|
||||
x:Name="VerticalDecreaseRect"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Fill="{TemplateBinding Foreground}" />
|
||||
<TickBar
|
||||
x:Name="LeftTickBar"
|
||||
Grid.RowSpan="3"
|
||||
Width="{ThemeResource SliderOutsideTickBarThemeHeight}"
|
||||
Margin="0,0,4,0"
|
||||
HorizontalAlignment="Right"
|
||||
Fill="{ThemeResource SliderTickBarFill}"
|
||||
Visibility="Collapsed" />
|
||||
<TickBar
|
||||
x:Name="VerticalInlineTickBar"
|
||||
Grid.RowSpan="3"
|
||||
Grid.Column="1"
|
||||
Width="{ThemeResource SliderTrackThemeHeight}"
|
||||
Fill="{ThemeResource SliderInlineTickBarFill}"
|
||||
Visibility="Collapsed" />
|
||||
<TickBar
|
||||
x:Name="RightTickBar"
|
||||
Grid.RowSpan="3"
|
||||
Grid.Column="2"
|
||||
Width="{ThemeResource SliderOutsideTickBarThemeHeight}"
|
||||
Margin="4,0,0,0"
|
||||
HorizontalAlignment="Left"
|
||||
Fill="{ThemeResource SliderTickBarFill}"
|
||||
Visibility="Collapsed" />
|
||||
<Thumb
|
||||
x:Name="VerticalThumb"
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="3"
|
||||
Width="24"
|
||||
Height="8"
|
||||
AutomationProperties.AccessibilityView="Raw"
|
||||
DataContext="{TemplateBinding Value}"
|
||||
FocusVisualMargin="-6,-14,-6,-14"
|
||||
Style="{StaticResource SliderThumbStyle}" />
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
</ResourceDictionary>
|
||||
@@ -0,0 +1,62 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
|
||||
<Style x:Key="InteractiveListViewHeaderStyle" TargetType="ListViewHeaderItem">
|
||||
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
|
||||
<Setter Property="FontSize" Value="{ThemeResource ListViewHeaderItemThemeFontSize}" />
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Setter Property="Margin" Value="0,0,0,4" />
|
||||
<Setter Property="Padding" Value="12,8,12,8" />
|
||||
<Setter Property="CornerRadius" Value="4" />
|
||||
<Setter Property="HorizontalContentAlignment" Value="Left" />
|
||||
<Setter Property="VerticalContentAlignment" Value="Center" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="ListViewHeaderItem">
|
||||
<Grid
|
||||
x:Name="RootGrid"
|
||||
Background="{TemplateBinding Background}"
|
||||
CornerRadius="{TemplateBinding CornerRadius}">
|
||||
<ContentPresenter
|
||||
x:Name="ContentPresenter"
|
||||
Padding="{TemplateBinding Padding}"
|
||||
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
Content="{TemplateBinding Content}"
|
||||
ContentTemplate="{TemplateBinding ContentTemplate}"
|
||||
ContentTransitions="{TemplateBinding ContentTransitions}" />
|
||||
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualStateGroup.Transitions>
|
||||
<VisualTransition GeneratedDuration="0:0:0.1" />
|
||||
</VisualStateGroup.Transitions>
|
||||
|
||||
<VisualState x:Name="Normal" />
|
||||
|
||||
<VisualState x:Name="PointerOver">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="RootGrid.Background" Value="{ThemeResource ListViewItemBackgroundPointerOver}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="Pressed">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="RootGrid.Background" Value="{ThemeResource ListViewItemBackgroundPressed}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="Disabled">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ContentPresenter.Opacity" Value="{ThemeResource ListViewItemDisabledThemeOpacity}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
</ResourceDictionary>
|
||||
@@ -4,7 +4,7 @@ using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.Models.Settings;
|
||||
using BetterLyrics.WinUI3.Parsers.LyricsParser;
|
||||
using BetterLyrics.WinUI3.Services.LyricsSearchService;
|
||||
using BetterLyrics.WinUI3.Services.MediaSessionsService;
|
||||
using BetterLyrics.WinUI3.Services.GSMTCService;
|
||||
using BetterLyrics.WinUI3.Services.SettingsService;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
@@ -20,7 +20,7 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
IRecipient<PropertyChangedMessage<SongInfo?>>
|
||||
{
|
||||
private readonly ILyricsSearchService _lyricsSearchService;
|
||||
private readonly IMediaSessionsService _mediaSessionsService;
|
||||
private readonly IGSMTCService _gsmtcService;
|
||||
private readonly ISettingsService _settingsService;
|
||||
|
||||
private LatestOnlyTaskRunner _lyricsSearchRunner = new();
|
||||
@@ -43,10 +43,10 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
[ObservableProperty]
|
||||
public partial bool IsSearching { get; set; } = false;
|
||||
|
||||
public LyricsSearchControlViewModel(ILyricsSearchService lyricsSearchService, IMediaSessionsService mediaSessionsService, ISettingsService settingsService)
|
||||
public LyricsSearchControlViewModel(ILyricsSearchService lyricsSearchService, IGSMTCService gsmtcService, ISettingsService settingsService)
|
||||
{
|
||||
_lyricsSearchService = lyricsSearchService;
|
||||
_mediaSessionsService = mediaSessionsService;
|
||||
_gsmtcService = gsmtcService;
|
||||
_settingsService = settingsService;
|
||||
|
||||
AppSettings = _settingsService.AppSettings;
|
||||
@@ -58,19 +58,19 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
{
|
||||
LyricsSearchResults.Clear();
|
||||
LyricsDataArr = null;
|
||||
if (_mediaSessionsService.CurrentSongInfo != null)
|
||||
if (_gsmtcService.CurrentSongInfo != null)
|
||||
{
|
||||
var found = GetMappedSongSearchQueryFromSettings();
|
||||
if (found == null)
|
||||
{
|
||||
MappedSongSearchQuery = new MappedSongSearchQuery
|
||||
{
|
||||
OriginalTitle = _mediaSessionsService.CurrentSongInfo.Title,
|
||||
OriginalArtist = _mediaSessionsService.CurrentSongInfo.DisplayArtists,
|
||||
OriginalAlbum = _mediaSessionsService.CurrentSongInfo.Album,
|
||||
MappedTitle = _mediaSessionsService.CurrentSongInfo.Title,
|
||||
MappedArtist = _mediaSessionsService.CurrentSongInfo.DisplayArtists,
|
||||
MappedAlbum = _mediaSessionsService.CurrentSongInfo.Album,
|
||||
OriginalTitle = _gsmtcService.CurrentSongInfo.Title,
|
||||
OriginalArtist = _gsmtcService.CurrentSongInfo.DisplayArtists,
|
||||
OriginalAlbum = _gsmtcService.CurrentSongInfo.Album,
|
||||
MappedTitle = _gsmtcService.CurrentSongInfo.Title,
|
||||
MappedArtist = _gsmtcService.CurrentSongInfo.DisplayArtists,
|
||||
MappedAlbum = _gsmtcService.CurrentSongInfo.Album,
|
||||
};
|
||||
}
|
||||
else
|
||||
@@ -82,16 +82,16 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
|
||||
private MappedSongSearchQuery? GetMappedSongSearchQueryFromSettings()
|
||||
{
|
||||
if (_mediaSessionsService.CurrentSongInfo == null)
|
||||
if (_gsmtcService.CurrentSongInfo == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var found = AppSettings.MappedSongSearchQueries
|
||||
.FirstOrDefault(x =>
|
||||
x.OriginalTitle == _mediaSessionsService.CurrentSongInfo.Title &&
|
||||
x.OriginalArtist == _mediaSessionsService.CurrentSongInfo.DisplayArtists &&
|
||||
x.OriginalAlbum == _mediaSessionsService.CurrentSongInfo.Album);
|
||||
x.OriginalTitle == _gsmtcService.CurrentSongInfo.Title &&
|
||||
x.OriginalArtist == _gsmtcService.CurrentSongInfo.DisplayArtists &&
|
||||
x.OriginalAlbum == _gsmtcService.CurrentSongInfo.Album);
|
||||
|
||||
return found;
|
||||
}
|
||||
@@ -102,7 +102,7 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
{
|
||||
return;
|
||||
}
|
||||
_mediaSessionsService.ChangePosition(value.StartMs / 1000.0);
|
||||
_gsmtcService.ChangePosition(value.StartMs / 1000.0);
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
@@ -121,7 +121,7 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
LyricsSearchResults = [..await Task.Run(async () =>
|
||||
{
|
||||
var result = await _lyricsSearchService.SearchAllAsync(
|
||||
((SongInfo?)_mediaSessionsService.CurrentSongInfo?.Clone() ?? new())
|
||||
((SongInfo?)_gsmtcService.CurrentSongInfo?.Clone() ?? new())
|
||||
.WithTitle(MappedSongSearchQuery.MappedTitle)
|
||||
.WithArtist(MappedSongSearchQuery.MappedArtist.SplitByCommonSplitter())
|
||||
.WithAlbum(MappedSongSearchQuery.MappedAlbum),
|
||||
@@ -196,9 +196,9 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
|
||||
public void Receive(PropertyChangedMessage<SongInfo?> message)
|
||||
{
|
||||
if (message.Sender is IMediaSessionsService)
|
||||
if (message.Sender is IGSMTCService)
|
||||
{
|
||||
if (message.PropertyName == nameof(IMediaSessionsService.CurrentSongInfo))
|
||||
if (message.PropertyName == nameof(IGSMTCService.CurrentSongInfo))
|
||||
{
|
||||
InitMappedSongSearchQuery();
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ using BetterLyrics.WinUI3.Models.Settings;
|
||||
using BetterLyrics.WinUI3.Services.FileSystemService;
|
||||
using BetterLyrics.WinUI3.Services.LocalizationService;
|
||||
using BetterLyrics.WinUI3.Services.SettingsService;
|
||||
using BetterLyrics.WinUI3.Services.SMTCService;
|
||||
using BetterLyrics.WinUI3.Views;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
@@ -43,16 +44,10 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
private readonly ILocalizationService _localizationService;
|
||||
private readonly IFileSystemService _fileSystemService;
|
||||
|
||||
private readonly MediaPlayer _mediaPlayer = new();
|
||||
private readonly MediaTimelineController _timelineController = new();
|
||||
private readonly SystemMediaTransportControls _smtc;
|
||||
[ObservableProperty] public partial ISMTCService SMTCService { get; set; }
|
||||
|
||||
private readonly DispatcherQueueTimer _refreshSongsTimer;
|
||||
|
||||
private IRandomAccessStream? _currentStream;
|
||||
private Stream? _currentNetStream;
|
||||
private IUnifiedFileSystem? _currentProvider;
|
||||
|
||||
// All songs
|
||||
private List<ExtendedTrack> _allTracks = [];
|
||||
// Songs in current playlist or songs in current file tree
|
||||
@@ -60,37 +55,22 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
// Filtered songs based on search query for current playlist
|
||||
private List<ExtendedTrack> _filteredTracks = [];
|
||||
|
||||
[ObservableProperty]
|
||||
public partial AppSettings AppSettings { get; set; }
|
||||
[ObservableProperty] public partial AppSettings AppSettings { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial bool IsLocalMediaNotFound { get; set; }
|
||||
[ObservableProperty] public partial bool IsLocalMediaNotFound { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Grouped tracks after filtering and sorting for current playlist
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
public partial ObservableCollection<GroupInfoList> GroupedTracks { get; set; } = [];
|
||||
[ObservableProperty] public partial ObservableCollection<GroupInfoList> GroupedTracks { get; set; } = [];
|
||||
|
||||
[ObservableProperty]
|
||||
public partial List<ExtendedTrack> SelectedTracks { get; set; } = [];
|
||||
[ObservableProperty] public partial List<ExtendedTrack> SelectedTracks { get; set; } = [];
|
||||
|
||||
[ObservableProperty]
|
||||
public partial int SelectedTracksTotalDuration { get; set; } = 0;
|
||||
[ObservableProperty] public partial int SelectedTracksTotalDuration { get; set; } = 0;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial ObservableCollection<PlayQueueItem> TrackPlayingQueue { get; set; }
|
||||
[ObservableProperty] public partial CommonSongProperty SongOrderType { get; set; } = CommonSongProperty.Title;
|
||||
|
||||
public PlayQueueItem? PlayingQueueItem => TrackPlayingQueue.ElementAtOrDefault(AppSettings.MusicGallerySettings.PlayQueueIndex);
|
||||
|
||||
[ObservableProperty]
|
||||
public partial ExtendedTrack? PlayingTrack { get; set; } = null;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial CommonSongProperty SongOrderType { get; set; } = CommonSongProperty.Title;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial int SelectedSongsTabInfoIndex { get; set; } = 0;
|
||||
[ObservableProperty] public partial int SelectedSongsTabInfoIndex { get; set; } = 0;
|
||||
|
||||
public SongsTabInfo? SelectedSongsTabInfo => AppSettings.StarredPlaylists.ElementAtOrDefault(SelectedSongsTabInfoIndex);
|
||||
|
||||
@@ -99,47 +79,32 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
|
||||
[ObservableProperty] public partial ExtendedTrack TrackRightTapped { get; set; } = new();
|
||||
|
||||
[ObservableProperty]
|
||||
public partial string SongSearchQuery { get; set; } = string.Empty;
|
||||
[ObservableProperty] public partial string SongSearchQuery { get; set; } = string.Empty;
|
||||
|
||||
[ObservableProperty] public partial ListViewSelectionMode SongListViewSelectionMode { get; set; } = ListViewSelectionMode.Single;
|
||||
|
||||
public ObservableCollection<FolderNode> FolderRoots { get; } = new();
|
||||
|
||||
public MusicGalleryPageViewModel(
|
||||
ISettingsService settingsService,
|
||||
ILocalizationService localizationService,
|
||||
IFileSystemService fileSystemService
|
||||
IFileSystemService fileSystemService,
|
||||
ISMTCService smtcService
|
||||
)
|
||||
{
|
||||
_localizationService = localizationService;
|
||||
_fileSystemService = fileSystemService;
|
||||
SMTCService = smtcService;
|
||||
|
||||
_refreshSongsTimer = _dispatcherQueue.CreateTimer();
|
||||
|
||||
_settingsService = settingsService;
|
||||
AppSettings = _settingsService.AppSettings;
|
||||
|
||||
TrackPlayingQueue = [.. AppSettings.MusicGallerySettings.PlayQueuePaths.Select(x => new PlayQueueItem(new ExtendedTrack(x)))];
|
||||
TrackPlayingQueue.CollectionChanged += TrackPlayingQueue_CollectionChanged;
|
||||
|
||||
RefreshSongs();
|
||||
|
||||
_settingsService.AppSettings.LocalMediaFolders.CollectionChanged += LocalMediaFolders_CollectionChanged;
|
||||
_settingsService.AppSettings.LocalMediaFolders.ItemPropertyChanged += LocalMediaFolders_ItemPropertyChanged;
|
||||
|
||||
_mediaPlayer.MediaOpened += MediaPlayer_MediaOpened;
|
||||
_mediaPlayer.MediaEnded += MediaPlayer_MediaEnded;
|
||||
_mediaPlayer.CommandManager.IsEnabled = false;
|
||||
|
||||
_timelineController = _mediaPlayer.TimelineController = new();
|
||||
_timelineController.PositionChanged += TimelineController_PositionChanged;
|
||||
|
||||
_smtc = _mediaPlayer.SystemMediaTransportControls;
|
||||
_smtc.IsPlayEnabled = true;
|
||||
_smtc.IsPauseEnabled = true;
|
||||
_smtc.IsNextEnabled = true;
|
||||
_smtc.IsPreviousEnabled = true;
|
||||
_smtc.ButtonPressed += Smtc_ButtonPressed;
|
||||
_smtc.PlaybackPositionChangeRequested += Smtc_PlaybackPositionChangeRequested;
|
||||
}
|
||||
|
||||
private void LocalMediaFolders_ItemPropertyChanged(object? sender, ItemPropertyChangedEventArgs e)
|
||||
@@ -147,134 +112,11 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
IsDataSyncError = AppSettings.LocalMediaFolders.Any(x => x.StatusSeverity == InfoBarSeverity.Error);
|
||||
}
|
||||
|
||||
private void TrackPlayingQueue_CollectionChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
AppSettings.MusicGallerySettings.PlayQueuePaths = [.. TrackPlayingQueue.Select(x => x.Track.Uri.ToDecodedAbsoluteUri())];
|
||||
}
|
||||
|
||||
private void LocalMediaFolders_CollectionChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
RefreshSongs();
|
||||
}
|
||||
|
||||
private void MediaPlayer_MediaEnded(MediaPlayer sender, object args)
|
||||
{
|
||||
PlayNextTrack();
|
||||
}
|
||||
|
||||
public void PlayNextTrack()
|
||||
{
|
||||
switch (AppSettings.MusicGallerySettings.PlaybackOrder)
|
||||
{
|
||||
case PlaybackOrder.RepeatAll:
|
||||
_dispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, async () =>
|
||||
{
|
||||
if (AppSettings.MusicGallerySettings.PlayQueueIndex < TrackPlayingQueue.Count - 1)
|
||||
{
|
||||
AppSettings.MusicGallerySettings.PlayQueueIndex++;
|
||||
}
|
||||
else
|
||||
{
|
||||
AppSettings.MusicGallerySettings.PlayQueueIndex = 0;
|
||||
}
|
||||
await PlayTrackAsync(PlayingQueueItem);
|
||||
});
|
||||
break;
|
||||
case PlaybackOrder.RepeatOne:
|
||||
_timelineController.Position = TimeSpan.Zero;
|
||||
break;
|
||||
case PlaybackOrder.Shuffle:
|
||||
_dispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, async () =>
|
||||
{
|
||||
if (TrackPlayingQueue.Count > 0)
|
||||
{
|
||||
AppSettings.MusicGallerySettings.PlayQueueIndex = new Random().Next(0, TrackPlayingQueue.Count);
|
||||
}
|
||||
await PlayTrackAsync(PlayingQueueItem);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void PlayPreviousTrack()
|
||||
{
|
||||
switch (AppSettings.MusicGallerySettings.PlaybackOrder)
|
||||
{
|
||||
case PlaybackOrder.RepeatAll:
|
||||
_dispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, async () =>
|
||||
{
|
||||
if (AppSettings.MusicGallerySettings.PlayQueueIndex > 0)
|
||||
{
|
||||
AppSettings.MusicGallerySettings.PlayQueueIndex--;
|
||||
}
|
||||
else
|
||||
{
|
||||
AppSettings.MusicGallerySettings.PlayQueueIndex = TrackPlayingQueue.Count - 1;
|
||||
}
|
||||
await PlayTrackAsync(PlayingQueueItem);
|
||||
});
|
||||
break;
|
||||
case PlaybackOrder.RepeatOne:
|
||||
_timelineController.Position = TimeSpan.Zero;
|
||||
break;
|
||||
case PlaybackOrder.Shuffle:
|
||||
_dispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, async () =>
|
||||
{
|
||||
if (TrackPlayingQueue.Count > 0)
|
||||
{
|
||||
AppSettings.MusicGallerySettings.PlayQueueIndex = new Random().Next(0, TrackPlayingQueue.Count);
|
||||
}
|
||||
await PlayTrackAsync(PlayingQueueItem);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void Smtc_PlaybackPositionChangeRequested(SystemMediaTransportControls sender, PlaybackPositionChangeRequestedEventArgs args)
|
||||
{
|
||||
_timelineController.Position = args.RequestedPlaybackPosition;
|
||||
}
|
||||
|
||||
private void MediaPlayer_MediaOpened(MediaPlayer sender, object args)
|
||||
{
|
||||
_timelineController.Start();
|
||||
_smtc.PlaybackStatus = MediaPlaybackStatus.Playing;
|
||||
}
|
||||
|
||||
private void TimelineController_PositionChanged(MediaTimelineController sender, object args)
|
||||
{
|
||||
_smtc.UpdateTimelineProperties(new SystemMediaTransportControlsTimelineProperties()
|
||||
{
|
||||
Position = sender.Position,
|
||||
EndTime = _mediaPlayer.PlaybackSession.NaturalDuration
|
||||
});
|
||||
}
|
||||
|
||||
private void Smtc_ButtonPressed(SystemMediaTransportControls sender, SystemMediaTransportControlsButtonPressedEventArgs args)
|
||||
{
|
||||
switch (args.Button)
|
||||
{
|
||||
case SystemMediaTransportControlsButton.Play:
|
||||
_smtc.PlaybackStatus = MediaPlaybackStatus.Playing;
|
||||
_timelineController.Resume();
|
||||
break;
|
||||
case SystemMediaTransportControlsButton.Pause:
|
||||
_smtc.PlaybackStatus = MediaPlaybackStatus.Paused;
|
||||
_timelineController.Pause();
|
||||
break;
|
||||
case SystemMediaTransportControlsButton.Next:
|
||||
PlayNextTrack();
|
||||
break;
|
||||
case SystemMediaTransportControlsButton.Previous:
|
||||
PlayPreviousTrack();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void CancelRefreshSongs()
|
||||
{
|
||||
}
|
||||
@@ -460,133 +302,6 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
ApplyPlaylist();
|
||||
}
|
||||
|
||||
public async Task PlayTrackAtAsync(int index)
|
||||
{
|
||||
await PlayTrackAsync(TrackPlayingQueue.ElementAtOrDefault(index));
|
||||
}
|
||||
|
||||
public async Task PlayTrackAsync(PlayQueueItem? playQueueItem)
|
||||
{
|
||||
_timelineController.Pause();
|
||||
_mediaPlayer.Source = null;
|
||||
|
||||
// 清理旧资源
|
||||
_currentStream?.Dispose();
|
||||
_currentNetStream?.Dispose();
|
||||
_currentStream = null;
|
||||
_currentNetStream = null;
|
||||
|
||||
if (playQueueItem == null)
|
||||
{
|
||||
_smtc.IsEnabled = false;
|
||||
_smtc.DisplayUpdater.ClearAll();
|
||||
}
|
||||
else
|
||||
{
|
||||
PlayingTrack = playQueueItem.Track;
|
||||
_smtc.IsEnabled = true;
|
||||
|
||||
try
|
||||
{
|
||||
var targetFolder = _settingsService.AppSettings.LocalMediaFolders.FirstOrDefault(f =>
|
||||
{
|
||||
var fUri = f.GetStandardUri().AbsoluteUri;
|
||||
return PlayingTrack.Uri.StartsWith(fUri, StringComparison.OrdinalIgnoreCase);
|
||||
});
|
||||
|
||||
if (targetFolder == null)
|
||||
{
|
||||
throw new FileNotFoundException(null, PlayingTrack.Uri.ToDecodedAbsoluteUri());
|
||||
}
|
||||
|
||||
_currentProvider = targetFolder.CreateFileSystem();
|
||||
if (_currentProvider == null) return;
|
||||
|
||||
await _currentProvider.ConnectAsync();
|
||||
|
||||
var fileCacheStub = new FilesIndexItem
|
||||
{
|
||||
Uri = PlayingTrack.Uri
|
||||
};
|
||||
|
||||
var sourceStream = await _fileSystemService.OpenFileAsync(_currentProvider, fileCacheStub);
|
||||
|
||||
if (sourceStream == null)
|
||||
{
|
||||
throw new FileNotFoundException(null, fileCacheStub.Uri);
|
||||
}
|
||||
|
||||
if (sourceStream.CanSeek)
|
||||
{
|
||||
_currentNetStream = sourceStream;
|
||||
}
|
||||
else
|
||||
{
|
||||
var memStream = new MemoryStream();
|
||||
|
||||
await sourceStream.CopyToAsync(memStream);
|
||||
memStream.Position = 0;
|
||||
|
||||
sourceStream.Dispose();
|
||||
|
||||
_currentNetStream = memStream;
|
||||
}
|
||||
|
||||
_currentStream = _currentNetStream.AsRandomAccessStream();
|
||||
|
||||
string contentType = GetMimeType(PlayingTrack.FileName);
|
||||
var mediaSource = MediaSource.CreateFromStream(_currentStream, contentType);
|
||||
|
||||
_mediaPlayer.Source = mediaSource;
|
||||
|
||||
var updater = _smtc.DisplayUpdater;
|
||||
updater.Type = MediaPlaybackType.Music;
|
||||
|
||||
updater.MusicProperties.Title = PlayingTrack.Title ?? PlayingTrack.FileName;
|
||||
updater.MusicProperties.Artist = PlayingTrack.Artist ?? "";
|
||||
updater.MusicProperties.AlbumTitle = PlayingTrack.Album ?? "";
|
||||
|
||||
updater.MusicProperties.Genres.Clear();
|
||||
updater.MusicProperties.Genres.Add($"{ExtendedGenreFiled.FileName}{Path.GetFileNameWithoutExtension(PlayingTrack.FileName)}");
|
||||
|
||||
updater.AppMediaId = Package.Current.Id.FullName;
|
||||
|
||||
if (!string.IsNullOrEmpty(PlayingTrack.LocalAlbumArtPath) && File.Exists(PlayingTrack.LocalAlbumArtPath))
|
||||
{
|
||||
var storageFile = await StorageFile.GetFileFromPathAsync(PlayingTrack.LocalAlbumArtPath);
|
||||
updater.Thumbnail = RandomAccessStreamReference.CreateFromFile(storageFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
updater.Thumbnail = null;
|
||||
}
|
||||
|
||||
updater.Update();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ToastHelper.ShowToast("Error", ex.Message, InfoBarSeverity.Error);
|
||||
_timelineController.Pause();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string GetMimeType(string path)
|
||||
{
|
||||
var ext = Path.GetExtension(path).ToLower();
|
||||
return ext switch
|
||||
{
|
||||
".mp3" => "audio/mpeg",
|
||||
".flac" => "audio/flac",
|
||||
".wav" => "audio/wav",
|
||||
".m4a" => "audio/mp4",
|
||||
".aac" => "audio/aac",
|
||||
".ogg" => "audio/ogg",
|
||||
".wma" => "audio/x-ms-wma",
|
||||
_ => "application/octet-stream"
|
||||
};
|
||||
}
|
||||
|
||||
partial void OnSongOrderTypeChanged(CommonSongProperty value)
|
||||
{
|
||||
ApplySongOrderType();
|
||||
@@ -641,7 +356,7 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
[RelayCommand]
|
||||
private async Task StopTrackAsync()
|
||||
{
|
||||
await PlayTrackAtAsync(-1);
|
||||
await SMTCService.PlayTrackAtAsync(-1);
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
@@ -652,6 +367,15 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
settingsPageViewModel.NavViewSelectedItemTag = "MediaLib";
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void ToggleSongListViewSelectionMode()
|
||||
{
|
||||
SongListViewSelectionMode =
|
||||
SongListViewSelectionMode == ListViewSelectionMode.Single ?
|
||||
ListViewSelectionMode.Multiple :
|
||||
ListViewSelectionMode.Single;
|
||||
}
|
||||
|
||||
public void Receive(PropertyChangedMessage<DateTime?> message)
|
||||
{
|
||||
if (message.Sender is MediaFolder)
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
using BetterLyrics.WinUI3.Extensions;
|
||||
using BetterLyrics.WinUI3.Hooks;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.Services.MediaSessionsService;
|
||||
using BetterLyrics.WinUI3.Services.GSMTCService;
|
||||
using BetterLyrics.WinUI3.Services.SMTCService;
|
||||
using BetterLyrics.WinUI3.Views;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
@@ -11,7 +12,9 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
{
|
||||
public partial class NowPlayingBarViewModel : BaseViewModel
|
||||
{
|
||||
public IMediaSessionsService MediaSessionsService { get; private set; }
|
||||
public IGSMTCService GSMTCService { get; private set; }
|
||||
|
||||
private readonly ISMTCService _smtcService;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial int Volume { get; set; }
|
||||
@@ -31,9 +34,10 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
[ObservableProperty]
|
||||
public partial double BottomCommandFlyoutTriggerOpacity { get; set; }
|
||||
|
||||
public NowPlayingBarViewModel(IMediaSessionsService mediaSessionsService)
|
||||
public NowPlayingBarViewModel(IGSMTCService mediaSessionsService, ISMTCService smtcService)
|
||||
{
|
||||
MediaSessionsService = mediaSessionsService;
|
||||
GSMTCService = mediaSessionsService;
|
||||
_smtcService = smtcService;
|
||||
|
||||
Volume = SystemVolumeHook.MasterVolume;
|
||||
SystemVolumeHook.VolumeNotification += SystemVolumeHelper_VolumeNotification;
|
||||
@@ -46,32 +50,38 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
|
||||
partial void OnTimelineSliderThumbSecondsChanged(double value)
|
||||
{
|
||||
TimelineSliderThumbLyricsLine = MediaSessionsService.CurrentLyricsData?.GetLyricsLine(value);
|
||||
TimelineSliderThumbLyricsLine = GSMTCService.CurrentLyricsData?.GetLyricsLine(value);
|
||||
}
|
||||
|
||||
|
||||
[RelayCommand]
|
||||
private async Task PlaySongAsync()
|
||||
{
|
||||
await MediaSessionsService.PlayAsync();
|
||||
await GSMTCService.PlayAsync();
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task PauseSongAsync()
|
||||
{
|
||||
await MediaSessionsService.PauseAsync();
|
||||
await GSMTCService.PauseAsync();
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task PreviousSongAsync()
|
||||
{
|
||||
await MediaSessionsService.PreviousAsync();
|
||||
await GSMTCService.PreviousAsync();
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task NextSongAsync()
|
||||
{
|
||||
await MediaSessionsService.NextAsync();
|
||||
await GSMTCService.NextAsync();
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task StopTrackAsync()
|
||||
{
|
||||
await _smtcService.PlayTrackAtAsync(-1);
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
using BetterLyrics.WinUI3.Hooks;
|
||||
|
||||
using BetterLyrics.WinUI3.Services.MediaSessionsService;
|
||||
using BetterLyrics.WinUI3.Services.GSMTCService;
|
||||
using BetterLyrics.WinUI3.Views;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
|
||||
@@ -10,9 +10,9 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
{
|
||||
public partial class NowPlayingPageViewModel : BaseViewModel
|
||||
{
|
||||
public IMediaSessionsService MediaSessionsService { get; private set; }
|
||||
public IGSMTCService MediaSessionsService { get; private set; }
|
||||
|
||||
public NowPlayingPageViewModel(IMediaSessionsService mediaSessionsService)
|
||||
public NowPlayingPageViewModel(IGSMTCService mediaSessionsService)
|
||||
{
|
||||
MediaSessionsService = mediaSessionsService;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
using BetterLyrics.WinUI3.Controls;
|
||||
using BetterLyrics.WinUI3.Models.Settings;
|
||||
using BetterLyrics.WinUI3.Services.SettingsService;
|
||||
using BetterLyrics.WinUI3.Services.SMTCService;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace BetterLyrics.WinUI3.ViewModels
|
||||
{
|
||||
public partial class PlayQueueViewModel : BaseViewModel
|
||||
{
|
||||
private readonly ISettingsService _settingsService;
|
||||
|
||||
public ISMTCService SMTCService { get; set; }
|
||||
|
||||
[ObservableProperty] public partial AppSettings AppSettings { get; set; }
|
||||
|
||||
public PlayQueueViewModel(ISMTCService smtcService, ISettingsService settingsService)
|
||||
{
|
||||
_settingsService = settingsService;
|
||||
SMTCService = smtcService;
|
||||
AppSettings = _settingsService.AppSettings;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.Models.Settings;
|
||||
using BetterLyrics.WinUI3.Services.LastFMService;
|
||||
using BetterLyrics.WinUI3.Services.MediaSessionsService;
|
||||
using BetterLyrics.WinUI3.Services.GSMTCService;
|
||||
|
||||
using BetterLyrics.WinUI3.Services.SettingsService;
|
||||
using BetterLyrics.WinUI3.Services.TranslationService;
|
||||
@@ -20,7 +20,7 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
{
|
||||
public partial class PlaybackSettingsControlViewModel : BaseViewModel
|
||||
{
|
||||
public IMediaSessionsService MediaSessionsService;
|
||||
public IGSMTCService GSMTCService;
|
||||
private readonly ITranslationService _translationService;
|
||||
private readonly ILastFMService _lastFMService;
|
||||
private readonly ISettingsService _settingsService;
|
||||
@@ -55,12 +55,12 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
|
||||
public PlaybackSettingsControlViewModel(
|
||||
ISettingsService settingsService,
|
||||
IMediaSessionsService mediaSessionsService,
|
||||
IGSMTCService gsmtcService,
|
||||
ITranslationService libreTranslationService,
|
||||
ILastFMService lastFMService,
|
||||
ITransliterationService transliterationService)
|
||||
{
|
||||
MediaSessionsService = mediaSessionsService;
|
||||
GSMTCService = gsmtcService;
|
||||
|
||||
_settingsService = settingsService;
|
||||
_translationService = libreTranslationService;
|
||||
@@ -206,7 +206,7 @@ namespace BetterLyrics.WinUI3.ViewModels
|
||||
{
|
||||
PasswordVaultHelper.Delete(Constants.App.AppName, Constants.AppleMusic.MediaUserTokenKey);
|
||||
PasswordVaultHelper.Save(Constants.App.AppName, Constants.AppleMusic.MediaUserTokenKey, AppleMusicMediaUserToken);
|
||||
MediaSessionsService.UpdateLyrics();
|
||||
GSMTCService.UpdateLyrics();
|
||||
}
|
||||
|
||||
partial void OnSelectedTargetLanguageIndexChanged(int value)
|
||||
|
||||
@@ -204,8 +204,12 @@
|
||||
|
||||
<controls:ContentSizer Grid.Column="1" TargetControl="{x:Bind LeftSidePanel}" />
|
||||
|
||||
<Grid x:Name="SongViewer" Grid.Column="2">
|
||||
<Grid
|
||||
x:Name="SongViewer"
|
||||
Grid.Column="2"
|
||||
RowSpacing="3">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" MinHeight="34" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
@@ -260,84 +264,105 @@
|
||||
</Flyout>
|
||||
</Grid.Tag>
|
||||
|
||||
<StackPanel Grid.Row="0" Spacing="6">
|
||||
|
||||
<AutoSuggestBox
|
||||
x:Name="SongSearchBox"
|
||||
x:Uid="MusicGalleryPageSongSearchBox"
|
||||
Margin="0,0,128,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
QueryIcon="Find"
|
||||
Text="{x:Bind ViewModel.SongSearchQuery, Mode=TwoWay}" />
|
||||
|
||||
<Grid>
|
||||
<StackPanel
|
||||
HorizontalAlignment="Left"
|
||||
Orientation="Horizontal"
|
||||
Spacing="6">
|
||||
|
||||
<CheckBox
|
||||
x:Name="SelectAllCheckBox"
|
||||
MinWidth="20"
|
||||
VerticalAlignment="Center"
|
||||
Checked="SelectAllCheckBox_Checked"
|
||||
Unchecked="SelectAllCheckBox_Unchecked"
|
||||
Visibility="{Binding ElementName=SongListViewSelectionModeToggleButton, Path=IsChecked, Converter={StaticResource BoolToVisibilityConverter}, Mode=OneWay}" />
|
||||
|
||||
<StackPanel VerticalAlignment="Center" Orientation="Horizontal">
|
||||
<TextBlock Foreground="{ThemeResource TextFillColorSecondaryBrush}" Text="{x:Bind ViewModel.SelectedTracks.Count, Mode=OneWay}" />
|
||||
<TextBlock Foreground="{ThemeResource TextFillColorSecondaryBrush}" Text="/" />
|
||||
<TextBlock Text="{x:Bind GroupedTracksCVS.View.Count, Mode=OneWay}" />
|
||||
</StackPanel>
|
||||
<StackPanel VerticalAlignment="Center" Orientation="Horizontal">
|
||||
<TextBlock Text="{x:Bind ViewModel.SelectedTracksTotalDuration, Mode=OneWay, Converter={StaticResource SecondsToFormattedTimeConverter}}" />
|
||||
</StackPanel>
|
||||
|
||||
</StackPanel>
|
||||
<StackPanel
|
||||
HorizontalAlignment="Right"
|
||||
Orientation="Horizontal"
|
||||
Spacing="6">
|
||||
<StackPanel Orientation="Horizontal" Spacing="12">
|
||||
<TextBlock
|
||||
x:Uid="MusicGalleryPageSortType"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource BodyStrongTextBlockStyle}" />
|
||||
<controls:Segmented
|
||||
x:Name="Segmented"
|
||||
SelectedIndex="{x:Bind ViewModel.SongOrderType, Converter={StaticResource EnumToIntConverter}, Mode=TwoWay}"
|
||||
SelectionMode="Single">
|
||||
<controls:SegmentedItem x:Uid="MusicGalleryPageSortByTitle" Icon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}" />
|
||||
<controls:SegmentedItem x:Uid="MusicGalleryPageSortByAlbum" Icon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}" />
|
||||
<controls:SegmentedItem x:Uid="MusicGalleryPageSortByArtist" Icon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}" />
|
||||
<controls:SegmentedItem x:Uid="MusicGalleryPageSortByFolder" Icon="{ui:FontIcon FontFamily={StaticResource IconFontFamily}, Glyph=}" />
|
||||
</controls:Segmented>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
</StackPanel>
|
||||
|
||||
<InfoBar
|
||||
x:Uid="MusicGalleryPageDataSync"
|
||||
Grid.Row="1"
|
||||
Grid.Row="0"
|
||||
IsClosable="False"
|
||||
IsOpen="{x:Bind ViewModel.IsDataSyncing, Mode=OneWay}" />
|
||||
|
||||
<InfoBar
|
||||
x:Uid="MusicGalleryPageDataSyncError"
|
||||
Grid.Row="1"
|
||||
Grid.Row="0"
|
||||
IsClosable="False"
|
||||
IsOpen="{x:Bind ViewModel.IsDataSyncError, Mode=OneWay}"
|
||||
Severity="Error" />
|
||||
|
||||
<SemanticZoom Grid.Row="2">
|
||||
<!-- 命令览 -->
|
||||
<Grid Grid.Row="1" ColumnSpacing="6">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- 切换选择模式 -->
|
||||
<ToggleButton
|
||||
x:Name="SongListViewSelectionModeToggleButton"
|
||||
Grid.Column="0"
|
||||
Command="{x:Bind ViewModel.ToggleSongListViewSelectionModeCommand}"
|
||||
Content="{ui:FontIcon FontSize=16,
|
||||
FontFamily={StaticResource IconFontFamily},
|
||||
Glyph=}"
|
||||
Style="{StaticResource GhostToggleButtonStyle}" />
|
||||
|
||||
<!-- 为多选模式保留 -->
|
||||
<Grid Grid.Column="1" Visibility="{Binding ElementName=SongListViewSelectionModeToggleButton, Path=IsChecked, Converter={StaticResource BoolToVisibilityConverter}, Mode=OneWay}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
<CheckBox
|
||||
x:Name="SelectAllCheckBox"
|
||||
Grid.Column="0"
|
||||
MinWidth="20"
|
||||
VerticalAlignment="Center"
|
||||
Checked="SelectAllCheckBox_Checked"
|
||||
Unchecked="SelectAllCheckBox_Unchecked" />
|
||||
<RichTextBlock Grid.Column="1" VerticalAlignment="Center">
|
||||
<Paragraph>
|
||||
<Run Text="{x:Bind ViewModel.SelectedTracks.Count, Mode=OneWay}" />
|
||||
<Run Text="/" />
|
||||
<Run Text="{x:Bind GroupedTracksCVS.View.Count, Mode=OneWay}" />
|
||||
<Run Text="{x:Bind ViewModel.SelectedTracksTotalDuration, Mode=OneWay, Converter={StaticResource SecondsToFormattedTimeConverter}}" />
|
||||
</Paragraph>
|
||||
</RichTextBlock>
|
||||
|
||||
</Grid>
|
||||
|
||||
<AppBarSeparator Grid.Column="2" />
|
||||
|
||||
<!-- 排序选择 -->
|
||||
<Grid Grid.Column="3" ColumnSpacing="12">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock
|
||||
x:Uid="MusicGalleryPageSortType"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource BodyStrongTextBlockStyle}" />
|
||||
<ComboBox Grid.Column="1" SelectedIndex="{x:Bind ViewModel.SongOrderType, Converter={StaticResource EnumToIntConverter}, Mode=TwoWay}">
|
||||
<ComboBoxItem x:Uid="MusicGalleryPageSortByTitle" />
|
||||
<ComboBoxItem x:Uid="MusicGalleryPageSortByAlbum" />
|
||||
<ComboBoxItem x:Uid="MusicGalleryPageSortByArtist" />
|
||||
<ComboBoxItem x:Uid="MusicGalleryPageSortByFolder" />
|
||||
</ComboBox>
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Column="4">
|
||||
<AutoSuggestBox
|
||||
x:Name="SongSearchBox"
|
||||
x:Uid="MusicGalleryPageSongSearchBox"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
QueryIcon="Find"
|
||||
Text="{x:Bind ViewModel.SongSearchQuery, Mode=TwoWay}" />
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
|
||||
<NavigationViewItemSeparator Grid.Row="2" />
|
||||
|
||||
<SemanticZoom Grid.Row="3">
|
||||
<SemanticZoom.ZoomedInView>
|
||||
<ListView
|
||||
x:Name="SongListView"
|
||||
ItemsSource="{x:Bind GroupedTracksCVS.View, Mode=OneWay}"
|
||||
SelectionChanged="SongListView_SelectionChanged"
|
||||
SelectionMode="Multiple">
|
||||
SelectionMode="{x:Bind ViewModel.SongListViewSelectionMode, Mode=TwoWay}">
|
||||
<ListView.ContextFlyout>
|
||||
<MenuBarItemFlyout Opened="AddToMenuBarItemFlyout_Opened">
|
||||
<MenuFlyoutSubItem x:Uid="MusicGalleryPageAddToPlayingQueue" IsEnabled="{x:Bind ViewModel.SelectedTracks.Count, Mode=OneWay, Converter={StaticResource IntToBoolConverter}}">
|
||||
@@ -421,14 +446,12 @@
|
||||
</ListView.ItemsPanel>
|
||||
<ListView.GroupStyle>
|
||||
<GroupStyle>
|
||||
<GroupStyle.HeaderContainerStyle>
|
||||
<Style BasedOn="{StaticResource InteractiveListViewHeaderStyle}" TargetType="ListViewHeaderItem" />
|
||||
</GroupStyle.HeaderContainerStyle>
|
||||
<GroupStyle.HeaderTemplate>
|
||||
<DataTemplate x:DataType="models:GroupInfoList">
|
||||
<Border AutomationProperties.AccessibilityView="Raw">
|
||||
<TextBlock
|
||||
AutomationProperties.AccessibilityView="Raw"
|
||||
Style="{ThemeResource SubtitleTextBlockStyle}"
|
||||
Text="{x:Bind}" />
|
||||
</Border>
|
||||
<TextBlock Text="{x:Bind}" />
|
||||
</DataTemplate>
|
||||
</GroupStyle.HeaderTemplate>
|
||||
</GroupStyle>
|
||||
@@ -441,9 +464,7 @@
|
||||
MaxWidth="500"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
ItemsSource="{x:Bind GroupedTracksCVS.View.CollectionGroups, Mode=OneWay}"
|
||||
ScrollViewer.IsHorizontalScrollChainingEnabled="False"
|
||||
SelectionMode="None">
|
||||
ItemsSource="{x:Bind GroupedTracksCVS.View.CollectionGroups, Mode=OneWay}">
|
||||
<GridView.ItemTemplate>
|
||||
<DataTemplate x:DataType="models:GroupInfoList">
|
||||
<TextBlock Style="{ThemeResource TitleTextBlockStyle}" Text="{Binding}" />
|
||||
@@ -453,7 +474,7 @@
|
||||
</SemanticZoom.ZoomedOutView>
|
||||
</SemanticZoom>
|
||||
|
||||
<Grid Grid.Row="2" Visibility="{x:Bind ViewModel.IsLocalMediaNotFound, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
<Grid Grid.Row="3" Visibility="{x:Bind ViewModel.IsLocalMediaNotFound, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
<StackPanel
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
@@ -470,155 +491,5 @@
|
||||
|
||||
</Grid>
|
||||
|
||||
<Grid
|
||||
x:Name="PlayQueue"
|
||||
Width="300"
|
||||
Margin="0,4,4,72"
|
||||
Padding="12,16,12,0"
|
||||
HorizontalAlignment="Right"
|
||||
Background="{ThemeResource AcrylicBackgroundFillColorDefaultBrush}"
|
||||
BorderBrush="{ThemeResource ControlElevationBorderBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="8"
|
||||
Translation="310,0,0">
|
||||
<Grid.TranslationTransition>
|
||||
<Vector3Transition />
|
||||
</Grid.TranslationTransition>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid Grid.Row="0">
|
||||
<TextBlock
|
||||
x:Uid="MusicGalleryPagePlayingQueue"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource BodyStrongTextBlockStyle}" />
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Row="2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<StackPanel
|
||||
Grid.Column="0"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Center"
|
||||
Orientation="Horizontal">
|
||||
<TextBlock Foreground="{ThemeResource TextFillColorSecondaryBrush}" Text="{x:Bind ViewModel.AppSettings.MusicGallerySettings.PlayQueueIndex, Mode=OneWay, Converter={StaticResource IndexToDisplayConverter}}" />
|
||||
<TextBlock Foreground="{ThemeResource TextFillColorSecondaryBrush}" Text="/" />
|
||||
<TextBlock Text="{x:Bind ViewModel.TrackPlayingQueue.Count, Mode=OneWay}" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Stop media session -->
|
||||
<Button
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Right"
|
||||
Command="{x:Bind ViewModel.StopTrackCommand}"
|
||||
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
FontSize=16,
|
||||
Glyph=}"
|
||||
Style="{StaticResource GhostButtonStyle}">
|
||||
<ToolTipService.ToolTip>
|
||||
<TextBlock x:Uid="MusicGalleryPageStopTrack" />
|
||||
</ToolTipService.ToolTip>
|
||||
</Button>
|
||||
<!-- Scroll to playing item -->
|
||||
<Button
|
||||
Grid.Column="3"
|
||||
HorizontalAlignment="Right"
|
||||
Click="ScrollToPlayingItemButton_Click"
|
||||
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
FontSize=16,
|
||||
Glyph=}"
|
||||
Style="{StaticResource GhostButtonStyle}">
|
||||
<ToolTipService.ToolTip>
|
||||
<TextBlock x:Uid="MusicGalleryPageScrollToPlayingItem" />
|
||||
</ToolTipService.ToolTip>
|
||||
</Button>
|
||||
<!-- Empty play queue -->
|
||||
<Button
|
||||
Grid.Column="4"
|
||||
HorizontalAlignment="Right"
|
||||
Click="EmptyPlayingQueueButton_Click"
|
||||
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
FontSize=16,
|
||||
Glyph=}"
|
||||
Style="{StaticResource GhostButtonStyle}">
|
||||
<ToolTipService.ToolTip>
|
||||
<TextBlock x:Uid="MusicGalleryPageEmptyPlayingQueue" />
|
||||
</ToolTipService.ToolTip>
|
||||
</Button>
|
||||
</Grid>
|
||||
|
||||
<ListView
|
||||
x:Name="PlayingQueueListView"
|
||||
Grid.Row="3"
|
||||
ItemsSource="{x:Bind ViewModel.TrackPlayingQueue, Mode=OneWay}"
|
||||
SelectedIndex="{x:Bind ViewModel.AppSettings.MusicGallerySettings.PlayQueueIndex, Mode=TwoWay}">
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid Padding="0,6">
|
||||
<Grid Tapped="PlayingQueueListVireItemGrid_Tapped">
|
||||
<StackPanel Margin="0,0,36,0">
|
||||
<TextBlock Text="{Binding Track.Title}" TextWrapping="Wrap" />
|
||||
<TextBlock
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
Text="{Binding Track.Artist}"
|
||||
TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<Grid HorizontalAlignment="Right">
|
||||
<Button
|
||||
Click="RemoveFromPlayingQueueButton_Click"
|
||||
Content="{ui:FontIcon FontFamily={StaticResource IconFontFamily},
|
||||
FontSize=16,
|
||||
Glyph=}"
|
||||
Style="{StaticResource GhostButtonStyle}">
|
||||
<ToolTipService.ToolTip>
|
||||
<TextBlock x:Uid="MusicGalleryPageRemoveFromPlayingQueue" />
|
||||
</ToolTipService.ToolTip>
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
|
||||
<Grid Grid.Row="3">
|
||||
<interactivity:Interaction.Behaviors>
|
||||
<interactivity:DataTriggerBehavior
|
||||
Binding="{x:Bind ViewModel.TrackPlayingQueue.Count, Mode=OneWay}"
|
||||
ComparisonCondition="Equal"
|
||||
Value="0">
|
||||
<interactivity:ChangePropertyAction PropertyName="Visibility" Value="Visible" />
|
||||
</interactivity:DataTriggerBehavior>
|
||||
<interactivity:DataTriggerBehavior
|
||||
Binding="{x:Bind ViewModel.TrackPlayingQueue.Count, Mode=OneWay}"
|
||||
ComparisonCondition="NotEqual"
|
||||
Value="0">
|
||||
<interactivity:ChangePropertyAction PropertyName="Visibility" Value="Collapsed" />
|
||||
</interactivity:DataTriggerBehavior>
|
||||
</interactivity:Interaction.Behaviors>
|
||||
<StackPanel
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Spacing="12">
|
||||
<Image MaxWidth="100" Source="/Assets/EmptyBox.png" />
|
||||
<TextBlock
|
||||
x:Uid="MusicGalleryPagePlayingQueueEmpty"
|
||||
HorizontalAlignment="Center"
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
</Page>
|
||||
|
||||
@@ -3,7 +3,7 @@ using BetterLyrics.WinUI3.Extensions;
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.Models.Settings;
|
||||
|
||||
using BetterLyrics.WinUI3.Services.SMTCService;
|
||||
using BetterLyrics.WinUI3.ViewModels;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using DevWinUI;
|
||||
@@ -14,6 +14,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
// To learn more about WinUI, the WinUI project structure,
|
||||
// and more about our project templates, see: http://aka.ms/winui-project-info.
|
||||
@@ -26,48 +27,12 @@ namespace BetterLyrics.WinUI3.Views
|
||||
public sealed partial class MusicGalleryPage : Page
|
||||
{
|
||||
public MusicGalleryPageViewModel ViewModel => (MusicGalleryPageViewModel)DataContext;
|
||||
|
||||
public bool IsPlayingQueueOpened
|
||||
{
|
||||
get { return (bool)GetValue(IsPlayingQueueOpenedProperty); }
|
||||
set { SetValue(IsPlayingQueueOpenedProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsPlayingQueueOpenedProperty =
|
||||
DependencyProperty.Register(nameof(IsPlayingQueueOpened), typeof(bool), typeof(MusicGalleryPage), new PropertyMetadata(false, OnDependencyPropertyChanged));
|
||||
private readonly ISMTCService _smtcService = Ioc.Default.GetRequiredService<ISMTCService>();
|
||||
|
||||
public MusicGalleryPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContext = Ioc.Default.GetRequiredService<MusicGalleryPageViewModel>();
|
||||
ViewModel.AppSettings.MusicGallerySettings.PropertyChanged += MusicGallerySettings_PropertyChanged;
|
||||
}
|
||||
|
||||
private static void OnDependencyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is MusicGalleryPage self)
|
||||
{
|
||||
if (e.Property == IsPlayingQueueOpenedProperty)
|
||||
{
|
||||
var newValue = (bool)e.NewValue;
|
||||
self.PlayQueue.Translation = newValue ? new() : new(310, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ScrollToPlayingItem()
|
||||
{
|
||||
if (ViewModel.PlayingQueueItem == null) return;
|
||||
if (PlayingQueueListView == null) return;
|
||||
PlayingQueueListView.ScrollIntoView(ViewModel.PlayingQueueItem);
|
||||
}
|
||||
|
||||
private void MusicGallerySettings_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName == nameof(MusicGallerySettings.PlayQueueIndex))
|
||||
{
|
||||
ScrollToPlayingItem();
|
||||
}
|
||||
}
|
||||
|
||||
private async void SongPathHyperlinkButton_Click(object sender, RoutedEventArgs e)
|
||||
@@ -75,69 +40,25 @@ namespace BetterLyrics.WinUI3.Views
|
||||
await LauncherHelper.SelectAndShowFile(((ExtendedTrack)((HyperlinkButton)sender).DataContext).Uri.ToDecodedAbsoluteUri());
|
||||
}
|
||||
|
||||
private async void PlayingQueueListVireItemGrid_Tapped(object sender, TappedRoutedEventArgs e)
|
||||
{
|
||||
var item = (PlayQueueItem)((FrameworkElement)sender).DataContext;
|
||||
await ViewModel.PlayTrackAsync(item);
|
||||
PlayingQueueListView.ScrollIntoView(item);
|
||||
}
|
||||
|
||||
private async void EmptyPlayingQueueButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ViewModel.TrackPlayingQueue.Clear();
|
||||
ViewModel.AppSettings.MusicGallerySettings.PlayQueueIndex = -1;
|
||||
await ViewModel.PlayTrackAtAsync(ViewModel.AppSettings.MusicGallerySettings.PlayQueueIndex);
|
||||
}
|
||||
|
||||
private void ScrollToPlayingItemButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ScrollToPlayingItem();
|
||||
}
|
||||
|
||||
private async void RemoveFromPlayingQueueButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
bool playNext = false;
|
||||
var item = (PlayQueueItem)((FrameworkElement)sender).DataContext;
|
||||
int index = ViewModel.TrackPlayingQueue.IndexOf(item);
|
||||
if (item == ViewModel.PlayingQueueItem)
|
||||
{
|
||||
playNext = true;
|
||||
}
|
||||
ViewModel.TrackPlayingQueue.Remove(item);
|
||||
if (playNext)
|
||||
{
|
||||
if (ViewModel.TrackPlayingQueue.Count == 0)
|
||||
{
|
||||
index = -1;
|
||||
}
|
||||
else if (index >= ViewModel.TrackPlayingQueue.Count)
|
||||
{
|
||||
index = ViewModel.TrackPlayingQueue.Count - 1;
|
||||
}
|
||||
ViewModel.AppSettings.MusicGallerySettings.PlayQueueIndex = index;
|
||||
await ViewModel.PlayTrackAtAsync(ViewModel.AppSettings.MusicGallerySettings.PlayQueueIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private async void AddSongToQueueNextMenuFlyoutItem_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
bool startPlaying = ViewModel.TrackPlayingQueue.Count == 0;
|
||||
ViewModel.TrackPlayingQueue.InsertRange(ViewModel.AppSettings.MusicGallerySettings.PlayQueueIndex + 1, SongListView.SelectedItems.Cast<ExtendedTrack>().Select(x => new PlayQueueItem(x)));
|
||||
bool startPlaying = _smtcService.TrackPlayingQueue.Count == 0;
|
||||
_smtcService.TrackPlayingQueue.InsertRange(ViewModel.AppSettings.MusicGallerySettings.PlayQueueIndex + 1, SongListView.SelectedItems.Cast<ExtendedTrack>().Select(x => new PlayQueueItem(x)));
|
||||
if (startPlaying)
|
||||
{
|
||||
ViewModel.AppSettings.MusicGallerySettings.PlayQueueIndex = ViewModel.AppSettings.MusicGallerySettings.PlayQueueIndex + 1;
|
||||
await ViewModel.PlayTrackAtAsync(ViewModel.AppSettings.MusicGallerySettings.PlayQueueIndex);
|
||||
await _smtcService.PlayTrackAtAsync(ViewModel.AppSettings.MusicGallerySettings.PlayQueueIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private async void AddSongToQueueEndMenuFlyoutItem_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
bool startPlaying = ViewModel.TrackPlayingQueue.Count == 0;
|
||||
ViewModel.TrackPlayingQueue.AddRange(SongListView.SelectedItems.Cast<ExtendedTrack>().Select(x => new PlayQueueItem(x)));
|
||||
bool startPlaying = _smtcService.TrackPlayingQueue.Count == 0;
|
||||
_smtcService.TrackPlayingQueue.AddRange(SongListView.SelectedItems.Cast<ExtendedTrack>().Select(x => new PlayQueueItem(x)));
|
||||
if (startPlaying)
|
||||
{
|
||||
ViewModel.AppSettings.MusicGallerySettings.PlayQueueIndex = ViewModel.AppSettings.MusicGallerySettings.PlayQueueIndex + 1;
|
||||
await ViewModel.PlayTrackAtAsync(ViewModel.AppSettings.MusicGallerySettings.PlayQueueIndex);
|
||||
await _smtcService.PlayTrackAtAsync(ViewModel.AppSettings.MusicGallerySettings.PlayQueueIndex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,7 +150,10 @@ namespace BetterLyrics.WinUI3.Views
|
||||
|
||||
private void SelectAllCheckBox_Checked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
SongListView.SelectAll();
|
||||
if (ViewModel.SongListViewSelectionMode == ListViewSelectionMode.Multiple)
|
||||
{
|
||||
SongListView.SelectAll();
|
||||
}
|
||||
}
|
||||
|
||||
private void SelectAllCheckBox_Unchecked(object sender, RoutedEventArgs e)
|
||||
@@ -243,12 +167,12 @@ namespace BetterLyrics.WinUI3.Views
|
||||
var track = (ExtendedTrack)((FrameworkElement)sender).DataContext;
|
||||
|
||||
// Play all the songs
|
||||
ViewModel.TrackPlayingQueue.Clear();
|
||||
_smtcService.TrackPlayingQueue.Clear();
|
||||
ViewModel.AppSettings.MusicGallerySettings.PlayQueueIndex = -1;
|
||||
|
||||
ViewModel.TrackPlayingQueue.InsertRange(ViewModel.AppSettings.MusicGallerySettings.PlayQueueIndex + 1, displayedTracks.Select(x => new PlayQueueItem(x)));
|
||||
_smtcService.TrackPlayingQueue.InsertRange(ViewModel.AppSettings.MusicGallerySettings.PlayQueueIndex + 1, displayedTracks.Select(x => new PlayQueueItem(x)));
|
||||
ViewModel.AppSettings.MusicGallerySettings.PlayQueueIndex = displayedTracks.ToList().IndexOf(track);
|
||||
await ViewModel.PlayTrackAtAsync(ViewModel.AppSettings.MusicGallerySettings.PlayQueueIndex);
|
||||
await _smtcService.PlayTrackAtAsync(ViewModel.AppSettings.MusicGallerySettings.PlayQueueIndex);
|
||||
}
|
||||
|
||||
private void Page_Loaded(object sender, RoutedEventArgs e)
|
||||
@@ -256,9 +180,12 @@ namespace BetterLyrics.WinUI3.Views
|
||||
var settings = ViewModel.AppSettings.MusicGallerySettings;
|
||||
if (settings.AutoPlay)
|
||||
{
|
||||
_ = ViewModel.PlayTrackAtAsync(settings.PlayQueueIndex);
|
||||
Task.Run(async () =>
|
||||
{
|
||||
await Task.Delay(1000);
|
||||
_ = _smtcService.PlayTrackAtAsync(settings.PlayQueueIndex);
|
||||
});
|
||||
}
|
||||
ScrollToPlayingItem();
|
||||
}
|
||||
|
||||
private void FolderTreeView_ItemInvoked(TreeView sender, TreeViewItemInvokedEventArgs args)
|
||||
@@ -316,5 +243,6 @@ namespace BetterLyrics.WinUI3.Views
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
Loaded="RootGrid_Loaded"
|
||||
Unloaded="RootGrid_Unloaded">
|
||||
|
||||
<local:MusicGalleryPage x:Name="MusicGalleryPage" IsPlayingQueueOpened="{Binding ElementName=NowPlayingBar, Path=IsPlayingQueueOpened, Mode=OneWay}" />
|
||||
<local:MusicGalleryPage x:Name="MusicGalleryPage" />
|
||||
|
||||
<local:NowPlayingPage
|
||||
x:Name="NowPlayingPage"
|
||||
@@ -32,15 +32,28 @@
|
||||
x:Name="NowPlayingBar"
|
||||
VerticalAlignment="Bottom"
|
||||
IsAutoHideEnabled="False"
|
||||
PlayQueueButtonClick="NowPlayingBar_PlayingQueueClick"
|
||||
PlaybackOrder="{x:Bind ViewModel.AppSettings.MusicGallerySettings.PlaybackOrder, Mode=TwoWay}"
|
||||
ShowPlaybackOrderButton="True"
|
||||
ShowPlayingQueueButton="True"
|
||||
ShowSongInfo="True"
|
||||
ShowStopButton="True"
|
||||
SongInfoTapped="NowPlayingBar_SongInfoTapped"
|
||||
TimeTapped="NowPlayingBar_TimeTapped" />
|
||||
|
||||
<!-- Title bar -->
|
||||
<StackPanel VerticalAlignment="Top" Orientation="Horizontal" />
|
||||
TimeTapped="NowPlayingBar_TimeTapped">
|
||||
<uc:NowPlayingBar.ContextFlyout>
|
||||
<Flyout x:Name="PlayQueueFlyout" ShouldConstrainToRootBounds="False">
|
||||
<Flyout.FlyoutPresenterStyle>
|
||||
<Style BasedOn="{StaticResource FlyoutGhostStyle}" TargetType="FlyoutPresenter">
|
||||
<Setter Property="MaxHeight" Value="600" />
|
||||
</Style>
|
||||
</Flyout.FlyoutPresenterStyle>
|
||||
<uc:PlayQueue
|
||||
x:Name="PlayQueue"
|
||||
Width="300"
|
||||
MaxHeight="600" />
|
||||
</Flyout>
|
||||
</uc:NowPlayingBar.ContextFlyout>
|
||||
</uc:NowPlayingBar>
|
||||
|
||||
</Grid>
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ using BetterLyrics.WinUI3.Extensions;
|
||||
using BetterLyrics.WinUI3.Hooks;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.Models.Settings;
|
||||
using BetterLyrics.WinUI3.Services.MediaSessionsService;
|
||||
using BetterLyrics.WinUI3.Services.GSMTCService;
|
||||
using BetterLyrics.WinUI3.ViewModels;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
@@ -14,6 +14,7 @@ using Microsoft.UI.Windowing;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Media.Imaging;
|
||||
using System.Threading.Tasks;
|
||||
using static Vanara.PInvoke.AdvApi32;
|
||||
|
||||
// To learn more about WinUI, the WinUI project structure,
|
||||
// and more about our project templates, see: http://aka.ms/winui-project-info.
|
||||
@@ -30,7 +31,7 @@ namespace BetterLyrics.WinUI3.Views
|
||||
{
|
||||
public MusicGalleryWindowViewModel ViewModel { get; private set; } = Ioc.Default.GetRequiredService<MusicGalleryWindowViewModel>();
|
||||
|
||||
private readonly IMediaSessionsService _mediaSessionsService = Ioc.Default.GetRequiredService<IMediaSessionsService>();
|
||||
private readonly IGSMTCService _gsmtcService = Ioc.Default.GetRequiredService<IGSMTCService>();
|
||||
|
||||
public MusicGalleryWindow()
|
||||
{
|
||||
@@ -47,7 +48,7 @@ namespace BetterLyrics.WinUI3.Views
|
||||
|
||||
private void UpdateAlbumArtThemeColors()
|
||||
{
|
||||
var result = _mediaSessionsService.CalculateAlbumArtThemeColors(
|
||||
var result = _gsmtcService.CalculateAlbumArtThemeColors(
|
||||
ViewModel.AppSettings.MusicGallerySettings.LyricsWindowStatus, Colors.Transparent);
|
||||
|
||||
NowPlayingPage.AlbumArtThemeColors = result;
|
||||
@@ -69,9 +70,9 @@ namespace BetterLyrics.WinUI3.Views
|
||||
|
||||
public void Receive(PropertyChangedMessage<BitmapImage?> message)
|
||||
{
|
||||
if (message.Sender is IMediaSessionsService)
|
||||
if (message.Sender is IGSMTCService)
|
||||
{
|
||||
if (message.PropertyName == nameof(IMediaSessionsService.AlbumArtBitmapImage))
|
||||
if (message.PropertyName == nameof(IGSMTCService.AlbumArtBitmapImage))
|
||||
{
|
||||
UpdateAlbumArtThemeColors();
|
||||
}
|
||||
@@ -131,7 +132,14 @@ namespace BetterLyrics.WinUI3.Views
|
||||
|
||||
private void NowPlayingBar_PlayingQueueClick(object sender, System.EventArgs e)
|
||||
{
|
||||
MusicGalleryPage.IsPlayingQueueOpened = !MusicGalleryPage.IsPlayingQueueOpened;
|
||||
if (PlayQueueFlyout.IsOpen)
|
||||
{
|
||||
PlayQueueFlyout.Hide();
|
||||
}
|
||||
else
|
||||
{
|
||||
PlayQueueFlyout.ShowAt(NowPlayingBar);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ using BetterLyrics.WinUI3.Helper;
|
||||
using BetterLyrics.WinUI3.Hooks;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.Models.Settings;
|
||||
using BetterLyrics.WinUI3.Services.MediaSessionsService;
|
||||
using BetterLyrics.WinUI3.Services.GSMTCService;
|
||||
using BetterLyrics.WinUI3.ViewModels;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
@@ -34,7 +34,7 @@ namespace BetterLyrics.WinUI3.Views
|
||||
IRecipient<PropertyChangedMessage<bool>>,
|
||||
IRecipient<PropertyChangedMessage<string>>
|
||||
{
|
||||
private readonly IMediaSessionsService _mediaSessionsService = Ioc.Default.GetRequiredService<IMediaSessionsService>();
|
||||
private readonly IGSMTCService _gsmtcService = Ioc.Default.GetRequiredService<IGSMTCService>();
|
||||
|
||||
private readonly DispatcherQueueTimer _layoutChangedTimer = App.Current.Resources.DispatcherQueue.CreateTimer();
|
||||
private readonly DispatcherQueueTimer _scrollChangedTimer = App.Current.Resources.DispatcherQueue.CreateTimer();
|
||||
@@ -114,9 +114,9 @@ namespace BetterLyrics.WinUI3.Views
|
||||
var artistsFontSize = albumArtLayoutSettings.IsAutoSongInfoFontSize ? lyricsLayoutMetrics.ArtistNameSize : albumArtLayoutSettings.SongInfoFontSize * 0.8;
|
||||
var albumFontSize = albumArtLayoutSettings.IsAutoSongInfoFontSize ? lyricsLayoutMetrics.AlbumNameSize : albumArtLayoutSettings.SongInfoFontSize * 0.8;
|
||||
|
||||
RenderTextBlock(TitleTextBlock, _mediaSessionsService.CurrentSongInfo?.Title, titleFontSize);
|
||||
RenderTextBlock(ArtistsTextBlock, _mediaSessionsService.CurrentSongInfo?.DisplayArtists, artistsFontSize);
|
||||
RenderTextBlock(AlbumTextBlock, _mediaSessionsService.CurrentSongInfo?.Album, albumFontSize);
|
||||
RenderTextBlock(TitleTextBlock, _gsmtcService.CurrentSongInfo?.Title, titleFontSize);
|
||||
RenderTextBlock(ArtistsTextBlock, _gsmtcService.CurrentSongInfo?.DisplayArtists, artistsFontSize);
|
||||
RenderTextBlock(AlbumTextBlock, _gsmtcService.CurrentSongInfo?.Album, albumFontSize);
|
||||
}
|
||||
|
||||
private void UpdateSongInfoOpacity()
|
||||
@@ -555,7 +555,7 @@ namespace BetterLyrics.WinUI3.Views
|
||||
private void LyricsScrollViewer_PointerReleased(object sender, Microsoft.UI.Xaml.Input.PointerRoutedEventArgs e)
|
||||
{
|
||||
LyricsCanvas.IsMousePressing = false;
|
||||
_mediaSessionsService.ChangeLyricsLine(LyricsCanvas.CurrentHoveringLineIndex);
|
||||
_gsmtcService.ChangeLyricsLine(LyricsCanvas.CurrentHoveringLineIndex);
|
||||
}
|
||||
|
||||
private void LyricsScrollViewer_PointerExited(object sender, Microsoft.UI.Xaml.Input.PointerRoutedEventArgs e)
|
||||
@@ -577,9 +577,9 @@ namespace BetterLyrics.WinUI3.Views
|
||||
|
||||
public async void Receive(PropertyChangedMessage<SongInfo?> message)
|
||||
{
|
||||
if (message.Sender is IMediaSessionsService)
|
||||
if (message.Sender is IGSMTCService)
|
||||
{
|
||||
if (message.PropertyName == nameof(IMediaSessionsService.CurrentSongInfo))
|
||||
if (message.PropertyName == nameof(IGSMTCService.CurrentSongInfo))
|
||||
{
|
||||
SongInfoStackPanel.Opacity = 0;
|
||||
await Task.Delay(Constants.Time.AnimationDuration);
|
||||
|
||||
@@ -5,7 +5,7 @@ using BetterLyrics.WinUI3.Extensions;
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using BetterLyrics.WinUI3.Hooks;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.Services.MediaSessionsService;
|
||||
using BetterLyrics.WinUI3.Services.GSMTCService;
|
||||
using BetterLyrics.WinUI3.Services.SettingsService;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
@@ -47,7 +47,7 @@ namespace BetterLyrics.WinUI3.Views
|
||||
public LyricsWindowStatus LyricsWindowStatus { get; private set; }
|
||||
|
||||
public NowPlayingWindowViewModel ViewModel { get; private set; } = Ioc.Default.GetRequiredService<NowPlayingWindowViewModel>();
|
||||
private readonly IMediaSessionsService _mediaSessionsService = Ioc.Default.GetRequiredService<IMediaSessionsService>();
|
||||
private readonly IGSMTCService _gsmtcService = Ioc.Default.GetRequiredService<IGSMTCService>();
|
||||
private readonly ISettingsService _settingsService = Ioc.Default.GetRequiredService<ISettingsService>();
|
||||
|
||||
public NowPlayingWindow(LyricsWindowStatus status)
|
||||
@@ -141,7 +141,7 @@ namespace BetterLyrics.WinUI3.Views
|
||||
|
||||
private void UpdateAlbumArtThemeColors()
|
||||
{
|
||||
var result = _mediaSessionsService.CalculateAlbumArtThemeColors(LyricsWindowStatus, _backdropAccentColor);
|
||||
var result = _gsmtcService.CalculateAlbumArtThemeColors(LyricsWindowStatus, _backdropAccentColor);
|
||||
|
||||
NowPlayingPage.AlbumArtThemeColors = result;
|
||||
RootGrid.RequestedTheme = result.ThemeType;
|
||||
@@ -231,7 +231,7 @@ namespace BetterLyrics.WinUI3.Views
|
||||
|
||||
private void OnAutoShowOrHideWindowChanged()
|
||||
{
|
||||
this.SetLyricsWindowVisibilityByPlayingStatus(_mediaSessionsService.CurrentIsPlaying, DispatcherQueue);
|
||||
this.SetLyricsWindowVisibilityByPlayingStatus(_gsmtcService.CurrentIsPlaying, DispatcherQueue);
|
||||
}
|
||||
|
||||
private void OnIsAdaptToEnvironmentChanged()
|
||||
@@ -466,9 +466,9 @@ namespace BetterLyrics.WinUI3.Views
|
||||
|
||||
public void Receive(PropertyChangedMessage<bool> message)
|
||||
{
|
||||
if (message.Sender is IMediaSessionsService)
|
||||
if (message.Sender is IGSMTCService)
|
||||
{
|
||||
if (message.PropertyName == nameof(IMediaSessionsService.CurrentIsPlaying))
|
||||
if (message.PropertyName == nameof(IGSMTCService.CurrentIsPlaying))
|
||||
{
|
||||
OnAutoShowOrHideWindowChanged();
|
||||
}
|
||||
@@ -520,9 +520,9 @@ namespace BetterLyrics.WinUI3.Views
|
||||
|
||||
public void Receive(PropertyChangedMessage<BitmapImage?> message)
|
||||
{
|
||||
if (message.Sender is IMediaSessionsService)
|
||||
if (message.Sender is IGSMTCService)
|
||||
{
|
||||
if (message.PropertyName == nameof(IMediaSessionsService.AlbumArtBitmapImage))
|
||||
if (message.PropertyName == nameof(IGSMTCService.AlbumArtBitmapImage))
|
||||
{
|
||||
UpdateAlbumArtThemeColors();
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ using BetterLyrics.WinUI3.Extensions;
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using BetterLyrics.WinUI3.Hooks;
|
||||
using BetterLyrics.WinUI3.Models.Settings;
|
||||
using BetterLyrics.WinUI3.Services.MediaSessionsService;
|
||||
using BetterLyrics.WinUI3.Services.GSMTCService;
|
||||
using BetterLyrics.WinUI3.Services.SettingsService;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
@@ -24,7 +24,7 @@ namespace BetterLyrics.WinUI3.Views;
|
||||
public sealed partial class SystemTrayWindow : Window, IRecipient<PropertyChangedMessage<List<string>>>
|
||||
{
|
||||
private ISettingsService _settingsService = Ioc.Default.GetRequiredService<ISettingsService>();
|
||||
private readonly IMediaSessionsService _mediaSessionsService = Ioc.Default.GetRequiredService<IMediaSessionsService>();
|
||||
private readonly IGSMTCService _gsmtcService = Ioc.Default.GetRequiredService<IGSMTCService>();
|
||||
|
||||
private WindowMessageMonitor _wmm;
|
||||
|
||||
@@ -92,13 +92,13 @@ public sealed partial class SystemTrayWindow : Window, IRecipient<PropertyChange
|
||||
{
|
||||
GlobalHotKeyHook.UpdateHotKey(this, ShortcutID.PlayOrPauseSong, _settingsService.AppSettings.GeneralSettings.PlayOrPauseShortcut, (() =>
|
||||
{
|
||||
if (_mediaSessionsService.CurrentIsPlaying)
|
||||
if (_gsmtcService.CurrentIsPlaying)
|
||||
{
|
||||
_ = _mediaSessionsService.PauseAsync();
|
||||
_ = _gsmtcService.PauseAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
_ = _mediaSessionsService.PlayAsync();
|
||||
_ = _gsmtcService.PlayAsync();
|
||||
}
|
||||
}));
|
||||
}
|
||||
@@ -107,7 +107,7 @@ public sealed partial class SystemTrayWindow : Window, IRecipient<PropertyChange
|
||||
{
|
||||
GlobalHotKeyHook.UpdateHotKey(this, ShortcutID.PreviousSong, _settingsService.AppSettings.GeneralSettings.PreviousSongShortcut, () =>
|
||||
{
|
||||
_ = _mediaSessionsService.PreviousAsync();
|
||||
_ = _gsmtcService.PreviousAsync();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@ public sealed partial class SystemTrayWindow : Window, IRecipient<PropertyChange
|
||||
{
|
||||
GlobalHotKeyHook.UpdateHotKey(this, ShortcutID.NextSong, _settingsService.AppSettings.GeneralSettings.NextSongShortcut, () =>
|
||||
{
|
||||
_ = _mediaSessionsService.NextAsync();
|
||||
_ = _gsmtcService.NextAsync();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user