fixed up media controller

This commit is contained in:
TheXamlGuy
2024-02-03 19:58:54 +00:00
parent 221c46218f
commit 23c398ea43
35 changed files with 217 additions and 195 deletions
@@ -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);
@@ -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,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="&#xE892;" />
</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="&#xE893;" />
</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,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,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,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">
+1 -1
View File
@@ -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>
+6 -9
View File
@@ -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;
} }
+1 -1
View File
@@ -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)" />
+1 -1
View File
@@ -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);
} }