Bug fixes
This commit is contained in:
@@ -84,7 +84,8 @@ public partial class App : Application
|
|||||||
services.AddTransient<IKeyDeriver, KeyDeriver>();
|
services.AddTransient<IKeyDeriver, KeyDeriver>();
|
||||||
|
|
||||||
services.AddTransient<ISecurityKeyFactory, SecurityKeyFactory>();
|
services.AddTransient<ISecurityKeyFactory, SecurityKeyFactory>();
|
||||||
services.AddTransient<IWalletStoreFactory, WalletStoreFactory>();
|
services.AddTransient<IWalletDatabaseFactory, WalletDatabaseFactory>();
|
||||||
|
services.AddTransient<IWalletConnectionFactory, WalletConnectionFactory>();
|
||||||
|
|
||||||
services.AddTransient<IInitialization, WalletProfileImageInitializer>();
|
services.AddTransient<IInitialization, WalletProfileImageInitializer>();
|
||||||
|
|
||||||
@@ -94,22 +95,19 @@ public partial class App : Application
|
|||||||
provider.GetServices<IConfigurationDescriptor<ItemConfiguration>>().OrderBy(x => x.Name) ??
|
provider.GetServices<IConfigurationDescriptor<ItemConfiguration>>().OrderBy(x => x.Name) ??
|
||||||
Enumerable.Empty<IConfigurationDescriptor<ItemConfiguration>>();
|
Enumerable.Empty<IConfigurationDescriptor<ItemConfiguration>>();
|
||||||
|
|
||||||
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<IDecoratorService<ProfileImage<IImageDescriptor>>, DecoratorService<ProfileImage<IImageDescriptor>>>();
|
services.TryAddSingleton<IDecoratorService<ProfileImage<IImageDescriptor>>,
|
||||||
|
DecoratorService<ProfileImage<IImageDescriptor>>>();
|
||||||
|
|
||||||
services.TryAddSingleton<IDecoratorService<SecurityKey>, DecoratorService<SecurityKey>>();
|
services.TryAddSingleton<IDecoratorService<SecurityKey>, DecoratorService<SecurityKey>>();
|
||||||
services.TryAddSingleton<IDecoratorService<WalletConnection>, DecoratorService<WalletConnection>>();
|
services.TryAddSingleton<IDecoratorService<WalletConnection>, DecoratorService<WalletConnection>>();
|
||||||
|
|
||||||
services.AddDbContextFactory<WalletContext>((provider, args) =>
|
services.AddTransient<IConnection>(provider => provider.GetRequiredService<IDecoratorService<WalletConnection>>().Value!);
|
||||||
{
|
|
||||||
if (provider.GetRequiredService<IDecoratorService<WalletConnection>>()
|
services.AddDbContextFactory<WalletContext>();
|
||||||
is IDecoratorService<WalletConnection> connection)
|
|
||||||
{
|
|
||||||
args.UseSqlite($"{connection.Service}");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
services.AddHandler<CreateProfileImageHandler>();
|
services.AddHandler<CreateProfileImageHandler>();
|
||||||
|
|
||||||
@@ -125,6 +123,7 @@ public partial class App : Application
|
|||||||
services.AddHandler<CountCategoriesHandler>();
|
services.AddHandler<CountCategoriesHandler>();
|
||||||
|
|
||||||
services.AddHandler<OpenWalletHandler>();
|
services.AddHandler<OpenWalletHandler>();
|
||||||
|
services.AddHandler<CloseWalletHandler>();
|
||||||
|
|
||||||
services.AddTemplate<WalletNavigationViewModel, WalletNavigationView>();
|
services.AddTemplate<WalletNavigationViewModel, WalletNavigationView>();
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,11 @@
|
|||||||
x:DataType="vm:WalletNavigationViewModel"
|
x:DataType="vm:WalletNavigationViewModel"
|
||||||
ListBoxExtension.IsItemInvokedEnabled="True"
|
ListBoxExtension.IsItemInvokedEnabled="True"
|
||||||
ToolTip.Tip="{Binding Name}">
|
ToolTip.Tip="{Binding Name}">
|
||||||
|
<ListBoxItem.Resources>
|
||||||
|
<x:Double x:Key="IconSize">40</x:Double>
|
||||||
|
<CornerRadius x:Key="IconCornerRadius">40</CornerRadius>
|
||||||
|
|
||||||
|
</ListBoxItem.Resources>
|
||||||
<Interaction.Behaviors>
|
<Interaction.Behaviors>
|
||||||
<DataTriggerBehavior Binding="{Binding IsOpened}" Value="False">
|
<DataTriggerBehavior Binding="{Binding IsOpened}" Value="False">
|
||||||
<ConditionAction>
|
<ConditionAction>
|
||||||
@@ -35,8 +40,33 @@
|
|||||||
</ConditionAction>
|
</ConditionAction>
|
||||||
</AttachedEventTriggerBehaviour>
|
</AttachedEventTriggerBehaviour>
|
||||||
</Interaction.Behaviors>
|
</Interaction.Behaviors>
|
||||||
<PersonPicture
|
<Grid>
|
||||||
Height="40"
|
<PersonPicture
|
||||||
DisplayName="{Binding Name}"
|
Width="{StaticResource IconSize}"
|
||||||
ProfilePicture="{Binding ImageDescriptor.Image}" />
|
Height="{StaticResource IconSize}"
|
||||||
|
DisplayName="{Binding Name}"
|
||||||
|
ProfilePicture="{Binding ImageDescriptor.Image}" />
|
||||||
|
<Button
|
||||||
|
Width="{StaticResource IconSize}"
|
||||||
|
Height="{StaticResource IconSize}"
|
||||||
|
Background="Transparent"
|
||||||
|
CornerRadius="{StaticResource IconCornerRadius}"
|
||||||
|
IsVisible="{Binding IsActivated}">
|
||||||
|
<Button.Flyout>
|
||||||
|
<MenuFlyout>
|
||||||
|
<MenuItem
|
||||||
|
Width="216"
|
||||||
|
Command="{Binding LockCommand}"
|
||||||
|
Header="Lock">
|
||||||
|
<MenuItem.Icon>
|
||||||
|
<PathIcon
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Data="F1 M 10 14.799999 C 10.266666 14.799999 10.499999 14.699999 10.7 14.5 C 10.9 14.299999 11 14.066667 11 13.799999 C 11 13.533333 10.9 13.299999 10.7 13.099999 C 10.499999 12.9 10.266666 12.799999 10 12.799999 C 9.733333 12.799999 9.499999 12.9 9.3 13.099999 C 9.099999 13.299999 9 13.533333 9 13.799999 C 9 14.066667 9.099999 14.299999 9.3 14.5 C 9.499999 14.699999 9.733333 14.799999 10 14.799999 Z M 6 7.799999 L 7 7.799999 L 7 6.799999 C 7 5.973333 7.293333 5.266666 7.88 4.68 C 8.466666 4.093334 9.173333 3.799999 10 3.799999 C 10.826666 3.799999 11.533333 4.093334 12.12 4.68 C 12.706666 5.266666 13 5.973333 13 6.799999 L 13 7.799999 L 14 7.799999 C 14.826666 7.799999 15.533332 8.093332 16.119999 8.679999 C 16.706665 9.266666 17 9.973333 17 10.799999 L 17 16.799999 C 17 17.626667 16.706665 18.333332 16.119999 18.92 C 15.533332 19.506666 14.826666 19.799999 14 19.799999 L 6 19.799999 C 5.173333 19.799999 4.466666 19.506666 3.88 18.92 C 3.293333 18.333332 3 17.626667 3 16.799999 L 3 10.799999 C 3 9.973333 3.293333 9.266666 3.88 8.679999 C 4.466666 8.093332 5.173333 7.799999 6 7.799999 Z M 10 4.799999 C 9.44 4.799999 8.966666 4.993332 8.58 5.379999 C 8.193333 5.766666 8 6.240001 8 6.799999 L 8 7.799999 L 12 7.799999 L 12 6.799999 C 12 6.240001 11.806666 5.766666 11.42 5.379999 C 11.033333 4.993332 10.559999 4.799999 10 4.799999 Z M 16 10.799999 C 16 10.24 15.806666 9.766666 15.42 9.379999 C 15.033333 8.993333 14.559999 8.799999 14 8.799999 L 6 8.799999 C 5.44 8.799999 4.966666 8.993333 4.58 9.379999 C 4.193333 9.766666 4 10.24 4 10.799999 L 4 16.799999 C 4 17.360001 4.193333 17.833332 4.58 18.219999 C 4.966666 18.606667 5.44 18.799999 6 18.799999 L 14 18.799999 C 14.559999 18.799999 15.033333 18.606667 15.42 18.219999 C 15.806666 17.833332 16 17.360001 16 16.799999 Z " />
|
||||||
|
</MenuItem.Icon>
|
||||||
|
</MenuItem>
|
||||||
|
</MenuFlyout>
|
||||||
|
</Button.Flyout>
|
||||||
|
</Button>
|
||||||
|
</Grid>
|
||||||
</ListBoxItem>
|
</ListBoxItem>
|
||||||
@@ -2,8 +2,9 @@
|
|||||||
|
|
||||||
namespace Wallet.Data;
|
namespace Wallet.Data;
|
||||||
|
|
||||||
public class WalletContext(DbContextOptions<WalletContext> options) :
|
public interface IConnection;
|
||||||
DbContext(options)
|
|
||||||
|
public class WalletContext(IConnection connection) : DbContext
|
||||||
{
|
{
|
||||||
public DbSet<BlobEntry> Blobs { get; set; }
|
public DbSet<BlobEntry> Blobs { get; set; }
|
||||||
|
|
||||||
@@ -11,6 +12,11 @@ public class WalletContext(DbContextOptions<WalletContext> options) :
|
|||||||
|
|
||||||
public DbSet<TagEntry> Tags { get; set; }
|
public DbSet<TagEntry> Tags { get; set; }
|
||||||
|
|
||||||
|
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||||
|
{
|
||||||
|
optionsBuilder.UseSqlite($"{connection}");
|
||||||
|
}
|
||||||
|
|
||||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
{
|
{
|
||||||
modelBuilder.Entity<ItemEntry>()
|
modelBuilder.Entity<ItemEntry>()
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ public class ArchiveItemHandler(IDecoratorService<Item<(Guid, string)>> decorato
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (decoratorService.Service is Item<(Guid, string)> item)
|
if (decoratorService.Value is Item<(Guid, string)> item)
|
||||||
{
|
{
|
||||||
if (cache.Contains(item))
|
if (cache.Contains(item))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Toolkit.Foundation;
|
||||||
|
using Wallet.Data;
|
||||||
|
using static Microsoft.EntityFrameworkCore.DbLoggerCategory.Database;
|
||||||
|
|
||||||
|
namespace Wallet;
|
||||||
|
|
||||||
|
public class CloseWalletHandler(IDecoratorService<WalletConnection> walletConnectionDecorator,
|
||||||
|
IDbContextFactory<WalletContext> dbContextFactory) :
|
||||||
|
IHandler<CloseEventArgs<Wallet>, bool>
|
||||||
|
{
|
||||||
|
public async Task<bool> Handle(CloseEventArgs<Wallet> args,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
walletConnectionDecorator.Set(null);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,8 +10,8 @@ public class ConfirmCreateItemHandler(IMediator mediator,
|
|||||||
{
|
{
|
||||||
public async Task Handle(ConfirmEventArgs<Item> args)
|
public async Task Handle(ConfirmEventArgs<Item> args)
|
||||||
{
|
{
|
||||||
if (itemHeaderConfiguration.Service is ItemHeaderConfiguration headerConfiguration &&
|
if (itemHeaderConfiguration.Value is ItemHeaderConfiguration headerConfiguration &&
|
||||||
itemConfigurationDecorator.Service is ItemConfiguration itemConfiguration)
|
itemConfigurationDecorator.Value is ItemConfiguration itemConfiguration)
|
||||||
{
|
{
|
||||||
if (headerConfiguration.Name is { Length: > 0 } name &&
|
if (headerConfiguration.Name is { Length: > 0 } name &&
|
||||||
headerConfiguration.Category is { Length: > 0 } category)
|
headerConfiguration.Category is { Length: > 0 } category)
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ public class ConfirmDeleteItemHandler(IDecoratorService<Item<(Guid, string)>> de
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (decoratorService.Service 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;
|
||||||
|
|
||||||
|
|||||||
@@ -11,9 +11,9 @@ public class ConfirmUpdateItemHandler(IDecoratorService<Item<(Guid, string)>> it
|
|||||||
{
|
{
|
||||||
public async Task Handle(ConfirmEventArgs<Item> args)
|
public async Task Handle(ConfirmEventArgs<Item> args)
|
||||||
{
|
{
|
||||||
if (itemDecorator?.Service is Item<(Guid, string)> item &&
|
if (itemDecorator?.Value is Item<(Guid, string)> item &&
|
||||||
itemHeaderConfiguration.Service is ItemHeaderConfiguration headerConfiguration &&
|
itemHeaderConfiguration.Value is ItemHeaderConfiguration headerConfiguration &&
|
||||||
itemConfigurationDecorator.Service is ItemConfiguration itemConfiguration)
|
itemConfigurationDecorator.Value is ItemConfiguration itemConfiguration)
|
||||||
{
|
{
|
||||||
if (headerConfiguration?.Name is { Length: > 0 } name &&
|
if (headerConfiguration?.Name is { Length: > 0 } name &&
|
||||||
headerConfiguration.Category is { Length: > 0 } category)
|
headerConfiguration.Category is { Length: > 0 } category)
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ public class CreateWalletHandler(IWalletHostFactory componentFactory,
|
|||||||
{
|
{
|
||||||
if (componentFactory.Create(name) is IComponentHost host)
|
if (componentFactory.Create(name) is IComponentHost host)
|
||||||
{
|
{
|
||||||
IWalletFactory factory = host.Services.GetRequiredService<IWalletFactory>();
|
IWalletFactory walletFactory = host.Services.GetRequiredService<IWalletFactory>();
|
||||||
if (await factory.Create(name, password, imageDescriptor))
|
if (await walletFactory.Create(name, password, imageDescriptor))
|
||||||
{
|
{
|
||||||
host.Start();
|
host.Start();
|
||||||
publisher.Publish(Activated.As(new Wallet<IComponentHost>(host)));
|
publisher.Publish(Activated.As(new Wallet<IComponentHost>(host)));
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ public class FavouriteItemHandler(IDecoratorService<Item<(Guid, string)>> decora
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (decoratorService.Service 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)));
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
namespace Wallet
|
||||||
|
{
|
||||||
|
public interface IWalletConnectionFactory
|
||||||
|
{
|
||||||
|
Task<WalletConnection?> Create(string name, string key);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
namespace Wallet;
|
||||||
|
|
||||||
|
public interface IWalletDatabaseFactory
|
||||||
|
{
|
||||||
|
Task<bool> Create(string name, string key);
|
||||||
|
}
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
namespace Wallet;
|
|
||||||
|
|
||||||
public interface IWalletStoreFactory
|
|
||||||
{
|
|
||||||
Task<bool> Create(string name, SecurityKey key);
|
|
||||||
}
|
|
||||||
@@ -12,7 +12,7 @@ public class ItemContentViewModelActivationHandler(IDecoratorService<Item<(Guid,
|
|||||||
{
|
{
|
||||||
public async Task Handle(ActivationEventArgs<ItemSectionViewModel> args)
|
public async Task Handle(ActivationEventArgs<ItemSectionViewModel> args)
|
||||||
{
|
{
|
||||||
if (itemDecorator.Service is Item<(Guid, string)> item)
|
if (itemDecorator.Value is Item<(Guid, string)> item)
|
||||||
{
|
{
|
||||||
if (item.Value is (Guid Id, _))
|
if (item.Value is (Guid Id, _))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ public class MainViewModelActivationHandler(IPublisher publisher,
|
|||||||
{
|
{
|
||||||
IDecoratorService<ProfileImage<IImageDescriptor>> profileImageDecorator =
|
IDecoratorService<ProfileImage<IImageDescriptor>> profileImageDecorator =
|
||||||
Wallet.Services.GetRequiredService<IDecoratorService<ProfileImage<IImageDescriptor>>>();
|
Wallet.Services.GetRequiredService<IDecoratorService<ProfileImage<IImageDescriptor>>>();
|
||||||
ProfileImage<IImageDescriptor>? profileImage = profileImageDecorator.Service;
|
ProfileImage<IImageDescriptor>? profileImage = profileImageDecorator.Value;
|
||||||
|
|
||||||
if (factory.Create<WalletNavigationViewModel>(args => args.Initialize(), configuration.Name, profileImage?.Value ?? null, selected)
|
if (factory.Create<WalletNavigationViewModel>(args => args.Initialize(), configuration.Name, profileImage?.Value ?? null, selected)
|
||||||
is WalletNavigationViewModel viewModel)
|
is WalletNavigationViewModel viewModel)
|
||||||
|
|||||||
@@ -5,10 +5,11 @@ namespace Wallet;
|
|||||||
|
|
||||||
public class OpenWalletHandler(IConfigurationDescriptor<WalletConfiguration> descriptor,
|
public class OpenWalletHandler(IConfigurationDescriptor<WalletConfiguration> descriptor,
|
||||||
ISecurityKeyFactory securityKeyFactory,
|
ISecurityKeyFactory securityKeyFactory,
|
||||||
IWalletStoreFactory WalletStorageFactory) :
|
IWalletConnectionFactory walletConnectionFactory,
|
||||||
IHandler<ActivateEventArgs<Wallet<string>>, bool>
|
IDecoratorService<WalletConnection> walletConnectionDecorator) :
|
||||||
|
IHandler<OpenEventArgs<Wallet<string>>, bool>
|
||||||
{
|
{
|
||||||
public async Task<bool> Handle(ActivateEventArgs<Wallet<string>> args,
|
public async Task<bool> Handle(OpenEventArgs<Wallet<string>> args,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
if (args.Sender is Wallet<string> Wallet &&
|
if (args.Sender is Wallet<string> Wallet &&
|
||||||
@@ -21,10 +22,13 @@ public class OpenWalletHandler(IConfigurationDescriptor<WalletConfiguration> des
|
|||||||
byte[]? salt = Convert.FromBase64String(keyPart[0]);
|
byte[]? salt = Convert.FromBase64String(keyPart[0]);
|
||||||
byte[]? encryptedKey = Convert.FromBase64String(keyPart[1]);
|
byte[]? encryptedKey = Convert.FromBase64String(keyPart[1]);
|
||||||
|
|
||||||
if (securityKeyFactory.Create(Encoding.UTF8.GetBytes(password), encryptedKey, salt) is SecurityKey key)
|
if (securityKeyFactory.Create(Encoding.UTF8.GetBytes(password),
|
||||||
|
encryptedKey, salt) is SecurityKey securityKey)
|
||||||
{
|
{
|
||||||
if (await WalletStorageFactory.Create(name, key))
|
if (await walletConnectionFactory.Create(name, Convert.ToBase64String(securityKey.DecryptedKey))
|
||||||
|
is WalletConnection connection)
|
||||||
{
|
{
|
||||||
|
walletConnectionDecorator.Set(connection);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,23 +43,11 @@ public partial class OpenWalletViewModel :
|
|||||||
using (await new ActivityLock(this))
|
using (await new ActivityLock(this))
|
||||||
{
|
{
|
||||||
if (await Validation.Validate(() => Password, [new ValidationRule(async () =>
|
if (await Validation.Validate(() => Password, [new ValidationRule(async () =>
|
||||||
await Mediator.Handle<ActivateEventArgs<Wallet<string>>, bool>(Activate.As(new Wallet<string>(Password))),
|
await Mediator.Handle<OpenEventArgs<Wallet<string>>, bool>(Open.As(new Wallet<string>(Password))),
|
||||||
"The password is incorrect, please try again.")]))
|
"The password is incorrect, please try again.")]))
|
||||||
{
|
{
|
||||||
Publisher.Publish(Opened.As<Wallet>());
|
Publisher.Publish(Opened.As<Wallet>());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task OnActivated()
|
|
||||||
{
|
|
||||||
Publisher.Publish(Activated.As<Wallet>());
|
|
||||||
await base.OnActivated();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override async Task OnDeactivated()
|
|
||||||
{
|
|
||||||
Publisher.Publish(Deactivated.As<Wallet>());
|
|
||||||
await base.OnDeactivated();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -12,7 +12,7 @@ public class UnarchiveItemHandler(IDecoratorService<Item<(Guid, string)>> decora
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (decoratorService.Service 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;
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ public class UnfavouriteItemHandler(IDecoratorService<Item<(Guid, string)>> deco
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (decoratorService.Service 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)));
|
||||||
|
|||||||
@@ -8,6 +8,16 @@
|
|||||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2" />
|
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2" />
|
||||||
<PackageReference Include="LinqKit.Microsoft.EntityFrameworkCore" Version="8.1.5" />
|
<PackageReference Include="LinqKit.Microsoft.EntityFrameworkCore" Version="8.1.5" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.0-preview.5.24306.3" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.0-preview.5.24306.3" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.0-preview.5.24306.3">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="9.0.0-preview.5.24306.3" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.0-preview.5.24306.3">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlcipher" Version="2.1.8" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Toolkit\Toolkit.Avalonia\Toolkit.Avalonia.csproj" />
|
<ProjectReference Include="..\Toolkit\Toolkit.Avalonia\Toolkit.Avalonia.csproj" />
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ public class WalletActivatedHandler(IWalletHostCollection Wallets,
|
|||||||
IDecoratorService<ProfileImage<IImageDescriptor>> profileImageDecorator =
|
IDecoratorService<ProfileImage<IImageDescriptor>> profileImageDecorator =
|
||||||
host.Services.GetRequiredService<IDecoratorService<ProfileImage<IImageDescriptor>>>();
|
host.Services.GetRequiredService<IDecoratorService<ProfileImage<IImageDescriptor>>>();
|
||||||
|
|
||||||
ProfileImage<IImageDescriptor>? profileImage = profileImageDecorator.Service;
|
ProfileImage<IImageDescriptor>? profileImage = profileImageDecorator.Value;
|
||||||
if (serviceFactory.Create<WalletNavigationViewModel>(args => args.Initialize(),
|
if (serviceFactory.Create<WalletNavigationViewModel>(args => args.Initialize(),
|
||||||
descriptor.Name, profileImage?.Value, false)
|
descriptor.Name, profileImage?.Value, false)
|
||||||
is WalletNavigationViewModel viewModel)
|
is WalletNavigationViewModel viewModel)
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Xml.Linq;
|
||||||
using Toolkit.Foundation;
|
using Toolkit.Foundation;
|
||||||
|
|
||||||
namespace Wallet;
|
namespace Wallet;
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
namespace Wallet;
|
using Wallet.Data;
|
||||||
|
|
||||||
public record WalletConnection(string connection)
|
namespace Wallet;
|
||||||
|
|
||||||
|
public record WalletConnection(string Value) :
|
||||||
|
IConnection
|
||||||
{
|
{
|
||||||
private readonly string connection = connection;
|
public override string ToString() => Value;
|
||||||
|
|
||||||
public override string ToString() => connection;
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
using Wallet.Data;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
|
||||||
|
namespace Wallet;
|
||||||
|
|
||||||
|
public class WalletConnectionFactory(IHostEnvironment environment) :
|
||||||
|
IWalletConnectionFactory
|
||||||
|
{
|
||||||
|
public async Task<WalletConnection?> Create(string name, string key)
|
||||||
|
{
|
||||||
|
string databaseFile = $"{Path.Combine(environment.ContentRootPath, name)}.wallet";
|
||||||
|
if (File.Exists(databaseFile))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await Task.Run(async () =>
|
||||||
|
{
|
||||||
|
WalletConnection connection = new($"Data Source={databaseFile};Mode=ReadWriteCreate;Pooling=true;Password={key}");
|
||||||
|
|
||||||
|
using WalletContext context = new(connection);
|
||||||
|
await context.Database.OpenConnectionAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
|
return connection;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
using Wallet.Data;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
|
||||||
|
namespace Wallet;
|
||||||
|
|
||||||
|
public class WalletDatabaseFactory(IHostEnvironment environment) :
|
||||||
|
IWalletDatabaseFactory
|
||||||
|
{
|
||||||
|
public async Task<bool> Create(string name, string key)
|
||||||
|
{
|
||||||
|
string databaseFile = $"{Path.Combine(environment.ContentRootPath, name)}.wallet";
|
||||||
|
try
|
||||||
|
{
|
||||||
|
WalletConnection connection = new($"Data Source={databaseFile};Mode=ReadWriteCreate;Pooling=true;Password={key}");
|
||||||
|
|
||||||
|
await Task.Run(async () =>
|
||||||
|
{
|
||||||
|
using WalletContext context = new(connection);
|
||||||
|
await context.Database.EnsureCreatedAsync();
|
||||||
|
|
||||||
|
context.Database.GetDbConnection().Close();
|
||||||
|
context.Database.SetConnectionString(null);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,8 +5,7 @@ using Toolkit.Foundation;
|
|||||||
namespace Wallet;
|
namespace Wallet;
|
||||||
|
|
||||||
public class WalletFactory(ISecurityKeyFactory securityKeyFactory,
|
public class WalletFactory(ISecurityKeyFactory securityKeyFactory,
|
||||||
IDecoratorService<SecurityKey> secureKeyStore,
|
IWalletDatabaseFactory walletDatabaseFactory,
|
||||||
IWalletStoreFactory walletStoreFactory,
|
|
||||||
IWritableConfiguration<WalletConfiguration> configuration,
|
IWritableConfiguration<WalletConfiguration> configuration,
|
||||||
IHostEnvironment environment,
|
IHostEnvironment environment,
|
||||||
IImageWriter imageWriter) :
|
IImageWriter imageWriter) :
|
||||||
@@ -18,9 +17,7 @@ public class WalletFactory(ISecurityKeyFactory securityKeyFactory,
|
|||||||
{
|
{
|
||||||
if (securityKeyFactory.Create(Encoding.UTF8.GetBytes(password)) is SecurityKey key)
|
if (securityKeyFactory.Create(Encoding.UTF8.GetBytes(password)) is SecurityKey key)
|
||||||
{
|
{
|
||||||
secureKeyStore.Set(key);
|
if (await walletDatabaseFactory.Create(name, Convert.ToBase64String(key.DecryptedKey)))
|
||||||
|
|
||||||
if (await walletStoreFactory.Create(name, key))
|
|
||||||
{
|
{
|
||||||
configuration.Write(args => args.Key = $"{Convert.ToBase64String(key.Salt)}:" +
|
configuration.Write(args => args.Key = $"{Convert.ToBase64String(key.Salt)}:" +
|
||||||
$"{Convert.ToBase64String(key.EncryptedKey)}:{Convert.ToBase64String(key.DecryptedKey)}");
|
$"{Convert.ToBase64String(key.EncryptedKey)}:{Convert.ToBase64String(key.DecryptedKey)}");
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using Toolkit.Foundation;
|
using Toolkit.Foundation;
|
||||||
|
|
||||||
namespace Wallet;
|
namespace Wallet;
|
||||||
@@ -77,6 +78,15 @@ public partial class WalletNavigationViewModel :
|
|||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private async Task Lock()
|
||||||
|
{
|
||||||
|
if (await Mediator.Handle<CloseEventArgs<Wallet>, bool>(Close.As<Wallet>()))
|
||||||
|
{
|
||||||
|
IsOpened = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public Task Handle(ActivatedEventArgs<Wallet> args)
|
public Task Handle(ActivatedEventArgs<Wallet> args)
|
||||||
{
|
{
|
||||||
IsActivated = true;
|
IsActivated = true;
|
||||||
|
|||||||
@@ -1,40 +0,0 @@
|
|||||||
using Wallet.Data;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using Microsoft.Extensions.Hosting;
|
|
||||||
using Toolkit.Foundation;
|
|
||||||
|
|
||||||
namespace Wallet;
|
|
||||||
|
|
||||||
public class WalletStoreFactory(IDecoratorService<WalletConnection> connection,
|
|
||||||
IHostEnvironment environment,
|
|
||||||
IServiceProvider provider) :
|
|
||||||
IWalletStoreFactory
|
|
||||||
{
|
|
||||||
public async Task<bool> Create(string name,
|
|
||||||
SecurityKey key)
|
|
||||||
{
|
|
||||||
connection.Set(new WalletConnection($"Data Source={Path.Combine(environment.ContentRootPath, name)}" +
|
|
||||||
$".wallet;Mode=ReadWriteCreate;Pooling=true;Password={Convert.ToBase64String(key.DecryptedKey)}"));
|
|
||||||
|
|
||||||
IDbContextFactory<WalletContext> dbContextFactory = provider.GetRequiredService<IDbContextFactory<WalletContext>>();
|
|
||||||
using WalletContext context = await dbContextFactory.CreateDbContextAsync();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await Task.Run(async () =>
|
|
||||||
{
|
|
||||||
await context.Database.EnsureCreatedAsync().ConfigureAwait(false);
|
|
||||||
await context.Database.CloseConnectionAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
context.Database.SetConnectionString(null);
|
|
||||||
}).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user