mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
cultivation optimization
This commit is contained in:
25
README.md
25
README.md
@@ -1,35 +1,26 @@
|
||||
# Snap.Hutao
|
||||
# [Snap.Hutao](https://hut.ao)
|
||||
> 唷,找本堂主有何贵干呀?
|
||||
|
||||

|
||||
|
||||
## 项目首页(文档)
|
||||
# 特别感谢
|
||||
|
||||
[](https://github.com/DGP-Studio/Snap.Hutao.Docs/actions/workflows/deploy-docs.yml)
|
||||
### 原神组织与个人
|
||||
|
||||
[HUT.AO](https://hut.ao)
|
||||
* [HolographicHat](https://github.com/HolographicHat)
|
||||
* [UIGF organization](https://uigf.org)
|
||||
|
||||
## 安装
|
||||
|
||||
* 前往 [下载页面](https://go.hut.ao/down) 下载最新版本的 `胡桃` 安装包
|
||||
* (曾启用的可以跳过此步骤)在系统设置中打开 **开发者选项** 界面,勾选 `开发人员模式` 和 `允许 PowerShell 脚本`
|
||||
* 完全解压后,右键使用 powershell 运行 `install.ps1` 文件
|
||||
* 安装完成后可以关闭 `允许 PowerShell 脚本`
|
||||
|
||||
## 特别感谢
|
||||
|
||||
### 原神项目
|
||||
### 特定的原神项目
|
||||
|
||||
* [biuuu/genshin-wish-export](https://github.com/biuuu/genshin-wish-export)
|
||||
* [HolographicHat/YaeAchievement](https://github.com/HolographicHat/YaeAchievement)
|
||||
* [HolographicHat/MiHoYoWebBridge](https://github.com/HolographicHat/MiHoYoWebBridge)
|
||||
* [xunkong/xunkong](https://github.com/xunkong/xunkong)
|
||||
* [YuehaiTeam/cocogoat](https://github.com/YuehaiTeam/cocogoat)
|
||||
|
||||
### 技术栈
|
||||
### 使用的技术栈
|
||||
|
||||
* [CommunityToolkit/dotnet](https://github.com/CommunityToolkit/dotnet)
|
||||
* [CommunityToolkit/WindowsCommunityToolkit](https://github.com/CommunityToolkit/WindowsCommunityToolkit)
|
||||
* [dahall/taskscheduler](https://github.com/dahall/taskscheduler)
|
||||
* [dotnet/efcore](https://github.com/dotnet/efcore)
|
||||
* [dotnet/runtime](https://github.com/dotnet/runtime)
|
||||
* [DotNetAnalyzers/StyleCopAnalyzers](https://github.com/DotNetAnalyzers/StyleCopAnalyzers)
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
|
||||
using Snap.Hutao.Factory.Abstraction;
|
||||
using Windows.Storage.Pickers;
|
||||
using Windows.Win32;
|
||||
using Windows.Win32.UI.Shell;
|
||||
using WinRT;
|
||||
using WinRT.Interop;
|
||||
|
||||
namespace Snap.Hutao.Factory;
|
||||
@@ -37,6 +40,7 @@ internal class PickerFactory : IPickerFactory
|
||||
picker.FileTypeFilter.Add(type);
|
||||
}
|
||||
|
||||
// https://github.com/microsoft/WindowsAppSDK/issues/2931
|
||||
picker.FileTypeFilter.Add(AnyType);
|
||||
|
||||
return picker;
|
||||
|
||||
@@ -25,6 +25,7 @@ public class CultivateItem : ObservableObject
|
||||
Inner = inner;
|
||||
Entity = entity;
|
||||
isFinished = Entity.IsFinished;
|
||||
IsToday = CultivateItemHelper.IsTodaysMaterial(inner.Id, DateTimeOffset.Now);
|
||||
|
||||
FinishStateCommand = new RelayCommand(FlipIsFinished);
|
||||
}
|
||||
@@ -59,6 +60,11 @@ public class CultivateItem : ObservableObject
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否为今日物品
|
||||
/// </summary>
|
||||
public bool IsToday { get; }
|
||||
|
||||
private void FlipIsFinished()
|
||||
{
|
||||
IsFinished = !IsFinished;
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Model.Binding.Cultivation;
|
||||
|
||||
/// <summary>
|
||||
/// 养成物品帮助类
|
||||
/// </summary>
|
||||
public static class CultivateItemHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 判断是否为当日物品
|
||||
/// </summary>
|
||||
/// <param name="itemId">材料Id</param>
|
||||
/// <param name="now">时间</param>
|
||||
/// <returns>是否为当日物品</returns>
|
||||
public static bool IsTodaysMaterial(int itemId, DateTimeOffset now)
|
||||
{
|
||||
DateTimeOffset utcNow = now.ToUniversalTime();
|
||||
utcNow = utcNow.AddHours(4);
|
||||
DayOfWeek dayOfWeek = utcNow.DayOfWeek;
|
||||
|
||||
return dayOfWeek switch
|
||||
{
|
||||
DayOfWeek.Monday or DayOfWeek.Thursday => itemId switch
|
||||
{
|
||||
104301 or 104302 or 104303 => true, // 「自由」
|
||||
104310 or 104311 or 104312 => true, // 「繁荣」
|
||||
104320 or 104321 or 104322 => true, // 「浮世」
|
||||
104329 or 104330 or 104331 => true, // 「诤言」
|
||||
114001 or 114002 or 114003 or 114004 => true, // 高塔孤王
|
||||
114013 or 114014 or 114015 or 114016 => true, // 孤云寒林
|
||||
114025 or 114026 or 114027 or 114028 => true, // 远海夷地
|
||||
114037 or 114038 or 114039 or 114040 => true, // 谧林涓露
|
||||
_ => false,
|
||||
},
|
||||
DayOfWeek.Tuesday or DayOfWeek.Friday => itemId switch
|
||||
{
|
||||
104304 or 104305 or 104306 => true, // 「抗争」
|
||||
104313 or 104314 or 104315 => true, // 「勤劳」
|
||||
104323 or 104324 or 104325 => true, // 「风雅」
|
||||
104332 or 104333 or 104334 => true, // 「巧思」
|
||||
114005 or 114006 or 114007 or 114008 => true, // 凛风奔狼
|
||||
114017 or 114018 or 114019 or 114020 => true, // 雾海云间
|
||||
114029 or 114030 or 114031 or 114032 => true, // 鸣神御灵
|
||||
114041 or 114042 or 114043 or 114044 => true, // 绿洲花园
|
||||
_ => false,
|
||||
},
|
||||
DayOfWeek.Wednesday or DayOfWeek.Saturday => itemId switch
|
||||
{
|
||||
104307 or 104308 or 104309 => true, // 「诗文」
|
||||
104316 or 104317 or 104318 => true, // 「黄金」
|
||||
104326 or 104327 or 104328 => true, // 「天光」
|
||||
104335 or 104336 or 104337 => true, // 「笃行」
|
||||
114009 or 114010 or 114011 or 114012 => true, // 狮牙斗士
|
||||
114021 or 114022 or 114023 or 114024 => true, // 漆黑陨铁
|
||||
114033 or 114034 or 114035 or 114036 => true, // 今昔剧画
|
||||
114045 or 114046 or 114047 or 114048 => true, // 谧林涓露
|
||||
_ => false,
|
||||
},
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Model.Metadata;
|
||||
using Snap.Hutao.Model.Metadata.Avatar;
|
||||
using Snap.Hutao.Model.Primitive;
|
||||
|
||||
namespace Snap.Hutao.Model.Binding.Hutao;
|
||||
|
||||
/// <summary>
|
||||
/// 料理奖励视图
|
||||
/// </summary>
|
||||
public class CookBonusView
|
||||
{
|
||||
/// <summary>
|
||||
/// 原型
|
||||
/// </summary>
|
||||
public Material OriginItem { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 名称
|
||||
/// </summary>
|
||||
public Material Item { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个新的料理奖励视图
|
||||
/// </summary>
|
||||
/// <param name="cookBonus">料理奖励</param>
|
||||
/// <param name="idMaterialMap">材料映射</param>
|
||||
/// <returns>新的料理奖励视图</returns>
|
||||
public static CookBonusView? Create(CookBonus? cookBonus, Dictionary<MaterialId, Material> idMaterialMap)
|
||||
{
|
||||
if (cookBonus == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
CookBonusView view = new()
|
||||
{
|
||||
OriginItem = idMaterialMap[cookBonus.OriginItemId],
|
||||
Item = idMaterialMap[cookBonus.ItemId],
|
||||
};
|
||||
|
||||
return view;
|
||||
}
|
||||
}
|
||||
@@ -31,60 +31,4 @@ internal class UIIF
|
||||
/// </summary>
|
||||
[JsonPropertyName("list")]
|
||||
public List<UIIFItem> List { get; set; } = default!;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// UIIF物品
|
||||
/// </summary>
|
||||
[JsonDerivedType(typeof(UIIFReliquary))]
|
||||
[JsonDerivedType(typeof(UIIFWeapon))]
|
||||
internal class UIIFItem
|
||||
{
|
||||
/// <summary>
|
||||
/// 物品Id
|
||||
/// </summary>
|
||||
[JsonPropertyName("itemId")]
|
||||
public int ItemId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 物品Id
|
||||
/// </summary>
|
||||
[JsonPropertyName("count")]
|
||||
public int Count { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// UIIF圣遗物
|
||||
/// </summary>
|
||||
internal class UIIFReliquary : UIIFItem
|
||||
{
|
||||
/// <summary>
|
||||
/// 物品Id
|
||||
/// </summary>
|
||||
[JsonPropertyName("level")]
|
||||
public int Level { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 副属性列表
|
||||
/// </summary>
|
||||
[JsonPropertyName("appendPropIdList")]
|
||||
public List<int> AppendPropIdList { get; set; } = default!;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// UIIF武器
|
||||
/// </summary>
|
||||
internal class UIIFWeapon : UIIFItem
|
||||
{
|
||||
/// <summary>
|
||||
/// 物品Id
|
||||
/// </summary>
|
||||
[JsonPropertyName("level")]
|
||||
public int Level { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 精炼等级 0-4
|
||||
/// </summary>
|
||||
[JsonPropertyName("promoteLevel")]
|
||||
public int PromoteLevel { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.Collections.Immutable;
|
||||
|
||||
namespace Snap.Hutao.Model.InterChange.Inventory;
|
||||
|
||||
/// <summary>
|
||||
/// UIIF物品
|
||||
/// </summary>
|
||||
internal class UIIFItem
|
||||
{
|
||||
/// <summary>
|
||||
/// 物品Id
|
||||
/// </summary>
|
||||
[JsonPropertyName("itemId")]
|
||||
public int ItemId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 物品Id
|
||||
/// </summary>
|
||||
[JsonPropertyName("count")]
|
||||
public int Count { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 等级
|
||||
/// Reliquary/Weapon
|
||||
/// </summary>
|
||||
[JsonPropertyName("level")]
|
||||
public int? Level { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 副属性列表
|
||||
/// Reliquary
|
||||
/// </summary>
|
||||
[JsonPropertyName("appendPropIdList")]
|
||||
public List<int>? AppendPropIdList { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 精炼等级 0-4
|
||||
/// Weapon
|
||||
/// </summary>
|
||||
[JsonPropertyName("promoteLevel")]
|
||||
public int? PromoteLevel { get; set; }
|
||||
}
|
||||
59
src/Snap.Hutao/Snap.Hutao/Model/Intrinsic/MaterialType.cs
Normal file
59
src/Snap.Hutao/Snap.Hutao/Model/Intrinsic/MaterialType.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Model.Intrinsic;
|
||||
|
||||
/// <summary>
|
||||
/// 材料类型
|
||||
/// </summary>
|
||||
[SuppressMessage("", "SA1602")]
|
||||
public enum MaterialType
|
||||
{
|
||||
MATERIAL_NONE = 0,
|
||||
MATERIAL_FOOD = 1,
|
||||
MATERIAL_QUEST = 2,
|
||||
MATERIAL_EXCHANGE = 4,
|
||||
MATERIAL_CONSUME,
|
||||
MATERIAL_EXP_FRUIT,
|
||||
MATERIAL_AVATAR,
|
||||
MATERIAL_ADSORBATE,
|
||||
MATERIAL_CRICKET,
|
||||
MATERIAL_ELEM_CRYSTAL,
|
||||
MATERIAL_WEAPON_EXP_STONE,
|
||||
MATERIAL_CHEST,
|
||||
MATERIAL_RELIQUARY_MATERIAL,
|
||||
MATERIAL_AVATAR_MATERIAL,
|
||||
MATERIAL_NOTICE_ADD_HP,
|
||||
MATERIAL_SEA_LAMP,
|
||||
MATERIAL_SELECTABLE_CHEST,
|
||||
MATERIAL_FLYCLOAK,
|
||||
MATERIAL_NAMECARD,
|
||||
MATERIAL_TALENT,
|
||||
MATERIAL_WIDGET,
|
||||
MATERIAL_CHEST_BATCH_USE,
|
||||
MATERIAL_FAKE_ABSORBATE,
|
||||
MATERIAL_CONSUME_BATCH_USE,
|
||||
MATERIAL_WOOD,
|
||||
MATERIAL_FURNITURE_FORMULA = 27,
|
||||
MATERIAL_CHANNELLER_SLAB_BUFF,
|
||||
MATERIAL_FURNITURE_SUITE_FORMULA,
|
||||
MATERIAL_COSTUME,
|
||||
MATERIAL_HOME_SEED,
|
||||
MATERIAL_FISH_BAIT,
|
||||
MATERIAL_FISH_ROD,
|
||||
MATERIAL_SUMO_BUFF, // never appear
|
||||
MATERIAL_FIREWORKS,
|
||||
MATERIAL_BGM,
|
||||
MATERIAL_SPICE_FOOD,
|
||||
MATERIAL_ACTIVITY_ROBOT,
|
||||
MATERIAL_ACTIVITY_GEAR,
|
||||
MATERIAL_ACTIVITY_JIGSAW,
|
||||
MATERIAL_ARANARA,
|
||||
MATERIAL_GCG_CARD,
|
||||
MATERIAL_GCG_CARD_FACE, // 影幻卡面
|
||||
MATERIAL_GCG_CARD_BACK,
|
||||
MATERIAL_GCG_FIELD,
|
||||
MATERIAL_DESHRET_MANUAL,
|
||||
MATERIAL_RENAME_ITEM,
|
||||
MATERIAL_GCG_EXCHANGE_ITEM,
|
||||
}
|
||||
@@ -22,6 +22,17 @@ public partial class Avatar : IStatisticsItemSource, ISummaryItemSource, INameQu
|
||||
[JsonIgnore]
|
||||
public ComplexAvatarCollocation? Collocation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [非元数据] 烹饪奖励
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public CookBonusView? CookBonusView { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 养成物品视图
|
||||
/// </summary>
|
||||
public List<Material>? CultivationItemsView { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ICalculableAvatar ToCalculable()
|
||||
{
|
||||
|
||||
@@ -81,5 +81,10 @@ public partial class Avatar
|
||||
/// <summary>
|
||||
/// 皮肤
|
||||
/// </summary>
|
||||
public IEnumerable<Costume> Costumes { get; set; } = default!;
|
||||
public List<Costume> Costumes { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 养成物品
|
||||
/// </summary>
|
||||
public List<MaterialId> CultivationItems { get; set; } = default!;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
// 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.Avatar;
|
||||
|
||||
@@ -13,45 +13,15 @@ public class CookBonus
|
||||
/// <summary>
|
||||
/// 原型名称
|
||||
/// </summary>
|
||||
public string OriginName { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 原型描述
|
||||
/// </summary>
|
||||
public string OriginDescription { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 原型图标
|
||||
/// </summary>
|
||||
public string OriginIcon { get; set; } = default!;
|
||||
public MaterialId OriginItemId { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 名称
|
||||
/// </summary>
|
||||
public string Name { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 描述
|
||||
/// </summary>
|
||||
public string Description { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 效果描述
|
||||
/// </summary>
|
||||
public string EffectDescription { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 图标
|
||||
/// </summary>
|
||||
public string Icon { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 物品等级
|
||||
/// </summary>
|
||||
public ItemQuality RankLevel { get; set; }
|
||||
public MaterialId ItemId { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 材料列表
|
||||
/// </summary>
|
||||
public List<ItemWithCount> InputList { get; set; } = default!;
|
||||
public List<MaterialId> InputList { get; set; } = default!;
|
||||
}
|
||||
@@ -83,7 +83,7 @@ public class FetterInfo
|
||||
/// <summary>
|
||||
/// 料理
|
||||
/// </summary>
|
||||
public CookBonus? CookBonus { get; set; }
|
||||
public CookBonus? CookBonus2 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 好感语音
|
||||
|
||||
@@ -105,4 +105,4 @@ internal class PropertyInfoDescriptor : ValueConverterBase<PropertyInfo, IList<L
|
||||
|
||||
return results;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Model.Intrinsic;
|
||||
using Snap.Hutao.Model.Primitive;
|
||||
|
||||
namespace Snap.Hutao.Model.Metadata;
|
||||
|
||||
@@ -13,7 +14,7 @@ public class Material
|
||||
/// <summary>
|
||||
/// 物品Id
|
||||
/// </summary>
|
||||
public int Id { get; set; }
|
||||
public MaterialId Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 等级
|
||||
@@ -25,6 +26,11 @@ public class Material
|
||||
/// </summary>
|
||||
public ItemType ItemType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 材料类型
|
||||
/// </summary>
|
||||
public MaterialType MaterialType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 图标
|
||||
/// </summary>
|
||||
@@ -44,4 +50,9 @@ public class Material
|
||||
/// 类型描述
|
||||
/// </summary>
|
||||
public string TypeDescription { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 效果描述
|
||||
/// </summary>
|
||||
public string? EffectDescription { get; set; }
|
||||
}
|
||||
71
src/Snap.Hutao/Snap.Hutao/Model/Primitive/MaterialId.cs
Normal file
71
src/Snap.Hutao/Snap.Hutao/Model/Primitive/MaterialId.cs
Normal file
@@ -0,0 +1,71 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Model.Primitive.Converter;
|
||||
|
||||
namespace Snap.Hutao.Model.Primitive;
|
||||
|
||||
/// <summary>
|
||||
/// 3-6位 材料Id
|
||||
/// </summary>
|
||||
[JsonConverter(typeof(IdentityConverter<MaterialId>))]
|
||||
public readonly struct MaterialId : IEquatable<MaterialId>, IComparable<MaterialId>
|
||||
{
|
||||
/// <summary>
|
||||
/// 值
|
||||
/// </summary>
|
||||
public readonly int Value;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MaterialId"/> struct.
|
||||
/// </summary>
|
||||
/// <param name="value">value</param>
|
||||
public MaterialId(int value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public static implicit operator int(MaterialId value)
|
||||
{
|
||||
return value.Value;
|
||||
}
|
||||
|
||||
public static implicit operator MaterialId(int value)
|
||||
{
|
||||
return new(value);
|
||||
}
|
||||
|
||||
public static bool operator ==(MaterialId left, MaterialId right)
|
||||
{
|
||||
return left.Value == right.Value;
|
||||
}
|
||||
|
||||
public static bool operator !=(MaterialId left, MaterialId right)
|
||||
{
|
||||
return !(left == right);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int CompareTo(MaterialId other)
|
||||
{
|
||||
return Value.CompareTo(other.Value);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool Equals(MaterialId other)
|
||||
{
|
||||
return Value == other.Value;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is MaterialId other && Equals(other);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return Value.GetHashCode();
|
||||
}
|
||||
}
|
||||
@@ -62,4 +62,4 @@ public readonly struct WeaponId : IEquatable<WeaponId>
|
||||
{
|
||||
return Value.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,6 @@ WM_GETMINMAXINFO
|
||||
WM_NCRBUTTONDOWN
|
||||
WM_NCRBUTTONUP
|
||||
|
||||
STDAPI
|
||||
|
||||
// Type definition
|
||||
CWMO_FLAGS
|
||||
HRESULT
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<Identity
|
||||
Name="7f0db578-026f-4e0b-a75b-d5d06bb0a74d"
|
||||
Publisher="CN=DGP Studio"
|
||||
Version="1.2.14.0" />
|
||||
Version="1.2.15.0" />
|
||||
|
||||
<Properties>
|
||||
<DisplayName>胡桃</DisplayName>
|
||||
|
||||
@@ -155,7 +155,8 @@ internal class CultivationService : ICultivationService
|
||||
List<BindingCultivateItem> resultItems = new();
|
||||
List<CultivateItem> items = await appDbContext.CultivateItems
|
||||
.Where(i => i.EntryId == entryId)
|
||||
.OrderBy(i => i.ItemId).ToListAsync()
|
||||
.OrderBy(i => i.ItemId)
|
||||
.ToListAsync()
|
||||
.ConfigureAwait(false);
|
||||
|
||||
foreach (CultivateItem item in items)
|
||||
@@ -173,7 +174,7 @@ internal class CultivationService : ICultivationService
|
||||
results.Add(new(entry, itemBase, resultItems));
|
||||
}
|
||||
|
||||
return new(results);
|
||||
return new(results.OrderByDescending(e => e.Items.Any(i => i.IsToday)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ using Microsoft.Extensions.DependencyInjection;
|
||||
using Snap.Hutao.Context.Database;
|
||||
using Snap.Hutao.Core.Database;
|
||||
using Snap.Hutao.Model.Entity;
|
||||
using Snap.Hutao.Web.Hoyolab.Takumi.Auth;
|
||||
using Snap.Hutao.Web.Hoyolab.Takumi.Binding;
|
||||
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.DailyNote;
|
||||
|
||||
@@ -23,7 +24,6 @@ internal class DailyNoteNotifier
|
||||
/// 构造一个新的实时便笺通知器
|
||||
/// </summary>
|
||||
/// <param name="scopeFactory">范围工厂</param>
|
||||
/// <param name="bindingClient">绑定客户端</param>
|
||||
/// <param name="entry">实时便笺入口</param>
|
||||
public DailyNoteNotifier(IServiceScopeFactory scopeFactory, DailyNoteEntry entry)
|
||||
{
|
||||
@@ -121,8 +121,17 @@ internal class DailyNoteNotifier
|
||||
{
|
||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
BindingClient bindingClient = scope.ServiceProvider.GetRequiredService<BindingClient>();
|
||||
AuthClient authClient = scope.ServiceProvider.GetRequiredService<AuthClient>();
|
||||
|
||||
string? actionTicket = await authClient
|
||||
.GetActionTicketByStokenAsync("game_role", entry.User)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
List<UserGameRole> roles = await scope.ServiceProvider
|
||||
.GetRequiredService<BindingClient>()
|
||||
.GetUserGameRolesByActionTicketAsync(actionTicket!, entry.User)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
List<UserGameRole> roles = await bindingClient.GetUserGameRolesByCookieAsync(entry.User).ConfigureAwait(false);
|
||||
string attribution = roles.SingleOrDefault(r => r.GameUid == entry.Uid)?.ToString() ?? "未知角色";
|
||||
|
||||
ToastContentBuilder builder = new ToastContentBuilder()
|
||||
|
||||
@@ -64,6 +64,13 @@ internal interface IMetadataService
|
||||
/// <returns>Id到角色的字典</returns>
|
||||
ValueTask<Dictionary<AvatarId, Avatar>> GetIdToAvatarMapAsync(CancellationToken token = default);
|
||||
|
||||
/// <summary>
|
||||
/// 异步获取Id到材料的字典
|
||||
/// </summary>
|
||||
/// <param name="token">取消令牌</param>
|
||||
/// <returns>Id到材料的字典</returns>
|
||||
ValueTask<Dictionary<MaterialId, Material>> GetIdToMaterialMapAsync(CancellationToken token = default(CancellationToken));
|
||||
|
||||
/// <summary>
|
||||
/// 异步获取ID到圣遗物副词条的字典
|
||||
/// </summary>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Model.Intrinsic;
|
||||
using Snap.Hutao.Model.Metadata;
|
||||
using Snap.Hutao.Model.Metadata.Avatar;
|
||||
using Snap.Hutao.Model.Metadata.Reliquary;
|
||||
using Snap.Hutao.Model.Metadata.Weapon;
|
||||
@@ -26,6 +27,12 @@ internal partial class MetadataService
|
||||
return FromCacheAsDictionaryAsync<AvatarId, Avatar>("Avatar", a => a.Id, token);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ValueTask<Dictionary<MaterialId, Material>> GetIdToMaterialMapAsync(CancellationToken token = default)
|
||||
{
|
||||
return FromCacheAsDictionaryAsync<MaterialId, Material>("Material", a => a.Id, token);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ValueTask<Dictionary<ReliquaryAffixId, ReliquaryAffix>> GetIdReliquaryAffixMapAsync(CancellationToken token = default)
|
||||
{
|
||||
|
||||
@@ -71,6 +71,7 @@
|
||||
<None Remove="View\Dialog\AchievementImportDialog.xaml" />
|
||||
<None Remove="View\Dialog\AdoptCalculatorDialog.xaml" />
|
||||
<None Remove="View\Dialog\AvatarInfoQueryDialog.xaml" />
|
||||
<None Remove="View\Dialog\CommunityGameRecordDialog.xaml" />
|
||||
<None Remove="View\Dialog\CultivateProjectDialog.xaml" />
|
||||
<None Remove="View\Dialog\CultivatePromotionDeltaDialog.xaml" />
|
||||
<None Remove="View\Dialog\DailyNoteNotificationDialog.xaml" />
|
||||
@@ -183,6 +184,11 @@
|
||||
<ItemGroup>
|
||||
<None Include="..\.editorconfig" Link=".editorconfig" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="View\Dialog\CommunityGameRecordDialog.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="View\Dialog\CultivatePromotionDeltaDialog.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<!-- Copyright (c) Microsoft Corporation and Contributors. -->
|
||||
<!-- Licensed under the MIT License. -->
|
||||
|
||||
<ContentDialog
|
||||
x:Class="Snap.Hutao.View.Dialog.CommunityGameRecordDialog"
|
||||
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"
|
||||
Closed="OnContentDialogClosed"
|
||||
DefaultButton="Primary"
|
||||
PrimaryButtonText="完成"
|
||||
Style="{StaticResource DefaultContentDialogStyle}"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid Loaded="OnGridLoaded">
|
||||
<WebView2
|
||||
Name="WebView"
|
||||
Width="360"
|
||||
Height="580"/>
|
||||
</Grid>
|
||||
</ContentDialog>
|
||||
@@ -0,0 +1,60 @@
|
||||
// Copyright (c) Microsoft Corporation and Contributors.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.Web.WebView2.Core;
|
||||
using Snap.Hutao.Model.Binding.User;
|
||||
using Snap.Hutao.Service.User;
|
||||
using Snap.Hutao.Web.Bridge;
|
||||
|
||||
namespace Snap.Hutao.View.Dialog;
|
||||
|
||||
/// <summary>
|
||||
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϸ<EFBFBD><CFB7>¼<EFBFBD>Ի<EFBFBD><D4BB><EFBFBD>
|
||||
/// </summary>
|
||||
public sealed partial class CommunityGameRecordDialog : ContentDialog
|
||||
{
|
||||
private readonly IServiceScope scope;
|
||||
[SuppressMessage("", "IDE0052")]
|
||||
private MiHoYoJSInterface? jsInterface;
|
||||
|
||||
/// <summary>
|
||||
/// <20><><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD>µ<EFBFBD><C2B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϸ<EFBFBD><CFB7>¼<EFBFBD>Ի<EFBFBD><D4BB><EFBFBD>
|
||||
/// </summary>
|
||||
/// <param name="window"><3E><><EFBFBD><EFBFBD></param>
|
||||
public CommunityGameRecordDialog(MainWindow window)
|
||||
{
|
||||
InitializeComponent();
|
||||
XamlRoot = window.Content.XamlRoot;
|
||||
scope = Ioc.Default.CreateScope();
|
||||
}
|
||||
|
||||
private void OnGridLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
InitializeAsync().SafeForget();
|
||||
}
|
||||
|
||||
private async Task InitializeAsync()
|
||||
{
|
||||
await WebView.EnsureCoreWebView2Async();
|
||||
CoreWebView2 coreWebView2 = WebView.CoreWebView2;
|
||||
User? user = scope.ServiceProvider.GetRequiredService<IUserService>().Current;
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
coreWebView2.SetCookie(user.CookieToken, user.Ltoken, null).SetMobileUserAgent();
|
||||
jsInterface = new(coreWebView2, scope.ServiceProvider);
|
||||
coreWebView2.Navigate("https://webstatic.mihoyo.com/app/community-game-records/index.html");
|
||||
}
|
||||
|
||||
private void OnContentDialogClosed(ContentDialog sender, ContentDialogClosedEventArgs args)
|
||||
{
|
||||
jsInterface = null;
|
||||
scope.Dispose();
|
||||
}
|
||||
}
|
||||
@@ -39,8 +39,7 @@ public sealed partial class SignInWebViewDialog : ContentDialog
|
||||
{
|
||||
await WebView.EnsureCoreWebView2Async();
|
||||
CoreWebView2 coreWebView2 = WebView.CoreWebView2;
|
||||
IUserService userService = scope.ServiceProvider.GetRequiredService<IUserService>();
|
||||
User? user = userService.Current;
|
||||
User? user = scope.ServiceProvider.GetRequiredService<IUserService>().Current;
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
|
||||
@@ -142,6 +142,13 @@
|
||||
<Grid>
|
||||
<ScrollViewer Padding="0,0,4,0">
|
||||
<StackPanel>
|
||||
<ItemsControl>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<InfoBar/>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
<Pivot>
|
||||
<PivotItem
|
||||
Content="{Binding Announcement.List[0]}"
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
x:Class="Snap.Hutao.View.Page.CultivationPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:cwua="using:CommunityToolkit.WinUI.UI.Animations"
|
||||
xmlns:cwucont="using:CommunityToolkit.WinUI.UI.Controls"
|
||||
xmlns:cwuconv="using:CommunityToolkit.WinUI.UI.Converters"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
@@ -29,6 +30,11 @@
|
||||
<x:Double>1</x:Double>
|
||||
</cwuconv:BoolToObjectConverter.FalseValue>
|
||||
</cwuconv:BoolToObjectConverter>
|
||||
|
||||
<cwuconv:BoolToObjectConverter
|
||||
x:Key="BoolToStyleSelector"
|
||||
FalseValue="{StaticResource BodyTextBlockStyle}"
|
||||
TrueValue="{StaticResource BaseTextBlockStyle}"/>
|
||||
</Page.Resources>
|
||||
|
||||
<mxi:Interaction.Behaviors>
|
||||
@@ -71,6 +77,7 @@
|
||||
<PivotItem Header="材料清单">
|
||||
<cwucont:AdaptiveGridView
|
||||
Padding="16,16,4,4"
|
||||
cwua:ItemsReorderAnimation.Duration="0:0:0.1"
|
||||
DesiredWidth="320"
|
||||
ItemContainerStyle="{StaticResource LargeGridViewItemStyle}"
|
||||
ItemsSource="{Binding CultivateEntries}"
|
||||
@@ -81,7 +88,7 @@
|
||||
<Grid Background="Transparent">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition Height="auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid Margin="8">
|
||||
<Grid.ColumnDefinitions>
|
||||
@@ -115,64 +122,65 @@
|
||||
ToolTipService.ToolTip="删除清单"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<ItemsControl
|
||||
Grid.Row="1"
|
||||
Margin="8,0,8,8"
|
||||
ItemsSource="{Binding Items}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid Margin="0,4,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid>
|
||||
<shvc:ItemIcon
|
||||
Width="32"
|
||||
Height="32"
|
||||
Icon="{Binding Inner.Icon, Converter={StaticResource ItemIconConverter}}"
|
||||
Opacity="{Binding IsFinished, Converter={StaticResource BoolToOpacityConverter}}"
|
||||
Quality="{Binding Inner.RankLevel}"/>
|
||||
<FontIcon
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="24"
|
||||
Glyph=""
|
||||
Visibility="{Binding IsFinished, Converter={StaticResource BoolToVisibilityConverter}}"/>
|
||||
</Grid>
|
||||
<Button
|
||||
Grid.Column="1"
|
||||
Height="32"
|
||||
Margin="6,0,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
Background="Transparent"
|
||||
BorderBrush="{x:Null}"
|
||||
BorderThickness="0"
|
||||
Command="{Binding FinishStateCommand}">
|
||||
<Grid Opacity="{Binding IsFinished, Converter={StaticResource BoolToOpacityConverter}}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock
|
||||
Grid.Column="0"
|
||||
Margin="0,0,0,0"
|
||||
<ScrollViewer Grid.Row="1" Height="240">
|
||||
<ItemsControl Margin="8,0,8,8" ItemsSource="{Binding Items}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid Margin="0,4,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid>
|
||||
<shvc:ItemIcon
|
||||
Width="32"
|
||||
Height="32"
|
||||
Icon="{Binding Inner.Icon, Converter={StaticResource ItemIconConverter}}"
|
||||
Opacity="{Binding IsFinished, Converter={StaticResource BoolToOpacityConverter}}"
|
||||
Quality="{Binding Inner.RankLevel}"/>
|
||||
<FontIcon
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding Inner.Name}"
|
||||
TextTrimming="CharacterEllipsis"/>
|
||||
<TextBlock
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding Entity.Count}"/>
|
||||
FontSize="24"
|
||||
Glyph=""
|
||||
Visibility="{Binding IsFinished, Converter={StaticResource BoolToVisibilityConverter}}"/>
|
||||
</Grid>
|
||||
</Button>
|
||||
<Button
|
||||
Grid.Column="1"
|
||||
Height="32"
|
||||
Margin="6,0,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
Background="Transparent"
|
||||
BorderBrush="{x:Null}"
|
||||
BorderThickness="0"
|
||||
Command="{Binding FinishStateCommand}">
|
||||
<Grid Opacity="{Binding IsFinished, Converter={StaticResource BoolToOpacityConverter}}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock
|
||||
Grid.Column="0"
|
||||
Margin="0,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
Style="{Binding IsToday, Converter={StaticResource BoolToStyleSelector}}"
|
||||
Text="{Binding Inner.Name}"
|
||||
TextTrimming="CharacterEllipsis"/>
|
||||
<TextBlock
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
Style="{Binding IsToday, Converter={StaticResource BoolToStyleSelector}}"
|
||||
Text="{Binding Entity.Count}"/>
|
||||
</Grid>
|
||||
</Button>
|
||||
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
|
||||
<Grid.Resources>
|
||||
<Storyboard x:Name="ButtonPanelVisibleStoryboard">
|
||||
|
||||
@@ -178,13 +178,13 @@
|
||||
</Grid.ColumnDefinitions>
|
||||
<shci:MonoChrome
|
||||
Grid.Column="0"
|
||||
Width="27.2"
|
||||
Height="27.2"
|
||||
Width="32"
|
||||
Height="32"
|
||||
Source="{Binding Selected.FetterInfo.VisionBefore, Converter={StaticResource ElementNameIconConverter}}"/>
|
||||
<shci:MonoChrome
|
||||
Grid.Column="1"
|
||||
Width="27.2"
|
||||
Height="27.2"
|
||||
Width="32"
|
||||
Height="32"
|
||||
Source="{Binding Selected.Weapon, Converter={StaticResource WeaponTypeIconConverter}}"/>
|
||||
</Grid>
|
||||
<shvc:ItemIcon
|
||||
@@ -196,9 +196,14 @@
|
||||
|
||||
<StackPanel Grid.Column="1" Margin="16,0,0,0">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Style="{StaticResource SubtitleTextBlockStyle}" Text="{Binding Selected.Name}"/>
|
||||
<TextBlock
|
||||
Margin="24,0,0,0"
|
||||
Margin="0,0,0,2"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource SubtitleTextBlockStyle}"
|
||||
Text="{Binding Selected.Name}"/>
|
||||
<TextBlock
|
||||
Margin="24,0,0,2"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource SubtitleTextBlockStyle}"
|
||||
Text="{Binding Selected.FetterInfo.Title}"/>
|
||||
</StackPanel>
|
||||
@@ -286,6 +291,24 @@
|
||||
Content="{Binding Selected.Property, Mode=OneWay}"
|
||||
ContentTemplate="{StaticResource PropertyDataTemplate}"/>
|
||||
|
||||
<TextBlock
|
||||
Margin="16,32,0,0"
|
||||
Style="{StaticResource BaseTextBlockStyle}"
|
||||
Text="养成材料"/>
|
||||
<GridView
|
||||
Margin="16,16,0,0"
|
||||
ItemsPanel="{StaticResource HorizontalStackPanelTemplate}"
|
||||
ItemsSource="{Binding Selected.CultivationItemsView}"
|
||||
SelectionMode="None">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<shvc:BottomTextControl Text="{Binding Name}">
|
||||
<shvc:ItemIcon Icon="{Binding Icon, Converter={StaticResource ItemIconConverter}}" Quality="{Binding RankLevel}"/>
|
||||
</shvc:BottomTextControl>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</GridView>
|
||||
|
||||
<TextBlock
|
||||
Margin="16,32,0,0"
|
||||
Style="{StaticResource BaseTextBlockStyle}"
|
||||
@@ -311,8 +334,6 @@
|
||||
Text="搭配角色"/>
|
||||
<GridView
|
||||
Margin="16,16,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
ItemsSource="{Binding Selected.Collocation.Avatars}"
|
||||
SelectionMode="None">
|
||||
<GridView.ItemTemplate>
|
||||
@@ -405,12 +426,7 @@
|
||||
Margin="16,32,0,0"
|
||||
Style="{StaticResource BaseTextBlockStyle}"
|
||||
Text="其他"/>
|
||||
<Border
|
||||
Margin="16,16,0,0"
|
||||
Background="{StaticResource CardBackgroundFillColorDefault}"
|
||||
BorderBrush="{StaticResource CardStrokeColorDefault}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="{StaticResource CompatCornerRadius}">
|
||||
<Border Margin="16,16,0,0" Style="{StaticResource BorderCardStyle}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
@@ -443,7 +459,7 @@
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
Header="料理">
|
||||
<Grid>
|
||||
<Grid DataContext="{Binding Selected.CookBonusView}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition Height="auto"/>
|
||||
@@ -451,7 +467,6 @@
|
||||
<RowDefinition Height="auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition/>
|
||||
@@ -465,8 +480,8 @@
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Margin="16,16,0,16"
|
||||
Text="{Binding Selected.FetterInfo.CookBonus.Name}">
|
||||
<shvc:ItemIcon Icon="{Binding Selected.FetterInfo.CookBonus.Icon, Converter={StaticResource ItemIconConverter}}" Quality="{Binding Selected.FetterInfo.CookBonus.RankLevel}"/>
|
||||
Text="{Binding Item.Name}">
|
||||
<shvc:ItemIcon Icon="{Binding Item.Icon, Converter={StaticResource ItemIconConverter}}" Quality="{Binding Item.RankLevel}"/>
|
||||
</shvc:BottomTextControl>
|
||||
<TextBlock
|
||||
Grid.Column="1"
|
||||
@@ -477,48 +492,26 @@
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Margin="16,16,0,16"
|
||||
Text="{Binding Selected.FetterInfo.CookBonus.OriginName}">
|
||||
<shvc:ItemIcon Icon="{Binding Selected.FetterInfo.CookBonus.OriginIcon, Converter={StaticResource ItemIconConverter}}" Quality="{Binding Selected.FetterInfo.CookBonus.RankLevel}"/>
|
||||
Text="{Binding OriginItem.Name}">
|
||||
<shvc:ItemIcon Icon="{Binding OriginItem.Icon, Converter={StaticResource ItemIconConverter}}" Quality="{Binding OriginItem.RankLevel}"/>
|
||||
</shvc:BottomTextControl>
|
||||
<Rectangle
|
||||
Grid.RowSpan="2"
|
||||
<StackPanel
|
||||
Grid.RowSpan="4"
|
||||
Grid.Column="2"
|
||||
Width="1"
|
||||
Margin="16,16,0,16"
|
||||
Fill="{StaticResource SystemChromeHighColor}"/>
|
||||
<TextBlock
|
||||
Grid.Column="3"
|
||||
Margin="16,16,0,0"
|
||||
Style="{StaticResource BaseTextBlockStyle}"
|
||||
Text="材料"/>
|
||||
<ItemsControl
|
||||
Grid.Row="1"
|
||||
Grid.Column="3"
|
||||
ItemsPanel="{StaticResource HorizontalStackPanelTemplate}"
|
||||
ItemsSource="{Binding Selected.FetterInfo.CookBonus.InputList}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<shvc:BottomTextControl
|
||||
Margin="16,16,0,16"
|
||||
Text="{Binding Count}"
|
||||
ToolTipService.ToolTip="{Binding Name}">
|
||||
<shvc:ItemIcon Icon="{Binding Icon, Converter={StaticResource ItemIconConverter}}" Quality="{Binding RankLevel}"/>
|
||||
</shvc:BottomTextControl>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.ColumnSpan="4"
|
||||
Margin="16,0,16,16"
|
||||
Text="{Binding Selected.FetterInfo.CookBonus.Description}"
|
||||
TextWrapping="Wrap"/>
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.ColumnSpan="4"
|
||||
Margin="16,0,16,16"
|
||||
Text="{Binding Selected.FetterInfo.CookBonus.EffectDescription}"
|
||||
TextWrapping="Wrap"/>
|
||||
Margin="16">
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.ColumnSpan="4"
|
||||
Text="{Binding Item.Description}"
|
||||
TextWrapping="Wrap"/>
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.ColumnSpan="4"
|
||||
Margin="0,16,0,0"
|
||||
Text="{Binding Item.EffectDescription}"
|
||||
TextWrapping="Wrap"/>
|
||||
</StackPanel>
|
||||
|
||||
</Grid>
|
||||
</Expander>
|
||||
<!-- 衣装 -->
|
||||
|
||||
@@ -185,6 +185,37 @@ internal class SettingViewModel : ObservableObject
|
||||
/// </summary>
|
||||
public ICommand ShowSignInWebViewDialogCommand { get; }
|
||||
|
||||
private static async Task DangerousUnusedLoginMethodAsync()
|
||||
{
|
||||
LoginMihoyoBBSDialog dialog = ActivatorUtilities.CreateInstance<LoginMihoyoBBSDialog>(Ioc.Default);
|
||||
(bool isOk, Dictionary<string, string>? data) = await dialog.GetInputAccountPasswordAsync().ConfigureAwait(false);
|
||||
|
||||
if (isOk)
|
||||
{
|
||||
(Response<LoginResult>? resp, Aigis? aigis) = await Ioc.Default
|
||||
.GetRequiredService<PassportClient2>()
|
||||
.LoginByPasswordAsync(data, CancellationToken.None)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (resp != null)
|
||||
{
|
||||
if (resp.IsOk())
|
||||
{
|
||||
Cookie cookie = Cookie.FromLoginResult(resp.Data);
|
||||
|
||||
await Ioc.Default
|
||||
.GetRequiredService<IUserService>()
|
||||
.ProcessInputCookieAsync(cookie)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (resp.ReturnCode == (int)KnownReturnCode.RET_NEED_AIGIS)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SetGamePathAsync()
|
||||
{
|
||||
IGameLocator locator = Ioc.Default.GetRequiredService<IEnumerable<IGameLocator>>()
|
||||
@@ -221,33 +252,10 @@ internal class SettingViewModel : ObservableObject
|
||||
private async Task DebugThrowExceptionAsync()
|
||||
{
|
||||
#if DEBUG
|
||||
LoginMihoyoBBSDialog dialog = ActivatorUtilities.CreateInstance<LoginMihoyoBBSDialog>(Ioc.Default);
|
||||
(bool isOk, Dictionary<string, string>? data) = await dialog.GetInputAccountPasswordAsync().ConfigureAwait(false);
|
||||
|
||||
if (isOk)
|
||||
{
|
||||
(Response<LoginResult>? resp, Aigis? aigis) = await Ioc.Default
|
||||
.GetRequiredService<PassportClient2>()
|
||||
.LoginByPasswordAsync(data, CancellationToken.None)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (resp != null)
|
||||
{
|
||||
if (resp.IsOk())
|
||||
{
|
||||
Cookie cookie = Cookie.FromLoginResult(resp.Data);
|
||||
|
||||
await Ioc.Default
|
||||
.GetRequiredService<IUserService>()
|
||||
.ProcessInputCookieAsync(cookie)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (resp.ReturnCode == (int)KnownReturnCode.RET_NEED_AIGIS)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
CommunityGameRecordDialog dialog = ActivatorUtilities.CreateInstance<CommunityGameRecordDialog>(Ioc.Default);
|
||||
await dialog.ShowAsync();
|
||||
#else
|
||||
await Task.Yield();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ using Snap.Hutao.Factory.Abstraction;
|
||||
using Snap.Hutao.Model.Binding.Cultivation;
|
||||
using Snap.Hutao.Model.Binding.Hutao;
|
||||
using Snap.Hutao.Model.Intrinsic;
|
||||
using Snap.Hutao.Model.Metadata;
|
||||
using Snap.Hutao.Model.Metadata.Avatar;
|
||||
using Snap.Hutao.Model.Primitive;
|
||||
using Snap.Hutao.Service.Abstraction;
|
||||
@@ -89,13 +90,14 @@ internal class WikiAvatarViewModel : ObservableObject
|
||||
{
|
||||
if (await metadataService.InitializeAsync().ConfigureAwait(false))
|
||||
{
|
||||
Dictionary<MaterialId, Material> idMaterialMap = await metadataService.GetIdToMaterialMapAsync().ConfigureAwait(false);
|
||||
List<Avatar> avatars = await metadataService.GetAvatarsAsync().ConfigureAwait(false);
|
||||
List<Avatar> sorted = avatars
|
||||
.OrderByDescending(avatar => avatar.BeginTime)
|
||||
.ThenByDescending(avatar => avatar.Sort)
|
||||
.ToList();
|
||||
|
||||
await CombineWithAvatarCollocationsAsync(sorted).ConfigureAwait(false);
|
||||
await CombineComplexDataAsync(sorted, idMaterialMap).ConfigureAwait(false);
|
||||
|
||||
await ThreadHelper.SwitchToMainThreadAsync();
|
||||
Avatars = new AdvancedCollectionView(sorted, true);
|
||||
@@ -103,7 +105,7 @@ internal class WikiAvatarViewModel : ObservableObject
|
||||
}
|
||||
}
|
||||
|
||||
private async Task CombineWithAvatarCollocationsAsync(List<Avatar> avatars)
|
||||
private async Task CombineComplexDataAsync(List<Avatar> avatars, Dictionary<MaterialId, Material> idMaterialMap)
|
||||
{
|
||||
if (await hutaoCache.InitializeForWikiAvatarViewModelAsync().ConfigureAwait(false))
|
||||
{
|
||||
@@ -112,6 +114,8 @@ internal class WikiAvatarViewModel : ObservableObject
|
||||
foreach (Avatar avatar in avatars)
|
||||
{
|
||||
avatar.Collocation = idCollocations.GetValueOrDefault(avatar.Id);
|
||||
avatar.CookBonusView ??= CookBonusView.Create(avatar.FetterInfo.CookBonus2, idMaterialMap);
|
||||
avatar.CultivationItemsView ??= avatar.CultivationItems.Select(i => idMaterialMap[i]).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -311,6 +311,14 @@ internal static class ApiEndpoints
|
||||
public const string AccountCreateActionTicket = $"{PassportApi}/account/ma-cn-verifier/app/createActionTicketByToken";
|
||||
#endregion
|
||||
|
||||
#region Patcher
|
||||
|
||||
/// <summary>
|
||||
/// 胡桃检查更新
|
||||
/// </summary>
|
||||
public const string PatcherHutaoStable = $"{PatcherApi}/hutao/stable";
|
||||
#endregion
|
||||
|
||||
#region SdkStaticLauncherApi
|
||||
|
||||
/// <summary>
|
||||
@@ -360,6 +368,8 @@ internal static class ApiEndpoints
|
||||
private const string PassportApiAuthApi = $"{PassportApi}/account/auth/api";
|
||||
private const string PassportApiV4 = "https://passport-api-v4.mihoyo.com";
|
||||
|
||||
private const string PatcherApi = "https://patcher.dgp-studio.cn";
|
||||
|
||||
private const string SdkStatic = "https://sdk-static.mihoyo.com";
|
||||
private const string SdkStaticLauncherApi = $"{SdkStatic}/hk4e_cn/mdk/launcher/api";
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ public class MiHoYoJSInterface
|
||||
/// </summary>
|
||||
/// <param name="webView">webview2</param>
|
||||
/// <param name="serviceProvider">服务提供器</param>
|
||||
protected MiHoYoJSInterface(CoreWebView2 webView, IServiceProvider serviceProvider)
|
||||
public MiHoYoJSInterface(CoreWebView2 webView, IServiceProvider serviceProvider)
|
||||
{
|
||||
this.webView = webView;
|
||||
this.serviceProvider = serviceProvider;
|
||||
@@ -159,7 +159,7 @@ public class MiHoYoJSInterface
|
||||
long t = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
|
||||
int r = GetRandom();
|
||||
string b = param.Payload.Body;
|
||||
string q = string.Join('&', param.Payload.Query.OrderBy(x => x.Key).Select(x => $"{x.Key}={x.Value}"));
|
||||
string q = param.Payload.GetQueryParam();
|
||||
string check = Md5Convert.ToHexString($"salt={salt}&t={t}&r={r}&b={b}&q={q}").ToLowerInvariant();
|
||||
|
||||
return new() { Data = new() { ["DS"] = $"{t},{r},{check}", }, };
|
||||
@@ -256,6 +256,13 @@ public class MiHoYoJSInterface
|
||||
return new() { Data = new() { { "statusBarHeight", 0 } } };
|
||||
}
|
||||
|
||||
[JsMethod("pushPage")]
|
||||
public virtual IJsResult? PushPage(JsParam<PushPagePayload> param)
|
||||
{
|
||||
webView.Navigate(param.Payload.Page);
|
||||
return null;
|
||||
}
|
||||
|
||||
[JsMethod("showAlertDialog")]
|
||||
public virtual Task<IJsResult?> ShowAlertDialogAsync(JsParam param)
|
||||
{
|
||||
@@ -286,12 +293,6 @@ public class MiHoYoJSInterface
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
[JsMethod("pushPage")]
|
||||
public virtual IJsResult? PushPage(JsParam param)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
[JsMethod("openSystemBrowser")]
|
||||
public virtual IJsResult? OpenSystemBrowser(JsParam param)
|
||||
{
|
||||
@@ -344,7 +345,7 @@ public class MiHoYoJSInterface
|
||||
private async void OnWebMessageReceived(CoreWebView2 webView2, CoreWebView2WebMessageReceivedEventArgs args)
|
||||
{
|
||||
string message = args.TryGetWebMessageAsString();
|
||||
|
||||
logger.LogInformation("[OnRawMessage]\n{message}", message);
|
||||
JsParam param = JsonSerializer.Deserialize<JsParam>(message)!;
|
||||
|
||||
logger.LogInformation("[OnMessage]\nMethod : {method}\nPayload : {payload}\nCallback: {callback}", param.Method, param.Payload, param.Callback);
|
||||
@@ -363,6 +364,7 @@ public class MiHoYoJSInterface
|
||||
"getUserInfo" => GetUserInfo(param),
|
||||
"hideLoading" => null,
|
||||
"login" => null,
|
||||
"pushPage" => PushPage(param),
|
||||
"showLoading" => null,
|
||||
_ => logger.LogWarning<IJsResult>("Unhandled Message Type: {method}", param.Method),
|
||||
};
|
||||
|
||||
@@ -12,11 +12,30 @@ public class DynamicSecrect2Playload
|
||||
/// q
|
||||
/// </summary>
|
||||
[JsonPropertyName("query")]
|
||||
public Dictionary<string, string> Query { get; set; } = default!;
|
||||
public Dictionary<string, JsonElement> Query { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// b
|
||||
/// </summary>
|
||||
[JsonPropertyName("body")]
|
||||
public string Body { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 获取排序后的的查询参数
|
||||
/// </summary>
|
||||
/// <returns>查询参数</returns>
|
||||
public string GetQueryParam()
|
||||
{
|
||||
IEnumerable<string> parts = Query.OrderBy(x => x.Key).Select(x =>
|
||||
{
|
||||
if (x.Value.ValueKind == JsonValueKind.True || x.Value.ValueKind == JsonValueKind.False)
|
||||
{
|
||||
return $"{x.Key}={x.Value.ToString().ToLowerInvariant()}";
|
||||
}
|
||||
|
||||
return $"{x.Key}={x.Value}";
|
||||
});
|
||||
|
||||
return string.Join('&', parts);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,4 +63,4 @@ public class JsParam<TPayload>
|
||||
Callback = jsParam.Callback,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Web.Bridge.Model;
|
||||
|
||||
/// <summary>
|
||||
/// 导航页面参数
|
||||
/// </summary>
|
||||
public class PushPagePayload
|
||||
{
|
||||
/// <summary>
|
||||
/// 页面Url
|
||||
/// </summary>
|
||||
[JsonPropertyName("page")]
|
||||
public string Page { get; set; } = default!;
|
||||
}
|
||||
@@ -59,6 +59,7 @@ internal class BindingClient
|
||||
/// <param name="user">用户</param>
|
||||
/// <param name="token">取消令牌</param>
|
||||
/// <returns>用户角色信息</returns>
|
||||
[Obsolete("Set-Cookie 冲突")]
|
||||
[ApiInformation(Cookie = CookieType.Ltoken)]
|
||||
public async Task<List<UserGameRole>> GetUserGameRolesByCookieAsync(User user, CancellationToken token = default)
|
||||
{
|
||||
|
||||
@@ -41,12 +41,12 @@ internal class BindingClient2
|
||||
/// <param name="user">用户</param>
|
||||
/// <param name="token">取消令牌</param>
|
||||
/// <returns>用户角色信息</returns>
|
||||
[ApiInformation(Cookie = CookieType.Stoken)]
|
||||
[ApiInformation(Cookie = CookieType.Stoken, Salt = SaltType.LK2)]
|
||||
public async Task<List<UserGameRole>> GetUserGameRolesByStokenAsync(User user, CancellationToken token = default)
|
||||
{
|
||||
Response<ListWrapper<UserGameRole>>? resp = await httpClient
|
||||
.SetUser(user, CookieType.Stoken)
|
||||
.UseDynamicSecret(DynamicSecretVersion.Gen1, SaltType.K2, true)
|
||||
.UseDynamicSecret(DynamicSecretVersion.Gen1, SaltType.LK2, true)
|
||||
.TryCatchGetFromJsonAsync<Response<ListWrapper<UserGameRole>>>(ApiEndpoints.UserGameRolesByStoken, options, logger, token)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ namespace Snap.Hutao.Web.Hutao;
|
||||
/// <summary>
|
||||
/// 胡桃API客户端
|
||||
/// </summary>
|
||||
// [Injection(InjectAs.Transient)]
|
||||
[HttpClient(HttpClientConfigration.Default)]
|
||||
internal class HomaClient
|
||||
{
|
||||
@@ -220,4 +219,4 @@ internal class HomaClient
|
||||
{
|
||||
return httpClient.TryCatchPostAsJsonAsync<SimpleRecord, Response<string>>($"{HutaoAPI}/Record/Upload", playerRecord, options, logger, token);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Web.Hutao.Patch;
|
||||
|
||||
/// <summary>
|
||||
/// 更新信息
|
||||
/// </summary>
|
||||
public class PatchInformation
|
||||
{
|
||||
/// <summary>
|
||||
/// 标签名 通常被替换为版本
|
||||
/// </summary>
|
||||
public string TagName { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 更新日志
|
||||
/// </summary>
|
||||
public string Body { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 浏览器下载链接
|
||||
/// </summary>
|
||||
public Uri BrowserDownloadUrl { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 缓存时间
|
||||
/// </summary>
|
||||
public DateTimeOffset CacheTime { get; set; }
|
||||
}
|
||||
51
src/Snap.Hutao/Snap.Hutao/Web/Hutao/PatchClient.cs
Normal file
51
src/Snap.Hutao/Snap.Hutao/Web/Hutao/PatchClient.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
|
||||
using Snap.Hutao.Extension;
|
||||
using Snap.Hutao.Model.Binding.User;
|
||||
using Snap.Hutao.Web.Hoyolab;
|
||||
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord;
|
||||
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.Avatar;
|
||||
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.SpiralAbyss;
|
||||
using Snap.Hutao.Web.Hutao.Model;
|
||||
using Snap.Hutao.Web.Hutao.Model.Post;
|
||||
using Snap.Hutao.Web.Response;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Json;
|
||||
|
||||
namespace Snap.Hutao.Web.Hutao;
|
||||
|
||||
/// <summary>
|
||||
/// 更新客户端
|
||||
/// </summary>
|
||||
[HttpClient(HttpClientConfigration.Default)]
|
||||
internal class PatchClient
|
||||
{
|
||||
private readonly HttpClient httpClient;
|
||||
private readonly JsonSerializerOptions options;
|
||||
private readonly ILogger<HomaClient> logger;
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的更新客户端
|
||||
/// </summary>
|
||||
/// <param name="httpClient">http 客户端</param>
|
||||
/// <param name="options">json选项</param>
|
||||
/// <param name="logger">日志器</param>
|
||||
public PatchClient(HttpClient httpClient, JsonSerializerOptions options, ILogger<HomaClient> logger)
|
||||
{
|
||||
this.httpClient = httpClient;
|
||||
this.options = options;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新信息
|
||||
/// </summary>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
public Task<Patch.PatchInformation?> GetPatchInformationAsync(CancellationToken token = default)
|
||||
{
|
||||
return httpClient.TryCatchGetFromJsonAsync<Patch.PatchInformation>(ApiEndpoints.PatcherHutaoStable, options, logger, token);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user