From 17d27f9535159df037bd861dd64b753ec2c92af7 Mon Sep 17 00:00:00 2001 From: DismissedLight <1686188646@qq.com> Date: Mon, 1 Jul 2024 17:00:18 +0800 Subject: [PATCH] make users great again --- .../Core/Database/AdvancedDbCollectionView.cs | 9 - ...edDbCollectionViewCurrentChangedMessage.cs | 15 - .../Core/Database/DbSetExtension.cs | 43 -- .../Core/Database/ScopedDbCurrent.cs | 124 ------ .../DependencyInjection.cs | 2 +- .../DependencyInjection/IocConfiguration.cs | 5 +- .../Snap.Hutao/Model/Entity/GameAccount.cs | 2 + .../AppDbServiceAppDbEntityExtension.cs | 19 - .../AppDbServiceCollectionExtension.cs | 19 - .../Abstraction/AppDbServiceExtension.cs | 110 +----- .../Achievement/AchievementDbService.cs | 38 +- .../Service/Achievement/AchievementService.cs | 4 +- .../AchievementStatisticsService.cs | 12 +- .../Achievement/IAchievementDbService.cs | 8 +- .../AvatarInfo/AvatarInfoDbBulkOperation.cs | 19 +- .../Service/AvatarInfo/AvatarInfoDbService.cs | 10 - .../Service/AvatarInfo/AvatarInfoService.cs | 2 +- .../AvatarInfo/IAvatarInfoDbService.cs | 4 - .../Cultivation/CultivationDbService.cs | 53 ++- .../Service/Cultivation/CultivationService.cs | 32 +- .../Cultivation/ICultivationDbService.cs | 26 +- .../Service/DailyNote/DailyNoteDbService.cs | 22 +- .../Service/DailyNote/DailyNoteService.cs | 34 +- .../Service/DailyNote/IDailyNoteDbService.cs | 10 +- .../Service/GachaLog/GachaLogDbService.cs | 368 ++---------------- .../Service/GachaLog/GachaLogFetchContext.cs | 2 +- .../GachaLog/GachaLogHutaoCloudService.cs | 22 +- .../Service/GachaLog/GachaLogService.cs | 8 +- .../Service/GachaLog/IGachaLogDbService.cs | 33 +- .../GachaLogQuerySTokenProvider.cs | 3 +- .../Service/GachaLog/UIGFExportService.cs | 4 +- .../Service/GachaLog/UIGFImportService.cs | 2 +- .../Game/Account/GameAccountService.cs | 6 +- .../Snap.Hutao/Service/Game/GameDbService.cs | 42 +- .../Snap.Hutao/Service/Game/IGameDbService.cs | 9 +- .../Service/Hutao/ObjectCacheDbService.cs | 11 +- .../Service/Inventory/IInventoryDbService.cs | 8 +- .../Service/Inventory/InventoryDbService.cs | 20 +- .../Service/Inventory/InventoryService.cs | 7 +- .../ISpiralAbyssRecordDbService.cs | 9 +- .../SpiralAbyss/SpiralAbyssRecordDbService.cs | 39 +- .../SpiralAbyss/SpiralAbyssRecordService.cs | 9 +- .../User/IUidProfilePictureDbService.cs | 8 +- .../Service/User/IUserCollectionService.cs | 11 +- .../Snap.Hutao/Service/User/IUserDbService.cs | 14 +- .../Snap.Hutao/Service/User/IUserService.cs | 2 +- .../Service/User/ProfilePictureService.cs | 6 +- .../User/UidProfilePictureDbService.cs | 13 +- .../Service/User/UserCollectionService.cs | 119 +++--- .../Snap.Hutao/Service/User/UserDbService.cs | 45 +-- .../Service/User/UserInitializationService.cs | 4 +- .../Service/User/UserRemovedMessage.cs | 16 + .../Snap.Hutao/Service/User/UserService.cs | 27 +- .../Service/User/UserServiceExtension.cs | 40 ++ .../Dialog/CultivateProjectDialog.xaml.cs | 4 +- .../Snap.Hutao/UI/Xaml/View/MainView.xaml.cs | 5 +- .../UI/Xaml/View/Page/CultivationPage.xaml | 6 +- .../UI/Xaml/View/Page/DailyNotePage.xaml | 39 +- .../Xaml/View/Page/ISupportLoginByWebView.cs | 5 +- .../Snap.Hutao/UI/Xaml/View/UserView.xaml | 74 ++-- .../MiHoYoJSBridgeWebView2ContentProvider.cs | 11 +- .../AchievementImporterScopeContext.cs | 1 - .../AvatarProperty/AvatarPropertyViewModel.cs | 19 +- .../ViewModel/DailyNote/DailyNoteViewModel.cs | 43 +- .../ViewModel/Game/LaunchGameViewModel.cs | 6 +- .../Snap.Hutao/ViewModel/MainViewModel.cs | 2 - .../SpiralAbyss/SpiralAbyssRecordViewModel.cs | 14 +- .../Snap.Hutao/ViewModel/User/User.cs | 86 ++-- .../Snap.Hutao/ViewModel/User/UserAndUid.cs | 27 +- .../User/UserAndUidChangedMessage.cs | 27 ++ .../ViewModel/User/UserViewModel.cs | 76 +--- .../ViewModel/Wiki/WikiAvatarViewModel.cs | 3 +- .../ViewModel/Wiki/WikiWeaponViewModel.cs | 3 +- .../Hoyolab/Takumi/Binding/UserGameRole.cs | 52 +-- 74 files changed, 581 insertions(+), 1451 deletions(-) delete mode 100644 src/Snap.Hutao/Snap.Hutao/Core/Database/AdvancedDbCollectionViewCurrentChangedMessage.cs delete mode 100644 src/Snap.Hutao/Snap.Hutao/Core/Database/ScopedDbCurrent.cs create mode 100644 src/Snap.Hutao/Snap.Hutao/Service/User/UserRemovedMessage.cs create mode 100644 src/Snap.Hutao/Snap.Hutao/ViewModel/User/UserAndUidChangedMessage.cs diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Database/AdvancedDbCollectionView.cs b/src/Snap.Hutao/Snap.Hutao/Core/Database/AdvancedDbCollectionView.cs index 1ebcc02b..7b03141f 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Database/AdvancedDbCollectionView.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Database/AdvancedDbCollectionView.cs @@ -1,7 +1,6 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. -using CommunityToolkit.Mvvm.Messaging; using Microsoft.EntityFrameworkCore; using Snap.Hutao.Core.Database.Abstraction; using Snap.Hutao.Model; @@ -53,10 +52,6 @@ internal sealed class AdvancedDbCollectionView : AdvancedCollectionView dbContext.Set().UpdateAndSave(currentItem); } } - - serviceProvider - .GetRequiredService() - .Send(new AdvancedDbCollectionViewCurrentChangedMessage(currentItem)); } } @@ -105,9 +100,5 @@ internal sealed class AdvancedDbCollectionView : Advance dbContext.Set().UpdateAndSave(currentItem.Entity); } } - - serviceProvider - .GetRequiredService() - .Send(new AdvancedDbCollectionViewCurrentChangedMessage(currentItem)); } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Database/AdvancedDbCollectionViewCurrentChangedMessage.cs b/src/Snap.Hutao/Snap.Hutao/Core/Database/AdvancedDbCollectionViewCurrentChangedMessage.cs deleted file mode 100644 index 3a2eca12..00000000 --- a/src/Snap.Hutao/Snap.Hutao/Core/Database/AdvancedDbCollectionViewCurrentChangedMessage.cs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) DGP Studio. All rights reserved. -// Licensed under the MIT license. - -namespace Snap.Hutao.Core.Database; - -internal sealed class AdvancedDbCollectionViewCurrentChangedMessage - where TItem : class -{ - public AdvancedDbCollectionViewCurrentChangedMessage(TItem? currentItem) - { - CurrentItem = currentItem; - } - - public TItem? CurrentItem { get; } -} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Database/DbSetExtension.cs b/src/Snap.Hutao/Snap.Hutao/Core/Database/DbSetExtension.cs index 23a27c2b..37599bdb 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Database/DbSetExtension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Database/DbSetExtension.cs @@ -20,14 +20,6 @@ internal static class DbSetExtension return dbSet.SaveChangesAndClearChangeTracker(); } - [Obsolete("Async operation over sqlite is meaningless")] - public static ValueTask AddAndSaveAsync(this DbSet dbSet, TEntity entity, CancellationToken token = default) - where TEntity : class - { - dbSet.Add(entity); - return dbSet.SaveChangesAndClearChangeTrackerAsync(token); - } - public static int AddRangeAndSave(this DbSet dbSet, IEnumerable entities) where TEntity : class { @@ -35,14 +27,6 @@ internal static class DbSetExtension return dbSet.SaveChangesAndClearChangeTracker(); } - [Obsolete("Async operation over sqlite is meaningless")] - public static ValueTask AddRangeAndSaveAsync(this DbSet dbSet, IEnumerable entities, CancellationToken token = default) - where TEntity : class - { - dbSet.AddRange(entities); - return dbSet.SaveChangesAndClearChangeTrackerAsync(token); - } - public static int RemoveAndSave(this DbSet dbSet, TEntity entity) where TEntity : class { @@ -50,14 +34,6 @@ internal static class DbSetExtension return dbSet.SaveChangesAndClearChangeTracker(); } - [Obsolete("Async operation over sqlite is meaningless")] - public static ValueTask RemoveAndSaveAsync(this DbSet dbSet, TEntity entity, CancellationToken token = default) - where TEntity : class - { - dbSet.Remove(entity); - return dbSet.SaveChangesAndClearChangeTrackerAsync(token); - } - public static int UpdateAndSave(this DbSet dbSet, TEntity entity) where TEntity : class { @@ -65,14 +41,6 @@ internal static class DbSetExtension return dbSet.SaveChangesAndClearChangeTracker(); } - [Obsolete("Async operation over sqlite is meaningless")] - public static ValueTask UpdateAndSaveAsync(this DbSet dbSet, TEntity entity, CancellationToken token = default) - where TEntity : class - { - dbSet.Update(entity); - return dbSet.SaveChangesAndClearChangeTrackerAsync(token); - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] private static int SaveChangesAndClearChangeTracker(this DbSet dbSet) where TEntity : class @@ -83,17 +51,6 @@ internal static class DbSetExtension return count; } - [Obsolete("Async operation over sqlite is meaningless")] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static async ValueTask SaveChangesAndClearChangeTrackerAsync(this DbSet dbSet, CancellationToken token = default) - where TEntity : class - { - DbContext dbContext = dbSet.Context(); - int count = await dbContext.SaveChangesAsync(token).ConfigureAwait(false); - dbContext.ChangeTracker.Clear(); - return count; - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] private static DbContext Context(this DbSet dbSet) where TEntity : class diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Database/ScopedDbCurrent.cs b/src/Snap.Hutao/Snap.Hutao/Core/Database/ScopedDbCurrent.cs deleted file mode 100644 index e0c58fd9..00000000 --- a/src/Snap.Hutao/Snap.Hutao/Core/Database/ScopedDbCurrent.cs +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright (c) DGP Studio. All rights reserved. -// Licensed under the MIT license. - -using CommunityToolkit.Mvvm.Messaging; -using Microsoft.EntityFrameworkCore; -using Snap.Hutao.Core.Database.Abstraction; -using Snap.Hutao.Model; -using Snap.Hutao.Model.Entity.Database; - -namespace Snap.Hutao.Core.Database; - -[Obsolete] -[ConstructorGenerated] -internal sealed partial class ScopedDbCurrent - where TEntity : class, ISelectable - where TMessage : Message.ValueChangedMessage, new() -{ - private readonly IServiceProvider serviceProvider; - private readonly IMessenger messenger; - - private TEntity? current; - - public TEntity? Current - { - get => current; - set - { - // prevent useless sets - if (current == value) - { - return; - } - - if (serviceProvider.IsDisposed()) - { - return; - } - - using (IServiceScope scope = serviceProvider.CreateScope()) - { - AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); - DbSet dbSet = appDbContext.Set(); - - // only update when not processing a deletion - if (value is not null && current is not null) - { - current.IsSelected = false; - dbSet.UpdateAndSave(current); - } - - TMessage message = new() { OldValue = current, NewValue = value }; - - current = value; - - if (current is not null) - { - current.IsSelected = true; - dbSet.UpdateAndSave(current); - } - - messenger.Send(message); - } - } - } -} - -[Obsolete] -[ConstructorGenerated] -internal sealed partial class ScopedDbCurrent - where TEntityOnly : class, IEntityAccess - where TEntity : class, ISelectable - where TMessage : Message.ValueChangedMessage, new() -{ - private readonly IServiceProvider serviceProvider; - private readonly IMessenger messenger; - - private TEntityOnly? current; - - public TEntityOnly? Current - { - get => current; - set - { - // prevent useless sets - if (current == value) - { - return; - } - - if (serviceProvider.IsDisposed()) - { - return; - } - - using (IServiceScope scope = serviceProvider.CreateScope()) - { - AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); - DbSet dbSet = appDbContext.Set(); - - // only update when not processing a deletion - if (value is not null) - { - if (current is not null) - { - current.Entity.IsSelected = false; - dbSet.UpdateAndSave(current.Entity); - } - } - - TMessage message = new() { OldValue = current, NewValue = value }; - - current = value; - - if (current is not null) - { - current.Entity.IsSelected = true; - dbSet.UpdateAndSave(current.Entity); - } - - messenger.Send(message); - } - } - } -} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/DependencyInjection.cs b/src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/DependencyInjection.cs index c226c003..ee49a41f 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/DependencyInjection.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/DependencyInjection.cs @@ -44,7 +44,7 @@ internal static class DependencyInjection .AddConfiguredHttpClients() // Discrete services - .AddSingleton() + .AddSingleton() .BuildServiceProvider(true); Ioc.Default.ConfigureServices(serviceProvider); diff --git a/src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/IocConfiguration.cs b/src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/IocConfiguration.cs index ac0cc302..b8774e86 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/IocConfiguration.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/IocConfiguration.cs @@ -30,10 +30,7 @@ internal static class IocConfiguration /// 可继续操作的集合 public static IServiceCollection AddDatabase(this IServiceCollection services) { - return services - .AddTransient(typeof(Database.ScopedDbCurrent<,>)) - .AddTransient(typeof(Database.ScopedDbCurrent<,,>)) - .AddDbContextPool(AddDbContextCore); + return services.AddDbContextPool(AddDbContextCore); static void AddDbContextCore(IServiceProvider serviceProvider, DbContextOptionsBuilder builder) { diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Entity/GameAccount.cs b/src/Snap.Hutao/Snap.Hutao/Model/Entity/GameAccount.cs index 8f18d4e5..a0e05ac6 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Entity/GameAccount.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Entity/GameAccount.cs @@ -4,6 +4,7 @@ using CommunityToolkit.Mvvm.ComponentModel; using Snap.Hutao.Core.Abstraction; using Snap.Hutao.Core.Database.Abstraction; +using Snap.Hutao.Model.Entity.Abstraction; using Snap.Hutao.Model.Entity.Primitive; using Snap.Hutao.UI.Xaml.Data; using System.ComponentModel.DataAnnotations; @@ -17,6 +18,7 @@ namespace Snap.Hutao.Model.Entity; [HighQuality] [Table("game_accounts")] internal sealed class GameAccount : ObservableObject, + IAppDbEntity, IReorderable, IAdvancedCollectionViewItem, IMappingFrom diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Abstraction/AppDbServiceAppDbEntityExtension.cs b/src/Snap.Hutao/Snap.Hutao/Service/Abstraction/AppDbServiceAppDbEntityExtension.cs index 8b97ee63..59a02c5d 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Abstraction/AppDbServiceAppDbEntityExtension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Abstraction/AppDbServiceAppDbEntityExtension.cs @@ -1,7 +1,6 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. -using Microsoft.EntityFrameworkCore; using Snap.Hutao.Model.Entity.Abstraction; namespace Snap.Hutao.Service.Abstraction; @@ -20,27 +19,9 @@ internal static class AppDbServiceAppDbEntityExtension return service.Delete(e => e.InnerId == innerId); } - public static ValueTask DeleteByInnerIdAsync(this IAppDbService service, TEntity entity, CancellationToken token = default) - where TEntity : class, IAppDbEntity - { - return service.DeleteByInnerIdAsync(entity.InnerId, token); - } - - public static ValueTask DeleteByInnerIdAsync(this IAppDbService service, Guid innerId, CancellationToken token = default) - where TEntity : class, IAppDbEntity - { - return service.DeleteAsync(e => e.InnerId == innerId, token); - } - public static List ListByArchiveId(this IAppDbService service, Guid archiveId) where TEntity : class, IAppDbEntityHasArchive { return service.Query(query => query.Where(e => e.ArchiveId == archiveId).ToList()); } - - public static ValueTask> ListByArchiveIdAsync(this IAppDbService service, Guid archiveId, CancellationToken token = default) - where TEntity : class, IAppDbEntityHasArchive - { - return service.QueryAsync((query, token) => query.Where(e => e.ArchiveId == archiveId).ToListAsync(token), token); - } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Abstraction/AppDbServiceCollectionExtension.cs b/src/Snap.Hutao/Snap.Hutao/Service/Abstraction/AppDbServiceCollectionExtension.cs index 0e522959..263708a9 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Abstraction/AppDbServiceCollectionExtension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Abstraction/AppDbServiceCollectionExtension.cs @@ -1,7 +1,6 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. -using Microsoft.EntityFrameworkCore; using System.Collections.ObjectModel; using System.Linq.Expressions; @@ -27,24 +26,6 @@ internal static class AppDbServiceCollectionExtension return service.Query(query1 => query(query1).ToList()); } - public static ValueTask> ListAsync(this IAppDbService service, CancellationToken token = default) - where TEntity : class - { - return service.QueryAsync((query, token) => query.ToListAsync(token), token); - } - - public static ValueTask> ListAsync(this IAppDbService service, Expression> predicate, CancellationToken token = default) - where TEntity : class - { - return service.ListAsync(query => query.Where(predicate), token); - } - - public static ValueTask> ListAsync(this IAppDbService service, Func, IQueryable> query, CancellationToken token = default) - where TEntity : class - { - return service.QueryAsync((query1, token) => query(query1).ToListAsync(token), token); - } - public static ObservableCollection ObservableCollection(this IAppDbService service) where TEntity : class { diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Abstraction/AppDbServiceExtension.cs b/src/Snap.Hutao/Snap.Hutao/Service/Abstraction/AppDbServiceExtension.cs index 8585d818..2041df8d 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Abstraction/AppDbServiceExtension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Abstraction/AppDbServiceExtension.cs @@ -20,137 +20,46 @@ internal static class AppDbServiceExtension } } - public static async ValueTask ExecuteAsync(this IAppDbService service, Func, ValueTask> asyncFunc) - where TEntity : class - { - using (IServiceScope scope = service.ServiceProvider.CreateScope()) - { - AppDbContext appDbContext = scope.GetAppDbContext(); - return await asyncFunc(appDbContext.Set()).ConfigureAwait(false); - } - } - - public static async ValueTask ExecuteAsync(this IAppDbService service, Func, CancellationToken, ValueTask> asyncFunc, CancellationToken token) - where TEntity : class - { - using (IServiceScope scope = service.ServiceProvider.CreateScope()) - { - AppDbContext appDbContext = scope.GetAppDbContext(); - return await asyncFunc(appDbContext.Set(), token).ConfigureAwait(false); - } - } - - public static async ValueTask ExecuteAsync(this IAppDbService service, Func, Task> asyncFunc) - where TEntity : class - { - using (IServiceScope scope = service.ServiceProvider.CreateScope()) - { - AppDbContext appDbContext = scope.GetAppDbContext(); - return await asyncFunc(appDbContext.Set()).ConfigureAwait(false); - } - } - - public static async ValueTask ExecuteAsync(this IAppDbService service, Func, CancellationToken, Task> asyncFunc, CancellationToken token) - where TEntity : class - { - using (IServiceScope scope = service.ServiceProvider.CreateScope()) - { - AppDbContext appDbContext = scope.GetAppDbContext(); - return await asyncFunc(appDbContext.Set(), token).ConfigureAwait(false); - } - } - public static int Add(this IAppDbService service, TEntity entity) where TEntity : class { return service.Execute(dbset => dbset.AddAndSave(entity)); } - [Obsolete] - public static ValueTask AddAsync(this IAppDbService service, TEntity entity, CancellationToken token = default) - where TEntity : class - { - return service.ExecuteAsync((dbset, token) => dbset.AddAndSaveAsync(entity, token), token); - } - public static int AddRange(this IAppDbService service, IEnumerable entities) where TEntity : class { return service.Execute(dbset => dbset.AddRangeAndSave(entities)); } - [Obsolete] - public static ValueTask AddRangeAsync(this IAppDbService service, IEnumerable entities, CancellationToken token = default) - where TEntity : class - { - return service.ExecuteAsync((dbset, token) => dbset.AddRangeAndSaveAsync(entities, token), token); - } - public static TResult Query(this IAppDbService service, Func, TResult> func) where TEntity : class { return service.Execute(dbset => func(dbset.AsNoTracking())); } - public static ValueTask QueryAsync(this IAppDbService service, Func, ValueTask> func) - where TEntity : class - { - return service.ExecuteAsync(dbset => func(dbset.AsNoTracking())); - } - - public static ValueTask QueryAsync(this IAppDbService service, Func, CancellationToken, ValueTask> func, CancellationToken token = default) - where TEntity : class - { - return service.ExecuteAsync((dbset, token) => func(dbset.AsNoTracking(), token), token); - } - - public static ValueTask QueryAsync(this IAppDbService service, Func, Task> func) - where TEntity : class - { - return service.ExecuteAsync(dbset => func(dbset.AsNoTracking())); - } - - public static ValueTask QueryAsync(this IAppDbService service, Func, CancellationToken, Task> func, CancellationToken token = default) - where TEntity : class - { - return service.ExecuteAsync((dbset, token) => func(dbset.AsNoTracking(), token), token); - } - public static TEntity Single(this IAppDbService service, Expression> predicate) where TEntity : class { return service.Query(query => query.Single(predicate)); } - public static ValueTask SingleAsync(this IAppDbService service, Expression> predicate, CancellationToken token = default) - where TEntity : class - { - return service.QueryAsync((query, token) => query.SingleAsync(predicate, token), token); - } - public static TEntity? SingleOrDefault(this IAppDbService service, Expression> predicate) where TEntity : class { return service.Query(query => query.SingleOrDefault(predicate)); } - public static ValueTask SingleOrDefaultAsync(this IAppDbService service, Expression> predicate, CancellationToken token = default) - where TEntity : class - { - return service.QueryAsync((query, token) => query.SingleOrDefaultAsync(predicate, token), token); - } - public static int Update(this IAppDbService service, TEntity entity) where TEntity : class { return service.Execute(dbset => dbset.UpdateAndSave(entity)); } - [Obsolete] - public static ValueTask UpdateAsync(this IAppDbService service, TEntity entity, CancellationToken token = default) - where TEntity : class + public static int Delete(this IAppDbService service) + where TEntity : class { - return service.ExecuteAsync((dbset, token) => dbset.UpdateAndSaveAsync(entity, token), token); + return service.Execute(dbset => dbset.ExecuteDelete()); } public static int Delete(this IAppDbService service, TEntity entity) @@ -164,17 +73,4 @@ internal static class AppDbServiceExtension { return service.Execute(dbset => dbset.Where(predicate).ExecuteDelete()); } - - [Obsolete] - public static ValueTask DeleteAsync(this IAppDbService service, TEntity entity, CancellationToken token = default) - where TEntity : class - { - return service.ExecuteAsync((dbset, token) => dbset.RemoveAndSaveAsync(entity, token), token); - } - - public static ValueTask DeleteAsync(this IAppDbService service, Expression> predicate, CancellationToken token = default) - where TEntity : class - { - return service.ExecuteAsync((dbset, token) => dbset.Where(predicate).ExecuteDeleteAsync(token), token); - } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Achievement/AchievementDbService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Achievement/AchievementDbService.cs index 0893ad3b..22f8ffd6 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Achievement/AchievementDbService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Achievement/AchievementDbService.cs @@ -1,7 +1,6 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. -using Microsoft.EntityFrameworkCore; using Snap.Hutao.Core.ExceptionService; using Snap.Hutao.Model.Entity; using Snap.Hutao.Model.Primitive; @@ -33,26 +32,21 @@ internal sealed partial class AchievementDbService : IAchievementDbService } } - public ValueTask GetFinishedAchievementCountByArchiveIdAsync(Guid archiveId, CancellationToken token = default) + public int GetFinishedAchievementCountByArchiveId(Guid archiveId) { - return this.QueryAsync( - (query, token) => query - .Where(a => a.ArchiveId == archiveId) - .Where(a => a.Status >= Model.Intrinsic.AchievementStatus.STATUS_FINISHED) - .CountAsync(token), - token); + return this.Query(query => query + .Where(a => a.ArchiveId == archiveId) + .Where(a => a.Status >= Model.Intrinsic.AchievementStatus.STATUS_FINISHED) + .Count()); } - [SuppressMessage("", "CA1305")] - public ValueTask> GetLatestFinishedAchievementListByArchiveIdAsync(Guid archiveId, int take, CancellationToken token = default) + public List GetLatestFinishedAchievementListByArchiveId(Guid archiveId, int take) { - return this.ListAsync( - query => query - .Where(a => a.ArchiveId == archiveId) - .Where(a => a.Status >= Model.Intrinsic.AchievementStatus.STATUS_FINISHED) - .OrderByDescending(a => a.Time.ToString()) - .Take(take), - token); + return this.List(query => query + .Where(a => a.ArchiveId == archiveId) + .Where(a => a.Status >= Model.Intrinsic.AchievementStatus.STATUS_FINISHED) + .OrderByDescending(a => a.Time.ToString()) + .Take(take)); } public void OverwriteAchievement(EntityAchievement achievement) @@ -80,18 +74,8 @@ internal sealed partial class AchievementDbService : IAchievementDbService return this.ListByArchiveId(archiveId); } - public ValueTask> GetAchievementListByArchiveIdAsync(Guid archiveId, CancellationToken token = default) - { - return this.ListByArchiveIdAsync(archiveId, token); - } - public List GetAchievementArchiveList() { return this.List(); } - - public ValueTask> GetAchievementArchiveListAsync(CancellationToken token = default) - { - return this.ListAsync(token); - } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Achievement/AchievementService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Achievement/AchievementService.cs index fb465b14..4c9934ac 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Achievement/AchievementService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Achievement/AchievementService.cs @@ -116,9 +116,7 @@ internal sealed partial class AchievementService : IAchievementService public async ValueTask ExportToUIAFAsync(AchievementArchive archive) { await taskContext.SwitchToBackgroundAsync(); - List entities = await achievementDbService - .GetAchievementListByArchiveIdAsync(archive.InnerId) - .ConfigureAwait(false); + List entities = achievementDbService.GetAchievementListByArchiveId(archive.InnerId); List list = entities.SelectList(UIAFItem.From); return new() diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Achievement/AchievementStatisticsService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Achievement/AchievementStatisticsService.cs index 29c21f50..fc5d5e16 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Achievement/AchievementStatisticsService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Achievement/AchievementStatisticsService.cs @@ -22,17 +22,11 @@ internal sealed partial class AchievementStatisticsService : IAchievementStatist await taskContext.SwitchToBackgroundAsync(); List results = []; - foreach (AchievementArchive archive in await achievementDbService.GetAchievementArchiveListAsync(token).ConfigureAwait(false)) + foreach (AchievementArchive archive in achievementDbService.GetAchievementArchiveList()) { - int finishedCount = await achievementDbService - .GetFinishedAchievementCountByArchiveIdAsync(archive.InnerId, token) - .ConfigureAwait(false); - + int finishedCount = achievementDbService.GetFinishedAchievementCountByArchiveId(archive.InnerId); int totalCount = context.IdAchievementMap.Count; - - List achievements = await achievementDbService - .GetLatestFinishedAchievementListByArchiveIdAsync(archive.InnerId, AchievementCardTakeCount, token) - .ConfigureAwait(false); + List achievements = achievementDbService.GetLatestFinishedAchievementListByArchiveId(archive.InnerId, AchievementCardTakeCount); results.Add(new() { diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Achievement/IAchievementDbService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Achievement/IAchievementDbService.cs index 0be00207..5f172bae 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Achievement/IAchievementDbService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Achievement/IAchievementDbService.cs @@ -14,17 +14,13 @@ internal interface IAchievementDbService : IAppDbService GetAchievementArchiveList(); - ValueTask> GetAchievementArchiveListAsync(CancellationToken token = default); - List GetAchievementListByArchiveId(Guid archiveId); - ValueTask> GetAchievementListByArchiveIdAsync(Guid archiveId, CancellationToken token = default); - Dictionary GetAchievementMapByArchiveId(Guid archiveId); - ValueTask GetFinishedAchievementCountByArchiveIdAsync(Guid archiveId, CancellationToken token = default); + int GetFinishedAchievementCountByArchiveId(Guid archiveId); - ValueTask> GetLatestFinishedAchievementListByArchiveIdAsync(Guid archiveId, int take, CancellationToken token = default); + List GetLatestFinishedAchievementListByArchiveId(Guid archiveId, int take); void OverwriteAchievement(EntityAchievement achievement); diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoDbBulkOperation.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoDbBulkOperation.cs index 4e6bca1c..a5061dcf 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoDbBulkOperation.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoDbBulkOperation.cs @@ -27,12 +27,14 @@ namespace Snap.Hutao.Service.AvatarInfo; [Injection(InjectAs.Singleton)] internal sealed partial class AvatarInfoDbBulkOperation { - private readonly IServiceProvider serviceProvider; private readonly IAvatarInfoDbService avatarInfoDbService; + private readonly IServiceProvider serviceProvider; + private readonly ITaskContext taskContext; public async ValueTask> UpdateDbAvatarInfosByShowcaseAsync(string uid, IEnumerable webInfos, CancellationToken token) { - List dbInfos = await avatarInfoDbService.GetAvatarInfoListByUidAsync(uid, token).ConfigureAwait(false); + await taskContext.SwitchToBackgroundAsync(); + List dbInfos = avatarInfoDbService.GetAvatarInfoListByUid(uid); EnsureItemsAvatarIdUnique(ref dbInfos, uid, out Dictionary dbInfoMap); using (IServiceScope scope = serviceProvider.CreateScope()) @@ -50,14 +52,15 @@ internal sealed partial class AvatarInfoDbBulkOperation AddOrUpdateAvatarInfo(entity, uid, appDbContext, webInfo); } - return await avatarInfoDbService.GetAvatarInfoListByUidAsync(uid, token).ConfigureAwait(false); + return avatarInfoDbService.GetAvatarInfoListByUid(uid); } } public async ValueTask> UpdateDbAvatarInfosByGameRecordCharacterAsync(UserAndUid userAndUid, CancellationToken token) { + await taskContext.SwitchToBackgroundAsync(); string uid = userAndUid.Uid.Value; - List dbInfos = await avatarInfoDbService.GetAvatarInfoListByUidAsync(uid, token).ConfigureAwait(false); + List dbInfos = avatarInfoDbService.GetAvatarInfoListByUid(uid); EnsureItemsAvatarIdUnique(ref dbInfos, uid, out Dictionary dbInfoMap); using (IServiceScope scope = serviceProvider.CreateScope()) @@ -103,14 +106,14 @@ internal sealed partial class AvatarInfoDbBulkOperation } Return: - return await avatarInfoDbService.GetAvatarInfoListByUidAsync(uid, token).ConfigureAwait(false); + return avatarInfoDbService.GetAvatarInfoListByUid(uid); } public async ValueTask> UpdateDbAvatarInfosByCalculateAvatarDetailAsync(UserAndUid userAndUid, CancellationToken token) { - token.ThrowIfCancellationRequested(); + await taskContext.SwitchToBackgroundAsync(); string uid = userAndUid.Uid.Value; - List dbInfos = await avatarInfoDbService.GetAvatarInfoListByUidAsync(uid, token).ConfigureAwait(false); + List dbInfos = avatarInfoDbService.GetAvatarInfoListByUid(uid); EnsureItemsAvatarIdUnique(ref dbInfos, uid, out Dictionary dbInfoMap); using (IServiceScope scope = serviceProvider.CreateScope()) @@ -146,7 +149,7 @@ internal sealed partial class AvatarInfoDbBulkOperation } } - return await avatarInfoDbService.GetAvatarInfoListByUidAsync(uid, token).ConfigureAwait(false); + return avatarInfoDbService.GetAvatarInfoListByUid(uid); } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoDbService.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoDbService.cs index e76f1dc5..08d9a106 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoDbService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoDbService.cs @@ -19,18 +19,8 @@ internal sealed partial class AvatarInfoDbService : IAvatarInfoDbService return this.List(i => i.Uid == uid); } - public ValueTask> GetAvatarInfoListByUidAsync(string uid, CancellationToken token = default) - { - return this.ListAsync(i => i.Uid == uid, token); - } - public void RemoveAvatarInfoRangeByUid(string uid) { this.Delete(i => i.Uid == uid); } - - public async ValueTask RemoveAvatarInfoRangeByUidAsync(string uid, CancellationToken token = default) - { - await this.DeleteAsync(i => i.Uid == uid, token).ConfigureAwait(false); - } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoService.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoService.cs index 7116fdbe..968185e2 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoService.cs @@ -74,7 +74,7 @@ internal sealed partial class AvatarInfoService : IAvatarInfoService default: { - List list = await avatarInfoDbService.GetAvatarInfoListByUidAsync(userAndUid.Uid.Value, token).ConfigureAwait(false); + List list = avatarInfoDbService.GetAvatarInfoListByUid(userAndUid.Uid.Value); Summary summary = await GetSummaryCoreAsync(list, token).ConfigureAwait(false); return new(RefreshResultKind.Ok, summary.Avatars.Count == 0 ? null : summary); } diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/IAvatarInfoDbService.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/IAvatarInfoDbService.cs index ad1ddb5f..ed73d953 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/IAvatarInfoDbService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/IAvatarInfoDbService.cs @@ -11,8 +11,4 @@ internal interface IAvatarInfoDbService : IAppDbService void RemoveAvatarInfoRangeByUid(string uid); List GetAvatarInfoListByUid(string uid); - - ValueTask> GetAvatarInfoListByUidAsync(string uid, CancellationToken token = default); - - ValueTask RemoveAvatarInfoRangeByUidAsync(string uid, CancellationToken token = default); } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/CultivationDbService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/CultivationDbService.cs index 34eca1e2..389de62e 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/CultivationDbService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/CultivationDbService.cs @@ -16,24 +16,24 @@ internal sealed partial class CultivationDbService : ICultivationDbService public IServiceProvider ServiceProvider { get => serviceProvider; } - public ValueTask> GetCultivateEntryListByProjectIdAsync(Guid projectId, CancellationToken token = default) + public List GetCultivateEntryListByProjectId(Guid projectId) { - return this.ListAsync(e => e.ProjectId == projectId, token); + return this.List(e => e.ProjectId == projectId); } - public ValueTask> GetCultivateEntryListIncludingLevelInformationByProjectIdAsync(Guid projectId, CancellationToken token = default) + public List GetCultivateEntryListIncludingLevelInformationByProjectId(Guid projectId) { - return this.ListAsync(query => query.Where(e => e.ProjectId == projectId).Include(e => e.LevelInformation), token); + return this.List(query => query.Where(e => e.ProjectId == projectId).Include(e => e.LevelInformation)); } - public ValueTask> GetCultivateItemListByEntryIdAsync(Guid entryId, CancellationToken token = default) + public List GetCultivateItemListByEntryId(Guid entryId) { - return this.ListAsync(query => query.Where(i => i.EntryId == entryId).OrderBy(i => i.ItemId), token); + return this.List(query => query.Where(i => i.EntryId == entryId).OrderBy(i => i.ItemId)); } - public async ValueTask RemoveCultivateEntryByIdAsync(Guid entryId, CancellationToken token = default) + public void RemoveCultivateEntryById(Guid entryId) { - await this.DeleteByInnerIdAsync(entryId, token).ConfigureAwait(false); + this.DeleteByInnerId(entryId); } public void UpdateCultivateItem(CultivateItem item) @@ -41,39 +41,34 @@ internal sealed partial class CultivationDbService : ICultivationDbService this.Update(item); } - public async ValueTask UpdateCultivateItemAsync(CultivateItem item, CancellationToken token = default) + public CultivateEntry? GetCultivateEntryByProjectIdAndItemId(Guid projectId, uint itemId) { - await this.UpdateAsync(item, token).ConfigureAwait(false); + return this.SingleOrDefault(e => e.ProjectId == projectId && e.Id == itemId); } - public async ValueTask GetCultivateEntryByProjectIdAndItemIdAsync(Guid projectId, uint itemId, CancellationToken token = default) + public void AddCultivateEntry(CultivateEntry entry) { - return await this.SingleOrDefaultAsync(e => e.ProjectId == projectId && e.Id == itemId, token).ConfigureAwait(false); + this.Add(entry); } - public async ValueTask AddCultivateEntryAsync(CultivateEntry entry, CancellationToken token = default) + public void RemoveCultivateItemRangeByEntryId(Guid entryId) { - await this.AddAsync(entry, token).ConfigureAwait(false); + this.Delete(i => i.EntryId == entryId); } - public async ValueTask RemoveCultivateItemRangeByEntryIdAsync(Guid entryId, CancellationToken token = default) + public void AddCultivateItemRange(IEnumerable toAdd) { - await this.DeleteAsync(i => i.EntryId == entryId, token).ConfigureAwait(false); + this.AddRange(toAdd); } - public async ValueTask AddCultivateItemRangeAsync(IEnumerable toAdd, CancellationToken token = default) + public void AddCultivateProject(CultivateProject project) { - await this.AddRangeAsync(toAdd, token).ConfigureAwait(false); + this.Add(project); } - public async ValueTask AddCultivateProjectAsync(CultivateProject project, CancellationToken token = default) + public void RemoveCultivateProjectById(Guid projectId) { - await this.AddAsync(project, token).ConfigureAwait(false); - } - - public async ValueTask RemoveCultivateProjectByIdAsync(Guid projectId, CancellationToken token = default) - { - await this.DeleteByInnerIdAsync(projectId, token).ConfigureAwait(false); + this.DeleteByInnerId(projectId); } public ObservableCollection GetCultivateProjectCollection() @@ -81,13 +76,13 @@ internal sealed partial class CultivationDbService : ICultivationDbService return this.ObservableCollection(); } - public async ValueTask RemoveLevelInformationByEntryIdAsync(Guid entryId, CancellationToken token = default) + public void RemoveLevelInformationByEntryId(Guid entryId) { - await this.DeleteAsync(l => l.EntryId == entryId, token).ConfigureAwait(false); + this.Delete(l => l.EntryId == entryId); } - public async ValueTask AddLevelInformationAsync(CultivateEntryLevelInformation levelInformation, CancellationToken token = default) + public void AddLevelInformation(CultivateEntryLevelInformation levelInformation) { - await this.AddAsync(levelInformation, token).ConfigureAwait(false); + this.Add(levelInformation); } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/CultivationService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/CultivationService.cs index 593b6925..8f5eab0c 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/CultivationService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/CultivationService.cs @@ -38,17 +38,14 @@ internal sealed partial class CultivationService : ICultivationService public async ValueTask> GetCultivateEntriesAsync(CultivateProject cultivateProject, ICultivationMetadataContext context) { await taskContext.SwitchToBackgroundAsync(); - List entries = await cultivationDbService - .GetCultivateEntryListIncludingLevelInformationByProjectIdAsync(cultivateProject.InnerId) - .ConfigureAwait(false); + List entries = cultivationDbService.GetCultivateEntryListIncludingLevelInformationByProjectId(cultivateProject.InnerId); List resultEntries = new(entries.Count); foreach (CultivateEntry entry in entries) { List entryItems = []; - // Async operation here, thus we can't use the Span trick. - foreach (CultivateItem cultivateItem in await cultivationDbService.GetCultivateItemListByEntryIdAsync(entry.InnerId).ConfigureAwait(false)) + foreach (CultivateItem cultivateItem in cultivationDbService.GetCultivateItemListByEntryId(entry.InnerId)) { entryItems.Add(new(cultivateItem, context.GetMaterial(cultivateItem.ItemId))); } @@ -77,9 +74,9 @@ internal sealed partial class CultivationService : ICultivationService Guid projectId = cultivateProject.InnerId; - foreach (CultivateEntry entry in await cultivationDbService.GetCultivateEntryListByProjectIdAsync(projectId, token).ConfigureAwait(false)) + foreach (CultivateEntry entry in cultivationDbService.GetCultivateEntryListByProjectId(projectId)) { - foreach (CultivateItem item in await cultivationDbService.GetCultivateItemListByEntryIdAsync(entry.InnerId, token).ConfigureAwait(false)) + foreach (CultivateItem item in cultivationDbService.GetCultivateItemListByEntryId(entry.InnerId)) { if (item.IsFinished) { @@ -97,7 +94,7 @@ internal sealed partial class CultivationService : ICultivationService } } - foreach (InventoryItem inventoryItem in await inventoryDbService.GetInventoryItemListByProjectIdAsync(projectId, token).ConfigureAwait(false)) + foreach (InventoryItem inventoryItem in inventoryDbService.GetInventoryItemListByProjectId(projectId)) { if (resultItems.SingleOrDefault(i => i.Inner.Id == inventoryItem.ItemId) is { } existedItem) { @@ -111,7 +108,8 @@ internal sealed partial class CultivationService : ICultivationService /// public async ValueTask RemoveCultivateEntryAsync(Guid entryId) { - await cultivationDbService.RemoveCultivateEntryByIdAsync(entryId).ConfigureAwait(false); + await taskContext.SwitchToBackgroundAsync(); + cultivationDbService.RemoveCultivateEntryById(entryId); } /// @@ -141,25 +139,23 @@ internal sealed partial class CultivationService : ICultivationService return false; } - CultivateEntry? entry = await cultivationDbService - .GetCultivateEntryByProjectIdAndItemIdAsync(Projects.CurrentItem.InnerId, itemId) - .ConfigureAwait(false); + CultivateEntry? entry = cultivationDbService.GetCultivateEntryByProjectIdAndItemId(Projects.CurrentItem.InnerId, itemId); if (entry is null) { entry = CultivateEntry.From(Projects.CurrentItem.InnerId, type, itemId); - await cultivationDbService.AddCultivateEntryAsync(entry).ConfigureAwait(false); + cultivationDbService.AddCultivateEntry(entry); } Guid entryId = entry.InnerId; - await cultivationDbService.RemoveLevelInformationByEntryIdAsync(entryId).ConfigureAwait(false); + cultivationDbService.RemoveLevelInformationByEntryId(entryId); CultivateEntryLevelInformation entryLevelInformation = CultivateEntryLevelInformation.From(entryId, type, levelInformation); - await cultivationDbService.AddLevelInformationAsync(entryLevelInformation).ConfigureAwait(false); + cultivationDbService.AddLevelInformation(entryLevelInformation); - await cultivationDbService.RemoveCultivateItemRangeByEntryIdAsync(entryId).ConfigureAwait(false); + cultivationDbService.RemoveCultivateItemRangeByEntryId(entryId); IEnumerable toAdd = items.Select(item => CultivateItem.From(entryId, item)); - await cultivationDbService.AddCultivateItemRangeAsync(toAdd).ConfigureAwait(false); + cultivationDbService.AddCultivateItemRange(toAdd); return true; } @@ -199,6 +195,6 @@ internal sealed partial class CultivationService : ICultivationService // Sync database await taskContext.SwitchToBackgroundAsync(); - await cultivationDbService.RemoveCultivateProjectByIdAsync(project.InnerId).ConfigureAwait(false); + cultivationDbService.RemoveCultivateProjectById(project.InnerId); } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/ICultivationDbService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/ICultivationDbService.cs index d54dabec..3a8e84a4 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/ICultivationDbService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/ICultivationDbService.cs @@ -12,33 +12,31 @@ internal interface ICultivationDbService : IAppDbService, IAppDbService { - ValueTask AddCultivateProjectAsync(CultivateProject project, CancellationToken token = default); + void AddCultivateProject(CultivateProject project); - ValueTask RemoveCultivateEntryByIdAsync(Guid entryId, CancellationToken token = default); + void RemoveCultivateEntryById(Guid entryId); - ValueTask RemoveCultivateItemRangeByEntryIdAsync(Guid entryId, CancellationToken token = default); + void RemoveCultivateItemRangeByEntryId(Guid entryId); - ValueTask RemoveCultivateProjectByIdAsync(Guid projectId, CancellationToken token = default); + void RemoveCultivateProjectById(Guid projectId); - ValueTask GetCultivateEntryByProjectIdAndItemIdAsync(Guid projectId, uint itemId, CancellationToken token = default); + CultivateEntry? GetCultivateEntryByProjectIdAndItemId(Guid projectId, uint itemId); - ValueTask> GetCultivateEntryListByProjectIdAsync(Guid projectId, CancellationToken token = default); + List GetCultivateEntryListByProjectId(Guid projectId); - ValueTask> GetCultivateItemListByEntryIdAsync(Guid entryId, CancellationToken token = default); + List GetCultivateItemListByEntryId(Guid entryId); ObservableCollection GetCultivateProjectCollection(); - ValueTask AddCultivateEntryAsync(CultivateEntry entry, CancellationToken token = default); + void AddCultivateEntry(CultivateEntry entry); - ValueTask AddCultivateItemRangeAsync(IEnumerable toAdd, CancellationToken token = default); + void AddCultivateItemRange(IEnumerable toAdd); void UpdateCultivateItem(CultivateItem item); - ValueTask UpdateCultivateItemAsync(CultivateItem item, CancellationToken token = default); + void RemoveLevelInformationByEntryId(Guid entryId); - ValueTask RemoveLevelInformationByEntryIdAsync(Guid entryId, CancellationToken token = default); + void AddLevelInformation(CultivateEntryLevelInformation levelInformation); - ValueTask AddLevelInformationAsync(CultivateEntryLevelInformation levelInformation, CancellationToken token = default); - - ValueTask> GetCultivateEntryListIncludingLevelInformationByProjectIdAsync(Guid projectId, CancellationToken token = default); + List GetCultivateEntryListIncludingLevelInformationByProjectId(Guid projectId); } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteDbService.cs b/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteDbService.cs index 8a3c03d0..f79f4fe0 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteDbService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteDbService.cs @@ -20,33 +20,23 @@ internal sealed partial class DailyNoteDbService : IDailyNoteDbService return this.Query(query => query.Any(n => n.Uid == uid)); } - public ValueTask ContainsUidAsync(string uid, CancellationToken token = default) + public void AddDailyNoteEntry(DailyNoteEntry entry) { - return this.QueryAsync(query => query.AnyAsync(n => n.Uid == uid)); + this.Add(entry); } - public async ValueTask AddDailyNoteEntryAsync(DailyNoteEntry entry, CancellationToken token = default) + public void DeleteDailyNoteEntryById(Guid entryId) { - await this.AddAsync(entry, token).ConfigureAwait(false); + this.DeleteByInnerId(entryId); } - public async ValueTask DeleteDailyNoteEntryByIdAsync(Guid entryId, CancellationToken token = default) + public void UpdateDailyNoteEntry(DailyNoteEntry entry) { - await this.DeleteByInnerIdAsync(entryId, token).ConfigureAwait(false); - } - - public async ValueTask UpdateDailyNoteEntryAsync(DailyNoteEntry entry, CancellationToken token = default) - { - await this.UpdateAsync(entry, token).ConfigureAwait(false); + this.Update(entry); } public List GetDailyNoteEntryListIncludingUser() { return this.List(query => query.Include(n => n.User)); } - - public ValueTask> GetDailyNoteEntryListIncludingUserAsync(CancellationToken token = default) - { - return this.ListAsync(query => query.Include(n => n.User), token); - } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteService.cs b/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteService.cs index a583d9ea..6b9a9aef 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteService.cs @@ -1,6 +1,7 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. +using CommunityToolkit.Mvvm.Messaging; using Snap.Hutao.Core.DependencyInjection.Abstraction; using Snap.Hutao.Model.Entity; using Snap.Hutao.Service.Abstraction; @@ -18,7 +19,7 @@ namespace Snap.Hutao.Service.DailyNote; [ConstructorGenerated] [Injection(InjectAs.Singleton, typeof(IDailyNoteService))] -internal sealed partial class DailyNoteService : IDailyNoteService +internal sealed partial class DailyNoteService : IDailyNoteService, IRecipient { private readonly DailyNoteNotificationOperation dailyNoteNotificationOperation; private readonly IServiceProvider serviceProvider; @@ -28,19 +29,17 @@ internal sealed partial class DailyNoteService : IDailyNoteService private ObservableCollection? entries; - /// public void Receive(UserRemovedMessage message) { // Database items have been deleted by cascade deleting. - taskContext.BeginInvokeOnMainThread(() => entries?.RemoveWhere(n => n.UserId == message.RemovedUserId)); + taskContext.BeginInvokeOnMainThread(() => entries?.RemoveWhere(n => n.UserId == message.RemovedUser.InnerId)); } - /// public async ValueTask AddDailyNoteAsync(UserAndUid userAndUid, CancellationToken token = default) { string roleUid = userAndUid.Uid.Value; - if (await dailyNoteDbService.ContainsUidAsync(roleUid, token).ConfigureAwait(false)) + if (dailyNoteDbService.ContainsUid(roleUid)) { return; } @@ -67,9 +66,9 @@ internal sealed partial class DailyNoteService : IDailyNoteService newEntry.UpdateDailyNote(dailyNoteResponse.Data); } - newEntry.UserGameRole = userService.GetUserGameRoleByUid(roleUid); + newEntry.UserGameRole = await userService.GetUserGameRoleByUidAsync(roleUid).ConfigureAwait(false); newEntry.ArchonQuestView = DailyNoteArchonQuestView.Create(newEntry.DailyNote, context.Chapters); - await dailyNoteDbService.AddDailyNoteEntryAsync(newEntry, token).ConfigureAwait(false); + dailyNoteDbService.AddDailyNoteEntry(newEntry); newEntry.User = userAndUid.User; await taskContext.SwitchToMainThreadAsync(); @@ -81,20 +80,20 @@ internal sealed partial class DailyNoteService : IDailyNoteService { if (entries is null) { - // IUserService.GetUserGameRoleByUid only usable after call IUserService.GetRoleCollectionAsync - await userService.GetRoleCollectionAsync().ConfigureAwait(false); await RefreshDailyNotesCoreAsync(forceRefresh, token).ConfigureAwait(false); using (IServiceScope scope = serviceProvider.CreateScope()) { DailyNoteMetadataContext context = await scope.GetRequiredService().GetContextAsync(token).ConfigureAwait(false); - List entryList = await dailyNoteDbService.GetDailyNoteEntryListIncludingUserAsync(token).ConfigureAwait(false); - entryList.ForEach(entry => + List entryList = dailyNoteDbService.GetDailyNoteEntryListIncludingUser(); + + foreach (DailyNoteEntry entry in entryList) { - entry.UserGameRole = userService.GetUserGameRoleByUid(entry.Uid); + entry.UserGameRole = await userService.GetUserGameRoleByUidAsync(entry.Uid).ConfigureAwait(false); entry.ArchonQuestView = DailyNoteArchonQuestView.Create(entry.DailyNote, context.Chapters); - }); + } + entries = entryList.ToObservableCollection(); } } @@ -116,22 +115,23 @@ internal sealed partial class DailyNoteService : IDailyNoteService entries.Remove(entry); await taskContext.SwitchToBackgroundAsync(); - await dailyNoteDbService.DeleteDailyNoteEntryByIdAsync(entry.InnerId, token).ConfigureAwait(false); + dailyNoteDbService.DeleteDailyNoteEntryById(entry.InnerId); } public async ValueTask UpdateDailyNoteAsync(DailyNoteEntry entry, CancellationToken token = default) { await taskContext.SwitchToBackgroundAsync(); - await dailyNoteDbService.UpdateDailyNoteEntryAsync(entry, token).ConfigureAwait(false); + dailyNoteDbService.UpdateDailyNoteEntry(entry); } private async ValueTask RefreshDailyNotesCoreAsync(bool forceRefresh, CancellationToken token = default) { + await taskContext.SwitchToBackgroundAsync(); using (IServiceScope scope = serviceProvider.CreateScope()) { DailyNoteWebhookOperation dailyNoteWebhookOperation = serviceProvider.GetRequiredService(); - foreach (DailyNoteEntry entry in await dailyNoteDbService.GetDailyNoteEntryListIncludingUserAsync(token).ConfigureAwait(false)) + foreach (DailyNoteEntry entry in dailyNoteDbService.GetDailyNoteEntryListIncludingUser()) { if (!forceRefresh && entry.DailyNote is not null) { @@ -163,7 +163,7 @@ internal sealed partial class DailyNoteService : IDailyNoteService { // 发送通知必须早于数据库更新,否则会导致通知重复 await dailyNoteNotificationOperation.SendAsync(entry).ConfigureAwait(false); - await dailyNoteDbService.UpdateDailyNoteEntryAsync(entry, token).ConfigureAwait(false); + dailyNoteDbService.UpdateDailyNoteEntry(entry); dailyNoteWebhookOperation.TryPostDailyNoteToWebhook(entry.Uid, dailyNote); } } diff --git a/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/IDailyNoteDbService.cs b/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/IDailyNoteDbService.cs index 70e6ea55..ba65e893 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/IDailyNoteDbService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/IDailyNoteDbService.cs @@ -8,17 +8,13 @@ namespace Snap.Hutao.Service.DailyNote; internal interface IDailyNoteDbService : IAppDbService { - ValueTask AddDailyNoteEntryAsync(DailyNoteEntry entry, CancellationToken token = default); + void AddDailyNoteEntry(DailyNoteEntry entry); bool ContainsUid(string uid); - ValueTask ContainsUidAsync(string uid, CancellationToken token = default); - - ValueTask DeleteDailyNoteEntryByIdAsync(Guid entryId, CancellationToken token = default); + void DeleteDailyNoteEntryById(Guid entryId); List GetDailyNoteEntryListIncludingUser(); - ValueTask> GetDailyNoteEntryListIncludingUserAsync(CancellationToken token = default); - - ValueTask UpdateDailyNoteEntryAsync(DailyNoteEntry entry, CancellationToken token = default); + void UpdateDailyNoteEntry(DailyNoteEntry entry); } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogDbService.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogDbService.cs index 92f3b85b..54a14f77 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogDbService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogDbService.cs @@ -1,12 +1,10 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. -using Microsoft.Data.Sqlite; -using Microsoft.EntityFrameworkCore; using Snap.Hutao.Core.Database; -using Snap.Hutao.Core.ExceptionService; using Snap.Hutao.Model.Entity; using Snap.Hutao.Model.Entity.Database; +using Snap.Hutao.Service.Abstraction; using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo; using System.Collections.ObjectModel; @@ -18,233 +16,49 @@ internal sealed partial class GachaLogDbService : IGachaLogDbService { private readonly IServiceProvider serviceProvider; + public IServiceProvider ServiceProvider { get => serviceProvider; } + public ObservableCollection GetGachaArchiveCollection() { - try - { - using (IServiceScope scope = serviceProvider.CreateScope()) - { - AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); - return appDbContext.GachaArchives.AsNoTracking().ToObservableCollection(); - } - } - catch (SqliteException ex) - { - string message = SH.FormatServiceGachaLogArchiveCollectionUserdataCorruptedMessage(ex.Message); - throw HutaoException.Throw(message, ex); - } + return this.ObservableCollection(); } public List GetGachaItemListByArchiveId(Guid archiveId) { - using (IServiceScope scope = serviceProvider.CreateScope()) - { - AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); - IOrderedQueryable result = appDbContext.GachaItems - .AsNoTracking() - .Where(i => i.ArchiveId == archiveId) - .OrderBy(i => i.Id); - return [.. result]; - } + return this.List(query => query.Where(i => i.ArchiveId == archiveId).OrderBy(i => i.Id)); } - public async ValueTask> GetGachaItemListByArchiveIdAsync(Guid archiveId) + public void RemoveGachaArchiveById(Guid archiveId) { - using (IServiceScope scope = serviceProvider.CreateScope()) - { - AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); - return await appDbContext.GachaItems - .AsNoTracking() - .Where(i => i.ArchiveId == archiveId) - .OrderBy(i => i.Id) - .ToListAsync() - .ConfigureAwait(false); - } - } - - public async ValueTask RemoveGachaArchiveByIdAsync(Guid archiveId) - { - using (IServiceScope scope = serviceProvider.CreateScope()) - { - AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); - await appDbContext.GachaArchives - .Where(a => a.InnerId == archiveId) - .ExecuteDeleteAsync() - .ConfigureAwait(false); - } - } - - public async ValueTask GetNewestGachaItemIdByArchiveIdAndQueryTypeAsync(Guid archiveId, GachaType queryType, CancellationToken token) - { - GachaItem? item = null; - - try - { - using (IServiceScope scope = serviceProvider.CreateScope()) - { - AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); - - // TODO: replace with MaxBy - // https://github.com/dotnet/efcore/issues/25566 - // .MaxBy(i => i.Id); - item = await appDbContext.GachaItems - .AsNoTracking() - .Where(i => i.ArchiveId == archiveId) - .Where(i => i.QueryType == queryType) - .OrderByDescending(i => i.Id) - .FirstOrDefaultAsync(token) - .ConfigureAwait(false); - } - } - catch (SqliteException ex) - { - HutaoException.Throw(SH.ServiceGachaLogEndIdUserdataCorruptedMessage, ex); - } - - return item?.Id ?? 0L; + this.DeleteByInnerId(archiveId); } public long GetNewestGachaItemIdByArchiveIdAndQueryType(Guid archiveId, GachaType queryType) { - GachaItem? item = null; - - try - { - using (IServiceScope scope = serviceProvider.CreateScope()) - { - AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); - - // TODO: replace with MaxBy - // https://github.com/dotnet/efcore/issues/25566 - // .MaxBy(i => i.Id); - item = appDbContext.GachaItems - .AsNoTracking() - .Where(i => i.ArchiveId == archiveId) - .Where(i => i.QueryType == queryType) - .OrderByDescending(i => i.Id) - .FirstOrDefault(); - } - } - catch (SqliteException ex) - { - HutaoException.Throw(SH.ServiceGachaLogEndIdUserdataCorruptedMessage, ex); - } - - return item?.Id ?? 0L; - } - - public async ValueTask GetNewestGachaItemIdByArchiveIdAndQueryTypeAsync(Guid archiveId, GachaType queryType) - { - GachaItem? item = null; - - try - { - using (IServiceScope scope = serviceProvider.CreateScope()) - { - AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); - - // TODO: replace with MaxBy - // https://github.com/dotnet/efcore/issues/25566 - // .MaxBy(i => i.Id); - item = await appDbContext.GachaItems - .AsNoTracking() - .Where(i => i.ArchiveId == archiveId) - .Where(i => i.QueryType == queryType) - .OrderByDescending(i => i.Id) - .FirstOrDefaultAsync() - .ConfigureAwait(false); - } - } - catch (SqliteException ex) - { - HutaoException.Throw(SH.ServiceGachaLogEndIdUserdataCorruptedMessage, ex); - } + GachaItem? item = this.Query(query => query + .Where(i => i.ArchiveId == archiveId && i.QueryType == queryType) + .OrderByDescending(i => i.Id) + .FirstOrDefault()); return item?.Id ?? 0L; } public long GetOldestGachaItemIdByArchiveId(Guid archiveId) { - GachaItem? item = null; - - using (IServiceScope scope = serviceProvider.CreateScope()) - { - AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); - - // TODO: replace with MaxBy - // https://github.com/dotnet/efcore/issues/25566 - // .MaxBy(i => i.Id); - item = appDbContext.GachaItems - .AsNoTracking() - .Where(i => i.ArchiveId == archiveId) - .OrderBy(i => i.Id) - .FirstOrDefault(); - } - - return item?.Id ?? long.MaxValue; - } - - public async ValueTask GetOldestGachaItemIdByArchiveIdAsync(Guid archiveId) - { - GachaItem? item = null; - - using (IServiceScope scope = serviceProvider.CreateScope()) - { - AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); - - // TODO: replace with MaxBy - // https://github.com/dotnet/efcore/issues/25566 - // .MaxBy(i => i.Id); - item = await appDbContext.GachaItems - .AsNoTracking() - .Where(i => i.ArchiveId == archiveId) - .OrderBy(i => i.Id) - .FirstOrDefaultAsync() - .ConfigureAwait(false); - } + GachaItem? item = this.Query(query => query + .Where(i => i.ArchiveId == archiveId) + .OrderBy(i => i.Id) + .FirstOrDefault()); return item?.Id ?? long.MaxValue; } public long GetOldestGachaItemIdByArchiveIdAndQueryType(Guid archiveId, GachaType queryType) { - GachaItem? item = null; - - using (IServiceScope scope = serviceProvider.CreateScope()) - { - AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); - - // TODO: replace with MaxBy - // https://github.com/dotnet/efcore/issues/25566 - // .MaxBy(i => i.Id); - item = appDbContext.GachaItems - .AsNoTracking() - .Where(i => i.ArchiveId == archiveId && i.QueryType == queryType) - .OrderBy(i => i.Id) - .FirstOrDefault(); - } - - return item?.Id ?? long.MaxValue; - } - - public async ValueTask GetOldestGachaItemIdByArchiveIdAndQueryTypeAsync(Guid archiveId, GachaType queryType, CancellationToken token) - { - GachaItem? item = null; - - using (IServiceScope scope = serviceProvider.CreateScope()) - { - AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); - - // TODO: replace with MaxBy - // https://github.com/dotnet/efcore/issues/25566 - // .MaxBy(i => i.Id); - item = await appDbContext.GachaItems - .AsNoTracking() - .Where(i => i.ArchiveId == archiveId && i.QueryType == queryType) - .OrderBy(i => i.Id) - .FirstOrDefaultAsync(token) - .ConfigureAwait(false); - } + GachaItem? item = this.Query(query => query + .Where(i => i.ArchiveId == archiveId && i.QueryType == queryType) + .OrderBy(i => i.Id) + .FirstOrDefault()); return item?.Id ?? long.MaxValue; } @@ -258,141 +72,41 @@ internal sealed partial class GachaLogDbService : IGachaLogDbService } } - public async ValueTask AddGachaArchiveAsync(GachaArchive archive) + [SuppressMessage("", "IDE0305")] + public List GetHutaoGachaItemListByArchiveIdAndQueryTypeNewerThanEndId(Guid archiveId, GachaType queryType, long endId) { - using (IServiceScope scope = serviceProvider.CreateScope()) - { - AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); - await appDbContext.GachaArchives.AddAndSaveAsync(archive).ConfigureAwait(false); - } + return this.Query>(query => query + .Where(i => i.ArchiveId == archiveId && i.QueryType == queryType) + .OrderByDescending(i => i.Id) + .Where(i => i.Id > endId) + .Select(i => new Web.Hutao.GachaLog.GachaItem() + { + GachaType = i.GachaType, + QueryType = i.QueryType, + ItemId = i.ItemId, + Time = i.Time, + Id = i.Id, + }) + .ToList()); } - public List GetHutaoGachaItemList(Guid archiveId, GachaType queryType, long endId) + public GachaArchive? GetGachaArchiveById(Guid archiveId) { - using (IServiceScope scope = serviceProvider.CreateScope()) - { - AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); - IQueryable result = appDbContext.GachaItems - .AsNoTracking() - .Where(i => i.ArchiveId == archiveId) - .Where(i => i.QueryType == queryType) - .OrderByDescending(i => i.Id) - .Where(i => i.Id > endId) - - // Keep this to make SQL generates correctly - .Select(i => new Web.Hutao.GachaLog.GachaItem() - { - GachaType = i.GachaType, - QueryType = i.QueryType, - ItemId = i.ItemId, - Time = i.Time, - Id = i.Id, - }); - return [.. result]; - } + return this.SingleOrDefault(a => a.InnerId == archiveId); } - public async ValueTask> GetHutaoGachaItemListAsync(Guid archiveId, GachaType queryType, long endId) + public GachaArchive? GetGachaArchiveByUid(string uid) { - using (IServiceScope scope = serviceProvider.CreateScope()) - { - AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); - return await appDbContext.GachaItems - .AsNoTracking() - .Where(i => i.ArchiveId == archiveId) - .Where(i => i.QueryType == queryType) - .OrderByDescending(i => i.Id) - .Where(i => i.Id > endId) - - // Keep this to make SQL generates correctly - .Select(i => new Web.Hutao.GachaLog.GachaItem() - { - GachaType = i.GachaType, - QueryType = i.QueryType, - ItemId = i.ItemId, - Time = i.Time, - Id = i.Id, - }) - .ToListAsync() - .ConfigureAwait(false); - } - } - - public async ValueTask GetGachaArchiveByIdAsync(Guid archiveId, CancellationToken token) - { - using (IServiceScope scope = serviceProvider.CreateScope()) - { - AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); - return await appDbContext.GachaArchives - .AsNoTracking() - .SingleOrDefaultAsync(a => a.InnerId == archiveId, token) - .ConfigureAwait(false); - } - } - - public async ValueTask GetGachaArchiveByUidAsync(string uid, CancellationToken token) - { - using (IServiceScope scope = serviceProvider.CreateScope()) - { - AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); - return await appDbContext.GachaArchives - .AsNoTracking() - .SingleOrDefaultAsync(a => a.Uid == uid, token) - .ConfigureAwait(false); - } - } - - public async ValueTask AddGachaItemsAsync(List items) - { - using (IServiceScope scope = serviceProvider.CreateScope()) - { - AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); - await appDbContext.GachaItems.AddRangeAndSaveAsync(items).ConfigureAwait(false); - } + return this.SingleOrDefault(a => a.Uid == uid); } public void AddGachaItemRange(List items) { - using (IServiceScope scope = serviceProvider.CreateScope()) - { - AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); - appDbContext.GachaItems.AddRangeAndSave(items); - } + this.AddRange(items); } - public async ValueTask AddGachaItemRangeAsync(List items) + public void RemoveGachaItemRangeByArchiveIdAndQueryTypeNewerThanEndId(Guid archiveId, GachaType queryType, long endId) { - using (IServiceScope scope = serviceProvider.CreateScope()) - { - AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); - await appDbContext.GachaItems.AddRangeAndSaveAsync(items).ConfigureAwait(false); - } - } - - public void RemoveNewerGachaItemRangeByArchiveIdQueryTypeAndEndId(Guid archiveId, GachaType queryType, long endId) - { - using (IServiceScope scope = serviceProvider.CreateScope()) - { - AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); - appDbContext.GachaItems - .AsNoTracking() - .Where(i => i.ArchiveId == archiveId && i.QueryType == queryType) - .Where(i => i.Id >= endId) - .ExecuteDelete(); - } - } - - public async ValueTask RemoveNewerGachaItemRangeByArchiveIdQueryTypeAndEndIdAsync(Guid archiveId, GachaType queryType, long endId) - { - using (IServiceScope scope = serviceProvider.CreateScope()) - { - AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); - await appDbContext.GachaItems - .AsNoTracking() - .Where(i => i.ArchiveId == archiveId && i.QueryType == queryType) - .Where(i => i.Id >= endId) - .ExecuteDeleteAsync() - .ConfigureAwait(false); - } + this.Delete(i => i.ArchiveId == archiveId && i.QueryType == queryType && i.Id >= endId); } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogFetchContext.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogFetchContext.cs index f94ba495..c3b1099e 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogFetchContext.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogFetchContext.cs @@ -87,7 +87,7 @@ internal struct GachaLogFetchContext // 全量刷新 if (!isLazy) { - gachaLogDbService.RemoveNewerGachaItemRangeByArchiveIdQueryTypeAndEndId(TargetArchive.InnerId, TypedQueryOptions.Type, TypedQueryOptions.EndId); + gachaLogDbService.RemoveGachaItemRangeByArchiveIdAndQueryTypeNewerThanEndId(TargetArchive.InnerId, TypedQueryOptions.Type, TypedQueryOptions.EndId); } gachaLogDbService.AddGachaItemRange(ItemsToAdd); diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogHutaoCloudService.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogHutaoCloudService.cs index aaaa0ca8..5c16919d 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogHutaoCloudService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogHutaoCloudService.cs @@ -39,10 +39,7 @@ internal sealed partial class GachaLogHutaoCloudService : IGachaLogHutaoCloudSer List items = []; foreach ((GachaType type, long endId) in endIds) { - List part = await gachaLogDbService - .GetHutaoGachaItemListAsync(gachaArchive.InnerId, type, endId) - .ConfigureAwait(false); - items.AddRange(part); + items.AddRange(gachaLogDbService.GetHutaoGachaItemListByArchiveIdAndQueryTypeNewerThanEndId(gachaArchive.InnerId, type, endId)); } return await homaGachaLogClient.UploadGachaItemsAsync(uid, items, token).ConfigureAwait(false); @@ -54,11 +51,8 @@ internal sealed partial class GachaLogHutaoCloudService : IGachaLogHutaoCloudSer /// public async ValueTask> RetrieveGachaArchiveIdAsync(string uid, CancellationToken token = default) { - GachaArchive? archive = await gachaLogDbService - .GetGachaArchiveByUidAsync(uid, token) - .ConfigureAwait(false); - - EndIds endIds = await CreateEndIdsAsync(archive, token).ConfigureAwait(false); + GachaArchive? archive = gachaLogDbService.GetGachaArchiveByUid(uid); + EndIds endIds = CreateEndIds(archive); Response> resp = await homaGachaLogClient .RetrieveGachaItemsAsync(uid, endIds, token) .ConfigureAwait(false); @@ -71,12 +65,12 @@ internal sealed partial class GachaLogHutaoCloudService : IGachaLogHutaoCloudSer if (archive is null) { archive = GachaArchive.From(uid); - await gachaLogDbService.AddGachaArchiveAsync(archive).ConfigureAwait(false); + gachaLogDbService.AddGachaArchive(archive); } Guid archiveId = archive.InnerId; List gachaItems = resp.Data.SelectList(i => Model.Entity.GachaItem.From(archiveId, i)); - await gachaLogDbService.AddGachaItemsAsync(gachaItems).ConfigureAwait(false); + gachaLogDbService.AddGachaItemRange(gachaItems); return new(true, archive.InnerId); } @@ -122,16 +116,14 @@ internal sealed partial class GachaLogHutaoCloudService : IGachaLogHutaoCloudSer return resp.IsOk() ? resp.Data : default; } - private async ValueTask CreateEndIdsAsync(GachaArchive? archive, CancellationToken token) + private EndIds CreateEndIds(GachaArchive? archive) { EndIds endIds = new(); foreach (GachaType type in GachaLog.QueryTypes) { if (archive is not null) { - endIds[type] = await gachaLogDbService - .GetOldestGachaItemIdByArchiveIdAndQueryTypeAsync(archive.InnerId, type, token) - .ConfigureAwait(false); + endIds[type] = gachaLogDbService.GetOldestGachaItemIdByArchiveIdAndQueryType(archive.InnerId, type); } } diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogService.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogService.cs index fd73c1cf..a7edb596 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogService.cs @@ -64,7 +64,7 @@ internal sealed partial class GachaLogService : IGachaLogService { using (ValueStopwatch.MeasureExecution(logger)) { - List items = await gachaLogDbService.GetGachaItemListByArchiveIdAsync(archive.InnerId).ConfigureAwait(false); + List items = gachaLogDbService.GetGachaItemListByArchiveId(archive.InnerId); return await gachaStatisticsFactory.CreateAsync(items, context).ConfigureAwait(false); } } @@ -77,7 +77,7 @@ internal sealed partial class GachaLogService : IGachaLogService List statistics = []; foreach (GachaArchive archive in Archives) { - List items = await gachaLogDbService.GetGachaItemListByArchiveIdAsync(archive.InnerId).ConfigureAwait(false); + List items = gachaLogDbService.GetGachaItemListByArchiveId(archive.InnerId); GachaStatisticsSlim slim = await gachaStatisticsSlimFactory.CreateAsync(context, items, archive.Uid).ConfigureAwait(false); statistics.Add(slim); } @@ -121,7 +121,7 @@ internal sealed partial class GachaLogService : IGachaLogService // Sync database await taskContext.SwitchToBackgroundAsync(); - await gachaLogDbService.RemoveGachaArchiveByIdAsync(archive.InnerId).ConfigureAwait(false); + gachaLogDbService.RemoveGachaArchiveById(archive.InnerId); // Sync cache await taskContext.SwitchToMainThreadAsync(); @@ -138,7 +138,7 @@ internal sealed partial class GachaLogService : IGachaLogService } else { - GachaArchive? newArchive = await gachaLogDbService.GetGachaArchiveByIdAsync(archiveId, token).ConfigureAwait(false); + GachaArchive? newArchive = gachaLogDbService.GetGachaArchiveById(archiveId); ArgumentNullException.ThrowIfNull(newArchive); await taskContext.SwitchToMainThreadAsync(); diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/IGachaLogDbService.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/IGachaLogDbService.cs index 14d38197..70fe771c 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/IGachaLogDbService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/IGachaLogDbService.cs @@ -2,54 +2,35 @@ // Licensed under the MIT license. using Snap.Hutao.Model.Entity; +using Snap.Hutao.Service.Abstraction; using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo; using System.Collections.ObjectModel; namespace Snap.Hutao.Service.GachaLog; -internal interface IGachaLogDbService +internal interface IGachaLogDbService : IAppDbService, IAppDbService { void AddGachaArchive(GachaArchive archive); - ValueTask AddGachaArchiveAsync(GachaArchive archive); - void AddGachaItemRange(List items); - ValueTask AddGachaItemsAsync(List items); + void RemoveGachaArchiveById(Guid archiveId); - ValueTask RemoveGachaArchiveByIdAsync(Guid archiveId); + void RemoveGachaItemRangeByArchiveIdAndQueryTypeNewerThanEndId(Guid archiveId, GachaType queryType, long endId); - void RemoveNewerGachaItemRangeByArchiveIdQueryTypeAndEndId(Guid archiveId, GachaType queryType, long endId); + GachaArchive? GetGachaArchiveById(Guid archiveId); - ValueTask GetGachaArchiveByIdAsync(Guid archiveId, CancellationToken token); - - ValueTask GetGachaArchiveByUidAsync(string uid, CancellationToken token); + GachaArchive? GetGachaArchiveByUid(string uid); ObservableCollection GetGachaArchiveCollection(); List GetGachaItemListByArchiveId(Guid archiveId); - ValueTask> GetGachaItemListByArchiveIdAsync(Guid archiveId); - - List GetHutaoGachaItemList(Guid archiveId, GachaType queryType, long endId); + List GetHutaoGachaItemListByArchiveIdAndQueryTypeNewerThanEndId(Guid archiveId, GachaType queryType, long endId); long GetNewestGachaItemIdByArchiveIdAndQueryType(Guid archiveId, GachaType queryType); - ValueTask GetNewestGachaItemIdByArchiveIdAndQueryTypeAsync(Guid archiveId, GachaType queryType, CancellationToken token); - long GetOldestGachaItemIdByArchiveId(Guid archiveId); long GetOldestGachaItemIdByArchiveIdAndQueryType(Guid archiveId, GachaType queryType); - - ValueTask GetOldestGachaItemIdByArchiveIdAndQueryTypeAsync(Guid archiveId, GachaType queryType, CancellationToken token); - - ValueTask GetNewestGachaItemIdByArchiveIdAndQueryTypeAsync(Guid archiveId, GachaType queryType); - - ValueTask GetOldestGachaItemIdByArchiveIdAsync(Guid archiveId); - - ValueTask> GetHutaoGachaItemListAsync(Guid archiveId, GachaType queryType, long endId); - - ValueTask AddGachaItemRangeAsync(List items); - - ValueTask RemoveNewerGachaItemRangeByArchiveIdQueryTypeAndEndIdAsync(Guid archiveId, GachaType queryType, long endId); } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/QueryProvider/GachaLogQuerySTokenProvider.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/QueryProvider/GachaLogQuerySTokenProvider.cs index 0aea9184..21221930 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/QueryProvider/GachaLogQuerySTokenProvider.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/QueryProvider/GachaLogQuerySTokenProvider.cs @@ -2,7 +2,6 @@ // Licensed under the MIT license. using Snap.Hutao.Service.User; -using Snap.Hutao.ViewModel.User; using Snap.Hutao.Web.Hoyolab.Takumi.Binding; using Snap.Hutao.Web.Request; using Snap.Hutao.Web.Response; @@ -25,7 +24,7 @@ internal sealed partial class GachaLogQuerySTokenProvider : IGachaLogQueryProvid /// public async ValueTask> GetQueryAsync() { - if (!UserAndUid.TryFromUser(userService.Current, out UserAndUid? userAndUid)) + if (await userService.GetCurrentUserAndUidAsync().ConfigureAwait(false) is not { } userAndUid) { return new(false, GachaLogQuery.Invalid(SH.MustSelectUserAndUid)); } diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/UIGFExportService.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/UIGFExportService.cs index 2aa4c217..cdf7f12e 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/UIGFExportService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/UIGFExportService.cs @@ -23,9 +23,7 @@ internal sealed partial class UIGFExportService : IUIGFExportService public async ValueTask ExportAsync(GachaLogServiceMetadataContext context, GachaArchive archive) { await taskContext.SwitchToBackgroundAsync(); - List entities = await gachaLogDbService - .GetGachaItemListByArchiveIdAsync(archive.InnerId) - .ConfigureAwait(false); + List entities = gachaLogDbService.GetGachaItemListByArchiveId(archive.InnerId); List list = entities.SelectList(i => UIGFItem.From(i, context.GetNameQualityByItemId(i.ItemId))); UIGF uigf = new() diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/UIGFImportService.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/UIGFImportService.cs index 5513f723..fe1bfaa3 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/UIGFImportService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/UIGFImportService.cs @@ -82,7 +82,7 @@ internal sealed partial class UIGFImportService : IUIGFImportService fullItems.AddRange(currentTypedList); } - await gachaLogDbService.AddGachaItemsAsync(fullItems).ConfigureAwait(false); + gachaLogDbService.AddGachaItemRange(fullItems); archives.MoveCurrentTo(archive); } diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/Account/GameAccountService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/Account/GameAccountService.cs index 146c25bf..93612d6f 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/Account/GameAccountService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/Account/GameAccountService.cs @@ -53,7 +53,7 @@ internal sealed partial class GameAccountService : IGameAccountService // sync database await taskContext.SwitchToBackgroundAsync(); - await gameDbService.AddGameAccountAsync(account).ConfigureAwait(false); + gameDbService.AddGameAccount(account); // sync cache await taskContext.SwitchToMainThreadAsync(); @@ -106,7 +106,7 @@ internal sealed partial class GameAccountService : IGameAccountService // sync database await taskContext.SwitchToBackgroundAsync(); - await gameDbService.UpdateGameAccountAsync(gameAccount).ConfigureAwait(false); + gameDbService.UpdateGameAccount(gameAccount); } } @@ -118,7 +118,7 @@ internal sealed partial class GameAccountService : IGameAccountService gameAccounts.Remove(gameAccount); await taskContext.SwitchToBackgroundAsync(); - await gameDbService.RemoveGameAccountByIdAsync(gameAccount.InnerId).ConfigureAwait(false); + gameDbService.RemoveGameAccountById(gameAccount.InnerId); } private static GameAccount? SingleGameAccountOrDefault(ObservableCollection gameAccounts, string registrySdk) diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/GameDbService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/GameDbService.cs index f8c1d164..3b0c93e3 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/GameDbService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/GameDbService.cs @@ -1,10 +1,9 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. -using Microsoft.EntityFrameworkCore; using Snap.Hutao.Core.Database; using Snap.Hutao.Model.Entity; -using Snap.Hutao.Model.Entity.Database; +using Snap.Hutao.Service.Abstraction; namespace Snap.Hutao.Service.Game; @@ -14,48 +13,25 @@ internal sealed partial class GameDbService : IGameDbService { private readonly IServiceProvider serviceProvider; + public IServiceProvider ServiceProvider { get => serviceProvider; } + public ObservableReorderableDbCollection GetGameAccountCollection() { - using (IServiceScope scope = serviceProvider.CreateScope()) - { - AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); - return appDbContext.GameAccounts.AsNoTracking().ToObservableReorderableDbCollection(serviceProvider); - } + return this.Query(query => query.ToObservableReorderableDbCollection(serviceProvider)); } - public async ValueTask AddGameAccountAsync(GameAccount gameAccount) + public void AddGameAccount(GameAccount gameAccount) { - using (IServiceScope scope = serviceProvider.CreateScope()) - { - AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); - await appDbContext.GameAccounts.AddAndSaveAsync(gameAccount).ConfigureAwait(false); - } + this.Add(gameAccount); } public void UpdateGameAccount(GameAccount gameAccount) { - using (IServiceScope scope = serviceProvider.CreateScope()) - { - AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); - appDbContext.GameAccounts.UpdateAndSave(gameAccount); - } + this.Update(gameAccount); } - public async ValueTask UpdateGameAccountAsync(GameAccount gameAccount) + public void RemoveGameAccountById(Guid id) { - using (IServiceScope scope = serviceProvider.CreateScope()) - { - AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); - await appDbContext.GameAccounts.UpdateAndSaveAsync(gameAccount).ConfigureAwait(false); - } - } - - public async ValueTask RemoveGameAccountByIdAsync(Guid id) - { - using (IServiceScope scope = serviceProvider.CreateScope()) - { - AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); - await appDbContext.GameAccounts.Where(a => a.InnerId == id).ExecuteDeleteAsync().ConfigureAwait(false); - } + this.DeleteByInnerId(id); } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/IGameDbService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/IGameDbService.cs index 5550d018..8b56ea53 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/IGameDbService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/IGameDbService.cs @@ -3,18 +3,17 @@ using Snap.Hutao.Core.Database; using Snap.Hutao.Model.Entity; +using Snap.Hutao.Service.Abstraction; namespace Snap.Hutao.Service.Game; -internal interface IGameDbService +internal interface IGameDbService : IAppDbService { - ValueTask AddGameAccountAsync(GameAccount gameAccount); + void AddGameAccount(GameAccount gameAccount); - ValueTask RemoveGameAccountByIdAsync(Guid id); + void RemoveGameAccountById(Guid id); ObservableReorderableDbCollection GetGameAccountCollection(); void UpdateGameAccount(GameAccount gameAccount); - - ValueTask UpdateGameAccountAsync(GameAccount gameAccount); } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Hutao/ObjectCacheDbService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Hutao/ObjectCacheDbService.cs index 4cd10218..acc46343 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Hutao/ObjectCacheDbService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Hutao/ObjectCacheDbService.cs @@ -12,22 +12,24 @@ namespace Snap.Hutao.Service.Hutao; [Injection(InjectAs.Singleton, typeof(IObjectCacheDbService))] internal sealed partial class ObjectCacheDbService : IObjectCacheDbService { - private readonly IServiceProvider serviceProvider; private readonly JsonSerializerOptions jsonSerializerOptions; + private readonly IServiceProvider serviceProvider; + private readonly ITaskContext taskContext; public async ValueTask AddObjectCacheAsync(string key, TimeSpan expire, T data) where T : class { + await taskContext.SwitchToBackgroundAsync(); using (IServiceScope scope = serviceProvider.CreateScope()) { AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); - await appDbContext.ObjectCache.AddAndSaveAsync(new() + appDbContext.ObjectCache.AddAndSave(new() { Key = key, ExpireTime = DateTimeOffset.UtcNow.Add(expire), Value = JsonSerializer.Serialize(data, jsonSerializerOptions), - }).ConfigureAwait(false); + }); } } @@ -36,6 +38,7 @@ internal sealed partial class ObjectCacheDbService : IObjectCacheDbService { try { + await taskContext.SwitchToBackgroundAsync(); using (IServiceScope scope = serviceProvider.CreateScope()) { AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); @@ -49,7 +52,7 @@ internal sealed partial class ObjectCacheDbService : IObjectCacheDbService return value; } - await appDbContext.ObjectCache.RemoveAndSaveAsync(entry).ConfigureAwait(false); + appDbContext.ObjectCache.RemoveAndSave(entry); } } } diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Inventory/IInventoryDbService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Inventory/IInventoryDbService.cs index 0098c263..6ccd4497 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Inventory/IInventoryDbService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Inventory/IInventoryDbService.cs @@ -8,15 +8,11 @@ namespace Snap.Hutao.Service.Inventory; internal interface IInventoryDbService : IAppDbService { - ValueTask AddInventoryItemRangeByProjectIdAsync(List items, CancellationToken token = default); + void AddInventoryItemRangeByProjectId(List items); - ValueTask RemoveInventoryItemRangeByProjectIdAsync(Guid projectId, CancellationToken token = default); + void RemoveInventoryItemRangeByProjectId(Guid projectId); void UpdateInventoryItem(InventoryItem item); - ValueTask UpdateInventoryItemAsync(InventoryItem item, CancellationToken token = default); - List GetInventoryItemListByProjectId(Guid projectId); - - ValueTask> GetInventoryItemListByProjectIdAsync(Guid projectId, CancellationToken token = default); } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Inventory/InventoryDbService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Inventory/InventoryDbService.cs index 236a4544..b9bf1657 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Inventory/InventoryDbService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Inventory/InventoryDbService.cs @@ -14,14 +14,14 @@ internal sealed partial class InventoryDbService : IInventoryDbService public IServiceProvider ServiceProvider { get => serviceProvider; } - public async ValueTask RemoveInventoryItemRangeByProjectIdAsync(Guid projectId, CancellationToken token = default) + public void RemoveInventoryItemRangeByProjectId(Guid projectId) { - await this.DeleteAsync(i => i.ProjectId == projectId, token).ConfigureAwait(false); + this.Delete(i => i.ProjectId == projectId); } - public async ValueTask AddInventoryItemRangeByProjectIdAsync(List items, CancellationToken token = default) + public void AddInventoryItemRangeByProjectId(List items) { - await this.AddRangeAsync(items, token).ConfigureAwait(false); + this.AddRange(items); } public void UpdateInventoryItem(InventoryItem item) @@ -29,18 +29,8 @@ internal sealed partial class InventoryDbService : IInventoryDbService this.Update(item); } - public async ValueTask UpdateInventoryItemAsync(InventoryItem item, CancellationToken token = default) - { - await this.UpdateAsync(item, token).ConfigureAwait(false); - } - public List GetInventoryItemListByProjectId(Guid projectId) { return this.List(i => i.ProjectId == projectId); } - - public ValueTask> GetInventoryItemListByProjectIdAsync(Guid projectId, CancellationToken token = default) - { - return this.ListAsync(i => i.ProjectId == projectId, token); - } -} +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Inventory/InventoryService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Inventory/InventoryService.cs index 9dea0796..df843c4b 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Inventory/InventoryService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Inventory/InventoryService.cs @@ -8,7 +8,6 @@ using Snap.Hutao.Service.Metadata.ContextAbstraction; using Snap.Hutao.Service.Notification; using Snap.Hutao.Service.User; using Snap.Hutao.ViewModel.Cultivation; -using Snap.Hutao.ViewModel.User; using Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate; using Snap.Hutao.Web.Response; @@ -54,7 +53,7 @@ internal sealed partial class InventoryService : IInventoryService BatchConsumption? batchConsumption = default; using (IServiceScope scope = serviceScopeFactory.CreateScope()) { - if (!UserAndUid.TryFromUser(userService.Current, out UserAndUid? userAndUid)) + if (await userService.GetCurrentUserAndUidAsync().ConfigureAwait(false) is not { } userAndUid) { infoBarService.Warning(SH.MustSelectUserAndUid); return; @@ -76,8 +75,8 @@ internal sealed partial class InventoryService : IInventoryService if (batchConsumption is { OverallConsume: { } items }) { - await inventoryDbService.RemoveInventoryItemRangeByProjectIdAsync(project.InnerId).ConfigureAwait(false); - await inventoryDbService.AddInventoryItemRangeByProjectIdAsync(items.SelectList(item => InventoryItem.From(project.InnerId, item.Id, (uint)((int)item.Num - item.LackNum)))).ConfigureAwait(false); + inventoryDbService.RemoveInventoryItemRangeByProjectId(project.InnerId); + inventoryDbService.AddInventoryItemRangeByProjectId(items.SelectList(item => InventoryItem.From(project.InnerId, item.Id, (uint)((int)item.Num - item.LackNum)))); } } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/SpiralAbyss/ISpiralAbyssRecordDbService.cs b/src/Snap.Hutao/Snap.Hutao/Service/SpiralAbyss/ISpiralAbyssRecordDbService.cs index 3c2688f6..411b7178 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/SpiralAbyss/ISpiralAbyssRecordDbService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/SpiralAbyss/ISpiralAbyssRecordDbService.cs @@ -2,14 +2,15 @@ // Licensed under the MIT license. using Snap.Hutao.Model.Entity; +using Snap.Hutao.Service.Abstraction; namespace Snap.Hutao.Service.SpiralAbyss; -internal interface ISpiralAbyssRecordDbService +internal interface ISpiralAbyssRecordDbService : IAppDbService { - ValueTask AddSpiralAbyssEntryAsync(SpiralAbyssEntry entry); + void AddSpiralAbyssEntry(SpiralAbyssEntry entry); - ValueTask> GetSpiralAbyssEntryListByUidAsync(string uid); + Dictionary GetSpiralAbyssEntryListByUid(string uid); - ValueTask UpdateSpiralAbyssEntryAsync(SpiralAbyssEntry entry); + void UpdateSpiralAbyssEntry(SpiralAbyssEntry entry); } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/SpiralAbyss/SpiralAbyssRecordDbService.cs b/src/Snap.Hutao/Snap.Hutao/Service/SpiralAbyss/SpiralAbyssRecordDbService.cs index f19e75e5..6079a19d 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/SpiralAbyss/SpiralAbyssRecordDbService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/SpiralAbyss/SpiralAbyssRecordDbService.cs @@ -1,10 +1,8 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. -using Microsoft.EntityFrameworkCore; -using Snap.Hutao.Core.Database; using Snap.Hutao.Model.Entity; -using Snap.Hutao.Model.Entity.Database; +using Snap.Hutao.Service.Abstraction; namespace Snap.Hutao.Service.SpiralAbyss; @@ -14,36 +12,23 @@ internal sealed partial class SpiralAbyssRecordDbService : ISpiralAbyssRecordDbS { private readonly IServiceProvider serviceProvider; - public async ValueTask> GetSpiralAbyssEntryListByUidAsync(string uid) - { - using (IServiceScope scope = serviceProvider.CreateScope()) - { - AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); - List entries = await appDbContext.SpiralAbysses - .Where(s => s.Uid == uid) - .OrderByDescending(s => s.ScheduleId) - .ToListAsync() - .ConfigureAwait(false); + public IServiceProvider ServiceProvider { get => serviceProvider; } - return entries.ToDictionary(e => e.ScheduleId); - } + public Dictionary GetSpiralAbyssEntryListByUid(string uid) + { + return this.Query(query => query + .Where(s => s.Uid == uid) + .OrderByDescending(s => s.ScheduleId) + .ToDictionary(e => e.ScheduleId)); } - public async ValueTask UpdateSpiralAbyssEntryAsync(SpiralAbyssEntry entry) + public void UpdateSpiralAbyssEntry(SpiralAbyssEntry entry) { - using (IServiceScope scope = serviceProvider.CreateScope()) - { - AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); - await appDbContext.SpiralAbysses.UpdateAndSaveAsync(entry).ConfigureAwait(false); - } + this.Update(entry); } - public async ValueTask AddSpiralAbyssEntryAsync(SpiralAbyssEntry entry) + public void AddSpiralAbyssEntry(SpiralAbyssEntry entry) { - using (IServiceScope scope = serviceProvider.CreateScope()) - { - AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); - await appDbContext.SpiralAbysses.AddAndSaveAsync(entry).ConfigureAwait(false); - } + this.Add(entry); } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/SpiralAbyss/SpiralAbyssRecordService.cs b/src/Snap.Hutao/Snap.Hutao/Service/SpiralAbyss/SpiralAbyssRecordService.cs index 1e546371..6b36d762 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/SpiralAbyss/SpiralAbyssRecordService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/SpiralAbyss/SpiralAbyssRecordService.cs @@ -59,9 +59,8 @@ internal sealed partial class SpiralAbyssRecordService : ISpiralAbyssRecordServi uid = userAndUid.Uid.Value; if (spiralAbysses is null) { - Dictionary entryMap = await spiralAbyssRecordDbService - .GetSpiralAbyssEntryListByUidAsync(userAndUid.Uid.Value) - .ConfigureAwait(false); + await taskContext.SwitchToBackgroundAsync(); + Dictionary entryMap = spiralAbyssRecordDbService.GetSpiralAbyssEntryListByUid(userAndUid.Uid.Value); ArgumentNullException.ThrowIfNull(metadataContext); spiralAbysses = metadataContext.IdScheduleMap.Values @@ -127,13 +126,13 @@ internal sealed partial class SpiralAbyssRecordService : ISpiralAbyssRecordServi if (view.Entity is not null) { view.Entity.SpiralAbyss = webSpiralAbyss; - await spiralAbyssRecordDbService.UpdateSpiralAbyssEntryAsync(view.Entity).ConfigureAwait(false); + spiralAbyssRecordDbService.UpdateSpiralAbyssEntry(view.Entity); targetEntry = view.Entity; } else { SpiralAbyssEntry newEntry = SpiralAbyssEntry.From(userAndUid.Uid.Value, webSpiralAbyss); - await spiralAbyssRecordDbService.AddSpiralAbyssEntryAsync(newEntry).ConfigureAwait(false); + spiralAbyssRecordDbService.AddSpiralAbyssEntry(newEntry); targetEntry = newEntry; } diff --git a/src/Snap.Hutao/Snap.Hutao/Service/User/IUidProfilePictureDbService.cs b/src/Snap.Hutao/Snap.Hutao/Service/User/IUidProfilePictureDbService.cs index a516d4cf..79570e50 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/User/IUidProfilePictureDbService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/User/IUidProfilePictureDbService.cs @@ -8,9 +8,9 @@ namespace Snap.Hutao.Service.User; internal interface IUidProfilePictureDbService : IAppDbService { - ValueTask SingleUidProfilePictureOrDefaultByUidAsync(string uid, CancellationToken token = default); + UidProfilePicture? SingleUidProfilePictureOrDefaultByUid(string uid); - ValueTask UpdateUidProfilePictureAsync(UidProfilePicture profilePicture, CancellationToken token = default); + void UpdateUidProfilePicture(UidProfilePicture profilePicture); - ValueTask DeleteUidProfilePictureByUidAsync(string uid, CancellationToken token = default); -} + void DeleteUidProfilePictureByUid(string uid); +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/User/IUserCollectionService.cs b/src/Snap.Hutao/Snap.Hutao/Service/User/IUserCollectionService.cs index 3b3c274f..fc1bc2ba 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/User/IUserCollectionService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/User/IUserCollectionService.cs @@ -2,9 +2,6 @@ // Licensed under the MIT license. using Snap.Hutao.Core.Database; -using Snap.Hutao.ViewModel.User; -using Snap.Hutao.Web.Hoyolab.Takumi.Binding; -using System.Collections.ObjectModel; using BindingUser = Snap.Hutao.ViewModel.User.User; using EntityUser = Snap.Hutao.Model.Entity.User; @@ -12,15 +9,9 @@ namespace Snap.Hutao.Service.User; internal interface IUserCollectionService { - ValueTask> GetUserAndUidCollectionAsync(); - - ValueTask> GetUserCollectionAsync(); - - UserGameRole? GetUserGameRoleByUid(string uid); + ValueTask> GetUsersAsync(); ValueTask RemoveUserAsync(BindingUser user); ValueTask> TryCreateAndAddUserFromInputCookieAsync(InputCookie inputCookie); - - bool TryGetUserByMid(string mid, [NotNullWhen(true)] out BindingUser? user); } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/User/IUserDbService.cs b/src/Snap.Hutao/Snap.Hutao/Service/User/IUserDbService.cs index b1b9c772..07ff84f1 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/User/IUserDbService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/User/IUserDbService.cs @@ -1,17 +1,19 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. +using Snap.Hutao.Service.Abstraction; + namespace Snap.Hutao.Service.User; -internal interface IUserDbService +internal interface IUserDbService : IAppDbService { - ValueTask DeleteUserByIdAsync(Guid id); + void DeleteUserById(Guid id); - ValueTask RemoveUsersAsync(); + void RemoveAllUsers(); - ValueTask> GetUserListAsync(); + List GetUserList(); - ValueTask UpdateUserAsync(Model.Entity.User user); + void UpdateUser(Model.Entity.User user); - ValueTask ClearUserSelectionAsync(); + void ClearUserSelection(); } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/User/IUserService.cs b/src/Snap.Hutao/Snap.Hutao/Service/User/IUserService.cs index a5488eea..50fe311c 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/User/IUserService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/User/IUserService.cs @@ -10,7 +10,7 @@ namespace Snap.Hutao.Service.User; internal interface IUserService { - ValueTask> GetUserCollectionAsync(); + ValueTask> GetUsersAsync(); ValueTask> ProcessInputCookieAsync(InputCookie inputCookie); diff --git a/src/Snap.Hutao/Snap.Hutao/Service/User/ProfilePictureService.cs b/src/Snap.Hutao/Snap.Hutao/Service/User/ProfilePictureService.cs index 2d6438ef..c43e6f78 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/User/ProfilePictureService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/User/ProfilePictureService.cs @@ -24,7 +24,7 @@ internal sealed partial class ProfilePictureService : IProfilePictureService { foreach (UserGameRole userGameRole in user.UserGameRoles) { - if (await uidProfilePictureDbService.SingleUidProfilePictureOrDefaultByUidAsync(userGameRole.GameUid, token).ConfigureAwait(false) is { } profilePicture) + if (uidProfilePictureDbService.SingleUidProfilePictureOrDefaultByUid(userGameRole.GameUid) is { } profilePicture) { if (await TryUpdateUserGameRoleAsync(userGameRole, profilePicture, token).ConfigureAwait(false)) { @@ -53,8 +53,8 @@ internal sealed partial class ProfilePictureService : IProfilePictureService { UidProfilePicture profilePicture = UidProfilePicture.From(userGameRole, playerInfo.ProfilePicture); - await uidProfilePictureDbService.DeleteUidProfilePictureByUidAsync(userGameRole.GameUid, token).ConfigureAwait(false); - await uidProfilePictureDbService.UpdateUidProfilePictureAsync(profilePicture, token).ConfigureAwait(false); + uidProfilePictureDbService.DeleteUidProfilePictureByUid(userGameRole.GameUid); + uidProfilePictureDbService.UpdateUidProfilePicture(profilePicture); await TryUpdateUserGameRoleAsync(userGameRole, profilePicture, token).ConfigureAwait(false); } diff --git a/src/Snap.Hutao/Snap.Hutao/Service/User/UidProfilePictureDbService.cs b/src/Snap.Hutao/Snap.Hutao/Service/User/UidProfilePictureDbService.cs index da6887f2..a83df593 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/User/UidProfilePictureDbService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/User/UidProfilePictureDbService.cs @@ -1,7 +1,6 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. -using Microsoft.EntityFrameworkCore; using Snap.Hutao.Model.Entity; using Snap.Hutao.Service.Abstraction; @@ -15,18 +14,18 @@ internal sealed partial class UidProfilePictureDbService : IUidProfilePictureDbS public IServiceProvider ServiceProvider { get => serviceProvider; } - public ValueTask SingleUidProfilePictureOrDefaultByUidAsync(string uid, CancellationToken token = default) + public UidProfilePicture? SingleUidProfilePictureOrDefaultByUid(string uid) { - return this.QueryAsync(query => query.SingleOrDefaultAsync(n => n.Uid == uid)); + return this.Query(query => query.SingleOrDefault(n => n.Uid == uid)); } - public async ValueTask UpdateUidProfilePictureAsync(UidProfilePicture profilePicture, CancellationToken token = default) + public void UpdateUidProfilePicture(UidProfilePicture profilePicture) { - await this.UpdateAsync(profilePicture, token).ConfigureAwait(false); + this.Update(profilePicture); } - public async ValueTask DeleteUidProfilePictureByUidAsync(string uid, CancellationToken token = default) + public void DeleteUidProfilePictureByUid(string uid) { - await this.DeleteAsync(profilePicture => profilePicture.Uid == uid, token).ConfigureAwait(false); + this.Delete(profilePicture => profilePicture.Uid == uid); } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/User/UserCollectionService.cs b/src/Snap.Hutao/Snap.Hutao/Service/User/UserCollectionService.cs index 635ce40c..fb1466ee 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/User/UserCollectionService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/User/UserCollectionService.cs @@ -5,7 +5,6 @@ using CommunityToolkit.Mvvm.Messaging; using Snap.Hutao.Core.Database; using Snap.Hutao.ViewModel.User; using Snap.Hutao.Web.Hoyolab.Takumi.Binding; -using System.Collections.ObjectModel; using BindingUser = Snap.Hutao.ViewModel.User.User; using EntityUser = Snap.Hutao.Model.Entity.User; @@ -25,7 +24,7 @@ internal sealed partial class UserCollectionService : IUserCollectionService, ID private AdvancedDbCollectionView? users; - public async ValueTask> GetUserCollectionAsync() + public async ValueTask> GetUsersAsync() { // Force run in background thread, otherwise will cause reentrance await taskContext.SwitchToBackgroundAsync(); @@ -33,88 +32,40 @@ internal sealed partial class UserCollectionService : IUserCollectionService, ID { if (users is null) { - List entities = await userDbService.GetUserListAsync().ConfigureAwait(false); + List entities = userDbService.GetUserList(); List users = await entities.SelectListAsync(userInitializationService.ResumeUserAsync).ConfigureAwait(false); foreach (BindingUser user in users) { if (user.NeedDbUpdateAfterResume) { - await userDbService.UpdateUserAsync(user.Entity).ConfigureAwait(false); + userDbService.UpdateUser(user.Entity); user.NeedDbUpdateAfterResume = false; } } await taskContext.SwitchToMainThreadAsync(); this.users = new(users.ToObservableReorderableDbCollection(serviceProvider), serviceProvider); + this.users.CurrentChanged += OnCurrentUserChanged; } } return users; } - public async ValueTask> GetUserAndUidCollectionAsync() - { - if (userAndUidCollection is null) - { - await taskContext.SwitchToBackgroundAsync(); - ObservableCollection users = await GetUserCollectionAsync().ConfigureAwait(false); - List roles = []; - uidUserGameRoleMap = []; - - foreach (BindingUser user in users) - { - foreach (UserGameRole role in user.UserGameRoles) - { - roles.Add(UserAndUid.From(user.Entity, role)); - uidUserGameRoleMap[role.GameUid] = role; - } - } - - userAndUidCollection = roles.ToObservableCollection(); - } - - return userAndUidCollection; - } - public async ValueTask RemoveUserAsync(BindingUser user) { - // Sync cache - await taskContext.SwitchToMainThreadAsync(); ArgumentNullException.ThrowIfNull(users); - users.Remove(user); - userAndUidCollection?.RemoveWhere(r => r.User.Mid == user.Entity.Mid); - if (user.Entity.Mid is not null) - { - midUserMap?.Remove(user.Entity.Mid); - } - - foreach (UserGameRole role in user.UserGameRoles) - { - uidUserGameRoleMap?.Remove(role.GameUid); - } // Sync database await taskContext.SwitchToBackgroundAsync(); - await userDbService.DeleteUserByIdAsync(user.Entity.InnerId).ConfigureAwait(false); + userDbService.DeleteUserById(user.Entity.InnerId); - messenger.Send(new UserRemovedMessage(user.Entity)); - } + // Sync cache + await taskContext.SwitchToMainThreadAsync(); + users.Remove(user); - public UserGameRole? GetUserGameRoleByUid(string uid) - { - if (uidUserGameRoleMap is null) - { - return default; - } - - return uidUserGameRoleMap.GetValueOrDefault(uid); - } - - public bool TryGetUserByMid(string mid, [NotNullWhen(true)] out BindingUser? user) - { - ArgumentNullException.ThrowIfNull(midUserMap); - return midUserMap.TryGetValue(mid, out user); + messenger.Send(new UserRemovedMessage(user)); } public async ValueTask> TryCreateAndAddUserFromInputCookieAsync(InputCookie inputCookie) @@ -127,25 +78,12 @@ internal sealed partial class UserCollectionService : IUserCollectionService, ID return new(UserOptionResult.CookieInvalid, SH.ServiceUserProcessCookieRequestUserInfoFailed); } - await GetUserCollectionAsync().ConfigureAwait(false); + await GetUsersAsync().ConfigureAwait(false); ArgumentNullException.ThrowIfNull(users); // Sync cache await taskContext.SwitchToMainThreadAsync(); users.Add(newUser); // Database synced in the collection - if (newUser.Entity.Mid is not null) - { - midUserMap?.Add(newUser.Entity.Mid, newUser); - } - - if (userAndUidCollection is not null) - { - foreach (UserGameRole role in newUser.UserGameRoles) - { - userAndUidCollection.Add(new(newUser.Entity, role)); - uidUserGameRoleMap?.Add(role.GameUid, role); - } - } ArgumentNullException.ThrowIfNull(newUser.UserInfo); return new(UserOptionResult.Added, newUser.UserInfo.Uid); @@ -155,4 +93,41 @@ internal sealed partial class UserCollectionService : IUserCollectionService, ID { throttler.Dispose(); } + + private void OnCurrentUserChanged(object? sender, object? args) + { + if (users is null) + { + messenger.Send(UserAndUidChangedMessage.Empty); + return; + } + + if (users.CurrentItem is null) + { + messenger.Send(UserAndUidChangedMessage.Empty); + return; + } + + // Suppress the BindingUser itself to raise the message + // This is to avoid the message being raised in the + // BindingUser.OnCurrentUserGameRoleChanged. + using (users.CurrentItem.SuppressCurrentUserGameRoleChangedMessage()) + { + foreach (UserGameRole role in users.CurrentItem.UserGameRoles) + { + if (role.GameUid == users.CurrentItem.PreferredUid) + { + users.CurrentItem.UserGameRoles.MoveCurrentTo(role); + break; + } + } + + if (users.CurrentItem.UserGameRoles.CurrentItem is null) + { + users.CurrentItem.UserGameRoles.MoveCurrentToFirst(); + } + } + + messenger.Send(new UserAndUidChangedMessage(users.CurrentItem)); + } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/User/UserDbService.cs b/src/Snap.Hutao/Snap.Hutao/Service/User/UserDbService.cs index 9e9630b7..f9f4f245 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/User/UserDbService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/User/UserDbService.cs @@ -2,8 +2,7 @@ // Licensed under the MIT license. using Microsoft.EntityFrameworkCore; -using Snap.Hutao.Core.Database; -using Snap.Hutao.Model.Entity.Database; +using Snap.Hutao.Service.Abstraction; namespace Snap.Hutao.Service.User; @@ -13,48 +12,30 @@ internal sealed partial class UserDbService : IUserDbService { private readonly IServiceProvider serviceProvider; - public async ValueTask DeleteUserByIdAsync(Guid id) + public IServiceProvider ServiceProvider { get => serviceProvider; } + + public void DeleteUserById(Guid id) { - using (IServiceScope scope = serviceProvider.CreateScope()) - { - AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); - await appDbContext.Users.Where(u => u.InnerId == id).ExecuteDeleteAsync().ConfigureAwait(false); - } + this.DeleteByInnerId(id); } - public async ValueTask> GetUserListAsync() + public List GetUserList() { - using (IServiceScope scope = serviceProvider.CreateScope()) - { - AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); - return await appDbContext.Users.AsNoTracking().ToListAsync().ConfigureAwait(false); - } + return this.List(); } - public async ValueTask UpdateUserAsync(Model.Entity.User user) + public void UpdateUser(Model.Entity.User user) { - using (IServiceScope scope = serviceProvider.CreateScope()) - { - AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); - await appDbContext.Users.UpdateAndSaveAsync(user).ConfigureAwait(false); - } + this.Update(user); } - public async ValueTask RemoveUsersAsync() + public void RemoveAllUsers() { - using (IServiceScope scope = serviceProvider.CreateScope()) - { - AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); - await appDbContext.Users.ExecuteDeleteAsync().ConfigureAwait(false); - } + this.Delete(); } - public async ValueTask ClearUserSelectionAsync() + public void ClearUserSelection() { - using (IServiceScope scope = serviceProvider.CreateScope()) - { - AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); - await appDbContext.Users.ExecuteUpdateAsync(update => update.SetProperty(user => user.IsSelected, user => false)).ConfigureAwait(false); - } + this.Execute(dbset => dbset.ExecuteUpdate(update => update.SetProperty(user => user.IsSelected, user => false))); } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/User/UserInitializationService.cs b/src/Snap.Hutao/Snap.Hutao/Service/User/UserInitializationService.cs index a310752c..137ee3bb 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/User/UserInitializationService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/User/UserInitializationService.cs @@ -18,6 +18,7 @@ internal sealed partial class UserInitializationService : IUserInitializationSer private readonly IUserFingerprintService userFingerprintService; private readonly IProfilePictureService profilePictureService; private readonly IServiceProvider serviceProvider; + private readonly ITaskContext taskContext; public async ValueTask ResumeUserAsync(Model.Entity.User inner, CancellationToken token = default) { @@ -210,7 +211,8 @@ internal sealed partial class UserInitializationService : IUserInitializationSer if (userGameRolesResponse.IsOk()) { - user.UserGameRoles = userGameRolesResponse.Data.List; + await taskContext.SwitchToMainThreadAsync(); + user.UserGameRoles = new(userGameRolesResponse.Data.List, true); return user.UserGameRoles.Count > 0; } else diff --git a/src/Snap.Hutao/Snap.Hutao/Service/User/UserRemovedMessage.cs b/src/Snap.Hutao/Snap.Hutao/Service/User/UserRemovedMessage.cs new file mode 100644 index 00000000..ebc289f0 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Service/User/UserRemovedMessage.cs @@ -0,0 +1,16 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using BindingUser = Snap.Hutao.ViewModel.User.User; + +namespace Snap.Hutao.Service.User; + +internal sealed class UserRemovedMessage +{ + public UserRemovedMessage(BindingUser removedUser) + { + RemovedUser = removedUser; + } + + public BindingUser RemovedUser { get; } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/User/UserService.cs b/src/Snap.Hutao/Snap.Hutao/Service/User/UserService.cs index 14166477..65ddf9e9 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/User/UserService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/User/UserService.cs @@ -8,8 +8,6 @@ using Snap.Hutao.Web.Hoyolab; using Snap.Hutao.Web.Hoyolab.Passport; using Snap.Hutao.Web.Hoyolab.Takumi.Binding; using Snap.Hutao.Web.Response; -using System.Collections.ObjectModel; -using Windows.Foundation; using BindingUser = Snap.Hutao.ViewModel.User.User; using EntityUser = Snap.Hutao.Model.Entity.User; @@ -33,22 +31,12 @@ internal sealed partial class UserService : IUserService, IUserServiceUnsafe public async ValueTask UnsafeRemoveAllUsersAsync() { await taskContext.SwitchToBackgroundAsync(); - await userDbService.RemoveUsersAsync().ConfigureAwait(false); + userDbService.RemoveAllUsers(); } - public ValueTask> GetUserCollectionAsync() + public ValueTask> GetUsersAsync() { - return userCollectionService.GetUserCollectionAsync(); - } - - public ValueTask> GetRoleCollectionAsync() - { - return userCollectionService.GetUserAndUidCollectionAsync(); - } - - public UserGameRole? GetUserGameRoleByUid(string uid) - { - return userCollectionService.GetUserGameRoleByUid(uid); + return userCollectionService.GetUsersAsync(); } public async ValueTask> ProcessInputCookieAsync(InputCookie inputCookie) @@ -64,7 +52,7 @@ internal sealed partial class UserService : IUserService, IUserServiceUnsafe } // 检查 mid 对应用户是否存在 - if (!userCollectionService.TryGetUserByMid(midOrAid, out BindingUser? user)) + if (await this.GetUserByMidAsync(midOrAid).ConfigureAwait(false) is not { } user) { return await userCollectionService.TryCreateAndAddUserFromInputCookieAsync(inputCookie).ConfigureAwait(false); } @@ -79,11 +67,11 @@ internal sealed partial class UserService : IUserService, IUserServiceUnsafe user.CookieToken = cookie.TryGetCookieToken(out Cookie? cookieToken) ? cookieToken : user.CookieToken; user.TryUpdateFingerprint(deviceFp); - await userDbService.UpdateUserAsync(user.Entity).ConfigureAwait(false); + userDbService.UpdateUser(user.Entity); return new(UserOptionResult.CookieUpdated, midOrAid); } - public async ValueTask RefreshCookieTokenAsync(Model.Entity.User user) + public async ValueTask RefreshCookieTokenAsync(EntityUser user) { // TODO: 提醒其他组件此用户的Cookie已更改 Response cookieTokenResponse; @@ -108,9 +96,8 @@ internal sealed partial class UserService : IUserService, IUserServiceUnsafe // Check null and create a new one to avoid System.NullReferenceException user.CookieToken ??= new(); - // Sync ui and database user.CookieToken[Cookie.COOKIE_TOKEN] = cookieToken; - await userDbService.UpdateUserAsync(user).ConfigureAwait(false); + userDbService.UpdateUser(user); return true; } diff --git a/src/Snap.Hutao/Snap.Hutao/Service/User/UserServiceExtension.cs b/src/Snap.Hutao/Snap.Hutao/Service/User/UserServiceExtension.cs index d29f3272..2f4e25be 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/User/UserServiceExtension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/User/UserServiceExtension.cs @@ -1,7 +1,11 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. +using Snap.Hutao.Core.Database; +using Snap.Hutao.ViewModel.User; +using Snap.Hutao.Web.Hoyolab.Takumi.Binding; using BindingUser = Snap.Hutao.ViewModel.User.User; +using EntityUser = Snap.Hutao.Model.Entity.User; namespace Snap.Hutao.Service.User; @@ -11,4 +15,40 @@ internal static class UserServiceExtension { return userService.RefreshCookieTokenAsync(user.Entity); } + + public static async ValueTask GetUserGameRoleByUidAsync(this IUserService userService, string uid) + { + AdvancedDbCollectionView users = await userService.GetUsersAsync().ConfigureAwait(false); + foreach (BindingUser user in users.SourceCollection) + { + foreach (UserGameRole role in user.UserGameRoles) + { + if (role.GameUid == uid) + { + return role; + } + } + } + + return null; + } + + public static async ValueTask GetCurrentUidAsync(this IUserService userService) + { + AdvancedDbCollectionView users = await userService.GetUsersAsync().ConfigureAwait(false); + return users.CurrentItem?.UserGameRoles?.CurrentItem?.GameUid; + } + + public static async ValueTask GetCurrentUserAndUidAsync(this IUserService userService) + { + AdvancedDbCollectionView users = await userService.GetUsersAsync().ConfigureAwait(false); + UserAndUid.TryFromUser(users.CurrentItem, out UserAndUid? userAndUid); + return userAndUid; + } + + public static async ValueTask GetUserByMidAsync(this IUserService userService, string mid) + { + AdvancedDbCollectionView users = await userService.GetUsersAsync().ConfigureAwait(false); + return users.SourceCollection.SingleOrDefault(u => u.Entity.Mid == mid); + } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/UI/Xaml/View/Dialog/CultivateProjectDialog.xaml.cs b/src/Snap.Hutao/Snap.Hutao/UI/Xaml/View/Dialog/CultivateProjectDialog.xaml.cs index 6429cc48..5c35ad0f 100644 --- a/src/Snap.Hutao/Snap.Hutao/UI/Xaml/View/Dialog/CultivateProjectDialog.xaml.cs +++ b/src/Snap.Hutao/Snap.Hutao/UI/Xaml/View/Dialog/CultivateProjectDialog.xaml.cs @@ -15,6 +15,7 @@ namespace Snap.Hutao.UI.Xaml.View.Dialog; [DependencyProperty("IsUidAttached", typeof(bool))] internal sealed partial class CultivateProjectDialog : ContentDialog { + private readonly IServiceProvider serviceProvider; private readonly ITaskContext taskContext; /// @@ -25,6 +26,7 @@ internal sealed partial class CultivateProjectDialog : ContentDialog { InitializeComponent(); + this.serviceProvider = serviceProvider; taskContext = serviceProvider.GetRequiredService(); } @@ -39,7 +41,7 @@ internal sealed partial class CultivateProjectDialog : ContentDialog if (result == ContentDialogResult.Primary) { string? uid = IsUidAttached - ? Ioc.Default.GetRequiredService().Current?.SelectedUserGameRole?.GameUid + ? await serviceProvider.GetRequiredService().GetCurrentUidAsync().ConfigureAwait(false) : null; return new(true, CultivateProject.From(Text, uid)); diff --git a/src/Snap.Hutao/Snap.Hutao/UI/Xaml/View/MainView.xaml.cs b/src/Snap.Hutao/Snap.Hutao/UI/Xaml/View/MainView.xaml.cs index 691a0a29..8a59935a 100644 --- a/src/Snap.Hutao/Snap.Hutao/UI/Xaml/View/MainView.xaml.cs +++ b/src/Snap.Hutao/Snap.Hutao/UI/Xaml/View/MainView.xaml.cs @@ -17,9 +17,6 @@ internal sealed partial class MainView : UserControl { private readonly INavigationService navigationService; - /// - /// 构造一个新的主视图 - /// public MainView() { IServiceProvider serviceProvider = Ioc.Default; @@ -28,7 +25,7 @@ internal sealed partial class MainView : UserControl InitializeComponent(); - this.Unloaded += OnUnloaded; + Unloaded += OnUnloaded; (DataContext as MainViewModel)?.Initialize(new BackgroundImagePresenterAccessor(BackgroundImagePresenter)); diff --git a/src/Snap.Hutao/Snap.Hutao/UI/Xaml/View/Page/CultivationPage.xaml b/src/Snap.Hutao/Snap.Hutao/UI/Xaml/View/Page/CultivationPage.xaml index b409ac95..4dd41976 100644 --- a/src/Snap.Hutao/Snap.Hutao/UI/Xaml/View/Page/CultivationPage.xaml +++ b/src/Snap.Hutao/Snap.Hutao/UI/Xaml/View/Page/CultivationPage.xaml @@ -354,7 +354,7 @@ - - - - - /// 用户 - /// 用户与角色 - /// 是否转换成功 public static bool TryFromUser([NotNullWhen(true)] User? user, [NotNullWhen(true)] out UserAndUid? userAndUid) { - if (user is not null && user.SelectedUserGameRole is not null) + if (user is { UserGameRoles.CurrentItem: { } role }) { - userAndUid = new UserAndUid(user.Entity, user.SelectedUserGameRole); + userAndUid = new UserAndUid(user.Entity, role); return true; } diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/User/UserAndUidChangedMessage.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/User/UserAndUidChangedMessage.cs new file mode 100644 index 00000000..18d8c13b --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/User/UserAndUidChangedMessage.cs @@ -0,0 +1,27 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +namespace Snap.Hutao.ViewModel.User; + +internal sealed class UserAndUidChangedMessage +{ + public static readonly UserAndUidChangedMessage Empty = new(null); + + public UserAndUidChangedMessage(User? user) + { + User = user; + if (UserAndUid.TryFromUser(user, out UserAndUid? userAndUid)) + { + UserAndUid = userAndUid; + } + } + + public User? User { get; set; } + + public UserAndUid? UserAndUid { get; } + + public static UserAndUidChangedMessage FromUser(User? user) + { + return new(user); + } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/User/UserViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/User/UserViewModel.cs index edb59f77..b7f12a6a 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/User/UserViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/User/UserViewModel.cs @@ -40,66 +40,18 @@ internal sealed partial class UserViewModel : ObservableObject private readonly ITaskContext taskContext; private readonly IUserService userService; - private User? selectedUser; - private ObservableReorderableDbCollection? users; + private AdvancedDbCollectionView? users; public RuntimeOptions RuntimeOptions { get => runtimeOptions; } - /// - /// 当前选择的用户信息 - /// - public User? SelectedUser - { - get => selectedUser ??= userService.Current; - set - { - if (value is not null) - { - // Should not raise propery changed event below - if (value.PreferredUid is not null) - { - value.SetSelectedUserGameRole(value.UserGameRoles.FirstOrDefault(role => role.GameUid == value.PreferredUid), false); - } + public AdvancedDbCollectionView? Users { get => users; set => SetProperty(ref users, value); } - if (value.SelectedUserGameRole is null) - { - value.SetSelectedUserGameRole(value.UserGameRoles.FirstOrFirstOrDefault(role => role.IsChosen), false); - } - } - - if (!ReferenceEquals(selectedUser, value)) - { - selectedUser = value; - userService.Current = value; - } - - OnPropertyChanged(nameof(SelectedUser)); - } - } - - /// - /// 用户信息集合 - /// - public ObservableReorderableDbCollection? Users { get => users; set => SetProperty(ref users, value); } - - /// - /// 处理用户操作结果 - /// - /// 操作结果 - /// uid - /// 任务 - internal async ValueTask HandleUserOptionResultAsync(UserOptionResult optionResult, string uid) + internal void HandleUserOptionResult(UserOptionResult optionResult, string uid) { switch (optionResult) { case UserOptionResult.Added: ArgumentNullException.ThrowIfNull(Users); - if (Users.Count == 1) - { - await taskContext.SwitchToMainThreadAsync(); - SelectedUser = Users.Single(); - } - infoBarService.Success(SH.FormatViewModelUserAdded(uid)); break; case UserOptionResult.CookieIncomplete: @@ -116,13 +68,13 @@ internal sealed partial class UserViewModel : ObservableObject } } - [Command("OpenUICommand")] - private async Task OpenUIAsync() + [Command("LoadCommand")] + private async Task LoadAsync() { try { - Users = await userService.GetUserCollectionAsync().ConfigureAwait(true); - SelectedUser = userService.Current; + Users = await userService.GetUsersAsync().ConfigureAwait(true); + Users.MoveCurrentToFirst(); } catch (HutaoException ex) { @@ -156,7 +108,7 @@ internal sealed partial class UserViewModel : ObservableObject { Cookie cookie = Cookie.Parse(rawCookie); (UserOptionResult optionResult, string uid) = await userService.ProcessInputCookieAsync(InputCookie.CreateWithDeviceFpInference(cookie, isOversea)).ConfigureAwait(false); - await HandleUserOptionResultAsync(optionResult, uid).ConfigureAwait(false); + HandleUserOptionResult(optionResult, uid); } } @@ -205,7 +157,7 @@ internal sealed partial class UserViewModel : ObservableObject { Cookie stokenV2 = Cookie.FromLoginResult(sTokenResponse.Data); (UserOptionResult optionResult, string uid) = await userService.ProcessInputCookieAsync(InputCookie.CreateWithDeviceFpInference(stokenV2, false)).ConfigureAwait(false); - await HandleUserOptionResultAsync(optionResult, uid).ConfigureAwait(false); + HandleUserOptionResult(optionResult, uid); } } @@ -219,9 +171,9 @@ internal sealed partial class UserViewModel : ObservableObject try { - if (user.IsSelected) + if (ReferenceEquals(users?.CurrentItem, user)) { - SelectedUser = default; + users.MoveCurrentToFirst(); } await userService.RemoveUserAsync(user).ConfigureAwait(false); @@ -260,12 +212,12 @@ internal sealed partial class UserViewModel : ObservableObject [Command("RefreshCookieTokenCommand")] private async Task RefreshCookieTokenAsync() { - if (SelectedUser is null) + if (users?.CurrentItem is null) { return; } - if (await userService.RefreshCookieTokenAsync(SelectedUser).ConfigureAwait(false)) + if (await userService.RefreshCookieTokenAsync(users.CurrentItem).ConfigureAwait(false)) { infoBarService.Success(SH.ViewUserRefreshCookieTokenSuccess); } @@ -278,7 +230,7 @@ internal sealed partial class UserViewModel : ObservableObject [Command("ClaimSignInRewardCommand")] private async Task ClaimSignInRewardAsync(AppBarButton? appBarButton) { - if (!UserAndUid.TryFromUser(SelectedUser, out UserAndUid? userAndUid)) + if (await userService.GetCurrentUserAndUidAsync().ConfigureAwait(false) is not { } userAndUid) { infoBarService.Warning(SH.MustSelectUserAndUid); return; diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WikiAvatarViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WikiAvatarViewModel.cs index 425b7553..72ecbc79 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WikiAvatarViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WikiAvatarViewModel.cs @@ -20,7 +20,6 @@ using Snap.Hutao.Service.User; using Snap.Hutao.UI.Xaml.Control.AutoSuggestBox; using Snap.Hutao.UI.Xaml.Data; using Snap.Hutao.UI.Xaml.View.Dialog; -using Snap.Hutao.ViewModel.User; using Snap.Hutao.Web.Response; using System.Collections.Frozen; using System.Collections.ObjectModel; @@ -162,7 +161,7 @@ internal sealed partial class WikiAvatarViewModel : Abstraction.ViewModel return; } - if (!UserAndUid.TryFromUser(userService.Current, out UserAndUid? userAndUid)) + if (await userService.GetCurrentUserAndUidAsync().ConfigureAwait(false) is not { } userAndUid) { infoBarService.Warning(SH.MustSelectUserAndUid); return; diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WikiWeaponViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WikiWeaponViewModel.cs index 726aa428..c254b240 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WikiWeaponViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WikiWeaponViewModel.cs @@ -20,7 +20,6 @@ using Snap.Hutao.Service.User; using Snap.Hutao.UI.Xaml.Control.AutoSuggestBox; using Snap.Hutao.UI.Xaml.Data; using Snap.Hutao.UI.Xaml.View.Dialog; -using Snap.Hutao.ViewModel.User; using Snap.Hutao.Web.Response; using System.Collections.Frozen; using System.Collections.ObjectModel; @@ -153,7 +152,7 @@ internal sealed partial class WikiWeaponViewModel : Abstraction.ViewModel return; } - if (!UserAndUid.TryFromUser(userService.Current, out UserAndUid? userAndUid)) + if (await userService.GetCurrentUserAndUidAsync().ConfigureAwait(false) is not { } userAndUid) { infoBarService.Warning(SH.MustSelectUserAndUid); return; diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Binding/UserGameRole.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Binding/UserGameRole.cs index e08f24cd..d8e1febb 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Binding/UserGameRole.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Binding/UserGameRole.cs @@ -2,71 +2,40 @@ // Licensed under the MIT license. using CommunityToolkit.Mvvm.ComponentModel; -using CommunityToolkit.Mvvm.Input; using Snap.Hutao.Service.User; +using Snap.Hutao.UI.Xaml.Data; namespace Snap.Hutao.Web.Hoyolab.Takumi.Binding; -/// -/// 用户游戏角色 -/// -[HighQuality] -internal sealed class UserGameRole : ObservableObject +internal sealed partial class UserGameRole : ObservableObject, IAdvancedCollectionViewItem { private string? profilePictureIcon; - private ICommand? refreshProfilePictureCommand; - /// - /// hk4e_cn for Genshin Impact - /// [JsonPropertyName("game_biz")] public string GameBiz { get; set; } = default!; - /// - /// 服务器 - /// [JsonPropertyName("region")] public Region Region { get; set; } = default!; - /// - /// 游戏Uid - /// [JsonPropertyName("game_uid")] public string GameUid { get; set; } = default!; - /// - /// 昵称 - /// [JsonPropertyName("nickname")] public string Nickname { get; set; } = default!; - /// - /// 等级 - /// [JsonPropertyName("level")] public int Level { get; set; } - /// - /// 是否选中 - /// [JsonPropertyName("is_chosen")] public bool IsChosen { get; set; } - /// - /// 地区名称 - /// [JsonPropertyName("region_name")] public string RegionName { get; set; } = default!; - /// - /// 是否为官服 - /// [JsonPropertyName("is_official")] public bool IsOfficial { get; set; } = default!; - /// - /// 玩家服务器与等级简述 - /// + [JsonIgnore] public string Description { get => $"{RegionName} | Lv.{Level}"; @@ -79,11 +48,6 @@ internal sealed class UserGameRole : ObservableObject set => SetProperty(ref profilePictureIcon, value); } - public ICommand RefreshProfilePictureCommand - { - get => refreshProfilePictureCommand ??= new AsyncRelayCommand(RefreshProfilePictureAsync); - } - public static implicit operator PlayerUid(UserGameRole userGameRole) { return new PlayerUid(userGameRole.GameUid, userGameRole.Region); @@ -95,7 +59,15 @@ internal sealed class UserGameRole : ObservableObject return $"{Nickname} | {RegionName} | Lv.{Level}"; } - [SuppressMessage("", "SH003")] + public object? GetPropertyValue(string name) + { + return name switch + { + _ => default, + }; + } + + [Command("RefreshProfilePictureCommand")] private async Task RefreshProfilePictureAsync() { await Ioc.Default.GetRequiredService().RefreshProfilePictureAsync(this).ConfigureAwait(false);