restructure project for part 2
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
namespace Hyperbar.Widget.MediaController.Windows;
|
||||
|
||||
public record Backward : INotification;
|
||||
@@ -0,0 +1,3 @@
|
||||
namespace Hyperbar.Widget.MediaController.Windows;
|
||||
|
||||
public record Foward : INotification;
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0-windows10.0.19041.0</TargetFramework>
|
||||
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
|
||||
<RuntimeIdentifiers>win10-x86;win10-x64;win10-arm64</RuntimeIdentifiers>
|
||||
<UseWinUI>true</UseWinUI>
|
||||
<UseRidGraph>true</UseRidGraph>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CommunityToolkit.WinUI" 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="Microsoft.WindowsAppSDK" Version="1.5.231202003-experimental1" />
|
||||
<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.Extensions.Hosting" Version="8.0.0" />
|
||||
<PackageReference Include="CustomExtensions.WinUI" Version="0.1.10-beta" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Hyperbar.Controls.Windows\Hyperbar.Controls.Windows.csproj" />
|
||||
<ProjectReference Include="..\Hyperbar.Interop.Windows\Hyperbar.Interop.Windows.csproj" />
|
||||
<ProjectReference Include="..\Hyperbar.Widget\Hyperbar.Widget.csproj" />
|
||||
<ProjectReference Include="..\Hyperbar\Hyperbar.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<UserControl
|
||||
x:Class="Hyperbar.Widget.MediaController.Windows.MediaButtonView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:interactions="using:Microsoft.Xaml.Interactions.Core"
|
||||
xmlns:interactivity="using:Microsoft.Xaml.Interactivity">
|
||||
<UserControl.Resources>
|
||||
<SolidColorBrush x:Key="ButtonBackground" Color="Transparent" />
|
||||
<SolidColorBrush x:Key="ButtonBorderBrush" Color="Transparent" />
|
||||
<SolidColorBrush x:Key="ButtonBorderBrushPointerOver" Color="Transparent" />
|
||||
<SolidColorBrush x:Key="ButtonBorderBrushPressed" Color="Transparent" />
|
||||
<SolidColorBrush x:Key="ButtonBorderBrushDisabled" Color="Transparent" />
|
||||
<Thickness x:Key="ButtonPadding">0</Thickness>
|
||||
<x:Double x:Key="ButtonWidth">40</x:Double>
|
||||
<x:Double x:Key="ButtonHeight">40</x:Double>
|
||||
</UserControl.Resources>
|
||||
<Button
|
||||
Width="{StaticResource ButtonWidth}"
|
||||
Height="{StaticResource ButtonHeight}"
|
||||
Padding="{StaticResource ButtonPadding}"
|
||||
Command="{Binding Click}"
|
||||
Content="{Binding Icon}"
|
||||
FontFamily="{StaticResource SymbolThemeFontFamily}"
|
||||
FontSize="16"
|
||||
ToolTipService.ToolTip="{Binding Text}">
|
||||
<interactivity:Interaction.Behaviors>
|
||||
<interactions:EventTriggerBehavior EventName="Loaded">
|
||||
<interactions:InvokeCommandAction Command="{Binding Initialize}" />
|
||||
</interactions:EventTriggerBehavior>
|
||||
</interactivity:Interaction.Behaviors>
|
||||
</Button>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,9 @@
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Hyperbar.Widget.MediaController.Windows;
|
||||
|
||||
public sealed partial class MediaButtonView :
|
||||
UserControl
|
||||
{
|
||||
public MediaButtonView() => InitializeComponent();
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Hyperbar.Widget;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace Hyperbar.Widget.MediaController.Windows;
|
||||
|
||||
public class MediaButtonViewModel(IServiceFactory serviceFactory,
|
||||
IMediator mediator,
|
||||
IDisposer disposer,
|
||||
ITemplateFactory templateFactory,
|
||||
Guid guid = default,
|
||||
string? text = null,
|
||||
string? icon = null,
|
||||
RelayCommand? command = null) :
|
||||
WidgetButtonViewModel(serviceFactory, mediator, disposer, templateFactory, guid, text, icon, command),
|
||||
IInitialization
|
||||
{
|
||||
public ICommand Initialize => new AsyncRelayCommand(InitializeAsync);
|
||||
|
||||
public async Task InitializeAsync() => await Mediator.PublishAsync<Request<Playback>>();
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
using Windows.Media.Control;
|
||||
|
||||
namespace Hyperbar.Widget.MediaController.Windows;
|
||||
|
||||
public class MediaController :
|
||||
INotificationHandler<Play>,
|
||||
INotificationHandler<Pause>,
|
||||
INotificationHandler<Request<Playback>>,
|
||||
INotificationHandler<Request<MediaInformation>>,
|
||||
IDisposable
|
||||
{
|
||||
private readonly IMediator mediator;
|
||||
private readonly IDisposer disposer;
|
||||
private readonly GlobalSystemMediaTransportControlsSession session;
|
||||
private readonly AsyncLock asyncLock = new();
|
||||
|
||||
public MediaController(IMediator mediator,
|
||||
IDisposer disposer,
|
||||
GlobalSystemMediaTransportControlsSession session)
|
||||
{
|
||||
this.mediator = mediator;
|
||||
this.disposer = disposer;
|
||||
this.session = session;
|
||||
|
||||
disposer.Add(this);
|
||||
mediator.Subscribe(this);
|
||||
|
||||
session.MediaPropertiesChanged += OnMediaPropertiesChanged;
|
||||
session.PlaybackInfoChanged += OnPlaybackInfoChanged;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
disposer.Dispose(this);
|
||||
}
|
||||
|
||||
public async Task Handle(Play notification,
|
||||
CancellationToken cancellationToken) =>
|
||||
await session.TryPlayAsync();
|
||||
|
||||
public async Task Handle(Pause notification,
|
||||
CancellationToken cancellationToken) =>
|
||||
await session.TryPauseAsync();
|
||||
|
||||
public async Task Handle(Request<Playback> notification,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
await mediator.PublishAsync(new Changed<Playback>(), cancellationToken);
|
||||
}
|
||||
|
||||
public async Task Handle(Request<MediaInformation> _,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
using (await asyncLock)
|
||||
{
|
||||
try
|
||||
{
|
||||
GlobalSystemMediaTransportControlsSessionMediaProperties mediaProperties = await session.TryGetMediaPropertiesAsync();
|
||||
await mediator.PublishAsync(new Changed<MediaInformation>(new MediaInformation(mediaProperties.Title,
|
||||
mediaProperties.Subtitle)), cancellationToken);
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async void OnMediaPropertiesChanged(GlobalSystemMediaTransportControlsSession sender,
|
||||
MediaPropertiesChangedEventArgs args)
|
||||
{
|
||||
using (await asyncLock)
|
||||
{
|
||||
try
|
||||
{
|
||||
GlobalSystemMediaTransportControlsSessionMediaProperties mediaProperties = await session.TryGetMediaPropertiesAsync();
|
||||
await mediator.PublishAsync(new Changed<MediaInformation>(new MediaInformation(mediaProperties.Title,
|
||||
mediaProperties.Artist)));
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async void OnPlaybackInfoChanged(GlobalSystemMediaTransportControlsSession sender,
|
||||
PlaybackInfoChangedEventArgs args)
|
||||
{
|
||||
await mediator.PublishAsync(new Changed<Playback>());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using Windows.Media.Control;
|
||||
|
||||
namespace Hyperbar.Widget.MediaController.Windows;
|
||||
|
||||
public class MediaControllerFactory(IServiceScopeFactory<MediaController> serviceScopeFactory) :
|
||||
IFactory<GlobalSystemMediaTransportControlsSession, MediaController?>
|
||||
{
|
||||
public MediaController? Create(GlobalSystemMediaTransportControlsSession value)
|
||||
{
|
||||
if (serviceScopeFactory.Create(value) is MediaController mediaController)
|
||||
{
|
||||
return mediaController;
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Hyperbar.Widget.MediaController.Windows;
|
||||
|
||||
public class MediaControllerHandler(IMediator mediator,
|
||||
IServiceScopeProvider<MediaController> scopeProvider,
|
||||
ICache<MediaController, MediaControllerViewModel> cache) :
|
||||
INotificationHandler<Created<MediaController>>
|
||||
{
|
||||
public async Task Handle(Created<MediaController> notification,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
if (notification.Value is MediaController mediaController)
|
||||
{
|
||||
if (scopeProvider.TryGet(mediaController, out IServiceScope? serviceScope))
|
||||
|
||||
if (serviceScope is not null)
|
||||
{
|
||||
if (serviceScope.ServiceProvider.GetService<IFactory<MediaController, MediaControllerViewModel?>>()
|
||||
is IFactory<MediaController, MediaControllerViewModel?> factory)
|
||||
{
|
||||
if (factory.Create(mediaController) is MediaControllerViewModel mediaControllerViewModel)
|
||||
{
|
||||
cache.Add(mediaController, mediaControllerViewModel);
|
||||
//await mediator.PublishAsync(new Created<MediaControllerViewModel>(mediaControllerViewModel),
|
||||
// cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
using Windows.Media.Control;
|
||||
|
||||
namespace Hyperbar.Widget.MediaController.Windows;
|
||||
|
||||
public class MediaControllerManager(IMediator mediator,
|
||||
IFactory<GlobalSystemMediaTransportControlsSession, MediaController> factory,
|
||||
IDispatcher dispatcher,
|
||||
IDisposer disposer) :
|
||||
IInitializer
|
||||
{
|
||||
private readonly AsyncLock asyncLock = new();
|
||||
private readonly List<KeyValuePair<GlobalSystemMediaTransportControlsSession, MediaController>> cache = [];
|
||||
private GlobalSystemMediaTransportControlsSessionManager? mediaTransportControlsSessionManager;
|
||||
|
||||
public async Task InitializeAsync()
|
||||
{
|
||||
mediaTransportControlsSessionManager = await GlobalSystemMediaTransportControlsSessionManager.RequestAsync();
|
||||
mediaTransportControlsSessionManager.SessionsChanged += OnSessionsChanged;
|
||||
|
||||
IReadOnlyList<GlobalSystemMediaTransportControlsSession> sessions =
|
||||
mediaTransportControlsSessionManager.GetSessions();
|
||||
|
||||
foreach (GlobalSystemMediaTransportControlsSession session in sessions)
|
||||
{
|
||||
await InitializeSessionAsync(session);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task InitializeSessionAsync(GlobalSystemMediaTransportControlsSession session)
|
||||
{
|
||||
if (factory.Create(session) is MediaController mediaController)
|
||||
{
|
||||
await mediator.PublishAsync(new Created<MediaController>(mediaController));
|
||||
cache.Add(new KeyValuePair<GlobalSystemMediaTransportControlsSession, MediaController>(session, mediaController));
|
||||
}
|
||||
}
|
||||
|
||||
private async void OnSessionsChanged(GlobalSystemMediaTransportControlsSessionManager sender,
|
||||
SessionsChangedEventArgs args)
|
||||
{
|
||||
IReadOnlyList<GlobalSystemMediaTransportControlsSession> sessions =
|
||||
sender.GetSessions();
|
||||
|
||||
using (await asyncLock)
|
||||
{
|
||||
foreach (KeyValuePair<GlobalSystemMediaTransportControlsSession, MediaController> session in
|
||||
cache.ToList())
|
||||
{
|
||||
if (!sessions.Any(x => x.SourceAppUserModelId == session.Key.SourceAppUserModelId))
|
||||
{
|
||||
await dispatcher.InvokeAsync(() => disposer.Dispose(session.Value));
|
||||
cache.Remove(session);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
using (await asyncLock)
|
||||
{
|
||||
foreach (GlobalSystemMediaTransportControlsSession session in sessions)
|
||||
{
|
||||
if (!cache.Any(x => x.Key.SourceAppUserModelId == session.SourceAppUserModelId))
|
||||
{
|
||||
await InitializeSessionAsync(session);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<UserControl
|
||||
x:Class="Hyperbar.Widget.MediaController.Windows.MediaControllerView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:ui="using:Hyperbar.UI.Windows">
|
||||
<Grid Width="400" Background="red">
|
||||
<ItemsControl
|
||||
HorizontalAlignment="Center"
|
||||
ItemTemplateSelector="{Binding Converter={ui:DataTemplateConverter}}"
|
||||
ItemsSource="{Binding}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Horizontal" Spacing="8" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
</ItemsControl>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,9 @@
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Hyperbar.Widget.MediaController.Windows;
|
||||
|
||||
public sealed partial class MediaControllerView :
|
||||
UserControl
|
||||
{
|
||||
public MediaControllerView() => InitializeComponent();
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Hyperbar.Widget;
|
||||
|
||||
namespace Hyperbar.Widget.MediaController.Windows;
|
||||
|
||||
public class MediaControllerViewModel :
|
||||
ObservableCollectionViewModel<WidgetComponentViewModel>,
|
||||
ITemplatedViewModel
|
||||
{
|
||||
public MediaControllerViewModel(ITemplateFactory templateFactory,
|
||||
IServiceFactory serviceFactory,
|
||||
IMediator mediator,
|
||||
IDisposer disposer) : base(serviceFactory, mediator, disposer)
|
||||
{
|
||||
TemplateFactory = templateFactory;
|
||||
|
||||
Add<MediaInformationViewModel>();
|
||||
Add<MediaButtonViewModel>("Backward", "\uEB9E");
|
||||
Add<MediaButtonViewModel>("Play", "\uE768", new RelayCommand(async () => await mediator.PublishAsync<Play>()));
|
||||
Add<MediaButtonViewModel>("Pause", "\uE769", new RelayCommand(async () => await mediator.PublishAsync<Pause>()));
|
||||
Add<MediaButtonViewModel>("Forward", "\uEB9D");
|
||||
}
|
||||
|
||||
public ITemplateFactory TemplateFactory { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace Hyperbar.Widget.MediaController.Windows;
|
||||
|
||||
public class MediaControllerViewModelFactory(IServiceFactory service) :
|
||||
IFactory<MediaController, MediaControllerViewModel?>
|
||||
{
|
||||
public MediaControllerViewModel? Create(MediaController value)
|
||||
{
|
||||
if (service.Create<MediaControllerViewModel>()
|
||||
is MediaControllerViewModel widgetComponentViewModel)
|
||||
{
|
||||
return widgetComponentViewModel;
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using Hyperbar.Widget;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Windows.Media.Control;
|
||||
|
||||
namespace Hyperbar.Widget.MediaController.Windows;
|
||||
|
||||
public class MediaControllerWidget :
|
||||
IWidget
|
||||
{
|
||||
public IWidgetBuilder Create() =>
|
||||
WidgetBuilder<MediaControllerWidgetConfiguration>.Configure(args =>
|
||||
{
|
||||
args.Name = "Media controller";
|
||||
}).ConfigureServices(args =>
|
||||
{
|
||||
args.AddWidgetTemplate<MediaControllerWidgetViewModel, MediaControllerWidgetView>()
|
||||
.AddSingleton<IInitializer, MediaControllerManager>()
|
||||
.AddTransient<IServiceScopeFactory<MediaController>, ServiceScopeFactory<MediaController>>()
|
||||
.AddTransient<IServiceScopeProvider<MediaController>, ServiceScopeProvider<MediaController>>()
|
||||
.AddCache<MediaController, IServiceScope>()
|
||||
.AddTransient<IFactory<GlobalSystemMediaTransportControlsSession, MediaController?>, MediaControllerFactory>()
|
||||
.AddHandler<MediaControllerHandler>()
|
||||
.AddTransient<IFactory<MediaController, MediaControllerViewModel?>, MediaControllerViewModelFactory>()
|
||||
.AddCache<MediaController, MediaControllerViewModel>()
|
||||
.AddContentTemplate<MediaControllerViewModel, MediaControllerView>()
|
||||
.AddContentTemplate<MediaInformationViewModel, MediaInformationView>()
|
||||
.AddContentTemplate<MediaButtonViewModel, MediaButtonView>();
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using Hyperbar.Widget;
|
||||
|
||||
namespace Hyperbar.Widget.MediaController.Windows;
|
||||
|
||||
public class MediaControllerWidgetConfiguration :
|
||||
WidgetConfiguration
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<UserControl
|
||||
x:Class="Hyperbar.Widget.MediaController.Windows.MediaControllerWidgetView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Button>sdfsdfsdg</Button>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,74 @@
|
||||
using CustomExtensions.WinUI;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
namespace Hyperbar.Widget.MediaController.Windows;
|
||||
|
||||
public sealed partial class MediaControllerWidgetView :
|
||||
UserControl
|
||||
{
|
||||
public MediaControllerWidgetView()
|
||||
{
|
||||
Foo(@"C:\Users\dan_c\AppData\Local\Packages\24ccddba-447f-4d37-891d-523e8d820f45_rmhrgjnfy8he0\LocalCache\Local\Hyperbar.Windows\Extensions\Hyperbar.Windows.MediaController\Hyperbar.Windows.MediaController.dll");
|
||||
LocateResourcePath(this);
|
||||
}
|
||||
|
||||
public Assembly ForeignAssembly { get; set; }
|
||||
|
||||
private string ForeignAssemblyDir;
|
||||
private string ForeignAssemblyName;
|
||||
private bool? IsHotReloadAvailable;
|
||||
private DisposableCollection Disposables = new();
|
||||
private bool IsDisposed;
|
||||
|
||||
internal static readonly Assembly? EntryAssembly;
|
||||
internal static readonly string HostingProcessDir;
|
||||
|
||||
static MediaControllerWidgetView()
|
||||
{
|
||||
EntryAssembly = Assembly.GetEntryAssembly();
|
||||
HostingProcessDir = Path.GetDirectoryName(EntryAssembly.Location);
|
||||
}
|
||||
|
||||
public void Foo(string assemblyPath)
|
||||
{
|
||||
// TODO: For some reason WinUI gets very angry when loading via AssemblyLoadContext,
|
||||
// even if using AssemblyLoadContext.Default which *should* have no difference than
|
||||
// Assembly.LoadFrom(), but it does.
|
||||
//
|
||||
// ExtensionContext = new(assemblyPath);
|
||||
// ForeignAssembly = ExtensionContext.LoadFromAssemblyPath(assemblyPath);
|
||||
ForeignAssembly = Assembly.LoadFrom(assemblyPath);
|
||||
ForeignAssemblyDir = Path.GetDirectoryName(ForeignAssembly.Location);
|
||||
ForeignAssemblyName = ForeignAssembly.GetName().Name;
|
||||
}
|
||||
|
||||
private string LocateResourcePath(object component, [CallerFilePath] string callerFilePath = "")
|
||||
{
|
||||
if (component.GetType().Assembly != ForeignAssembly)
|
||||
{
|
||||
throw new InvalidProgramException();
|
||||
}
|
||||
string resourceName = Path.GetFileName(callerFilePath)[..^3];
|
||||
|
||||
string[] pathParts = callerFilePath.Split('\\')[..^1];
|
||||
for (int i = pathParts.Length - 1; i > 1; i++)
|
||||
{
|
||||
string pathCandidate = Path.Join(pathParts[i..pathParts.Length].Append(resourceName).Prepend(ForeignAssemblyName).ToArray());
|
||||
FileInfo sourceResource = new(Path.Combine(ForeignAssemblyDir, pathCandidate));
|
||||
FileInfo colocatedResource = new(Path.Combine(HostingProcessDir, pathCandidate));
|
||||
if (colocatedResource.Exists)
|
||||
{
|
||||
return pathCandidate;
|
||||
}
|
||||
if (sourceResource.Exists)
|
||||
{
|
||||
return sourceResource.FullName;
|
||||
}
|
||||
|
||||
throw new FileNotFoundException("Could not find resource", resourceName);
|
||||
}
|
||||
|
||||
throw new FileNotFoundException("Could not find resource", resourceName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using Hyperbar.Widget;
|
||||
|
||||
namespace Hyperbar.Widget.MediaController.Windows;
|
||||
|
||||
public class MediaControllerWidgetViewModel(ITemplateFactory templateFactory,
|
||||
IServiceFactory serviceFactory,
|
||||
IMediator mediator,
|
||||
IDisposer disposer,
|
||||
IEnumerable<MediaControllerViewModel> items) :
|
||||
ObservableCollectionViewModel<MediaControllerViewModel>(serviceFactory, mediator, disposer, items),
|
||||
IWidgetViewModel,
|
||||
ITemplatedViewModel
|
||||
{
|
||||
public ITemplateFactory TemplateFactory => templateFactory;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
namespace Hyperbar.Widget.MediaController.Windows;
|
||||
|
||||
public record MediaInformation(string Title, string Description);
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<UserControl
|
||||
x:Class="Hyperbar.Widget.MediaController.Windows.MediaInformationView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:interactions="using:Microsoft.Xaml.Interactions.Core"
|
||||
xmlns:interactivity="using:Microsoft.Xaml.Interactivity">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="40" />
|
||||
<ColumnDefinition Width="8" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Border
|
||||
Grid.Column="0"
|
||||
Width="40"
|
||||
Height="40"
|
||||
Background="Red" />
|
||||
<StackPanel Grid.Column="2">
|
||||
<TextBlock Style="{ThemeResource BaseTextBlockStyle}" Text="{Binding Title}" />
|
||||
<TextBlock
|
||||
Opacity="0.7"
|
||||
Style="{ThemeResource CaptionTextBlockStyle}"
|
||||
Text="{Binding Description}" />
|
||||
<interactivity:Interaction.Behaviors>
|
||||
<interactions:EventTriggerBehavior EventName="Loaded">
|
||||
<interactions:InvokeCommandAction Command="{Binding Initialize}" />
|
||||
</interactions:EventTriggerBehavior>
|
||||
</interactivity:Interaction.Behaviors>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,10 @@
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Hyperbar.UI.Windows;
|
||||
|
||||
namespace Hyperbar.Widget.MediaController.Windows;
|
||||
|
||||
public sealed partial class MediaInformationView :
|
||||
UserControl
|
||||
{
|
||||
public MediaInformationView() => this.InitializeComponent(ref _contentLoaded);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Hyperbar.Widget;
|
||||
|
||||
namespace Hyperbar.Widget.MediaController.Windows;
|
||||
|
||||
public partial class MediaInformationViewModel(IServiceFactory serviceFactory,
|
||||
IMediator mediator,
|
||||
IDisposer disposer,
|
||||
ITemplateFactory templateFactory) :
|
||||
WidgetComponentViewModel(serviceFactory, mediator, disposer, templateFactory),
|
||||
IInitialization,
|
||||
INotificationHandler<Changed<MediaInformation>>
|
||||
{
|
||||
[ObservableProperty]
|
||||
private string? description;
|
||||
|
||||
[ObservableProperty]
|
||||
private string? title;
|
||||
|
||||
public Task Handle(Changed<MediaInformation> notification,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
if (notification.Value is MediaInformation value)
|
||||
{
|
||||
Title = value.Title;
|
||||
Description = value.Description;
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public override async Task InitializeAsync() =>
|
||||
await Mediator.PublishAsync<Request<MediaInformation>>();
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
namespace Hyperbar.Widget.MediaController.Windows;
|
||||
|
||||
public record Pause : INotification;
|
||||
@@ -0,0 +1,3 @@
|
||||
namespace Hyperbar.Widget.MediaController.Windows;
|
||||
|
||||
public record Play : INotification;
|
||||
@@ -0,0 +1,3 @@
|
||||
namespace Hyperbar.Widget.MediaController.Windows;
|
||||
|
||||
public record Playback : INotification;
|
||||
Reference in New Issue
Block a user