mirror of
https://github.com/LanZhan-Harmony/WindowsMusicPlayer-TheUntamedMusicPlayer.git
synced 2026-05-06 19:20:18 +08:00
基本完成查看图片页
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:UntamedMusicPlayer.Controls"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Window.SystemBackdrop>
|
||||
@@ -12,6 +13,7 @@
|
||||
|
||||
<Grid>
|
||||
<Grid.Resources>
|
||||
<Thickness x:Key="AppBarButtonContentViewboxCollapsedMargin">0,12,0,6</Thickness>
|
||||
<SolidColorBrush x:Key="AppBarButtonForegroundPointerOver" Color="{ThemeResource SystemAccentColor}"/>
|
||||
<SolidColorBrush x:Key="AppBarButtonForegroundPressed"
|
||||
Opacity="0.5"
|
||||
@@ -23,7 +25,6 @@
|
||||
|
||||
<ScrollViewer x:Name="Scroll"
|
||||
HorizontalScrollBarVisibility="Auto"
|
||||
Tapped="Scroll_Tapped"
|
||||
VerticalScrollBarVisibility="Auto"
|
||||
ZoomMode="Enabled">
|
||||
<Image x:Name="Image"
|
||||
@@ -37,56 +38,43 @@
|
||||
Orientation="Horizontal">
|
||||
<Border Background="#CC000000" CornerRadius="{ThemeResource OverlayCornerRadius}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<AppBarButton Width="40" Height="40"
|
||||
<AppBarButton x:Uid="ImageViewer_Save"
|
||||
Width="40" Height="40"
|
||||
Click="SaveButton_Click" Foreground="White"
|
||||
ToolTipService.ToolTip="保存">
|
||||
<AppBarButton.Icon>
|
||||
<SymbolIcon Margin="0,-4,0,4" Symbol="Save"/>
|
||||
</AppBarButton.Icon>
|
||||
</AppBarButton>
|
||||
<AppBarButton Width="40" Height="40"
|
||||
Icon="{ui:FontIcon Glyph=}"/>
|
||||
<AppBarButton x:Uid="ImageViewer_Copy"
|
||||
Width="40" Height="40"
|
||||
Click="CopyButton_Click" Foreground="White"
|
||||
ToolTipService.ToolTip="复制">
|
||||
<AppBarButton.Icon>
|
||||
<SymbolIcon Margin="0,-4,0,4" Symbol="Copy"/>
|
||||
</AppBarButton.Icon>
|
||||
</AppBarButton>
|
||||
Icon="{ui:FontIcon Glyph=}"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<Border Margin="12,0,0,0"
|
||||
Background="#CC000000"
|
||||
CornerRadius="{ThemeResource OverlayCornerRadius}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<AppBarButton Width="40" Height="40"
|
||||
<AppBarButton x:Uid="ImageViewer_OriginalSize"
|
||||
Width="40" Height="40"
|
||||
Margin="0,0,0,0"
|
||||
Click="OriginButton_Click" Foreground="White"
|
||||
ToolTipService.ToolTip="原始大小">
|
||||
<AppBarButton.Icon>
|
||||
<SymbolIcon Margin="0,-4,0,4" Symbol="Pictures"/>
|
||||
</AppBarButton.Icon>
|
||||
</AppBarButton>
|
||||
<AppBarButton Width="40" Height="40"
|
||||
Icon="{ui:FontIcon Glyph=}"/>
|
||||
<AppBarButton x:Uid="ImageViewer_ZoomOut"
|
||||
Width="40" Height="40"
|
||||
Click="ZoomOutButton_Click" Foreground="White"
|
||||
ToolTipService.ToolTip="缩小">
|
||||
<AppBarButton.Icon>
|
||||
<SymbolIcon Margin="0,-4,0,4" Symbol="ZoomOut"/>
|
||||
</AppBarButton.Icon>
|
||||
Icon="{ui:FontIcon Glyph=}">
|
||||
<AppBarButton.KeyboardAccelerators>
|
||||
<KeyboardAccelerator Key="Down" Modifiers="None"/>
|
||||
<KeyboardAccelerator Key="Down"/>
|
||||
</AppBarButton.KeyboardAccelerators>
|
||||
</AppBarButton>
|
||||
<TextBlock Margin="8,0" VerticalAlignment="Center"
|
||||
<TextBlock Margin="8,-4,8,0" VerticalAlignment="Center"
|
||||
FontSize="16" Foreground="White"
|
||||
Text="{x:Bind GetZoomText(Scroll.ZoomFactor), Mode=OneWay}"/>
|
||||
<AppBarButton Width="40" Height="40"
|
||||
<AppBarButton x:Uid="ImageViewer_ZoomIn"
|
||||
Width="40" Height="40"
|
||||
Click="ZoomInButton_Click" Foreground="White"
|
||||
ToolTipService.ToolTip="放大">
|
||||
Icon="{ui:FontIcon Glyph=}">
|
||||
<AppBarButton.KeyboardAccelerators>
|
||||
<KeyboardAccelerator Key="Up" Modifiers="None"/>
|
||||
<KeyboardAccelerator Key="Up"/>
|
||||
</AppBarButton.KeyboardAccelerators>
|
||||
<AppBarButton.Icon>
|
||||
<SymbolIcon Margin="0,-4,0,4" Symbol="ZoomIn"/>
|
||||
</AppBarButton.Icon>
|
||||
</AppBarButton>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.UI.Windowing;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
@@ -6,13 +8,18 @@ using Microsoft.UI.Xaml.Media.Imaging;
|
||||
using Microsoft.Windows.Storage.Pickers;
|
||||
using UntamedMusicPlayer.Contracts.Models;
|
||||
using UntamedMusicPlayer.Helpers;
|
||||
using UntamedMusicPlayer.Models;
|
||||
using UntamedMusicPlayer.Services;
|
||||
using Windows.ApplicationModel.DataTransfer;
|
||||
using Windows.Storage.Streams;
|
||||
using ZLogger;
|
||||
|
||||
namespace UntamedMusicPlayer.Controls;
|
||||
|
||||
public sealed partial class ImageViewerWindow : Window
|
||||
public sealed partial class ImageViewerWindow : Window, IDisposable
|
||||
{
|
||||
private readonly ILogger _logger = LoggingService.CreateLogger<ImageViewerWindow>();
|
||||
|
||||
private readonly BitmapImage _image;
|
||||
private readonly IDetailedSongInfoBase _info;
|
||||
|
||||
@@ -24,29 +31,59 @@ public sealed partial class ImageViewerWindow : Window
|
||||
Path.Combine(AppContext.BaseDirectory, "Assets/AppIcon/Icon.ico")
|
||||
);
|
||||
AppWindow.SetIcon(Path.Combine(AppContext.BaseDirectory, "Assets/AppIcon/Icon.ico"));
|
||||
Title = "AppDisplayName".GetLocalized();
|
||||
Title = "ImageViewerTitle".GetLocalized();
|
||||
ExtendsContentIntoTitleBar = true;
|
||||
var theme = ThemeSelectorService.IsDarkTheme ? ElementTheme.Dark : ElementTheme.Light;
|
||||
((FrameworkElement)Content).RequestedTheme = theme;
|
||||
TitleBarHelper.UpdateTitleBar(
|
||||
AppWindow.TitleBar,
|
||||
((FrameworkElement)Content).RequestedTheme
|
||||
);
|
||||
|
||||
_image = info.Cover!;
|
||||
_info = info;
|
||||
var presenter = (OverlappedPresenter)AppWindow.Presenter;
|
||||
presenter.Maximize();
|
||||
|
||||
Activate();
|
||||
}
|
||||
|
||||
private async void SaveButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
(sender as Button)!.IsEnabled = false;
|
||||
var extension = ".jpg";
|
||||
var picker = new FileSavePicker(App.MainWindow!.AppWindow.Id)
|
||||
var picker = new FileSavePicker(AppWindow.Id)
|
||||
{
|
||||
CommitButtonText = "保存图片",
|
||||
SuggestedFileName = _info.Title,
|
||||
SuggestedStartLocation = PickerLocationId.PicturesLibrary,
|
||||
FileTypeChoices = { { "EditSongInfoDialog_CoverImage".GetLocalized(), [extension] } },
|
||||
FileTypeChoices =
|
||||
{
|
||||
{ "EditSongInfoDialog_CoverImage".GetLocalized(), [ExtractExtension()] },
|
||||
},
|
||||
};
|
||||
var file = await picker.PickSaveFileAsync();
|
||||
if (file is not null)
|
||||
{
|
||||
await File.WriteAllBytesAsync(file.Path, null);
|
||||
byte[] data;
|
||||
try
|
||||
{
|
||||
if (_info.IsOnline)
|
||||
{
|
||||
using var client = new HttpClient();
|
||||
data = await client.GetByteArrayAsync(
|
||||
((IDetailedOnlineSongInfo)_info).CoverPath!
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
data = ((DetailedLocalSongInfo)_info).CoverBuffer!;
|
||||
}
|
||||
if (data.Length > 0)
|
||||
{
|
||||
await File.WriteAllBytesAsync(file.Path, data);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ZLogInformation(ex, $"{_info.Title}封面保存失败");
|
||||
}
|
||||
}
|
||||
(sender as Button)!.IsEnabled = true;
|
||||
}
|
||||
@@ -66,14 +103,20 @@ public sealed partial class ImageViewerWindow : Window
|
||||
}
|
||||
else
|
||||
{
|
||||
var stream = RandomAccessStreamReference.CreateFromStream(null);
|
||||
package.SetBitmap(stream);
|
||||
var buffer = ((DetailedLocalSongInfo)_info).CoverBuffer!;
|
||||
var stream = new InMemoryRandomAccessStream();
|
||||
await stream.WriteAsync(buffer.AsBuffer());
|
||||
stream.Seek(0);
|
||||
var streamRef = RandomAccessStreamReference.CreateFromStream(stream);
|
||||
package.SetBitmap(streamRef);
|
||||
package.OperationCompleted += (s, _) => stream.Dispose();
|
||||
}
|
||||
Clipboard.SetContent(package);
|
||||
Clipboard.Flush();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine(ex);
|
||||
_logger.ZLogInformation(ex, $"复制封面失败");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,4 +136,72 @@ public sealed partial class ImageViewerWindow : Window
|
||||
}
|
||||
|
||||
private string GetZoomText(float zoom) => $"{(int)(zoom * 100)}%";
|
||||
|
||||
private string ExtractExtension()
|
||||
{
|
||||
if (_info.IsOnline)
|
||||
{
|
||||
var coverPath = ((IDetailedOnlineSongInfo)_info).CoverPath;
|
||||
if (string.IsNullOrEmpty(coverPath))
|
||||
{
|
||||
return ".jpeg";
|
||||
}
|
||||
var uri = new Uri(coverPath);
|
||||
var extension = Path.GetExtension(uri.AbsolutePath).ToLower();
|
||||
if (string.IsNullOrEmpty(extension))
|
||||
{
|
||||
return ".jpeg";
|
||||
}
|
||||
return extension;
|
||||
}
|
||||
|
||||
var buffer = ((DetailedLocalSongInfo)_info).CoverBuffer;
|
||||
if (buffer is not { Length: >= 2 })
|
||||
{
|
||||
return ".jpeg";
|
||||
}
|
||||
|
||||
// JPEG (jpg, jpeg, jpe, jfif): FF D8
|
||||
if (buffer[0] == 0xFF && buffer[1] == 0xD8)
|
||||
{
|
||||
return ".jpeg";
|
||||
}
|
||||
|
||||
// BMP (bmp, dip): 42 4D
|
||||
if (buffer[0] == 0x42 && buffer[1] == 0x4D)
|
||||
{
|
||||
return ".bmp";
|
||||
}
|
||||
|
||||
if (buffer.Length >= 4)
|
||||
{
|
||||
// PNG: 89 50 4E 47
|
||||
if (buffer[0] == 0x89 && buffer[1] == 0x50 && buffer[2] == 0x4E && buffer[3] == 0x47)
|
||||
{
|
||||
return ".png";
|
||||
}
|
||||
// GIF: 47 49 46 38 ('GIF8')
|
||||
if (buffer[0] == 0x47 && buffer[1] == 0x49 && buffer[2] == 0x46 && buffer[3] == 0x38)
|
||||
{
|
||||
return ".gif";
|
||||
}
|
||||
// TIFF (Little Endian): 49 49 2A 00, (Big Endian): 4D 4D 00 2A
|
||||
if (
|
||||
(buffer[0] == 0x49 && buffer[1] == 0x49 && buffer[2] == 0x2A && buffer[3] == 0x00)
|
||||
|| (
|
||||
buffer[0] == 0x4D && buffer[1] == 0x4D && buffer[2] == 0x00 && buffer[3] == 0x2A
|
||||
)
|
||||
)
|
||||
{
|
||||
return ".tiff";
|
||||
}
|
||||
}
|
||||
|
||||
return ".jpeg";
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Microsoft.UI;
|
||||
using Microsoft.UI.Windowing;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Windows.UI;
|
||||
using Windows.UI.ViewManagement;
|
||||
@@ -13,60 +14,55 @@ public sealed partial class TitleBarHelper
|
||||
private const int WAACTIVE = 0x01;
|
||||
private const int WMACTIVATE = 0x0006;
|
||||
|
||||
public static void UpdateTitleBar(ElementTheme theme)
|
||||
public static void UpdateTitleBar(AppWindowTitleBar titleBar, ElementTheme theme)
|
||||
{
|
||||
if (App.MainWindow is not null && App.MainWindow.ExtendsContentIntoTitleBar)
|
||||
if (theme == ElementTheme.Default)
|
||||
{
|
||||
if (theme == ElementTheme.Default)
|
||||
{
|
||||
var uiSettings = new UISettings();
|
||||
var background = uiSettings.GetColorValue(UIColorType.Background);
|
||||
theme = background == Colors.White ? ElementTheme.Light : ElementTheme.Dark;
|
||||
}
|
||||
var uiSettings = new UISettings();
|
||||
var background = uiSettings.GetColorValue(UIColorType.Background);
|
||||
theme = background == Colors.White ? ElementTheme.Light : ElementTheme.Dark;
|
||||
}
|
||||
|
||||
var titleBar = App.MainWindow.AppWindow.TitleBar;
|
||||
titleBar.ButtonForegroundColor = theme switch
|
||||
{
|
||||
ElementTheme.Dark => Colors.White,
|
||||
ElementTheme.Light => Colors.Black,
|
||||
_ => Colors.Transparent,
|
||||
};
|
||||
|
||||
titleBar.ButtonForegroundColor = theme switch
|
||||
{
|
||||
ElementTheme.Dark => Colors.White,
|
||||
ElementTheme.Light => Colors.Black,
|
||||
_ => Colors.Transparent,
|
||||
};
|
||||
titleBar.ButtonHoverForegroundColor = theme switch
|
||||
{
|
||||
ElementTheme.Dark => Colors.White,
|
||||
ElementTheme.Light => Colors.Black,
|
||||
_ => Colors.Transparent,
|
||||
};
|
||||
|
||||
titleBar.ButtonHoverForegroundColor = theme switch
|
||||
{
|
||||
ElementTheme.Dark => Colors.White,
|
||||
ElementTheme.Light => Colors.Black,
|
||||
_ => Colors.Transparent,
|
||||
};
|
||||
titleBar.ButtonHoverBackgroundColor = theme switch
|
||||
{
|
||||
ElementTheme.Dark => Color.FromArgb(0x33, 0xFF, 0xFF, 0xFF),
|
||||
ElementTheme.Light => Color.FromArgb(0x33, 0x00, 0x00, 0x00),
|
||||
_ => Colors.Transparent,
|
||||
};
|
||||
|
||||
titleBar.ButtonHoverBackgroundColor = theme switch
|
||||
{
|
||||
ElementTheme.Dark => Color.FromArgb(0x33, 0xFF, 0xFF, 0xFF),
|
||||
ElementTheme.Light => Color.FromArgb(0x33, 0x00, 0x00, 0x00),
|
||||
_ => Colors.Transparent,
|
||||
};
|
||||
titleBar.ButtonPressedBackgroundColor = theme switch
|
||||
{
|
||||
ElementTheme.Dark => Color.FromArgb(0x66, 0xFF, 0xFF, 0xFF),
|
||||
ElementTheme.Light => Color.FromArgb(0x66, 0x00, 0x00, 0x00),
|
||||
_ => Colors.Transparent,
|
||||
};
|
||||
|
||||
titleBar.ButtonPressedBackgroundColor = theme switch
|
||||
{
|
||||
ElementTheme.Dark => Color.FromArgb(0x66, 0xFF, 0xFF, 0xFF),
|
||||
ElementTheme.Light => Color.FromArgb(0x66, 0x00, 0x00, 0x00),
|
||||
_ => Colors.Transparent,
|
||||
};
|
||||
titleBar.BackgroundColor = Colors.Transparent;
|
||||
|
||||
titleBar.BackgroundColor = Colors.Transparent;
|
||||
|
||||
var hwnd = WindowNative.GetWindowHandle(App.MainWindow);
|
||||
if (hwnd == GetActiveWindow())
|
||||
{
|
||||
SendMessage(hwnd, WMACTIVATE, WAINACTIVE, nint.Zero);
|
||||
SendMessage(hwnd, WMACTIVATE, WAACTIVE, nint.Zero);
|
||||
}
|
||||
else
|
||||
{
|
||||
SendMessage(hwnd, WMACTIVATE, WAACTIVE, nint.Zero);
|
||||
SendMessage(hwnd, WMACTIVATE, WAINACTIVE, nint.Zero);
|
||||
}
|
||||
var hwnd = WindowNative.GetWindowHandle(App.MainWindow);
|
||||
if (hwnd == GetActiveWindow())
|
||||
{
|
||||
SendMessage(hwnd, WMACTIVATE, WAINACTIVE, nint.Zero);
|
||||
SendMessage(hwnd, WMACTIVATE, WAACTIVE, nint.Zero);
|
||||
}
|
||||
else
|
||||
{
|
||||
SendMessage(hwnd, WMACTIVATE, WAACTIVE, nint.Zero);
|
||||
SendMessage(hwnd, WMACTIVATE, WAINACTIVE, nint.Zero);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -423,7 +423,8 @@ public sealed partial class MainWindow : WindowEx, IRecipient<LogMessage>
|
||||
args.Cancel = true;
|
||||
sender.Hide(); // 立即隐藏窗口,提升视觉响应
|
||||
Data.MusicPlayer.Pause(); // 立即停止音乐播放
|
||||
Data.DesktopLyricWindow?.Close(); // 立即关闭桌面歌词
|
||||
Data.DesktopLyricWindow?.Dispose(); // 立即关闭桌面歌词
|
||||
Data.ImageViewerWindows?.ForEach(w => w.Dispose()); // 立即关闭图片查看器
|
||||
|
||||
Settings.NotFirstUsed = true;
|
||||
// 并行执行保存以缩短退出后的存活时间
|
||||
@@ -459,7 +460,6 @@ public sealed partial class MainWindow : WindowEx, IRecipient<LogMessage>
|
||||
try
|
||||
{
|
||||
Data.MusicPlayer.Dispose();
|
||||
Data.DesktopLyricWindow?.Dispose();
|
||||
UnregisterGlobalHotKeys();
|
||||
|
||||
RootGrid.RemoveHandler(UIElement.KeyDownEvent, new KeyEventHandler(OnGlobalKeyDown));
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using UntamedMusicPlayer.Contracts.Models;
|
||||
using UntamedMusicPlayer.Controls;
|
||||
using UntamedMusicPlayer.Helpers;
|
||||
using UntamedMusicPlayer.LyricRenderer;
|
||||
using UntamedMusicPlayer.Playback;
|
||||
@@ -94,6 +95,7 @@ public static class Data
|
||||
public static LyricPage? LyricPage { get; set; }
|
||||
public static RootPlayBarView? RootPlayBarView { get; set; }
|
||||
public static DesktopLyricWindow? DesktopLyricWindow { get; set; }
|
||||
public static List<ImageViewerWindow>? ImageViewerWindows { get; set; }
|
||||
#endregion
|
||||
|
||||
#region ViewModels
|
||||
|
||||
@@ -328,7 +328,7 @@ public sealed partial class MaterialSelectorService : IMaterialSelectorService
|
||||
StrongReferenceMessenger.Default.Send(
|
||||
new ThemeChangeMessage(ThemeSelectorService.IsDarkTheme)
|
||||
);
|
||||
TitleBarHelper.UpdateTitleBar(sender.ActualTheme);
|
||||
TitleBarHelper.UpdateTitleBar(App.MainWindow!.AppWindow.TitleBar, sender.ActualTheme);
|
||||
SetConfigurationSourceTheme();
|
||||
ChangeTheme();
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ public sealed class ThemeSelectorService : IThemeSelectorService
|
||||
if (App.MainWindow!.Content is FrameworkElement rootElement)
|
||||
{
|
||||
rootElement.RequestedTheme = Theme;
|
||||
TitleBarHelper.UpdateTitleBar(Theme);
|
||||
TitleBarHelper.UpdateTitleBar(App.MainWindow.AppWindow.TitleBar, Theme);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -999,4 +999,25 @@
|
||||
<data name="Settings_Playlist" xml:space="preserve">
|
||||
<value>Playlist</value>
|
||||
</data>
|
||||
<data name="Lyric_ShowCover.Text" xml:space="preserve">
|
||||
<value>Show cover</value>
|
||||
</data>
|
||||
<data name="ImageViewerTitle" xml:space="preserve">
|
||||
<value>Untamed Image Viewer</value>
|
||||
</data>
|
||||
<data name="ImageViewer_ZoomIn.ToolTipService.ToolTip" xml:space="preserve">
|
||||
<value>Zoom in (↑ / Ctrl+Mouse wheel up)</value>
|
||||
</data>
|
||||
<data name="ImageViewer_OriginalSize.ToolTipService.ToolTip" xml:space="preserve">
|
||||
<value>Original size</value>
|
||||
</data>
|
||||
<data name="ImageViewer_Copy.ToolTipService.ToolTip" xml:space="preserve">
|
||||
<value>Copy to clipboard</value>
|
||||
</data>
|
||||
<data name="ImageViewer_Save.ToolTipService.ToolTip" xml:space="preserve">
|
||||
<value>Save</value>
|
||||
</data>
|
||||
<data name="ImageViewer_ZoomOut.ToolTipService.ToolTip" xml:space="preserve">
|
||||
<value>Zoom out (↑ / Ctrl+Mouse wheel down)</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -999,4 +999,25 @@
|
||||
<data name="Settings_Playlist" xml:space="preserve">
|
||||
<value>播放列表</value>
|
||||
</data>
|
||||
<data name="Lyric_ShowCover.Text" xml:space="preserve">
|
||||
<value>显示封面</value>
|
||||
</data>
|
||||
<data name="ImageViewerTitle" xml:space="preserve">
|
||||
<value>无羁 图片查看器</value>
|
||||
</data>
|
||||
<data name="ImageViewer_ZoomIn.ToolTipService.ToolTip" xml:space="preserve">
|
||||
<value>放大 (↑ / Ctrl+鼠标滚轮向上)</value>
|
||||
</data>
|
||||
<data name="ImageViewer_OriginalSize.ToolTipService.ToolTip" xml:space="preserve">
|
||||
<value>原始大小</value>
|
||||
</data>
|
||||
<data name="ImageViewer_Copy.ToolTipService.ToolTip" xml:space="preserve">
|
||||
<value>复制到剪贴板</value>
|
||||
</data>
|
||||
<data name="ImageViewer_Save.ToolTipService.ToolTip" xml:space="preserve">
|
||||
<value>保存</value>
|
||||
</data>
|
||||
<data name="ImageViewer_ZoomOut.ToolTipService.ToolTip" xml:space="preserve">
|
||||
<value>缩小 (↓ / Ctrl+鼠标滚轮向下)</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -1,16 +1,35 @@
|
||||
using System.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Media.Animation;
|
||||
using UntamedMusicPlayer.Contracts.Models;
|
||||
using UntamedMusicPlayer.Controls;
|
||||
using UntamedMusicPlayer.LyricRenderer;
|
||||
using UntamedMusicPlayer.Models;
|
||||
using UntamedMusicPlayer.Playback;
|
||||
using UntamedMusicPlayer.Views;
|
||||
|
||||
namespace UntamedMusicPlayer.ViewModels;
|
||||
|
||||
public sealed class LyricViewModel
|
||||
public sealed partial class LyricViewModel : ObservableObject, IDisposable
|
||||
{
|
||||
public LyricViewModel() { }
|
||||
[ObservableProperty]
|
||||
public partial bool IsShowCoverEnabled { get; set; }
|
||||
|
||||
public LyricViewModel()
|
||||
{
|
||||
IsShowCoverEnabled = Data.PlayState.CurrentSong?.Cover is not null;
|
||||
Data.PlayState.PropertyChanged += OnStateChanged;
|
||||
}
|
||||
|
||||
private void OnStateChanged(object? sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName is nameof(SharedPlaybackState.CurrentSong))
|
||||
{
|
||||
IsShowCoverEnabled = Data.PlayState.CurrentSong?.Cover is not null;
|
||||
}
|
||||
}
|
||||
|
||||
public void ListView_ItemClick(object _, ItemClickEventArgs e)
|
||||
{
|
||||
@@ -108,4 +127,15 @@ public sealed class LyricViewModel
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async void ShowCoverButton_Click(object _1, RoutedEventArgs _2)
|
||||
{
|
||||
Data.ImageViewerWindows ??= [];
|
||||
Data.ImageViewerWindows.Add(new ImageViewerWindow(Data.PlayState.CurrentSong!));
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Data.PlayState.PropertyChanged -= OnStateChanged;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,12 +153,10 @@ public sealed partial class RootPlayBarViewModel : ObservableObject
|
||||
if (!IsDesktopLyricWindowStarted)
|
||||
{
|
||||
Data.DesktopLyricWindow = new DesktopLyricWindow();
|
||||
Data.DesktopLyricWindow.Activate();
|
||||
IsDesktopLyricWindowStarted = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Data.DesktopLyricWindow?.Close();
|
||||
Data.DesktopLyricWindow?.Dispose();
|
||||
IsDesktopLyricWindowStarted = false;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:model="using:UntamedMusicPlayer.Models"
|
||||
xmlns:winuiex="using:WinUIEx"
|
||||
Closed="Window_Closed"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid x:Name="Draggable" VerticalAlignment="Center">
|
||||
|
||||
@@ -74,7 +74,7 @@ public sealed partial class DesktopLyricWindow : WindowEx, IDisposable
|
||||
this.CenterOnScreen(null, null);
|
||||
this.Move(AppWindow.Position.X, y);
|
||||
|
||||
Closed += Window_Closed;
|
||||
Activate();
|
||||
}
|
||||
|
||||
private double GetTextBlockWidth(string? currentLyricContent)
|
||||
@@ -167,6 +167,7 @@ public sealed partial class DesktopLyricWindow : WindowEx, IDisposable
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Close();
|
||||
Data.DesktopLyricWindow = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,6 +238,10 @@
|
||||
Click="{x:Bind ViewModel.ShowArtistButton_Click}"
|
||||
Icon="{ui:FontIcon FontFamily={StaticResource UntamedFontFamily},
|
||||
Glyph=}"/>
|
||||
<MenuFlyoutItem x:Uid="Lyric_ShowCover"
|
||||
Click="{x:Bind ViewModel.ShowCoverButton_Click}"
|
||||
Icon="{ui:FontIcon Glyph=}"
|
||||
IsEnabled="{x:Bind ViewModel.IsShowCoverEnabled, Mode=OneWay}"/>
|
||||
<MenuFlyoutItem x:Uid="Songs_Properties"
|
||||
Click="PropertiesButton_Click"
|
||||
Icon="{ui:FontIcon FontFamily={StaticResource UntamedFontFamily},
|
||||
|
||||
Reference in New Issue
Block a user