fixed up media controller
This commit is contained in:
@@ -17,7 +17,7 @@
|
|||||||
<None Remove="bin/Debug/net8.0-windows10.0.19041.0/Hyperbar.Windows.Controls.pri" />
|
<None Remove="bin/Debug/net8.0-windows10.0.19041.0/Hyperbar.Windows.Controls.pri" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.5.231202003-experimental1" />
|
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.5.240124002-experimental2" />
|
||||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26031-preview" />
|
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26031-preview" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.5.231202003-experimental1" />
|
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.5.240124002-experimental2" />
|
||||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26031-preview" />
|
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26031-preview" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ using Windows.Storage.Streams;
|
|||||||
namespace Hyperbar.UI.Windows;
|
namespace Hyperbar.UI.Windows;
|
||||||
|
|
||||||
public class StreamToImageSourceConverter :
|
public class StreamToImageSourceConverter :
|
||||||
ValueConverter<Stream, ImageSource>
|
ValueConverter<byte[], ImageSource>
|
||||||
{
|
{
|
||||||
protected override ImageSource? ConvertTo(Stream value,
|
protected override ImageSource? ConvertTo(byte[] value,
|
||||||
Type? targetType,
|
Type? targetType,
|
||||||
object? parameter,
|
object? parameter,
|
||||||
string? language)
|
string? language)
|
||||||
@@ -17,8 +17,8 @@ public class StreamToImageSourceConverter :
|
|||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
|
|
||||||
IRandomAccessStream randomAccessStream =
|
MemoryStream memoryStream = new(value);
|
||||||
WindowsRuntimeStreamExtensions.AsRandomAccessStream(value);
|
IRandomAccessStream randomAccessStream = memoryStream.AsRandomAccessStream();
|
||||||
|
|
||||||
BitmapImage bitmapImage = new();
|
BitmapImage bitmapImage = new();
|
||||||
bitmapImage.SetSource(randomAccessStream);
|
bitmapImage.SetSource(randomAccessStream);
|
||||||
|
|||||||
+1
-1
@@ -12,7 +12,7 @@
|
|||||||
<PackageReference Include="CommunityToolkit.WinUI" Version="7.1.2" />
|
<PackageReference Include="CommunityToolkit.WinUI" Version="7.1.2" />
|
||||||
<PackageReference Include="CommunityToolkit.WinUI.UI.Controls" Version="7.1.2" />
|
<PackageReference Include="CommunityToolkit.WinUI.UI.Controls" Version="7.1.2" />
|
||||||
<PackageReference Include="CommunityToolkit.WinUI.UI.Controls.Primitives" Version="7.1.2" />
|
<PackageReference Include="CommunityToolkit.WinUI.UI.Controls.Primitives" Version="7.1.2" />
|
||||||
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.5.231202003-experimental1" />
|
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.5.240124002-experimental2" />
|
||||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26031-preview" />
|
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26031-preview" />
|
||||||
<PackageReference Include="Microsoft.Xaml.Behaviors.WinUI.Managed" Version="2.0.9" />
|
<PackageReference Include="Microsoft.Xaml.Behaviors.WinUI.Managed" Version="2.0.9" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
|
||||||
|
namespace Hyperbar.Widget.MediaController.Windows;
|
||||||
|
|
||||||
|
public interface IMediaButtonViewModel :
|
||||||
|
IObservableViewModel
|
||||||
|
{
|
||||||
|
IRelayCommand? InvokeCommand { get; set; }
|
||||||
|
|
||||||
|
bool IsEnabled { get; set; }
|
||||||
|
|
||||||
|
string? State { get; set; }
|
||||||
|
}
|
||||||
+1
-1
@@ -1,3 +1,3 @@
|
|||||||
namespace Hyperbar.Widget.MediaController.Windows;
|
namespace Hyperbar.Widget.MediaController.Windows;
|
||||||
|
|
||||||
public record Previous : INotification;
|
public record MediaButton(bool IsEnabled);
|
||||||
@@ -4,7 +4,8 @@
|
|||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:interactions="using:Microsoft.Xaml.Interactions.Core"
|
xmlns:interactions="using:Microsoft.Xaml.Interactions.Core"
|
||||||
xmlns:interactivity="using:Microsoft.Xaml.Interactivity">
|
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
|
||||||
|
xmlns:triggers="using:CommunityToolkit.WinUI.UI.Triggers">
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
<SolidColorBrush x:Key="ButtonBackground" Color="Transparent" />
|
<SolidColorBrush x:Key="ButtonBackground" Color="Transparent" />
|
||||||
<SolidColorBrush x:Key="ButtonBorderBrush" Color="Transparent" />
|
<SolidColorBrush x:Key="ButtonBorderBrush" Color="Transparent" />
|
||||||
@@ -16,18 +17,49 @@
|
|||||||
<x:Double x:Key="ButtonHeight">40</x:Double>
|
<x:Double x:Key="ButtonHeight">40</x:Double>
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
<Button
|
<Button
|
||||||
|
x:Name="Button"
|
||||||
Width="{StaticResource ButtonWidth}"
|
Width="{StaticResource ButtonWidth}"
|
||||||
Height="{StaticResource ButtonHeight}"
|
Height="{StaticResource ButtonHeight}"
|
||||||
Padding="{StaticResource ButtonPadding}"
|
Padding="{StaticResource ButtonPadding}"
|
||||||
Command="{Binding Click}"
|
Command="{x:Bind ViewModel.InvokeCommand}"
|
||||||
Content="{Binding Icon}"
|
Content="{x:Bind ViewModel.State}"
|
||||||
FontFamily="{StaticResource SymbolThemeFontFamily}"
|
FontFamily="{StaticResource SymbolThemeFontFamily}"
|
||||||
FontSize="16"
|
FontSize="16"
|
||||||
ToolTipService.ToolTip="{Binding Text}">
|
IsEnabled="False">
|
||||||
<interactivity:Interaction.Behaviors>
|
<interactivity:Interaction.Behaviors>
|
||||||
<interactions:EventTriggerBehavior EventName="Loaded">
|
<interactions:EventTriggerBehavior EventName="Loaded">
|
||||||
<interactions:InvokeCommandAction Command="{Binding Initialize}" />
|
<interactions:InvokeCommandAction Command="{x:Bind ViewModel.InitializeCommand}" />
|
||||||
</interactions:EventTriggerBehavior>
|
</interactions:EventTriggerBehavior>
|
||||||
</interactivity:Interaction.Behaviors>
|
</interactivity:Interaction.Behaviors>
|
||||||
|
<VisualStateManager.VisualStateGroups>
|
||||||
|
<VisualStateGroup>
|
||||||
|
<VisualState x:Name="MediaPreviousButtonState">
|
||||||
|
<VisualState.StateTriggers>
|
||||||
|
<triggers:IsEqualStateTrigger Value="{Binding State}" To="MediaPreviousButton" />
|
||||||
|
</VisualState.StateTriggers>
|
||||||
|
<VisualState.Setters>
|
||||||
|
<Setter Target="Button.Content" Value="" />
|
||||||
|
</VisualState.Setters>
|
||||||
|
</VisualState>
|
||||||
|
<VisualState x:Name="MediaNextButtonState">
|
||||||
|
<VisualState.StateTriggers>
|
||||||
|
<triggers:IsEqualStateTrigger Value="{Binding State}" To="MediaNextButton" />
|
||||||
|
</VisualState.StateTriggers>
|
||||||
|
<VisualState.Setters>
|
||||||
|
<Setter Target="Button.Content" Value="" />
|
||||||
|
</VisualState.Setters>
|
||||||
|
</VisualState>
|
||||||
|
</VisualStateGroup>
|
||||||
|
<VisualStateGroup>
|
||||||
|
<VisualState x:Name="IsEnabledState">
|
||||||
|
<VisualState.StateTriggers>
|
||||||
|
<triggers:IsEqualStateTrigger Value="{Binding IsEnabled}" To="True" />
|
||||||
|
</VisualState.StateTriggers>
|
||||||
|
<VisualState.Setters>
|
||||||
|
<Setter Target="Button.IsEnabled" Value="True" />
|
||||||
|
</VisualState.Setters>
|
||||||
|
</VisualState>
|
||||||
|
</VisualStateGroup>
|
||||||
|
</VisualStateManager.VisualStateGroups>
|
||||||
</Button>
|
</Button>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
|||||||
@@ -9,5 +9,5 @@ public sealed partial class MediaButtonView :
|
|||||||
public MediaButtonView() =>
|
public MediaButtonView() =>
|
||||||
this.InitializeComponent(ref _contentLoaded);
|
this.InitializeComponent(ref _contentLoaded);
|
||||||
|
|
||||||
private MediaButtonViewModel ViewModel => (MediaButtonViewModel)DataContext;
|
private IMediaButtonViewModel ViewModel => (IMediaButtonViewModel)DataContext;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,42 +3,33 @@ using CommunityToolkit.Mvvm.Input;
|
|||||||
|
|
||||||
namespace Hyperbar.Widget.MediaController.Windows;
|
namespace Hyperbar.Widget.MediaController.Windows;
|
||||||
|
|
||||||
[NotificationHandler(nameof(PlaybackButtonType))]
|
public partial class MediaButtonViewModel<TMediaButton>(IServiceFactory serviceFactory,
|
||||||
public partial class MediaButtonViewModel(IServiceFactory serviceFactory,
|
|
||||||
IMediator mediator,
|
IMediator mediator,
|
||||||
IDisposer disposer,
|
IDisposer disposer,
|
||||||
ITemplateFactory templateFactory,
|
ITemplateFactory templateFactory,
|
||||||
PlaybackButtonType playbackButtonType,
|
IRelayCommand invokeCommand) :
|
||||||
Guid guid = default,
|
WidgetComponentViewModel(serviceFactory, mediator, disposer, templateFactory),
|
||||||
string? text = null,
|
INotificationHandler<Changed<TMediaButton>>,
|
||||||
string? icon = null,
|
IMediaButtonViewModel
|
||||||
RelayCommand? command = null) :
|
where TMediaButton :
|
||||||
WidgetButtonViewModel(serviceFactory, mediator, disposer, templateFactory, guid, text, icon, command)
|
MediaButton
|
||||||
{
|
{
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private PlaybackButtonType playbackButtonType = playbackButtonType;
|
private IRelayCommand? invokeCommand = invokeCommand;
|
||||||
|
|
||||||
public Task Handle(Changed<MediaControllerPlaybackStatus> notification,
|
[ObservableProperty]
|
||||||
|
private bool isEnabled;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string? state = $"{typeof(TMediaButton).Name}";
|
||||||
|
|
||||||
|
public Task Handle(Changed<TMediaButton> args,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
if (notification.Value is MediaControllerPlaybackStatus information)
|
IsEnabled = args.Value is not null && args.Value.IsEnabled;
|
||||||
{
|
|
||||||
//switch (buttonType)
|
|
||||||
//{
|
|
||||||
// case PlaybackButtonType.Play:
|
|
||||||
// Visible = information.Status is PlaybackStatus.Paused;
|
|
||||||
// break;
|
|
||||||
// case PlaybackButtonType.Pause:
|
|
||||||
// Visible = information.Status is PlaybackStatus.Playing;
|
|
||||||
// break;
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
//public override Task OnInitializeAsync()
|
public override async Task InitializeAsync() =>
|
||||||
//{
|
await Mediator.PublishAsync<Request<TMediaButton>>();
|
||||||
// await Mediator.PublishAsync<Request<PlaybackInformation>>();
|
}
|
||||||
//}
|
|
||||||
}
|
|
||||||
@@ -1,13 +1,16 @@
|
|||||||
using Windows.Media.Control;
|
using System.Collections.Concurrent;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using Windows.Media.Control;
|
||||||
using Windows.Storage.Streams;
|
using Windows.Storage.Streams;
|
||||||
|
|
||||||
namespace Hyperbar.Widget.MediaController.Windows;
|
namespace Hyperbar.Widget.MediaController.Windows;
|
||||||
|
|
||||||
public class MediaController :
|
public class MediaController :
|
||||||
INotificationHandler<Play>,
|
INotificationHandler<Request<MediaPrevious>>,
|
||||||
INotificationHandler<Pause>,
|
INotificationHandler<Request<MediaNext>>,
|
||||||
INotificationHandler<Request<MediaControllerPlaybackStatus>>,
|
|
||||||
INotificationHandler<Request<MediaInformation>>,
|
INotificationHandler<Request<MediaInformation>>,
|
||||||
|
INotificationHandler<Request<MediaPreviousButton>>,
|
||||||
|
INotificationHandler<Request<MediaNextButton>>,
|
||||||
IDisposable
|
IDisposable
|
||||||
{
|
{
|
||||||
private readonly AsyncLock asyncLock = new();
|
private readonly AsyncLock asyncLock = new();
|
||||||
@@ -38,79 +41,100 @@ public class MediaController :
|
|||||||
disposer.Dispose(this);
|
disposer.Dispose(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Handle(Play notification,
|
|
||||||
CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
await session.TryPlayAsync();
|
|
||||||
await UpdateMediaPlaybackPropertiesAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Handle(Pause notification,
|
|
||||||
CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
await session.TryPauseAsync();
|
|
||||||
await UpdateMediaPlaybackPropertiesAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Handle(Request<MediaControllerPlaybackStatus> args,
|
|
||||||
CancellationToken cancellationToken) => await UpdateMediaPlaybackPropertiesAsync();
|
|
||||||
|
|
||||||
public async Task Handle(Request<MediaInformation> args,
|
public async Task Handle(Request<MediaInformation> args,
|
||||||
CancellationToken cancellationToken) => await UpdateMediaPropertiesAsync();
|
CancellationToken cancellationToken) => await UpdateMediaInformationAsync();
|
||||||
|
|
||||||
|
public async Task Handle(Request<MediaNext> args,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
await session.TrySkipNextAsync();
|
||||||
|
await UpdateMediaStateAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Handle(Request<MediaPrevious> args, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
await session.TrySkipPreviousAsync();
|
||||||
|
await UpdateMediaStateAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Handle(Request<MediaPreviousButton> args,
|
||||||
|
CancellationToken cancellationToken) => await UpdateMediaStateAsync();
|
||||||
|
|
||||||
|
public async Task Handle(Request<MediaNextButton> args,
|
||||||
|
CancellationToken cancellationToken) => await UpdateMediaStateAsync();
|
||||||
|
|
||||||
private async void OnMediaPropertiesChanged(GlobalSystemMediaTransportControlsSession sender,
|
private async void OnMediaPropertiesChanged(GlobalSystemMediaTransportControlsSession sender,
|
||||||
MediaPropertiesChangedEventArgs args) => await UpdateMediaPropertiesAsync();
|
MediaPropertiesChangedEventArgs args)
|
||||||
|
{
|
||||||
|
await UpdateMediaInformationAsync();
|
||||||
|
await UpdateMediaStateAsync();
|
||||||
|
}
|
||||||
|
|
||||||
private async void OnPlaybackInfoChanged(GlobalSystemMediaTransportControlsSession sender,
|
private async void OnPlaybackInfoChanged(GlobalSystemMediaTransportControlsSession sender,
|
||||||
PlaybackInfoChangedEventArgs args) => await UpdateMediaPlaybackPropertiesAsync();
|
PlaybackInfoChangedEventArgs args) => await UpdateMediaStateAsync();
|
||||||
|
|
||||||
private async Task UpdateMediaPlaybackPropertiesAsync()
|
private async Task UpdateMediaInformationAsync()
|
||||||
{
|
{
|
||||||
using (await asyncLock)
|
try
|
||||||
{
|
{
|
||||||
try
|
GlobalSystemMediaTransportControlsSessionMediaProperties mediaProperties =
|
||||||
|
await session.TryGetMediaPropertiesAsync();
|
||||||
|
|
||||||
|
byte[]? buffer = null;
|
||||||
|
|
||||||
|
if (mediaProperties.Thumbnail is not null)
|
||||||
{
|
{
|
||||||
GlobalSystemMediaTransportControlsSessionPlaybackInfo playbackInfo = session.GetPlaybackInfo();
|
IRandomAccessStreamWithContentType randomAccessStream =
|
||||||
|
await mediaProperties.Thumbnail.OpenReadAsync();
|
||||||
|
|
||||||
if (playbackInfo.PlaybackStatus != playbackStatus)
|
var stream = randomAccessStream.AsStream();
|
||||||
{
|
|
||||||
playbackStatus = playbackInfo.PlaybackStatus;
|
|
||||||
await mediator.PublishAsync(new Changed<MediaControllerPlaybackStatus>(
|
|
||||||
new MediaControllerPlaybackStatus((PlaybackStatus)playbackStatus)));
|
|
||||||
|
|
||||||
}
|
using MemoryStream memoryStream = new();
|
||||||
|
await stream.CopyToAsync(memoryStream);
|
||||||
|
buffer = memoryStream.ToArray();
|
||||||
}
|
}
|
||||||
catch
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
await mediator.PublishAsync(new Changed<MediaInformation>(new MediaInformation(mediaProperties.Title,
|
||||||
|
mediaProperties.Artist, buffer)));
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task UpdateMediaPropertiesAsync()
|
private bool isPreviousEnabled;
|
||||||
|
private bool isNextEnabled;
|
||||||
|
|
||||||
|
private async Task UpdateMediaStateAsync()
|
||||||
{
|
{
|
||||||
using (await asyncLock)
|
try
|
||||||
{
|
{
|
||||||
try
|
GlobalSystemMediaTransportControlsSessionPlaybackInfo playbackInfo =
|
||||||
|
session.GetPlaybackInfo();
|
||||||
|
|
||||||
|
bool isPreviousEnabled = playbackInfo.Controls.IsPreviousEnabled;
|
||||||
|
if (this.isPreviousEnabled != isPreviousEnabled)
|
||||||
{
|
{
|
||||||
|
await mediator.PublishAsync(new Changed<MediaPreviousButton>(new
|
||||||
|
MediaPreviousButton(isPreviousEnabled)));
|
||||||
|
|
||||||
GlobalSystemMediaTransportControlsSessionMediaProperties mediaProperties =
|
this.isPreviousEnabled = isPreviousEnabled;
|
||||||
await session.TryGetMediaPropertiesAsync();
|
|
||||||
|
|
||||||
IRandomAccessStreamWithContentType? randomAccessStream = null;
|
|
||||||
if (mediaProperties.Thumbnail is not null)
|
|
||||||
{
|
|
||||||
randomAccessStream =
|
|
||||||
await mediaProperties.Thumbnail.OpenReadAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
await mediator.PublishAsync(new Changed<MediaInformation>(new MediaInformation(mediaProperties.Title,
|
|
||||||
mediaProperties.Artist, randomAccessStream is not null ? randomAccessStream.AsStream() : default)));
|
|
||||||
}
|
}
|
||||||
catch
|
|
||||||
|
bool isNextEnabled = playbackInfo.Controls.IsNextEnabled;
|
||||||
|
if (this.isNextEnabled != isNextEnabled)
|
||||||
{
|
{
|
||||||
|
await mediator.PublishAsync(new Changed<MediaNextButton>(new
|
||||||
|
MediaNextButton(isNextEnabled)));
|
||||||
|
|
||||||
|
this.isNextEnabled = isNextEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
namespace Hyperbar.Widget.MediaController.Windows;
|
|
||||||
|
|
||||||
public record MediaControllerPlaybackStatus(PlaybackStatus Status) :
|
|
||||||
INotification;
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
using CommunityToolkit.Mvvm.Input;
|
|
||||||
|
|
||||||
namespace Hyperbar.Widget.MediaController.Windows;
|
|
||||||
|
|
||||||
public class MediaControllerPlaybackStatusHandler(IMediator mediator,
|
|
||||||
IServiceFactory factory) :
|
|
||||||
INotificationHandler<Changed<MediaControllerPlaybackStatus>>
|
|
||||||
{
|
|
||||||
public async Task Handle(Changed<MediaControllerPlaybackStatus> notification,
|
|
||||||
CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
if (notification.Value is MediaControllerPlaybackStatus mediaControllerPlaybackInformation)
|
|
||||||
{
|
|
||||||
if (mediaControllerPlaybackInformation.Status is PlaybackStatus.Playing)
|
|
||||||
{
|
|
||||||
await mediator.PublishAsync(new Replaced<WidgetComponentViewModel>(2, factory.Create<MediaButtonViewModel>(
|
|
||||||
PlaybackButtonType.Pause, "Pause", "\uE769",
|
|
||||||
new RelayCommand(async () => await mediator.PublishAsync<Pause>()))), nameof(MediaControllerViewModel),
|
|
||||||
cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mediaControllerPlaybackInformation.Status is PlaybackStatus.Paused)
|
|
||||||
{
|
|
||||||
await mediator.PublishAsync(new Replaced<WidgetComponentViewModel>(2, factory.Create<MediaButtonViewModel>(
|
|
||||||
PlaybackButtonType.Pause, "Play", "\uE768",
|
|
||||||
new RelayCommand(async () => await mediator.PublishAsync<Play>()))), nameof(MediaControllerViewModel),
|
|
||||||
cancellationToken);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
namespace Hyperbar.Widget.MediaController.Windows;
|
namespace Hyperbar.Widget.MediaController.Windows;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[NotificationHandler(nameof(MediaControllerViewModel))]
|
[NotificationHandler(nameof(MediaControllerViewModel))]
|
||||||
public class MediaControllerViewModel :
|
public class MediaControllerViewModel :
|
||||||
ObservableCollectionViewModel<WidgetComponentViewModel>,
|
ObservableCollectionViewModel<WidgetComponentViewModel>,
|
||||||
@@ -16,17 +18,14 @@ public class MediaControllerViewModel :
|
|||||||
|
|
||||||
Add<MediaInformationViewModel>();
|
Add<MediaInformationViewModel>();
|
||||||
|
|
||||||
Add<MediaButtonViewModel>(PlaybackButtonType.Previous,
|
Add<MediaButtonViewModel<MediaPreviousButton>>(new RelayCommand(async () =>
|
||||||
"Previous", "\uEB9E",
|
await mediator.PublishAsync<Request<MediaPrevious>>()));
|
||||||
new RelayCommand(async () => await mediator.PublishAsync<Previous>()));
|
|
||||||
|
|
||||||
Add<MediaButtonViewModel>(PlaybackButtonType.Pause,
|
Add<MediaButtonViewModel<MediaPlayPauseButton>>(new RelayCommand(async () =>
|
||||||
"Pause", "\uE769",
|
await mediator.PublishAsync<Request<MediaPlayPauseButton>>()));
|
||||||
new RelayCommand(async () => await mediator.PublishAsync<Pause>()));
|
|
||||||
|
|
||||||
Add<MediaButtonViewModel>(PlaybackButtonType.Forward,
|
Add<MediaButtonViewModel<MediaNextButton>>(new RelayCommand(async () =>
|
||||||
"Forward", "\uEB9D",
|
await mediator.PublishAsync<Request<MediaNext>>()));
|
||||||
new RelayCommand(async () => await mediator.PublishAsync<Forward>()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ITemplateFactory TemplateFactory { get; set; }
|
public ITemplateFactory TemplateFactory { get; set; }
|
||||||
|
|||||||
@@ -23,9 +23,10 @@ public class MediaControllerWidget :
|
|||||||
.AddHandler<MediaControllerHandler>()
|
.AddHandler<MediaControllerHandler>()
|
||||||
.AddTransient<IFactory<MediaController, MediaControllerViewModel?>, MediaControllerViewModelFactory>()
|
.AddTransient<IFactory<MediaController, MediaControllerViewModel?>, MediaControllerViewModelFactory>()
|
||||||
.AddCache<MediaController, MediaControllerViewModel>()
|
.AddCache<MediaController, MediaControllerViewModel>()
|
||||||
.AddHandler<MediaControllerPlaybackStatusHandler>()
|
|
||||||
.AddContentTemplate<MediaControllerViewModel, MediaControllerView>()
|
.AddContentTemplate<MediaControllerViewModel, MediaControllerView>()
|
||||||
.AddContentTemplate<MediaInformationViewModel, MediaInformationView>()
|
.AddContentTemplate<MediaInformationViewModel, MediaInformationView>()
|
||||||
.AddContentTemplate<MediaButtonViewModel, MediaButtonView>();
|
.AddContentTemplate<MediaButtonViewModel<MediaPreviousButton>, MediaButtonView>()
|
||||||
|
.AddContentTemplate<MediaButtonViewModel<MediaPlayPauseButton>, MediaButtonView>()
|
||||||
|
.AddContentTemplate<MediaButtonViewModel<MediaNextButton>, MediaButtonView>();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,4 @@
|
|||||||
|
|
||||||
public record MediaInformation(string Title,
|
public record MediaInformation(string Title,
|
||||||
string Description,
|
string Description,
|
||||||
Stream? ThumbnailSource);
|
byte[]? Image);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Width="40"
|
Width="40"
|
||||||
Height="40">
|
Height="40">
|
||||||
<Image Source="{Binding ThumbnailSource, Converter={windows:StreamToImageSourceConverter}}" />
|
<Image Source="{Binding Image, Converter={windows:StreamToImageSourceConverter}}" />
|
||||||
</Border>
|
</Border>
|
||||||
<StackPanel Grid.Column="2">
|
<StackPanel Grid.Column="2">
|
||||||
<TextBlock
|
<TextBlock
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
TextWrapping="NoWrap" />
|
TextWrapping="NoWrap" />
|
||||||
<interactivity:Interaction.Behaviors>
|
<interactivity:Interaction.Behaviors>
|
||||||
<interactions:EventTriggerBehavior EventName="Loaded">
|
<interactions:EventTriggerBehavior EventName="Loaded">
|
||||||
<interactions:InvokeCommandAction Command="{x:Bind ViewModel.Initialize}" />
|
<interactions:InvokeCommandAction Command="{x:Bind ViewModel.InitializeCommand}" />
|
||||||
</interactions:EventTriggerBehavior>
|
</interactions:EventTriggerBehavior>
|
||||||
</interactivity:Interaction.Behaviors>
|
</interactivity:Interaction.Behaviors>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ public partial class MediaInformationViewModel(IServiceFactory serviceFactory,
|
|||||||
private string? description;
|
private string? description;
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private Stream? thumbnailSource;
|
private byte[]? image;
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private string? title;
|
private string? title;
|
||||||
@@ -25,12 +25,12 @@ public partial class MediaInformationViewModel(IServiceFactory serviceFactory,
|
|||||||
{
|
{
|
||||||
Title = value.Title;
|
Title = value.Title;
|
||||||
Description = value.Description;
|
Description = value.Description;
|
||||||
ThumbnailSource = value.ThumbnailSource;
|
Image = value.Image;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task OnInitializeAsync() =>
|
public override async Task InitializeAsync() =>
|
||||||
await Mediator.PublishAsync<Request<MediaInformation>>();
|
await Mediator.PublishAsync<Request<MediaInformation>>();
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1,3 +1,3 @@
|
|||||||
namespace Hyperbar.Widget.MediaController.Windows;
|
namespace Hyperbar.Widget.MediaController.Windows;
|
||||||
|
|
||||||
public record Play : INotification;
|
public record MediaNext;
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
namespace Hyperbar.Widget.MediaController.Windows;
|
||||||
|
|
||||||
|
public record MediaNextButton(bool IsEnabled) :
|
||||||
|
MediaButton(IsEnabled);
|
||||||
+1
-1
@@ -1,3 +1,3 @@
|
|||||||
namespace Hyperbar.Widget.MediaController.Windows;
|
namespace Hyperbar.Widget.MediaController.Windows;
|
||||||
|
|
||||||
public record Pause : INotification;
|
public record MediaPlayPause;
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
namespace Hyperbar.Widget.MediaController.Windows;
|
||||||
|
|
||||||
|
public record MediaPlayPauseButton(bool IsEnabled) :
|
||||||
|
MediaButton(IsEnabled);
|
||||||
+1
-1
@@ -1,3 +1,3 @@
|
|||||||
namespace Hyperbar.Widget.MediaController.Windows;
|
namespace Hyperbar.Widget.MediaController.Windows;
|
||||||
|
|
||||||
public record Forward : INotification;
|
public record MediaPrevious;
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
namespace Hyperbar.Widget.MediaController.Windows;
|
||||||
|
|
||||||
|
public record MediaPreviousButton(bool IsEnabled) :
|
||||||
|
MediaButton(IsEnabled);
|
||||||
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
namespace Hyperbar.Widget.MediaController.Windows;
|
|
||||||
|
|
||||||
public enum PlaybackButtonType
|
|
||||||
{
|
|
||||||
Previous,
|
|
||||||
Play,
|
|
||||||
Pause,
|
|
||||||
Forward
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
namespace Hyperbar.Widget.MediaController.Windows;
|
|
||||||
|
|
||||||
public enum PlaybackStatus
|
|
||||||
{
|
|
||||||
Closed,
|
|
||||||
Opened,
|
|
||||||
Changing,
|
|
||||||
Stopped,
|
|
||||||
Playing,
|
|
||||||
Paused
|
|
||||||
}
|
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.5.231202003-experimental1" />
|
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.5.240124002-experimental2" />
|
||||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26031-preview" />
|
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26031-preview" />
|
||||||
<PackageReference Include="Microsoft.Xaml.Behaviors.WinUI.Managed" Version="2.0.9" />
|
<PackageReference Include="Microsoft.Xaml.Behaviors.WinUI.Managed" Version="2.0.9" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
Width="{StaticResource ButtonWidth}"
|
Width="{StaticResource ButtonWidth}"
|
||||||
Height="{StaticResource ButtonHeight}"
|
Height="{StaticResource ButtonHeight}"
|
||||||
Padding="{StaticResource ButtonPadding}"
|
Padding="{StaticResource ButtonPadding}"
|
||||||
Command="{Binding Click}"
|
Command="{Binding InvokeCommand}"
|
||||||
Content="{Binding Icon}"
|
Content="{Binding Icon}"
|
||||||
FontFamily="{StaticResource SymbolThemeFontFamily}"
|
FontFamily="{StaticResource SymbolThemeFontFamily}"
|
||||||
FontSize="16"
|
FontSize="16"
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
<SplitButton
|
<SplitButton
|
||||||
Height="{StaticResource ButtonHeight}"
|
Height="{StaticResource ButtonHeight}"
|
||||||
Margin="0,1,0,0"
|
Margin="0,1,0,0"
|
||||||
Command="{Binding Click}"
|
Command="{Binding InvokeCommand}"
|
||||||
Content="{Binding Icon}"
|
Content="{Binding Icon}"
|
||||||
FontFamily="{StaticResource SymbolThemeFontFamily}"
|
FontFamily="{StaticResource SymbolThemeFontFamily}"
|
||||||
FontSize="16">
|
FontSize="16">
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
</ItemsControl.ItemContainerTransitions>
|
</ItemsControl.ItemContainerTransitions>
|
||||||
<interactivity:Interaction.Behaviors>
|
<interactivity:Interaction.Behaviors>
|
||||||
<interactions:EventTriggerBehavior EventName="Loaded">
|
<interactions:EventTriggerBehavior EventName="Loaded">
|
||||||
<interactions:InvokeCommandAction Command="{Binding Initialize}" />
|
<interactions:InvokeCommandAction Command="{Binding InitializeCommand}" />
|
||||||
</interactions:EventTriggerBehavior>
|
</interactions:EventTriggerBehavior>
|
||||||
</interactivity:Interaction.Behaviors>
|
</interactivity:Interaction.Behaviors>
|
||||||
</ItemsControl>
|
</ItemsControl>
|
||||||
|
|||||||
@@ -11,14 +11,8 @@ public partial class WidgetButtonViewModel(IServiceFactory serviceFactory,
|
|||||||
Guid id,
|
Guid id,
|
||||||
string? text = null,
|
string? text = null,
|
||||||
string? icon = null,
|
string? icon = null,
|
||||||
RelayCommand? command = null) : WidgetComponentViewModel(serviceFactory, mediator, disposer, templateFactory)
|
RelayCommand? invokeCommand = null) : WidgetComponentViewModel(serviceFactory, mediator, disposer, templateFactory)
|
||||||
{
|
{
|
||||||
[ObservableProperty]
|
|
||||||
private IRelayCommand? click = command;
|
|
||||||
|
|
||||||
[ObservableProperty]
|
|
||||||
private bool enabled;
|
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private string? icon = icon;
|
private string? icon = icon;
|
||||||
|
|
||||||
@@ -26,8 +20,11 @@ public partial class WidgetButtonViewModel(IServiceFactory serviceFactory,
|
|||||||
private Guid id = id;
|
private Guid id = id;
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private string? text = text;
|
private IRelayCommand? invokeCommand = invokeCommand;
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private bool visible;
|
private bool isEnabled;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string? text = text;
|
||||||
}
|
}
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
<PackageReference Include="CommunityToolkit.WinUI.UI.Controls.Primitives" Version="7.1.2" />
|
<PackageReference Include="CommunityToolkit.WinUI.UI.Controls.Primitives" Version="7.1.2" />
|
||||||
<PackageReference Include="CustomExtensions.WinUI" Version="0.1.10-beta" />
|
<PackageReference Include="CustomExtensions.WinUI" Version="0.1.10-beta" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
||||||
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.5.231202003-experimental1" />
|
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.5.240124002-experimental2" />
|
||||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26031-preview" />
|
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26031-preview" />
|
||||||
<PackageReference Include="Microsoft.Xaml.Behaviors.WinUI.Managed" Version="2.0.9" />
|
<PackageReference Include="Microsoft.Xaml.Behaviors.WinUI.Managed" Version="2.0.9" />
|
||||||
<Manifest Include="$(ApplicationManifest)" />
|
<Manifest Include="$(ApplicationManifest)" />
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ namespace Hyperbar;
|
|||||||
|
|
||||||
public interface IInitialization
|
public interface IInitialization
|
||||||
{
|
{
|
||||||
ICommand Initialize { get; }
|
ICommand InitializeCommand { get; }
|
||||||
|
|
||||||
Task InitializeAsync();
|
Task InitializeAsync();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
namespace Hyperbar;
|
namespace Hyperbar;
|
||||||
|
|
||||||
public interface IObservableCollectionViewModel<TItem>;
|
public interface IObservableCollectionViewModel<TItem> :
|
||||||
|
IObservableViewModel;
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
using System.Windows.Input;
|
||||||
|
|
||||||
|
namespace Hyperbar;
|
||||||
|
|
||||||
|
public interface IObservableViewModel
|
||||||
|
{
|
||||||
|
ICommand InitializeCommand { get; }
|
||||||
|
}
|
||||||
@@ -30,7 +30,7 @@ public partial class ObservableCollectionViewModel<TItem> :
|
|||||||
private bool isInitialized;
|
private bool isInitialized;
|
||||||
|
|
||||||
public ObservableCollectionViewModel(IServiceFactory serviceFactory,
|
public ObservableCollectionViewModel(IServiceFactory serviceFactory,
|
||||||
IMediator mediator,
|
IMediator mediator,
|
||||||
IDisposer disposer)
|
IDisposer disposer)
|
||||||
{
|
{
|
||||||
ServiceFactory = serviceFactory;
|
ServiceFactory = serviceFactory;
|
||||||
@@ -54,7 +54,6 @@ public partial class ObservableCollectionViewModel<TItem> :
|
|||||||
mediator.Subscribe(this);
|
mediator.Subscribe(this);
|
||||||
|
|
||||||
collection.CollectionChanged += OnCollectionChanged;
|
collection.CollectionChanged += OnCollectionChanged;
|
||||||
|
|
||||||
AddRange(items);
|
AddRange(items);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,8 +61,8 @@ public partial class ObservableCollectionViewModel<TItem> :
|
|||||||
|
|
||||||
public int Count => collection.Count;
|
public int Count => collection.Count;
|
||||||
|
|
||||||
public ICommand Initialize =>
|
public ICommand InitializeCommand =>
|
||||||
new AsyncRelayCommand(InitializeAsync);
|
new AsyncRelayCommand(CoreInitializeAsync);
|
||||||
|
|
||||||
bool IList.IsFixedSize => false;
|
bool IList.IsFixedSize => false;
|
||||||
|
|
||||||
@@ -297,7 +296,7 @@ public partial class ObservableCollectionViewModel<TItem> :
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual Task OnInitializeAsync()
|
public virtual Task InitializeAsync()
|
||||||
{
|
{
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
@@ -370,7 +369,7 @@ public partial class ObservableCollectionViewModel<TItem> :
|
|||||||
private static bool IsCompatibleObject(object? value) =>
|
private static bool IsCompatibleObject(object? value) =>
|
||||||
(value is TItem) || (value == null && default(TItem) == null);
|
(value is TItem) || (value == null && default(TItem) == null);
|
||||||
|
|
||||||
public async Task InitializeAsync()
|
private async Task CoreInitializeAsync()
|
||||||
{
|
{
|
||||||
if (isInitialized)
|
if (isInitialized)
|
||||||
{
|
{
|
||||||
@@ -380,8 +379,9 @@ public partial class ObservableCollectionViewModel<TItem> :
|
|||||||
isInitialized = true;
|
isInitialized = true;
|
||||||
|
|
||||||
await Mediator.PublishAsync<Enumerate<TItem>>();
|
await Mediator.PublishAsync<Enumerate<TItem>>();
|
||||||
await OnInitializeAsync();
|
await InitializeAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnCollectionChanged(object? sender, NotifyCollectionChangedEventArgs args) =>
|
private void OnCollectionChanged(object? sender, NotifyCollectionChangedEventArgs args) =>
|
||||||
CollectionChanged?.Invoke(this, args);
|
CollectionChanged?.Invoke(this, args);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user