mirror of
https://github.com/microsoft/PowerToys
synced 2025-09-01 15:05:12 +00:00
[Peek] Add Audio Previewer (#31619)
* add audio previewer * fix button on activation * revert change
This commit is contained in:
committed by
GitHub
parent
58e598815c
commit
42fb394bf3
2
.github/actions/spell-check/expect.txt
vendored
2
.github/actions/spell-check/expect.txt
vendored
@@ -38,6 +38,7 @@ ALPHATYPE
|
|||||||
AModifier
|
AModifier
|
||||||
AMPROPERTY
|
AMPROPERTY
|
||||||
AMPROPSETID
|
AMPROPSETID
|
||||||
|
amr
|
||||||
ANDSCANS
|
ANDSCANS
|
||||||
animatedvisuals
|
animatedvisuals
|
||||||
ansicolor
|
ansicolor
|
||||||
@@ -488,6 +489,7 @@ Filterkeyboard
|
|||||||
Filterx
|
Filterx
|
||||||
findfast
|
findfast
|
||||||
FIXEDFILEINFO
|
FIXEDFILEINFO
|
||||||
|
flac
|
||||||
flyouts
|
flyouts
|
||||||
FOF
|
FOF
|
||||||
FOFX
|
FOFX
|
||||||
|
@@ -63,5 +63,9 @@ namespace Peek.Common.Models
|
|||||||
public static readonly PropertyKey FileType = new PropertyKey(new Guid(0xb725f130, 0x47ef, 0x101a, 0xa5, 0xf1, 0x02, 0x60, 0x8c, 0x9e, 0xeb, 0xac), 4);
|
public static readonly PropertyKey FileType = new PropertyKey(new Guid(0xb725f130, 0x47ef, 0x101a, 0xa5, 0xf1, 0x02, 0x60, 0x8c, 0x9e, 0xeb, 0xac), 4);
|
||||||
public static readonly PropertyKey FrameWidth = new PropertyKey(new Guid(0x64440491, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03), 3);
|
public static readonly PropertyKey FrameWidth = new PropertyKey(new Guid(0x64440491, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03), 3);
|
||||||
public static readonly PropertyKey FrameHeight = new PropertyKey(new Guid(0x64440491, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03), 4);
|
public static readonly PropertyKey FrameHeight = new PropertyKey(new Guid(0x64440491, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03), 4);
|
||||||
|
public static readonly PropertyKey MusicTitle = new PropertyKey(new Guid(0xf29f85e0, 0x4ff9, 0x1068, 0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9), 2);
|
||||||
|
public static readonly PropertyKey MusicDisplayArtist = new PropertyKey(new Guid(0xFD122953, 0xFA93, 0x4EF7, 0x92, 0xC3, 0x04, 0xC9, 0x46, 0xB2, 0xF7, 0xC8), 100);
|
||||||
|
public static readonly PropertyKey MusicAlbum = new PropertyKey(new Guid(0x56a3372e, 0xce9c, 0x11d2, 0x9f, 0xe, 0x0, 0x60, 0x97, 0xc6, 0x86, 0xf6), 4);
|
||||||
|
public static readonly PropertyKey MusicDuration = new PropertyKey(new Guid(0x64440490, 0x4c8b, 0x11d1, 0x8b, 0x70, 0x8, 0x0, 0x36, 0xb1, 0x1a, 0x3), 3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
106
src/modules/peek/Peek.FilePreviewer/Controls/AudioControl.xaml
Normal file
106
src/modules/peek/Peek.FilePreviewer/Controls/AudioControl.xaml
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
<!-- Copyright (c) Microsoft Corporation. All rights reserved. -->
|
||||||
|
<!-- Licensed under the MIT License. See LICENSE in the project root for license information. -->
|
||||||
|
|
||||||
|
<UserControl
|
||||||
|
x:Class="Peek.FilePreviewer.Controls.AudioControl"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:local="using:Peek.FilePreviewer.Controls"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:tkconverters="using:CommunityToolkit.WinUI.Converters"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
|
||||||
|
<UserControl.Resources>
|
||||||
|
<tkconverters:StringVisibilityConverter x:Key="StringVisibilityConverter" />
|
||||||
|
</UserControl.Resources>
|
||||||
|
|
||||||
|
<Grid
|
||||||
|
MaxWidth="800"
|
||||||
|
Margin="16"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
ColumnSpacing="24"
|
||||||
|
RowSpacing="24">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="auto" />
|
||||||
|
<RowDefinition Height="auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="auto" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<Border
|
||||||
|
Grid.Row="0"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="24,0,0,0"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
BorderBrush="{ThemeResource SurfaceStrokeColorDefaultBrush}"
|
||||||
|
BorderThickness="1"
|
||||||
|
ToolTipService.ToolTip="{x:Bind ToolTipText, Mode=OneWay}">
|
||||||
|
<Image Width="180" Source="{x:Bind Source.Thumbnail, Mode=OneWay}" />
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<StackPanel
|
||||||
|
Grid.Row="0"
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="0,0,24,0"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Spacing="5">
|
||||||
|
<TextBlock
|
||||||
|
FontSize="26"
|
||||||
|
FontWeight="SemiBold"
|
||||||
|
MaxLines="3"
|
||||||
|
Text="{x:Bind Source.Title, Mode=OneWay}"
|
||||||
|
TextTrimming="CharacterEllipsis"
|
||||||
|
TextWrapping="Wrap">
|
||||||
|
<ToolTipService.ToolTip>
|
||||||
|
<ToolTip Content="{x:Bind Source.Title, Mode=OneWay}" />
|
||||||
|
</ToolTipService.ToolTip>
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock
|
||||||
|
Text="{x:Bind Source.Artist, Mode=OneWay}"
|
||||||
|
TextTrimming="CharacterEllipsis"
|
||||||
|
Visibility="{x:Bind Source.Artist, Mode=OneWay, Converter={StaticResource StringVisibilityConverter}}">
|
||||||
|
<ToolTipService.ToolTip>
|
||||||
|
<ToolTip Content="{x:Bind Source.Artist, Mode=OneWay}" />
|
||||||
|
</ToolTipService.ToolTip>
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock
|
||||||
|
Text="{x:Bind Source.Album, Mode=OneWay}"
|
||||||
|
TextTrimming="CharacterEllipsis"
|
||||||
|
Visibility="{x:Bind Source.Album, Mode=OneWay, Converter={StaticResource StringVisibilityConverter}}">
|
||||||
|
<ToolTipService.ToolTip>
|
||||||
|
<ToolTip Content="{x:Bind Source.Album, Mode=OneWay}" />
|
||||||
|
</ToolTipService.ToolTip>
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock Text="{x:Bind Source.Length, Mode=OneWay}" TextTrimming="CharacterEllipsis">
|
||||||
|
<ToolTipService.ToolTip>
|
||||||
|
<ToolTip Content="{x:Bind Source.Length, Mode=OneWay}" />
|
||||||
|
</ToolTipService.ToolTip>
|
||||||
|
</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<MediaPlayerElement
|
||||||
|
x:Name="PlayerElement"
|
||||||
|
Grid.Row="1"
|
||||||
|
Grid.ColumnSpan="2"
|
||||||
|
VerticalAlignment="Top"
|
||||||
|
AreTransportControlsEnabled="True"
|
||||||
|
AutoPlay="True"
|
||||||
|
Source="{x:Bind Source.MediaSource, Mode=OneWay}">
|
||||||
|
<MediaPlayerElement.KeyboardAccelerators>
|
||||||
|
<KeyboardAccelerator Key="Space" Invoked="KeyboardAccelerator_Space_Invoked" />
|
||||||
|
</MediaPlayerElement.KeyboardAccelerators>
|
||||||
|
<MediaPlayerElement.TransportControls>
|
||||||
|
<MediaTransportControls
|
||||||
|
MaxWidth="900"
|
||||||
|
Margin="0"
|
||||||
|
IsCompact="True"
|
||||||
|
IsZoomButtonVisible="False" />
|
||||||
|
</MediaPlayerElement.TransportControls>
|
||||||
|
</MediaPlayerElement>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
@@ -0,0 +1,73 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation
|
||||||
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using Microsoft.UI.Xaml;
|
||||||
|
using Microsoft.UI.Xaml.Controls;
|
||||||
|
using Peek.FilePreviewer.Previewers.MediaPreviewer.Models;
|
||||||
|
|
||||||
|
namespace Peek.FilePreviewer.Controls
|
||||||
|
{
|
||||||
|
public sealed partial class AudioControl : UserControl
|
||||||
|
{
|
||||||
|
public static readonly DependencyProperty SourceProperty = DependencyProperty.Register(
|
||||||
|
nameof(Source),
|
||||||
|
typeof(AudioPreviewData),
|
||||||
|
typeof(AudioControl),
|
||||||
|
new PropertyMetadata(null, new PropertyChangedCallback((d, e) => ((AudioControl)d).SourcePropertyChanged())));
|
||||||
|
|
||||||
|
public static readonly DependencyProperty ToolTipTextProperty = DependencyProperty.Register(
|
||||||
|
nameof(ToolTipText),
|
||||||
|
typeof(string),
|
||||||
|
typeof(AudioControl),
|
||||||
|
new PropertyMetadata(null));
|
||||||
|
|
||||||
|
public AudioPreviewData? Source
|
||||||
|
{
|
||||||
|
get { return (AudioPreviewData)GetValue(SourceProperty); }
|
||||||
|
set { SetValue(SourceProperty, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ToolTipText
|
||||||
|
{
|
||||||
|
get { return (string)GetValue(ToolTipTextProperty); }
|
||||||
|
set { SetValue(ToolTipTextProperty, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public AudioControl()
|
||||||
|
{
|
||||||
|
this.InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SourcePropertyChanged()
|
||||||
|
{
|
||||||
|
if (Source == null)
|
||||||
|
{
|
||||||
|
PlayerElement.MediaPlayer.Pause();
|
||||||
|
PlayerElement.MediaPlayer.Source = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void KeyboardAccelerator_Space_Invoked(Microsoft.UI.Xaml.Input.KeyboardAccelerator sender, Microsoft.UI.Xaml.Input.KeyboardAcceleratorInvokedEventArgs args)
|
||||||
|
{
|
||||||
|
var mediaPlayer = PlayerElement.MediaPlayer;
|
||||||
|
|
||||||
|
if (mediaPlayer.Source == null || !mediaPlayer.CanPause)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mediaPlayer.CurrentState == Windows.Media.Playback.MediaPlayerState.Playing)
|
||||||
|
{
|
||||||
|
mediaPlayer.Pause();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mediaPlayer.Play();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prevent the keyboard accelerator to be called twice
|
||||||
|
args.Handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -10,6 +10,7 @@
|
|||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
SizeChanged="SizeChanged_Handler"
|
SizeChanged="SizeChanged_Handler"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
|
|
||||||
<Grid
|
<Grid
|
||||||
MaxWidth="1000"
|
MaxWidth="1000"
|
||||||
Margin="48"
|
Margin="48"
|
||||||
|
@@ -30,7 +30,7 @@
|
|||||||
MaxWidth="{x:Bind ImagePreviewer.MaxImageSize.Width, Mode=OneWay}"
|
MaxWidth="{x:Bind ImagePreviewer.MaxImageSize.Width, Mode=OneWay}"
|
||||||
MaxHeight="{x:Bind ImagePreviewer.MaxImageSize.Height, Mode=OneWay}"
|
MaxHeight="{x:Bind ImagePreviewer.MaxImageSize.Height, Mode=OneWay}"
|
||||||
Source="{x:Bind ImagePreviewer.Preview, Mode=OneWay}"
|
Source="{x:Bind ImagePreviewer.Preview, Mode=OneWay}"
|
||||||
ToolTipService.ToolTip="{x:Bind ImageInfoTooltip, Mode=OneWay}"
|
ToolTipService.ToolTip="{x:Bind InfoTooltip, Mode=OneWay}"
|
||||||
Visibility="{x:Bind IsPreviewVisible(ImagePreviewer, Previewer.State), Mode=OneWay}" />
|
Visibility="{x:Bind IsPreviewVisible(ImagePreviewer, Previewer.State), Mode=OneWay}" />
|
||||||
|
|
||||||
<MediaPlayerElement
|
<MediaPlayerElement
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
AreTransportControlsEnabled="True"
|
AreTransportControlsEnabled="True"
|
||||||
AutoPlay="True"
|
AutoPlay="True"
|
||||||
Source="{x:Bind VideoPreviewer.Preview, Mode=OneWay}"
|
Source="{x:Bind VideoPreviewer.Preview, Mode=OneWay}"
|
||||||
ToolTipService.ToolTip="{x:Bind ImageInfoTooltip, Mode=OneWay}"
|
ToolTipService.ToolTip="{x:Bind InfoTooltip, Mode=OneWay}"
|
||||||
Visibility="{x:Bind IsPreviewVisible(VideoPreviewer, Previewer.State), Mode=OneWay}">
|
Visibility="{x:Bind IsPreviewVisible(VideoPreviewer, Previewer.State), Mode=OneWay}">
|
||||||
<MediaPlayerElement.KeyboardAccelerators>
|
<MediaPlayerElement.KeyboardAccelerators>
|
||||||
<KeyboardAccelerator Key="Space" Invoked="KeyboardAccelerator_Space_Invoked" />
|
<KeyboardAccelerator Key="Space" Invoked="KeyboardAccelerator_Space_Invoked" />
|
||||||
@@ -52,6 +52,12 @@
|
|||||||
</MediaPlayerElement.TransportControls>
|
</MediaPlayerElement.TransportControls>
|
||||||
</MediaPlayerElement>
|
</MediaPlayerElement>
|
||||||
|
|
||||||
|
<controls:AudioControl
|
||||||
|
x:Name="AudioPreview"
|
||||||
|
Source="{x:Bind AudioPreviewer.Preview, Mode=OneWay}"
|
||||||
|
ToolTipText="{x:Bind InfoTooltip, Mode=OneWay}"
|
||||||
|
Visibility="{x:Bind IsPreviewVisible(AudioPreviewer, Previewer.State), Mode=OneWay}" />
|
||||||
|
|
||||||
<controls:BrowserControl
|
<controls:BrowserControl
|
||||||
x:Name="BrowserPreview"
|
x:Name="BrowserPreview"
|
||||||
x:Load="True"
|
x:Load="True"
|
||||||
|
@@ -48,6 +48,7 @@ namespace Peek.FilePreviewer
|
|||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
[NotifyPropertyChangedFor(nameof(ImagePreviewer))]
|
[NotifyPropertyChangedFor(nameof(ImagePreviewer))]
|
||||||
[NotifyPropertyChangedFor(nameof(VideoPreviewer))]
|
[NotifyPropertyChangedFor(nameof(VideoPreviewer))]
|
||||||
|
[NotifyPropertyChangedFor(nameof(AudioPreviewer))]
|
||||||
[NotifyPropertyChangedFor(nameof(BrowserPreviewer))]
|
[NotifyPropertyChangedFor(nameof(BrowserPreviewer))]
|
||||||
[NotifyPropertyChangedFor(nameof(ArchivePreviewer))]
|
[NotifyPropertyChangedFor(nameof(ArchivePreviewer))]
|
||||||
[NotifyPropertyChangedFor(nameof(ShellPreviewHandlerPreviewer))]
|
[NotifyPropertyChangedFor(nameof(ShellPreviewHandlerPreviewer))]
|
||||||
@@ -56,7 +57,7 @@ namespace Peek.FilePreviewer
|
|||||||
private IPreviewer? previewer;
|
private IPreviewer? previewer;
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private string imageInfoTooltip = ResourceLoaderInstance.ResourceLoader.GetString("PreviewTooltip_Blank");
|
private string infoTooltip = ResourceLoaderInstance.ResourceLoader.GetString("PreviewTooltip_Blank");
|
||||||
|
|
||||||
private CancellationTokenSource _cancellationTokenSource = new();
|
private CancellationTokenSource _cancellationTokenSource = new();
|
||||||
|
|
||||||
@@ -94,6 +95,8 @@ namespace Peek.FilePreviewer
|
|||||||
|
|
||||||
public IVideoPreviewer? VideoPreviewer => Previewer as IVideoPreviewer;
|
public IVideoPreviewer? VideoPreviewer => Previewer as IVideoPreviewer;
|
||||||
|
|
||||||
|
public IAudioPreviewer? AudioPreviewer => Previewer as IAudioPreviewer;
|
||||||
|
|
||||||
public IBrowserPreviewer? BrowserPreviewer => Previewer as IBrowserPreviewer;
|
public IBrowserPreviewer? BrowserPreviewer => Previewer as IBrowserPreviewer;
|
||||||
|
|
||||||
public IArchivePreviewer? ArchivePreviewer => Previewer as IArchivePreviewer;
|
public IArchivePreviewer? ArchivePreviewer => Previewer as IArchivePreviewer;
|
||||||
@@ -152,6 +155,8 @@ namespace Peek.FilePreviewer
|
|||||||
Previewer = null;
|
Previewer = null;
|
||||||
ImagePreview.Visibility = Visibility.Collapsed;
|
ImagePreview.Visibility = Visibility.Collapsed;
|
||||||
VideoPreview.Visibility = Visibility.Collapsed;
|
VideoPreview.Visibility = Visibility.Collapsed;
|
||||||
|
|
||||||
|
AudioPreview.Visibility = Visibility.Collapsed;
|
||||||
BrowserPreview.Visibility = Visibility.Collapsed;
|
BrowserPreview.Visibility = Visibility.Collapsed;
|
||||||
ArchivePreview.Visibility = Visibility.Collapsed;
|
ArchivePreview.Visibility = Visibility.Collapsed;
|
||||||
DrivePreview.Visibility = Visibility.Collapsed;
|
DrivePreview.Visibility = Visibility.Collapsed;
|
||||||
@@ -159,6 +164,8 @@ namespace Peek.FilePreviewer
|
|||||||
|
|
||||||
ImagePreview.FlowDirection = FlowDirection.LeftToRight;
|
ImagePreview.FlowDirection = FlowDirection.LeftToRight;
|
||||||
VideoPreview.FlowDirection = FlowDirection.LeftToRight;
|
VideoPreview.FlowDirection = FlowDirection.LeftToRight;
|
||||||
|
|
||||||
|
AudioPreview.FlowDirection = FlowDirection.LeftToRight;
|
||||||
BrowserPreview.FlowDirection = FlowDirection.LeftToRight;
|
BrowserPreview.FlowDirection = FlowDirection.LeftToRight;
|
||||||
ArchivePreview.FlowDirection = FlowDirection.LeftToRight;
|
ArchivePreview.FlowDirection = FlowDirection.LeftToRight;
|
||||||
DrivePreview.FlowDirection = FlowDirection.LeftToRight;
|
DrivePreview.FlowDirection = FlowDirection.LeftToRight;
|
||||||
@@ -203,7 +210,7 @@ namespace Peek.FilePreviewer
|
|||||||
await Previewer.LoadPreviewAsync(cancellationToken);
|
await Previewer.LoadPreviewAsync(cancellationToken);
|
||||||
|
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
await UpdateImageTooltipAsync(cancellationToken);
|
await UpdateTooltipAsync(cancellationToken);
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
{
|
{
|
||||||
@@ -225,6 +232,7 @@ namespace Peek.FilePreviewer
|
|||||||
VideoPreview.MediaPlayer.Source = null;
|
VideoPreview.MediaPlayer.Source = null;
|
||||||
VideoPreview.Source = null;
|
VideoPreview.Source = null;
|
||||||
|
|
||||||
|
AudioPreview.Source = null;
|
||||||
ImagePreview.Source = null;
|
ImagePreview.Source = null;
|
||||||
ArchivePreview.Source = null;
|
ArchivePreview.Source = null;
|
||||||
BrowserPreview.Source = null;
|
BrowserPreview.Source = null;
|
||||||
@@ -327,7 +335,7 @@ namespace Peek.FilePreviewer
|
|||||||
args.Handled = true;
|
args.Handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task UpdateImageTooltipAsync(CancellationToken cancellationToken)
|
private async Task UpdateTooltipAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
if (Item == null)
|
if (Item == null)
|
||||||
{
|
{
|
||||||
@@ -353,7 +361,7 @@ namespace Peek.FilePreviewer
|
|||||||
string fileSizeFormatted = string.IsNullOrEmpty(fileSize) ? string.Empty : "\n" + ReadableStringHelper.FormatResourceString("PreviewTooltip_FileSize", fileSize);
|
string fileSizeFormatted = string.IsNullOrEmpty(fileSize) ? string.Empty : "\n" + ReadableStringHelper.FormatResourceString("PreviewTooltip_FileSize", fileSize);
|
||||||
sb.Append(fileSizeFormatted);
|
sb.Append(fileSizeFormatted);
|
||||||
|
|
||||||
ImageInfoTooltip = sb.ToString();
|
InfoTooltip = sb.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -17,6 +17,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Remove="Controls\ArchiveControl.xaml" />
|
<None Remove="Controls\ArchiveControl.xaml" />
|
||||||
|
<None Remove="Controls\AudioControl.xaml" />
|
||||||
<None Remove="Controls\BrowserControl.xaml" />
|
<None Remove="Controls\BrowserControl.xaml" />
|
||||||
<None Remove="Controls\DriveControl.xaml" />
|
<None Remove="Controls\DriveControl.xaml" />
|
||||||
<None Remove="Controls\ShellPreviewHandlerControl.xaml" />
|
<None Remove="Controls\ShellPreviewHandlerControl.xaml" />
|
||||||
@@ -28,6 +29,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="CommunityToolkit.Mvvm" />
|
<PackageReference Include="CommunityToolkit.Mvvm" />
|
||||||
|
<PackageReference Include="CommunityToolkit.WinUI.Converters" />
|
||||||
<PackageReference Include="Microsoft.WindowsAppSDK" />
|
<PackageReference Include="Microsoft.WindowsAppSDK" />
|
||||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" />
|
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" />
|
||||||
<PackageReference Include="SharpCompress" />
|
<PackageReference Include="SharpCompress" />
|
||||||
@@ -47,6 +49,12 @@
|
|||||||
<ProjectReference Include="..\Peek.Common\Peek.Common.csproj" />
|
<ProjectReference Include="..\Peek.Common\Peek.Common.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Page Update="Controls\AudioControl.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Page Update="Controls\DriveControl.xaml">
|
<Page Update="Controls\DriveControl.xaml">
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
@@ -0,0 +1,13 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation
|
||||||
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using Peek.FilePreviewer.Previewers.MediaPreviewer.Models;
|
||||||
|
|
||||||
|
namespace Peek.FilePreviewer.Previewers.Interfaces
|
||||||
|
{
|
||||||
|
public interface IAudioPreviewer : IPreviewer
|
||||||
|
{
|
||||||
|
public AudioPreviewData? Preview { get; }
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,175 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation
|
||||||
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using Microsoft.UI.Dispatching;
|
||||||
|
using Microsoft.UI.Xaml.Media.Imaging;
|
||||||
|
using Peek.Common.Extensions;
|
||||||
|
using Peek.Common.Helpers;
|
||||||
|
using Peek.Common.Models;
|
||||||
|
using Peek.FilePreviewer.Models;
|
||||||
|
using Peek.FilePreviewer.Previewers.Helpers;
|
||||||
|
using Peek.FilePreviewer.Previewers.Interfaces;
|
||||||
|
using Peek.FilePreviewer.Previewers.MediaPreviewer.Models;
|
||||||
|
using Windows.Foundation;
|
||||||
|
using Windows.Media.Core;
|
||||||
|
using Windows.Storage;
|
||||||
|
|
||||||
|
namespace Peek.FilePreviewer.Previewers.MediaPreviewer
|
||||||
|
{
|
||||||
|
public partial class AudioPreviewer : ObservableObject, IAudioPreviewer
|
||||||
|
{
|
||||||
|
[ObservableProperty]
|
||||||
|
private PreviewState _state;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private AudioPreviewData _preview;
|
||||||
|
|
||||||
|
private IFileSystemItem Item { get; }
|
||||||
|
|
||||||
|
private DispatcherQueue Dispatcher { get; }
|
||||||
|
|
||||||
|
public AudioPreviewer(IFileSystemItem file)
|
||||||
|
{
|
||||||
|
Item = file;
|
||||||
|
Dispatcher = DispatcherQueue.GetForCurrentThread();
|
||||||
|
Preview = new AudioPreviewData();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task CopyAsync()
|
||||||
|
{
|
||||||
|
await Dispatcher.RunOnUiThread(async () =>
|
||||||
|
{
|
||||||
|
var storageItem = await Item.GetStorageItemAsync();
|
||||||
|
ClipboardHelper.SaveToClipboard(storageItem);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<PreviewSize> GetPreviewSizeAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var size = new Size(680, 400);
|
||||||
|
var previewSize = new PreviewSize { MonitorSize = size, UseEffectivePixels = true };
|
||||||
|
return Task.FromResult(previewSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task LoadPreviewAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
State = PreviewState.Loading;
|
||||||
|
|
||||||
|
var thumbnailTask = LoadThumbnailAsync(cancellationToken);
|
||||||
|
var sourceTask = LoadSourceAsync(cancellationToken);
|
||||||
|
var metadataTask = LoadMetadataAsync(cancellationToken);
|
||||||
|
|
||||||
|
await Task.WhenAll(thumbnailTask, sourceTask, metadataTask);
|
||||||
|
|
||||||
|
if (!thumbnailTask.Result || !sourceTask.Result || !metadataTask.Result)
|
||||||
|
{
|
||||||
|
State = PreviewState.Error;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
State = PreviewState.Loaded;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<bool> LoadThumbnailAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return TaskExtension.RunSafe(async () =>
|
||||||
|
{
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
await Dispatcher.RunOnUiThread(async () =>
|
||||||
|
{
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
var thumbnail = await IconHelper.GetThumbnailAsync(Item.Path, cancellationToken)
|
||||||
|
?? await IconHelper.GetIconAsync(Item.Path, cancellationToken);
|
||||||
|
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
Preview.Thumbnail = thumbnail ?? new SvgImageSource(new Uri("ms-appx:///Assets/Peek/DefaultFileIcon.svg"));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task<bool> LoadSourceAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return TaskExtension.RunSafe(async () =>
|
||||||
|
{
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
var storageFile = await Item.GetStorageItemAsync() as StorageFile;
|
||||||
|
|
||||||
|
await Dispatcher.RunOnUiThread(() =>
|
||||||
|
{
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
Preview.MediaSource = MediaSource.CreateFromStorageFile(storageFile);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task<bool> LoadMetadataAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return TaskExtension.RunSafe(async () =>
|
||||||
|
{
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
await Dispatcher.RunOnUiThread(() =>
|
||||||
|
{
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
Preview.Title = PropertyStoreHelper.TryGetStringProperty(Item.Path, PropertyKey.MusicTitle)
|
||||||
|
?? Item.Name[..^Item.Extension.Length];
|
||||||
|
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
var artist = PropertyStoreHelper.TryGetStringProperty(Item.Path, PropertyKey.MusicDisplayArtist);
|
||||||
|
Preview.Artist = artist != null
|
||||||
|
? string.Format(CultureInfo.CurrentCulture, ResourceLoaderInstance.ResourceLoader.GetString("Audio_Artist"), artist)
|
||||||
|
: string.Empty;
|
||||||
|
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
var album = PropertyStoreHelper.TryGetStringProperty(Item.Path, PropertyKey.MusicAlbum);
|
||||||
|
Preview.Album = album != null
|
||||||
|
? string.Format(CultureInfo.CurrentCulture, ResourceLoaderInstance.ResourceLoader.GetString("Audio_Album"), album)
|
||||||
|
: string.Empty;
|
||||||
|
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
var ticksLength = PropertyStoreHelper.TryGetUlongProperty(Item.Path, PropertyKey.MusicDuration);
|
||||||
|
if (ticksLength.HasValue)
|
||||||
|
{
|
||||||
|
var length = TimeSpan.FromTicks((long)ticksLength);
|
||||||
|
var truncatedLength = new TimeSpan(length.Hours, length.Minutes, length.Seconds).ToString("g", CultureInfo.CurrentCulture);
|
||||||
|
Preview.Length = string.Format(CultureInfo.CurrentCulture, ResourceLoaderInstance.ResourceLoader.GetString("Audio_Length"), truncatedLength);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Preview.Length = string.Empty;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsFileTypeSupported(string fileExt)
|
||||||
|
{
|
||||||
|
return _supportedFileTypes.Contains(fileExt);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly HashSet<string> _supportedFileTypes = new()
|
||||||
|
{
|
||||||
|
".aac",
|
||||||
|
".ac3",
|
||||||
|
".amr",
|
||||||
|
".flac",
|
||||||
|
".m4a",
|
||||||
|
".mp3",
|
||||||
|
".ogg",
|
||||||
|
".wav",
|
||||||
|
".wma",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,39 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation
|
||||||
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using Microsoft.UI.Xaml.Media;
|
||||||
|
using Windows.Media.Core;
|
||||||
|
|
||||||
|
namespace Peek.FilePreviewer.Previewers.MediaPreviewer.Models
|
||||||
|
{
|
||||||
|
public partial class AudioPreviewData : ObservableObject
|
||||||
|
{
|
||||||
|
[ObservableProperty]
|
||||||
|
private MediaSource? _mediaSource;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private ImageSource? _thumbnail;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _title;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _artist;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _album;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _length;
|
||||||
|
|
||||||
|
public AudioPreviewData()
|
||||||
|
{
|
||||||
|
Artist = string.Empty;
|
||||||
|
Title = string.Empty;
|
||||||
|
Album = string.Empty;
|
||||||
|
Length = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -9,6 +9,7 @@ using Peek.Common.Models;
|
|||||||
using Peek.FilePreviewer.Models;
|
using Peek.FilePreviewer.Models;
|
||||||
using Peek.FilePreviewer.Previewers.Archives;
|
using Peek.FilePreviewer.Previewers.Archives;
|
||||||
using Peek.FilePreviewer.Previewers.Drive;
|
using Peek.FilePreviewer.Previewers.Drive;
|
||||||
|
using Peek.FilePreviewer.Previewers.MediaPreviewer;
|
||||||
using Peek.UI.Telemetry.Events;
|
using Peek.UI.Telemetry.Events;
|
||||||
|
|
||||||
namespace Peek.FilePreviewer.Previewers
|
namespace Peek.FilePreviewer.Previewers
|
||||||
@@ -32,6 +33,10 @@ namespace Peek.FilePreviewer.Previewers
|
|||||||
{
|
{
|
||||||
return new VideoPreviewer(file);
|
return new VideoPreviewer(file);
|
||||||
}
|
}
|
||||||
|
else if (AudioPreviewer.IsFileTypeSupported(file.Extension))
|
||||||
|
{
|
||||||
|
return new AudioPreviewer(file);
|
||||||
|
}
|
||||||
else if (WebBrowserPreviewer.IsFileTypeSupported(file.Extension))
|
else if (WebBrowserPreviewer.IsFileTypeSupported(file.Extension))
|
||||||
{
|
{
|
||||||
return new WebBrowserPreviewer(file, _previewSettings);
|
return new WebBrowserPreviewer(file, _previewSettings);
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) Microsoft Corporation
|
// Copyright (c) Microsoft Corporation
|
||||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
// See the LICENSE file in the project root for more information.
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
@@ -306,4 +306,16 @@
|
|||||||
<value>Unknown</value>
|
<value>Unknown</value>
|
||||||
<comment>Used for unknown drive type or file system</comment>
|
<comment>Used for unknown drive type or file system</comment>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Audio_Album" xml:space="preserve">
|
||||||
|
<value>Album: {0}</value>
|
||||||
|
<comment>{0} is the title of the album read from file metadata</comment>
|
||||||
|
</data>
|
||||||
|
<data name="Audio_Artist" xml:space="preserve">
|
||||||
|
<value>Artist: {0}</value>
|
||||||
|
<comment>{0} is the artist read from file metadata</comment>
|
||||||
|
</data>
|
||||||
|
<data name="Audio_Length" xml:space="preserve">
|
||||||
|
<value>Length: {0}</value>
|
||||||
|
<comment>{0} is the duration of the audio read from file metadata</comment>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
Reference in New Issue
Block a user