diff --git a/src/Snap.Hutao/Snap.Hutao.SourceGeneration/DedendencyInjection/InjectionGenerator.cs b/src/Snap.Hutao/Snap.Hutao.SourceGeneration/DedendencyInjection/InjectionGenerator.cs
index 9dc87951..9fcfb952 100644
--- a/src/Snap.Hutao/Snap.Hutao.SourceGeneration/DedendencyInjection/InjectionGenerator.cs
+++ b/src/Snap.Hutao/Snap.Hutao.SourceGeneration/DedendencyInjection/InjectionGenerator.cs
@@ -22,6 +22,7 @@ public class InjectionGenerator : ISourceGenerator
{
private const string InjectAsSingletonName = "Snap.Hutao.Core.DependencyInjection.Annotation.InjectAs.Singleton";
private const string InjectAsTransientName = "Snap.Hutao.Core.DependencyInjection.Annotation.InjectAs.Transient";
+ private const string InjectAsScopedName = "Snap.Hutao.Core.DependencyInjection.Annotation.InjectAs.Scoped";
///
public void Initialize(GeneratorInitializationContext context)
@@ -97,8 +98,11 @@ internal static partial class ServiceCollectionExtensions
case InjectAsTransientName:
lineBuilder.Append(@" services.AddTransient(");
break;
+ case InjectAsScopedName:
+ lineBuilder.Append(@" services.AddScoped(");
+ break;
default:
- throw new InvalidOperationException($"非法的InjectAs值: [{injectAsName}]");
+ throw new InvalidOperationException($"非法的 InjectAs 值: [{injectAsName}]");
}
if (arguments.Length == 2)
diff --git a/src/Snap.Hutao/Snap.Hutao/Control/ScopedPage.cs b/src/Snap.Hutao/Snap.Hutao/Control/ScopedPage.cs
index 88b6d70b..841049cf 100644
--- a/src/Snap.Hutao/Snap.Hutao/Control/ScopedPage.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Control/ScopedPage.cs
@@ -28,9 +28,6 @@ public class ScopedPage : Page
serviceScope = Ioc.Default.CreateScope();
}
- ///
- public IServiceProvider ServiceProvider { get => serviceScope.ServiceProvider; }
-
///
/// 初始化
///
@@ -38,7 +35,7 @@ public class ScopedPage : Page
public void InitializeWith()
where TViewModel : class, ISupportCancellation
{
- ISupportCancellation viewModel = ServiceProvider.GetRequiredService();
+ ISupportCancellation viewModel = serviceScope.ServiceProvider.GetRequiredService();
viewModel.CancellationToken = viewLoadingCancellationTokenSource.Token;
DataContext = viewModel;
}
diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Caching/CacheBase.cs b/src/Snap.Hutao/Snap.Hutao/Core/Caching/CacheBase.cs
index c02db516..e2ce01a9 100644
--- a/src/Snap.Hutao/Snap.Hutao/Core/Caching/CacheBase.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Core/Caching/CacheBase.cs
@@ -23,6 +23,8 @@ public abstract class CacheBase
{
private readonly SemaphoreSlim cacheFolderSemaphore = new(1);
private readonly ILogger logger;
+
+ // violate di rule
private readonly HttpClient httpClient;
private StorageFolder? baseFolder;
diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Database/DbCurrent.cs b/src/Snap.Hutao/Snap.Hutao/Core/Database/DbCurrent.cs
index bb05fa6d..bc3add7e 100644
--- a/src/Snap.Hutao/Snap.Hutao/Core/Database/DbCurrent.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Core/Database/DbCurrent.cs
@@ -3,7 +3,6 @@
using CommunityToolkit.Mvvm.Messaging;
using Microsoft.EntityFrameworkCore;
-using Snap.Hutao.Extension;
namespace Snap.Hutao.Core.Database;
@@ -17,7 +16,6 @@ internal class DbCurrent
where TEntity : class, ISelectable
where TMessage : Message.ValueChangedMessage, new()
{
- private readonly DbContext dbContext;
private readonly DbSet dbSet;
private readonly IMessenger messenger;
@@ -31,7 +29,6 @@ internal class DbCurrent
///
public DbCurrent(DbSet dbSet, IMessenger messenger)
{
- this.dbContext = dbSet.Context();
this.dbSet = dbSet;
this.messenger = messenger;
}
diff --git a/src/Snap.Hutao/Snap.Hutao/Extension/DbSetExtension.cs b/src/Snap.Hutao/Snap.Hutao/Core/Database/DbSetExtension.cs
similarity index 67%
rename from src/Snap.Hutao/Snap.Hutao/Extension/DbSetExtension.cs
rename to src/Snap.Hutao/Snap.Hutao/Core/Database/DbSetExtension.cs
index aac80a60..e0e87e8f 100644
--- a/src/Snap.Hutao/Snap.Hutao/Extension/DbSetExtension.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Core/Database/DbSetExtension.cs
@@ -4,7 +4,7 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
-namespace Snap.Hutao.Extension;
+namespace Snap.Hutao.Core.Database;
///
/// 数据库集合上下文
@@ -50,6 +50,34 @@ public static class DbSetExtension
return entry;
}
+ ///
+ /// 添加并保存
+ ///
+ /// 实体类型
+ /// 数据库集
+ /// 实体
+ /// 影响条数
+ public static int AddAndSave(this DbSet dbSet, TEntity entity)
+ where TEntity : class
+ {
+ dbSet.Add(entity);
+ return dbSet.Context().SaveChanges();
+ }
+
+ ///
+ /// 移除并保存
+ ///
+ /// 实体类型
+ /// 数据库集
+ /// 实体
+ /// 影响条数
+ public static int RemoveAndSave(this DbSet dbSet, TEntity entity)
+ where TEntity : class
+ {
+ dbSet.Remove(entity);
+ return dbSet.Context().SaveChanges();
+ }
+
///
/// 更新并保存
///
diff --git a/src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/Annotation/InjectAs.cs b/src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/Annotation/InjectAs.cs
index a9f36cfc..c970b34c 100644
--- a/src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/Annotation/InjectAs.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/Annotation/InjectAs.cs
@@ -17,4 +17,9 @@ public enum InjectAs
/// 指示应注册为短期对象
///
Transient,
+
+ ///
+ /// 指示应注册为范围对象
+ ///
+ Scoped,
}
diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Json/Converter/SeparatorCommaInt32EnumerableConverter.cs b/src/Snap.Hutao/Snap.Hutao/Core/Json/Converter/SeparatorCommaInt32EnumerableConverter.cs
index 14bef433..40142bb0 100644
--- a/src/Snap.Hutao/Snap.Hutao/Core/Json/Converter/SeparatorCommaInt32EnumerableConverter.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Core/Json/Converter/SeparatorCommaInt32EnumerableConverter.cs
@@ -21,4 +21,4 @@ internal class SeparatorCommaInt32EnumerableConverter : JsonConverter
internal static class SettingKeys
{
- ///
- /// 上次打开时App的版本
- ///
- public const string LastAppVersion = "LastAppVersion";
-
///
/// 窗体左侧
///
diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Validation/Must.cs b/src/Snap.Hutao/Snap.Hutao/Core/Validation/Must.cs
index 09a31df1..10f37bf9 100644
--- a/src/Snap.Hutao/Snap.Hutao/Core/Validation/Must.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Core/Validation/Must.cs
@@ -38,18 +38,6 @@ public static class Must
}
}
- ///
- /// 任务异常
- ///
- /// 异常消息
- /// 异常的任务
- [SuppressMessage("", "VSTHRD200")]
- public static Task Fault(string message)
- {
- InvalidOperationException exception = new(message);
- return Task.FromException(exception);
- }
-
///
/// 任务异常
///
diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Binding/Achievement.cs b/src/Snap.Hutao/Snap.Hutao/Model/Binding/Achievement.cs
index 9d7ffa72..d0c3e409 100644
--- a/src/Snap.Hutao/Snap.Hutao/Model/Binding/Achievement.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Model/Binding/Achievement.cs
@@ -1,12 +1,14 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
+using CommunityToolkit.Mvvm.ComponentModel;
+
namespace Snap.Hutao.Model.Binding;
///
/// 用于视图绑定的成就
///
-public class Achievement : Observable
+public class Achievement : ObservableObject
{
///
/// 满进度占位符
@@ -28,7 +30,7 @@ public class Achievement : Observable
this.inner = inner;
this.entity = entity;
- // Property should only be set when is user checking.
+ // Property should only be set when it's user checking.
isChecked = (int)entity.Status >= 2;
}
@@ -50,7 +52,7 @@ public class Achievement : Observable
get => isChecked;
set
{
- Set(ref isChecked, value);
+ SetProperty(ref isChecked, value);
// Only update state when checked
if (value)
@@ -67,6 +69,6 @@ public class Achievement : Observable
///
public string Time
{
- get => entity.Time.ToString("yyyy-MM-dd HH:mm:ss");
+ get => entity.Time.ToString("yyyy.MM.dd HH:mm:ss");
}
}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Binding/User.cs b/src/Snap.Hutao/Snap.Hutao/Model/Binding/User.cs
index 5fcd09d8..1df4de43 100644
--- a/src/Snap.Hutao/Snap.Hutao/Model/Binding/User.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Model/Binding/User.cs
@@ -1,6 +1,7 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
+using CommunityToolkit.Mvvm.ComponentModel;
using Snap.Hutao.Extension;
using Snap.Hutao.Web.Hoyolab;
using Snap.Hutao.Web.Hoyolab.Bbs.User;
@@ -12,7 +13,7 @@ namespace Snap.Hutao.Model.Binding;
///
/// 用于视图绑定的用户
///
-public class User : Observable
+public class User : ObservableObject
{
private readonly EntityUser inner;
@@ -44,7 +45,7 @@ public class User : Observable
public UserGameRole? SelectedUserGameRole
{
get => selectedUserGameRole;
- private set => Set(ref selectedUserGameRole, value);
+ private set => SetProperty(ref selectedUserGameRole, value);
}
///
@@ -58,7 +59,19 @@ public class User : Observable
public Cookie Cookie
{
get => inner.Cookie;
- set => inner.Cookie = value;
+ set
+ {
+ inner.Cookie = value;
+ OnPropertyChanged(nameof(HasSToken));
+ }
+ }
+
+ ///
+ /// 是否拥有 SToken
+ ///
+ public bool HasSToken
+ {
+ get => inner.Cookie.ContainsSToken();
}
///
@@ -71,6 +84,17 @@ public class User : Observable
///
public bool IsInitialized { get => isInitialized; }
+ ///
+ /// 更新SToken
+ ///
+ /// uid
+ /// cookie
+ internal void UpdateSToken(string uid, Cookie cookie)
+ {
+ Cookie.InsertSToken(uid, cookie);
+ OnPropertyChanged(nameof(HasSToken));
+ }
+
///
/// 从数据库恢复用户
///
@@ -79,11 +103,7 @@ public class User : Observable
/// 角色客户端
/// 取消令牌
/// 用户是否初始化完成,若Cookie失效会返回
- internal static async Task ResumeAsync(
- EntityUser inner,
- UserClient userClient,
- BindingClient userGameRoleClient,
- CancellationToken token = default)
+ internal static async Task ResumeAsync(EntityUser inner, UserClient userClient, BindingClient userGameRoleClient, CancellationToken token = default)
{
User user = new(inner);
bool successful = await user.InitializeCoreAsync(userClient, userGameRoleClient, token).ConfigureAwait(false);
@@ -98,36 +118,20 @@ public class User : Observable
/// 角色客户端
/// 取消令牌
/// 用户是否初始化完成,若Cookie失效会返回
- internal static async Task CreateAsync(
- Cookie cookie,
- UserClient userClient,
- BindingClient userGameRoleClient,
- CancellationToken token = default)
+ internal static async Task CreateAsync(Cookie cookie, UserClient userClient, BindingClient userGameRoleClient, CancellationToken token = default)
{
User user = new(EntityUser.Create(cookie));
bool successful = await user.InitializeCoreAsync(userClient, userGameRoleClient, token).ConfigureAwait(false);
return successful ? user : null;
}
- private async Task InitializeCoreAsync(
- UserClient userClient,
- BindingClient userGameRoleClient,
- CancellationToken token = default)
+ private async Task InitializeCoreAsync(UserClient userClient, BindingClient userGameRoleClient, CancellationToken token = default)
{
if (isInitialized)
{
return true;
}
- await InitializeUserInfoAndUserGameRolesAsync(userClient, userGameRoleClient, token).ConfigureAwait(false);
-
- isInitialized = true;
-
- return UserInfo != null && UserGameRoles.Any();
- }
-
- private async Task InitializeUserInfoAndUserGameRolesAsync(UserClient userClient, BindingClient userGameRoleClient, CancellationToken token)
- {
UserInfo = await userClient
.GetUserFullInfoAsync(this, token)
.ConfigureAwait(false);
@@ -137,5 +141,9 @@ public class User : Observable
.ConfigureAwait(false);
SelectedUserGameRole = UserGameRoles.FirstOrFirstOrDefault(role => role.IsChosen);
+
+ isInitialized = true;
+
+ return UserInfo != null && UserGameRoles.Any();
}
}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Observable.cs b/src/Snap.Hutao/Snap.Hutao/Model/Observable.cs
deleted file mode 100644
index 9b0db94f..00000000
--- a/src/Snap.Hutao/Snap.Hutao/Model/Observable.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright (c) DGP Studio. All rights reserved.
-// Licensed under the MIT license.
-
-using System.Runtime.CompilerServices;
-
-namespace Snap.Hutao.Model;
-
-///
-/// 简单的实现了 接口
-///
-public abstract class Observable : INotifyPropertyChanged
-{
- ///
- public event PropertyChangedEventHandler? PropertyChanged;
-
- ///
- /// 设置字段的值
- ///
- /// 字段类型
- /// 现有值
- /// 新的值
- /// 属性名称
- /// 项是否更新
- protected bool Set([NotNullIfNotNull("value")] ref T storage, T value, [CallerMemberName] string propertyName = default!)
- {
- if (Equals(storage, value))
- {
- return false;
- }
-
- storage = value;
- OnPropertyChanged(propertyName);
- return true;
- }
-
- ///
- /// 触发
- ///
- /// 属性名称
- protected void OnPropertyChanged(string propertyName)
- {
- PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
- }
-}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Primitive/AvatarId.cs b/src/Snap.Hutao/Snap.Hutao/Model/Primitive/AvatarId.cs
new file mode 100644
index 00000000..811d5e61
--- /dev/null
+++ b/src/Snap.Hutao/Snap.Hutao/Model/Primitive/AvatarId.cs
@@ -0,0 +1,65 @@
+// Copyright (c) DGP Studio. All rights reserved.
+// Licensed under the MIT license.
+
+using Snap.Hutao.Model.Primitive.Converter;
+
+namespace Snap.Hutao.Model.Primitive;
+
+///
+/// 角色Id
+///
+[JsonConverter(typeof(AvatarIdConverter))]
+public readonly struct AvatarId : IEquatable
+{
+ ///
+ /// 值
+ ///
+ public readonly int Value;
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// value
+ public AvatarId(int value)
+ {
+ Value = value;
+ }
+
+ public static implicit operator int(AvatarId value)
+ {
+ return value.Value;
+ }
+
+ public static implicit operator AvatarId(int value)
+ {
+ return new(value);
+ }
+
+ public static bool operator ==(AvatarId left, AvatarId right)
+ {
+ return left.Value == right.Value;
+ }
+
+ public static bool operator !=(AvatarId left, AvatarId right)
+ {
+ return !(left == right);
+ }
+
+ ///
+ public bool Equals(AvatarId other)
+ {
+ return Value == other.Value;
+ }
+
+ ///
+ public override bool Equals(object? obj)
+ {
+ return obj is AvatarId other && Equals(other);
+ }
+
+ ///
+ public override int GetHashCode()
+ {
+ return Value.GetHashCode();
+ }
+}
diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Primitive/Converter/AvatarIdConverter.cs b/src/Snap.Hutao/Snap.Hutao/Model/Primitive/Converter/AvatarIdConverter.cs
new file mode 100644
index 00000000..4d1f9443
--- /dev/null
+++ b/src/Snap.Hutao/Snap.Hutao/Model/Primitive/Converter/AvatarIdConverter.cs
@@ -0,0 +1,22 @@
+// Copyright (c) DGP Studio. All rights reserved.
+// Licensed under the MIT license.
+
+namespace Snap.Hutao.Model.Primitive.Converter;
+
+///
+/// 角色Id转换器
+///
+internal class AvatarIdConverter : JsonConverter
+{
+ ///
+ public override AvatarId Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ return reader.GetInt32();
+ }
+
+ ///
+ public override void Write(Utf8JsonWriter writer, AvatarId value, JsonSerializerOptions options)
+ {
+ writer.WriteNumberValue(value);
+ }
+}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Primitive/Converter/WeaponIdConverter.cs b/src/Snap.Hutao/Snap.Hutao/Model/Primitive/Converter/WeaponIdConverter.cs
new file mode 100644
index 00000000..e489f3a2
--- /dev/null
+++ b/src/Snap.Hutao/Snap.Hutao/Model/Primitive/Converter/WeaponIdConverter.cs
@@ -0,0 +1,22 @@
+// Copyright (c) DGP Studio. All rights reserved.
+// Licensed under the MIT license.
+
+namespace Snap.Hutao.Model.Primitive.Converter;
+
+///
+/// 武器Id转换器
+///
+internal class WeaponIdConverter : JsonConverter
+{
+ ///
+ public override WeaponId Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ return reader.GetInt32();
+ }
+
+ ///
+ public override void Write(Utf8JsonWriter writer, WeaponId value, JsonSerializerOptions options)
+ {
+ writer.WriteNumberValue(value);
+ }
+}
diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Primitive/WeaponId.cs b/src/Snap.Hutao/Snap.Hutao/Model/Primitive/WeaponId.cs
new file mode 100644
index 00000000..731234de
--- /dev/null
+++ b/src/Snap.Hutao/Snap.Hutao/Model/Primitive/WeaponId.cs
@@ -0,0 +1,65 @@
+// Copyright (c) DGP Studio. All rights reserved.
+// Licensed under the MIT license.
+
+using Snap.Hutao.Model.Primitive.Converter;
+
+namespace Snap.Hutao.Model.Primitive;
+
+///
+/// 武器Id
+///
+[JsonConverter(typeof(WeaponIdConverter))]
+public readonly struct WeaponId : IEquatable
+{
+ ///
+ /// 值
+ ///
+ public readonly int Value;
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// value
+ public WeaponId(int value)
+ {
+ Value = value;
+ }
+
+ public static implicit operator int(WeaponId value)
+ {
+ return value.Value;
+ }
+
+ public static implicit operator WeaponId(int value)
+ {
+ return new(value);
+ }
+
+ public static bool operator ==(WeaponId left, WeaponId right)
+ {
+ return left.Value == right.Value;
+ }
+
+ public static bool operator !=(WeaponId left, WeaponId right)
+ {
+ return !(left == right);
+ }
+
+ ///
+ public bool Equals(WeaponId other)
+ {
+ return Value == other.Value;
+ }
+
+ ///
+ public override bool Equals(object? obj)
+ {
+ return obj is WeaponId other && Equals(other);
+ }
+
+ ///
+ public override int GetHashCode()
+ {
+ return Value.GetHashCode();
+ }
+}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Selectable.cs b/src/Snap.Hutao/Snap.Hutao/Model/Selectable.cs
index c1ba5061..a3c12bfa 100644
--- a/src/Snap.Hutao/Snap.Hutao/Model/Selectable.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Model/Selectable.cs
@@ -1,6 +1,8 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
+using CommunityToolkit.Mvvm.ComponentModel;
+
namespace Snap.Hutao.Model;
///
@@ -8,7 +10,7 @@ namespace Snap.Hutao.Model;
/// 默认为选中状态
///
/// 值的类型
-public class Selectable : Observable
+public class Selectable : ObservableObject
where T : class
{
private readonly Action? selectedChanged;
@@ -35,7 +37,7 @@ public class Selectable : Observable
get => isSelected;
set
{
- Set(ref isSelected, value);
+ SetProperty(ref isSelected, value);
selectedChanged?.Invoke();
}
}
@@ -43,5 +45,5 @@ public class Selectable : Observable
///
/// 存放的对象
///
- public T Value { get => value; set => Set(ref this.value, value); }
+ public T Value { get => value; set => SetProperty(ref this.value, value); }
}
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Achievement/AchievementDbOperation.cs b/src/Snap.Hutao/Snap.Hutao/Service/Achievement/AchievementDbOperation.cs
index b29f75c5..7bbc1f8b 100644
--- a/src/Snap.Hutao/Snap.Hutao/Service/Achievement/AchievementDbOperation.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Service/Achievement/AchievementDbOperation.cs
@@ -2,6 +2,7 @@
// Licensed under the MIT license.
using Snap.Hutao.Context.Database;
+using Snap.Hutao.Core.Database;
using Snap.Hutao.Model.InterChange.Achievement;
using EntityAchievement = Snap.Hutao.Model.Entity.Achievement;
@@ -63,7 +64,7 @@ public class AchievementDbOperation
if (entity == null && uiaf != null)
{
- AddEntity(EntityAchievement.Create(archiveId, uiaf));
+ appDbContext.Achievements.AddAndSave(EntityAchievement.Create(archiveId, uiaf));
add++;
continue;
}
@@ -85,8 +86,8 @@ public class AchievementDbOperation
if (aggressive)
{
- RemoveEntity(entity);
- AddEntity(EntityAchievement.Create(archiveId, uiaf));
+ appDbContext.Achievements.RemoveAndSave(entity);
+ appDbContext.Achievements.AddAndSave(EntityAchievement.Create(archiveId, uiaf));
update++;
}
}
@@ -96,7 +97,7 @@ public class AchievementDbOperation
moveEntity = false;
moveUIAF = true;
- AddEntity(EntityAchievement.Create(archiveId, uiaf));
+ appDbContext.Achievements.AddAndSave(EntityAchievement.Create(archiveId, uiaf));
add++;
}
}
@@ -115,7 +116,7 @@ public class AchievementDbOperation
/// 导入结果
public ImportResult Overwrite(Guid archiveId, IEnumerable items)
{
- IQueryable oldData = appDbContext.Achievements
+ IOrderedQueryable oldData = appDbContext.Achievements
.Where(a => a.ArchiveId == archiveId)
.OrderBy(a => a.Id);
@@ -142,13 +143,13 @@ public class AchievementDbOperation
if (oldEntity == null && newEntity != null)
{
- AddEntity(newEntity);
+ appDbContext.Achievements.AddAndSave(newEntity);
add++;
continue;
}
else if (oldEntity != null && newEntity == null)
{
- RemoveEntity(oldEntity);
+ appDbContext.Achievements.RemoveAndSave(oldEntity);
remove++;
continue;
}
@@ -157,7 +158,7 @@ public class AchievementDbOperation
{
moveOld = true;
moveNew = false;
- RemoveEntity(oldEntity);
+ appDbContext.Achievements.RemoveAndSave(oldEntity);
remove++;
}
else if (oldEntity.Id == newEntity.Id)
@@ -172,8 +173,8 @@ public class AchievementDbOperation
}
else
{
- RemoveEntity(oldEntity);
- AddEntity(newEntity);
+ appDbContext.Achievements.RemoveAndSave(oldEntity);
+ appDbContext.Achievements.AddAndSave(newEntity);
update++;
}
}
@@ -182,7 +183,7 @@ public class AchievementDbOperation
// entity.Id > uiaf.Id
moveOld = false;
moveNew = true;
- AddEntity(newEntity);
+ appDbContext.Achievements.AddAndSave(newEntity);
add++;
}
}
@@ -196,16 +197,4 @@ public class AchievementDbOperation
return new(add, update, remove);
}
-
- private void AddEntity(EntityAchievement entity)
- {
- appDbContext.Achievements.Add(entity);
- appDbContext.SaveChanges();
- }
-
- private void RemoveEntity(EntityAchievement entity)
- {
- appDbContext.Achievements.Remove(entity);
- appDbContext.SaveChanges();
- }
}
\ 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 2a21e0bc..62d9348b 100644
--- a/src/Snap.Hutao/Snap.Hutao/Service/Achievement/AchievementService.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Service/Achievement/AchievementService.cs
@@ -19,7 +19,7 @@ namespace Snap.Hutao.Service.Achievement;
///
/// 成就服务
///
-[Injection(InjectAs.Transient, typeof(IAchievementService))]
+[Injection(InjectAs.Scoped, typeof(IAchievementService))]
internal class AchievementService : IAchievementService
{
private readonly AppDbContext appDbContext;
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoService.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoService.cs
index b95e49ea..87b24585 100644
--- a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoService.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoService.cs
@@ -17,7 +17,7 @@ namespace Snap.Hutao.Service.AvatarInfo;
///
/// 角色信息服务
///
-[Injection(InjectAs.Transient, typeof(IAvatarInfoService))]
+[Injection(InjectAs.Scoped, typeof(IAvatarInfoService))]
internal class AvatarInfoService : IAvatarInfoService
{
private readonly AppDbContext appDbContext;
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/GachaStatisticsFactory.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/GachaStatisticsFactory.cs
index 61ee8144..8086beed 100644
--- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/GachaStatisticsFactory.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/GachaStatisticsFactory.cs
@@ -17,7 +17,7 @@ namespace Snap.Hutao.Service.GachaLog.Factory;
///
/// 祈愿统计工厂
///
-[Injection(InjectAs.Transient, typeof(IGachaStatisticsFactory))]
+[Injection(InjectAs.Scoped, typeof(IGachaStatisticsFactory))]
internal class GachaStatisticsFactory : IGachaStatisticsFactory
{
private readonly IMetadataService metadataService;
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogService.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogService.cs
index fef5135c..da78ae13 100644
--- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogService.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogService.cs
@@ -14,7 +14,6 @@ using Snap.Hutao.Model.Binding.Gacha.Abstraction;
using Snap.Hutao.Model.Entity;
using Snap.Hutao.Model.InterChange.GachaLog;
using Snap.Hutao.Model.Metadata.Abstraction;
-using Snap.Hutao.Service.Abstraction;
using Snap.Hutao.Service.GachaLog.Factory;
using Snap.Hutao.Service.Metadata;
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
@@ -27,7 +26,7 @@ namespace Snap.Hutao.Service.GachaLog;
///
/// 祈愿记录服务
///
-[Injection(InjectAs.Transient, typeof(IGachaLogService))]
+[Injection(InjectAs.Scoped, typeof(IGachaLogService))]
internal class GachaLogService : IGachaLogService, ISupportAsyncInitialization
{
///
@@ -45,7 +44,6 @@ internal class GachaLogService : IGachaLogService, ISupportAsyncInitialization
private readonly IEnumerable urlProviders;
private readonly GachaInfoClient gachaInfoClient;
private readonly IMetadataService metadataService;
- private readonly IInfoBarService infoBarService;
private readonly IGachaStatisticsFactory gachaStatisticsFactory;
private readonly ILogger logger;
private readonly DbCurrent dbCurrent;
@@ -66,7 +64,6 @@ internal class GachaLogService : IGachaLogService, ISupportAsyncInitialization
/// Url提供器集合
/// 祈愿记录客户端
/// 元数据服务
- /// 信息条服务
/// 祈愿统计工厂
/// 日志器
/// 消息器
@@ -75,7 +72,6 @@ internal class GachaLogService : IGachaLogService, ISupportAsyncInitialization
IEnumerable urlProviders,
GachaInfoClient gachaInfoClient,
IMetadataService metadataService,
- IInfoBarService infoBarService,
IGachaStatisticsFactory gachaStatisticsFactory,
ILogger logger,
IMessenger messenger)
@@ -84,7 +80,6 @@ internal class GachaLogService : IGachaLogService, ISupportAsyncInitialization
this.urlProviders = urlProviders;
this.gachaInfoClient = gachaInfoClient;
this.metadataService = metadataService;
- this.infoBarService = infoBarService;
this.logger = logger;
this.gachaStatisticsFactory = gachaStatisticsFactory;
@@ -135,8 +130,8 @@ internal class GachaLogService : IGachaLogService, ISupportAsyncInitialization
nameAvatarMap = await metadataService.GetNameToAvatarMapAsync(token).ConfigureAwait(false);
nameWeaponMap = await metadataService.GetNameToWeaponMapAsync(token).ConfigureAwait(false);
- idAvatarMap = await metadataService.GetIdToAvatarMapAsync().ConfigureAwait(false);
- idWeaponMap = await metadataService.GetIdToWeaponMapAsync().ConfigureAwait(false);
+ idAvatarMap = await metadataService.GetIdToAvatarMapAsync(token).ConfigureAwait(false);
+ idWeaponMap = await metadataService.GetIdToWeaponMapAsync(token).ConfigureAwait(false);
IsInitialized = true;
}
@@ -214,8 +209,8 @@ internal class GachaLogService : IGachaLogService, ISupportAsyncInitialization
archiveCollection.Remove(archive);
// Sync database
- appDbContext.GachaArchives.Remove(archive);
- return appDbContext.SaveChangesAsync();
+ appDbContext.GachaArchives.RemoveAndSave(archive);
+ return Task.CompletedTask;
}
private static Task RandomDelayAsync(CancellationToken token)
@@ -232,7 +227,6 @@ internal class GachaLogService : IGachaLogService, ISupportAsyncInitialization
long trimId = appDbContext.GachaItems
.Where(i => i.ArchiveId == archiveId)
.OrderBy(i => i.Id)
- .Take(1)
.FirstOrDefault()?.Id ?? long.MaxValue;
IEnumerable toAdd = list
@@ -326,8 +320,7 @@ internal class GachaLogService : IGachaLogService, ISupportAsyncInitialization
if (archive == null)
{
GachaArchive created = GachaArchive.Create(uid);
- appDbContext.GachaArchives.Add(created);
- appDbContext.SaveChanges();
+ appDbContext.GachaArchives.AddAndSave(created);
archive = appDbContext.GachaArchives.Single(a => a.Uid == uid);
GachaArchive temp = archive;
@@ -346,10 +339,9 @@ internal class GachaLogService : IGachaLogService, ISupportAsyncInitialization
.Where(i => i.ArchiveId == archive.InnerId)
.Where(i => i.QueryType == configType)
.OrderByDescending(i => i.Id)
- .Take(1)
.FirstOrDefault();
- // MaxBy should be supported by .NET 7
+ // TODO MaxBy should be supported by .NET 7
// .MaxBy(i => i.Id);
}
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/GameService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/GameService.cs
index 8b29b3c3..4196cc51 100644
--- a/src/Snap.Hutao/Snap.Hutao/Service/Game/GameService.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/GameService.cs
@@ -4,8 +4,8 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
using Snap.Hutao.Context.Database;
+using Snap.Hutao.Core.Database;
using Snap.Hutao.Core.Threading;
-using Snap.Hutao.Extension;
using Snap.Hutao.Model.Entity;
using Snap.Hutao.Service.Game.Locator;
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/User/UserService.cs b/src/Snap.Hutao/Snap.Hutao/Service/User/UserService.cs
index 87b5511c..44931981 100644
--- a/src/Snap.Hutao/Snap.Hutao/Service/User/UserService.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Service/User/UserService.cs
@@ -153,8 +153,8 @@ internal class UserService : IUserService
// 检查 stoken 是否存在
if (cookie.ContainsSToken())
{
- // insert stoken directly
- userWithSameUid.Cookie.InsertSToken(uid, cookie);
+ // insert stoken
+ userWithSameUid.UpdateSToken(uid, cookie);
appDbContext.Users.Update(userWithSameUid.Entity);
appDbContext.SaveChanges();
diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/AchievementViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/AchievementViewModel.cs
index 62598222..ffaa7611 100644
--- a/src/Snap.Hutao/Snap.Hutao/ViewModel/AchievementViewModel.cs
+++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/AchievementViewModel.cs
@@ -30,7 +30,7 @@ namespace Snap.Hutao.ViewModel;
///
/// 成就视图模型
///
-[Injection(InjectAs.Transient)]
+[Injection(InjectAs.Scoped)]
internal class AchievementViewModel
: ObservableObject,
ISupportCancellation,
@@ -42,10 +42,10 @@ internal class AchievementViewModel
new(nameof(Model.Binding.Achievement.IsChecked), SortDirection.Ascending);
private readonly IMetadataService metadataService;
- private readonly IAchievementService achievementService;
private readonly IInfoBarService infoBarService;
private readonly JsonSerializerOptions options;
- private readonly IPickerFactory pickerFactory;
+
+ private readonly IAchievementService achievementService;
private readonly TaskCompletionSource openUICompletionSource = new();
@@ -67,7 +67,7 @@ internal class AchievementViewModel
/// 信息条服务
/// Json序列化选项
/// 异步命令工厂
- /// 文件选择器工厂
+ /// 范围工厂
/// 消息器
public AchievementViewModel(
IMetadataService metadataService,
@@ -75,14 +75,12 @@ internal class AchievementViewModel
IInfoBarService infoBarService,
JsonSerializerOptions options,
IAsyncRelayCommandFactory asyncRelayCommandFactory,
- IPickerFactory pickerFactory,
IMessenger messenger)
{
this.metadataService = metadataService;
this.achievementService = achievementService;
this.infoBarService = infoBarService;
this.options = options;
- this.pickerFactory = pickerFactory;
OpenUICommand = asyncRelayCommandFactory.Create(OpenUIAsync);
ImportUIAFFromClipboardCommand = asyncRelayCommandFactory.Create(ImportUIAFFromClipboardAsync);
@@ -416,6 +414,7 @@ internal class AchievementViewModel
return;
}
+ IPickerFactory pickerFactory = Ioc.Default.GetRequiredService();
FileOpenPicker picker = pickerFactory.GetFileOpenPicker();
picker.SuggestedStartLocation = PickerLocationId.Desktop;
picker.CommitButtonText = "导入";
diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/AnnouncementViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/AnnouncementViewModel.cs
index fbc6d37f..758537d8 100644
--- a/src/Snap.Hutao/Snap.Hutao/ViewModel/AnnouncementViewModel.cs
+++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/AnnouncementViewModel.cs
@@ -16,12 +16,10 @@ namespace Snap.Hutao.ViewModel;
///
/// 公告视图模型
///
-[Injection(InjectAs.Transient)]
+[Injection(InjectAs.Scoped)]
internal class AnnouncementViewModel : ObservableObject, ISupportCancellation
{
private readonly IAnnouncementService announcementService;
- private readonly INavigationService navigationService;
- private readonly IInfoBarService infoBarService;
private readonly ILogger logger;
private AnnouncementWrapper? announcement;
@@ -36,14 +34,10 @@ internal class AnnouncementViewModel : ObservableObject, ISupportCancellation
/// 日志器
public AnnouncementViewModel(
IAnnouncementService announcementService,
- INavigationService navigationService,
IAsyncRelayCommandFactory asyncRelayCommandFactory,
- IInfoBarService infoBarService,
ILogger logger)
{
this.announcementService = announcementService;
- this.navigationService = navigationService;
- this.infoBarService = infoBarService;
this.logger = logger;
OpenUICommand = asyncRelayCommandFactory.Create(OpenUIAsync);
@@ -88,10 +82,12 @@ internal class AnnouncementViewModel : ObservableObject, ISupportCancellation
{
if (WebView2Helper.IsSupported)
{
+ INavigationService navigationService = Ioc.Default.GetRequiredService();
navigationService.Navigate(data: new NavigationExtra(content));
}
else
{
+ IInfoBarService infoBarService = Ioc.Default.GetRequiredService();
infoBarService.Warning("尚未安装 WebView2 运行时。");
}
}
diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/AvatarPropertyViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/AvatarPropertyViewModel.cs
index a991165a..d32215c1 100644
--- a/src/Snap.Hutao/Snap.Hutao/ViewModel/AvatarPropertyViewModel.cs
+++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/AvatarPropertyViewModel.cs
@@ -18,7 +18,7 @@ namespace Snap.Hutao.ViewModel;
///
/// 角色属性视图模型
///
-[Injection(InjectAs.Transient)]
+[Injection(InjectAs.Scoped)]
internal class AvatarPropertyViewModel : ObservableObject, ISupportCancellation
{
private readonly IUserService userService;
diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/ExperimentalFeaturesViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/ExperimentalFeaturesViewModel.cs
index 2fa5d654..86cfd206 100644
--- a/src/Snap.Hutao/Snap.Hutao/ViewModel/ExperimentalFeaturesViewModel.cs
+++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/ExperimentalFeaturesViewModel.cs
@@ -16,7 +16,7 @@ namespace Snap.Hutao.ViewModel;
///
/// 实验性功能视图模型
///
-[Injection(InjectAs.Transient)]
+[Injection(InjectAs.Scoped)]
internal class ExperimentalFeaturesViewModel : ObservableObject
{
private readonly IFileSystemLocation hutaoLocation;
diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/GachaLogViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/GachaLogViewModel.cs
index 52b66a52..1c4b3e72 100644
--- a/src/Snap.Hutao/Snap.Hutao/ViewModel/GachaLogViewModel.cs
+++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/GachaLogViewModel.cs
@@ -24,7 +24,7 @@ namespace Snap.Hutao.ViewModel;
///
/// 祈愿记录视图模型
///
-[Injection(InjectAs.Transient)]
+[Injection(InjectAs.Scoped)]
internal class GachaLogViewModel : ObservableObject, ISupportCancellation
{
private readonly IGachaLogService gachaLogService;
diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/HutaoDatabaseViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/HutaoDatabaseViewModel.cs
index 9056ff1f..8e5e220c 100644
--- a/src/Snap.Hutao/Snap.Hutao/ViewModel/HutaoDatabaseViewModel.cs
+++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/HutaoDatabaseViewModel.cs
@@ -12,7 +12,7 @@ namespace Snap.Hutao.ViewModel;
///
/// 胡桃数据库视图模型
///
-[Injection(InjectAs.Transient)]
+[Injection(InjectAs.Scoped)]
internal class HutaoDatabaseViewModel : ObservableObject, ISupportCancellation
{
private readonly IHtaoCache hutaoCache;
diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/SettingViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/SettingViewModel.cs
index d7a8a4f1..b0945ec7 100644
--- a/src/Snap.Hutao/Snap.Hutao/ViewModel/SettingViewModel.cs
+++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/SettingViewModel.cs
@@ -3,7 +3,7 @@
using CommunityToolkit.Mvvm.ComponentModel;
using Snap.Hutao.Context.Database;
-using Snap.Hutao.Extension;
+using Snap.Hutao.Core.Database;
using Snap.Hutao.Model.Entity;
namespace Snap.Hutao.ViewModel;
@@ -11,7 +11,7 @@ namespace Snap.Hutao.ViewModel;
///
/// 测试视图模型
///
-[Injection(InjectAs.Transient)]
+[Injection(InjectAs.Scoped)]
internal class SettingViewModel : ObservableObject
{
private readonly AppDbContext appDbContext;
diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/UserViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/UserViewModel.cs
index d44a266a..2f76298c 100644
--- a/src/Snap.Hutao/Snap.Hutao/ViewModel/UserViewModel.cs
+++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/UserViewModel.cs
@@ -18,7 +18,7 @@ namespace Snap.Hutao.ViewModel;
///
/// 用户视图模型
///
-[Injection(InjectAs.Transient)]
+[Injection(InjectAs.Singleton)]
internal class UserViewModel : ObservableObject
{
private readonly IUserService userService;
diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/WikiAvatarViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/WikiAvatarViewModel.cs
index 94230150..f6728b02 100644
--- a/src/Snap.Hutao/Snap.Hutao/ViewModel/WikiAvatarViewModel.cs
+++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/WikiAvatarViewModel.cs
@@ -15,7 +15,7 @@ namespace Snap.Hutao.ViewModel;
///
/// 角色资料视图模型
///
-[Injection(InjectAs.Transient)]
+[Injection(InjectAs.Scoped)]
internal class WikiAvatarViewModel : ObservableObject
{
private readonly IMetadataService metadataService;