diff --git a/Wallet.Avalonia/ItemHeaderView.axaml b/Wallet.Avalonia/ItemHeaderView.axaml index 09490fd..3c3ec82 100644 --- a/Wallet.Avalonia/ItemHeaderView.axaml +++ b/Wallet.Avalonia/ItemHeaderView.axaml @@ -4,6 +4,7 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:ui="using:FluentAvalonia.UI.Controls" xmlns:vm="using:Wallet" + Margin="0,0,0,-18" x:DataType="vm:ItemHeaderViewModel"> 144 @@ -72,63 +73,70 @@ Text="" /> - - - - + + + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + diff --git a/Wallet.Data/BlobEntry.cs b/Wallet.Data/BlobEntity.cs similarity index 92% rename from Wallet.Data/BlobEntry.cs rename to Wallet.Data/BlobEntity.cs index ab5503b..1e49542 100644 --- a/Wallet.Data/BlobEntry.cs +++ b/Wallet.Data/BlobEntity.cs @@ -4,7 +4,7 @@ using System.ComponentModel.DataAnnotations.Schema; namespace Wallet.Data; [Table("Blobs")] -public record BlobEntry +public record BlobEntity { public byte[]? Data { get; set; } diff --git a/Wallet.Data/ItemEntry.cs b/Wallet.Data/ItemEntity.cs similarity index 64% rename from Wallet.Data/ItemEntry.cs rename to Wallet.Data/ItemEntity.cs index 38eeec9..1014d03 100644 --- a/Wallet.Data/ItemEntry.cs +++ b/Wallet.Data/ItemEntity.cs @@ -4,7 +4,7 @@ using System.ComponentModel.DataAnnotations.Schema; namespace Wallet.Data; [Table("Items")] -public record ItemEntry +public record ItemEntity { [Key] public Guid Id { get; set; } @@ -17,11 +17,11 @@ public record ItemEntry public Guid? ImageId { get; set; } - public BlobEntry? Image { get; set; } + public BlobEntity? Image { get; set; } public required string Category { get; set; } - public ICollection Tags { get; set; } = new List(); + public ICollection Tags { get; set; } = new List(); - public ICollection Blobs { get; set; } = new List(); + public ICollection Blobs { get; set; } = new List(); } \ No newline at end of file diff --git a/Wallet.Data/LockerContext.cs b/Wallet.Data/LockerContext.cs index 32611af..0d9a7d1 100644 --- a/Wallet.Data/LockerContext.cs +++ b/Wallet.Data/LockerContext.cs @@ -6,11 +6,11 @@ public interface IConnection; public class WalletContext(IConnection connection) : DbContext { - public DbSet Blobs { get; set; } + public DbSet Blobs { get; set; } - public DbSet Items { get; set; } + public DbSet Items { get; set; } - public DbSet Tags { get; set; } + public DbSet Tags { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { @@ -19,27 +19,27 @@ public class WalletContext(IConnection connection) : DbContext protected override void OnModelCreating(ModelBuilder modelBuilder) { - modelBuilder.Entity() + modelBuilder.Entity() .HasKey(x => x.Id); - modelBuilder.Entity() + modelBuilder.Entity() .HasMany(x => x.Tags) .WithOne() .OnDelete(DeleteBehavior.Cascade); - modelBuilder.Entity() + modelBuilder.Entity() .HasMany(x => x.Blobs) .WithOne() .OnDelete(DeleteBehavior.Cascade); - modelBuilder.Entity(). + modelBuilder.Entity(). HasOne(i => i.Image) .WithOne() - .HasForeignKey(i => i.ImageId) + .HasForeignKey(i => i.ImageId) .IsRequired(false) .OnDelete(DeleteBehavior.Restrict); - modelBuilder.Entity() + modelBuilder.Entity() .HasKey(x => x.Id); } } \ No newline at end of file diff --git a/Wallet.Data/TagEntry.cs b/Wallet.Data/TagEntity.cs similarity index 90% rename from Wallet.Data/TagEntry.cs rename to Wallet.Data/TagEntity.cs index 7dfb202..07f4385 100644 --- a/Wallet.Data/TagEntry.cs +++ b/Wallet.Data/TagEntity.cs @@ -4,7 +4,7 @@ using System.ComponentModel.DataAnnotations.Schema; namespace Wallet.Data; [Table("Tags")] -public class TagEntry +public class TagEntity { [Key] public Guid Id { get; set; } diff --git a/Wallet/CreateItemHandler.cs b/Wallet/CreateItemHandler.cs index d3c46c0..75bc4c1 100644 --- a/Wallet/CreateItemHandler.cs +++ b/Wallet/CreateItemHandler.cs @@ -28,12 +28,12 @@ public class CreateItemHandler(IImageWriter imageWriter, thumbData = memoryStream.ToArray(); } - ItemEntry itemEntry = new() + ItemEntity itemEntry = new() { Id = id, Name = name, Category = category, - Image = thumbData != null ? new BlobEntry + Image = thumbData != null ? new BlobEntity { Id = Guid.NewGuid(), Data = thumbData, @@ -42,7 +42,7 @@ public class CreateItemHandler(IImageWriter imageWriter, } : null, Blobs = { - new BlobEntry + new BlobEntity { Id = Guid.NewGuid(), Data = Encoding.UTF8.GetBytes(content), @@ -53,7 +53,7 @@ public class CreateItemHandler(IImageWriter imageWriter, }; using WalletContext context = await dbContextFactory.CreateDbContextAsync(cancellationToken); - EntityEntry? result = await context.AddAsync(itemEntry, cancellationToken); + EntityEntry? result = await context.AddAsync(itemEntry, cancellationToken); await context.SaveChangesAsync(cancellationToken); diff --git a/Wallet/DeleteItemHandler.cs b/Wallet/DeleteItemHandler.cs index 3bdc87e..99bad4d 100644 --- a/Wallet/DeleteItemHandler.cs +++ b/Wallet/DeleteItemHandler.cs @@ -15,7 +15,7 @@ public class DeleteItemHandler(IDbContextFactory dbContextFactory Guid id = item.Value; using WalletContext context = await dbContextFactory.CreateDbContextAsync(cancellationToken); - if (await context.FindAsync(id) is ItemEntry result) + if (await context.FindAsync(id) is ItemEntity result) { context.Items.Remove(result); await context.SaveChangesAsync(cancellationToken); diff --git a/Wallet/ItemEntry.cs b/Wallet/ItemEntry.cs new file mode 100644 index 0000000..eae9dde --- /dev/null +++ b/Wallet/ItemEntry.cs @@ -0,0 +1,3 @@ +namespace Wallet; + +public record ItemEntry; diff --git a/Wallet/ItemEntryViewModel.cs b/Wallet/ItemEntryViewModel.cs index 4a70695..d7fdf8e 100644 --- a/Wallet/ItemEntryViewModel.cs +++ b/Wallet/ItemEntryViewModel.cs @@ -19,9 +19,9 @@ public partial class ItemEntryViewModel(IServiceProvider provider, double width) : Observable(provider, factory, mediator, publisher, subscriber, disposer, key, value), IItemEntryViewModel, - INotificationHandler>, - INotificationHandler>, - INotificationHandler> + INotificationHandler>, + INotificationHandler>, + INotificationHandler> where TValue : notnull { [ObservableProperty] @@ -36,10 +36,10 @@ public partial class ItemEntryViewModel(IServiceProvider provider, [ObservableProperty] private double width = width; - public Task Handle(UpdateEventArgs args) => + public Task Handle(UpdateEventArgs args) => Task.FromResult(State = ItemState.Write); - public Task Handle(CancelEventArgs args) + public Task Handle(CancelEventArgs args) { Revert(); @@ -47,7 +47,7 @@ public partial class ItemEntryViewModel(IServiceProvider provider, return Task.CompletedTask; } - public Task Handle(ConfirmEventArgs args) + public Task Handle(ConfirmEventArgs args) { Commit(); diff --git a/Wallet/ItemHandler.cs b/Wallet/ItemHandler.cs index 05408bf..c7b3a62 100644 --- a/Wallet/ItemHandler.cs +++ b/Wallet/ItemHandler.cs @@ -16,7 +16,7 @@ public class ItemHandler(IDbContextFactory dbContextFactory) : Guid id = item.Value; using WalletContext context = await dbContextFactory.CreateDbContextAsync(cancellationToken); - var result = await context.Set() + var result = await context.Set() .Where(x => x.Id == id) .Select(x => new { @@ -35,7 +35,7 @@ public class ItemHandler(IDbContextFactory dbContextFactory) : if (result is not null) { ItemConfiguration? configuration = null; - if (result.Blob is BlobEntry blob && blob.Data is { Length: > 0 } data) + if (result.Blob is BlobEntity blob && blob.Data is { Length: > 0 } data) { try { diff --git a/Wallet/ItemHeaderViewModel.cs b/Wallet/ItemHeaderViewModel.cs index 3858db7..7ca28d4 100644 --- a/Wallet/ItemHeaderViewModel.cs +++ b/Wallet/ItemHeaderViewModel.cs @@ -1,14 +1,17 @@ using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; +using System.Xml.Linq; using Toolkit.Foundation; +using Wallet.Data; namespace Wallet; public partial class ItemHeaderViewModel : Observable, - INotificationHandler>, - INotificationHandler>, - INotificationHandler>, + IHandler, bool>, + INotificationHandler>, + INotificationHandler>, + INotificationHandler>, INotificationHandler>>, INotificationHandler>>, IItemViewModel @@ -30,11 +33,14 @@ public partial class ItemHeaderViewModel : IPublisher publisher, ISubscriber subscriber, IDisposer disposer, + IValidation validation, ItemHeaderConfiguration configuration, ItemState state, string value, IImageDescriptor? imageDescriptor = null) : base(provider, factory, mediator, publisher, subscriber, disposer, value) { + Validation = validation; + this.configuration = configuration; State = state; @@ -43,12 +49,18 @@ public partial class ItemHeaderViewModel : Track(nameof(Value), () => Value, x => Value = x); Track(nameof(ImageDescriptor), () => ImageDescriptor, x => ImageDescriptor = x); + + Validation.Add(() => Value, [new ValidationRule(() => Value is { Length: > 0 }, "Name is required")], + ValidationTrigger.Deferred); } - public Task Handle(UpdateEventArgs args) => + [ObservableProperty] + private IValidation validation; + + public Task Handle(UpdateEventArgs args) => Task.FromResult(State = ItemState.Write); - public Task Handle(CancelEventArgs args) + public Task Handle(CancelEventArgs args) { Revert(); @@ -56,7 +68,7 @@ public partial class ItemHeaderViewModel : return Task.CompletedTask; } - public Task Handle(ConfirmEventArgs args) + public Task Handle(ConfirmEventArgs args) { Commit(); @@ -85,6 +97,9 @@ public partial class ItemHeaderViewModel : return Task.CompletedTask; } + public async Task Handle(ValidateEventArgs args, + CancellationToken cancellationToken) => await Validation.Validate(); + protected override void OnValueChanged() { if (configuration is not null) diff --git a/Wallet/ItemImageHandler.cs b/Wallet/ItemImageHandler.cs index 83074e4..e839dce 100644 --- a/Wallet/ItemImageHandler.cs +++ b/Wallet/ItemImageHandler.cs @@ -16,7 +16,7 @@ public class ItemImageHandler(IDbContextFactory dbContextFactory, Guid id = item.Value; using WalletContext context = await dbContextFactory.CreateDbContextAsync(cancellationToken); - var result = await context.Set() + var result = await context.Set() .Where(x => x.Id == id) .Select(x => new { @@ -25,7 +25,7 @@ public class ItemImageHandler(IDbContextFactory dbContextFactory, .FirstOrDefaultAsync(cancellationToken); if (result is not null && - result.Image is BlobEntry image && + result.Image is BlobEntity image && image.Data is { Length: > 0 } data) { MemoryStream stream = new(data); diff --git a/Wallet/ItemViewModel.cs b/Wallet/ItemViewModel.cs index 63e8fc1..6663b3a 100644 --- a/Wallet/ItemViewModel.cs +++ b/Wallet/ItemViewModel.cs @@ -1,5 +1,6 @@ using CommunityToolkit.Mvvm.ComponentModel; using Toolkit.Foundation; +using Wallet.Data; namespace Wallet; @@ -77,6 +78,7 @@ public partial class ItemViewModel : public Task Handle(UpdateEventArgs args) { + Publisher.Publish(Update.As()); Publisher.Publish(Notify.As(Factory.Create(new List { Factory.Create(), @@ -89,6 +91,7 @@ public partial class ItemViewModel : public Task Handle(CancelEventArgs args) { + Publisher.Publish(Cancel.As()); Publisher.Publish(Notify.As(Factory.Create(new List { Factory.Create(), @@ -99,20 +102,29 @@ public partial class ItemViewModel : return Task.CompletedTask; } - public Task Handle(ConfirmEventArgs args) + public async Task Handle(ConfirmEventArgs args) { - Publisher.Publish(Notify.As(Factory.Create(new List + List results = []; + await foreach (bool result in Mediator.HandleManyAsync, bool>(Validate.As())) { - Factory.Create(Favourite), - Factory.Create(), - Factory.Create(), - }))); + results.Add(result); + } - Publisher.Publish(Confirm.As(), - State is ItemState.New ? nameof(ItemState.New) : nameof(ItemState.Write)); + if (results.All(result => result)) + { + Publisher.Publish(Confirm.As()); + Publisher.Publish(Notify.As(Factory.Create(new List + { + Factory.Create(Favourite), + Factory.Create(), + Factory.Create(), + }))); - State = ItemState.Read; - return Task.CompletedTask; + Publisher.Publish(Confirm.As(), + State is ItemState.New ? nameof(ItemState.New) : nameof(ItemState.Write)); + + State = ItemState.Read; + } } public override Task OnActivated() diff --git a/Wallet/QueryWalletHandler.cs b/Wallet/QueryWalletHandler.cs index d538187..81c856e 100644 --- a/Wallet/QueryWalletHandler.cs +++ b/Wallet/QueryWalletHandler.cs @@ -16,8 +16,8 @@ public class QueryWalletHandler(IDbContextFactory dbContextFactor { (string filter, string text) = Wallet.Value; - ExpressionStarter predicate = - PredicateBuilder.New(true); + ExpressionStarter predicate = + PredicateBuilder.New(true); if (filter is { Length: <= 0 }) { @@ -49,7 +49,7 @@ public class QueryWalletHandler(IDbContextFactory dbContextFactor } using WalletContext context = await dbContextFactory.CreateDbContextAsync(cancellationToken); - var results = await context.Set() + var results = await context.Set() .Where(predicate) .Select(x => new { diff --git a/Wallet/UpdateItemHander.cs b/Wallet/UpdateItemHander.cs index 9019269..e660ed1 100644 --- a/Wallet/UpdateItemHander.cs +++ b/Wallet/UpdateItemHander.cs @@ -20,7 +20,7 @@ public class UpdateItemHander(IDbContextFactory dbContextFactory, try { using WalletContext context = await dbContextFactory.CreateDbContextAsync(cancellationToken); - ItemEntry? result = result = await context.Set() + ItemEntity? result = result = await context.Set() .Include(x => x.Image).FirstOrDefaultAsync(x => x.Id == id, cancellationToken); if (result is not null) @@ -40,7 +40,7 @@ public class UpdateItemHander(IDbContextFactory dbContextFactory, imageWriter.Write(imageDescriptor, memoryStream); thumbData = memoryStream.ToArray(); - if (result.Image is BlobEntry existingImageBlob) + if (result.Image is BlobEntity existingImageBlob) { existingImageBlob.Data = thumbData; existingImageBlob.DateTime = DateTime.UtcNow; @@ -49,7 +49,7 @@ public class UpdateItemHander(IDbContextFactory dbContextFactory, } else { - result.Image = new BlobEntry + result.Image = new BlobEntity { Id = Guid.NewGuid(), Data = thumbData, diff --git a/Wallet/UpdateItemStateHandler.cs b/Wallet/UpdateItemStateHandler.cs index c5dd8af..677b905 100644 --- a/Wallet/UpdateItemStateHandler.cs +++ b/Wallet/UpdateItemStateHandler.cs @@ -13,7 +13,7 @@ public class UpdateItemStateHandler(IDbContextFactory dbContextFa if (args.Sender is (Guid id, int state)) { using WalletContext context = await dbContextFactory.CreateDbContextAsync(cancellationToken); - if (await context.FindAsync(id) is ItemEntry result) + if (await context.FindAsync(id) is ItemEntity result) { result.State = state; await context.SaveChangesAsync(cancellationToken);