Added ICollectionSynchronization

This commit is contained in:
TheXamlGuy
2024-06-04 12:14:00 +01:00
parent 0842988dc3
commit 554c12382a
44 changed files with 149 additions and 116 deletions
+16 -5
View File
@@ -79,13 +79,13 @@ public partial class App : Application
return new ItemConfigurationCollection(items.ToDictionary(x => x.Name, x => (Func<ItemConfiguration>)(() => x.Value))); return new ItemConfigurationCollection(items.ToDictionary(x => x.Name, x => (Func<ItemConfiguration>)(() => x.Value)));
}); });
services.TryAddSingleton<IValueStore<SecurityKey>, ValueStore<SecurityKey>>(); services.TryAddSingleton<IDecoratorService<SecurityKey>, DecoratorService<SecurityKey>>();
services.TryAddSingleton<IValueStore<LockerConnection>, ValueStore<LockerConnection>>(); services.TryAddSingleton<IDecoratorService<LockerConnection>, DecoratorService<LockerConnection>>();
services.AddDbContextFactory<LockerContext>((provider, args) => services.AddDbContextFactory<LockerContext>((provider, args) =>
{ {
if (provider.GetRequiredService<IValueStore<LockerConnection>>() if (provider.GetRequiredService<IDecoratorService<LockerConnection>>()
is IValueStore<LockerConnection> connection) is IDecoratorService<LockerConnection> connection)
{ {
args.UseSqlite($"{connection.Value}"); args.UseSqlite($"{connection.Value}");
} }
@@ -111,6 +111,11 @@ public partial class App : Application
services.AddTemplate<LockerViewModel, LockerView>("Locker"); services.AddTemplate<LockerViewModel, LockerView>("Locker");
services.AddTemplate<ItemCollectionViewModel, ItemCollectionView>("ContentItemCollection"); services.AddTemplate<ItemCollectionViewModel, ItemCollectionView>("ContentItemCollection");
services.AddSingleton<IDecoratorService<ICollectionSynchronization<ItemNavigationViewModel>>,
DecoratorService<ICollectionSynchronization<ItemNavigationViewModel>>>();
services.AddSingleton(provider => provider.GetRequiredService<IDecoratorService<ICollectionSynchronization<ItemNavigationViewModel>>>().Value!);
services.AddHandler<AggerateItemViewModelHandler>(); services.AddHandler<AggerateItemViewModelHandler>();
services.AddTemplate<LockerHeaderViewModel, LockerHeaderView>("LockerHeader"); services.AddTemplate<LockerHeaderViewModel, LockerHeaderView>("LockerHeader");
@@ -123,7 +128,7 @@ public partial class App : Application
services.AddHandler<AggregateItemCategoryViewModelHandler>(); services.AddHandler<AggregateItemCategoryViewModelHandler>();
services.AddScoped<IValueStore<Item<(Guid, string)>>, ValueStore<Item<(Guid, string)>>>(); services.AddScoped<IDecoratorService<Item<(Guid, string)>>, DecoratorService<Item<(Guid, string)>>>();
services.AddTemplate<AddItemNavigationViewModel, AddItemNavigationView>(); services.AddTemplate<AddItemNavigationViewModel, AddItemNavigationView>();
@@ -143,6 +148,12 @@ public partial class App : Application
services.AddTemplate<ItemMaskedTextEntryViewModel, ItemMaskedTextEntryView>(); services.AddTemplate<ItemMaskedTextEntryViewModel, ItemMaskedTextEntryView>();
services.AddTemplate<ItemDropdownEntryViewModel, ItemDropdownEntryView>(); services.AddTemplate<ItemDropdownEntryViewModel, ItemDropdownEntryView>();
services.AddScoped<IDecoratorService<ICollectionSynchronization<IItemEntryViewModel>>,
DecoratorService<ICollectionSynchronization<IItemEntryViewModel>>>();
services.AddScoped(provider => provider.GetRequiredService<IDecoratorService<ICollectionSynchronization<IItemEntryViewModel>>>().Value!);
services.AddTemplate<ItemCommandHeaderViewModel, ItemCommandHeaderView>("ItemCommandHeader"); services.AddTemplate<ItemCommandHeaderViewModel, ItemCommandHeaderView>("ItemCommandHeader");
services.AddTemplate<FavouriteItemActionViewModel, FavouriteItemActionView>(); services.AddTemplate<FavouriteItemActionViewModel, FavouriteItemActionView>();
@@ -6,6 +6,6 @@
x:DataType="vm:ItemMaskedTextEntryViewModel" x:DataType="vm:ItemMaskedTextEntryViewModel"
Header="{Binding Key}"> Header="{Binding Key}">
<SettingsExpander.Footer> <SettingsExpander.Footer>
<TextBox MinWidth="264" /> <TextBox MinWidth="264" Text="{Binding Value}" />
</SettingsExpander.Footer> </SettingsExpander.Footer>
</SettingsExpander> </SettingsExpander>
@@ -9,6 +9,7 @@
<TextBox <TextBox
MinWidth="264" MinWidth="264"
Classes="revealPasswordButton" Classes="revealPasswordButton"
PasswordChar="&#x25CF;" /> PasswordChar="&#x25CF;"
Text="{Binding Value}" />
</SettingsExpander.Footer> </SettingsExpander.Footer>
</SettingsExpander> </SettingsExpander>
+1 -1
View File
@@ -6,6 +6,6 @@
x:DataType="vm:ItemTextEntryViewModel" x:DataType="vm:ItemTextEntryViewModel"
Header="{Binding Key}"> Header="{Binding Key}">
<SettingsExpander.Footer> <SettingsExpander.Footer>
<TextBox MinWidth="264" /> <TextBox MinWidth="264" Text="{Binding Value}" />
</SettingsExpander.Footer> </SettingsExpander.Footer>
</SettingsExpander> </SettingsExpander>
+3 -1
View File
@@ -8,8 +8,10 @@ public record BlobEntry
{ {
public byte[]? Data { get; set; } public byte[]? Data { get; set; }
public DocumentType Type { get; set; } public int Type { get; set; }
[Key] [Key]
public int Id { get; set; } public int Id { get; set; }
public DateTimeOffset DateTime { get; set; }
} }
-7
View File
@@ -1,7 +0,0 @@
namespace Bitvault.Data;
public enum DocumentType
{
Form,
File
}
@@ -16,19 +16,19 @@ public class AggregateItemContentFromCategoryViewModelHandler(IItemConfiguration
{ {
if (factory.Invoke() is ItemConfiguration configuration) if (factory.Invoke() is ItemConfiguration configuration)
{ {
int index = 0; foreach (ItemSectionConfiguration configurationSection in configuration.Sections)
foreach (ItemSectionConfiguration section in configuration.Sections)
{ {
if (serviceFactory.Create<ItemSectionViewModel>($"{nameof(ItemSection)}{index}") is ItemSectionViewModel sectionViewModel) string section = $"{nameof(ItemSection)}:{Guid.NewGuid}";
if (serviceFactory.Create<ItemSectionViewModel>(section)
is ItemSectionViewModel sectionViewModel)
{ {
publisher.Publish(Create.As(sectionViewModel), nameof(ItemContentViewModel)); publisher.Publish(Create.As(sectionViewModel), nameof(ItemContentViewModel));
foreach (ItemEntryConfiguration entryConfiguration in section.Entries) foreach (ItemEntryConfiguration entryConfiguration in configurationSection.Entries)
{ {
if (await mediator.Handle<ItemEntryConfiguration, IItemEntryViewModel?>(entryConfiguration, if (await mediator.Handle<ItemEntryConfiguration, IItemEntryViewModel?>(entryConfiguration,
entryConfiguration.GetType().Name) is IItemEntryViewModel entryViewModel) entryConfiguration.GetType().Name) is IItemEntryViewModel entryViewModel)
{ {
publisher.Publish(Create.As(entryViewModel), $"{nameof(ItemSection)}{index}"); publisher.Publish(Create.As(entryViewModel), section);
} }
} }
} }
+2 -2
View File
@@ -30,13 +30,13 @@ public class AggerateItemViewModelHandler(IMediator mediator,
{ {
IServiceScope serviceScope = serviceProvider.CreateScope(); IServiceScope serviceScope = serviceProvider.CreateScope();
IServiceFactory serviceFactory = serviceScope.ServiceProvider.GetRequiredService<IServiceFactory>(); IServiceFactory serviceFactory = serviceScope.ServiceProvider.GetRequiredService<IServiceFactory>();
IValueStore<Item<(Guid, string)>> valueStore = serviceScope.ServiceProvider.GetRequiredService<IValueStore<Item<(Guid, string)>>>(); IDecoratorService<Item<(Guid, string)>> decoratorService = serviceScope.ServiceProvider.GetRequiredService<IDecoratorService<Item<(Guid, string)>>>();
if (serviceFactory.Create<ItemNavigationViewModel>(Id, Name, "Description", Category, selected, Favourite, Archived) is ItemNavigationViewModel viewModel) if (serviceFactory.Create<ItemNavigationViewModel>(Id, Name, "Description", Category, selected, Favourite, Archived) is ItemNavigationViewModel viewModel)
{ {
Item<(Guid, string)> item = new((Id, Name)); Item<(Guid, string)> item = new((Id, Name));
valueStore.Set(item); decoratorService.Set(item);
cache.Add(item); cache.Add(item);
publisher.Publish(Create.As(viewModel), nameof(ItemCollectionViewModel)); publisher.Publish(Create.As(viewModel), nameof(ItemCollectionViewModel));
+2 -2
View File
@@ -2,7 +2,7 @@
namespace Bitvault; namespace Bitvault;
public class ArchiveItemHandler(IValueStore<Item<(Guid, string)>> valueStore, public class ArchiveItemHandler(IDecoratorService<Item<(Guid, string)>> decoratorService,
ICache<Item<(Guid, string)>> cache, ICache<Item<(Guid, string)>> cache,
IMediator mediator) : IMediator mediator) :
INotificationHandler<ArchiveEventArgs<Item>> INotificationHandler<ArchiveEventArgs<Item>>
@@ -11,7 +11,7 @@ public class ArchiveItemHandler(IValueStore<Item<(Guid, string)>> valueStore,
{ {
try try
{ {
if (valueStore.Value is Item<(Guid, string)> item) if (decoratorService.Value is Item<(Guid, string)> item)
{ {
if (cache.Contains(item)) if (cache.Contains(item))
{ {
+5 -2
View File
@@ -8,11 +8,14 @@ public class ConfirmCreateItemHandler(IMediator mediator,
{ {
public async Task Handle(ConfirmEventArgs<Item> args) public async Task Handle(ConfirmEventArgs<Item> args)
{ {
string? name = await mediator.Handle<ConfirmEventArgs<Item>, string? name = await mediator.Handle<ConfirmEventArgs<ItemHeader>,
string?>(args, nameof(ItemHeader)); string>(Confirm.As<ItemHeader>());
if (name is not null) if (name is not null)
{ {
IList<ItemEntryConfiguration?> entries = await mediator.HandleMany<ConfirmEventArgs<ItemContentEntry>,
ItemEntryConfiguration>(Confirm.As<ItemContentEntry>());
Guid id = Guid.NewGuid(); Guid id = Guid.NewGuid();
publisher.Publish(Created.As(new Item<(Guid, string)>((id, name)))); publisher.Publish(Created.As(new Item<(Guid, string)>((id, name))));
+6 -6
View File
@@ -2,24 +2,24 @@
namespace Bitvault; namespace Bitvault;
public class ConfirmUpdateItemHandler(IValueStore<Item<(Guid, string)>> store, public class ConfirmUpdateItemHandler(IDecoratorService<Item<(Guid, string)>> store,
IMediator mediator, IMediator mediator,
IPublisher publisher) : IPublisher publisher) :
INotificationHandler<ConfirmEventArgs<Item>> INotificationHandler<ConfirmEventArgs<Item>>
{ {
public async Task Handle(ConfirmEventArgs<Item> args) public async Task Handle(ConfirmEventArgs<Item> args)
{ {
ItemHeaderConfiguration? configuration = await mediator.Handle<ConfirmEventArgs<Item>, string? name = await mediator.Handle<ConfirmEventArgs<ItemHeader>,
ItemHeaderConfiguration>(args); string>(Confirm.As<ItemHeader>());
if (configuration is not null) if (name is not null)
{ {
publisher.Publish(Notify.As(configuration));
publisher.Publish(Notify.As(new ItemHeader<string>(name)));
if (store?.Value is Item<(Guid, string)> item) if (store?.Value is Item<(Guid, string)> item)
{ {
(Guid id, string _) = item.Value; (Guid id, string _) = item.Value;
string? name = configuration.Name;
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));
+1
View File
@@ -22,6 +22,7 @@ public class CreateItemHandler(IDbContextFactory<LockerContext> dbContextFactory
{ {
result = await context.AddAsync(new ItemEntry { Id = id, Name = name, Category = category }, cancellationToken); result = await context.AddAsync(new ItemEntry { Id = id, Name = name, Category = category }, cancellationToken);
await context.SaveChangesAsync(cancellationToken); await context.SaveChangesAsync(cancellationToken);
}, cancellationToken); }, cancellationToken);
if (result is not null) if (result is not null)
+1 -1
View File
@@ -18,7 +18,7 @@ public class CreateLockerHandler(ILockerFactory componentFactory,
if (componentFactory.Create(name) is IComponentHost host) if (componentFactory.Create(name) is IComponentHost host)
{ {
ISecurityKeyFactory keyVaultFactory = host.Services.GetRequiredService<ISecurityKeyFactory>(); ISecurityKeyFactory keyVaultFactory = host.Services.GetRequiredService<ISecurityKeyFactory>();
IValueStore<SecurityKey> secureKeyStore = host.Services.GetRequiredService<IValueStore<SecurityKey>>(); IDecoratorService<SecurityKey> secureKeyStore = host.Services.GetRequiredService<IDecoratorService<SecurityKey>>();
ILockerStorageFactory lockerStorageFactory = host.Services.GetRequiredService<ILockerStorageFactory>(); ILockerStorageFactory lockerStorageFactory = host.Services.GetRequiredService<ILockerStorageFactory>();
if (keyVaultFactory.Create(Encoding.UTF8.GetBytes(password)) is SecurityKey key) if (keyVaultFactory.Create(Encoding.UTF8.GetBytes(password)) is SecurityKey key)
+2 -2
View File
@@ -2,7 +2,7 @@
namespace Bitvault; namespace Bitvault;
public class FavouriteItemHandler(IValueStore<Item<(Guid, string)>> valueStore, public class FavouriteItemHandler(IDecoratorService<Item<(Guid, string)>> decoratorService,
IMediator mediator) : IMediator mediator) :
INotificationHandler<FavouriteEventArgs<Item>> INotificationHandler<FavouriteEventArgs<Item>>
{ {
@@ -10,7 +10,7 @@ public class FavouriteItemHandler(IValueStore<Item<(Guid, string)>> valueStore,
{ {
try try
{ {
if (valueStore.Value is Item<(Guid, string)> item) if (decoratorService.Value is Item<(Guid, string)> item)
{ {
(Guid id, string name) = item.Value; (Guid id, string name) = item.Value;
await mediator.Handle<UpdateEventArgs<(Guid, int)>, bool>(new UpdateEventArgs<(Guid, int)>((id, 1))); await mediator.Handle<UpdateEventArgs<(Guid, int)>, bool>(new UpdateEventArgs<(Guid, int)>((id, 1)));
+3 -2
View File
@@ -5,12 +5,13 @@ namespace Bitvault;
public partial class FooterViewModel : public partial class FooterViewModel :
ObservableCollection<IMainNavigationViewModel> ObservableCollection<IMainNavigationViewModel>
{ {
public FooterViewModel(IServiceProvider provider, public FooterViewModel(ICollectionSynchronizer synchronizer,
IServiceProvider provider,
IServiceFactory factory, IServiceFactory factory,
IMediator mediator, IMediator mediator,
IPublisher publisher, IPublisher publisher,
ISubscription subscriber, ISubscription subscriber,
IDisposer disposer) : base(provider, factory, mediator, publisher, subscriber, disposer) IDisposer disposer) : base(synchronizer, provider, factory, mediator, publisher, subscriber, disposer)
{ {
Add<ManageNavigationViewModel>(); Add<ManageNavigationViewModel>();
} }
+3 -2
View File
@@ -4,14 +4,15 @@ using Toolkit.Foundation;
namespace Bitvault; namespace Bitvault;
[Notification(typeof(CreateEventArgs<ItemCategoryNavigationViewModel>), nameof(ItemCategoryCollectionViewModel))] [Notification(typeof(CreateEventArgs<ItemCategoryNavigationViewModel>), nameof(ItemCategoryCollectionViewModel))]
public partial class ItemCategoryCollectionViewModel(IServiceProvider provider, public partial class ItemCategoryCollectionViewModel(ICollectionSynchronizer synchronizer,
IServiceProvider provider,
IServiceFactory factory, IServiceFactory factory,
IMediator mediator, IMediator mediator,
IPublisher publisher, IPublisher publisher,
ISubscription subscriber, ISubscription subscriber,
IDisposer disposer, IDisposer disposer,
IContentTemplate template) : IContentTemplate template) :
ObservableCollection<ItemCategoryNavigationViewModel>(provider, factory, mediator, publisher, subscriber, disposer) ObservableCollection<ItemCategoryNavigationViewModel>(synchronizer, provider, factory, mediator, publisher, subscriber, disposer)
{ {
[ObservableProperty] [ObservableProperty]
private IContentTemplate template = template; private IContentTemplate template = template;
+3 -2
View File
@@ -18,7 +18,8 @@ public partial class ItemCollectionViewModel :
private LockerViewModelConfiguration configuration; private LockerViewModelConfiguration configuration;
public ItemCollectionViewModel(IServiceProvider provider, public ItemCollectionViewModel(ICollectionSynchronizer synchronizer,
IServiceProvider provider,
IServiceFactory factory, IServiceFactory factory,
IMediator mediator, IMediator mediator,
IPublisher publisher, IPublisher publisher,
@@ -27,7 +28,7 @@ public partial class ItemCollectionViewModel :
IContentTemplate template, IContentTemplate template,
NamedComponent named, NamedComponent named,
LockerViewModelConfiguration configuration, LockerViewModelConfiguration configuration,
string? filter = null) : base(provider, factory, mediator, publisher, subscriber, disposer) string? filter = null) : base(synchronizer, provider, factory, mediator, publisher, subscriber, disposer)
{ {
Template = template; Template = template;
Named = $"{named}"; Named = $"{named}";
+3 -2
View File
@@ -2,14 +2,15 @@
namespace Bitvault; namespace Bitvault;
public partial class ItemCommandHeaderViewModel(IServiceProvider provider, public partial class ItemCommandHeaderViewModel(ICollectionSynchronizer synchronizer,
IServiceProvider provider,
IServiceFactory factory, IServiceFactory factory,
IMediator mediator, IMediator mediator,
IPublisher publisher, IPublisher publisher,
ISubscription subscriber, ISubscription subscriber,
IDisposer disposer, IDisposer disposer,
IContentTemplate template) : IContentTemplate template) :
ObservableCollection(provider, factory, mediator, publisher, subscriber, disposer), ObservableCollection(synchronizer, provider, factory, mediator, publisher, subscriber, disposer),
INotificationHandler<NotifyEventArgs<ItemCommandHeaderCollection>> INotificationHandler<NotifyEventArgs<ItemCommandHeaderCollection>>
{ {
public IContentTemplate Template { get; set; } = template; public IContentTemplate Template { get; set; } = template;
+5
View File
@@ -0,0 +1,5 @@
namespace Bitvault;
public record ItemContentEntry<TValue>(TValue Value);
public record ItemContentEntry;
+3 -2
View File
@@ -3,14 +3,15 @@
namespace Bitvault; namespace Bitvault;
[Notification(typeof(CreateEventArgs<ItemSectionViewModel>), nameof(ItemContentViewModel))] [Notification(typeof(CreateEventArgs<ItemSectionViewModel>), nameof(ItemContentViewModel))]
public partial class ItemContentViewModel(IServiceProvider provider, public partial class ItemContentViewModel(ICollectionSynchronizer synchronizer,
IServiceProvider provider,
IServiceFactory factory, IMediator mediator, IServiceFactory factory, IMediator mediator,
IPublisher publisher, IPublisher publisher,
ISubscription subscriber, ISubscription subscriber,
IDisposer disposer, IDisposer disposer,
IContentTemplate template, IContentTemplate template,
ItemState state = ItemState.Read) : ItemState state = ItemState.Read) :
ObservableCollection<ItemSectionViewModel>(provider, factory, mediator, publisher, subscriber, disposer), ObservableCollection<ItemSectionViewModel>(synchronizer, provider, factory, mediator, publisher, subscriber, disposer),
IItemEntryViewModel, IItemEntryViewModel,
INotificationHandler<NotifyEventArgs<ItemCategory<string>>> INotificationHandler<NotifyEventArgs<ItemCategory<string>>>
{ {
+2 -2
View File
@@ -16,7 +16,7 @@ public class ItemCreatedHandler(IServiceProvider serviceProvider,
IServiceScope serviceScope = serviceProvider.CreateScope(); IServiceScope serviceScope = serviceProvider.CreateScope();
IServiceFactory serviceFactory = serviceScope.ServiceProvider.GetRequiredService<IServiceFactory>(); IServiceFactory serviceFactory = serviceScope.ServiceProvider.GetRequiredService<IServiceFactory>();
IValueStore<Item<(Guid, string)>> valueStore = serviceScope.ServiceProvider.GetRequiredService<IValueStore<Item<(Guid, string)>>>(); IDecoratorService<Item<(Guid, string)>> decoratorService = serviceScope.ServiceProvider.GetRequiredService<IDecoratorService<Item<(Guid, string)>>>();
if (serviceFactory.Create<ItemNavigationViewModel>(id, name, "Description", true) if (serviceFactory.Create<ItemNavigationViewModel>(id, name, "Description", true)
is ItemNavigationViewModel viewModel) is ItemNavigationViewModel viewModel)
@@ -24,7 +24,7 @@ public class ItemCreatedHandler(IServiceProvider serviceProvider,
cache.Add(item); cache.Add(item);
int index = cache.IndexOf(item); int index = cache.IndexOf(item);
valueStore.Set(item); decoratorService.Set(item);
publisher.Publish(Insert.As(index, viewModel), publisher.Publish(Insert.As(index, viewModel),
nameof(ItemCollectionViewModel)); nameof(ItemCollectionViewModel));
+3 -2
View File
@@ -8,6 +8,7 @@ public partial class ItemDropdownEntryViewModel(IServiceProvider provider,
IPublisher publisher, IPublisher publisher,
ISubscription subscriber, ISubscription subscriber,
IDisposer disposer, IDisposer disposer,
ICollectionSynchronization<IItemEntryViewModel> synchronization,
ItemEntryConfiguration configuration,
string? key = default, string? key = default,
object? value = default) : Observable<string, object?>(provider, factory, mediator, publisher, subscriber, disposer, key, value), string? value = default) : ItemEntryViewModel<string, string?>(provider, factory, mediator, publisher, subscriber, disposer, synchronization, configuration, key, value);
IItemEntryViewModel;
@@ -8,7 +8,8 @@ public class ItemDropdownEntryViewModelHandler(IServiceFactory serviceFactory) :
public Task<IItemEntryViewModel?> Handle(DropdownEntryConfiguration args, public Task<IItemEntryViewModel?> Handle(DropdownEntryConfiguration args,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
if (serviceFactory.Create<ItemDropdownEntryViewModel>(args.Label, args.Value ?? new object()) is ItemDropdownEntryViewModel viewModel) if (serviceFactory.Create<ItemDropdownEntryViewModel>(args, args.Label, args.Value ?? "")
is ItemDropdownEntryViewModel viewModel)
{ {
return Task.FromResult<IItemEntryViewModel?>(viewModel); return Task.FromResult<IItemEntryViewModel?>(viewModel);
} }
+16 -13
View File
@@ -1,24 +1,27 @@
using CommunityToolkit.Mvvm.ComponentModel; using Toolkit.Foundation;
using Toolkit.Foundation;
namespace Bitvault; namespace Bitvault;
public partial class ItemEntryViewModel<TKey, TValue> : public partial class ItemEntryViewModel<TKey, TValue>(IServiceProvider provider,
Observable<TKey, TValue>
{
public ItemEntryViewModel(IServiceProvider provider,
IServiceFactory factory, IServiceFactory factory,
IMediator mediator, IMediator mediator,
IPublisher publisher, IPublisher publisher,
ISubscription subscriber, ISubscription subscriber,
IDisposer disposer, IDisposer disposer,
string type, ICollectionSynchronization<IItemEntryViewModel> synchronization,
ItemEntryConfiguration configuration,
TKey? key = default, TKey? key = default,
TValue? value = default) : base(provider, factory, mediator, publisher, subscriber, disposer, key, value) TValue? value = default) :
{ Observable<TKey, TValue>(provider, factory, mediator, publisher, subscriber, disposer, key, value),
Type = type; IHandler<ConfirmEventArgs<ItemContentEntry>, ItemEntryConfiguration>,
} IItemEntryViewModel,
IIndexable
{
public int Index => synchronization.IndexOf(this);
[ObservableProperty] public Task<ItemEntryConfiguration> Handle(ConfirmEventArgs<ItemContentEntry> args,
private string type; CancellationToken cancellationToken)
{
return Task.FromResult(configuration with { Value = Value });
}
} }
+2
View File
@@ -1,3 +1,5 @@
namespace Bitvault; namespace Bitvault;
public record ItemHeader<TValue>(TValue Value);
public record ItemHeader; public record ItemHeader;
-6
View File
@@ -1,6 +0,0 @@
namespace Bitvault;
public record ItemHeaderConfiguration
{
public string Name { get; init; } = "";
}
+4 -5
View File
@@ -3,14 +3,13 @@ using Toolkit.Foundation;
namespace Bitvault; namespace Bitvault;
[Notification(typeof(ConfirmEventArgs<Item>), nameof(ItemHeader))]
public partial class ItemHeaderViewModel : public partial class ItemHeaderViewModel :
Observable<string, string>, Observable<string, string>,
IHandler<ValidationEventArgs<Item>, bool>,
IHandler<ConfirmEventArgs<Item>, string?>,
INotificationHandler<UpdateEventArgs<Item>>, INotificationHandler<UpdateEventArgs<Item>>,
INotificationHandler<ConfirmEventArgs<Item>>, INotificationHandler<ConfirmEventArgs<Item>>,
INotificationHandler<CancelEventArgs<Item>>, INotificationHandler<CancelEventArgs<Item>>,
IHandler<ValidationEventArgs<ItemHeader>, bool>,
IHandler<ConfirmEventArgs<ItemHeader>, string?>,
INotificationHandler<NotifyEventArgs<ItemCategory<string>>> INotificationHandler<NotifyEventArgs<ItemCategory<string>>>
{ {
[ObservableProperty] [ObservableProperty]
@@ -34,7 +33,7 @@ public partial class ItemHeaderViewModel :
Track(nameof(Value), () => Value, newValue => Value = newValue); Track(nameof(Value), () => Value, newValue => Value = newValue);
} }
public Task<bool> Handle(ValidationEventArgs<Item> args, public Task<bool> Handle(ValidationEventArgs<ItemHeader> args,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
return Task.FromResult(true); return Task.FromResult(true);
@@ -69,6 +68,6 @@ public partial class ItemHeaderViewModel :
return Task.CompletedTask; return Task.CompletedTask;
} }
public Task<string?> Handle(ConfirmEventArgs<Item> args, public Task<string?> Handle(ConfirmEventArgs<ItemHeader> args,
CancellationToken cancellationToken) => Task.FromResult(Value); CancellationToken cancellationToken) => Task.FromResult(Value);
} }
+3 -2
View File
@@ -8,6 +8,7 @@ public partial class ItemMaskedTextEntryViewModel(IServiceProvider provider,
IPublisher publisher, IPublisher publisher,
ISubscription subscriber, ISubscription subscriber,
IDisposer disposer, IDisposer disposer,
ICollectionSynchronization<IItemEntryViewModel> synchronization,
ItemEntryConfiguration configuration,
string? key = default, string? key = default,
object? value = default) : Observable<string, object?>(provider, factory, mediator, publisher, subscriber, disposer, key, value), string? value = default) : ItemEntryViewModel<string, string?>(provider, factory, mediator, publisher, subscriber, disposer, synchronization, configuration, key, value);
IItemEntryViewModel;
@@ -8,7 +8,7 @@ public class ItemMaskedTextEntryViewModelHandler(IServiceFactory serviceFactory)
public Task<IItemEntryViewModel?> Handle(MaskedTextEntryConfiguration args, public Task<IItemEntryViewModel?> Handle(MaskedTextEntryConfiguration args,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
if (serviceFactory.Create<ItemMaskedTextEntryViewModel>(args.Label, args.Value ?? new object()) is if (serviceFactory.Create<ItemMaskedTextEntryViewModel>(args, args.Label, args.Value ?? "") is
ItemMaskedTextEntryViewModel viewModel) ItemMaskedTextEntryViewModel viewModel)
{ {
return Task.FromResult<IItemEntryViewModel?>(viewModel); return Task.FromResult<IItemEntryViewModel?>(viewModel);
+2 -2
View File
@@ -18,7 +18,7 @@ public class ItemModifiedHandler(IServiceProvider serviceProvider,
if (cachedItem is not null) if (cachedItem is not null)
{ {
IServiceScope serviceScope = serviceProvider.CreateScope(); IServiceScope serviceScope = serviceProvider.CreateScope();
IValueStore<Item<(Guid, string)>> valueStore = serviceScope.ServiceProvider.GetRequiredService<IValueStore<Item<(Guid, string)>>>(); IDecoratorService<Item<(Guid, string)>> decoratorService = serviceScope.ServiceProvider.GetRequiredService<IDecoratorService<Item<(Guid, string)>>>();
int oldIndex = cache.IndexOf(cachedItem); int oldIndex = cache.IndexOf(cachedItem);
cache.Remove(cachedItem); cache.Remove(cachedItem);
@@ -26,7 +26,7 @@ public class ItemModifiedHandler(IServiceProvider serviceProvider,
cache.Add(newItem); cache.Add(newItem);
int newIndex = cache.IndexOf(newItem); int newIndex = cache.IndexOf(newItem);
valueStore.Set(newItem); decoratorService.Set(newItem);
publisher.Publish(MoveTo.As<ItemNavigationViewModel>(oldIndex, newIndex), publisher.Publish(MoveTo.As<ItemNavigationViewModel>(oldIndex, newIndex),
nameof(ItemCollectionViewModel)); nameof(ItemCollectionViewModel));
+8 -6
View File
@@ -1,6 +1,5 @@
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
using Toolkit.Foundation; using Toolkit.Foundation;
using Toolkit.UI.Avalonia;
namespace Bitvault; namespace Bitvault;
@@ -11,6 +10,7 @@ public partial class ItemNavigationViewModel(IServiceProvider provider,
ISubscription subscriber, ISubscription subscriber,
IDisposer disposer, IDisposer disposer,
IContentTemplate template, IContentTemplate template,
ICollectionSynchronization<ItemNavigationViewModel> synchronization,
NamedComponent named, NamedComponent named,
Guid id, Guid id,
string name = "", string name = "",
@@ -24,8 +24,9 @@ public partial class ItemNavigationViewModel(IServiceProvider provider,
INotificationHandler<UnarchiveEventArgs<Item>>, INotificationHandler<UnarchiveEventArgs<Item>>,
INotificationHandler<FavouriteEventArgs<Item>>, INotificationHandler<FavouriteEventArgs<Item>>,
INotificationHandler<UnfavouriteEventArgs<Item>>, INotificationHandler<UnfavouriteEventArgs<Item>>,
INotificationHandler<NotifyEventArgs<ItemHeaderConfiguration>>, INotificationHandler<NotifyEventArgs<ItemHeader<string>>>,
ISelectable, ISelectable,
IIndexable,
IRemovable IRemovable
{ {
[ObservableProperty] [ObservableProperty]
@@ -52,7 +53,8 @@ public partial class ItemNavigationViewModel(IServiceProvider provider,
[ObservableProperty] [ObservableProperty]
private bool selected = selected; private bool selected = selected;
public bool Attached { get; set; } public int Index => synchronization.IndexOf(this);
public IContentTemplate Template { get; set; } = template; public IContentTemplate Template { get; set; } = template;
public Task Handle(ArchiveEventArgs<Item> args) => public Task Handle(ArchiveEventArgs<Item> args) =>
@@ -67,11 +69,11 @@ public partial class ItemNavigationViewModel(IServiceProvider provider,
public Task Handle(UnfavouriteEventArgs<Item> args) => public Task Handle(UnfavouriteEventArgs<Item> args) =>
Task.FromResult(Favourite = false); Task.FromResult(Favourite = false);
public Task Handle(NotifyEventArgs<ItemHeaderConfiguration> args) public Task Handle(NotifyEventArgs<ItemHeader<string>> args)
{ {
if (args.Value is ItemHeaderConfiguration configuration) if (args.Value is ItemHeader<string> header)
{ {
Name = configuration.Name; Name = header.Value;
} }
return Task.CompletedTask; return Task.CompletedTask;
+3 -3
View File
@@ -8,7 +8,7 @@ public partial class ItemPasswordEntryViewModel(IServiceProvider provider,
IPublisher publisher, IPublisher publisher,
ISubscription subscriber, ISubscription subscriber,
IDisposer disposer, IDisposer disposer,
string type, ICollectionSynchronization<IItemEntryViewModel> synchronization,
ItemEntryConfiguration configuration,
string? key = default, string? key = default,
object? value = default) : ItemEntryViewModel<string, object?>(provider, factory, mediator, publisher, subscriber, disposer, type, key, value), string? value = default) : ItemEntryViewModel<string, string?>(provider, factory, mediator, publisher, subscriber, disposer, synchronization, configuration, key, value);
IItemEntryViewModel;
@@ -8,7 +8,7 @@ public class ItemPasswordEntryViewModelHandler(IServiceFactory serviceFactory) :
public Task<IItemEntryViewModel?> Handle(PasswordEntryConfiguration args, public Task<IItemEntryViewModel?> Handle(PasswordEntryConfiguration args,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
if (serviceFactory.Create<ItemPasswordEntryViewModel>("Password", args.Label, args.Value ?? new object()) if (serviceFactory.Create<ItemPasswordEntryViewModel>(args, args.Label, args.Value ?? "")
is ItemPasswordEntryViewModel viewModel) is ItemPasswordEntryViewModel viewModel)
{ {
return Task.FromResult<IItemEntryViewModel?>(viewModel); return Task.FromResult<IItemEntryViewModel?>(viewModel);
+3 -2
View File
@@ -4,14 +4,15 @@ using Toolkit.Foundation;
namespace Bitvault; namespace Bitvault;
[Notification(typeof(CreateEventArgs<IItemEntryViewModel>), nameof(Section))] [Notification(typeof(CreateEventArgs<IItemEntryViewModel>), nameof(Section))]
public partial class ItemSectionViewModel(IServiceProvider provider, public partial class ItemSectionViewModel(ICollectionSynchronizer synchronizer,
IServiceProvider provider,
IServiceFactory factory, IServiceFactory factory,
IMediator mediator, IMediator mediator,
IPublisher publisher, IPublisher publisher,
ISubscription subscriber, ISubscription subscriber,
IDisposer disposer, IDisposer disposer,
IContentTemplate template, IContentTemplate template,
string section) : ObservableCollection<IItemEntryViewModel>(provider, factory, mediator, publisher, subscriber, disposer) string section) : ObservableCollection<IItemEntryViewModel>(synchronizer, provider, factory, mediator, publisher, subscriber, disposer)
{ {
[ObservableProperty] [ObservableProperty]
private string section = section; private string section = section;
+3 -2
View File
@@ -8,6 +8,7 @@ public partial class ItemTextEntryViewModel(IServiceProvider provider,
IPublisher publisher, IPublisher publisher,
ISubscription subscriber, ISubscription subscriber,
IDisposer disposer, IDisposer disposer,
ICollectionSynchronization<IItemEntryViewModel> synchronization,
ItemEntryConfiguration configuration,
string? key = default, string? key = default,
string? value = default) : Observable<string, string>(provider, factory, mediator, publisher, subscriber, disposer, key, value), string? value = default) : ItemEntryViewModel<string, string?>(provider, factory, mediator, publisher, subscriber, disposer, synchronization, configuration, key, value);
IItemEntryViewModel;
+2 -1
View File
@@ -8,7 +8,8 @@ public class ItemTextEntryViewModelHandler(IServiceFactory serviceFactory) :
public Task<IItemEntryViewModel?> Handle(TextEntryConfiguration args, public Task<IItemEntryViewModel?> Handle(TextEntryConfiguration args,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
if (serviceFactory.Create<ItemTextEntryViewModel>(args.Label, args.Value ?? "") is ItemTextEntryViewModel viewModel) if (serviceFactory.Create<ItemTextEntryViewModel>(args, args.Label, args.Value ?? "")
is ItemTextEntryViewModel viewModel)
{ {
return Task.FromResult<IItemEntryViewModel?>(viewModel); return Task.FromResult<IItemEntryViewModel?>(viewModel);
} }
+3 -2
View File
@@ -29,7 +29,8 @@ public partial class ItemViewModel :
[ObservableProperty] [ObservableProperty]
private bool fromCategory; private bool fromCategory;
public ItemViewModel(IServiceProvider provider, public ItemViewModel(ICollectionSynchronizer synchronizer,
IServiceProvider provider,
IServiceFactory factory, IServiceFactory factory,
IMediator mediator, IMediator mediator,
IPublisher publisher, IPublisher publisher,
@@ -41,7 +42,7 @@ public partial class ItemViewModel :
bool fromCategory = false, bool fromCategory = false,
string name = "", string name = "",
bool favourite = false, bool favourite = false,
bool archived = false) : base(provider, factory, mediator, publisher, subscriber, disposer) bool archived = false) : base(synchronizer,provider, factory, mediator, publisher, subscriber, disposer)
{ {
Template = template; Template = template;
Named = $"{named}"; Named = $"{named}";
+3 -2
View File
@@ -2,14 +2,15 @@
namespace Bitvault; namespace Bitvault;
public partial class LockerHeaderViewModel(IServiceProvider provider, public partial class LockerHeaderViewModel(ICollectionSynchronizer synchronizer,
IServiceProvider provider,
IServiceFactory factory, IServiceFactory factory,
IMediator mediator, IMediator mediator,
IPublisher publisher, IPublisher publisher,
ISubscription subscriber, ISubscription subscriber,
IDisposer disposer, IDisposer disposer,
IContentTemplate template) : IContentTemplate template) :
ObservableCollection(provider, factory, mediator, publisher, subscriber, disposer), ObservableCollection(synchronizer, provider, factory, mediator, publisher, subscriber, disposer),
INotificationHandler<NotifyEventArgs<LockerCommandHeaderCollection>> INotificationHandler<NotifyEventArgs<LockerCommandHeaderCollection>>
{ {
public IContentTemplate Template { get; set; } = template; public IContentTemplate Template { get; set; } = template;
+3 -2
View File
@@ -27,7 +27,8 @@ public partial class LockerNavigationViewModel :
[ObservableProperty] [ObservableProperty]
private bool selected; private bool selected;
public LockerNavigationViewModel(IServiceProvider provider, public LockerNavigationViewModel(ICollectionSynchronizer synchronizer,
IServiceProvider provider,
IServiceFactory factory, IServiceFactory factory,
IMediator mediator, IMediator mediator,
IPublisher publisher, IPublisher publisher,
@@ -35,7 +36,7 @@ public partial class LockerNavigationViewModel :
IDisposer disposer, IDisposer disposer,
IContentTemplate template, IContentTemplate template,
string name, string name,
bool selected) : base(provider, factory, mediator, publisher, subscriber, disposer) bool selected) : base(synchronizer,provider, factory, mediator, publisher, subscriber, disposer)
{ {
Template = template; Template = template;
Name = name; Name = name;
+1 -1
View File
@@ -6,7 +6,7 @@ using Toolkit.Foundation;
namespace Bitvault; namespace Bitvault;
public class LockerStorageFactory(IValueStore<LockerConnection> connection, public class LockerStorageFactory(IDecoratorService<LockerConnection> connection,
IHostEnvironment environment, IHostEnvironment environment,
IServiceProvider provider) : IServiceProvider provider) :
ILockerStorageFactory ILockerStorageFactory
+4 -2
View File
@@ -1,4 +1,5 @@
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
using Microsoft.Extensions.DependencyInjection;
using Toolkit.Foundation; using Toolkit.Foundation;
namespace Bitvault; namespace Bitvault;
@@ -10,14 +11,15 @@ public partial class MainViewModel :
[ObservableProperty] [ObservableProperty]
private FooterViewModel footer; private FooterViewModel footer;
public MainViewModel(IServiceProvider provider, public MainViewModel(ICollectionSynchronizer synchronizer,
IServiceProvider provider,
IServiceFactory factory, IServiceFactory factory,
IMediator mediator, IMediator mediator,
IPublisher publisher, IPublisher publisher,
ISubscription subscriber, ISubscription subscriber,
IDisposer disposer, IDisposer disposer,
IContentTemplate template, IContentTemplate template,
FooterViewModel footer) : base(provider, factory, mediator, publisher, subscriber, disposer) FooterViewModel footer) : base(synchronizer, provider, factory, mediator, publisher, subscriber, disposer)
{ {
Template = template; Template = template;
Footer = footer; Footer = footer;
+3 -2
View File
@@ -6,13 +6,14 @@ public partial class ManageViewModel :
ObservableCollection, ObservableCollection,
IMainNavigationViewModel IMainNavigationViewModel
{ {
public ManageViewModel(IServiceProvider provider, public ManageViewModel(ICollectionSynchronizer synchronizer,
IServiceProvider provider,
IServiceFactory factory, IServiceFactory factory,
IMediator mediator, IMediator mediator,
IPublisher publisher, IPublisher publisher,
ISubscription subscriber, ISubscription subscriber,
IDisposer disposer, IDisposer disposer,
IContentTemplate template) : base(provider, factory, mediator, publisher, subscriber, disposer) IContentTemplate template) : base(synchronizer,provider, factory, mediator, publisher, subscriber, disposer)
{ {
Template = template; Template = template;
+2 -2
View File
@@ -4,7 +4,7 @@ using Toolkit.Foundation;
namespace Bitvault; namespace Bitvault;
public class UnarchiveItemHandler(IValueStore<Item<(Guid, string)>> valueStore, public class UnarchiveItemHandler(IDecoratorService<Item<(Guid, string)>> decoratorService,
IDbContextFactory<LockerContext> dbContextFactory) : IDbContextFactory<LockerContext> dbContextFactory) :
INotificationHandler<UnarchiveEventArgs<Item>> INotificationHandler<UnarchiveEventArgs<Item>>
{ {
@@ -12,7 +12,7 @@ public class UnarchiveItemHandler(IValueStore<Item<(Guid, string)>> valueStore,
{ {
try try
{ {
if (valueStore.Value is Item<(Guid, string)> item) if (decoratorService.Value is Item<(Guid, string)> item)
{ {
(Guid id, string name) = item.Value; (Guid id, string name) = item.Value;
await Task.Run(async () => await Task.Run(async () =>
+2 -2
View File
@@ -1,7 +1,7 @@
using Toolkit.Foundation; using Toolkit.Foundation;
namespace Bitvault; namespace Bitvault;
public class UnfavouriteItemHandler(IValueStore<Item<(Guid, string)>> valueStore, public class UnfavouriteItemHandler(IDecoratorService<Item<(Guid, string)>> decoratorService,
IMediator mediator) : IMediator mediator) :
INotificationHandler<UnfavouriteEventArgs<Item>> INotificationHandler<UnfavouriteEventArgs<Item>>
{ {
@@ -9,7 +9,7 @@ public class UnfavouriteItemHandler(IValueStore<Item<(Guid, string)>> valueStore
{ {
try try
{ {
if (valueStore.Value is Item<(Guid, string)> item) if (decoratorService.Value is Item<(Guid, string)> item)
{ {
(Guid id, string name) = item.Value; (Guid id, string name) = item.Value;
await mediator.Handle<UpdateEventArgs<(Guid, int)>, bool>(new UpdateEventArgs<(Guid, int)>((id, 0))); await mediator.Handle<UpdateEventArgs<(Guid, int)>, bool>(new UpdateEventArgs<(Guid, int)>((id, 0)));