mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
Compare commits
1 Commits
refactor/h
...
feat/1100
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
37767261cd |
@@ -104,7 +104,6 @@ internal class ScopedPage : Page
|
||||
|
||||
// Dispose the scope
|
||||
pageScope.Dispose();
|
||||
GC.Collect(GC.MaxGeneration, GCCollectionMode.Aggressive, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Snap.Hutao.Model.Entity;
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
[Table("cultivate_entries")]
|
||||
internal sealed class CultivateEntry : IDbMappingForeignKeyFrom<CultivateEntry, CultivateType, uint>, IAppDbEntity
|
||||
internal sealed class CultivateEntry : IDbMappingForeignKeyFrom<CultivateEntry, CultivateType, uint>
|
||||
{
|
||||
/// <summary>
|
||||
/// 内部Id
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
using Snap.Hutao.Core.Abstraction;
|
||||
using Snap.Hutao.Core.Database;
|
||||
using Snap.Hutao.Model.Entity.Abstraction;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
@@ -14,7 +13,7 @@ namespace Snap.Hutao.Model.Entity;
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
[Table("cultivate_projects")]
|
||||
internal sealed class CultivateProject : ISelectable, IMappingFrom<CultivateProject, string, string>, IAppDbEntity
|
||||
internal sealed class CultivateProject : ISelectable, IMappingFrom<CultivateProject, string, string>
|
||||
{
|
||||
/// <summary>
|
||||
/// 内部Id
|
||||
|
||||
@@ -16,6 +16,9 @@ internal sealed partial class SettingEntry
|
||||
public const string ElementTheme = "ElementTheme";
|
||||
public const string BackgroundImageType = "BackgroundImageType";
|
||||
|
||||
public const string IsAutoUploadGachaLogEnabled = "IsAutoUploadGachaLogEnabled";
|
||||
public const string IsAutoUploadSpiralAbyssRecordEnabled = "IsAutoUploadSpiralAbyssRecordEnabled";
|
||||
|
||||
public const string AnnouncementRegion = "AnnouncementRegion";
|
||||
|
||||
public const string IsEmptyHistoryWishVisible = "IsEmptyHistoryWishVisible";
|
||||
|
||||
@@ -1361,18 +1361,6 @@
|
||||
<data name="ViewDialogSettingDeleteUserDataTitle" xml:space="preserve">
|
||||
<value>是否永久删除用户数据</value>
|
||||
</data>
|
||||
<data name="ViewDialogSpiralAbyssUploadRecordHomaNotLoginCloseButtonText" xml:space="preserve">
|
||||
<value>前往登录</value>
|
||||
</data>
|
||||
<data name="ViewDialogSpiralAbyssUploadRecordHomaNotLoginHint" xml:space="preserve">
|
||||
<value>当前未登录胡桃账号,上传深渊数据无法获赠胡桃云时长</value>
|
||||
</data>
|
||||
<data name="ViewDialogSpiralAbyssUploadRecordHomaNotLoginPrimaryButtonText" xml:space="preserve">
|
||||
<value>继续上传</value>
|
||||
</data>
|
||||
<data name="ViewDialogSpiralAbyssUploadRecordHomaNotLoginTitle" xml:space="preserve">
|
||||
<value>上传深渊数据</value>
|
||||
</data>
|
||||
<data name="ViewDialogUpdatePackageDownloadUpdatelogLinkContent" xml:space="preserve">
|
||||
<value>查看更新日志</value>
|
||||
</data>
|
||||
@@ -1745,6 +1733,12 @@
|
||||
<data name="ViewModelSettingSetGamePathDatabaseFailedTitle" xml:space="preserve">
|
||||
<value>保存游戏路径失败</value>
|
||||
</data>
|
||||
<data name="ViewModelSpiralAbyssUploadRecordHomaNotLoginContent" xml:space="preserve">
|
||||
<value>当前未登录胡桃账号,上传深渊数据无法获赠胡桃云时长</value>
|
||||
</data>
|
||||
<data name="ViewModelSpiralAbyssUploadRecordHomaNotLoginTitle" xml:space="preserve">
|
||||
<value>上传深渊数据</value>
|
||||
</data>
|
||||
<data name="ViewModelUserAdded" xml:space="preserve">
|
||||
<value>用户 [{0}] 添加成功</value>
|
||||
</data>
|
||||
@@ -2594,6 +2588,24 @@
|
||||
<data name="ViewpageSettingHomeHeader" xml:space="preserve">
|
||||
<value>主页</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingHutaoCloudAutoUploadDescription" xml:space="preserve">
|
||||
<value>登录胡桃通行证后自动上传至胡桃云</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingHutaoCloudAutoUploadHeader" xml:space="preserve">
|
||||
<value>自动上传</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingHutaoCloudGachaLogAutoUploadDescription" xml:space="preserve">
|
||||
<value>刷新祈愿记录后自动上传至胡桃云,需要有效的胡桃云服务</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingHutaoCloudGachaLogAutoUploadHeader" xml:space="preserve">
|
||||
<value>自动上传祈愿记录</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingHutaoCloudSpiralAbyssAutoUploadDescription" xml:space="preserve">
|
||||
<value>刷新深境螺旋数据后自动上传至胡桃云</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingHutaoCloudSpiralAbyssAutoUploadHeader" xml:space="preserve">
|
||||
<value>自动上传深境螺旋数据</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingHutaoPassportDangerZoneDescription" xml:space="preserve">
|
||||
<value>三思而后行</value>
|
||||
</data>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Snap.Hutao.Core.Database;
|
||||
using Snap.Hutao.Model.Entity.Abstraction;
|
||||
|
||||
namespace Snap.Hutao.Service.Abstraction;
|
||||
@@ -11,25 +12,13 @@ internal static class AppDbServiceAppDbEntityExtension
|
||||
public static int DeleteByInnerId<TEntity>(this IAppDbService<TEntity> service, TEntity entity)
|
||||
where TEntity : class, IAppDbEntity
|
||||
{
|
||||
return service.DeleteByInnerId(entity.InnerId);
|
||||
}
|
||||
|
||||
public static int DeleteByInnerId<TEntity>(this IAppDbService<TEntity> service, Guid innerId)
|
||||
where TEntity : class, IAppDbEntity
|
||||
{
|
||||
return service.Delete(e => e.InnerId == innerId);
|
||||
return service.Execute(dbset => dbset.ExecuteDeleteWhere(e => e.InnerId == entity.InnerId));
|
||||
}
|
||||
|
||||
public static ValueTask<int> DeleteByInnerIdAsync<TEntity>(this IAppDbService<TEntity> service, TEntity entity, CancellationToken token = default)
|
||||
where TEntity : class, IAppDbEntity
|
||||
{
|
||||
return service.DeleteByInnerIdAsync(entity.InnerId, token);
|
||||
}
|
||||
|
||||
public static ValueTask<int> DeleteByInnerIdAsync<TEntity>(this IAppDbService<TEntity> service, Guid innerId, CancellationToken token = default)
|
||||
where TEntity : class, IAppDbEntity
|
||||
{
|
||||
return service.DeleteAsync(e => e.InnerId == innerId, token);
|
||||
return service.ExecuteAsync((dbset, token) => dbset.ExecuteDeleteWhereAsync(e => e.InnerId == entity.InnerId, token), token);
|
||||
}
|
||||
|
||||
public static List<TEntity> ListByArchiveId<TEntity>(this IAppDbService<TEntity> service, Guid archiveId)
|
||||
|
||||
@@ -30,13 +30,7 @@ internal static class AppDbServiceCollectionExtension
|
||||
public static ValueTask<List<TEntity>> ListAsync<TEntity>(this IAppDbService<TEntity> service, Expression<Func<TEntity, bool>> predicate, CancellationToken token = default)
|
||||
where TEntity : class
|
||||
{
|
||||
return service.ListAsync(query => query.Where(predicate), token);
|
||||
}
|
||||
|
||||
public static ValueTask<List<TResult>> ListAsync<TEntity, TResult>(this IAppDbService<TEntity> service, Func<IQueryable<TEntity>, IQueryable<TResult>> query, CancellationToken token = default)
|
||||
where TEntity : class
|
||||
{
|
||||
return service.QueryAsync((query1, token) => query(query1).ToListAsync(token), token);
|
||||
return service.QueryAsync((query, token) => query.Where(predicate).ToListAsync(token), token);
|
||||
}
|
||||
|
||||
public static ObservableCollection<TEntity> ObservableCollection<TEntity>(this IAppDbService<TEntity> service)
|
||||
|
||||
@@ -126,18 +126,6 @@ internal static class AppDbServiceExtension
|
||||
return service.QueryAsync((query, token) => query.SingleAsync(predicate, token), token);
|
||||
}
|
||||
|
||||
public static TEntity? SingleOrDefault<TEntity>(this IAppDbService<TEntity> service, Expression<Func<TEntity, bool>> predicate)
|
||||
where TEntity : class
|
||||
{
|
||||
return service.Query(query => query.SingleOrDefault(predicate));
|
||||
}
|
||||
|
||||
public static ValueTask<TEntity?> SingleOrDefaultAsync<TEntity>(this IAppDbService<TEntity> service, Expression<Func<TEntity, bool>> predicate, CancellationToken token = default)
|
||||
where TEntity : class
|
||||
{
|
||||
return service.QueryAsync((query, token) => query.SingleOrDefaultAsync(predicate, token), token);
|
||||
}
|
||||
|
||||
public static int Update<TEntity>(this IAppDbService<TEntity> service, TEntity entity)
|
||||
where TEntity : class
|
||||
{
|
||||
@@ -156,21 +144,9 @@ internal static class AppDbServiceExtension
|
||||
return service.Execute(dbset => dbset.RemoveAndSave(entity));
|
||||
}
|
||||
|
||||
public static int Delete<TEntity>(this IAppDbService<TEntity> service, Expression<Func<TEntity, bool>> predicate)
|
||||
where TEntity : class
|
||||
{
|
||||
return service.Execute(dbset => dbset.Where(predicate).ExecuteDelete());
|
||||
}
|
||||
|
||||
public static ValueTask<int> DeleteAsync<TEntity>(this IAppDbService<TEntity> service, TEntity entity, CancellationToken token = default)
|
||||
where TEntity : class
|
||||
{
|
||||
return service.ExecuteAsync((dbset, token) => dbset.RemoveAndSaveAsync(entity, token), token);
|
||||
}
|
||||
|
||||
public static ValueTask<int> DeleteAsync<TEntity>(this IAppDbService<TEntity> service, Expression<Func<TEntity, bool>> predicate, CancellationToken token = default)
|
||||
where TEntity : class
|
||||
{
|
||||
return service.ExecuteAsync((dbset, token) => dbset.Where(predicate).ExecuteDeleteAsync(token), token);
|
||||
}
|
||||
}
|
||||
@@ -46,12 +46,13 @@ internal sealed partial class AchievementDbService : IAchievementDbService
|
||||
[SuppressMessage("", "CA1305")]
|
||||
public ValueTask<List<EntityAchievement>> GetLatestFinishedAchievementListByArchiveIdAsync(Guid archiveId, int take, CancellationToken token = default)
|
||||
{
|
||||
return this.ListAsync<EntityAchievement, EntityAchievement>(
|
||||
query => query
|
||||
return this.QueryAsync<EntityAchievement, List<EntityAchievement>>(
|
||||
(query, token) => query
|
||||
.Where(a => a.ArchiveId == archiveId)
|
||||
.Where(a => a.Status >= Model.Intrinsic.AchievementStatus.STATUS_FINISHED)
|
||||
.OrderByDescending(a => a.Time.ToString())
|
||||
.Take(take),
|
||||
.Take(take)
|
||||
.ToListAsync(token),
|
||||
token);
|
||||
}
|
||||
|
||||
|
||||
@@ -12,5 +12,12 @@ namespace Snap.Hutao.Service.Announcement;
|
||||
[HighQuality]
|
||||
internal interface IAnnouncementService
|
||||
{
|
||||
ValueTask<AnnouncementWrapper> GetAnnouncementWrapperAsync(string languageCode, Region region, CancellationToken token = default);
|
||||
/// <summary>
|
||||
/// 异步获取游戏公告与活动,通常会进行缓存
|
||||
/// </summary>
|
||||
/// <param name="languageCode">语言代码</param>
|
||||
/// <param name="region">服务器</param>
|
||||
/// <param name="cancellationToken">取消令牌</param>
|
||||
/// <returns>公告包装器</returns>
|
||||
ValueTask<AnnouncementWrapper> GetAnnouncementWrapperAsync(string languageCode, Region region, CancellationToken cancellationToken = default);
|
||||
}
|
||||
@@ -15,6 +15,8 @@ namespace Snap.Hutao.Service;
|
||||
[Injection(InjectAs.Singleton)]
|
||||
internal sealed partial class AppOptions : DbStoreOptions
|
||||
{
|
||||
private bool? isAutoUploadGachaLogEnabled;
|
||||
private bool? isAutoUploadSpiralAbyssRecordEnabled;
|
||||
private bool? isEmptyHistoryWishVisible;
|
||||
private bool? isUnobtainedWishItemVisible;
|
||||
private BackdropType? backdropType;
|
||||
@@ -23,6 +25,18 @@ internal sealed partial class AppOptions : DbStoreOptions
|
||||
private Region? region;
|
||||
private string? geetestCustomCompositeUrl;
|
||||
|
||||
public bool IsAutoUploadGachaLogEnabled
|
||||
{
|
||||
get => GetOption(ref isAutoUploadGachaLogEnabled, SettingEntry.IsAutoUploadGachaLogEnabled, false);
|
||||
set => SetOption(ref isAutoUploadGachaLogEnabled, SettingEntry.IsAutoUploadGachaLogEnabled, value);
|
||||
}
|
||||
|
||||
public bool IsAutoUploadSpiralAbyssRecordEnabled
|
||||
{
|
||||
get => GetOption(ref isAutoUploadSpiralAbyssRecordEnabled, SettingEntry.IsAutoUploadSpiralAbyssRecordEnabled, false);
|
||||
set => SetOption(ref isAutoUploadSpiralAbyssRecordEnabled, SettingEntry.IsAutoUploadSpiralAbyssRecordEnabled, value);
|
||||
}
|
||||
|
||||
public bool IsEmptyHistoryWishVisible
|
||||
{
|
||||
get => GetOption(ref isEmptyHistoryWishVisible, SettingEntry.IsEmptyHistoryWishVisible, false);
|
||||
|
||||
@@ -29,11 +29,11 @@ internal sealed partial class AvatarInfoDbService : IAvatarInfoDbService
|
||||
|
||||
public void RemoveAvatarInfoRangeByUid(string uid)
|
||||
{
|
||||
this.Delete(i => i.Uid == uid);
|
||||
this.Execute(dbset => dbset.Where(i => i.Uid == uid).ExecuteDelete());
|
||||
}
|
||||
|
||||
public async ValueTask RemoveAvatarInfoRangeByUidAsync(string uid, CancellationToken token = default)
|
||||
{
|
||||
await this.DeleteAsync(i => i.Uid == uid, token).ConfigureAwait(false);
|
||||
await this.ExecuteAsync((dbset, token) => dbset.Where(i => i.Uid == uid).ExecuteDeleteAsync(token), token).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
@@ -25,11 +25,11 @@ internal sealed partial class AvatarInfoService : IAvatarInfoService
|
||||
private readonly IMetadataService metadataService;
|
||||
private readonly ISummaryFactory summaryFactory;
|
||||
|
||||
public async ValueTask<ValueResult<RefreshResultKind, Summary?>> GetSummaryAsync(UserAndUid userAndUid, RefreshOption refreshOption, CancellationToken token = default)
|
||||
public async ValueTask<ValueResult<RefreshResult, Summary?>> GetSummaryAsync(UserAndUid userAndUid, RefreshOption refreshOption, CancellationToken token = default)
|
||||
{
|
||||
if (!await metadataService.InitializeAsync().ConfigureAwait(false))
|
||||
{
|
||||
return new(RefreshResultKind.MetadataNotInitialized, null);
|
||||
return new(RefreshResult.MetadataNotInitialized, null);
|
||||
}
|
||||
|
||||
switch (refreshOption)
|
||||
@@ -40,43 +40,43 @@ internal sealed partial class AvatarInfoService : IAvatarInfoService
|
||||
|
||||
if (resp is null)
|
||||
{
|
||||
return new(RefreshResultKind.APIUnavailable, default);
|
||||
return new(RefreshResult.APIUnavailable, default);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(resp.Message))
|
||||
{
|
||||
return new(RefreshResultKind.StatusCodeNotSucceed, new Summary { Message = resp.Message });
|
||||
return new(RefreshResult.StatusCodeNotSucceed, new Summary { Message = resp.Message });
|
||||
}
|
||||
|
||||
if (!resp.IsValid)
|
||||
{
|
||||
return new(RefreshResultKind.ShowcaseNotOpen, default);
|
||||
return new(RefreshResult.ShowcaseNotOpen, default);
|
||||
}
|
||||
|
||||
List<EntityAvatarInfo> list = await avatarInfoDbBulkOperation.UpdateDbAvatarInfosByShowcaseAsync(userAndUid.Uid.Value, resp.AvatarInfoList, token).ConfigureAwait(false);
|
||||
Summary summary = await GetSummaryCoreAsync(list, token).ConfigureAwait(false);
|
||||
return new(RefreshResultKind.Ok, summary);
|
||||
return new(RefreshResult.Ok, summary);
|
||||
}
|
||||
|
||||
case RefreshOption.RequestFromHoyolabGameRecord:
|
||||
{
|
||||
List<EntityAvatarInfo> list = await avatarInfoDbBulkOperation.UpdateDbAvatarInfosByGameRecordCharacterAsync(userAndUid, token).ConfigureAwait(false);
|
||||
Summary summary = await GetSummaryCoreAsync(list, token).ConfigureAwait(false);
|
||||
return new(RefreshResultKind.Ok, summary);
|
||||
return new(RefreshResult.Ok, summary);
|
||||
}
|
||||
|
||||
case RefreshOption.RequestFromHoyolabCalculate:
|
||||
{
|
||||
List<EntityAvatarInfo> list = await avatarInfoDbBulkOperation.UpdateDbAvatarInfosByCalculateAvatarDetailAsync(userAndUid, token).ConfigureAwait(false);
|
||||
Summary summary = await GetSummaryCoreAsync(list, token).ConfigureAwait(false);
|
||||
return new(RefreshResultKind.Ok, summary);
|
||||
return new(RefreshResult.Ok, summary);
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
List<EntityAvatarInfo> list = await avatarInfoDbService.GetAvatarInfoListByUidAsync(userAndUid.Uid.Value, token).ConfigureAwait(false);
|
||||
Summary summary = await GetSummaryCoreAsync(list, token).ConfigureAwait(false);
|
||||
return new(RefreshResultKind.Ok, summary.Avatars.Count == 0 ? null : summary);
|
||||
return new(RefreshResult.Ok, summary.Avatars.Count == 0 ? null : summary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,5 +19,5 @@ internal interface IAvatarInfoService
|
||||
/// <param name="refreshOption">刷新选项</param>
|
||||
/// <param name="token">取消令牌</param>
|
||||
/// <returns>总览数据</returns>
|
||||
ValueTask<ValueResult<RefreshResultKind, Summary?>> GetSummaryAsync(UserAndUid userAndUid, RefreshOption refreshOption, CancellationToken token = default);
|
||||
ValueTask<ValueResult<RefreshResult, Summary?>> GetSummaryAsync(UserAndUid userAndUid, RefreshOption refreshOption, CancellationToken token = default);
|
||||
}
|
||||
@@ -7,7 +7,7 @@ namespace Snap.Hutao.Service.AvatarInfo;
|
||||
/// 刷新结果
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
internal enum RefreshResultKind
|
||||
internal enum RefreshResult
|
||||
{
|
||||
/// <summary>
|
||||
/// 正常
|
||||
@@ -26,11 +26,11 @@ internal sealed partial class BackgroundImageService : IBackgroundImageService
|
||||
private readonly ITaskContext taskContext;
|
||||
private readonly AppOptions appOptions;
|
||||
|
||||
private HashSet<string>? currentBackgroundPathSet;
|
||||
private HashSet<string> currentBackgroundPathSet;
|
||||
|
||||
public async ValueTask<ValueResult<bool, BackgroundImage?>> GetNextBackgroundImageAsync(BackgroundImage? previous, CancellationToken token = default)
|
||||
public async ValueTask<ValueResult<bool, BackgroundImage?>> GetNextBackgroundImageAsync(BackgroundImage? previous)
|
||||
{
|
||||
HashSet<string> backgroundSet = await SkipOrInitBackgroundAsync(token).ConfigureAwait(false);
|
||||
HashSet<string> backgroundSet = await SkipOrInitBackgroundAsync().ConfigureAwait(false);
|
||||
|
||||
if (backgroundSet.Count <= 0)
|
||||
{
|
||||
@@ -79,7 +79,7 @@ internal sealed partial class BackgroundImageService : IBackgroundImageService
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask<HashSet<string>> SkipOrInitBackgroundAsync(CancellationToken token = default)
|
||||
private async ValueTask<HashSet<string>> SkipOrInitBackgroundAsync()
|
||||
{
|
||||
switch (appOptions.BackgroundImageType)
|
||||
{
|
||||
@@ -90,7 +90,7 @@ internal sealed partial class BackgroundImageService : IBackgroundImageService
|
||||
string backgroundFolder = runtimeOptions.GetDataFolderBackgroundFolder();
|
||||
|
||||
currentBackgroundPathSet = Directory
|
||||
.EnumerateFiles(backgroundFolder, "*", SearchOption.AllDirectories)
|
||||
.GetFiles(backgroundFolder, "*.*", SearchOption.AllDirectories)
|
||||
.Where(path => AllowedFormats.Contains(Path.GetExtension(path)))
|
||||
.ToHashSet();
|
||||
}
|
||||
@@ -100,13 +100,13 @@ internal sealed partial class BackgroundImageService : IBackgroundImageService
|
||||
}
|
||||
|
||||
case BackgroundImageType.HutaoBing:
|
||||
await SetCurrentBackgroundPathSetAsync((client, token) => client.GetBingWallpaperAsync(token), token).ConfigureAwait(false);
|
||||
await SetCurrentBackgroundPathSetAsync(client => client.GetBingWallpaperAsync()).ConfigureAwait(false);
|
||||
break;
|
||||
case BackgroundImageType.HutaoDaily:
|
||||
await SetCurrentBackgroundPathSetAsync((client, token) => client.GetTodayWallpaperAsync(token), token).ConfigureAwait(false);
|
||||
await SetCurrentBackgroundPathSetAsync(client => client.GetTodayWallpaperAsync()).ConfigureAwait(false);
|
||||
break;
|
||||
case BackgroundImageType.HutaoOfficialLauncher:
|
||||
await SetCurrentBackgroundPathSetAsync((client, token) => client.GetLauncherWallpaperAsync(token), token).ConfigureAwait(false);
|
||||
await SetCurrentBackgroundPathSetAsync(client => client.GetLauncherWallpaperAsync()).ConfigureAwait(false);
|
||||
break;
|
||||
default:
|
||||
currentBackgroundPathSet = [];
|
||||
@@ -116,10 +116,10 @@ internal sealed partial class BackgroundImageService : IBackgroundImageService
|
||||
currentBackgroundPathSet ??= [];
|
||||
return currentBackgroundPathSet;
|
||||
|
||||
async Task SetCurrentBackgroundPathSetAsync(Func<HutaoWallpaperClient, CancellationToken, ValueTask<Response<Wallpaper>>> responseFactory, CancellationToken token = default)
|
||||
async Task SetCurrentBackgroundPathSetAsync(Func<HutaoWallpaperClient, ValueTask<Response<Wallpaper>>> responseFactory)
|
||||
{
|
||||
HutaoWallpaperClient wallpaperClient = serviceProvider.GetRequiredService<HutaoWallpaperClient>();
|
||||
Response<Wallpaper> response = await responseFactory(wallpaperClient, token).ConfigureAwait(false);
|
||||
Response<Wallpaper> response = await responseFactory(wallpaperClient).ConfigureAwait(false);
|
||||
if (response is { Data: Wallpaper wallpaper })
|
||||
{
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
|
||||
@@ -5,5 +5,5 @@ namespace Snap.Hutao.Service.BackgroundImage;
|
||||
|
||||
internal interface IBackgroundImageService
|
||||
{
|
||||
ValueTask<ValueResult<bool, BackgroundImage?>> GetNextBackgroundImageAsync(BackgroundImage? previous, CancellationToken token = default);
|
||||
ValueTask<ValueResult<bool, BackgroundImage?>> GetNextBackgroundImageAsync(BackgroundImage? previous);
|
||||
}
|
||||
@@ -2,8 +2,9 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Snap.Hutao.Core.Database;
|
||||
using Snap.Hutao.Model.Entity;
|
||||
using Snap.Hutao.Service.Abstraction;
|
||||
using Snap.Hutao.Model.Entity.Database;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace Snap.Hutao.Service.Cultivation;
|
||||
@@ -14,90 +15,182 @@ internal sealed partial class CultivationDbService : ICultivationDbService
|
||||
{
|
||||
private readonly IServiceProvider serviceProvider;
|
||||
|
||||
public IServiceProvider ServiceProvider { get => serviceProvider; }
|
||||
|
||||
public List<InventoryItem> GetInventoryItemListByProjectId(Guid projectId)
|
||||
{
|
||||
return this.List<InventoryItem>(i => i.ProjectId == projectId);
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
{
|
||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
IQueryable<InventoryItem> result = appDbContext.InventoryItems.AsNoTracking().Where(a => a.ProjectId == projectId);
|
||||
return [.. result];
|
||||
}
|
||||
}
|
||||
|
||||
public ValueTask<List<InventoryItem>> GetInventoryItemListByProjectIdAsync(Guid projectId, CancellationToken token = default)
|
||||
public async ValueTask<List<InventoryItem>> GetInventoryItemListByProjectIdAsync(Guid projectId)
|
||||
{
|
||||
return this.ListAsync<InventoryItem>(i => i.ProjectId == projectId, token);
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
{
|
||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
return await appDbContext.InventoryItems
|
||||
.AsNoTracking()
|
||||
.Where(a => a.ProjectId == projectId)
|
||||
.ToListAsync()
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
public ValueTask<List<CultivateEntry>> GetCultivateEntryListByProjectIdAsync(Guid projectId, CancellationToken token = default)
|
||||
public async ValueTask<List<CultivateEntry>> GetCultivateEntryListByProjectIdAsync(Guid projectId)
|
||||
{
|
||||
return this.ListAsync<CultivateEntry>(e => e.ProjectId == projectId, token);
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
{
|
||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
return await appDbContext.CultivateEntries
|
||||
.AsNoTracking()
|
||||
.Where(e => e.ProjectId == projectId)
|
||||
.ToListAsync()
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
public ValueTask<List<CultivateEntry>> GetCultivateEntryListIncludingLevelInformationByProjectIdAsync(Guid projectId, CancellationToken token = default)
|
||||
public async ValueTask<List<CultivateEntry>> GetCultivateEntryIncludeLevelInformationListByProjectIdAsync(Guid projectId)
|
||||
{
|
||||
return this.ListAsync<CultivateEntry, CultivateEntry>(query => query.Where(e => e.ProjectId == projectId).Include(e => e.LevelInformation), token);
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
{
|
||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
return await appDbContext.CultivateEntries
|
||||
.AsNoTracking()
|
||||
.Where(e => e.ProjectId == projectId)
|
||||
.Include(e => e.LevelInformation)
|
||||
.ToListAsync()
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
public ValueTask<List<CultivateItem>> GetCultivateItemListByEntryIdAsync(Guid entryId, CancellationToken token = default)
|
||||
public async ValueTask<List<CultivateItem>> GetCultivateItemListByEntryIdAsync(Guid entryId)
|
||||
{
|
||||
return this.ListAsync<CultivateItem, CultivateItem>(query => query.Where(i => i.EntryId == entryId).OrderBy(i => i.ItemId), token);
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
{
|
||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
return await appDbContext.CultivateItems
|
||||
.Where(i => i.EntryId == entryId)
|
||||
.OrderBy(i => i.ItemId)
|
||||
.ToListAsync()
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask RemoveCultivateEntryByIdAsync(Guid entryId, CancellationToken token = default)
|
||||
public async ValueTask RemoveCultivateEntryByIdAsync(Guid entryId)
|
||||
{
|
||||
await this.DeleteByInnerIdAsync<CultivateEntry>(entryId, token).ConfigureAwait(false);
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
{
|
||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
await appDbContext.CultivateEntries
|
||||
.ExecuteDeleteWhereAsync(i => i.InnerId == entryId)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateCultivateItem(CultivateItem item)
|
||||
{
|
||||
this.Update(item);
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
{
|
||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
appDbContext.CultivateItems.UpdateAndSave(item);
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask UpdateCultivateItemAsync(CultivateItem item, CancellationToken token = default)
|
||||
public async ValueTask UpdateCultivateItemAsync(CultivateItem item)
|
||||
{
|
||||
await this.UpdateAsync(item, token).ConfigureAwait(false);
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
{
|
||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
await appDbContext.CultivateItems.UpdateAndSaveAsync(item).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask<CultivateEntry?> GetCultivateEntryByProjectIdAndItemIdAsync(Guid projectId, uint itemId, CancellationToken token = default)
|
||||
public async ValueTask<CultivateEntry?> GetCultivateEntryByProjectIdAndItemIdAsync(Guid projectId, uint itemId)
|
||||
{
|
||||
return await this.SingleOrDefaultAsync<CultivateEntry>(e => e.ProjectId == projectId && e.Id == itemId, token).ConfigureAwait(false);
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
{
|
||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
return await appDbContext.CultivateEntries
|
||||
.SingleOrDefaultAsync(e => e.ProjectId == projectId && e.Id == itemId)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask AddCultivateEntryAsync(CultivateEntry entry, CancellationToken token = default)
|
||||
public async ValueTask AddCultivateEntryAsync(CultivateEntry entry)
|
||||
{
|
||||
await this.AddAsync(entry, token).ConfigureAwait(false);
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
{
|
||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
await appDbContext.CultivateEntries.AddAndSaveAsync(entry).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask RemoveCultivateItemRangeByEntryIdAsync(Guid entryId, CancellationToken token = default)
|
||||
public async ValueTask RemoveCultivateItemRangeByEntryIdAsync(Guid entryId)
|
||||
{
|
||||
await this.DeleteAsync<CultivateItem>(i => i.EntryId == entryId, token).ConfigureAwait(false);
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
{
|
||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
await appDbContext.CultivateItems
|
||||
.ExecuteDeleteWhereAsync(i => i.EntryId == entryId)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask AddCultivateItemRangeAsync(IEnumerable<CultivateItem> toAdd, CancellationToken token = default)
|
||||
public async ValueTask AddCultivateItemRangeAsync(IEnumerable<CultivateItem> toAdd)
|
||||
{
|
||||
await this.AddRangeAsync(toAdd, token).ConfigureAwait(false);
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
{
|
||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
await appDbContext.CultivateItems.AddRangeAndSaveAsync(toAdd).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask AddCultivateProjectAsync(CultivateProject project, CancellationToken token = default)
|
||||
public async ValueTask AddCultivateProjectAsync(CultivateProject project)
|
||||
{
|
||||
await this.AddAsync(project, token).ConfigureAwait(false);
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
{
|
||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
await appDbContext.CultivateProjects.AddAndSaveAsync(project).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask RemoveCultivateProjectByIdAsync(Guid projectId, CancellationToken token = default)
|
||||
public async ValueTask RemoveCultivateProjectByIdAsync(Guid projectId)
|
||||
{
|
||||
await this.DeleteByInnerIdAsync<CultivateProject>(projectId, token).ConfigureAwait(false);
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
{
|
||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
await appDbContext.CultivateProjects
|
||||
.ExecuteDeleteWhereAsync(p => p.InnerId == projectId)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
public ObservableCollection<CultivateProject> GetCultivateProjectCollection()
|
||||
{
|
||||
return this.ObservableCollection<CultivateProject>();
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
{
|
||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
return appDbContext.CultivateProjects.AsNoTracking().ToObservableCollection();
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask RemoveLevelInformationByEntryIdAsync(Guid entryId, CancellationToken token = default)
|
||||
public async ValueTask RemoveLevelInformationByEntryIdAsync(Guid entryId)
|
||||
{
|
||||
await this.DeleteAsync<CultivateEntryLevelInformation>(l => l.EntryId == entryId, token).ConfigureAwait(false);
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
{
|
||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
await appDbContext.LevelInformations.ExecuteDeleteWhereAsync(l => l.EntryId == entryId).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask AddLevelInformationAsync(CultivateEntryLevelInformation levelInformation, CancellationToken token = default)
|
||||
public async ValueTask AddLevelInformationAsync(CultivateEntryLevelInformation levelInformation)
|
||||
{
|
||||
await this.AddAsync(levelInformation, token).ConfigureAwait(false);
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
{
|
||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
await appDbContext.LevelInformations.AddAndSaveAsync(levelInformation).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Core.Database;
|
||||
using Snap.Hutao.Model.Entity;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace Snap.Hutao.Service.Cultivation;
|
||||
|
||||
/// <summary>
|
||||
/// 集合部分
|
||||
/// </summary>
|
||||
internal sealed partial class CultivationService
|
||||
{
|
||||
private ObservableCollection<CultivateProject>? projects;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public CultivateProject? Current
|
||||
{
|
||||
get => dbCurrent.Current;
|
||||
set => dbCurrent.Current = value;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ObservableCollection<CultivateProject> ProjectCollection
|
||||
{
|
||||
get
|
||||
{
|
||||
if (projects is null)
|
||||
{
|
||||
projects = cultivationDbService.GetCultivateProjectCollection();
|
||||
Current ??= projects.SelectedOrDefault();
|
||||
}
|
||||
|
||||
return projects;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async ValueTask<ProjectAddResult> TryAddProjectAsync(CultivateProject project)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(project.Name))
|
||||
{
|
||||
return ProjectAddResult.InvalidName;
|
||||
}
|
||||
|
||||
ArgumentNullException.ThrowIfNull(projects);
|
||||
|
||||
if (projects.Any(a => a.Name == project.Name))
|
||||
{
|
||||
return ProjectAddResult.AlreadyExists;
|
||||
}
|
||||
|
||||
// Sync cache
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
projects.Add(project);
|
||||
|
||||
// Sync database
|
||||
await taskContext.SwitchToBackgroundAsync();
|
||||
await cultivationDbService.AddCultivateProjectAsync(project).ConfigureAwait(false);
|
||||
|
||||
return ProjectAddResult.Added;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async ValueTask RemoveProjectAsync(CultivateProject project)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(projects);
|
||||
|
||||
// Sync cache
|
||||
// Keep this on main thread.
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
projects.Remove(project);
|
||||
|
||||
// Sync database
|
||||
await taskContext.SwitchToBackgroundAsync();
|
||||
await cultivationDbService.RemoveCultivateProjectByIdAsync(project.InnerId).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
@@ -4,13 +4,13 @@
|
||||
using Snap.Hutao.Core.Database;
|
||||
using Snap.Hutao.Model;
|
||||
using Snap.Hutao.Model.Entity;
|
||||
using Snap.Hutao.Model.Entity.Database;
|
||||
using Snap.Hutao.Model.Entity.Primitive;
|
||||
using Snap.Hutao.Model.Metadata.Item;
|
||||
using Snap.Hutao.Service.Inventory;
|
||||
using Snap.Hutao.Service.Metadata.ContextAbstraction;
|
||||
using Snap.Hutao.ViewModel.Cultivation;
|
||||
using System.Collections.ObjectModel;
|
||||
using CalculateItem = Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate.Item;
|
||||
|
||||
namespace Snap.Hutao.Service.Cultivation;
|
||||
|
||||
@@ -25,46 +25,28 @@ internal sealed partial class CultivationService : ICultivationService
|
||||
private readonly ScopedDbCurrent<CultivateProject, Message.CultivateProjectChangedMessage> dbCurrent;
|
||||
private readonly ICultivationDbService cultivationDbService;
|
||||
private readonly IInventoryDbService inventoryDbService;
|
||||
private readonly IServiceProvider serviceProvider;
|
||||
private readonly ITaskContext taskContext;
|
||||
|
||||
private ObservableCollection<CultivateProject>? projects;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public CultivateProject? Current
|
||||
{
|
||||
get => dbCurrent.Current;
|
||||
set => dbCurrent.Current = value;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ObservableCollection<CultivateProject> ProjectCollection
|
||||
{
|
||||
get
|
||||
{
|
||||
if (projects is null)
|
||||
{
|
||||
projects = cultivationDbService.GetCultivateProjectCollection();
|
||||
Current ??= projects.SelectedOrDefault();
|
||||
}
|
||||
|
||||
return projects;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public List<InventoryItemView> GetInventoryItemViews(CultivateProject cultivateProject, ICultivationMetadataContext context, ICommand saveCommand)
|
||||
{
|
||||
Guid projectId = cultivateProject.InnerId;
|
||||
List<InventoryItem> entities = cultivationDbService.GetInventoryItemListByProjectId(projectId);
|
||||
|
||||
List<InventoryItemView> results = [];
|
||||
foreach (Material meta in context.EnumerateInventoryMaterial())
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
{
|
||||
InventoryItem entity = entities.SingleOrDefault(e => e.ItemId == meta.Id) ?? InventoryItem.From(projectId, meta.Id);
|
||||
results.Add(new(entity, meta, saveCommand));
|
||||
}
|
||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
|
||||
return results;
|
||||
Guid projectId = cultivateProject.InnerId;
|
||||
List<InventoryItem> entities = cultivationDbService.GetInventoryItemListByProjectId(projectId);
|
||||
|
||||
List<InventoryItemView> results = [];
|
||||
foreach (Material meta in context.EnumerateInventoryMaterial())
|
||||
{
|
||||
InventoryItem entity = entities.SingleOrDefault(e => e.ItemId == meta.Id) ?? InventoryItem.From(projectId, meta.Id);
|
||||
results.Add(new(entity, meta, saveCommand));
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -72,15 +54,13 @@ internal sealed partial class CultivationService : ICultivationService
|
||||
{
|
||||
await taskContext.SwitchToBackgroundAsync();
|
||||
List<CultivateEntry> entries = await cultivationDbService
|
||||
.GetCultivateEntryListIncludingLevelInformationByProjectIdAsync(cultivateProject.InnerId)
|
||||
.GetCultivateEntryIncludeLevelInformationListByProjectIdAsync(cultivateProject.InnerId)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
List<CultivateEntryView> resultEntries = new(entries.Count);
|
||||
foreach (CultivateEntry entry in entries)
|
||||
{
|
||||
List<CultivateItemView> entryItems = [];
|
||||
|
||||
// Async operation here, thus we can't use the Span trick.
|
||||
foreach (CultivateItem cultivateItem in await cultivationDbService.GetCultivateItemListByEntryIdAsync(entry.InnerId).ConfigureAwait(false))
|
||||
{
|
||||
entryItems.Add(new(cultivateItem, context.GetMaterial(cultivateItem.ItemId)));
|
||||
@@ -98,7 +78,9 @@ internal sealed partial class CultivationService : ICultivationService
|
||||
resultEntries.Add(new(entry, item, entryItems));
|
||||
}
|
||||
|
||||
return resultEntries.SortByDescending(e => e.IsToday).ToObservableCollection();
|
||||
return resultEntries
|
||||
.OrderByDescending(e => e.IsToday)
|
||||
.ToObservableCollection();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -110,9 +92,11 @@ internal sealed partial class CultivationService : ICultivationService
|
||||
|
||||
Guid projectId = cultivateProject.InnerId;
|
||||
|
||||
foreach (CultivateEntry entry in await cultivationDbService.GetCultivateEntryListByProjectIdAsync(projectId, token).ConfigureAwait(false))
|
||||
token.ThrowIfCancellationRequested();
|
||||
|
||||
foreach (CultivateEntry entry in await cultivationDbService.GetCultivateEntryListByProjectIdAsync(projectId).ConfigureAwait(false))
|
||||
{
|
||||
foreach (CultivateItem item in await cultivationDbService.GetCultivateItemListByEntryIdAsync(entry.InnerId, token).ConfigureAwait(false))
|
||||
foreach (CultivateItem item in await cultivationDbService.GetCultivateItemListByEntryIdAsync(entry.InnerId).ConfigureAwait(false))
|
||||
{
|
||||
if (item.IsFinished)
|
||||
{
|
||||
@@ -130,7 +114,9 @@ internal sealed partial class CultivationService : ICultivationService
|
||||
}
|
||||
}
|
||||
|
||||
foreach (InventoryItem inventoryItem in await cultivationDbService.GetInventoryItemListByProjectIdAsync(projectId, token).ConfigureAwait(false))
|
||||
token.ThrowIfCancellationRequested();
|
||||
|
||||
foreach (InventoryItem inventoryItem in await cultivationDbService.GetInventoryItemListByProjectIdAsync(projectId).ConfigureAwait(false))
|
||||
{
|
||||
if (resultItems.SingleOrDefault(i => i.Inner.Id == inventoryItem.ItemId) is { } existedItem)
|
||||
{
|
||||
@@ -138,12 +124,15 @@ internal sealed partial class CultivationService : ICultivationService
|
||||
}
|
||||
}
|
||||
|
||||
token.ThrowIfCancellationRequested();
|
||||
|
||||
return resultItems.SortBy(item => item.Inner.Id, MaterialIdComparer.Shared).ToObservableCollection();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async ValueTask RemoveCultivateEntryAsync(Guid entryId)
|
||||
{
|
||||
await taskContext.SwitchToBackgroundAsync();
|
||||
await cultivationDbService.RemoveCultivateEntryByIdAsync(entryId).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
@@ -160,7 +149,7 @@ internal sealed partial class CultivationService : ICultivationService
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async ValueTask<bool> SaveConsumptionAsync(CultivateType type, uint itemId, List<CalculateItem> items, LevelInformation levelInformation)
|
||||
public async ValueTask<bool> SaveConsumptionAsync(CultivateType type, uint itemId, List<Web.Hoyolab.Takumi.Event.Calculate.Item> items, LevelInformation levelInformation)
|
||||
{
|
||||
if (items.Count == 0)
|
||||
{
|
||||
@@ -201,45 +190,4 @@ internal sealed partial class CultivationService : ICultivationService
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async ValueTask<ProjectAddResultKind> TryAddProjectAsync(CultivateProject project)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(project.Name))
|
||||
{
|
||||
return ProjectAddResultKind.InvalidName;
|
||||
}
|
||||
|
||||
ArgumentNullException.ThrowIfNull(projects);
|
||||
|
||||
if (projects.Any(a => a.Name == project.Name))
|
||||
{
|
||||
return ProjectAddResultKind.AlreadyExists;
|
||||
}
|
||||
|
||||
// Sync cache
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
projects.Add(project);
|
||||
|
||||
// Sync database
|
||||
await taskContext.SwitchToBackgroundAsync();
|
||||
await cultivationDbService.AddCultivateProjectAsync(project).ConfigureAwait(false);
|
||||
|
||||
return ProjectAddResultKind.Added;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async ValueTask RemoveProjectAsync(CultivateProject project)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(projects);
|
||||
|
||||
// Sync cache
|
||||
// Keep this on main thread.
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
projects.Remove(project);
|
||||
|
||||
// Sync database
|
||||
await taskContext.SwitchToBackgroundAsync();
|
||||
await cultivationDbService.RemoveCultivateProjectByIdAsync(project.InnerId).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
@@ -2,48 +2,43 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Model.Entity;
|
||||
using Snap.Hutao.Service.Abstraction;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace Snap.Hutao.Service.Cultivation;
|
||||
|
||||
internal interface ICultivationDbService : IAppDbService<InventoryItem>,
|
||||
IAppDbService<CultivateEntryLevelInformation>,
|
||||
IAppDbService<CultivateProject>,
|
||||
IAppDbService<CultivateEntry>,
|
||||
IAppDbService<CultivateItem>
|
||||
internal interface ICultivationDbService
|
||||
{
|
||||
ValueTask AddCultivateProjectAsync(CultivateProject project, CancellationToken token = default);
|
||||
ValueTask AddCultivateProjectAsync(CultivateProject project);
|
||||
|
||||
ValueTask RemoveCultivateEntryByIdAsync(Guid entryId, CancellationToken token = default);
|
||||
ValueTask RemoveCultivateEntryByIdAsync(Guid entryId);
|
||||
|
||||
ValueTask RemoveCultivateItemRangeByEntryIdAsync(Guid entryId, CancellationToken token = default);
|
||||
ValueTask RemoveCultivateItemRangeByEntryIdAsync(Guid entryId);
|
||||
|
||||
ValueTask RemoveCultivateProjectByIdAsync(Guid projectId, CancellationToken token = default);
|
||||
ValueTask RemoveCultivateProjectByIdAsync(Guid projectId);
|
||||
|
||||
ValueTask<CultivateEntry?> GetCultivateEntryByProjectIdAndItemIdAsync(Guid projectId, uint itemId, CancellationToken token = default);
|
||||
ValueTask<CultivateEntry?> GetCultivateEntryByProjectIdAndItemIdAsync(Guid projectId, uint itemId);
|
||||
|
||||
ValueTask<List<CultivateEntry>> GetCultivateEntryListByProjectIdAsync(Guid projectId, CancellationToken token = default);
|
||||
ValueTask<List<CultivateEntry>> GetCultivateEntryListByProjectIdAsync(Guid projectId);
|
||||
|
||||
ValueTask<List<CultivateItem>> GetCultivateItemListByEntryIdAsync(Guid entryId, CancellationToken token = default);
|
||||
ValueTask<List<CultivateItem>> GetCultivateItemListByEntryIdAsync(Guid entryId);
|
||||
|
||||
ObservableCollection<CultivateProject> GetCultivateProjectCollection();
|
||||
|
||||
List<InventoryItem> GetInventoryItemListByProjectId(Guid projectId);
|
||||
|
||||
ValueTask<List<InventoryItem>> GetInventoryItemListByProjectIdAsync(Guid projectId, CancellationToken token = default);
|
||||
ValueTask<List<InventoryItem>> GetInventoryItemListByProjectIdAsync(Guid projectId);
|
||||
|
||||
ValueTask AddCultivateEntryAsync(CultivateEntry entry, CancellationToken token = default);
|
||||
ValueTask AddCultivateEntryAsync(CultivateEntry entry);
|
||||
|
||||
ValueTask AddCultivateItemRangeAsync(IEnumerable<CultivateItem> toAdd, CancellationToken token = default);
|
||||
ValueTask AddCultivateItemRangeAsync(IEnumerable<CultivateItem> toAdd);
|
||||
|
||||
void UpdateCultivateItem(CultivateItem item);
|
||||
|
||||
ValueTask UpdateCultivateItemAsync(CultivateItem item, CancellationToken token = default);
|
||||
ValueTask UpdateCultivateItemAsync(CultivateItem item);
|
||||
|
||||
ValueTask RemoveLevelInformationByEntryIdAsync(Guid entryId, CancellationToken token = default);
|
||||
ValueTask RemoveLevelInformationByEntryIdAsync(Guid entryId);
|
||||
|
||||
ValueTask AddLevelInformationAsync(CultivateEntryLevelInformation levelInformation, CancellationToken token = default);
|
||||
ValueTask AddLevelInformationAsync(CultivateEntryLevelInformation levelInformation);
|
||||
|
||||
ValueTask<List<CultivateEntry>> GetCultivateEntryListIncludingLevelInformationByProjectIdAsync(Guid projectId, CancellationToken token = default);
|
||||
ValueTask<List<CultivateEntry>> GetCultivateEntryIncludeLevelInformationListByProjectIdAsync(Guid projectId);
|
||||
}
|
||||
@@ -65,5 +65,5 @@ internal interface ICultivationService
|
||||
/// </summary>
|
||||
/// <param name="project">项目</param>
|
||||
/// <returns>添加操作的结果</returns>
|
||||
ValueTask<ProjectAddResultKind> TryAddProjectAsync(CultivateProject project);
|
||||
ValueTask<ProjectAddResult> TryAddProjectAsync(CultivateProject project);
|
||||
}
|
||||
@@ -8,10 +8,9 @@ namespace Snap.Hutao.Service.Cultivation;
|
||||
|
||||
internal sealed class MaterialIdComparer : IComparer<MaterialId>
|
||||
{
|
||||
private static MaterialIdComparer? shared;
|
||||
private static object? syncRoot;
|
||||
private static readonly Lazy<MaterialIdComparer> LazyShared = new(() => new());
|
||||
|
||||
public static MaterialIdComparer Shared { get => LazyInitializer.EnsureInitialized(ref shared, ref syncRoot, () => new()); }
|
||||
public static MaterialIdComparer Shared { get => LazyShared.Value; }
|
||||
|
||||
public int Compare(MaterialId x, MaterialId y)
|
||||
{
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace Snap.Hutao.Service.Cultivation;
|
||||
/// 项目添加结果
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
internal enum ProjectAddResultKind
|
||||
internal enum ProjectAddResult
|
||||
{
|
||||
/// <summary>
|
||||
/// 添加成功
|
||||
@@ -25,7 +25,7 @@ internal sealed partial class DailyNoteNotificationOperation
|
||||
|
||||
private readonly ITaskContext taskContext;
|
||||
private readonly IGameServiceFacade gameService;
|
||||
private readonly IServiceScopeFactory serviceScopeFactory;
|
||||
private readonly BindingClient bindingClient;
|
||||
private readonly DailyNoteOptions options;
|
||||
private readonly RuntimeOptions runtimeOptions;
|
||||
|
||||
@@ -58,19 +58,14 @@ internal sealed partial class DailyNoteNotificationOperation
|
||||
}
|
||||
else
|
||||
{
|
||||
using (IServiceScope scope = serviceScopeFactory.CreateScope())
|
||||
Response<ListWrapper<UserGameRole>> rolesResponse = await bindingClient
|
||||
.GetUserGameRolesOverseaAwareAsync(entry.User)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (rolesResponse.IsOk())
|
||||
{
|
||||
BindingClient bindingClient = scope.ServiceProvider.GetRequiredService<BindingClient>();
|
||||
|
||||
Response<ListWrapper<UserGameRole>> rolesResponse = await bindingClient
|
||||
.GetUserGameRolesOverseaAwareAsync(entry.User)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (rolesResponse.IsOk())
|
||||
{
|
||||
List<UserGameRole> roles = rolesResponse.Data.List;
|
||||
attribution = roles.SingleOrDefault(r => r.GameUid == entry.Uid)?.ToString() ?? ToastAttributionUnknown;
|
||||
}
|
||||
List<UserGameRole> roles = rolesResponse.Data.List;
|
||||
attribution = roles.SingleOrDefault(r => r.GameUid == entry.Uid)?.ToString() ?? ToastAttributionUnknown;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -181,7 +181,6 @@
|
||||
<None Remove="View\Dialog\LaunchGameConfigurationFixDialog.xaml" />
|
||||
<None Remove="View\Dialog\LaunchGamePackageConvertDialog.xaml" />
|
||||
<None Remove="View\Dialog\ReconfirmDialog.xaml" />
|
||||
<None Remove="View\Dialog\SpiralAbyssUploadRecordHomaNotLoginDialog.xaml" />
|
||||
<None Remove="View\Dialog\UpdatePackageDownloadConfirmDialog.xaml" />
|
||||
<None Remove="View\Dialog\UserDialog.xaml" />
|
||||
<None Remove="View\Dialog\UserQRCodeDialog.xaml" />
|
||||
@@ -355,11 +354,6 @@
|
||||
<ItemGroup Condition="'$(DisableMsixProjectCapabilityAddedByProject)'!='true' and '$(EnablePreviewMsixTooling)'=='true'">
|
||||
<ProjectCapability Include="Msix" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="View\Dialog\SpiralAbyssUploadRecordHomaNotLoginDialog.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="View\Dialog\UpdatePackageDownloadConfirmDialog.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
<ContentDialog
|
||||
x:Class="Snap.Hutao.View.Dialog.SpiralAbyssUploadRecordHomaNotLoginDialog"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:shcm="using:Snap.Hutao.Control.Markup"
|
||||
Title="{shcm:ResourceString Name=ViewDialogSpiralAbyssUploadRecordHomaNotLoginTitle}"
|
||||
CloseButtonText="{shcm:ResourceString Name=ViewDialogSpiralAbyssUploadRecordHomaNotLoginCloseButtonText}"
|
||||
DefaultButton="Close"
|
||||
PrimaryButtonText="{shcm:ResourceString Name=ViewDialogSpiralAbyssUploadRecordHomaNotLoginPrimaryButtonText}"
|
||||
Style="{StaticResource DefaultContentDialogStyle}"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<TextBlock Text="{shcm:ResourceString Name=ViewDialogSpiralAbyssUploadRecordHomaNotLoginHint}"/>
|
||||
</ContentDialog>
|
||||
@@ -1,24 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Snap.Hutao.View.Dialog;
|
||||
|
||||
internal sealed partial class SpiralAbyssUploadRecordHomaNotLoginDialog : ContentDialog
|
||||
{
|
||||
private readonly ITaskContext taskContext;
|
||||
|
||||
public SpiralAbyssUploadRecordHomaNotLoginDialog(IServiceProvider serviceProvider)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
taskContext = serviceProvider.GetRequiredService<ITaskContext>();
|
||||
}
|
||||
|
||||
public async ValueTask<bool> ConfirmAsync()
|
||||
{
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
return await ShowAsync() is ContentDialogResult.Primary;
|
||||
}
|
||||
}
|
||||
@@ -265,6 +265,22 @@
|
||||
</cwc:SettingsExpander.Items>
|
||||
</cwc:SettingsExpander>
|
||||
</ScrollViewer>
|
||||
<ScrollViewer>
|
||||
<cwc:SettingsExpander
|
||||
Description="{shcm:ResourceString Name=ViewPageSettingHutaoCloudAutoUploadDescription}"
|
||||
Header="{shcm:ResourceString Name=ViewPageSettingHutaoCloudAutoUploadHeader}"
|
||||
HeaderIcon="{shcm:FontIcon Glyph=}"
|
||||
IsExpanded="True">
|
||||
<cwc:SettingsExpander.Items>
|
||||
<cwc:SettingsCard Description="{shcm:ResourceString Name=ViewPageSettingHutaoCloudGachaLogAutoUploadDescription}" Header="{shcm:ResourceString Name=ViewPageSettingHutaoCloudGachaLogAutoUploadHeader}">
|
||||
<ToggleSwitch IsOn="{Binding AppOptions.IsAutoUploadGachaLogEnabled, Mode=TwoWay}"/>
|
||||
</cwc:SettingsCard>
|
||||
<cwc:SettingsCard Description="{shcm:ResourceString Name=ViewPageSettingHutaoCloudSpiralAbyssAutoUploadDescription}" Header="{shcm:ResourceString Name=ViewPageSettingHutaoCloudSpiralAbyssAutoUploadHeader}">
|
||||
<ToggleSwitch IsOn="{Binding AppOptions.IsAutoUploadSpiralAbyssRecordEnabled, Mode=TwoWay}"/>
|
||||
</cwc:SettingsCard>
|
||||
</cwc:SettingsExpander.Items>
|
||||
</cwc:SettingsExpander>
|
||||
</ScrollViewer>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Border>
|
||||
|
||||
@@ -120,7 +120,7 @@ internal sealed partial class AvatarPropertyViewModel : Abstraction.ViewModel, I
|
||||
{
|
||||
try
|
||||
{
|
||||
ValueResult<RefreshResultKind, Summary?> summaryResult;
|
||||
ValueResult<RefreshResult, Summary?> summaryResult;
|
||||
using (await EnterCriticalExecutionAsync().ConfigureAwait(false))
|
||||
{
|
||||
ContentDialog dialog = await contentDialogFactory
|
||||
@@ -135,8 +135,8 @@ internal sealed partial class AvatarPropertyViewModel : Abstraction.ViewModel, I
|
||||
}
|
||||
}
|
||||
|
||||
(RefreshResultKind result, Summary? summary) = summaryResult;
|
||||
if (result == RefreshResultKind.Ok)
|
||||
(RefreshResult result, Summary? summary) = summaryResult;
|
||||
if (result == RefreshResult.Ok)
|
||||
{
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
Summary = summary;
|
||||
@@ -146,16 +146,16 @@ internal sealed partial class AvatarPropertyViewModel : Abstraction.ViewModel, I
|
||||
{
|
||||
switch (result)
|
||||
{
|
||||
case RefreshResultKind.APIUnavailable:
|
||||
case RefreshResult.APIUnavailable:
|
||||
infoBarService.Warning(SH.ViewModelAvatarPropertyEnkaApiUnavailable);
|
||||
break;
|
||||
|
||||
case RefreshResultKind.StatusCodeNotSucceed:
|
||||
case RefreshResult.StatusCodeNotSucceed:
|
||||
ArgumentNullException.ThrowIfNull(summary);
|
||||
infoBarService.Warning(summary.Message);
|
||||
break;
|
||||
|
||||
case RefreshResultKind.ShowcaseNotOpen:
|
||||
case RefreshResult.ShowcaseNotOpen:
|
||||
infoBarService.Warning(SH.ViewModelAvatarPropertyShowcaseNotOpen);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -86,15 +86,15 @@ internal sealed partial class CultivationViewModel : Abstraction.ViewModel
|
||||
|
||||
switch (await cultivationService.TryAddProjectAsync(project).ConfigureAwait(false))
|
||||
{
|
||||
case ProjectAddResultKind.Added:
|
||||
case ProjectAddResult.Added:
|
||||
infoBarService.Success(SH.ViewModelCultivationProjectAdded);
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
SelectedProject = project;
|
||||
break;
|
||||
case ProjectAddResultKind.InvalidName:
|
||||
case ProjectAddResult.InvalidName:
|
||||
infoBarService.Information(SH.ViewModelCultivationProjectInvalidName);
|
||||
break;
|
||||
case ProjectAddResultKind.AlreadyExists:
|
||||
case ProjectAddResult.AlreadyExists:
|
||||
infoBarService.Information(SH.ViewModelCultivationProjectAlreadyExists);
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -11,6 +11,7 @@ using Snap.Hutao.Factory.Picker;
|
||||
using Snap.Hutao.Factory.Progress;
|
||||
using Snap.Hutao.Model.Entity;
|
||||
using Snap.Hutao.Model.InterChange.GachaLog;
|
||||
using Snap.Hutao.Service;
|
||||
using Snap.Hutao.Service.GachaLog;
|
||||
using Snap.Hutao.Service.GachaLog.QueryProvider;
|
||||
using Snap.Hutao.Service.Notification;
|
||||
@@ -38,6 +39,7 @@ internal sealed partial class GachaLogViewModel : Abstraction.ViewModel
|
||||
private readonly IInfoBarService infoBarService;
|
||||
private readonly JsonSerializerOptions options;
|
||||
private readonly ITaskContext taskContext;
|
||||
private readonly AppOptions appOptions;
|
||||
|
||||
private ObservableCollection<GachaArchive>? archives;
|
||||
private GachaArchive? selectedArchive;
|
||||
@@ -198,6 +200,11 @@ internal sealed partial class GachaLogViewModel : Abstraction.ViewModel
|
||||
{
|
||||
await SetSelectedArchiveAndUpdateStatisticsAsync(gachaLogService.CurrentArchive, true).ConfigureAwait(false);
|
||||
await hideToken.DisposeAsync().ConfigureAwait(false);
|
||||
|
||||
if (HutaoCloudViewModel.Options.IsCloudServiceAllowed && appOptions.IsAutoUploadGachaLogEnabled)
|
||||
{
|
||||
await HutaoCloudViewModel.UploadAsync(gachaLogService.CurrentArchive).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -47,6 +47,35 @@ internal sealed partial class HutaoCloudViewModel : Abstraction.ViewModel
|
||||
/// </summary>
|
||||
internal ICommand RetrieveCommand { get; set; }
|
||||
|
||||
[Command("UploadCommand")]
|
||||
internal async Task UploadAsync(GachaArchive? gachaArchive)
|
||||
{
|
||||
if (gachaArchive is not null)
|
||||
{
|
||||
ContentDialog dialog = await contentDialogFactory
|
||||
.CreateForIndeterminateProgressAsync(SH.ViewModelGachaLogUploadToHutaoCloudProgress)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
bool isOk;
|
||||
string message;
|
||||
|
||||
using (await dialog.BlockAsync(taskContext).ConfigureAwait(false))
|
||||
{
|
||||
(isOk, message) = await hutaoCloudService.UploadGachaItemsAsync(gachaArchive).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (isOk)
|
||||
{
|
||||
infoBarService.Success(message);
|
||||
await RefreshUidCollectionAsync().ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
infoBarService.Warning(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步获取祈愿记录
|
||||
/// </summary>
|
||||
@@ -77,35 +106,6 @@ internal sealed partial class HutaoCloudViewModel : Abstraction.ViewModel
|
||||
await Windows.System.Launcher.LaunchUriAsync("https://afdian.net/item/80d3b9decf9011edb5f452540025c377".ToUri());
|
||||
}
|
||||
|
||||
[Command("UploadCommand")]
|
||||
private async Task UploadAsync(GachaArchive? gachaArchive)
|
||||
{
|
||||
if (gachaArchive is not null)
|
||||
{
|
||||
ContentDialog dialog = await contentDialogFactory
|
||||
.CreateForIndeterminateProgressAsync(SH.ViewModelGachaLogUploadToHutaoCloudProgress)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
bool isOk;
|
||||
string message;
|
||||
|
||||
using (await dialog.BlockAsync(taskContext).ConfigureAwait(false))
|
||||
{
|
||||
(isOk, message) = await hutaoCloudService.UploadGachaItemsAsync(gachaArchive).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (isOk)
|
||||
{
|
||||
infoBarService.Success(message);
|
||||
await RefreshUidCollectionAsync().ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
infoBarService.Warning(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Command("DeleteCommand")]
|
||||
private async Task DeleteAsync(string? uid)
|
||||
{
|
||||
|
||||
@@ -5,13 +5,11 @@ using CommunityToolkit.Mvvm.Messaging;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Snap.Hutao.Factory.ContentDialog;
|
||||
using Snap.Hutao.Message;
|
||||
using Snap.Hutao.Service;
|
||||
using Snap.Hutao.Service.Hutao;
|
||||
using Snap.Hutao.Service.Navigation;
|
||||
using Snap.Hutao.Service.Notification;
|
||||
using Snap.Hutao.Service.SpiralAbyss;
|
||||
using Snap.Hutao.Service.User;
|
||||
using Snap.Hutao.View.Dialog;
|
||||
using Snap.Hutao.View.Page;
|
||||
using Snap.Hutao.ViewModel.Complex;
|
||||
using Snap.Hutao.ViewModel.User;
|
||||
using Snap.Hutao.Web.Hutao.Response;
|
||||
@@ -32,12 +30,12 @@ internal sealed partial class SpiralAbyssRecordViewModel : Abstraction.ViewModel
|
||||
private readonly ISpiralAbyssRecordService spiralAbyssRecordService;
|
||||
private readonly IContentDialogFactory contentDialogFactory;
|
||||
private readonly HutaoSpiralAbyssClient spiralAbyssClient;
|
||||
private readonly INavigationService navigationService;
|
||||
private readonly IInfoBarService infoBarService;
|
||||
private readonly ITaskContext taskContext;
|
||||
private readonly IUserService userService;
|
||||
private readonly HutaoDatabaseViewModel hutaoDatabaseViewModel;
|
||||
private readonly HutaoUserOptions hutaoUserOptions;
|
||||
private readonly AppOptions appOptions;
|
||||
|
||||
private ObservableCollection<SpiralAbyssView>? spiralAbyssEntries;
|
||||
private SpiralAbyssView? selectedView;
|
||||
@@ -128,6 +126,11 @@ internal sealed partial class SpiralAbyssRecordViewModel : Abstraction.ViewModel
|
||||
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
SelectedView = SpiralAbyssEntries.FirstOrDefault(s => s.Engaged);
|
||||
|
||||
if (hutaoUserOptions.IsLoggedIn && appOptions.IsAutoUploadSpiralAbyssRecordEnabled)
|
||||
{
|
||||
await UploadSpiralAbyssRecordCoreAsync(userAndUid).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -139,42 +142,45 @@ internal sealed partial class SpiralAbyssRecordViewModel : Abstraction.ViewModel
|
||||
{
|
||||
if (!hutaoUserOptions.IsLoggedIn)
|
||||
{
|
||||
SpiralAbyssUploadRecordHomaNotLoginDialog dialog = await contentDialogFactory
|
||||
.CreateInstanceAsync<SpiralAbyssUploadRecordHomaNotLoginDialog>()
|
||||
ContentDialogResult result = await contentDialogFactory
|
||||
.CreateForConfirmCancelAsync(SH.ViewModelSpiralAbyssUploadRecordHomaNotLoginTitle, SH.ViewModelSpiralAbyssUploadRecordHomaNotLoginContent)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (!await dialog.ConfirmAsync().ConfigureAwait(false))
|
||||
if (result is not ContentDialogResult.Primary)
|
||||
{
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
await navigationService.NavigateAsync<SettingPage>(INavigationAwaiter.Default, true).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SimpleRecord? record = await spiralAbyssClient.GetPlayerRecordAsync(userAndUid).ConfigureAwait(false);
|
||||
if (record is not null)
|
||||
{
|
||||
Web.Response.Response response = await spiralAbyssClient.UploadRecordAsync(record).ConfigureAwait(false);
|
||||
|
||||
if (response is { ReturnCode: 0 })
|
||||
{
|
||||
if (response is ILocalizableResponse localizableResponse)
|
||||
{
|
||||
infoBarService.Success(localizableResponse.GetLocalizationMessage());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (response is ILocalizableResponse localizableResponse)
|
||||
{
|
||||
infoBarService.Warning(localizableResponse.GetLocalizationMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
await UploadSpiralAbyssRecordCoreAsync(userAndUid).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
infoBarService.Warning(SH.MustSelectUserAndUid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask UploadSpiralAbyssRecordCoreAsync(UserAndUid userAndUid)
|
||||
{
|
||||
SimpleRecord? record = await spiralAbyssClient.GetPlayerRecordAsync(userAndUid).ConfigureAwait(false);
|
||||
if (record is not null)
|
||||
{
|
||||
Web.Response.Response response = await spiralAbyssClient.UploadRecordAsync(record).ConfigureAwait(false);
|
||||
|
||||
if (response is { ReturnCode: 0 })
|
||||
{
|
||||
if (response is ILocalizableResponse localizableResponse)
|
||||
{
|
||||
infoBarService.Success(localizableResponse.GetLocalizationMessage());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (response is ILocalizableResponse localizableResponse)
|
||||
{
|
||||
infoBarService.Warning(localizableResponse.GetLocalizationMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user