diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Theme/Uri.xaml b/src/Snap.Hutao/Snap.Hutao/Control/Theme/Uri.xaml index 090e6817..2d8cbaa4 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/Theme/Uri.xaml +++ b/src/Snap.Hutao/Snap.Hutao/Control/Theme/Uri.xaml @@ -17,8 +17,13 @@ https://api.snapgenshin.com/static/raw/Bg/UI_Icon_Intee_Explore_1.png https://api.snapgenshin.com/static/raw/Bg/UI_ImgSign_ItemIcon.png https://api.snapgenshin.com/static/raw/Bg/UI_ItemIcon_None.png - https://api.snapgenshin.com/static/raw/Bg/UI_MarkQuest_Events_Proce.png - https://api.snapgenshin.com/static/raw/Bg/UI_MarkTower.png + + + https://api.snapgenshin.com/static/raw/Mark/UI_MarkQuest_Events_Proce.png + https://api.snapgenshin.com/static/raw/Mark/UI_MarkQuest_Events_Start.png + https://api.snapgenshin.com/static/raw/Mark/UI_MarkQuest_Main_Proce.png + https://api.snapgenshin.com/static/raw/Mark/UI_MarkQuest_Main_Start.png + https://api.snapgenshin.com/static/raw/Mark/UI_MarkTower.png https://api.snapgenshin.com/static/raw/ItemIcon/UI_ItemIcon_201.png diff --git a/src/Snap.Hutao/Snap.Hutao/IdentityStructs.json b/src/Snap.Hutao/Snap.Hutao/IdentityStructs.json index cd8c0019..9a59b452 100644 --- a/src/Snap.Hutao/Snap.Hutao/IdentityStructs.json +++ b/src/Snap.Hutao/Snap.Hutao/IdentityStructs.json @@ -23,6 +23,18 @@ "Equatable": true, "EqualityOperators": true }, + { + "Name": "ChapterId", + "Documentation": "章节 Id", + "Equatable": true, + "EqualityOperators": true + }, + { + "Name": "ChapterGroupId", + "Documentation": "章节分组 Id", + "Equatable": true, + "EqualityOperators": true + }, { "Name": "EquipAffixId", "Documentation": "装备属性 Id", @@ -113,6 +125,12 @@ "Equatable": true, "EqualityOperators": true }, + { + "Name": "QuestId", + "Documentation": "任务 Id", + "Equatable": true, + "EqualityOperators": true + }, { "Name": "ReliquaryLevel", "Documentation": "圣遗物等级 1 - 21", diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Entity/DailyNoteEntry.cs b/src/Snap.Hutao/Snap.Hutao/Model/Entity/DailyNoteEntry.cs index 2707e75d..f4d0f945 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Entity/DailyNoteEntry.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Entity/DailyNoteEntry.cs @@ -4,6 +4,8 @@ using CommunityToolkit.Mvvm.ComponentModel; using Snap.Hutao.Core.Abstraction; using Snap.Hutao.Model.Entity.Abstraction; +using Snap.Hutao.Model.Primitive; +using Snap.Hutao.ViewModel.DailyNote; using Snap.Hutao.ViewModel.User; using Snap.Hutao.Web.Hoyolab.Takumi.Binding; using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.DailyNote; @@ -53,6 +55,9 @@ internal sealed class DailyNoteEntry : ObservableObject, IMappingFrom public DailyNote? DailyNote { get; set; } + [NotMapped] + public DailyNoteArchonQuestView ArchonQuestView { get; set; } = default!; + /// /// 刷新时间 /// @@ -128,4 +133,4 @@ internal sealed class DailyNoteEntry : ObservableObject, IMappingFrom + /// Archon Quest 魔神任务 + /// AQ, + + /// + /// Fractions Quest 帮派任务 + /// FQ, + + /// + /// Legend Quest 传说任务 + /// LQ, + + /// + /// Event Quest 活动任务 + /// EQ, + + /// + /// Daily Quest 日常任务 + /// DQ, + + /// + /// Indescribable Quest 不可描述的任务? + /// IQ, + VQ, + + /// + /// World Quest 世界任务 + /// WQ, } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Chapter.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Chapter.cs new file mode 100644 index 00000000..01434f40 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Chapter.cs @@ -0,0 +1,34 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Snap.Hutao.Model.Intrinsic; +using Snap.Hutao.Model.Primitive; + +namespace Snap.Hutao.Model.Metadata; + +internal sealed class Chapter +{ + public ChapterId Id { get; set; } + + public ChapterGroupId GroupId { get; set; } + + public QuestId BeginQuestId { get; set; } + + public QuestId EndQuestId { get; set; } + + public uint NeedPlayerLevel { get; set; } + + public string Number { get; set; } = default!; + + public string Title { get; set; } = default!; + + public string Icon { get; set; } = default!; + + public string ImageTitle { get; set; } = default!; + + public string SerialNumberIcon { get; set; } = default!; + + public City CityId { get; set; } + + public QuestType QuestType { get; set; } +} diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/City.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/City.cs index 799fbb51..2cbb5ed1 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/City.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/City.cs @@ -6,6 +6,7 @@ namespace Snap.Hutao.Model.Metadata; // CityTaskOpenExcelConfig internal enum City : uint { + None = 0, Mondstadt = 1, Liyue = 2, Inazuma = 3, diff --git a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx index 8dde5516..73dee2ef 100644 --- a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx +++ b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx @@ -3044,6 +3044,9 @@ 已复制到剪贴板 + + 所有魔神任务已完成 + 全部完成 diff --git a/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteMetadataContext.cs b/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteMetadataContext.cs new file mode 100644 index 00000000..c2636753 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteMetadataContext.cs @@ -0,0 +1,13 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Snap.Hutao.Model.Metadata; +using Snap.Hutao.Service.Metadata.ContextAbstraction; + +namespace Snap.Hutao.Service.DailyNote; + +internal class DailyNoteMetadataContext : IMetadataContext, + IMetadataListChapterSource +{ + public List Chapters { get; set; } = default!; +} diff --git a/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteService.cs b/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteService.cs index 68897c1f..eb3fe322 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteService.cs @@ -5,7 +5,11 @@ using CommunityToolkit.Mvvm.Messaging; using Snap.Hutao.Core.DependencyInjection.Abstraction; using Snap.Hutao.Message; using Snap.Hutao.Model.Entity; +using Snap.Hutao.Service.Abstraction; +using Snap.Hutao.Service.Metadata; +using Snap.Hutao.Service.Metadata.ContextAbstraction; using Snap.Hutao.Service.User; +using Snap.Hutao.ViewModel.DailyNote; using Snap.Hutao.ViewModel.User; using Snap.Hutao.Web.Hoyolab; using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord; @@ -83,9 +87,18 @@ internal sealed partial class DailyNoteService : IDailyNoteService, IRecipient entryList = await dailyNoteDbService.GetDailyNoteEntryListIncludingUserAsync(token).ConfigureAwait(false); - entryList.ForEach(entry => { entry.UserGameRole = userService.GetUserGameRoleByUid(entry.Uid); }); - entries = entryList.ToObservableCollection(); + using (IServiceScope scope = serviceProvider.CreateScope()) + { + DailyNoteMetadataContext context = await scope.GetRequiredService().GetContextAsync(token).ConfigureAwait(false); + + List entryList = await dailyNoteDbService.GetDailyNoteEntryListIncludingUserAsync(token).ConfigureAwait(false); + entryList.ForEach(entry => + { + entry.UserGameRole = userService.GetUserGameRoleByUid(entry.Uid); + entry.ArchonQuestView = DailyNoteArchonQuestView.Create(entry.DailyNote, context.Chapters); + }); + entries = entryList.ToObservableCollection(); + } } return entries; @@ -159,4 +172,4 @@ internal sealed partial class DailyNoteService : IDailyNoteService, IRecipient Chapters { get; set; } +} diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/ContextAbstraction/MetadataServiceContextExtension.cs b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/ContextAbstraction/MetadataServiceContextExtension.cs index 7cd18212..fd17f81d 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/ContextAbstraction/MetadataServiceContextExtension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/ContextAbstraction/MetadataServiceContextExtension.cs @@ -23,6 +23,11 @@ internal static class MetadataServiceContextExtension listAchievementSource.Achievements = await metadataService.GetAchievementListAsync(token).ConfigureAwait(false); } + if (context is IMetadataListChapterSource listChapterSource) + { + listChapterSource.Chapters = await metadataService.GetChapterListAsync(token).ConfigureAwait(false); + } + if (context is IMetadataListGachaEventSource listGachaEventSource) { listGachaEventSource.GachaEvents = await metadataService.GetGachaEventListAsync(token).ConfigureAwait(false); diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataFileNames.cs b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataFileNames.cs index f668c965..6a2e2b5c 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataFileNames.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataFileNames.cs @@ -10,6 +10,7 @@ internal static class MetadataFileNames public const string FileNameAvatar = "Avatar"; public const string FileNameAvatarCurve = "AvatarCurve"; public const string FileNameAvatarPromote = "AvatarPromote"; + public const string FileNameChapter = "Chapter"; public const string FileNameDisplayItem = "DisplayItem"; public const string FileNameGachaEvent = "GachaEvent"; public const string FileNameMaterial = "Material"; diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataServiceListExtension.cs b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataServiceListExtension.cs index 4377b0e3..1532e245 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataServiceListExtension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataServiceListExtension.cs @@ -20,6 +20,11 @@ internal static class MetadataServiceListExtension return metadataService.FromCacheOrFileAsync>(FileNameAchievement, token); } + public static ValueTask> GetChapterListAsync(this IMetadataService metadataService, CancellationToken token = default) + { + return metadataService.FromCacheOrFileAsync>(FileNameChapter, token); + } + public static ValueTask> GetAchievementGoalListAsync(this IMetadataService metadataService, CancellationToken token = default) { return metadataService.FromCacheOrFileAsync>(FileNameAchievementGoal, token); diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/DailyNotePage.xaml b/src/Snap.Hutao/Snap.Hutao/View/Page/DailyNotePage.xaml index 62875649..d695ac9f 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Page/DailyNotePage.xaml +++ b/src/Snap.Hutao/Snap.Hutao/View/Page/DailyNotePage.xaml @@ -3,7 +3,8 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:cw="using:CommunityToolkit.WinUI" - xmlns:cwc="using:CommunityToolkit.WinUI.Controls" + xmlns:cwcont="using:CommunityToolkit.WinUI.Controls" + xmlns:cwconv="using:CommunityToolkit.WinUI.Converters" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mxi="using:Microsoft.Xaml.Interactivity" @@ -12,6 +13,7 @@ xmlns:shch="using:Snap.Hutao.Control.Helper" xmlns:shci="using:Snap.Hutao.Control.Image" xmlns:shcm="using:Snap.Hutao.Control.Markup" + xmlns:shme="using:Snap.Hutao.Model.Entity" xmlns:shvc="using:Snap.Hutao.View.Control" xmlns:shvcp="using:Snap.Hutao.View.Card.Primitive" xmlns:shvd="using:Snap.Hutao.ViewModel.DailyNote" @@ -26,6 +28,16 @@ + + + + @@ -43,7 +55,7 @@ - + @@ -108,6 +120,43 @@ Grid.Row="1" Margin="0,8,0,0" Spacing="6"> + + + + + + + + + + + + @@ -202,7 +251,7 @@ Margin="4" VerticalAlignment="Center" shch:FrameworkElementHelper.SquareLength="32" - Source="{StaticResource UI_MarkQuest_Events_Proce}"/> + Source="{Binding DailyNote.DailyTask.IsExtraTaskRewardReceived, Converter={StaticResource DailyTaskIconConverter}}"/> - @@ -450,16 +499,16 @@ 0 - - + - + - - + - + - - + - + - - - + - + - + - chapters) + { + this.dailyNote = dailyNote; + Ids = chapters + .Where(chapter => chapter.QuestType is QuestType.AQ) + .Select(chapter => chapter.Id) + .ToList(); + } + + public List Ids { get; set; } = default!; + + public int ProgressValue + { + get + { + if (TryGetFirstArchonQuest(out ArchonQuest? quest)) + { + return Ids.IndexOf(quest.Id); + } + + return Ids.Count; + } + } + + public string ProgressFormatted + { + get + { + if (TryGetFirstArchonQuest(out ArchonQuest? quest)) + { + return quest.Status.GetLocalizedDescription(); + } + + return SH.WebDailyNoteArchonQuestStatusFinished; + } + } + + public string ChapterFormatted + { + get + { + if (TryGetFirstArchonQuest(out ArchonQuest? quest)) + { + return $"{quest.ChapterNum} {quest.ChapterTitle}"; + } + + return SH.WebDailyNoteArchonQuestChapterFinished; + } + } + + public static DailyNoteArchonQuestView Create(WebDailyNote? dailyNote, List chapters) + { + return new(dailyNote, chapters); + } + + private bool TryGetFirstArchonQuest([NotNullWhen(true)] out ArchonQuest? archonQuest) + { + if (dailyNote is { ArchonQuestProgress.List: [{ } target, ..] }) + { + archonQuest = target; + return true; + } + + archonQuest = default; + return false; + } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/DailyNote/DailyNoteViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/DailyNote/DailyNoteViewModel.cs index 0a08086e..bb0e89b0 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/DailyNote/DailyNoteViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/DailyNote/DailyNoteViewModel.cs @@ -7,6 +7,7 @@ using Snap.Hutao.Core; using Snap.Hutao.Factory.ContentDialog; using Snap.Hutao.Model.Entity; using Snap.Hutao.Service.DailyNote; +using Snap.Hutao.Service.Metadata; using Snap.Hutao.Service.Notification; using Snap.Hutao.Service.User; using Snap.Hutao.View.Control; @@ -27,6 +28,7 @@ internal sealed partial class DailyNoteViewModel : Abstraction.ViewModel private readonly IContentDialogFactory contentDialogFactory; private readonly IDailyNoteService dailyNoteService; private readonly DailyNoteOptions dailyNoteOptions; + private readonly IMetadataService metadataService; private readonly IInfoBarService infoBarService; private readonly RuntimeOptions runtimeOptions; private readonly ITaskContext taskContext; @@ -53,22 +55,26 @@ internal sealed partial class DailyNoteViewModel : Abstraction.ViewModel protected override async ValueTask InitializeUIAsync() { - try + if (await metadataService.InitializeAsync().ConfigureAwait(false)) { - await taskContext.SwitchToBackgroundAsync(); - ObservableCollection roles = await userService.GetRoleCollectionAsync().ConfigureAwait(false); - ObservableCollection entries = await dailyNoteService.GetDailyNoteEntryCollectionAsync().ConfigureAwait(false); + try + { + await taskContext.SwitchToBackgroundAsync(); + ObservableCollection roles = await userService.GetRoleCollectionAsync().ConfigureAwait(false); + ObservableCollection entries = await dailyNoteService.GetDailyNoteEntryCollectionAsync().ConfigureAwait(false); - await taskContext.SwitchToMainThreadAsync(); - UserAndUids = roles; - DailyNoteEntries = entries; - return true; - } - catch (Core.ExceptionService.UserdataCorruptedException ex) - { - infoBarService.Error(ex); - return false; + await taskContext.SwitchToMainThreadAsync(); + UserAndUids = roles; + DailyNoteEntries = entries; + return true; + } + catch (Core.ExceptionService.UserdataCorruptedException ex) + { + infoBarService.Error(ex); + } } + + return false; } [Command("TrackRoleCommand")] diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/Guide/StaticResource.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Guide/StaticResource.cs index d51c1de4..dec258d7 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/Guide/StaticResource.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Guide/StaticResource.cs @@ -33,6 +33,7 @@ internal static class StaticResource { "IconElement", 0 }, { "ItemIcon", 0 }, { "LoadingPic", 0 }, + { "Mark", 0 }, { "MonsterIcon", 0 }, { "MonsterSmallIcon", 0 }, { "NameCardIcon", 0 }, @@ -62,6 +63,7 @@ internal static class StaticResource { "IconElement", 3 }, { "ItemIcon", 4 }, { "LoadingPic", 2 }, + { "Mark", 0 }, { "MonsterIcon", 3 }, { "MonsterSmallIcon", 2 }, { "NameCardIcon", 3 }, diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/DailyNote/DailyNote.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/DailyNote/DailyNote.cs index a88b0459..9ed8402c 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/DailyNote/DailyNote.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/DailyNote/DailyNote.cs @@ -132,4 +132,10 @@ internal sealed class DailyNote : DailyNoteCommon [JsonPropertyName("archon_quest_progress")] public ArchonQuestProgress ArchonQuestProgress { get; set; } = default!; + + [JsonIgnore] + public bool IsArchonQuestFinished + { + get => ArchonQuestProgress.List.Count == 0; + } } \ No newline at end of file