Make it possible to gather values using scoped ItemConfiguration

This commit is contained in:
TheXamlGuy
2024-06-05 22:22:06 +01:00
parent 5c6df1e611
commit 79bc00c878
19 changed files with 73 additions and 97 deletions
+3
View File
@@ -129,6 +129,9 @@ public partial class App : Application
services.AddTemplate<ItemNavigationViewModel, ItemNavigationView>(); services.AddTemplate<ItemNavigationViewModel, ItemNavigationView>();
services.AddTemplate<EmptyItemCollectionViewModel, EmptyItemCollectionView>("EmptyItemCollection"); services.AddTemplate<EmptyItemCollectionViewModel, EmptyItemCollectionView>("EmptyItemCollection");
services.AddScoped<IDecoratorService<ItemConfiguration>, DecoratorService<ItemConfiguration>>();
services.AddTemplate<ItemViewModel, ItemView>("Item"); services.AddTemplate<ItemViewModel, ItemView>("Item");
services.AddTemplate<ItemHeaderViewModel, ItemHeaderView>(); services.AddTemplate<ItemHeaderViewModel, ItemHeaderView>();
services.AddTemplate<ItemContentViewModel, ItemContentView>(); services.AddTemplate<ItemContentViewModel, ItemContentView>();
+10 -15
View File
@@ -3,28 +3,23 @@
namespace Bitvault; namespace Bitvault;
public class ConfirmCreateItemHandler(IMediator mediator, public class ConfirmCreateItemHandler(IMediator mediator,
IDecoratorService<ItemConfiguration> decoratorItemConfiguration,
IPublisher publisher) : IPublisher publisher) :
INotificationHandler<ConfirmEventArgs<Item>> INotificationHandler<ConfirmEventArgs<Item>>
{ {
public async Task Handle(ConfirmEventArgs<Item> args) public async Task Handle(ConfirmEventArgs<Item> args)
{ {
string? name = await mediator.Handle<ConfirmEventArgs<ItemHeader>, if (decoratorItemConfiguration.Value is ItemConfiguration configuration)
string>(Confirm.As<ItemHeader>());
if (name is not null)
{ {
IList<(int, string)> sections = await mediator.HandleMany<ConfirmEventArgs<ItemSection>, string? name = await mediator.Handle<ConfirmEventArgs<ItemHeader>, string>(Confirm.As<ItemHeader>());
(int, string)>(Confirm.As<ItemSection>()); if (name is not null)
{
Guid id = Guid.NewGuid();
publisher.Publish(Created.As(new Item<(Guid, string)>((id, name))));
IList<(int, ItemEntryConfiguration)> entries = await mediator.HandleMany<ConfirmEventArgs<ItemContentEntry>, await mediator.Handle<CreateEventArgs<(Guid, string, string,
(int, ItemEntryConfiguration)>(Confirm.As<ItemContentEntry>()); ItemConfiguration)>, bool>(new CreateEventArgs<(Guid, string, string, ItemConfiguration)>((id, name, "", configuration)));
}
Guid id = Guid.NewGuid();
publisher.Publish(Created.As(new Item<(Guid, string)>((id, name))));
await mediator.Handle<CreateEventArgs<(Guid, string, string,
ItemConfiguration)>, bool>(new CreateEventArgs<(Guid, string, string, ItemConfiguration)>((id, name, "",
new ItemConfiguration())));
} }
} }
} }
+2 -4
View File
@@ -8,10 +8,8 @@ public partial class ConfirmItemActionViewModel(IServiceProvider provider,
IMediator mediator, IMediator mediator,
IPublisher publisher, IPublisher publisher,
ISubscription subscriber, ISubscription subscriber,
IDisposer disposer, IDisposer disposer) : Observable(provider, factory, mediator, publisher, subscriber, disposer)
ItemState state) : Observable(provider, factory, mediator, publisher, subscriber, disposer)
{ {
[RelayCommand] [RelayCommand]
public void Invoke() => Publisher.Publish(Confirm.As<Item>(), public void Invoke() => Publisher.Publish(Confirm.As<Item>());
state is ItemState.New ? nameof(ItemState.New) : nameof(ItemState.Write));
} }
+5 -5
View File
@@ -2,7 +2,8 @@
namespace Bitvault; namespace Bitvault;
public class ConfirmUpdateItemHandler(IDecoratorService<Item<(Guid, string)>> store, public class ConfirmUpdateItemHandler(IDecoratorService<Item<(Guid, string)>> decoratorItem,
IDecoratorService<ItemConfiguration> decoratorItemConfiguration,
IMediator mediator, IMediator mediator,
IPublisher publisher) : IPublisher publisher) :
INotificationHandler<ConfirmEventArgs<Item>> INotificationHandler<ConfirmEventArgs<Item>>
@@ -14,17 +15,16 @@ public class ConfirmUpdateItemHandler(IDecoratorService<Item<(Guid, string)>> st
if (name is not null) if (name is not null)
{ {
var dd = decoratorItemConfiguration;
publisher.Publish(Notify.As(new ItemHeader<string>(name))); publisher.Publish(Notify.As(new ItemHeader<string>(name)));
if (store?.Value is Item<(Guid, string)> item) if (decoratorItem?.Value is Item<(Guid, string)> item)
{ {
(Guid id, string _) = item.Value; (Guid id, string _) = item.Value;
Item<(Guid, string)> newItem = new((id, name)); Item<(Guid, string)> newItem = new((id, name));
publisher.Publish(Modified.As(item, newItem)); publisher.Publish(Modified.As(item, newItem));
store.Set(newItem); decoratorItem.Set(newItem);
await mediator.Handle<UpdateEventArgs<(Guid, string, ItemConfiguration)>, bool>(new UpdateEventArgs<(Guid, string, await mediator.Handle<UpdateEventArgs<(Guid, string, ItemConfiguration)>, bool>(new UpdateEventArgs<(Guid, string,
ItemConfiguration)>((id, name, new ItemConfiguration()))); ItemConfiguration)>((id, name, new ItemConfiguration())));
-5
View File
@@ -1,5 +0,0 @@
namespace Bitvault;
public record ItemContentEntry<TValue>(TValue Value);
public record ItemContentEntry;
+2 -4
View File
@@ -8,8 +8,7 @@ public partial class ItemContentViewModel(IServiceProvider provider,
IPublisher publisher, IPublisher publisher,
ISubscription subscriber, ISubscription subscriber,
IDisposer disposer, IDisposer disposer,
IContentTemplate template, IContentTemplate template) :
ItemState state = ItemState.Read) :
ObservableCollection<ItemSectionViewModel>(provider, factory, mediator, publisher, subscriber, disposer), ObservableCollection<ItemSectionViewModel>(provider, factory, mediator, publisher, subscriber, disposer),
IItemEntryViewModel, IItemEntryViewModel,
INotificationHandler<NotifyEventArgs<ItemCategory<string>>> INotificationHandler<NotifyEventArgs<ItemCategory<string>>>
@@ -22,8 +21,7 @@ public partial class ItemContentViewModel(IServiceProvider provider,
{ {
if (category.Value is string value) if (category.Value is string value)
{ {
Fetch(() => new SynchronizeExpression(new SynchronizeEventArgs<IItemEntryViewModel, Fetch(() => new SynchronizeExpression(new SynchronizeEventArgs<IItemEntryViewModel, string>(value)), true);
(string, ISynchronizationCollection<ItemSectionViewModel>)>((value, this))), true);
} }
} }
+1 -2
View File
@@ -8,7 +8,6 @@ public partial class ItemDropdownEntryViewModel(IServiceProvider provider,
IPublisher publisher, IPublisher publisher,
ISubscription subscriber, ISubscription subscriber,
IDisposer disposer, IDisposer disposer,
ISynchronizationCollection<IItemEntryViewModel> synchronization,
ItemEntryConfiguration configuration, ItemEntryConfiguration configuration,
string? key = default, string? key = default,
string? value = default) : ItemEntryViewModel<string, string?>(provider, factory, mediator, publisher, subscriber, disposer, synchronization, configuration, key, value); object? value = default) : ItemEntryViewModel(provider, factory, mediator, publisher, subscriber, disposer, configuration, key, value);
@@ -10,7 +10,7 @@ public class ItemDropdownEntryViewModelHandler(IServiceFactory serviceFactory) :
{ {
if (args.Value is DropdownEntryConfiguration configuration) if (args.Value is DropdownEntryConfiguration configuration)
{ {
if (serviceFactory.Create<ItemDropdownEntryViewModel>([.. args.Parameters, configuration, configuration.Label, configuration.Value ?? ""]) if (serviceFactory.Create<ItemDropdownEntryViewModel>(configuration, configuration.Label, configuration.Value ?? "")
is ItemDropdownEntryViewModel viewModel) is ItemDropdownEntryViewModel viewModel)
{ {
return Task.FromResult<IItemEntryViewModel?>(viewModel); return Task.FromResult<IItemEntryViewModel?>(viewModel);
+8 -13
View File
@@ -1,24 +1,19 @@
using Toolkit.Foundation; using System.ComponentModel;
using Toolkit.Foundation;
namespace Bitvault; namespace Bitvault;
public partial class ItemEntryViewModel<TKey, TValue>(IServiceProvider provider, public partial class ItemEntryViewModel(IServiceProvider provider,
IServiceFactory factory, IServiceFactory factory,
IMediator mediator, IMediator mediator,
IPublisher publisher, IPublisher publisher,
ISubscription subscriber, ISubscription subscriber,
IDisposer disposer, IDisposer disposer,
ISynchronizationCollection<IItemEntryViewModel> synchronization,
ItemEntryConfiguration configuration, ItemEntryConfiguration configuration,
TKey? key = default, string? key = default,
TValue? value = default) : object? value = default) :
Observable<TKey, TValue>(provider, factory, mediator, publisher, subscriber, disposer, key, value), Observable<string, object>(provider, factory, mediator, publisher, subscriber, disposer, key, value),
IHandler<ConfirmEventArgs<ItemContentEntry>, (int, ItemEntryConfiguration)>, IItemEntryViewModel
IItemEntryViewModel,
IIndexable
{ {
public int Index => synchronization.IndexOf(this); protected override void OnValueChanged() => configuration.Value = Value;
public Task<(int, ItemEntryConfiguration)> Handle(ConfirmEventArgs<ItemContentEntry> args,
CancellationToken cancellationToken) => Task.FromResult((Index, configuration with { Value = Value }));
} }
+1 -2
View File
@@ -8,7 +8,6 @@ public partial class ItemMaskedTextEntryViewModel(IServiceProvider provider,
IPublisher publisher, IPublisher publisher,
ISubscription subscriber, ISubscription subscriber,
IDisposer disposer, IDisposer disposer,
ISynchronizationCollection<IItemEntryViewModel> synchronization,
ItemEntryConfiguration configuration, ItemEntryConfiguration configuration,
string? key = default, string? key = default,
string? value = default) : ItemEntryViewModel<string, string?>(provider, factory, mediator, publisher, subscriber, disposer, synchronization, configuration, key, value); object? value = default) : ItemEntryViewModel(provider, factory, mediator, publisher, subscriber, disposer, configuration, key, value);
@@ -10,7 +10,7 @@ public class ItemMaskedTextEntryViewModelHandler(IServiceFactory serviceFactory)
{ {
if (args.Value is MaskedTextEntryConfiguration configuration) if (args.Value is MaskedTextEntryConfiguration configuration)
{ {
if (serviceFactory.Create<ItemMaskedTextEntryViewModel>([.. args.Parameters, configuration, configuration.Label, configuration.Value ?? ""]) if (serviceFactory.Create<ItemMaskedTextEntryViewModel>(configuration, configuration.Label, configuration.Value ?? "")
is ItemMaskedTextEntryViewModel viewModel) is ItemMaskedTextEntryViewModel viewModel)
{ {
return Task.FromResult<IItemEntryViewModel?>(viewModel); return Task.FromResult<IItemEntryViewModel?>(viewModel);
+1
View File
@@ -24,6 +24,7 @@ public partial class ItemNavigationViewModel(IServiceProvider provider,
INotificationHandler<FavouriteEventArgs<Item>>, INotificationHandler<FavouriteEventArgs<Item>>,
INotificationHandler<UnfavouriteEventArgs<Item>>, INotificationHandler<UnfavouriteEventArgs<Item>>,
INotificationHandler<NotifyEventArgs<ItemHeader<string>>>, INotificationHandler<NotifyEventArgs<ItemHeader<string>>>,
IKeyed<Guid>,
ISelectable, ISelectable,
IRemovable IRemovable
{ {
+1 -2
View File
@@ -8,7 +8,6 @@ public partial class ItemPasswordEntryViewModel(IServiceProvider provider,
IPublisher publisher, IPublisher publisher,
ISubscription subscriber, ISubscription subscriber,
IDisposer disposer, IDisposer disposer,
ISynchronizationCollection<IItemEntryViewModel> synchronization,
ItemEntryConfiguration configuration, ItemEntryConfiguration configuration,
string? key = default, string? key = default,
string? value = default) : ItemEntryViewModel<string, string?>(provider, factory, mediator, publisher, subscriber, disposer, synchronization, configuration, key, value); object? value = default) : ItemEntryViewModel(provider, factory, mediator, publisher, subscriber, disposer, configuration, key, value);
@@ -10,7 +10,7 @@ public class ItemPasswordEntryViewModelHandler(IServiceFactory serviceFactory) :
{ {
if (args.Value is PasswordEntryConfiguration configuration) if (args.Value is PasswordEntryConfiguration configuration)
{ {
if (serviceFactory.Create<ItemPasswordEntryViewModel>([.. args.Parameters, configuration, configuration.Label, configuration.Value ?? ""]) if (serviceFactory.Create<ItemPasswordEntryViewModel>(configuration, configuration.Label, configuration.Value ?? "")
is ItemPasswordEntryViewModel viewModel) is ItemPasswordEntryViewModel viewModel)
{ {
return Task.FromResult<IItemEntryViewModel?>(viewModel); return Task.FromResult<IItemEntryViewModel?>(viewModel);
+5 -14
View File
@@ -1,9 +1,8 @@
using CommunityToolkit.Mvvm.ComponentModel; using Toolkit.Foundation;
using Toolkit.Foundation;
namespace Bitvault; namespace Bitvault;
[Notification(typeof(CreateEventArgs<IItemEntryViewModel>), nameof(Section))] [Notification(typeof(CreateEventArgs<IItemEntryViewModel>), nameof(Id))]
public partial class ItemSectionViewModel(IServiceProvider provider, public partial class ItemSectionViewModel(IServiceProvider provider,
IServiceFactory factory, IServiceFactory factory,
IMediator mediator, IMediator mediator,
@@ -11,18 +10,10 @@ public partial class ItemSectionViewModel(IServiceProvider provider,
ISubscription subscriber, ISubscription subscriber,
IDisposer disposer, IDisposer disposer,
IContentTemplate template, IContentTemplate template,
ISynchronizationCollection<ItemSectionViewModel> synchronization, string id) : ObservableCollection<IItemEntryViewModel>(provider, factory, mediator, publisher, subscriber, disposer),
string section) : ObservableCollection<IItemEntryViewModel>(provider, factory, mediator, publisher, subscriber, disposer), IKeyed<string>
IHandler<ConfirmEventArgs<ItemSection>, (int, string)>,
IIndexable
{ {
[ObservableProperty] public string Id => id;
private string section = section;
public IContentTemplate Template { get; set; } = template; public IContentTemplate Template { get; set; } = template;
public int Index => synchronization.IndexOf(this);
public Task<(int, string)> Handle(ConfirmEventArgs<ItemSection> args,
CancellationToken cancellationToken) => Task.FromResult((0, Section));
} }
+1 -2
View File
@@ -8,7 +8,6 @@ public partial class ItemTextEntryViewModel(IServiceProvider provider,
IPublisher publisher, IPublisher publisher,
ISubscription subscriber, ISubscription subscriber,
IDisposer disposer, IDisposer disposer,
ISynchronizationCollection<IItemEntryViewModel> synchronization,
ItemEntryConfiguration configuration, ItemEntryConfiguration configuration,
string? key = default, string? key = default,
string? value = default) : ItemEntryViewModel<string, string?>(provider, factory, mediator, publisher, subscriber, disposer, synchronization, configuration, key, value); object? value = default) : ItemEntryViewModel(provider, factory, mediator, publisher, subscriber, disposer, configuration, key, value);
+1 -1
View File
@@ -10,7 +10,7 @@ public class ItemTextEntryViewModelHandler(IServiceFactory serviceFactory) :
{ {
if (args.Value is TextEntryConfiguration configuration) if (args.Value is TextEntryConfiguration configuration)
{ {
if (serviceFactory.Create<ItemTextEntryViewModel>([.. args.Parameters, configuration, configuration.Label, configuration.Value ?? ""]) if (serviceFactory.Create<ItemTextEntryViewModel>(configuration, configuration.Label, configuration.Value ?? "")
is ItemTextEntryViewModel viewModel) is ItemTextEntryViewModel viewModel)
{ {
return Task.FromResult<IItemEntryViewModel?>(viewModel); return Task.FromResult<IItemEntryViewModel?>(viewModel);
+7 -6
View File
@@ -3,12 +3,10 @@ using Toolkit.Foundation;
namespace Bitvault; namespace Bitvault;
[Notification(typeof(ConfirmEventArgs<Item>), nameof(ItemState.New))]
[Notification(typeof(ConfirmEventArgs<Item>), nameof(ItemState.Write))]
public partial class ItemViewModel : public partial class ItemViewModel :
ObservableCollection, ObservableCollection,
INotificationHandler<UpdateEventArgs<Item>>,
INotificationHandler<ConfirmEventArgs<Item>>, INotificationHandler<ConfirmEventArgs<Item>>,
INotificationHandler<UpdateEventArgs<Item>>,
INotificationHandler<CancelEventArgs<Item>> INotificationHandler<CancelEventArgs<Item>>
{ {
[ObservableProperty] [ObservableProperty]
@@ -51,8 +49,8 @@ public partial class ItemViewModel :
Archived = archived; Archived = archived;
Name = name; Name = name;
Add<ItemHeaderViewModel>(state, name); Add<ItemHeaderViewModel>(name, state);
Add<ItemContentViewModel>(state); Add<ItemContentViewModel>();
} }
public IContentTemplate Template { get; set; } public IContentTemplate Template { get; set; }
@@ -61,7 +59,7 @@ public partial class ItemViewModel :
{ {
Publisher.Publish(Notify.As(Factory.Create<ItemCommandHeaderCollection>(new List<IDisposable> Publisher.Publish(Notify.As(Factory.Create<ItemCommandHeaderCollection>(new List<IDisposable>
{ {
Factory.Create<ConfirmItemActionViewModel>(ItemState.Write), Factory.Create<ConfirmItemActionViewModel>(),
Factory.Create<DismissItemActionViewModel>(), Factory.Create<DismissItemActionViewModel>(),
}))); })));
@@ -97,6 +95,9 @@ public partial class ItemViewModel :
Factory.Create<EditItemActionViewModel>(), Factory.Create<EditItemActionViewModel>(),
Factory.Create<ArchiveItemActionViewModel>(), Factory.Create<ArchiveItemActionViewModel>(),
}))); })));
Publisher.Publish(Confirm.As<Item>(),
State is ItemState.New ? nameof(ItemState.New) : nameof(ItemState.Write));
State = ItemState.Read; State = ItemState.Read;
return Task.CompletedTask; return Task.CompletedTask;
@@ -4,36 +4,40 @@ using Toolkit.Foundation;
namespace Bitvault; namespace Bitvault;
public class SynchronizeItemContentFromCategoryViewModelHandler(IItemConfigurationCollection configurations, public class SynchronizeItemContentFromCategoryViewModelHandler(IItemConfigurationCollection configurations,
IDecoratorService<ItemConfiguration> decoratorItemConfiguration,
IServiceFactory serviceFactory, IServiceFactory serviceFactory,
IMediator mediator, IMediator mediator,
IPublisher publisher) : IPublisher publisher) :
INotificationHandler<SynchronizeEventArgs<IItemEntryViewModel, INotificationHandler<SynchronizeEventArgs<IItemEntryViewModel, string>>
(string, ISynchronizationCollection<ItemSectionViewModel>)>>
{ {
public async Task Handle(SynchronizeEventArgs<IItemEntryViewModel, (string, ISynchronizationCollection<ItemSectionViewModel>)> args) public async Task Handle(SynchronizeEventArgs<IItemEntryViewModel, string> args)
{ {
(string category, ISynchronizationCollection<ItemSectionViewModel> synchronization) = args.Value; if (args.Value is string category)
if (configurations.TryGetValue(category, out Func<ItemConfiguration>? factory))
{ {
if (factory.Invoke() is ItemConfiguration configuration) if (configurations.TryGetValue(category, out Func<ItemConfiguration>? configurationFactory))
{ {
foreach (ItemSectionConfiguration configurationSection in configuration.Sections) if (configurationFactory.Invoke() is ItemConfiguration configuration)
{ {
string section = $"{nameof(ItemSection)}:{Guid.NewGuid()}"; decoratorItemConfiguration.Set(configuration);
if (serviceFactory.Create<ItemSectionViewModel>(synchronization, section) foreach (ItemSectionConfiguration configurationSection in configuration.Sections)
is ItemSectionViewModel sectionViewModel)
{ {
publisher.Publish(Create.As(sectionViewModel), nameof(ItemContentViewModel)); string id = $"{nameof(ItemSection)}:{Guid.NewGuid()}";
foreach (IItemEntryConfiguration entryConfiguration in configurationSection.Entries) if (serviceFactory.Create<ItemSectionViewModel>(id)
is ItemSectionViewModel sectionViewModel)
{ {
Type messageType = typeof(CreateEventArgs<>).MakeGenericType(entryConfiguration.GetType()); publisher.Publish(Create.As(sectionViewModel), nameof(ItemContentViewModel));
ConstructorInfo? constructor = messageType.GetConstructor([entryConfiguration.GetType(), typeof(object[])]); foreach (IItemEntryConfiguration entryConfiguration in configurationSection.Entries)
if (constructor?.Invoke(new object[] { entryConfiguration, new object[] { sectionViewModel } }) is object message)
{ {
if (await mediator.Handle<object, IItemEntryViewModel?>(message, entryConfiguration.GetType().Name) is IItemEntryViewModel entryViewModel) Type messageType = typeof(CreateEventArgs<>).MakeGenericType(entryConfiguration.GetType());
ConstructorInfo? constructor = messageType.GetConstructor([entryConfiguration.GetType(), typeof(object[])]);
if (constructor?.Invoke(new object[] { entryConfiguration, new object[] { sectionViewModel } }) is object message)
{ {
publisher.Publish(Create.As(entryViewModel), section); if (await mediator.Handle<object, IItemEntryViewModel?>(message,
entryConfiguration.GetType().Name) is IItemEntryViewModel entryViewModel)
{
publisher.Publish(Create.As(entryViewModel), id);
}
} }
} }
} }
@@ -41,6 +45,5 @@ public class SynchronizeItemContentFromCategoryViewModelHandler(IItemConfigurati
} }
} }
} }
} }
} }