Bunch of insane work
This commit is contained in:
@@ -1,15 +0,0 @@
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Hyperbar.UI.Windows;
|
||||
|
||||
public class DataTemplateConverter :
|
||||
ValueConverter<object, DataTemplateSelector>
|
||||
{
|
||||
protected override DataTemplateSelector? ConvertTo(object value,
|
||||
Type? targetType,
|
||||
object? parameter,
|
||||
string? language)
|
||||
{
|
||||
return new TemplateGenerator();
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Hyperbar.UI.Windows;
|
||||
|
||||
public class TemplateFactory(IEnumerable<IContentTemplateDescriptor> descriptors,
|
||||
IServiceProvider provider) :
|
||||
ITemplateFactory
|
||||
{
|
||||
public object? Create(object key)
|
||||
{
|
||||
if (descriptors.FirstOrDefault(x => x.Key == key)
|
||||
is IContentTemplateDescriptor descriptor)
|
||||
{
|
||||
if (provider.GetRequiredKeyedService(descriptor.TemplateType,
|
||||
descriptor.Key) is { } template)
|
||||
{
|
||||
return template;
|
||||
}
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Markup;
|
||||
|
||||
namespace Hyperbar.UI.Windows;
|
||||
|
||||
public class TemplateGenerator : DataTemplateSelector
|
||||
{
|
||||
protected override DataTemplate SelectTemplateCore(object item)
|
||||
{
|
||||
string xamlString = @"
|
||||
<DataTemplate xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
|
||||
xmlns:ui=""using:Hyperbar.UI.Windows"">
|
||||
<ui:TemplateGeneratorControl VerticalContentAlignment=""Stretch""
|
||||
HorizontalContentAlignment=""Stretch""
|
||||
HorizontalAlignment=""Stretch""
|
||||
VerticalAlignment=""Stretch""/>
|
||||
</DataTemplate>";
|
||||
|
||||
return (DataTemplate)XamlReader.Load(xamlString);
|
||||
}
|
||||
|
||||
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
|
||||
{
|
||||
string xamlString = @"
|
||||
<DataTemplate xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
|
||||
xmlns:ui=""using:Hyperbar.UI.Windows"">
|
||||
<ui:TemplateGeneratorControl VerticalContentAlignment=""Stretch""
|
||||
HorizontalContentAlignment=""Stretch""
|
||||
HorizontalAlignment=""Stretch""
|
||||
VerticalAlignment=""Stretch""/>
|
||||
</DataTemplate>";
|
||||
|
||||
return (DataTemplate)XamlReader.Load(xamlString);
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Hyperbar.UI.Windows;
|
||||
|
||||
public class TemplateGeneratorControl :
|
||||
ContentControl
|
||||
{
|
||||
public TemplateGeneratorControl()
|
||||
{
|
||||
DataContextChanged += OnDataContextChanged;
|
||||
}
|
||||
|
||||
private void OnDataContextChanged(FrameworkElement sender,
|
||||
DataContextChangedEventArgs args)
|
||||
{
|
||||
if (DataContext is ITemplatedViewModel templatedViewModel)
|
||||
{
|
||||
Content = templatedViewModel.TemplateFactory.Create(DataContext.GetType().Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Hyperbar.UI.Windows;
|
||||
|
||||
public class ViewModelTemplatePresenter :
|
||||
ContentPresenter
|
||||
{
|
||||
public ViewModelTemplatePresenter()
|
||||
{
|
||||
DataContextChanged += OnDataContextChanged;
|
||||
}
|
||||
|
||||
private void OnDataContextChanged(FrameworkElement sender,
|
||||
DataContextChangedEventArgs args)
|
||||
{
|
||||
//if (DataContext is IViewModelTemplate templatedViewModel)
|
||||
//{
|
||||
// Content = templatedViewModel.TemplateFactory
|
||||
// .Create(DataContext.GetType().Name);
|
||||
//}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Markup;
|
||||
|
||||
namespace Hyperbar.UI.Windows;
|
||||
|
||||
public class ImplicitTemplate :
|
||||
MarkupExtension
|
||||
{
|
||||
protected override object ProvideValue(IXamlServiceProvider serviceProvider) =>
|
||||
new ImplicitTemplateSelector();
|
||||
|
||||
internal class ImplicitTemplateSelector :
|
||||
DataTemplateSelector
|
||||
{
|
||||
protected override DataTemplate SelectTemplateCore(object item,
|
||||
DependencyObject container)
|
||||
{
|
||||
|
||||
|
||||
string xamlString = @"
|
||||
<DataTemplate xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
|
||||
xmlns:ui=""using:Hyperbar.UI.Windows"">
|
||||
<ui:ViewModelTemplatePresenter VerticalContentAlignment=""Stretch""
|
||||
HorizontalContentAlignment=""Stretch""
|
||||
HorizontalAlignment=""Stretch""
|
||||
VerticalAlignment=""Stretch""/>
|
||||
</DataTemplate>";
|
||||
|
||||
return (DataTemplate)XamlReader.Load(xamlString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class ViewModelTemplate :
|
||||
MarkupExtension
|
||||
{
|
||||
protected override object ProvideValue(IXamlServiceProvider serviceProvider) =>
|
||||
new ViewModelTemplateSelector();
|
||||
|
||||
internal class ViewModelTemplateSelector :
|
||||
DataTemplateSelector
|
||||
{
|
||||
protected override DataTemplate SelectTemplateCore(object item)
|
||||
{
|
||||
if (item is IObservableViewModel observableViewModel)
|
||||
{
|
||||
if (observableViewModel.ServiceProvider.GetService<IViewModelTemplateDescriptorProvider>()
|
||||
is ViewModelTemplateDescriptorProvider descriptors)
|
||||
{
|
||||
if (descriptors.Get(item.GetType().Name) is IViewModelTemplateDescriptor descriptor)
|
||||
{
|
||||
string xamlString = @$"
|
||||
<DataTemplate xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
|
||||
xmlns:ui=""using:{descriptor.TemplateType.Namespace}"">
|
||||
<ui:{descriptor.TemplateType.Name} />
|
||||
</DataTemplate>";
|
||||
|
||||
return (DataTemplate)XamlReader.Load(xamlString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new DataTemplate();
|
||||
}
|
||||
|
||||
protected override DataTemplate SelectTemplateCore(object item,
|
||||
DependencyObject container)
|
||||
{
|
||||
if (item is IObservableViewModel observableViewModel)
|
||||
{
|
||||
if (observableViewModel.ServiceProvider.GetService<IViewModelTemplateDescriptorProvider>()
|
||||
is ViewModelTemplateDescriptorProvider descriptors)
|
||||
{
|
||||
if (descriptors.Get(item.GetType().Name) is IViewModelTemplateDescriptor descriptor)
|
||||
{
|
||||
string xamlString = @$"
|
||||
<DataTemplate xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
|
||||
xmlns:ui=""using:{descriptor.TemplateType.Namespace}"">
|
||||
<ui:{descriptor.TemplateType.Name} />
|
||||
</DataTemplate>";
|
||||
|
||||
return (DataTemplate)XamlReader.Load(xamlString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new DataTemplate();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,17 @@
|
||||
using Hyperbar.Interop.Windows;
|
||||
using Microsoft.UI.Windowing;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Windows.Graphics;
|
||||
using WinRT.Interop;
|
||||
|
||||
namespace Hyperbar.UI.Windows;
|
||||
|
||||
public class NavigationItemTemplateSelector :
|
||||
DataTemplateSelector
|
||||
{
|
||||
|
||||
}
|
||||
public static class WindowExtensions
|
||||
{
|
||||
public static WindowMessageListener CreateMessageListener(this Window window) =>
|
||||
@@ -36,6 +42,16 @@ public static class WindowExtensions
|
||||
public static void SetStyle(this Window window,
|
||||
ExtendedWindowStyle style) => window.GetHandle().SetExtendedWindowStyle(style);
|
||||
|
||||
public static void TitleBarConfiguration(this Window window,
|
||||
Action<AppWindowTitleBar> titleBarDelegate)
|
||||
{
|
||||
AppWindow appWindow = window.AppWindow;
|
||||
if (appWindow.TitleBar is AppWindowTitleBar titleBar)
|
||||
{
|
||||
titleBarDelegate.Invoke(titleBar);
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetTopMost(this Window window,
|
||||
bool value)
|
||||
{
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
namespace Hyperbar.Widget.Contextual.Windows;
|
||||
|
||||
public class ContextualWidgetViewModel(ITemplateFactory templateFactory,
|
||||
public class ContextualWidgetViewModel(IViewModelTemplateFactory templateFactory,
|
||||
IServiceFactory serviceFactory,
|
||||
IMediator mediator,
|
||||
IDisposer disposer,
|
||||
IEnumerable<IWidgetComponentViewModel> items) :
|
||||
ObservableCollectionViewModel<IWidgetComponentViewModel>(serviceFactory, mediator, disposer, items),
|
||||
IWidgetViewModel,
|
||||
ITemplatedViewModel
|
||||
IWidgetViewModel
|
||||
{
|
||||
public ITemplateFactory TemplateFactory => templateFactory;
|
||||
public IViewModelTemplateFactory TemplateFactory => templateFactory;
|
||||
}
|
||||
@@ -3,12 +3,13 @@ using CommunityToolkit.Mvvm.Input;
|
||||
|
||||
namespace Hyperbar.Widget.MediaController.Windows;
|
||||
|
||||
public partial class MediaButtonViewModel<TMediaButton>(IServiceFactory serviceFactory,
|
||||
public partial class MediaButtonViewModel<TMediaButton>(IServiceProvider serviceProvider,
|
||||
IServiceFactory serviceFactory,
|
||||
IMediator mediator,
|
||||
IDisposer disposer,
|
||||
ITemplateFactory templateFactory,
|
||||
IViewModelTemplateFactory templateFactory,
|
||||
IRelayCommand invokeCommand) :
|
||||
WidgetComponentViewModel(serviceFactory, mediator, disposer, templateFactory),
|
||||
WidgetComponentViewModel(serviceProvider, serviceFactory, mediator, disposer, templateFactory),
|
||||
INotificationHandler<Changed<MediaButton<TMediaButton>>>,
|
||||
IMediaButtonViewModel
|
||||
{
|
||||
|
||||
@@ -3,18 +3,16 @@
|
||||
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:windows="using:Hyperbar.UI.Windows">
|
||||
<Grid>
|
||||
<ItemsControl
|
||||
HorizontalAlignment="Right"
|
||||
HorizontalContentAlignment="Right"
|
||||
ItemTemplateSelector="{Binding Converter={windows:DataTemplateConverter}}"
|
||||
ItemsSource="{x:Bind ViewModel}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Horizontal" Spacing="8" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
</ItemsControl>
|
||||
</Grid>
|
||||
xmlns:ui="using:Hyperbar.UI.Windows">
|
||||
<ItemsControl
|
||||
HorizontalAlignment="Right"
|
||||
HorizontalContentAlignment="Right"
|
||||
ItemTemplateSelector="{ui:ViewModelTemplate}"
|
||||
ItemsSource="{x:Bind ViewModel}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Horizontal" Spacing="8" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
</ItemsControl>
|
||||
</UserControl>
|
||||
|
||||
@@ -2,17 +2,15 @@
|
||||
|
||||
namespace Hyperbar.Widget.MediaController.Windows;
|
||||
|
||||
|
||||
|
||||
[NotificationHandler(nameof(MediaControllerViewModel))]
|
||||
public class MediaControllerViewModel :
|
||||
ObservableCollectionViewModel<WidgetComponentViewModel>,
|
||||
ITemplatedViewModel
|
||||
ObservableCollectionViewModel<WidgetComponentViewModel>
|
||||
{
|
||||
public MediaControllerViewModel(ITemplateFactory templateFactory,
|
||||
public MediaControllerViewModel(IViewModelTemplateFactory templateFactory,
|
||||
IServiceProvider serviceProvider,
|
||||
IServiceFactory serviceFactory,
|
||||
IMediator mediator,
|
||||
IDisposer disposer) : base(serviceFactory, mediator, disposer)
|
||||
IDisposer disposer) : base(serviceProvider, serviceFactory, mediator, disposer)
|
||||
{
|
||||
TemplateFactory = templateFactory;
|
||||
|
||||
@@ -28,5 +26,5 @@ public class MediaControllerViewModel :
|
||||
await mediator.PublishAsync<Request<MediaNext>>()));
|
||||
}
|
||||
|
||||
public ITemplateFactory TemplateFactory { get; set; }
|
||||
public IViewModelTemplateFactory TemplateFactory { get; set; }
|
||||
}
|
||||
@@ -3,9 +3,9 @@
|
||||
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"
|
||||
xmlns:windows="using:Hyperbar.UI.Windows">
|
||||
xmlns:ui="using:Hyperbar.UI.Windows">
|
||||
<FlipView
|
||||
Width="360"
|
||||
ItemTemplateSelector="{Binding Converter={windows:DataTemplateConverter}}"
|
||||
ItemTemplateSelector="{ui:ViewModelTemplate}"
|
||||
ItemsSource="{Binding}" />
|
||||
</UserControl>
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
using Hyperbar.Widget;
|
||||
namespace Hyperbar.Widget.MediaController.Windows;
|
||||
|
||||
namespace Hyperbar.Widget.MediaController.Windows;
|
||||
|
||||
public class MediaControllerWidgetViewModel(ITemplateFactory templateFactory,
|
||||
public class MediaControllerWidgetViewModel(IViewModelTemplateFactory templateFactory,
|
||||
IServiceProvider serviceProvider,
|
||||
IServiceFactory serviceFactory,
|
||||
IMediator mediator,
|
||||
IDisposer disposer,
|
||||
IEnumerable<MediaControllerViewModel> items) :
|
||||
ObservableCollectionViewModel<MediaControllerViewModel>(serviceFactory, mediator, disposer, items),
|
||||
IWidgetViewModel,
|
||||
ITemplatedViewModel
|
||||
ObservableCollectionViewModel<MediaControllerViewModel>(serviceProvider, serviceFactory, mediator, disposer, items),
|
||||
IWidgetViewModel
|
||||
{
|
||||
public ITemplateFactory TemplateFactory => templateFactory;
|
||||
public IViewModelTemplateFactory TemplateFactory => templateFactory;
|
||||
}
|
||||
@@ -2,11 +2,12 @@
|
||||
|
||||
namespace Hyperbar.Widget.MediaController.Windows;
|
||||
|
||||
public partial class MediaInformationViewModel(IServiceFactory serviceFactory,
|
||||
public partial class MediaInformationViewModel(IServiceProvider serviceProvider,
|
||||
IServiceFactory serviceFactory,
|
||||
IMediator mediator,
|
||||
IDisposer disposer,
|
||||
ITemplateFactory templateFactory) :
|
||||
WidgetComponentViewModel(serviceFactory, mediator, disposer, templateFactory),
|
||||
IViewModelTemplateFactory templateFactory) :
|
||||
WidgetComponentViewModel(serviceProvider, serviceFactory, mediator, disposer, templateFactory),
|
||||
INotificationHandler<Changed<MediaInformation>>
|
||||
{
|
||||
[ObservableProperty]
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
namespace Hyperbar.Widget.Primary.Windows;
|
||||
|
||||
[NotificationHandler(nameof(PrimaryWidgetViewModel))]
|
||||
public class PrimaryWidgetViewModel(ITemplateFactory templateFactory,
|
||||
public class PrimaryWidgetViewModel(IViewModelTemplateFactory templateFactory,
|
||||
IServiceProvider serviceProvider,
|
||||
IServiceFactory serviceFactory,
|
||||
IMediator mediator,
|
||||
IDisposer disposer) :
|
||||
ObservableCollectionViewModel<IWidgetComponentViewModel>(serviceFactory, mediator, disposer),
|
||||
IWidgetViewModel,
|
||||
ITemplatedViewModel
|
||||
ObservableCollectionViewModel<IWidgetComponentViewModel>(serviceProvider, serviceFactory, mediator, disposer),
|
||||
IWidgetViewModel
|
||||
{
|
||||
public ITemplateFactory TemplateFactory => templateFactory;
|
||||
public IViewModelTemplateFactory TemplateFactory => templateFactory;
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Hyperbar.Widget;
|
||||
|
||||
namespace Hyperbar.Widget.Primary.Windows;
|
||||
|
||||
|
||||
@@ -19,7 +19,8 @@ public static class IServiceCollectionExtensions
|
||||
services.AddSingleton(provider.GetRequiredService<IList<IXamlMetadataProvider>>());
|
||||
services.AddSingleton(provider.GetRequiredService<IDispatcher>());
|
||||
|
||||
services.AddTransient<ITemplateFactory, TemplateFactory>();
|
||||
services.AddTransient<IViewModelTemplateDescriptorProvider, ViewModelTemplateDescriptorProvider>();
|
||||
services.AddTransient<IViewModelTemplateFactory, ViewModelTemplateFactory>();
|
||||
|
||||
services.AddScoped<IVirtualKeyboard, VirtualKeyboard>();
|
||||
services.AddHandler<KeyAcceleratorHandler>();
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:interactions="using:Microsoft.Xaml.Interactions.Core"
|
||||
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
|
||||
xmlns:windows="using:Hyperbar.UI.Windows">
|
||||
xmlns:ui="using:Hyperbar.UI.Windows">
|
||||
<Grid>
|
||||
<ItemsControl ItemTemplateSelector="{Binding Converter={windows:DataTemplateConverter}}" ItemsSource="{Binding Mode=TwoWay}">
|
||||
<ItemsControl ItemTemplateSelector="{ui:ViewModelTemplate}" ItemsSource="{Binding Mode=TwoWay}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Horizontal" Spacing="8" />
|
||||
|
||||
@@ -33,7 +33,7 @@ public static class IServiceCollectionExtensions
|
||||
services.AddKeyedTransient(typeof(IWidgetViewModel), key, contentType);
|
||||
services.TryAddKeyedTransient(key, (provider, key) => provider.GetService<IWidgetView>()!);
|
||||
|
||||
services.AddTransient<IContentTemplateDescriptor>(provider => new ContentTemplateDescriptor { ContentType = contentType, TemplateType = templateType, Key = key });
|
||||
services.AddTransient<IViewModelTemplateDescriptor>(provider => new ViewModelTemplateDescriptor { ViewModelType = contentType, TemplateType = templateType, Key = key });
|
||||
|
||||
return services;
|
||||
}
|
||||
@@ -54,8 +54,8 @@ public static class IServiceCollectionExtensions
|
||||
services.AddKeyedTransient(typeof(IWidgetViewModel), key, contentType);
|
||||
services.TryAddKeyedTransient(templateType, key);
|
||||
|
||||
services.AddTransient<IContentTemplateDescriptor>(provider =>
|
||||
new ContentTemplateDescriptor { ContentType = contentType,
|
||||
services.AddTransient<IViewModelTemplateDescriptor>(provider =>
|
||||
new ViewModelTemplateDescriptor { ViewModelType = contentType,
|
||||
TemplateType = templateType, Key = key });
|
||||
|
||||
return services;
|
||||
|
||||
@@ -4,14 +4,15 @@ using CommunityToolkit.Mvvm.Input;
|
||||
namespace Hyperbar.Widget;
|
||||
|
||||
[NotificationHandler(nameof(Id))]
|
||||
public partial class WidgetButtonViewModel(IServiceFactory serviceFactory,
|
||||
public partial class WidgetButtonViewModel(IServiceProvider serviceProvider,
|
||||
IServiceFactory serviceFactory,
|
||||
IMediator mediator,
|
||||
IDisposer disposer,
|
||||
ITemplateFactory templateFactory,
|
||||
IViewModelTemplateFactory templateFactory,
|
||||
Guid id,
|
||||
string? text = null,
|
||||
string? icon = null,
|
||||
RelayCommand? invokeCommand = null) : WidgetComponentViewModel(serviceFactory, mediator, disposer, templateFactory)
|
||||
RelayCommand? invokeCommand = null) : WidgetComponentViewModel(serviceProvider, serviceFactory, mediator, disposer, templateFactory)
|
||||
{
|
||||
[ObservableProperty]
|
||||
private string? icon = icon;
|
||||
|
||||
@@ -2,25 +2,26 @@
|
||||
|
||||
public partial class WidgetComponentViewModel :
|
||||
ObservableCollectionViewModel<IWidgetComponentViewModel>,
|
||||
IWidgetComponentViewModel,
|
||||
ITemplatedViewModel
|
||||
IWidgetComponentViewModel
|
||||
{
|
||||
public WidgetComponentViewModel(IServiceFactory serviceFactory,
|
||||
public WidgetComponentViewModel(IServiceProvider serviceProvider,
|
||||
IServiceFactory serviceFactory,
|
||||
IMediator mediator,
|
||||
IDisposer disposer,
|
||||
ITemplateFactory templateFactory,
|
||||
IEnumerable<IWidgetComponentViewModel> items) : base(serviceFactory, mediator, disposer, items)
|
||||
IViewModelTemplateFactory templateFactory,
|
||||
IEnumerable<IWidgetComponentViewModel> items) : base(serviceProvider, serviceFactory, mediator, disposer, items)
|
||||
{
|
||||
TemplateFactory = templateFactory;
|
||||
}
|
||||
|
||||
public WidgetComponentViewModel(IServiceFactory serviceFactory,
|
||||
public WidgetComponentViewModel(IServiceProvider serviceProvider,
|
||||
IServiceFactory serviceFactory,
|
||||
IMediator mediator,
|
||||
IDisposer disposer,
|
||||
ITemplateFactory templateFactory) : base(serviceFactory, mediator, disposer)
|
||||
IViewModelTemplateFactory templateFactory) : base(serviceProvider, serviceFactory, mediator, disposer)
|
||||
{
|
||||
TemplateFactory = templateFactory;
|
||||
}
|
||||
|
||||
public ITemplateFactory TemplateFactory { get; private set; }
|
||||
public IViewModelTemplateFactory TemplateFactory { get; private set; }
|
||||
}
|
||||
@@ -4,14 +4,15 @@ using CommunityToolkit.Mvvm.Input;
|
||||
namespace Hyperbar.Widget;
|
||||
|
||||
[NotificationHandler(nameof(Id))]
|
||||
public partial class WidgetMenuViewModel(IServiceFactory serviceFactory,
|
||||
public partial class WidgetMenuViewModel(IServiceProvider serviceProvider,
|
||||
IServiceFactory serviceFactory,
|
||||
IMediator mediator,
|
||||
IDisposer disposer,
|
||||
ITemplateFactory templateFactory,
|
||||
IViewModelTemplateFactory templateFactory,
|
||||
Guid id = default,
|
||||
string? text = null,
|
||||
string? icon = null,
|
||||
RelayCommand? command = null) : WidgetComponentViewModel(serviceFactory, mediator, disposer, templateFactory)
|
||||
RelayCommand? command = null) : WidgetComponentViewModel(serviceProvider, serviceFactory, mediator, disposer, templateFactory)
|
||||
{
|
||||
[ObservableProperty]
|
||||
private IRelayCommand? click = command;
|
||||
|
||||
@@ -4,15 +4,16 @@ using CommunityToolkit.Mvvm.Input;
|
||||
namespace Hyperbar.Widget;
|
||||
|
||||
[NotificationHandler(nameof(Id))]
|
||||
public partial class WidgetSplitButtonViewModel(IServiceFactory serviceFactory,
|
||||
public partial class WidgetSplitButtonViewModel(IServiceProvider serviceProvider,
|
||||
IServiceFactory serviceFactory,
|
||||
IMediator mediator,
|
||||
IDisposer disposer,
|
||||
ITemplateFactory templateFactory,
|
||||
IViewModelTemplateFactory templateFactory,
|
||||
IEnumerable<IWidgetComponentViewModel> items,
|
||||
Guid id = default,
|
||||
string? text = null,
|
||||
string? icon = null,
|
||||
RelayCommand? command = null) : WidgetComponentViewModel(serviceFactory, mediator, disposer, templateFactory, items)
|
||||
RelayCommand? command = null) : WidgetComponentViewModel(serviceProvider, serviceFactory, mediator, disposer, templateFactory, items)
|
||||
{
|
||||
[ObservableProperty]
|
||||
private IRelayCommand? click = command;
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
<DataTemplate x:Key="DefaultDataTemplate">
|
||||
<ui:TemplateGeneratorControl />
|
||||
<ui:ViewModelTemplatePresenter />
|
||||
</DataTemplate>
|
||||
</ResourceDictionary>
|
||||
</Application.Resources>
|
||||
|
||||
@@ -37,7 +37,9 @@ public partial class App :
|
||||
services.AddHostedService<AppService>();
|
||||
|
||||
services.AddSingleton<IDispatcher>(new Dispatcher(DispatcherQueue.GetForCurrentThread()));
|
||||
services.AddTransient<ITemplateFactory, TemplateFactory>();
|
||||
|
||||
services.AddTransient<IViewModelTemplateDescriptorProvider, ViewModelTemplateDescriptorProvider>();
|
||||
services.AddTransient<IViewModelTemplateFactory, ViewModelTemplateFactory>();
|
||||
|
||||
services.AddHandler<AppConfigurationChangedHandler>();
|
||||
services.AddConfiguration<AppConfiguration>(args =>
|
||||
@@ -55,6 +57,9 @@ public partial class App :
|
||||
services.AddContentTemplate<SettingsButtonViewModel, SettingsButtonView>();
|
||||
services.AddContentTemplate<SettingsViewModel, SettingsView>("Settings");
|
||||
|
||||
services.AddContentTemplate<GeneralSettingsNavigationViewModel, GeneralSettingsNavigationView>();
|
||||
services.AddContentTemplate<WidgetSettingsNavigationViewModel, WidgetSettingsNavigationView>();
|
||||
|
||||
services.AddTransient<IInitializer, AppInitializer>();
|
||||
})
|
||||
.Build();
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
x:Class="Hyperbar.Windows.ApplicationBarView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:windows="using:Hyperbar.UI.Windows">
|
||||
xmlns:ui="using:Hyperbar.UI.Windows">
|
||||
<UserControl.Resources>
|
||||
<SolidColorBrush x:Key="ButtonBackground" Color="Transparent" />
|
||||
<SolidColorBrush x:Key="ButtonBorderBrush" Color="Transparent" />
|
||||
@@ -17,7 +17,7 @@
|
||||
</UserControl.Resources>
|
||||
<ItemsControl
|
||||
Margin="6,0,6,0"
|
||||
ItemTemplateSelector="{Binding Converter={windows:DataTemplateConverter}}"
|
||||
ItemTemplateSelector="{ui:ViewModelTemplate}"
|
||||
ItemsSource="{x:Bind ViewModel, Mode=OneWay}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
@@ -36,7 +36,7 @@
|
||||
</ItemsControl.ItemContainerTransitions>
|
||||
<ItemsControl.ItemContainerStyle>
|
||||
<Style TargetType="ContentPresenter">
|
||||
<Setter Property="windows:GridExtension.GridColumnBindingPath" Value="Index" />
|
||||
<Setter Property="ui:GridExtension.GridColumnBindingPath" Value="Index" />
|
||||
</Style>
|
||||
</ItemsControl.ItemContainerStyle>
|
||||
</ItemsControl>
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
|
||||
[NotificationHandler(nameof(IWidgetHostViewModel))]
|
||||
public partial class ApplicationBarViewModel :
|
||||
ObservableCollectionViewModel<IDisposable>,
|
||||
ITemplatedViewModel
|
||||
ObservableCollectionViewModel<IDisposable>
|
||||
{
|
||||
public ApplicationBarViewModel(ITemplateFactory templateFactory,
|
||||
public ApplicationBarViewModel(IViewModelTemplateFactory templateFactory,
|
||||
IServiceProvider serviceProvider,
|
||||
IServiceFactory serviceFactory,
|
||||
IMediator mediator,
|
||||
IDisposer disposer) : base(serviceFactory, mediator, disposer)
|
||||
IDisposer disposer) : base(serviceProvider, serviceFactory, mediator, disposer)
|
||||
{
|
||||
TemplateFactory = templateFactory;
|
||||
|
||||
@@ -16,5 +16,5 @@ public partial class ApplicationBarViewModel :
|
||||
Add<SecondaryViewModel>(1);
|
||||
}
|
||||
|
||||
public ITemplateFactory TemplateFactory { get; }
|
||||
public IViewModelTemplateFactory TemplateFactory { get; }
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<NavigationViewItem
|
||||
x:Class="Hyperbar.Windows.GeneralSettingsNavigationView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Content="General" />
|
||||
@@ -0,0 +1,10 @@
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Hyperbar.Windows;
|
||||
|
||||
public sealed partial class GeneralSettingsNavigationView :
|
||||
NavigationViewItem
|
||||
{
|
||||
public GeneralSettingsNavigationView() =>
|
||||
InitializeComponent();
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace Hyperbar.Windows;
|
||||
|
||||
public class GeneralSettingsNavigationViewModel(IServiceProvider serviceProvider,
|
||||
IServiceFactory serviceFactory,
|
||||
IMediator mediator,
|
||||
IDisposer disposer,
|
||||
string text) :
|
||||
NavigationViewModel(serviceProvider, serviceFactory, mediator, disposer, text)
|
||||
{
|
||||
}
|
||||
@@ -15,10 +15,12 @@
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Remove="ApplicationBarView.xaml" />
|
||||
<None Remove="GeneralSettingsNavigationView.xaml" />
|
||||
<None Remove="PrimaryView.xaml" />
|
||||
<None Remove="SecondaryView.xaml" />
|
||||
<None Remove="SettingsButtonView.xaml" />
|
||||
<None Remove="SettingsView.xaml" />
|
||||
<None Remove="WidgetSettingsNavigationView.xaml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Assets\SplashScreen.scale-200.png" />
|
||||
@@ -55,6 +57,16 @@
|
||||
<ProjectReference Include="..\Hyperbar.Widget\Hyperbar.Widget.csproj" />
|
||||
<ProjectReference Include="..\Hyperbar\Hyperbar.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="GeneralSettingsNavigationView.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="WidgetSettingsNavigationView.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="SettingsView.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
x:Class="Hyperbar.Windows.PrimaryView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:windows="using:Hyperbar.UI.Windows">
|
||||
xmlns:ui="using:Hyperbar.UI.Windows">
|
||||
<ItemsControl
|
||||
HorizontalAlignment="Center"
|
||||
ItemTemplateSelector="{Binding Converter={windows:DataTemplateConverter}}"
|
||||
ItemTemplateSelector="{ui:ViewModelTemplate}"
|
||||
ItemsSource="{x:Bind ViewModel}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
|
||||
@@ -3,17 +3,17 @@
|
||||
namespace Hyperbar.Widget;
|
||||
|
||||
[NotificationHandler(nameof(IWidgetHostViewModel))]
|
||||
public partial class PrimaryViewModel(ITemplateFactory templateFactory,
|
||||
public partial class PrimaryViewModel(IViewModelTemplateFactory templateFactory,
|
||||
IServiceProvider serviceProvider,
|
||||
IServiceFactory serviceFactory,
|
||||
IMediator mediator,
|
||||
IDisposer disposer,
|
||||
int index) :
|
||||
ObservableCollectionViewModel<IWidgetViewModel>(serviceFactory, mediator, disposer),
|
||||
IWidgetHostViewModel,
|
||||
ITemplatedViewModel
|
||||
ObservableCollectionViewModel<IWidgetViewModel>(serviceProvider, serviceFactory, mediator, disposer),
|
||||
IWidgetHostViewModel
|
||||
{
|
||||
[ObservableProperty]
|
||||
private int index = index;
|
||||
|
||||
public ITemplateFactory TemplateFactory => templateFactory;
|
||||
public IViewModelTemplateFactory TemplateFactory => templateFactory;
|
||||
}
|
||||
@@ -3,9 +3,9 @@
|
||||
x:Class="Hyperbar.Windows.SecondaryView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:windows="using:Hyperbar.UI.Windows">
|
||||
xmlns:ui="using:Hyperbar.UI.Windows">
|
||||
<Grid>
|
||||
<ItemsControl ItemTemplateSelector="{Binding Converter={windows:DataTemplateConverter}}" ItemsSource="{x:Bind ViewModel, Mode=OneWay}">
|
||||
<ItemsControl ItemTemplateSelector="{ui:ViewModelTemplate}" ItemsSource="{x:Bind ViewModel, Mode=OneWay}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<ItemsStackPanel Orientation="Horizontal" />
|
||||
|
||||
@@ -4,17 +4,17 @@ using Hyperbar.Windows;
|
||||
namespace Hyperbar.Widget;
|
||||
|
||||
public partial class SecondaryViewModel :
|
||||
ObservableCollectionViewModel<IDisposable>,
|
||||
ITemplatedViewModel
|
||||
ObservableCollectionViewModel<IDisposable>
|
||||
{
|
||||
[ObservableProperty]
|
||||
private int index;
|
||||
|
||||
public SecondaryViewModel(ITemplateFactory templateFactory,
|
||||
public SecondaryViewModel(IViewModelTemplateFactory templateFactory,
|
||||
IServiceProvider serviceProvider,
|
||||
IServiceFactory serviceFactory,
|
||||
IMediator mediator,
|
||||
IDisposer disposer,
|
||||
int index) : base(serviceFactory, mediator, disposer)
|
||||
int index) : base(serviceProvider, serviceFactory, mediator, disposer)
|
||||
{
|
||||
TemplateFactory = templateFactory;
|
||||
this.index = index;
|
||||
@@ -22,5 +22,5 @@ public partial class SecondaryViewModel :
|
||||
Add<SettingsButtonViewModel>();
|
||||
}
|
||||
|
||||
public ITemplateFactory TemplateFactory { get; }
|
||||
public IViewModelTemplateFactory TemplateFactory { get; }
|
||||
}
|
||||
@@ -4,21 +4,21 @@ using CommunityToolkit.Mvvm.Input;
|
||||
namespace Hyperbar.Windows;
|
||||
|
||||
public partial class SettingsButtonViewModel :
|
||||
ObservableViewModel,
|
||||
ITemplatedViewModel
|
||||
ObservableViewModel
|
||||
{
|
||||
[ObservableProperty]
|
||||
private IRelayCommand? invokeCommand;
|
||||
|
||||
public SettingsButtonViewModel(ITemplateFactory templateFactory,
|
||||
public SettingsButtonViewModel(IViewModelTemplateFactory templateFactory,
|
||||
IServiceProvider serviceProvider,
|
||||
IServiceFactory serviceFactory,
|
||||
IMediator mediator,
|
||||
IDisposer disposer) : base(serviceFactory, mediator, disposer)
|
||||
IDisposer disposer) : base(serviceProvider, serviceFactory, mediator, disposer)
|
||||
{
|
||||
TemplateFactory = templateFactory;
|
||||
InvokeCommand = new AsyncRelayCommand(async () =>
|
||||
await mediator.PublishAsync(new Navigate("Settings")));
|
||||
}
|
||||
|
||||
public ITemplateFactory TemplateFactory { get; }
|
||||
public IViewModelTemplateFactory TemplateFactory { get; }
|
||||
}
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
x:Class="Hyperbar.Windows.SettingsView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:hyperbar="using:Hyperbar">
|
||||
xmlns:ui="using:Hyperbar.UI.Windows"
|
||||
xmlns:windows="using:Hyperbar.Windows">
|
||||
<Window.SystemBackdrop>
|
||||
<MicaBackdrop />
|
||||
</Window.SystemBackdrop>
|
||||
@@ -11,11 +12,6 @@
|
||||
IsBackButtonVisible="Collapsed"
|
||||
IsPaneToggleButtonVisible="False"
|
||||
IsSettingsVisible="False"
|
||||
MenuItemsSource="{x:Bind ViewModel, Mode=OneWay}">
|
||||
<NavigationView.MenuItemTemplate>
|
||||
<DataTemplate x:DataType="hyperbar:NavigationViewModel">
|
||||
<NavigationViewItem Content="{x:Bind Text, Mode=OneWay}" />
|
||||
</DataTemplate>
|
||||
</NavigationView.MenuItemTemplate>
|
||||
</NavigationView>
|
||||
MenuItemTemplateSelector="{ui:ViewModelTemplate}"
|
||||
MenuItemsSource="{x:Bind ViewModel, Mode=OneWay}" />
|
||||
</Window>
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
using Hyperbar.UI.Windows;
|
||||
using Microsoft.UI;
|
||||
using Microsoft.UI.Xaml;
|
||||
|
||||
namespace Hyperbar.Windows;
|
||||
@@ -5,9 +7,18 @@ namespace Hyperbar.Windows;
|
||||
public partial class SettingsView :
|
||||
Window
|
||||
{
|
||||
public SettingsView() =>
|
||||
public SettingsView()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
this.TitleBarConfiguration(args =>
|
||||
{
|
||||
args.ExtendsContentIntoTitleBar = true;
|
||||
args.ButtonBackgroundColor = Colors.Transparent;
|
||||
args.ButtonInactiveBackgroundColor = Colors.Transparent;
|
||||
});
|
||||
}
|
||||
|
||||
protected SettingsViewModel ViewModel =>
|
||||
(SettingsViewModel)(Content as FrameworkElement)!.DataContext;
|
||||
}
|
||||
|
||||
@@ -1,13 +1,19 @@
|
||||
namespace Hyperbar.Windows;
|
||||
|
||||
public partial class SettingsViewModel :
|
||||
ObservableCollectionViewModel<NavigationViewModel>
|
||||
ObservableCollectionViewModel<INavigationViewModel>
|
||||
{
|
||||
public SettingsViewModel(IServiceFactory serviceFactory,
|
||||
public SettingsViewModel(IServiceProvider serviceProvider,
|
||||
IServiceFactory serviceFactory,
|
||||
IMediator mediator,
|
||||
IDisposer disposer) : base(serviceFactory, mediator, disposer)
|
||||
IDisposer disposer,
|
||||
IViewModelTemplateFactory templateFactory) : base(serviceProvider, serviceFactory, mediator, disposer)
|
||||
{
|
||||
Add<NavigationViewModel>("General");
|
||||
Add<NavigationViewModel>("Widgets");
|
||||
Add<GeneralSettingsNavigationViewModel>("General");
|
||||
Add<WidgetSettingsNavigationViewModel>("Widgets");
|
||||
|
||||
TemplateFactory = templateFactory;
|
||||
}
|
||||
|
||||
public IViewModelTemplateFactory TemplateFactory { get; }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace Hyperbar.Windows;
|
||||
|
||||
public class WidgetNavigationViewModel(IServiceProvider serviceProvider,
|
||||
IServiceFactory serviceFactory,
|
||||
IMediator mediator,
|
||||
IDisposer disposer,
|
||||
string text) :
|
||||
NavigationViewModel(serviceProvider, serviceFactory, mediator, disposer, text)
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<NavigationViewItem
|
||||
x:Class="Hyperbar.Windows.WidgetSettingsNavigationView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Content="Widgets" />
|
||||
@@ -0,0 +1,10 @@
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Hyperbar.Windows;
|
||||
|
||||
public sealed partial class WidgetSettingsNavigationView :
|
||||
NavigationViewItem
|
||||
{
|
||||
public WidgetSettingsNavigationView() =>
|
||||
InitializeComponent();
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace Hyperbar.Windows;
|
||||
|
||||
public class WidgetSettingsNavigationViewModel(IServiceProvider serviceProvider,
|
||||
IServiceFactory serviceFactory,
|
||||
IMediator mediator,
|
||||
IDisposer disposer,
|
||||
string text) :
|
||||
NavigationViewModel<WidgetNavigationViewModel>(serviceProvider, serviceFactory, mediator, disposer, text)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -164,9 +164,9 @@ public static class IServiceCollectionExtensions
|
||||
services.AddKeyedTransient(contentType, key);
|
||||
services.AddKeyedTransient(templateType, key);
|
||||
|
||||
services.AddTransient<IContentTemplateDescriptor>(provider => new ContentTemplateDescriptor
|
||||
services.AddTransient<IViewModelTemplateDescriptor>(provider => new ViewModelTemplateDescriptor
|
||||
{
|
||||
ContentType = contentType,
|
||||
ViewModelType = contentType,
|
||||
TemplateType = templateType,
|
||||
Key = key
|
||||
});
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Hyperbar;
|
||||
|
||||
public interface INavigationViewModel :
|
||||
IObservableViewModel
|
||||
{
|
||||
string Text { get; set; }
|
||||
}
|
||||
@@ -1,8 +1,14 @@
|
||||
using System.Windows.Input;
|
||||
namespace Hyperbar;
|
||||
|
||||
namespace Hyperbar;
|
||||
|
||||
public interface IObservableViewModel
|
||||
public interface IObservableViewModel :
|
||||
IInitialization,
|
||||
IDisposable
|
||||
{
|
||||
ICommand InitializeCommand { get; }
|
||||
public IDisposer Disposer { get; }
|
||||
|
||||
public IMediator Mediator { get; }
|
||||
|
||||
public IServiceFactory ServiceFactory { get; }
|
||||
|
||||
public IServiceProvider ServiceProvider { get; }
|
||||
}
|
||||
@@ -5,7 +5,7 @@ namespace Hyperbar;
|
||||
public class NavigateHandler :
|
||||
INotificationHandler<Navigate>
|
||||
{
|
||||
private readonly IEnumerable<IContentTemplateDescriptor> contentTemplateDescriptors;
|
||||
private readonly IEnumerable<IViewModelTemplateDescriptor> contentTemplateDescriptors;
|
||||
private readonly IServiceProvider provider;
|
||||
private readonly IMediator mediator;
|
||||
private readonly IEnumerable<INavigationDescriptor> navigationDescriptors;
|
||||
@@ -13,7 +13,7 @@ public class NavigateHandler :
|
||||
public NavigateHandler(IServiceProvider provider,
|
||||
IMediator mediator,
|
||||
IEnumerable<INavigationDescriptor> navigationDescriptors,
|
||||
IEnumerable<IContentTemplateDescriptor> contentTemplateDescriptors)
|
||||
IEnumerable<IViewModelTemplateDescriptor> contentTemplateDescriptors)
|
||||
{
|
||||
this.provider = provider;
|
||||
this.mediator = mediator;
|
||||
@@ -25,7 +25,7 @@ public class NavigateHandler :
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
if (contentTemplateDescriptors.FirstOrDefault(x => x.Key == args.Key)
|
||||
is IContentTemplateDescriptor contentTemplateDescriptor)
|
||||
is IViewModelTemplateDescriptor contentTemplateDescriptor)
|
||||
{
|
||||
if (navigationDescriptors.FirstOrDefault(x => contentTemplateDescriptor.TemplateType == x.Type ||
|
||||
contentTemplateDescriptor.TemplateType.BaseType == x.Type) is { } navigationDescriptor)
|
||||
@@ -35,7 +35,7 @@ public class NavigateHandler :
|
||||
{
|
||||
if (provider.GetRequiredKeyedService(contentTemplateDescriptor.TemplateType,
|
||||
contentTemplateDescriptor.Key) is { } template &&
|
||||
provider.GetRequiredKeyedService(contentTemplateDescriptor.ContentType,
|
||||
provider.GetRequiredKeyedService(contentTemplateDescriptor.ViewModelType,
|
||||
contentTemplateDescriptor.Key) is { } content)
|
||||
{
|
||||
Type navigateType = typeof(Navigate<>)
|
||||
|
||||
@@ -3,16 +3,32 @@
|
||||
namespace Hyperbar;
|
||||
|
||||
public partial class NavigationViewModel :
|
||||
ObservableCollectionViewModel<NavigationViewModel>
|
||||
ObservableCollectionViewModel<INavigationViewModel>,
|
||||
INavigationViewModel
|
||||
{
|
||||
[ObservableProperty]
|
||||
private string? text;
|
||||
|
||||
public NavigationViewModel(IServiceFactory serviceFactory,
|
||||
public NavigationViewModel(IServiceProvider serviceProvider,
|
||||
IServiceFactory serviceFactory,
|
||||
IMediator mediator,
|
||||
IDisposer disposer,
|
||||
string text) : base(serviceFactory, mediator, disposer)
|
||||
string text) : base(serviceProvider, serviceFactory, mediator, disposer)
|
||||
{
|
||||
this.text = text;
|
||||
}
|
||||
}
|
||||
|
||||
public partial class NavigationViewModel<TNavigationViewModel>(IServiceProvider serviceProvider,
|
||||
IServiceFactory serviceFactory,
|
||||
IMediator mediator,
|
||||
IDisposer disposer,
|
||||
string text) :
|
||||
ObservableCollectionViewModel<TNavigationViewModel>(serviceProvider, serviceFactory, mediator, disposer),
|
||||
INavigationViewModel
|
||||
where TNavigationViewModel :
|
||||
INavigationViewModel
|
||||
{
|
||||
[ObservableProperty]
|
||||
private string? text = text;
|
||||
}
|
||||
|
||||
@@ -8,31 +8,29 @@ using System.Windows.Input;
|
||||
|
||||
namespace Hyperbar;
|
||||
|
||||
public partial class ObservableCollectionViewModel<TItem> :
|
||||
public partial class ObservableCollectionViewModel<TViewModel> :
|
||||
ObservableObject,
|
||||
IObservableCollectionViewModel<TItem>,
|
||||
IList<TItem>,
|
||||
IObservableCollectionViewModel<TViewModel>,
|
||||
IList<TViewModel>,
|
||||
IList,
|
||||
IReadOnlyList<TItem>,
|
||||
IReadOnlyList<TViewModel>,
|
||||
INotifyCollectionChanged,
|
||||
INotificationHandler<Remove<TItem>>,
|
||||
INotificationHandler<Create<TItem>>,
|
||||
INotificationHandler<Insert<TItem>>,
|
||||
INotificationHandler<Move<TItem>>,
|
||||
INotificationHandler<Replace<TItem>>,
|
||||
IDisposable,
|
||||
IInitialization
|
||||
where TItem :
|
||||
IDisposable
|
||||
INotificationHandler<Remove<TViewModel>>,
|
||||
INotificationHandler<Create<TViewModel>>,
|
||||
INotificationHandler<Insert<TViewModel>>,
|
||||
INotificationHandler<Move<TViewModel>>,
|
||||
INotificationHandler<Replace<TViewModel>>
|
||||
{
|
||||
private readonly ObservableCollection<TItem> collection = [];
|
||||
private readonly ObservableCollection<TViewModel> collection = [];
|
||||
|
||||
private bool isInitialized;
|
||||
|
||||
public ObservableCollectionViewModel(IServiceFactory serviceFactory,
|
||||
public ObservableCollectionViewModel(IServiceProvider serviceProvider,
|
||||
IServiceFactory serviceFactory,
|
||||
IMediator mediator,
|
||||
IDisposer disposer)
|
||||
{
|
||||
ServiceProvider = serviceProvider;
|
||||
ServiceFactory = serviceFactory;
|
||||
Mediator = mediator;
|
||||
Disposer = disposer;
|
||||
@@ -42,11 +40,13 @@ public partial class ObservableCollectionViewModel<TItem> :
|
||||
collection.CollectionChanged += OnCollectionChanged;
|
||||
}
|
||||
|
||||
public ObservableCollectionViewModel(IServiceFactory serviceFactory,
|
||||
public ObservableCollectionViewModel(IServiceProvider serviceProvider,
|
||||
IServiceFactory serviceFactory,
|
||||
IMediator mediator,
|
||||
IDisposer disposer,
|
||||
IEnumerable<TItem> items)
|
||||
IEnumerable<TViewModel> items)
|
||||
{
|
||||
ServiceProvider = serviceProvider;
|
||||
ServiceFactory = serviceFactory;
|
||||
Mediator = mediator;
|
||||
Disposer = disposer;
|
||||
@@ -61,28 +61,28 @@ public partial class ObservableCollectionViewModel<TItem> :
|
||||
|
||||
public int Count => collection.Count;
|
||||
|
||||
public IDisposer Disposer { get; private set; }
|
||||
|
||||
public ICommand InitializeCommand =>
|
||||
new AsyncRelayCommand(CoreInitializeAsync);
|
||||
new AsyncRelayCommand(CoreInitializeAsync);
|
||||
|
||||
bool IList.IsFixedSize => false;
|
||||
|
||||
bool ICollection<TItem>.IsReadOnly => false;
|
||||
bool ICollection<TViewModel>.IsReadOnly => false;
|
||||
|
||||
bool IList.IsReadOnly => false;
|
||||
|
||||
bool ICollection.IsSynchronized => false;
|
||||
|
||||
public IMediator Mediator { get; private set; }
|
||||
|
||||
public IServiceFactory ServiceFactory { get; private set; }
|
||||
|
||||
object ICollection.SyncRoot => this;
|
||||
|
||||
protected IDisposer Disposer { get; private set; }
|
||||
public IServiceProvider ServiceProvider { get; private set; }
|
||||
|
||||
protected IList<TItem> Items => collection;
|
||||
|
||||
protected IMediator Mediator { get; private set; }
|
||||
|
||||
protected IServiceFactory ServiceFactory { get; private set; }
|
||||
|
||||
public TItem this[int index]
|
||||
public TViewModel this[int index]
|
||||
{
|
||||
get => collection[index];
|
||||
set => SetItem(index, value);
|
||||
@@ -93,11 +93,11 @@ public partial class ObservableCollectionViewModel<TItem> :
|
||||
get => collection[index];
|
||||
set
|
||||
{
|
||||
TItem? item = default;
|
||||
TViewModel? item = default;
|
||||
|
||||
try
|
||||
{
|
||||
item = (TItem)value!;
|
||||
item = (TViewModel)value!;
|
||||
}
|
||||
catch (InvalidCastException)
|
||||
{
|
||||
@@ -108,16 +108,16 @@ public partial class ObservableCollectionViewModel<TItem> :
|
||||
}
|
||||
}
|
||||
|
||||
public TItem Add()
|
||||
public TViewModel Add()
|
||||
{
|
||||
TItem? item = ServiceFactory.Create<TItem>();
|
||||
TViewModel? item = ServiceFactory.Create<TViewModel>();
|
||||
|
||||
Add(item);
|
||||
return item;
|
||||
}
|
||||
|
||||
public TItem Add<T>(params object?[] parameters)
|
||||
where T : TItem
|
||||
public TViewModel Add<T>(params object?[] parameters)
|
||||
where T : TViewModel
|
||||
{
|
||||
T? item = ServiceFactory.Create<T>(parameters);
|
||||
Add(item);
|
||||
@@ -125,9 +125,9 @@ public partial class ObservableCollectionViewModel<TItem> :
|
||||
return item;
|
||||
}
|
||||
|
||||
public TItem Add<T>()
|
||||
public TViewModel Add<T>()
|
||||
where T :
|
||||
TItem
|
||||
TViewModel
|
||||
{
|
||||
T? item = ServiceFactory.Create<T>();
|
||||
Add(item);
|
||||
@@ -135,7 +135,7 @@ public partial class ObservableCollectionViewModel<TItem> :
|
||||
return item;
|
||||
}
|
||||
|
||||
public void Add(TItem item)
|
||||
public void Add(TViewModel item)
|
||||
{
|
||||
int index = collection.Count;
|
||||
InsertItem(index, item);
|
||||
@@ -144,16 +144,16 @@ public partial class ObservableCollectionViewModel<TItem> :
|
||||
public void Add(object item)
|
||||
{
|
||||
int index = collection.Count;
|
||||
InsertItem(index, (TItem)item);
|
||||
InsertItem(index, (TViewModel)item);
|
||||
}
|
||||
|
||||
int IList.Add(object? value)
|
||||
{
|
||||
TItem? item = default;
|
||||
TViewModel? item = default;
|
||||
|
||||
try
|
||||
{
|
||||
item = (TItem)value!;
|
||||
item = (TViewModel)value!;
|
||||
}
|
||||
catch (InvalidCastException)
|
||||
{
|
||||
@@ -164,9 +164,9 @@ public partial class ObservableCollectionViewModel<TItem> :
|
||||
return Count - 1;
|
||||
}
|
||||
|
||||
public void AddRange(IEnumerable<TItem> items)
|
||||
public void AddRange(IEnumerable<TViewModel> items)
|
||||
{
|
||||
foreach (TItem? item in items)
|
||||
foreach (TViewModel? item in items)
|
||||
{
|
||||
Add(item);
|
||||
}
|
||||
@@ -174,7 +174,7 @@ public partial class ObservableCollectionViewModel<TItem> :
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
foreach (TItem item in collection)
|
||||
foreach (TViewModel item in collection)
|
||||
{
|
||||
Disposer.Dispose(item);
|
||||
}
|
||||
@@ -182,17 +182,17 @@ public partial class ObservableCollectionViewModel<TItem> :
|
||||
ClearItems();
|
||||
}
|
||||
|
||||
public bool Contains(TItem item) =>
|
||||
public bool Contains(TViewModel item) =>
|
||||
collection.Contains(item);
|
||||
|
||||
bool IList.Contains(object? value) =>
|
||||
IsCompatibleObject(value) && Contains((TItem)value!);
|
||||
IsCompatibleObject(value) && Contains((TViewModel)value!);
|
||||
|
||||
public void CopyTo(TItem[] array, int index) =>
|
||||
public void CopyTo(TViewModel[] array, int index) =>
|
||||
collection.CopyTo(array, index);
|
||||
|
||||
void ICollection.CopyTo(Array array, int index) =>
|
||||
collection.CopyTo((TItem[])array, index);
|
||||
collection.CopyTo((TViewModel[])array, index);
|
||||
|
||||
public virtual void Dispose()
|
||||
{
|
||||
@@ -200,16 +200,16 @@ public partial class ObservableCollectionViewModel<TItem> :
|
||||
Disposer.Dispose(this);
|
||||
}
|
||||
|
||||
public System.Collections.Generic.IEnumerator<TItem> GetEnumerator() =>
|
||||
public System.Collections.Generic.IEnumerator<TViewModel> GetEnumerator() =>
|
||||
collection.GetEnumerator();
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() =>
|
||||
((IEnumerable)collection).GetEnumerator();
|
||||
|
||||
public Task Handle(Remove<TItem> notification,
|
||||
public Task Handle(Remove<TViewModel> notification,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
foreach (TItem item in this.ToList())
|
||||
foreach (TViewModel item in this.ToList())
|
||||
{
|
||||
if (notification.Value is not null && notification.Value.Equals(item))
|
||||
{
|
||||
@@ -220,10 +220,10 @@ public partial class ObservableCollectionViewModel<TItem> :
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task Handle(Create<TItem> notification,
|
||||
public Task Handle(Create<TViewModel> notification,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
if (notification.Value is TItem item)
|
||||
if (notification.Value is TViewModel item)
|
||||
{
|
||||
Add(item);
|
||||
}
|
||||
@@ -231,10 +231,10 @@ public partial class ObservableCollectionViewModel<TItem> :
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task Handle(Insert<TItem> notification,
|
||||
public Task Handle(Insert<TViewModel> notification,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
if (notification.Value is TItem item)
|
||||
if (notification.Value is TViewModel item)
|
||||
{
|
||||
Insert(notification.Index, item);
|
||||
}
|
||||
@@ -242,10 +242,10 @@ public partial class ObservableCollectionViewModel<TItem> :
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task Handle(Move<TItem> notification,
|
||||
public Task Handle(Move<TViewModel> notification,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
if (notification.Value is TItem item)
|
||||
if (notification.Value is TViewModel item)
|
||||
{
|
||||
Move(notification.Index, item);
|
||||
}
|
||||
@@ -253,10 +253,10 @@ public partial class ObservableCollectionViewModel<TItem> :
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task Handle(Replace<TItem> notification,
|
||||
public Task Handle(Replace<TViewModel> notification,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
if (notification.Value is TItem item)
|
||||
if (notification.Value is TViewModel item)
|
||||
{
|
||||
Replace(notification.Index, item);
|
||||
}
|
||||
@@ -264,25 +264,27 @@ public partial class ObservableCollectionViewModel<TItem> :
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public int IndexOf(TItem item) =>
|
||||
public int IndexOf(TViewModel item) =>
|
||||
collection.IndexOf(item);
|
||||
|
||||
int IList.IndexOf(object? value) =>
|
||||
IsCompatibleObject(value) ?
|
||||
IndexOf((TItem)value!) : -1;
|
||||
public void Insert(int index, TItem item) =>
|
||||
InsertItem(index, item);
|
||||
IndexOf((TViewModel)value!) : -1;
|
||||
public virtual Task InitializeAsync() => Task.CompletedTask;
|
||||
|
||||
public void Insert(int index, TViewModel item) =>
|
||||
InsertItem(index, item);
|
||||
|
||||
void IList.Insert(int index,
|
||||
object? value)
|
||||
{
|
||||
if (value is TItem item)
|
||||
if (value is TViewModel item)
|
||||
{
|
||||
Insert(index, item);
|
||||
}
|
||||
}
|
||||
|
||||
public bool Move(int index, TItem item)
|
||||
public bool Move(int index, TViewModel item)
|
||||
{
|
||||
int oldIndex = collection.IndexOf(item);
|
||||
if (oldIndex < 0)
|
||||
@@ -295,13 +297,7 @@ public partial class ObservableCollectionViewModel<TItem> :
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual Task InitializeAsync()
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public bool Remove(TItem item)
|
||||
public bool Remove(TViewModel item)
|
||||
{
|
||||
int index = collection.IndexOf(item);
|
||||
if (index < 0)
|
||||
@@ -319,14 +315,14 @@ public partial class ObservableCollectionViewModel<TItem> :
|
||||
{
|
||||
if (IsCompatibleObject(value))
|
||||
{
|
||||
Remove((TItem)value!);
|
||||
Remove((TViewModel)value!);
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveAt(int index) =>
|
||||
RemoveItem(index);
|
||||
|
||||
public bool Replace(int index, TItem item)
|
||||
public bool Replace(int index, TViewModel item)
|
||||
{
|
||||
if (index <= Count - 1)
|
||||
{
|
||||
@@ -346,7 +342,7 @@ public partial class ObservableCollectionViewModel<TItem> :
|
||||
collection.Clear();
|
||||
|
||||
protected virtual void InsertItem(int index,
|
||||
TItem value)
|
||||
TViewModel value)
|
||||
{
|
||||
Disposer.Add(this, value);
|
||||
Disposer.Add(value, value, Disposable.Create(() =>
|
||||
@@ -363,11 +359,11 @@ public partial class ObservableCollectionViewModel<TItem> :
|
||||
protected virtual void RemoveItem(int index) =>
|
||||
collection.RemoveAt(index);
|
||||
|
||||
protected virtual void SetItem(int index, TItem item) =>
|
||||
protected virtual void SetItem(int index, TViewModel item) =>
|
||||
collection[index] = item;
|
||||
|
||||
private static bool IsCompatibleObject(object? value) =>
|
||||
(value is TItem) || (value == null && default(TItem) == null);
|
||||
(value is TViewModel) || (value == null && default(TViewModel) == null);
|
||||
|
||||
private async Task CoreInitializeAsync()
|
||||
{
|
||||
@@ -378,7 +374,7 @@ public partial class ObservableCollectionViewModel<TItem> :
|
||||
|
||||
isInitialized = true;
|
||||
|
||||
await Mediator.PublishAsync<Enumerate<TItem>>();
|
||||
await Mediator.PublishAsync<Enumerate<TViewModel>>();
|
||||
await InitializeAsync();
|
||||
}
|
||||
|
||||
@@ -386,7 +382,8 @@ public partial class ObservableCollectionViewModel<TItem> :
|
||||
CollectionChanged?.Invoke(this, args);
|
||||
}
|
||||
|
||||
public class ObservableCollectionViewModel(IServiceFactory serviceFactory,
|
||||
public class ObservableCollectionViewModel(IServiceProvider serviceProvider,
|
||||
IServiceFactory serviceFactory,
|
||||
IMediator mediator,
|
||||
IDisposer disposer) :
|
||||
ObservableCollectionViewModel<IDisposable>(serviceFactory, mediator, disposer);
|
||||
ObservableCollectionViewModel<IDisposable>(serviceProvider, serviceFactory, mediator, disposer);
|
||||
@@ -1,16 +1,45 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace Hyperbar;
|
||||
|
||||
public class ObservableViewModel(IServiceFactory serviceFactory,
|
||||
public class ObservableViewModel(IServiceProvider serviceProvider,
|
||||
IServiceFactory serviceFactory,
|
||||
IMediator mediator,
|
||||
IDisposer disposer) :
|
||||
ObservableObject,
|
||||
IDisposable
|
||||
IObservableViewModel
|
||||
{
|
||||
public IServiceFactory ServiceFactory => serviceFactory;
|
||||
private bool isInitialized;
|
||||
|
||||
public IDisposer Disposer => disposer;
|
||||
|
||||
public ICommand InitializeCommand =>
|
||||
new AsyncRelayCommand(CoreInitializeAsync);
|
||||
|
||||
public IMediator Mediator => mediator;
|
||||
|
||||
public void Dispose() => disposer.Dispose(this);
|
||||
public IServiceFactory ServiceFactory => serviceFactory;
|
||||
|
||||
public IServiceProvider ServiceProvider => serviceProvider;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
disposer.Dispose(this);
|
||||
}
|
||||
|
||||
public virtual Task InitializeAsync() => Task.CompletedTask;
|
||||
|
||||
private async Task CoreInitializeAsync()
|
||||
{
|
||||
if (isInitialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
isInitialized = true;
|
||||
await InitializeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
namespace Hyperbar;
|
||||
|
||||
public record ContentTemplateDescriptor :
|
||||
IContentTemplateDescriptor
|
||||
{
|
||||
public required Type ContentType { get; set; }
|
||||
|
||||
public required Type TemplateType { get; set; }
|
||||
|
||||
public required object Key { get; set; }
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
namespace Hyperbar;
|
||||
|
||||
public interface ITemplatedViewModel
|
||||
{
|
||||
ITemplateFactory TemplateFactory { get; }
|
||||
}
|
||||
+3
-3
@@ -1,10 +1,10 @@
|
||||
namespace Hyperbar;
|
||||
|
||||
public interface IContentTemplateDescriptor
|
||||
public interface IViewModelTemplateDescriptor
|
||||
{
|
||||
Type ContentType { get; set; }
|
||||
|
||||
object Key { get; set; }
|
||||
|
||||
Type TemplateType { get; set; }
|
||||
|
||||
Type ViewModelType { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Hyperbar;
|
||||
|
||||
public interface IViewModelTemplateDescriptorProvider
|
||||
{
|
||||
IViewModelTemplateDescriptor? Get(object key);
|
||||
}
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
namespace Hyperbar;
|
||||
|
||||
public interface ITemplateFactory
|
||||
public interface IViewModelTemplateFactory
|
||||
{
|
||||
object? Create(object key);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace Hyperbar;
|
||||
|
||||
public record ViewModelTemplateDescriptor :
|
||||
IViewModelTemplateDescriptor
|
||||
{
|
||||
public required Type ViewModelType { get; set; }
|
||||
|
||||
public required Type TemplateType { get; set; }
|
||||
|
||||
public required object Key { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace Hyperbar;
|
||||
|
||||
public class ViewModelTemplateDescriptorProvider(IEnumerable<IViewModelTemplateDescriptor> descriptors) :
|
||||
IViewModelTemplateDescriptorProvider
|
||||
{
|
||||
public IViewModelTemplateDescriptor? Get(object key)
|
||||
{
|
||||
if (descriptors.FirstOrDefault(x => x.Key == key)
|
||||
is IViewModelTemplateDescriptor descriptor)
|
||||
{
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Hyperbar;
|
||||
|
||||
public class ViewModelTemplateFactory(IViewModelTemplateDescriptorProvider descriptors,
|
||||
IServiceProvider services) :
|
||||
IViewModelTemplateFactory
|
||||
{
|
||||
public object? Create(object key)
|
||||
{
|
||||
if (descriptors.Get(key)
|
||||
is IViewModelTemplateDescriptor descriptor)
|
||||
{
|
||||
if (services.GetRequiredKeyedService(descriptor.TemplateType,
|
||||
descriptor.Key) is { } template)
|
||||
{
|
||||
return template;
|
||||
}
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user