It it now possible to create/edit item contents

This commit is contained in:
TheXamlGuy
2024-06-06 20:42:23 +01:00
parent 1302145f1c
commit c399e8c05c
30 changed files with 331 additions and 180 deletions
+2 -1
View File
@@ -87,11 +87,12 @@ public partial class App : Application
if (provider.GetRequiredService<IDecoratorService<LockerConnection>>()
is IDecoratorService<LockerConnection> connection)
{
args.UseSqlite($"{connection.Value}");
args.UseSqlite($"{connection.Service}");
}
});
services.AddHandler<QueryLockerHandler>();
services.AddHandler<RequestItemHandler>();
services.AddHandler<CreateItemHandler>();
services.AddHandler<UpdateItemHander>();
services.AddHandler<UpdateItemStateHandler>();
+2 -25
View File
@@ -17,36 +17,13 @@
<Interaction.Behaviors>
<DataTriggerBehavior Binding="{Binding State}" Value="{x:Static vm:ItemState.Read}">
<AddClassAction ClassName="Read" RemoveIfExists="True" />
<RemoveClassAction ClassName="Write" />
</DataTriggerBehavior>
<DataTriggerBehavior Binding="{Binding State}" Value="{x:Static vm:ItemState.Write}">
<AddClassAction ClassName="Write" RemoveIfExists="True" />
<RemoveClassAction ClassName="Read" />
</DataTriggerBehavior>
</Interaction.Behaviors>
<TextBox.Styles>
<Style Selector="TextBox.Read">
<Setter Property="IsReadOnly" Value="True" />
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="Background" Value="Transparent" />
<Style Selector="^:pointerover">
<Setter Property="Foreground" Value="{DynamicResource TextControlForegroundPointerOver}" />
<Style Selector="^ /template/ Border#PART_BorderElement">
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="Background" Value="Transparent" />
</Style>
</Style>
<Style Selector="^:focus">
<Setter Property="Foreground" Value="{DynamicResource TextControlForegroundFocused}" />
<Style Selector="^ /template/ TextBlock#PART_Watermark">
<Setter Property="Foreground" Value="{DynamicResource TextControlPlaceholderForegroundFocused}" />
</Style>
<Style Selector="^ /template/ Border#PART_BorderElement">
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderBrush" Value="Transparent" />
</Style>
</Style>
</Style>
<Style Selector="TextBox.Write" />
</TextBox.Styles>
</TextBox>
</StackPanel>
</UserControl>
@@ -6,6 +6,17 @@
x:DataType="vm:ItemMaskedTextEntryViewModel"
Header="{Binding Key}">
<SettingsExpander.Footer>
<TextBox MinWidth="264" Text="{Binding Value}" />
<TextBox HorizontalAlignment="Right" Text="{Binding Value}">
<Interaction.Behaviors>
<DataTriggerBehavior Binding="{Binding State}" Value="{x:Static vm:ItemState.Read}">
<AddClassAction ClassName="Read" RemoveIfExists="True" />
<RemoveClassAction ClassName="Write" />
</DataTriggerBehavior>
<DataTriggerBehavior Binding="{Binding State}" Value="{x:Static vm:ItemState.Write}">
<AddClassAction ClassName="Write" RemoveIfExists="True" />
<RemoveClassAction ClassName="Read" />
</DataTriggerBehavior>
</Interaction.Behaviors>
</TextBox>
</SettingsExpander.Footer>
</SettingsExpander>
+10 -1
View File
@@ -10,6 +10,15 @@
MinWidth="264"
Classes="revealPasswordButton"
PasswordChar="&#x25CF;"
Text="{Binding Value}" />
Text="{Binding Value}">
<Interaction.Behaviors>
<DataTriggerBehavior Binding="{Binding State}" Value="{x:Static vm:ItemState.Read}">
<AddClassAction ClassName="Read" RemoveIfExists="True" />
</DataTriggerBehavior>
<DataTriggerBehavior Binding="{Binding State}" Value="{x:Static vm:ItemState.Write}">
<RemoveClassAction ClassName="Read" />
</DataTriggerBehavior>
</Interaction.Behaviors>
</TextBox>
</SettingsExpander.Footer>
</SettingsExpander>
+12 -1
View File
@@ -6,6 +6,17 @@
x:DataType="vm:ItemTextEntryViewModel"
Header="{Binding Key}">
<SettingsExpander.Footer>
<TextBox MinWidth="264" Text="{Binding Value}" />
<TextBox HorizontalAlignment="Right" Text="{Binding Value}">
<Interaction.Behaviors>
<DataTriggerBehavior Binding="{Binding State}" Value="{x:Static vm:ItemState.Read}">
<AddClassAction ClassName="Read" RemoveIfExists="True" />
<RemoveClassAction ClassName="Write" />
</DataTriggerBehavior>
<DataTriggerBehavior Binding="{Binding State}" Value="{x:Static vm:ItemState.Write}">
<AddClassAction ClassName="Write" RemoveIfExists="True" />
<RemoveClassAction ClassName="Read" />
</DataTriggerBehavior>
</Interaction.Behaviors>
</TextBox>
</SettingsExpander.Footer>
</SettingsExpander>
+39 -1
View File
@@ -4,6 +4,44 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:Bitvault"
x:DataType="vm:ItemViewModel">
<UserControl.Styles>
<Style Selector="TextBox.Write">
<Setter Property="MinWidth" Value="264" />
</Style>
<Style Selector="TextBox.Read">
<Setter Property="MinWidth" Value="0" />
<Setter Property="IsReadOnly" Value="True" />
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="Foreground">
<Setter.Value>
<SolidColorBrush Opacity="0.7" Color="{DynamicResource TextFillColorPrimary}" />
</Setter.Value>
</Setter>
<Style Selector="^:pointerover">
<Setter Property="Foreground">
<Setter.Value>
<SolidColorBrush Opacity="0.7" Color="{DynamicResource TextFillColorPrimary}" />
</Setter.Value>
</Setter>
<Style Selector="^ /template/ Border#PART_BorderElement">
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="Background" Value="Transparent" />
</Style>
</Style>
<Style Selector="^:focus">
<Setter Property="Foreground">
<Setter.Value>
<SolidColorBrush Opacity="0.7" Color="{DynamicResource TextFillColorPrimary}" />
</Setter.Value>
</Setter>
<Style Selector="^ /template/ Border#PART_BorderElement">
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderBrush" Value="Transparent" />
</Style>
</Style>
</Style>
</UserControl.Styles>
<Interaction.Behaviors>
<AttachedBehaviour>
<NavigateAction
@@ -22,7 +60,7 @@
</ConditionalExpression>
</ConditionAction.Condition>
<NavigateBackAction Region="Left" />
</ConditionAction>
</ConditionAction>
</DataTriggerBehavior>
</Interaction.Behaviors>
<ScrollViewer Padding="12,12,12,0">
+1 -1
View File
@@ -13,5 +13,5 @@ public record BlobEntry
[Key]
public int Id { get; set; }
public DateTimeOffset DateTime { get; set; }
public DateTime DateTime { get; set; }
}
+2 -2
View File
@@ -17,7 +17,7 @@ public record ItemEntry
public required string Category { get; set; }
public ICollection<TagEntry>? Tags { get; }
public ICollection<TagEntry> Tags { get; set; } = new List<TagEntry>();
public ICollection<BlobEntry>? Blobs { get; }
public ICollection<BlobEntry> Blobs { get; set; } = new List<BlobEntry>();
}
+1 -1
View File
@@ -11,7 +11,7 @@ public class ArchiveItemHandler(IDecoratorService<Item<(Guid, string)>> decorato
{
try
{
if (decoratorService.Value is Item<(Guid, string)> item)
if (decoratorService.Service is Item<(Guid, string)> item)
{
if (cache.Contains(item))
{
+2 -2
View File
@@ -3,13 +3,13 @@
namespace Bitvault;
public class ConfirmCreateItemHandler(IMediator mediator,
IDecoratorService<ItemConfiguration> decoratorItemConfiguration,
IDecoratorService<ItemConfiguration> itemConfigurationDecorator,
IPublisher publisher) :
INotificationHandler<ConfirmEventArgs<Item>>
{
public async Task Handle(ConfirmEventArgs<Item> args)
{
if (decoratorItemConfiguration.Value is ItemConfiguration configuration)
if (itemConfigurationDecorator.Service is ItemConfiguration configuration)
{
string? name = await mediator.Handle<ConfirmEventArgs<ItemHeader>, string>(Confirm.As<ItemHeader>());
if (name is not null)
+13 -12
View File
@@ -2,32 +2,33 @@
namespace Bitvault;
public class ConfirmUpdateItemHandler(IDecoratorService<Item<(Guid, string)>> decoratorItem,
IDecoratorService<ItemConfiguration> decoratorItemConfiguration,
public class ConfirmUpdateItemHandler(IDecoratorService<Item<(Guid, string)>> itemDecorator,
IDecoratorService<ItemConfiguration> itemConfigurationDecorator,
IMediator mediator,
IPublisher publisher) :
INotificationHandler<ConfirmEventArgs<Item>>
{
public async Task Handle(ConfirmEventArgs<Item> args)
{
string? name = await mediator.Handle<ConfirmEventArgs<ItemHeader>,
string>(Confirm.As<ItemHeader>());
if (name is not null)
if (itemDecorator?.Service is Item<(Guid, string)> item &&
itemConfigurationDecorator.Service is ItemConfiguration configuration)
{
var dd = decoratorItemConfiguration;
publisher.Publish(Notify.As(new ItemHeader<string>(name)));
if (decoratorItem?.Value is Item<(Guid, string)> item)
string? name = await mediator.Handle<ConfirmEventArgs<ItemHeader>,
string>(Confirm.As<ItemHeader>());
if (name is not null)
{
publisher.Publish(Notify.As(new ItemHeader<string>(name)));
(Guid id, string _) = item.Value;
Item<(Guid, string)> newItem = new((id, name));
publisher.Publish(Modified.As(item, newItem));
decoratorItem.Set(newItem);
itemDecorator.Set(newItem);
await mediator.Handle<UpdateEventArgs<(Guid, string, ItemConfiguration)>, bool>(new UpdateEventArgs<(Guid, string,
ItemConfiguration)>((id, name, new ItemConfiguration())));
await mediator.Handle<UpdateEventArgs<Item<(Guid, string, ItemConfiguration)>>, bool>(new UpdateEventArgs<Item<(Guid, string,
ItemConfiguration)>>(new Item<(Guid, string, ItemConfiguration)>((id, name, configuration))));
}
}
}
+18 -7
View File
@@ -1,6 +1,8 @@
using Bitvault.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using System.Text;
using System.Text.Json;
using Toolkit.Foundation;
namespace Bitvault;
@@ -15,15 +17,24 @@ public class CreateItemHandler(IDbContextFactory<LockerContext> dbContextFactory
{
try
{
using LockerContext context = dbContextFactory.CreateDbContext();
EntityEntry<ItemEntry>? result = null;
await Task.Run(async () =>
string content = JsonSerializer.Serialize(configuration);
ItemEntry itemEntry = new()
{
result = await context.AddAsync(new ItemEntry { Id = id, Name = name, Category = category }, cancellationToken);
await context.SaveChangesAsync(cancellationToken);
Id = id,
Name = name,
Category = category
};
}, cancellationToken);
itemEntry.Blobs.Add(new()
{
Data = Encoding.UTF8.GetBytes(content),
DateTime = DateTime.Now,
Type = 0,
});
using LockerContext context = await dbContextFactory.CreateDbContextAsync(cancellationToken);
EntityEntry<ItemEntry>? result = await context.AddAsync(itemEntry, cancellationToken);
await context.SaveChangesAsync(cancellationToken);
if (result is not null)
{
+23 -18
View File
@@ -7,36 +7,41 @@ namespace Bitvault;
public class CreateLockerHandler(ILockerFactory componentFactory,
IPublisher publisher) :
IHandler<CreateEventArgs<Locker>, bool>
IHandler<CreateEventArgs<Locker<(string, string)>>, bool>
{
public async Task<bool> Handle(CreateEventArgs<Locker> args,
public async Task<bool> Handle(CreateEventArgs<Locker<(string, string)>> args,
CancellationToken cancellationToken)
{
if (args.Value is Locker locker && locker.Name is { Length: > 0 } name &&
locker.Password is { Length: > 0 } password)
if (args.Value is Locker <(string, string)> locker)
{
if (componentFactory.Create(name) is IComponentHost host)
if (locker.Value is (string name, string password) &&
name is { Length: > 0 } &&
password is { Length: > 0 })
{
ISecurityKeyFactory keyVaultFactory = host.Services.GetRequiredService<ISecurityKeyFactory>();
IDecoratorService<SecurityKey> secureKeyStore = host.Services.GetRequiredService<IDecoratorService<SecurityKey>>();
ILockerStorageFactory lockerStorageFactory = host.Services.GetRequiredService<ILockerStorageFactory>();
if (keyVaultFactory.Create(Encoding.UTF8.GetBytes(password)) is SecurityKey key)
if (componentFactory.Create(name) is IComponentHost host)
{
secureKeyStore.Set(key);
ISecurityKeyFactory keyVaultFactory = host.Services.GetRequiredService<ISecurityKeyFactory>();
IDecoratorService<SecurityKey> secureKeyStore = host.Services.GetRequiredService<IDecoratorService<SecurityKey>>();
ILockerStorageFactory lockerStorageFactory = host.Services.GetRequiredService<ILockerStorageFactory>();
if (await lockerStorageFactory.Create(name, key))
if (keyVaultFactory.Create(Encoding.UTF8.GetBytes(password)) is SecurityKey key)
{
IWritableConfiguration<LockerConfiguration> configuration =
host.Services.GetRequiredService<IWritableConfiguration<LockerConfiguration>>();
secureKeyStore.Set(key);
configuration.Write(args => args.Key = $"{Convert.ToBase64String(key.Salt)}:{Convert.ToBase64String(key.EncryptedKey)}:{Convert.ToBase64String(key.DecryptedKey)}");
host.Start();
if (await lockerStorageFactory.Create(name, key))
{
IWritableConfiguration<LockerConfiguration> configuration =
host.Services.GetRequiredService<IWritableConfiguration<LockerConfiguration>>();
publisher.Publish(Activated.As(host), cancellationToken);
return true;
configuration.Write(args => args.Key = $"{Convert.ToBase64String(key.Salt)}:{Convert.ToBase64String(key.EncryptedKey)}:{Convert.ToBase64String(key.DecryptedKey)}");
host.Start();
publisher.Publish(Activated.As(host), cancellationToken);
return true;
}
}
}
}
}
+1 -1
View File
@@ -22,5 +22,5 @@ public partial class CreateLockerViewModel(IServiceProvider provider,
private string password;
public async Task<bool> Confirm() =>
await Mediator.Handle<CreateEventArgs<Locker>, bool>(Create.As(new Locker(Name, Password)));
await Mediator.Handle<CreateEventArgs<Locker<(string, string)>>, bool>(Create.As(new Locker<(string, string)>((Name, Password))));
}
+1 -1
View File
@@ -10,7 +10,7 @@ public class FavouriteItemHandler(IDecoratorService<Item<(Guid, string)>> decora
{
try
{
if (decoratorService.Value is Item<(Guid, string)> item)
if (decoratorService.Service is Item<(Guid, string)> item)
{
(Guid id, string name) = item.Value;
await mediator.Handle<UpdateEventArgs<(Guid, int)>, bool>(new UpdateEventArgs<(Guid, int)>((id, 1)));
+29 -3
View File
@@ -1,4 +1,4 @@
using System.ComponentModel;
using CommunityToolkit.Mvvm.ComponentModel;
using Toolkit.Foundation;
namespace Bitvault;
@@ -13,7 +13,33 @@ public partial class ItemEntryViewModel(IServiceProvider provider,
string? key = default,
object? value = default) :
Observable<string, object>(provider, factory, mediator, publisher, subscriber, disposer, key, value),
IItemEntryViewModel
IItemEntryViewModel,
INotificationHandler<UpdateEventArgs<Item>>,
INotificationHandler<ConfirmEventArgs<Item>>,
INotificationHandler<CancelEventArgs<Item>>
{
protected override void OnValueChanged() => configuration.Value = Value;
[ObservableProperty]
private ItemState state = ItemState.Read;
protected override void OnValueChanged() =>
configuration.Value = Value;
public Task Handle(UpdateEventArgs<Item> args) =>
Task.FromResult(State = ItemState.Write);
public Task Handle(CancelEventArgs<Item> args)
{
Revert();
State = ItemState.Read;
return Task.CompletedTask;
}
public Task Handle(ConfirmEventArgs<Item> args)
{
Commit();
State = ItemState.Read;
return Task.CompletedTask;
}
}
+1 -1
View File
@@ -118,7 +118,7 @@ public partial class ItemViewModel :
{
Publisher.Publish(Notify.As(Factory.Create<ItemCommandHeaderCollection>(new List<IDisposable>
{
Factory.Create<ConfirmItemActionViewModel>(State),
Factory.Create<ConfirmItemActionViewModel>(),
Factory.Create<DismissItemActionViewModel>(),
})));
}
+2 -20
View File
@@ -1,23 +1,5 @@
namespace Bitvault;
public record Locker
{
public Locker(string name, string password)
{
Name = name;
Password = password;
}
public record Locker<TValue>(TValue Value);
public Locker(string password)
{
Password = password;
}
public Locker()
{
}
public string Name { get; } = "";
public string? Password { get; } = "";
}
public record Locker;
+5 -3
View File
@@ -6,12 +6,14 @@ namespace Bitvault;
public class OpenLockerHandler(IConfigurationDescriptor<LockerConfiguration> descriptor,
ISecurityKeyFactory securityKeyFactory,
ILockerStorageFactory lockerStorageFactory) :
IHandler<ActivateEventArgs<Locker>, bool>
IHandler<ActivateEventArgs<Locker<string>>, bool>
{
public async Task<bool> Handle(ActivateEventArgs<Locker> args,
public async Task<bool> Handle(ActivateEventArgs<Locker<string>> args,
CancellationToken cancellationToken)
{
if (args.Value is Locker locker && descriptor.Name is { Length: > 0 } name && locker.Password is { Length: > 0 } password)
if (args.Value is Locker<string> locker &&
descriptor.Name is { Length: > 0 } name &&
locker.Value is { Length: > 0 } password)
{
LockerConfiguration configuration = descriptor.Value;
if (configuration.Key?.Split(':') is { Length: >= 2 } keyPart)
+1 -1
View File
@@ -24,7 +24,7 @@ public partial class OpenLockerViewModel(IServiceProvider provider,
{
if (Password is { Length: > 0 })
{
if (await Mediator.Handle<ActivateEventArgs<Locker>, bool>(Activate.As(new Locker(Password))))
if (await Mediator.Handle<ActivateEventArgs<Locker<string>>, bool>(Activate.As(new Locker<string>(Password))))
{
Publisher.Publish(Opened.As<Locker>());
}
-6
View File
@@ -1,6 +0,0 @@
namespace Bitvault;
public record QueryItemConfiguration
{
public int Id { get; set; }
}
-8
View File
@@ -1,8 +0,0 @@
namespace Bitvault;
public record QueryLockerConfiguration
{
public string? Filter { get; set; }
public string? Query { get; set; }
}
+22 -24
View File
@@ -6,52 +6,50 @@ using Toolkit.Foundation;
namespace Bitvault;
public class QueryLockerHandler(IDbContextFactory<LockerContext> dbContextFactory) :
IHandler<RequestEventArgs<QueryLockerConfiguration>, IReadOnlyCollection<(Guid Id, string? Name, string Category, bool Favourite, bool Archived)>>
IHandler<QueryEventArgs<Locker<(string, string)>>, IReadOnlyCollection<(Guid Id, string? Name, string Category, bool Favourite, bool Archived)>>
{
public async Task<IReadOnlyCollection<(Guid Id, string? Name, string Category, bool Favourite, bool Archived)>> Handle(RequestEventArgs<QueryLockerConfiguration> args,
CancellationToken cancellationToken)
public async Task<IReadOnlyCollection<(Guid Id, string? Name, string Category, bool Favourite, bool Archived)>>
Handle(QueryEventArgs<Locker<(string, string)>> args,CancellationToken cancellationToken)
{
List<(Guid Id, string? Name, string Category, bool Favourite, bool Archived)> items = [];
if (args.Value is QueryLockerConfiguration queryConfiguration)
if (args.Value is Locker<(string, string)> locker)
{
(string filter, string text) = locker.Value;
ExpressionStarter<ItemEntry> predicate =
PredicateBuilder.New<ItemEntry>(true);
if (queryConfiguration.Filter == "All")
if (filter == "All")
{
predicate = predicate.And(x => x.State != 2);
}
if (queryConfiguration.Filter == "Starred")
if (filter == "Starred")
{
predicate = predicate.And(x => x.State != 2 && x.State == 1);
}
if (queryConfiguration.Filter == "Archive")
if (filter == "Archive")
{
predicate = predicate.And(x => x.State == 2);
}
if (queryConfiguration.Query is { Length: > 0 } query)
if (text is { Length: > 0 })
{
predicate = predicate.And(x => EF.Functions.Like(x.Name, $"%{query}%"));
predicate = predicate.And(x => EF.Functions.Like(x.Name, $"%{text}%"));
}
var results = await Task.Run(async () =>
{
using LockerContext context = dbContextFactory.CreateDbContext();
return await context.Set<ItemEntry>()
.Where(predicate)
.Select(x => new
{
x.Id,
x.Name,
x.Category,
Favourite = x.State == 1,
Archived = x.State == 2
}).ToListAsync();
});
using LockerContext context = await dbContextFactory.CreateDbContextAsync(cancellationToken);
var results = await context.Set<ItemEntry>()
.Where(predicate)
.Select(x => new
{
x.Id,
x.Name,
x.Category,
Favourite = x.State == 1,
Archived = x.State == 2
}).ToListAsync(cancellationToken: cancellationToken);
foreach (var result in results.OrderBy(x => x.Name, StringComparer.OrdinalIgnoreCase))
{
+55
View File
@@ -0,0 +1,55 @@
using Bitvault.Data;
using Microsoft.EntityFrameworkCore;
using System.Text.Json;
using Toolkit.Foundation;
namespace Bitvault;
public class RequestItemHandler(IDbContextFactory<LockerContext> dbContextFactory) :
IHandler<RequestEventArgs<Item<Guid>>, (Guid, string, string?, string, ItemConfiguration?)>
{
public async Task<(Guid, string, string?, string, ItemConfiguration?)> Handle(RequestEventArgs<Item<Guid>> args,
CancellationToken cancellationToken)
{
if (args.Value is Item<Guid> item)
{
Guid id = item.Value;
using LockerContext context = await dbContextFactory.CreateDbContextAsync(cancellationToken);
var result = await context.Set<ItemEntry>()
.Where(x => x.Id == id)
.Select(x => new
{
x.Id,
x.Name,
x.Description,
x.Category,
Blob = x.Blobs
.Where(b => b.Type == 0)
.OrderByDescending(b => b.DateTime)
.FirstOrDefault()
})
.FirstOrDefaultAsync(cancellationToken);
if (result is not null)
{
ItemConfiguration? configuration = null;
if (result.Blob is BlobEntry blob && blob.Data is { Length: > 0 } data)
{
try
{
configuration = JsonSerializer.Deserialize<ItemConfiguration>(data);
}
catch
{
}
}
return (result.Id, result.Name, result.Description, result.Category, configuration);
}
}
return default;
}
}
@@ -1,19 +1,52 @@
using Toolkit.Foundation;
using System.Reflection;
using Toolkit.Foundation;
namespace Bitvault;
public class SynchronizeItemContentViewModelHandler(IMediator mediator,
public class SynchronizeItemContentViewModelHandler(IDecoratorService<Item<(Guid, string)>> itemDecorator,
IDecoratorService<ItemConfiguration> itemConfigurationDecorator,
IMediator mediator,
IServiceFactory serviceFactory,
IPublisher publisher) :
INotificationHandler<SynchronizeEventArgs<IItemEntryViewModel>>
INotificationHandler<SynchronizeEventArgs<ItemSectionViewModel>>
{
public Task Handle(SynchronizeEventArgs<IItemEntryViewModel> args)
public async Task Handle(SynchronizeEventArgs<ItemSectionViewModel> args)
{
//wModel>(false) is ItemHeaderViewModel viewModel)
//{
// publisher.Publish(Create.As<IItemEntryViewModel>(viewModel), nameof(ItemViewModel));
//}
if (itemDecorator.Service is Item<(Guid, string)> item)
{
if (item.Value is (Guid Id, _))
{
(_, _, _, _, ItemConfiguration? configuration) = await mediator.Handle<RequestEventArgs<Item<Guid>>, (Guid, string, string?, string,
ItemConfiguration?)>(Request.As(new Item<Guid>(Id)));
return Task.CompletedTask;
if (configuration is not null)
{
itemConfigurationDecorator.Set(configuration);
foreach (ItemSectionConfiguration configurationSection in configuration.Sections)
{
string id = $"{nameof(ItemSection)}:{Guid.NewGuid()}";
if (serviceFactory.Create<ItemSectionViewModel>(id)
is ItemSectionViewModel sectionViewModel)
{
publisher.Publish(Create.As(sectionViewModel), nameof(ItemContentViewModel));
foreach (IItemEntryConfiguration entryConfiguration in configurationSection.Entries)
{
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)
{
if (await mediator.Handle<object, IItemEntryViewModel?>(message,
entryConfiguration.GetType().Name) is IItemEntryViewModel entryViewModel)
{
publisher.Publish(Create.As(entryViewModel), id);
}
}
}
}
}
}
}
}
}
}
+5 -6
View File
@@ -17,12 +17,11 @@ public class SynchronizeItemViewModelHandler(IMediator mediator,
cache.Clear();
bool selected = true;
if (await mediator.Handle<RequestEventArgs<QueryLockerConfiguration>,
IReadOnlyCollection<(Guid Id, string Name, string Category, bool Favourite, bool Archived)>>(Request.As(new QueryLockerConfiguration
{
Filter = configuration.Filter,
Query = configuration.Query
})) is IReadOnlyCollection<(Guid Id, string Name, string Category, bool Favourite, bool Archived)> results)
IReadOnlyCollection<(Guid Id, string Name, string Category, bool Favourite, bool Archived)>? results =
await mediator.Handle<QueryEventArgs<Locker<(string?, string?)>>,
IReadOnlyCollection<(Guid Id, string Name, string Category, bool Favourite, bool Archived)>>(Query.As(new Locker<(string?, string?)>((configuration.Filter, configuration.Query))));
if (results is not null)
{
foreach ((Guid Id, string Name, string Category, bool Favourite, bool Archived) in results)
{
+8 -10
View File
@@ -1,5 +1,6 @@
using Bitvault.Data;
using Microsoft.EntityFrameworkCore;
using System.Threading;
using Toolkit.Foundation;
namespace Bitvault;
@@ -12,19 +13,16 @@ public class UnarchiveItemHandler(IDecoratorService<Item<(Guid, string)>> decora
{
try
{
if (decoratorService.Value is Item<(Guid, string)> item)
if (decoratorService.Service is Item<(Guid, string)> item)
{
(Guid id, string name) = item.Value;
await Task.Run(async () =>
{
using LockerContext context = await dbContextFactory.CreateDbContextAsync();
if (await context.FindAsync<ItemEntry>(id) is ItemEntry result)
{
result.State = 0;
await context.SaveChangesAsync();
}
});
using LockerContext context = await dbContextFactory.CreateDbContextAsync();
if (await context.FindAsync<ItemEntry>(id) is ItemEntry result)
{
result.State = 0;
await context.SaveChangesAsync();
}
}
}
catch
+1 -1
View File
@@ -9,7 +9,7 @@ public class UnfavouriteItemHandler(IDecoratorService<Item<(Guid, string)>> deco
{
try
{
if (decoratorService.Value is Item<(Guid, string)> item)
if (decoratorService.Service is Item<(Guid, string)> item)
{
(Guid id, string name) = item.Value;
await mediator.Handle<UpdateEventArgs<(Guid, int)>, bool>(new UpdateEventArgs<(Guid, int)>((id, 0)));
+20 -12
View File
@@ -1,31 +1,39 @@
using Bitvault.Data;
using Microsoft.EntityFrameworkCore;
using System.Text.Json;
using System.Text;
using Toolkit.Foundation;
namespace Bitvault;
public class UpdateItemHander(IDbContextFactory<LockerContext> dbContextFactory) :
IHandler<UpdateEventArgs<(Guid, string, ItemConfiguration)>, bool>
IHandler<UpdateEventArgs<Item<(Guid, string, ItemConfiguration)>>, bool>
{
public async Task<bool> Handle(UpdateEventArgs<(Guid, string, ItemConfiguration)> args,
public async Task<bool> Handle(UpdateEventArgs<Item<(Guid, string, ItemConfiguration)>> args,
CancellationToken cancellationToken)
{
if (args.Value is (Guid id, string name, ItemConfiguration configuration))
if (args.Value is Item<(Guid, string, ItemConfiguration)> item)
{
(Guid id, string name, ItemConfiguration configuration) = item.Value;
try
{
using LockerContext context = dbContextFactory.CreateDbContext();
ItemEntry? result = null;
using LockerContext context = await dbContextFactory.CreateDbContextAsync(cancellationToken);
ItemEntry? result = result = await context.Set<ItemEntry>().FindAsync([id], cancellationToken);
await Task.Run(async () =>
if (result is not null)
{
result = await context.Set<ItemEntry>().FindAsync(id);
if (result is not null)
string content = JsonSerializer.Serialize(configuration);
result.Blobs.Add(new()
{
result.Name = name;
await context.SaveChangesAsync(cancellationToken);
}
}, cancellationToken);
Data = Encoding.UTF8.GetBytes(content),
DateTime = DateTime.Now,
Type = 0,
});
result.Name = name;
await context.SaveChangesAsync(cancellationToken);
}
if (result is not null)
{
+1 -1
View File
@@ -14,7 +14,7 @@ public class UpdateItemStateHandler(IDbContextFactory<LockerContext> dbContextFa
{
await Task.Run(async () =>
{
using LockerContext context = await dbContextFactory.CreateDbContextAsync();
using LockerContext context = await dbContextFactory.CreateDbContextAsync(cancellationToken);
if (await context.FindAsync<ItemEntry>(id) is ItemEntry result)
{
result.State = state;