bunch ov fixes
This commit is contained in:
@@ -1,4 +1,7 @@
|
|||||||
using System.Runtime.CompilerServices;
|
using Microsoft.UI.Xaml;
|
||||||
|
using Microsoft.UI.Xaml.Controls.Primitives;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using WinRT;
|
using WinRT;
|
||||||
|
|
||||||
namespace Hyperbar.UI.Windows;
|
namespace Hyperbar.UI.Windows;
|
||||||
@@ -6,19 +9,30 @@ namespace Hyperbar.UI.Windows;
|
|||||||
public static class IWinRTObjectExtensions
|
public static class IWinRTObjectExtensions
|
||||||
{
|
{
|
||||||
public static void InitializeComponent<TComponent>(this TComponent component,
|
public static void InitializeComponent<TComponent>(this TComponent component,
|
||||||
ref bool loaded,
|
ref bool loaded, [CallerFilePath] string path = "")
|
||||||
[CallerFilePath] string path = "")
|
where TComponent : IWinRTObject
|
||||||
where TComponent :
|
|
||||||
IWinRTObject
|
|
||||||
{
|
{
|
||||||
if (loaded)
|
if (!loaded)
|
||||||
{
|
{
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
loaded = true;
|
loaded = true;
|
||||||
|
|
||||||
//Uri resourceLocator = ApplicationExtensionHost.Current.LocateResource(component, callerFilePath);
|
Type type = component.GetType();
|
||||||
//Application.LoadComponent(component, resourceLocator, ComponentResourceLocation.Nested);
|
if (type.Assembly is Assembly assembly && Path.GetDirectoryName(assembly.Location) is string assemblyDirectory)
|
||||||
|
{
|
||||||
|
string resourceName = Path.GetFileNameWithoutExtension(path);
|
||||||
|
string[] pathParts = path.Split(Path.DirectorySeparatorChar)[..^1];
|
||||||
|
|
||||||
|
string? resourcePath = pathParts
|
||||||
|
.Reverse()
|
||||||
|
.Select(part => Path.Combine(assemblyDirectory, part, resourceName))
|
||||||
|
.FirstOrDefault(File.Exists);
|
||||||
|
|
||||||
|
if (resourcePath is not null)
|
||||||
|
{
|
||||||
|
Application.LoadComponent(component, new Uri($"ms-appx:///{resourcePath.Replace('\\', '/')}"),
|
||||||
|
ComponentResourceLocation.Nested);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1,3 +1,3 @@
|
|||||||
namespace Hyperbar.Widget.MediaController.Windows;
|
namespace Hyperbar.Widget.MediaController.Windows;
|
||||||
|
|
||||||
public record Foward : INotification;
|
public record Forward : INotification;
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
using Microsoft.UI.Xaml.Controls;
|
using Microsoft.UI.Xaml.Controls;
|
||||||
|
using Hyperbar.UI.Windows;
|
||||||
|
|
||||||
namespace Hyperbar.Widget.MediaController.Windows;
|
namespace Hyperbar.Widget.MediaController.Windows;
|
||||||
|
|
||||||
public sealed partial class MediaButtonView :
|
public sealed partial class MediaButtonView :
|
||||||
UserControl
|
UserControl
|
||||||
{
|
{
|
||||||
public MediaButtonView() => InitializeComponent();
|
public MediaButtonView() =>
|
||||||
|
this.InitializeComponent(ref _contentLoaded);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,47 @@
|
|||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using Hyperbar.Widget;
|
|
||||||
using System.Windows.Input;
|
|
||||||
|
|
||||||
namespace Hyperbar.Widget.MediaController.Windows;
|
namespace Hyperbar.Widget.MediaController.Windows;
|
||||||
|
|
||||||
public class MediaButtonViewModel(IServiceFactory serviceFactory,
|
public class MediaButtonViewModel :
|
||||||
|
WidgetButtonViewModel,
|
||||||
|
IInitialization,
|
||||||
|
INotificationHandler<Changed<PlaybackInformation>>
|
||||||
|
{
|
||||||
|
private readonly PlaybackButtonType buttonType;
|
||||||
|
|
||||||
|
public MediaButtonViewModel(IServiceFactory serviceFactory,
|
||||||
IMediator mediator,
|
IMediator mediator,
|
||||||
IDisposer disposer,
|
IDisposer disposer,
|
||||||
ITemplateFactory templateFactory,
|
ITemplateFactory templateFactory,
|
||||||
|
PlaybackButtonType buttonType,
|
||||||
Guid guid = default,
|
Guid guid = default,
|
||||||
string? text = null,
|
string? text = null,
|
||||||
string? icon = null,
|
string? icon = null,
|
||||||
RelayCommand? command = null) :
|
RelayCommand? command = null) : base (serviceFactory, mediator, disposer, templateFactory, guid, text, icon, command)
|
||||||
WidgetButtonViewModel(serviceFactory, mediator, disposer, templateFactory, guid, text, icon, command),
|
|
||||||
IInitialization
|
|
||||||
{
|
{
|
||||||
public ICommand Initialize => new AsyncRelayCommand(InitializeAsync);
|
this.buttonType = buttonType;
|
||||||
|
mediator.Subscribe(this);
|
||||||
public async Task InitializeAsync() => await Mediator.PublishAsync<Request<Playback>>();
|
}
|
||||||
|
|
||||||
|
public Task Handle(Changed<PlaybackInformation> notification,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
if (notification.Value is PlaybackInformation information)
|
||||||
|
{
|
||||||
|
switch (buttonType)
|
||||||
|
{
|
||||||
|
case PlaybackButtonType.Play:
|
||||||
|
Visible = information.Status is PlaybackStatus.Playing;
|
||||||
|
break;
|
||||||
|
case PlaybackButtonType.Pause:
|
||||||
|
Visible = information.Status is PlaybackStatus.Paused;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task InitializeAsync() =>
|
||||||
|
await Mediator.PublishAsync<Request<PlaybackInformation>>();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,14 +5,14 @@ namespace Hyperbar.Widget.MediaController.Windows;
|
|||||||
public class MediaController :
|
public class MediaController :
|
||||||
INotificationHandler<Play>,
|
INotificationHandler<Play>,
|
||||||
INotificationHandler<Pause>,
|
INotificationHandler<Pause>,
|
||||||
INotificationHandler<Request<Playback>>,
|
INotificationHandler<Request<PlaybackInformation>>,
|
||||||
INotificationHandler<Request<MediaInformation>>,
|
INotificationHandler<Request<MediaInformation>>,
|
||||||
IDisposable
|
IDisposable
|
||||||
{
|
{
|
||||||
private readonly IMediator mediator;
|
|
||||||
private readonly IDisposer disposer;
|
|
||||||
private readonly GlobalSystemMediaTransportControlsSession session;
|
|
||||||
private readonly AsyncLock asyncLock = new();
|
private readonly AsyncLock asyncLock = new();
|
||||||
|
private readonly IDisposer disposer;
|
||||||
|
private readonly IMediator mediator;
|
||||||
|
private readonly GlobalSystemMediaTransportControlsSession session;
|
||||||
|
|
||||||
public MediaController(IMediator mediator,
|
public MediaController(IMediator mediator,
|
||||||
IDisposer disposer,
|
IDisposer disposer,
|
||||||
@@ -31,51 +31,46 @@ public class MediaController :
|
|||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
disposer.Dispose(this);
|
disposer.Dispose(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Handle(Play notification,
|
public async Task Handle(Play notification,
|
||||||
CancellationToken cancellationToken) =>
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
await session.TryPlayAsync();
|
await session.TryPlayAsync();
|
||||||
|
await UpdateMediaPlaybackPropertiesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
public async Task Handle(Pause notification,
|
public async Task Handle(Pause notification,
|
||||||
CancellationToken cancellationToken) =>
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
await session.TryPauseAsync();
|
await session.TryPauseAsync();
|
||||||
|
await UpdateMediaPlaybackPropertiesAsync();
|
||||||
public async Task Handle(Request<Playback> notification,
|
|
||||||
CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
await mediator.PublishAsync(new Changed<Playback>(), cancellationToken);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Handle(Request<MediaInformation> _,
|
public async Task Handle(Request<PlaybackInformation> args,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken) => await UpdateMediaPlaybackPropertiesAsync();
|
||||||
{
|
|
||||||
using (await asyncLock)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
GlobalSystemMediaTransportControlsSessionMediaProperties mediaProperties = await session.TryGetMediaPropertiesAsync();
|
|
||||||
await mediator.PublishAsync(new Changed<MediaInformation>(new MediaInformation(mediaProperties.Title,
|
|
||||||
mediaProperties.Subtitle)), cancellationToken);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
public async Task Handle(Request<MediaInformation> args,
|
||||||
}
|
CancellationToken cancellationToken) => await UpdateMediaPropertiesAsync();
|
||||||
}
|
|
||||||
|
|
||||||
private async void OnMediaPropertiesChanged(GlobalSystemMediaTransportControlsSession sender,
|
private async void OnMediaPropertiesChanged(GlobalSystemMediaTransportControlsSession sender,
|
||||||
MediaPropertiesChangedEventArgs args)
|
MediaPropertiesChangedEventArgs args) => await UpdateMediaPropertiesAsync();
|
||||||
|
|
||||||
|
private async void OnPlaybackInfoChanged(GlobalSystemMediaTransportControlsSession sender,
|
||||||
|
PlaybackInfoChangedEventArgs args) => await UpdateMediaPlaybackPropertiesAsync();
|
||||||
|
|
||||||
|
private async Task UpdateMediaPlaybackPropertiesAsync()
|
||||||
{
|
{
|
||||||
using (await asyncLock)
|
using (await asyncLock)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
GlobalSystemMediaTransportControlsSessionMediaProperties mediaProperties = await session.TryGetMediaPropertiesAsync();
|
GlobalSystemMediaTransportControlsSessionPlaybackInfo playbackInfo = session.GetPlaybackInfo();
|
||||||
await mediator.PublishAsync(new Changed<MediaInformation>(new MediaInformation(mediaProperties.Title,
|
await mediator.PublishAsync(new Changed<PlaybackInformation>(
|
||||||
mediaProperties.Artist)));
|
new PlaybackInformation((PlaybackStatus)playbackInfo.PlaybackStatus)));
|
||||||
|
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@@ -84,9 +79,23 @@ public class MediaController :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void OnPlaybackInfoChanged(GlobalSystemMediaTransportControlsSession sender,
|
private async Task UpdateMediaPropertiesAsync()
|
||||||
PlaybackInfoChangedEventArgs args)
|
|
||||||
{
|
{
|
||||||
await mediator.PublishAsync(new Changed<Playback>());
|
using (await asyncLock)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
GlobalSystemMediaTransportControlsSessionMediaProperties mediaProperties =
|
||||||
|
await session.TryGetMediaPropertiesAsync();
|
||||||
|
|
||||||
|
await mediator.PublishAsync(new Changed<MediaInformation>(new MediaInformation(mediaProperties.Title,
|
||||||
|
mediaProperties.Artist)));
|
||||||
|
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -22,8 +22,8 @@ public class MediaControllerHandler(IMediator mediator,
|
|||||||
if (factory.Create(mediaController) is MediaControllerViewModel mediaControllerViewModel)
|
if (factory.Create(mediaController) is MediaControllerViewModel mediaControllerViewModel)
|
||||||
{
|
{
|
||||||
cache.Add(mediaController, mediaControllerViewModel);
|
cache.Add(mediaController, mediaControllerViewModel);
|
||||||
//await mediator.PublishAsync(new Created<MediaControllerViewModel>(mediaControllerViewModel),
|
await mediator.PublishAsync(new Created<MediaControllerViewModel>(mediaControllerViewModel),
|
||||||
// cancellationToken);
|
cancellationToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
using Microsoft.UI.Xaml.Controls;
|
using Microsoft.UI.Xaml.Controls;
|
||||||
|
using Hyperbar.UI.Windows;
|
||||||
|
|
||||||
namespace Hyperbar.Widget.MediaController.Windows;
|
namespace Hyperbar.Widget.MediaController.Windows;
|
||||||
|
|
||||||
public sealed partial class MediaControllerView :
|
public sealed partial class MediaControllerView :
|
||||||
UserControl
|
UserControl
|
||||||
{
|
{
|
||||||
public MediaControllerView() => InitializeComponent();
|
public MediaControllerView() =>
|
||||||
|
this.InitializeComponent(ref _contentLoaded);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using Hyperbar.Widget;
|
|
||||||
|
|
||||||
namespace Hyperbar.Widget.MediaController.Windows;
|
namespace Hyperbar.Widget.MediaController.Windows;
|
||||||
|
|
||||||
@@ -15,10 +14,24 @@ public class MediaControllerViewModel :
|
|||||||
TemplateFactory = templateFactory;
|
TemplateFactory = templateFactory;
|
||||||
|
|
||||||
Add<MediaInformationViewModel>();
|
Add<MediaInformationViewModel>();
|
||||||
Add<MediaButtonViewModel>("Backward", "\uEB9E");
|
|
||||||
Add<MediaButtonViewModel>("Play", "\uE768", new RelayCommand(async () => await mediator.PublishAsync<Play>()));
|
Add<MediaButtonViewModel>(PlaybackButtonType.Previous,
|
||||||
Add<MediaButtonViewModel>("Pause", "\uE769", new RelayCommand(async () => await mediator.PublishAsync<Pause>()));
|
"Previous", "\uEB9E",
|
||||||
Add<MediaButtonViewModel>("Forward", "\uEB9D");
|
new RelayCommand(async () => await mediator.PublishAsync<Previous>()));
|
||||||
|
|
||||||
|
Add<MediaButtonViewModel>(PlaybackButtonType.Play,
|
||||||
|
"Play", "\uE768",
|
||||||
|
new RelayCommand(async () => await mediator.PublishAsync<Play>()));
|
||||||
|
|
||||||
|
Add<MediaButtonViewModel>(PlaybackButtonType.Pause,
|
||||||
|
"Pause", "\uE769",
|
||||||
|
new RelayCommand(async () => await mediator.PublishAsync<Pause>()));
|
||||||
|
|
||||||
|
Add<MediaButtonViewModel>(PlaybackButtonType.Forward,
|
||||||
|
"Forward", "\uEB9D",
|
||||||
|
new RelayCommand(async () => await mediator.PublishAsync<Forward>()));
|
||||||
|
|
||||||
|
mediator.Subscribe(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ITemplateFactory TemplateFactory { get; set; }
|
public ITemplateFactory TemplateFactory { get; set; }
|
||||||
|
|||||||
@@ -2,6 +2,12 @@
|
|||||||
<UserControl
|
<UserControl
|
||||||
x:Class="Hyperbar.Widget.MediaController.Windows.MediaControllerWidgetView"
|
x:Class="Hyperbar.Widget.MediaController.Windows.MediaControllerWidgetView"
|
||||||
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"
|
||||||
<Button>sdfsdfsdg</Button>
|
xmlns:ui="using:Hyperbar.UI.Windows">
|
||||||
|
<FlipView
|
||||||
|
x:Name="FlipView"
|
||||||
|
Width="400"
|
||||||
|
Background="Transparent"
|
||||||
|
ItemTemplateSelector="{Binding Converter={ui:DataTemplateConverter}}"
|
||||||
|
ItemsSource="{Binding}" />
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
|||||||
@@ -1,74 +1,11 @@
|
|||||||
using CustomExtensions.WinUI;
|
|
||||||
using Microsoft.UI.Xaml.Controls;
|
using Microsoft.UI.Xaml.Controls;
|
||||||
using System.Reflection;
|
using Hyperbar.UI.Windows;
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
namespace Hyperbar.Widget.MediaController.Windows;
|
namespace Hyperbar.Widget.MediaController.Windows;
|
||||||
|
|
||||||
public sealed partial class MediaControllerWidgetView :
|
public sealed partial class MediaControllerWidgetView :
|
||||||
UserControl
|
UserControl
|
||||||
{
|
{
|
||||||
public MediaControllerWidgetView()
|
public MediaControllerWidgetView() =>
|
||||||
{
|
this.InitializeComponent(ref _contentLoaded);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="40" />
|
<ColumnDefinition Width="40" />
|
||||||
<ColumnDefinition Width="8" />
|
<ColumnDefinition Width="8" />
|
||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="80" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<Border
|
<Border
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
|
|||||||
@@ -6,5 +6,6 @@ namespace Hyperbar.Widget.MediaController.Windows;
|
|||||||
public sealed partial class MediaInformationView :
|
public sealed partial class MediaInformationView :
|
||||||
UserControl
|
UserControl
|
||||||
{
|
{
|
||||||
public MediaInformationView() => this.InitializeComponent(ref _contentLoaded);
|
public MediaInformationView() =>
|
||||||
|
this.InitializeComponent(ref _contentLoaded);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
namespace Hyperbar.Widget.MediaController.Windows;
|
|
||||||
|
|
||||||
public record Playback : INotification;
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
namespace Hyperbar.Widget.MediaController.Windows;
|
||||||
|
|
||||||
|
public enum PlaybackButtonType
|
||||||
|
{
|
||||||
|
Previous,
|
||||||
|
Play,
|
||||||
|
Pause,
|
||||||
|
Forward
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
namespace Hyperbar.Widget.MediaController.Windows;
|
||||||
|
|
||||||
|
public record PlaybackInformation(PlaybackStatus Status) :
|
||||||
|
INotification;
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
namespace Hyperbar.Widget.MediaController.Windows;
|
||||||
|
|
||||||
|
public enum PlaybackStatus
|
||||||
|
{
|
||||||
|
Closed,
|
||||||
|
Opened,
|
||||||
|
Changing,
|
||||||
|
Stopped,
|
||||||
|
Playing,
|
||||||
|
Paused
|
||||||
|
}
|
||||||
+1
-1
@@ -1,3 +1,3 @@
|
|||||||
namespace Hyperbar.Widget.MediaController.Windows;
|
namespace Hyperbar.Widget.MediaController.Windows;
|
||||||
|
|
||||||
public record Backward : INotification;
|
public record Previous : INotification;
|
||||||
@@ -7,13 +7,6 @@
|
|||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
|
||||||
<None Remove="WidgetBarView.xaml" />
|
|
||||||
<None Remove="WidgetButtonView.xaml" />
|
|
||||||
<None Remove="WidgetContainerView.xaml" />
|
|
||||||
<None Remove="WidgetSplitButtonView.xaml" />
|
|
||||||
<None Remove="WidgetView.xaml" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.5.231202003-experimental1" />
|
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.5.231202003-experimental1" />
|
||||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26031-preview" />
|
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26031-preview" />
|
||||||
@@ -25,26 +18,4 @@
|
|||||||
<ProjectReference Include="..\Hyperbar.Widget\Hyperbar.Widget.csproj" />
|
<ProjectReference Include="..\Hyperbar.Widget\Hyperbar.Widget.csproj" />
|
||||||
<ProjectReference Include="..\Hyperbar\Hyperbar.csproj" />
|
<ProjectReference Include="..\Hyperbar\Hyperbar.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
|
||||||
<Page Update="WidgetBarView.xaml">
|
|
||||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
|
||||||
<SubType>Designer</SubType>
|
|
||||||
</Page>
|
|
||||||
<Page Update="WidgetButtonView.xaml">
|
|
||||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
|
||||||
<SubType>Designer</SubType>
|
|
||||||
</Page>
|
|
||||||
<Page Update="WidgetContainerView.xaml">
|
|
||||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
|
||||||
<SubType>Designer</SubType>
|
|
||||||
</Page>
|
|
||||||
<Page Update="WidgetSplitButtonView.xaml">
|
|
||||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
|
||||||
<SubType>Designer</SubType>
|
|
||||||
</Page>
|
|
||||||
<Page Update="WidgetView.xaml">
|
|
||||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
|
||||||
<SubType>Designer</SubType>
|
|
||||||
</Page>
|
|
||||||
</ItemGroup>
|
|
||||||
</Project>
|
</Project>
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
using System.Reflection;
|
using Windows.ApplicationModel.Resources.Core;
|
||||||
using Windows.ApplicationModel.Resources.Core;
|
|
||||||
using Windows.Storage;
|
using Windows.Storage;
|
||||||
|
|
||||||
namespace Hyperbar.Widget.Windows;
|
namespace Hyperbar.Widget.Windows;
|
||||||
@@ -9,27 +8,23 @@ internal class WidgetResourceInitialization(IWidgetAssembly widgetAssembly) :
|
|||||||
{
|
{
|
||||||
public async Task InitializeAsync()
|
public async Task InitializeAsync()
|
||||||
{
|
{
|
||||||
if (widgetAssembly.Assembly is Assembly assembly)
|
string assemblyDirectory = Path.GetDirectoryName(widgetAssembly.Assembly.Location) ?? string.Empty;
|
||||||
{
|
string[] possibleFileNames = ["resources.pri", $"{widgetAssembly.Assembly.GetName().Name}.pri"];
|
||||||
if (Path.GetDirectoryName(assembly.Location) is string assemblyDirectory)
|
|
||||||
{
|
|
||||||
FileInfo resourceFileInfo = new(Path.Combine(assemblyDirectory,
|
|
||||||
"resources.pri"));
|
|
||||||
|
|
||||||
if (!resourceFileInfo.Exists)
|
FileInfo? resourceFileInfo = null;
|
||||||
|
foreach (string fileName in possibleFileNames)
|
||||||
{
|
{
|
||||||
resourceFileInfo = new(Path.Combine(assemblyDirectory,
|
resourceFileInfo = new FileInfo(Path.Combine(assemblyDirectory, fileName));
|
||||||
$"{assembly.GetName().Name}.pri"));
|
if (resourceFileInfo.Exists)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!resourceFileInfo.Exists)
|
if (resourceFileInfo?.Exists is true)
|
||||||
{
|
{
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
StorageFile file = await StorageFile.GetFileFromPathAsync(resourceFileInfo.FullName);
|
StorageFile file = await StorageFile.GetFileFromPathAsync(resourceFileInfo.FullName);
|
||||||
ResourceManager.Current.LoadPriFiles(new[] { file });
|
ResourceManager.Current.LoadPriFiles(new[] { file });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
@@ -12,7 +12,6 @@ public static class IServiceCollectionExtensions
|
|||||||
|
|
||||||
services.AddHandler<WidgetExtensionEnumerator>();
|
services.AddHandler<WidgetExtensionEnumerator>();
|
||||||
services.AddHandler<WidgetExtensionHandler>();
|
services.AddHandler<WidgetExtensionHandler>();
|
||||||
services.AddHandler<WidgetExtensionHandler>();
|
|
||||||
services.AddHandler<WidgetHostHandler>();
|
services.AddHandler<WidgetHostHandler>();
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
|
|||||||
@@ -25,9 +25,6 @@ public class WidgetBuilder<TConfiguration>(TConfiguration configuration) :
|
|||||||
services.AddScoped<IServiceFactory>(provider =>
|
services.AddScoped<IServiceFactory>(provider =>
|
||||||
new ServiceFactory((type, parameters) =>
|
new ServiceFactory((type, parameters) =>
|
||||||
ActivatorUtilities.CreateInstance(provider, type, parameters!)));
|
ActivatorUtilities.CreateInstance(provider, type, parameters!)));
|
||||||
|
|
||||||
services.AddHostedService<WidgetService>();
|
|
||||||
|
|
||||||
services.AddScoped<IMediator, Mediator>();
|
services.AddScoped<IMediator, Mediator>();
|
||||||
services.AddScoped<IDisposer, Disposer>();
|
services.AddScoped<IDisposer, Disposer>();
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,9 @@ public partial class WidgetButtonViewModel(IServiceFactory serviceFactory,
|
|||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private IRelayCommand? click = command;
|
private IRelayCommand? click = command;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool enabled;
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private string? icon = icon;
|
private string? icon = icon;
|
||||||
|
|
||||||
@@ -24,4 +27,7 @@ public partial class WidgetButtonViewModel(IServiceFactory serviceFactory,
|
|||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private string? text = text;
|
private string? text = text;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool visible;
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
namespace Hyperbar.Widget;
|
||||||
|
|
||||||
namespace Hyperbar.Widget;
|
|
||||||
|
|
||||||
public partial class WidgetComponentViewModel :
|
public partial class WidgetComponentViewModel :
|
||||||
ObservableCollectionViewModel<IWidgetComponentViewModel>,
|
ObservableCollectionViewModel<IWidgetComponentViewModel>,
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ public class WidgetExtensionHandler(IProxyServiceCollection<IWidgetBuilder> type
|
|||||||
if(notification.Value is WidgetExtension widgetExtension)
|
if(notification.Value is WidgetExtension widgetExtension)
|
||||||
{
|
{
|
||||||
IWidgetBuilder builder = widgetExtension.Widget.Create();
|
IWidgetBuilder builder = widgetExtension.Widget.Create();
|
||||||
|
|
||||||
builder.ConfigureServices(args =>
|
builder.ConfigureServices(args =>
|
||||||
{
|
{
|
||||||
args.AddSingleton(widgetExtension.Assembly);
|
args.AddSingleton(widgetExtension.Assembly);
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
using Microsoft.Extensions.Hosting;
|
|
||||||
|
|
||||||
namespace Hyperbar.Widget;
|
|
||||||
|
|
||||||
public sealed class WidgetService(IEnumerable<IInitializer> initializers) :
|
|
||||||
IHostedService
|
|
||||||
{
|
|
||||||
public async Task StartAsync(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
foreach (IInitializer initializer in initializers)
|
|
||||||
{
|
|
||||||
await initializer.InitializeAsync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
|
|
||||||
}
|
|
||||||
@@ -1,11 +1,5 @@
|
|||||||
namespace Hyperbar;
|
namespace Hyperbar;
|
||||||
|
|
||||||
[AttributeUsage(AttributeTargets.Class)]
|
|
||||||
public class NotificationHandlerAttribute(object key) : Attribute
|
|
||||||
{
|
|
||||||
public object Key { get; } = key;
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface IMediator
|
public interface IMediator
|
||||||
{
|
{
|
||||||
Task PublishAsync<TNotification>(TNotification notification,
|
Task PublishAsync<TNotification>(TNotification notification,
|
||||||
|
|||||||
@@ -107,31 +107,18 @@ public class Mediator(IServiceProvider provider,
|
|||||||
public void Subscribe(object handler)
|
public void Subscribe(object handler)
|
||||||
{
|
{
|
||||||
Type handlerType = handler.GetType();
|
Type handlerType = handler.GetType();
|
||||||
object? key = null;
|
object? key = GetKeyFromHandler(handlerType, handler);
|
||||||
|
|
||||||
if (Attribute.GetCustomAttribute(handlerType, typeof(NotificationHandlerAttribute))
|
foreach (Type interfaceType in GetNotificationHandlerInterfaces(handlerType))
|
||||||
is NotificationHandlerAttribute attribute)
|
|
||||||
{
|
{
|
||||||
if (handlerType.GetProperty($"{attribute.Key}") is PropertyInfo property)
|
if (interfaceType.GetGenericArguments().FirstOrDefault()
|
||||||
|
is Type argumentType)
|
||||||
{
|
{
|
||||||
if (property.GetValue(handler, null) is { } value)
|
if (object.Equals(key, default))
|
||||||
{
|
{
|
||||||
key = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
key = attribute.Key;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (Type interfaceType in handlerType.GetInterfaces().Where(x => x.IsGenericType
|
}
|
||||||
&& x.GetGenericTypeDefinition() == typeof(INotificationHandler<>)))
|
subjects.AddOrUpdate(key ?? argumentType, new List<object> { handler }, (value, collection) =>
|
||||||
{
|
|
||||||
if (interfaceType.GetGenericArguments() is { Length: 1 } arguments)
|
|
||||||
{
|
|
||||||
key ??= arguments[0];
|
|
||||||
subjects.AddOrUpdate(key, [handler], (value, collection) =>
|
|
||||||
{
|
{
|
||||||
collection.Add(handler);
|
collection.Add(handler);
|
||||||
return collection;
|
return collection;
|
||||||
@@ -139,4 +126,26 @@ public class Mediator(IServiceProvider provider,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private object? GetKeyFromHandler(Type handlerType, object handler)
|
||||||
|
{
|
||||||
|
if (handlerType.GetCustomAttribute<NotificationHandlerAttribute>() is NotificationHandlerAttribute attribute)
|
||||||
|
{
|
||||||
|
if (handlerType.GetProperty($"{attribute.Key}") is PropertyInfo property
|
||||||
|
&& property.GetValue(handler) is { } value)
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return attribute.Key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<Type> GetNotificationHandlerInterfaces(Type handlerType) => handlerType.GetInterfaces()
|
||||||
|
.Where(interfaceType => interfaceType.IsGenericType && interfaceType
|
||||||
|
.GetGenericTypeDefinition() == typeof(INotificationHandler<>));
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
namespace Hyperbar;
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
|
||||||
|
public class NotificationHandlerAttribute(object key) : Attribute
|
||||||
|
{
|
||||||
|
public object Key { get; } = key;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user