diff --git a/src/Snap.Hutao/Snap.Hutao/App.xaml b/src/Snap.Hutao/Snap.Hutao/App.xaml
index 245ac7ad..100f6c55 100644
--- a/src/Snap.Hutao/Snap.Hutao/App.xaml
+++ b/src/Snap.Hutao/Snap.Hutao/App.xaml
@@ -81,6 +81,12 @@
https://static.snapgenshin.com/EmotionIcon/UI_EmotionIcon250.png
https://static.snapgenshin.com/EmotionIcon/UI_EmotionIcon272.png
https://static.snapgenshin.com/EmotionIcon/UI_EmotionIcon293.png
+
+ https://smms.app/image/x9psnPrcbYoCl6U
+ https://smms.app/image/n4gwxlFGPTX2j8p
+ https://smms.app/image/kbh1a2YVXpxWuez
+ https://smms.app/image/zJ4UYqKiD6uQlLc
+ https://smms.app/image/DQyTF3rv4aA8MZV
diff --git a/src/Snap.Hutao/Snap.Hutao/Extension/EnumerableExtension.List.cs b/src/Snap.Hutao/Snap.Hutao/Extension/EnumerableExtension.List.cs
index 26b97745..0b09464f 100644
--- a/src/Snap.Hutao/Snap.Hutao/Extension/EnumerableExtension.List.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Extension/EnumerableExtension.List.cs
@@ -105,17 +105,19 @@ internal static partial class EnumerableExtension
return results;
}
- ///
- /// 按元素的键排序
- ///
- /// 元素类型
- /// 键类型
- /// 列表
- /// 键选择器
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
- public static void SortBy(this List list, Func keySelector)
+ public static List SortBy(this List list, Func keySelector)
where TKey : IComparable
{
list.Sort((left, right) => keySelector(left).CompareTo(keySelector(right)));
+ return list;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveOptimization)]
+ public static List SortByDescending(this List list, Func keySelector)
+ where TKey : IComparable
+ {
+ list.Sort((left, right) => keySelector(right).CompareTo(keySelector(left)));
+ return list;
}
}
diff --git a/src/Snap.Hutao/Snap.Hutao/Resource/Icon/UI_ItemIcon_220021.png b/src/Snap.Hutao/Snap.Hutao/Resource/Icon/UI_ItemIcon_220021.png
deleted file mode 100644
index 3d006d7b..00000000
Binary files a/src/Snap.Hutao/Snap.Hutao/Resource/Icon/UI_ItemIcon_220021.png and /dev/null differ
diff --git a/src/Snap.Hutao/Snap.Hutao/Resource/Icon/UI_MarkQuest_Events_Proce.png b/src/Snap.Hutao/Snap.Hutao/Resource/Icon/UI_MarkQuest_Events_Proce.png
deleted file mode 100644
index 0899c458..00000000
Binary files a/src/Snap.Hutao/Snap.Hutao/Resource/Icon/UI_MarkQuest_Events_Proce.png and /dev/null differ
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteNotificationOperation.cs b/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteNotificationOperation.cs
index d1890b35..36653791 100644
--- a/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteNotificationOperation.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteNotificationOperation.cs
@@ -141,7 +141,7 @@ internal sealed class DailyNoteNotificationOperation
{
notifyInfos.Add(new(
SH.ServiceDailyNoteNotifierResin,
- Web.Hoyolab.OssImages.UIItemIcon210,
+ Web.Hoyolab.Images.UIItemIcon210,
$"{entry.DailyNote.CurrentResin}",
string.Format(SH.ServiceDailyNoteNotifierResinCurrent, entry.DailyNote.CurrentResin)));
entry.ResinNotifySuppressed = true;
@@ -158,7 +158,7 @@ internal sealed class DailyNoteNotificationOperation
{
notifyInfos.Add(new(
SH.ServiceDailyNoteNotifierHomeCoin,
- Web.Hoyolab.OssImages.UIItemIcon204,
+ Web.Hoyolab.Images.UIItemIcon204,
$"{entry.DailyNote.CurrentHomeCoin}",
string.Format(SH.ServiceDailyNoteNotifierHomeCoinCurrent, entry.DailyNote.CurrentHomeCoin)));
entry.HomeCoinNotifySuppressed = true;
@@ -175,7 +175,7 @@ internal sealed class DailyNoteNotificationOperation
{
notifyInfos.Add(new(
SH.ServiceDailyNoteNotifierDailyTask,
- Web.Hoyolab.OssImages.UIMarkQuestEventsProce,
+ Web.Hoyolab.Images.UIMarkQuestEventsProce,
SH.ServiceDailyNoteNotifierDailyTaskHint,
entry.DailyNote.ExtraTaskRewardDescription));
entry.DailyTaskNotifySuppressed = true;
@@ -192,7 +192,7 @@ internal sealed class DailyNoteNotificationOperation
{
notifyInfos.Add(new(
SH.ServiceDailyNoteNotifierTransformer,
- Web.Hoyolab.OssImages.UIItemIcon220021,
+ Web.Hoyolab.Images.UIItemIcon220021,
SH.ServiceDailyNoteNotifierTransformerAdaptiveHint,
SH.ServiceDailyNoteNotifierTransformerHint));
entry.TransformerNotifySuppressed = true;
@@ -209,7 +209,7 @@ internal sealed class DailyNoteNotificationOperation
{
notifyInfos.Add(new(
SH.ServiceDailyNoteNotifierExpedition,
- Web.Hoyolab.OssImages.UIIconInteeExplore1,
+ Web.Hoyolab.Images.UIIconInteeExplore1,
SH.ServiceDailyNoteNotifierExpeditionAdaptiveHint,
SH.ServiceDailyNoteNotifierExpeditionHint));
entry.ExpeditionNotifySuppressed = true;
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/ChannelOptions.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/ChannelOptions.cs
index 2f8a06ac..e8255f7f 100644
--- a/src/Snap.Hutao/Snap.Hutao/Service/Game/ChannelOptions.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/ChannelOptions.cs
@@ -11,6 +11,9 @@ namespace Snap.Hutao.Service.Game;
[HighQuality]
internal readonly struct ChannelOptions
{
+ public const string ChannelName = "channel";
+ public const string SubChannelName = "sub_channel";
+
///
/// 通道
///
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/GameDbService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/GameDbService.cs
new file mode 100644
index 00000000..7c4f10ed
--- /dev/null
+++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/GameDbService.cs
@@ -0,0 +1,62 @@
+// Copyright (c) DGP Studio. All rights reserved.
+// Licensed under the MIT license.
+
+using Microsoft.EntityFrameworkCore;
+using Snap.Hutao.Core.Database;
+using Snap.Hutao.Model.Entity;
+using Snap.Hutao.Model.Entity.Database;
+using System.Collections.ObjectModel;
+
+namespace Snap.Hutao.Service.Game;
+
+[ConstructorGenerated]
+[Injection(InjectAs.Singleton, typeof(IGameDbService))]
+internal sealed partial class GameDbService : IGameDbService
+{
+ private readonly IServiceProvider serviceProvider;
+
+ public ObservableCollection GetGameAccountCollection()
+ {
+ using (IServiceScope scope = serviceProvider.CreateScope())
+ {
+ AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService();
+ return appDbContext.GameAccounts.AsNoTracking().ToObservableCollection();
+ }
+ }
+
+ public async ValueTask AddGameAccountAsync(GameAccount gameAccount)
+ {
+ using (IServiceScope scope = serviceProvider.CreateScope())
+ {
+ AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService();
+ await appDbContext.GameAccounts.AddAndSaveAsync(gameAccount).ConfigureAwait(false);
+ }
+ }
+
+ public async ValueTask UpdateGameAccountAsync(GameAccount gameAccount)
+ {
+ using (IServiceScope scope = serviceProvider.CreateScope())
+ {
+ AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService();
+ await appDbContext.GameAccounts.UpdateAndSaveAsync(gameAccount).ConfigureAwait(false);
+ }
+ }
+
+ public void UpdateGameAccount(GameAccount gameAccount)
+ {
+ using (IServiceScope scope = serviceProvider.CreateScope())
+ {
+ AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService();
+ appDbContext.GameAccounts.UpdateAndSave(gameAccount);
+ }
+ }
+
+ public async ValueTask DeleteGameAccountByIdAsync(Guid id)
+ {
+ using (IServiceScope scope = serviceProvider.CreateScope())
+ {
+ AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService();
+ await appDbContext.GameAccounts.ExecuteDeleteWhereAsync(a => a.InnerId == id).ConfigureAwait(false);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/GameService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/GameService.cs
index 78e45255..fcbd5f8f 100644
--- a/src/Snap.Hutao/Snap.Hutao/Service/Game/GameService.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/GameService.cs
@@ -1,13 +1,10 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
-using Microsoft.EntityFrameworkCore;
using Snap.Hutao.Core;
-using Snap.Hutao.Core.Database;
using Snap.Hutao.Core.ExceptionService;
using Snap.Hutao.Core.IO.Ini;
using Snap.Hutao.Model.Entity;
-using Snap.Hutao.Model.Entity.Database;
using Snap.Hutao.Service.Game.Locator;
using Snap.Hutao.Service.Game.Package;
using Snap.Hutao.View.Dialog;
@@ -32,7 +29,7 @@ internal sealed partial class GameService : IGameService
private readonly IServiceProvider serviceProvider;
private readonly IGameDbService gameDbService;
private readonly LaunchOptions launchOptions;
- private readonly RuntimeOptions hutaoOptions;
+ private readonly RuntimeOptions runtimeOptions;
private readonly ITaskContext taskContext;
private readonly AppOptions appOptions;
@@ -48,48 +45,45 @@ internal sealed partial class GameService : IGameService
///
public async ValueTask> GetGamePathAsync()
{
- using (IServiceScope scope = serviceProvider.CreateScope())
+ // Cannot find in setting
+ if (string.IsNullOrEmpty(appOptions.GamePath))
{
- // Cannot find in setting
- if (string.IsNullOrEmpty(appOptions.GamePath))
- {
- IGameLocatorFactory locatorFactory = scope.ServiceProvider.GetRequiredService();
+ IGameLocatorFactory locatorFactory = serviceProvider.GetRequiredService();
- // Try locate by unity log
- ValueResult result = await locatorFactory
- .Create(GameLocationSource.UnityLog)
+ // Try locate by unity log
+ ValueResult result = await locatorFactory
+ .Create(GameLocationSource.UnityLog)
+ .LocateGamePathAsync()
+ .ConfigureAwait(false);
+
+ if (!result.IsOk)
+ {
+ // Try locate by registry
+ result = await locatorFactory
+ .Create(GameLocationSource.Registry)
.LocateGamePathAsync()
.ConfigureAwait(false);
-
- if (!result.IsOk)
- {
- // Try locate by registry
- result = await locatorFactory
- .Create(GameLocationSource.Registry)
- .LocateGamePathAsync()
- .ConfigureAwait(false);
- }
-
- if (result.IsOk)
- {
- // Save result.
- appOptions.GamePath = result.Value;
- }
- else
- {
- return new(false, SH.ServiceGamePathLocateFailed);
- }
}
- if (!string.IsNullOrEmpty(appOptions.GamePath))
+ if (result.IsOk)
{
- return new(true, appOptions.GamePath);
+ // Save result.
+ appOptions.GamePath = result.Value;
}
else
{
- return new(false, null!);
+ return new(false, SH.ServiceGamePathLocateFailed);
}
}
+
+ if (!string.IsNullOrEmpty(appOptions.GamePath))
+ {
+ return new(true, appOptions.GamePath);
+ }
+ else
+ {
+ return new(false, null!);
+ }
}
///
@@ -107,8 +101,8 @@ internal sealed partial class GameService : IGameService
using (FileStream stream = File.OpenRead(configPath))
{
List parameters = IniSerializer.Deserialize(stream).OfType().ToList();
- string? channel = parameters.FirstOrDefault(p => p.Key == "channel")?.Value;
- string? subChannel = parameters.FirstOrDefault(p => p.Key == "sub_channel")?.Value;
+ string? channel = parameters.FirstOrDefault(p => p.Key == ChannelOptions.ChannelName)?.Value;
+ string? subChannel = parameters.FirstOrDefault(p => p.Key == ChannelOptions.SubChannelName)?.Value;
return new(channel, subChannel, isOversea);
}
@@ -178,14 +172,10 @@ internal sealed partial class GameService : IGameService
string gameFileName = Path.GetFileName(gamePath);
progress.Report(new(SH.ServiceGameEnsureGameResourceQueryResourceInformation));
- Response response;
- using (IServiceScope scope = serviceProvider.CreateScope())
- {
- response = await scope.ServiceProvider
- .GetRequiredService()
- .GetResourceAsync(launchScheme)
- .ConfigureAwait(false);
- }
+ Response response = await serviceProvider
+ .GetRequiredService()
+ .GetResourceAsync(launchScheme)
+ .ConfigureAwait(false);
if (response.IsOk())
{
@@ -257,7 +247,7 @@ internal sealed partial class GameService : IGameService
return;
}
- Process game = ProcessInterop.PrepareGameProcess(launchOptions, gamePath);
+ Process game = ProcessInterop.InitializeGameProcess(launchOptions, gamePath);
try
{
@@ -265,7 +255,7 @@ internal sealed partial class GameService : IGameService
game.Start();
- bool isAdvancedOptionsAllowed = hutaoOptions.IsElevated && appOptions.IsAdvancedLaunchOptionsEnabled;
+ bool isAdvancedOptionsAllowed = runtimeOptions.IsElevated && appOptions.IsAdvancedLaunchOptionsEnabled;
if (isAdvancedOptionsAllowed && launchOptions.MultipleInstances && !isFirstInstance)
{
ProcessInterop.DisableProtection(game, gamePath);
@@ -317,14 +307,7 @@ internal sealed partial class GameService : IGameService
// sync database
await taskContext.SwitchToBackgroundAsync();
- using (IServiceScope scope = serviceProvider.CreateScope())
- {
- await scope.ServiceProvider
- .GetRequiredService()
- .GameAccounts
- .AddAndSaveAsync(account)
- .ConfigureAwait(false);
- }
+ await gameDbService.AddGameAccountAsync(account).ConfigureAwait(false);
// sync cache
await taskContext.SwitchToMainThreadAsync();
@@ -365,11 +348,8 @@ internal sealed partial class GameService : IGameService
///
public void AttachGameAccountToUid(GameAccount gameAccount, string uid)
{
- using (IServiceScope scope = serviceProvider.CreateScope())
- {
- gameAccount.UpdateAttachUid(uid);
- scope.ServiceProvider.GetRequiredService().GameAccounts.UpdateAndSave(gameAccount);
- }
+ gameAccount.UpdateAttachUid(uid);
+ gameDbService.UpdateGameAccount(gameAccount);
}
///
@@ -385,11 +365,7 @@ internal sealed partial class GameService : IGameService
// sync database
await taskContext.SwitchToBackgroundAsync();
- using (IServiceScope scope = serviceProvider.CreateScope())
- {
- AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService();
- await appDbContext.GameAccounts.UpdateAndSaveAsync(gameAccount).ConfigureAwait(false);
- }
+ await gameDbService.UpdateGameAccountAsync(gameAccount).ConfigureAwait(false);
}
}
@@ -400,10 +376,7 @@ internal sealed partial class GameService : IGameService
gameAccounts!.Remove(gameAccount);
await taskContext.SwitchToBackgroundAsync();
- using (IServiceScope scope = serviceProvider.CreateScope())
- {
- await scope.ServiceProvider.GetRequiredService().GameAccounts.RemoveAndSaveAsync(gameAccount).ConfigureAwait(false);
- }
+ await gameDbService.DeleteGameAccountByIdAsync(gameAccount.InnerId).ConfigureAwait(false);
}
private static bool LaunchSchemeMatchesExecutable(LaunchScheme launchScheme, string gameFileName)
@@ -415,25 +388,4 @@ internal sealed partial class GameService : IGameService
_ => false,
};
}
-}
-
-[ConstructorGenerated]
-[Injection(InjectAs.Singleton, typeof(IGameDbService))]
-internal sealed partial class GameDbService : IGameDbService
-{
- private readonly IServiceProvider serviceProvider;
-
- public ObservableCollection GetGameAccountCollection()
- {
- using (IServiceScope scope = serviceProvider.CreateScope())
- {
- AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService();
- return appDbContext.GameAccounts.AsNoTracking().ToObservableCollection();
- }
- }
-}
-
-internal interface IGameDbService
-{
- ObservableCollection GetGameAccountCollection();
}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/IGameDbService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/IGameDbService.cs
new file mode 100644
index 00000000..42f50de8
--- /dev/null
+++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/IGameDbService.cs
@@ -0,0 +1,20 @@
+// Copyright (c) DGP Studio. All rights reserved.
+// Licensed under the MIT license.
+
+using Snap.Hutao.Model.Entity;
+using System.Collections.ObjectModel;
+
+namespace Snap.Hutao.Service.Game;
+
+internal interface IGameDbService
+{
+ ValueTask AddGameAccountAsync(GameAccount gameAccount);
+
+ ValueTask DeleteGameAccountByIdAsync(Guid id);
+
+ ObservableCollection GetGameAccountCollection();
+
+ void UpdateGameAccount(GameAccount gameAccount);
+
+ ValueTask UpdateGameAccountAsync(GameAccount gameAccount);
+}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/LaunchOptions.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/LaunchOptions.cs
index b96c1a48..baf237b3 100644
--- a/src/Snap.Hutao/Snap.Hutao/Service/Game/LaunchOptions.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/LaunchOptions.cs
@@ -43,16 +43,7 @@ internal sealed class LaunchOptions : DbStoreOptions
primaryScreenWidth = primaryRect.Width;
primaryScreenHeight = primaryRect.Height;
- // This list can't use foreach
- // https://github.com/microsoft/microsoft-ui-xaml/issues/6454
- IReadOnlyList displayAreas = DisplayArea.FindAll();
- for (int i = 0; i < displayAreas.Count; i++)
- {
- DisplayArea displayArea = displayAreas[i];
- int index = i + 1;
- Monitors.Add(new($"{displayArea.DisplayId.Value:X8}:{index}", index));
- }
-
+ InitializeMonitors(Monitors);
InitializeScreenFps(out primaryScreenFps);
}
@@ -168,6 +159,19 @@ internal sealed class LaunchOptions : DbStoreOptions
set => SetOption(ref multipleInstances, SettingEntry.MultipleInstances, value);
}
+ private static void InitializeMonitors(List> monitors)
+ {
+ // This list can't use foreach
+ // https://github.com/microsoft/microsoft-ui-xaml/issues/6454
+ IReadOnlyList displayAreas = DisplayArea.FindAll();
+ for (int i = 0; i < displayAreas.Count; i++)
+ {
+ DisplayArea displayArea = displayAreas[i];
+ int index = i + 1;
+ monitors.Add(new($"{displayArea.DisplayId.Value:X8}:{index}", index));
+ }
+ }
+
private static void InitializeScreenFps(out int fps)
{
HDC hDC = GetDC(HWND.Null);
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/ProcessInterop.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/ProcessInterop.cs
index 07ef89e8..123fb6d6 100644
--- a/src/Snap.Hutao/Snap.Hutao/Service/Game/ProcessInterop.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/ProcessInterop.cs
@@ -24,7 +24,7 @@ internal static class ProcessInterop
/// 启动选项
/// 游戏路径
/// 初始化后的游戏进程
- public static Process PrepareGameProcess(LaunchOptions options, string gamePath)
+ public static Process InitializeGameProcess(LaunchOptions options, string gamePath)
{
// https://docs.unity.cn/cn/current/Manual/PlayerCommandLineArguments.html
string commandLine = new CommandLineBuilder()
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Hutao/HutaoCache.cs b/src/Snap.Hutao/Snap.Hutao/Service/Hutao/HutaoCache.cs
index 1b49d828..13152b8b 100644
--- a/src/Snap.Hutao/Snap.Hutao/Service/Hutao/HutaoCache.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Service/Hutao/HutaoCache.cs
@@ -95,21 +95,7 @@ internal sealed partial class HutaoCache : IHutaoCache
Dictionary idAvatarMap = await GetIdAvatarMapExtendedAsync().ConfigureAwait(false);
Dictionary idWeaponMap = await metadataService.GetIdToWeaponMapAsync().ConfigureAwait(false);
Dictionary idReliquarySetMap = await metadataService.GetEquipAffixIdToReliquarySetMapAsync().ConfigureAwait(false);
-
- List avatarCollocationsRaw;
- using (IServiceScope scope = serviceProvider.CreateScope())
- {
- IHutaoService hutaoService = scope.ServiceProvider.GetRequiredService();
- avatarCollocationsRaw = await hutaoService.GetAvatarCollocationsAsync().ConfigureAwait(false);
- }
-
- AvatarCollocations = avatarCollocationsRaw.Select(co => new AvatarCollocationView()
- {
- AvatarId = co.AvatarId,
- Avatars = co.Avatars.Select(a => new AvatarView(idAvatarMap[a.Item], a.Rate)).ToList(),
- Weapons = co.Weapons.Select(w => new WeaponView(idWeaponMap[w.Item], w.Rate)).ToList(),
- ReliquarySets = co.Reliquaries.Select(r => new ReliquarySetView(r, idReliquarySetMap)).ToList(),
- }).ToList();
+ await AvatarCollocationsAsync(idAvatarMap, idWeaponMap, idReliquarySetMap).ConfigureAwait(false);
wikiAvatarViewModelTaskSource.TrySetResult(true);
return true;
@@ -131,19 +117,7 @@ internal sealed partial class HutaoCache : IHutaoCache
if (await metadataService.InitializeAsync().ConfigureAwait(false))
{
Dictionary idAvatarMap = await GetIdAvatarMapExtendedAsync().ConfigureAwait(false);
-
- List weaponCollocationsRaw;
- using (IServiceScope scope = serviceProvider.CreateScope())
- {
- IHutaoService hutaoService = scope.ServiceProvider.GetRequiredService();
- weaponCollocationsRaw = await hutaoService.GetWeaponCollocationsAsync().ConfigureAwait(false);
- }
-
- WeaponCollocations = weaponCollocationsRaw.Select(co => new WeaponCollocationView()
- {
- WeaponId = co.WeaponId,
- Avatars = co.Avatars.Select(a => new AvatarView(idAvatarMap[a.Item], a.Rate)).ToList(),
- }).ToList();
+ await WeaponCollocationsAsync(idAvatarMap).ConfigureAwait(false);
wikiWeaponViewModelTaskSource.TrySetResult(true);
return true;
@@ -164,6 +138,41 @@ internal sealed partial class HutaoCache : IHutaoCache
return idAvatarExtendedMap;
}
+ private async ValueTask AvatarCollocationsAsync(Dictionary idAvatarMap, Dictionary idWeaponMap, Dictionary idReliquarySetMap)
+ {
+ List avatarCollocationsRaw;
+ using (IServiceScope scope = serviceProvider.CreateScope())
+ {
+ IHutaoService hutaoService = scope.ServiceProvider.GetRequiredService();
+ avatarCollocationsRaw = await hutaoService.GetAvatarCollocationsAsync().ConfigureAwait(false);
+ }
+
+ AvatarCollocations = avatarCollocationsRaw.SelectList(co => new AvatarCollocationView()
+ {
+ AvatarId = co.AvatarId,
+ Avatars = co.Avatars.SelectList(a => new AvatarView(idAvatarMap[a.Item], a.Rate)),
+ Weapons = co.Weapons.SelectList(w => new WeaponView(idWeaponMap[w.Item], w.Rate)),
+ ReliquarySets = co.Reliquaries.SelectList(r => new ReliquarySetView(r, idReliquarySetMap)),
+ });
+ }
+
+ private async ValueTask WeaponCollocationsAsync(Dictionary idAvatarMap)
+ {
+ List weaponCollocationsRaw;
+ using (IServiceScope scope = serviceProvider.CreateScope())
+ {
+ IHutaoService hutaoService = scope.ServiceProvider.GetRequiredService();
+ weaponCollocationsRaw = await hutaoService.GetWeaponCollocationsAsync().ConfigureAwait(false);
+ }
+
+ WeaponCollocations = weaponCollocationsRaw.SelectList(co => new WeaponCollocationView()
+ {
+ WeaponId = co.WeaponId,
+ Avatars = co.Avatars.SelectList(a => new AvatarView(idAvatarMap[a.Item], a.Rate)),
+ });
+ }
+
+ [SuppressMessage("", "SH003")]
private async Task AvatarAppearanceRankAsync(Dictionary idAvatarMap)
{
List avatarAppearanceRanksRaw;
@@ -173,13 +182,14 @@ internal sealed partial class HutaoCache : IHutaoCache
avatarAppearanceRanksRaw = await hutaoService.GetAvatarAppearanceRanksAsync().ConfigureAwait(false);
}
- AvatarAppearanceRanks = avatarAppearanceRanksRaw.OrderByDescending(r => r.Floor).Select(rank => new AvatarRankView
+ AvatarAppearanceRanks = avatarAppearanceRanksRaw.SortByDescending(r => r.Floor).SelectList(rank => new AvatarRankView
{
Floor = string.Format(SH.ModelBindingHutaoComplexRankFloor, rank.Floor),
- Avatars = rank.Ranks.OrderByDescending(r => r.Rate).Select(rank => new AvatarView(idAvatarMap[rank.Item], rank.Rate)).ToList(),
- }).ToList();
+ Avatars = rank.Ranks.SortByDescending(r => r.Rate).SelectList(rank => new AvatarView(idAvatarMap[rank.Item], rank.Rate)),
+ });
}
+ [SuppressMessage("", "SH003")]
private async Task AvatarUsageRanksAsync(Dictionary idAvatarMap)
{
List avatarUsageRanksRaw;
@@ -189,13 +199,14 @@ internal sealed partial class HutaoCache : IHutaoCache
avatarUsageRanksRaw = await hutaoService.GetAvatarUsageRanksAsync().ConfigureAwait(false);
}
- AvatarUsageRanks = avatarUsageRanksRaw.OrderByDescending(r => r.Floor).Select(rank => new AvatarRankView
+ AvatarUsageRanks = avatarUsageRanksRaw.SortByDescending(r => r.Floor).SelectList(rank => new AvatarRankView
{
Floor = string.Format(SH.ModelBindingHutaoComplexRankFloor, rank.Floor),
- Avatars = rank.Ranks.OrderByDescending(r => r.Rate).Select(rank => new AvatarView(idAvatarMap[rank.Item], rank.Rate)).ToList(),
- }).ToList();
+ Avatars = rank.Ranks.SortByDescending(r => r.Rate).SelectList(rank => new AvatarView(idAvatarMap[rank.Item], rank.Rate)),
+ });
}
+ [SuppressMessage("", "SH003")]
private async Task AvatarConstellationInfosAsync(Dictionary idAvatarMap)
{
List avatarConstellationInfosRaw;
@@ -205,12 +216,13 @@ internal sealed partial class HutaoCache : IHutaoCache
avatarConstellationInfosRaw = await hutaoService.GetAvatarConstellationInfosAsync().ConfigureAwait(false);
}
- AvatarConstellationInfos = avatarConstellationInfosRaw.OrderBy(i => i.HoldingRate).Select(info =>
+ AvatarConstellationInfos = avatarConstellationInfosRaw.SortBy(i => i.HoldingRate).SelectList(info =>
{
return new AvatarConstellationInfoView(idAvatarMap[info.AvatarId], info.HoldingRate, info.Constellations.SelectList(x => x.Rate));
- }).ToList();
+ });
}
+ [SuppressMessage("", "SH003")]
private async Task TeamAppearancesAsync(Dictionary idAvatarMap)
{
List teamAppearancesRaw;
@@ -220,9 +232,10 @@ internal sealed partial class HutaoCache : IHutaoCache
teamAppearancesRaw = await hutaoService.GetTeamAppearancesAsync().ConfigureAwait(false);
}
- TeamAppearances = teamAppearancesRaw.OrderByDescending(t => t.Floor).Select(team => new TeamAppearanceView(team, idAvatarMap)).ToList();
+ TeamAppearances = teamAppearancesRaw.SortByDescending(t => t.Floor).SelectList(team => new TeamAppearanceView(team, idAvatarMap));
}
+ [SuppressMessage("", "SH003")]
private async Task OverviewAsync()
{
using (IServiceScope scope = serviceProvider.CreateScope())
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Hutao/HutaoService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Hutao/HutaoService.cs
index fa60cea2..42ca5bcf 100644
--- a/src/Snap.Hutao/Snap.Hutao/Service/Hutao/HutaoService.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Service/Hutao/HutaoService.cs
@@ -108,8 +108,6 @@ internal sealed partial class HutaoService : IHutaoService
await appDbContext.ObjectCache.AddAndSaveAsync(new()
{
Key = key,
-
- // We hold the cache for 4 hours
ExpireTime = DateTimeOffset.Now.Add(CacheExpireTime),
Value = JsonSerializer.Serialize(data, options),
}).ConfigureAwait(false);
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Hutao/HutaoUserOptions.cs b/src/Snap.Hutao/Snap.Hutao/Service/Hutao/HutaoUserOptions.cs
index 53f13b5f..2dc82229 100644
--- a/src/Snap.Hutao/Snap.Hutao/Service/Hutao/HutaoUserOptions.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Service/Hutao/HutaoUserOptions.cs
@@ -86,7 +86,7 @@ internal sealed class HutaoUserOptions : ObservableObject, IOptions DateTimeOffset.Now;
GachaLogExpireAt = string.Format(Regex.Unescape(SH.ServiceHutaoUserGachaLogExpiredAt), userInfo.GachaLogExpireAt);
+ IsCloudServiceAllowed = IsLicensedDeveloper || userInfo.GachaLogExpireAt > DateTimeOffset.Now;
}
}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj b/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj
index c24a6729..c2d0b685 100644
--- a/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj
+++ b/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj
@@ -97,11 +97,8 @@
-
-
-
@@ -227,11 +224,8 @@
-
-
-
diff --git a/src/Snap.Hutao/Snap.Hutao/View/Card/DailyNoteCard.xaml b/src/Snap.Hutao/Snap.Hutao/View/Card/DailyNoteCard.xaml
index 87d3ade6..b1603e43 100644
--- a/src/Snap.Hutao/Snap.Hutao/View/Card/DailyNoteCard.xaml
+++ b/src/Snap.Hutao/Snap.Hutao/View/Card/DailyNoteCard.xaml
@@ -6,6 +6,7 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:mxi="using:Microsoft.Xaml.Interactivity"
xmlns:shcb="using:Snap.Hutao.Control.Behavior"
+ xmlns:shci="using:Snap.Hutao.Control.Image"
xmlns:shvc="using:Snap.Hutao.View.Control"
xmlns:shvd="using:Snap.Hutao.ViewModel.DailyNote"
Padding="0"
@@ -75,7 +76,7 @@
-
+
-
+