mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
file nesting
This commit is contained in:
31
src/Snap.Hutao/Snap.Hutao/.filenesting.json
Normal file
31
src/Snap.Hutao/Snap.Hutao/.filenesting.json
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"help": "https://go.microsoft.com/fwlink/?linkid=866610",
|
||||||
|
"dependentFileProviders": {
|
||||||
|
"add": {
|
||||||
|
"extensionToExtension": {
|
||||||
|
"add": {
|
||||||
|
".json": [ ".txt" ]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pathSegment": {
|
||||||
|
"add": {
|
||||||
|
".*": [ ".cs" ]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fileSuffixToExtension": {
|
||||||
|
"add": {
|
||||||
|
"DesignTimeFactory.cs": [".cs"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fileToFile": {
|
||||||
|
"add": {
|
||||||
|
"app.manifest": [ "App.xaml.cs" ],
|
||||||
|
"Package.appxmanifest": [ "App.xaml.cs" ],
|
||||||
|
"GlobalUsing.cs": [ "Program.cs" ],
|
||||||
|
".filenesting.json": [ "Program.cs" ],
|
||||||
|
".editorconfig": [ "Program.cs" ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
src/Snap.Hutao/Snap.Hutao/Assets/Logo.ico
Normal file
BIN
src/Snap.Hutao/Snap.Hutao/Assets/Logo.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 66 KiB |
@@ -61,6 +61,11 @@ public class AppDbContext : DbContext
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public DbSet<GameAccount> GameAccounts { get; set; } = default!;
|
public DbSet<GameAccount> GameAccounts { get; set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 实时便笺
|
||||||
|
/// </summary>
|
||||||
|
public DbSet<DailyNoteEntry> DailyNotes { get; set; } = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 构造一个临时的应用程序数据库上下文
|
/// 构造一个临时的应用程序数据库上下文
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -76,6 +81,7 @@ public class AppDbContext : DbContext
|
|||||||
{
|
{
|
||||||
modelBuilder
|
modelBuilder
|
||||||
.ApplyConfiguration(new AvatarInfoConfiguration())
|
.ApplyConfiguration(new AvatarInfoConfiguration())
|
||||||
.ApplyConfiguration(new UserConfiguration());
|
.ApplyConfiguration(new UserConfiguration())
|
||||||
|
.ApplyConfiguration(new DailyNoteEntryConfiguration());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -15,12 +15,12 @@ namespace Snap.Hutao.Core;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal static class CoreEnvironment
|
internal static class CoreEnvironment
|
||||||
{
|
{
|
||||||
// 计算过程:https://gist.github.com/Lightczx/373c5940b36e24b25362728b52dec4fd
|
// 计算过程:https://github.com/UIGF-org/Hoyolab.Salt
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 动态密钥1的盐
|
/// 动态密钥1的盐
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const string DynamicSecret1Salt = "yUZ3s0Sna1IrSNfk29Vo6vRapdOyqyhB";
|
public const string DynamicSecret1Salt = "jEpJb9rRARU2rXDA9qYbZ3selxkuct9a";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 动态密钥2的盐
|
/// 动态密钥2的盐
|
||||||
@@ -35,7 +35,7 @@ internal static class CoreEnvironment
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 米游社 Rpc 版本
|
/// 米游社 Rpc 版本
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const string HoyolabXrpcVersion = "2.38.1";
|
public const string HoyolabXrpcVersion = "2.40.1";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 标准UA
|
/// 标准UA
|
||||||
|
|||||||
38
src/Snap.Hutao/Snap.Hutao/Core/TaskSchedulerHelper.cs
Normal file
38
src/Snap.Hutao/Snap.Hutao/Core/TaskSchedulerHelper.cs
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Microsoft.Win32.TaskScheduler;
|
||||||
|
using SchedulerTask = Microsoft.Win32.TaskScheduler.Task;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Core;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 任务计划器服务
|
||||||
|
/// </summary>
|
||||||
|
internal class TaskSchedulerHelper
|
||||||
|
{
|
||||||
|
private const string DailyNoteRefreshTaskName = "SnapHutaoDailyNoteRefreshTask";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 注册实时便笺刷新任务
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="interval">间隔(秒)</param>
|
||||||
|
public void RegisterForDailyNoteRefresh(int interval)
|
||||||
|
{
|
||||||
|
TimeSpan intervalTime = TimeSpan.FromSeconds(interval);
|
||||||
|
if (TaskService.Instance.GetTask(DailyNoteRefreshTaskName) is SchedulerTask targetTask)
|
||||||
|
{
|
||||||
|
TimeTrigger? trigger = targetTask.Definition.Triggers[0] as TimeTrigger;
|
||||||
|
trigger!.Repetition.Interval = intervalTime;
|
||||||
|
targetTask.RegisterChanges();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TaskDefinition task = TaskService.Instance.NewTask();
|
||||||
|
task.RegistrationInfo.Description = "胡桃实时便笺刷新任务 | 请勿编辑或删除。";
|
||||||
|
task.Triggers.Add(new TimeTrigger() { Repetition = new(intervalTime, TimeSpan.Zero), });
|
||||||
|
task.Actions.Add("explorer", "hutao://DailyNote/Refresh");
|
||||||
|
TaskService.Instance.RootFolder.RegisterTaskDefinition(DailyNoteRefreshTaskName, task);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,25 +1,30 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
namespace Snap.Hutao.Model.Metadata.Achievement;
|
namespace Snap.Hutao.Core.Windowing;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 成就触发器类型
|
/// 背景类型
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum AchievementTriggerType
|
public enum BackdropType
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 任务
|
/// 无
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Quest = 1,
|
None = 0,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 子任务
|
/// 亚克力
|
||||||
/// </summary>
|
/// </summary>
|
||||||
SubQuest = 2,
|
Acrylic,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 日常任务
|
/// 云母
|
||||||
/// </summary>
|
/// </summary>
|
||||||
DailyTask = 3,
|
Mica,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 变种云母
|
||||||
|
/// </summary>
|
||||||
|
MicaAlt,
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,16 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using CommunityToolkit.Mvvm.Messaging;
|
||||||
using Microsoft.UI;
|
using Microsoft.UI;
|
||||||
using Microsoft.UI.Windowing;
|
using Microsoft.UI.Windowing;
|
||||||
using Microsoft.UI.Xaml;
|
using Microsoft.UI.Xaml;
|
||||||
using Snap.Hutao.Core.Logging;
|
using Snap.Hutao.Core.Logging;
|
||||||
using Snap.Hutao.Extension;
|
using Snap.Hutao.Extension;
|
||||||
|
using Snap.Hutao.Message;
|
||||||
using Snap.Hutao.Win32;
|
using Snap.Hutao.Win32;
|
||||||
|
using System.IO;
|
||||||
|
using Windows.ApplicationModel;
|
||||||
using Windows.Graphics;
|
using Windows.Graphics;
|
||||||
using Windows.UI;
|
using Windows.UI;
|
||||||
using Windows.Win32.Foundation;
|
using Windows.Win32.Foundation;
|
||||||
@@ -15,11 +19,10 @@ using WinRT.Interop;
|
|||||||
namespace Snap.Hutao.Core.Windowing;
|
namespace Snap.Hutao.Core.Windowing;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 窗口管理器
|
/// 扩展窗口
|
||||||
/// 主要包含了针对窗体的 P/Inoke 逻辑
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="TWindow">窗体类型</typeparam>
|
/// <typeparam name="TWindow">窗体类型</typeparam>
|
||||||
internal sealed class ExtendedWindow<TWindow>
|
internal sealed class ExtendedWindow<TWindow> : IRecipient<BackdropTypeChangedMessage>
|
||||||
where TWindow : Window, IExtendedWindowSource
|
where TWindow : Window, IExtendedWindowSource
|
||||||
{
|
{
|
||||||
private readonly HWND handle;
|
private readonly HWND handle;
|
||||||
@@ -33,8 +36,10 @@ internal sealed class ExtendedWindow<TWindow>
|
|||||||
|
|
||||||
private readonly bool useLegacyDragBar;
|
private readonly bool useLegacyDragBar;
|
||||||
|
|
||||||
|
private SystemBackdrop? systemBackdrop;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 构造一个新的窗口状态管理器
|
/// 构造一个新的扩展窗口
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="window">窗口</param>
|
/// <param name="window">窗口</param>
|
||||||
/// <param name="titleBar">充当标题栏的元素</param>
|
/// <param name="titleBar">充当标题栏的元素</param>
|
||||||
@@ -65,6 +70,17 @@ internal sealed class ExtendedWindow<TWindow>
|
|||||||
return new(window, window.TitleBar);
|
return new(window, window.TitleBar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public void Receive(BackdropTypeChangedMessage message)
|
||||||
|
{
|
||||||
|
if (systemBackdrop != null)
|
||||||
|
{
|
||||||
|
systemBackdrop.BackdropType = message.BackdropType;
|
||||||
|
bool micaApplied = systemBackdrop.TryApply();
|
||||||
|
logger.LogInformation(EventIds.BackdropState, "Apply {name} : {result}", nameof(SystemBackdrop), micaApplied ? "succeed" : "failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static void UpdateTitleButtonColor(AppWindowTitleBar appTitleBar)
|
private static void UpdateTitleButtonColor(AppWindowTitleBar appTitleBar)
|
||||||
{
|
{
|
||||||
appTitleBar.ButtonBackgroundColor = Colors.Transparent;
|
appTitleBar.ButtonBackgroundColor = Colors.Transparent;
|
||||||
@@ -102,7 +118,7 @@ internal sealed class ExtendedWindow<TWindow>
|
|||||||
private void InitializeWindow()
|
private void InitializeWindow()
|
||||||
{
|
{
|
||||||
appWindow.Title = "胡桃";
|
appWindow.Title = "胡桃";
|
||||||
|
appWindow.SetIcon(Path.Combine(Package.Current.InstalledLocation.Path, "Assets/Logos/Logo.ico"));
|
||||||
ExtendsContentIntoTitleBar();
|
ExtendsContentIntoTitleBar();
|
||||||
|
|
||||||
Persistence.RecoverOrInit(appWindow, window.PersistSize, window.InitSize);
|
Persistence.RecoverOrInit(appWindow, window.PersistSize, window.InitSize);
|
||||||
@@ -113,12 +129,14 @@ internal sealed class ExtendedWindow<TWindow>
|
|||||||
|
|
||||||
appWindow.Show(true);
|
appWindow.Show(true);
|
||||||
|
|
||||||
bool micaApplied = new SystemBackdrop(window).TryApply();
|
systemBackdrop = new(window);
|
||||||
|
bool micaApplied = systemBackdrop.TryApply();
|
||||||
logger.LogInformation(EventIds.BackdropState, "Apply {name} : {result}", nameof(SystemBackdrop), micaApplied ? "succeed" : "failed");
|
logger.LogInformation(EventIds.BackdropState, "Apply {name} : {result}", nameof(SystemBackdrop), micaApplied ? "succeed" : "failed");
|
||||||
|
|
||||||
bool subClassApplied = subclassManager.TrySetWindowSubclass();
|
bool subClassApplied = subclassManager.TrySetWindowSubclass();
|
||||||
logger.LogInformation(EventIds.SubClassing, "Apply {name} : {result}", nameof(WindowSubclassManager<TWindow>), subClassApplied ? "succeed" : "failed");
|
logger.LogInformation(EventIds.SubClassing, "Apply {name} : {result}", nameof(WindowSubclassManager<TWindow>), subClassApplied ? "succeed" : "failed");
|
||||||
|
|
||||||
|
Ioc.Default.GetRequiredService<IMessenger>().Register(this);
|
||||||
window.Closed += OnWindowClosed;
|
window.Closed += OnWindowClosed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.UI.Composition;
|
using Microsoft.UI.Composition;
|
||||||
using Microsoft.UI.Composition.SystemBackdrops;
|
using Microsoft.UI.Composition.SystemBackdrops;
|
||||||
using Microsoft.UI.Xaml;
|
using Microsoft.UI.Xaml;
|
||||||
|
using Snap.Hutao.Context.Database;
|
||||||
|
using Snap.Hutao.Core.Database;
|
||||||
|
using Snap.Hutao.Model.Entity;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using Windows.System;
|
using Windows.System;
|
||||||
using WinRT;
|
using WinRT;
|
||||||
@@ -18,7 +22,7 @@ public class SystemBackdrop
|
|||||||
private readonly Window window;
|
private readonly Window window;
|
||||||
|
|
||||||
private DispatcherQueueHelper? dispatcherQueueHelper;
|
private DispatcherQueueHelper? dispatcherQueueHelper;
|
||||||
private MicaController? backdropController;
|
private ISystemBackdropControllerWithTargets? backdropController;
|
||||||
private SystemBackdropConfiguration? configuration;
|
private SystemBackdropConfiguration? configuration;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -28,7 +32,18 @@ public class SystemBackdrop
|
|||||||
public SystemBackdrop(Window window)
|
public SystemBackdrop(Window window)
|
||||||
{
|
{
|
||||||
this.window = window;
|
this.window = window;
|
||||||
|
using (IServiceScope scope = Ioc.Default.CreateScope())
|
||||||
|
{
|
||||||
|
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||||
|
SettingEntry entry = appDbContext.Settings.SingleOrAdd(SettingEntry.SystemBackdropType, BackdropType.Mica.ToString());
|
||||||
|
BackdropType = Enum.Parse<BackdropType>(entry.Value!);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 背景类型
|
||||||
|
/// </summary>
|
||||||
|
public BackdropType BackdropType { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 尝试设置背景
|
/// 尝试设置背景
|
||||||
@@ -36,30 +51,49 @@ public class SystemBackdrop
|
|||||||
/// <returns>是否设置成功</returns>
|
/// <returns>是否设置成功</returns>
|
||||||
public bool TryApply()
|
public bool TryApply()
|
||||||
{
|
{
|
||||||
if (!MicaController.IsSupported())
|
bool isSupport = BackdropType switch
|
||||||
|
{
|
||||||
|
BackdropType.Acrylic => DesktopAcrylicController.IsSupported(),
|
||||||
|
BackdropType.Mica or BackdropType.MicaAlt => MicaController.IsSupported(),
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!isSupport)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
// Previous one
|
||||||
|
if (backdropController != null)
|
||||||
|
{
|
||||||
|
backdropController.RemoveAllSystemBackdropTargets();
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
dispatcherQueueHelper = new();
|
dispatcherQueueHelper = new();
|
||||||
dispatcherQueueHelper.Ensure();
|
dispatcherQueueHelper.Ensure();
|
||||||
|
}
|
||||||
|
|
||||||
// Hooking up the policy object
|
// Hooking up the policy object
|
||||||
configuration = new();
|
configuration = new()
|
||||||
|
{
|
||||||
|
IsInputActive = true, // Initial configuration state.
|
||||||
|
};
|
||||||
|
SetConfigurationSourceTheme(configuration);
|
||||||
|
|
||||||
window.Activated += OnWindowActivated;
|
window.Activated += OnWindowActivated;
|
||||||
window.Closed += OnWindowClosed;
|
window.Closed += OnWindowClosed;
|
||||||
((FrameworkElement)window.Content).ActualThemeChanged += OnWindowThemeChanged;
|
((FrameworkElement)window.Content).ActualThemeChanged += OnWindowThemeChanged;
|
||||||
|
|
||||||
// Initial configuration state.
|
backdropController = BackdropType switch
|
||||||
configuration.IsInputActive = true;
|
|
||||||
SetConfigurationSourceTheme(configuration);
|
|
||||||
|
|
||||||
backdropController = new()
|
|
||||||
{
|
{
|
||||||
// Mica Alt
|
BackdropType.Acrylic => new DesktopAcrylicController(),
|
||||||
Kind = MicaKind.BaseAlt,
|
BackdropType.Mica => new MicaController() { Kind = MicaKind.Base },
|
||||||
|
BackdropType.MicaAlt => new MicaController() { Kind = MicaKind.BaseAlt },
|
||||||
|
_ => throw Must.NeverHappen(),
|
||||||
};
|
};
|
||||||
|
|
||||||
backdropController.AddSystemBackdropTarget(window.As<ICompositionSupportsSystemBackdrop>());
|
backdropController.AddSystemBackdropTarget(window.As<ICompositionSupportsSystemBackdrop>());
|
||||||
backdropController.SetSystemBackdropConfiguration(configuration);
|
backdropController.SetSystemBackdropConfiguration(configuration);
|
||||||
|
|
||||||
@@ -69,7 +103,7 @@ public class SystemBackdrop
|
|||||||
|
|
||||||
private void OnWindowActivated(object sender, WindowActivatedEventArgs args)
|
private void OnWindowActivated(object sender, WindowActivatedEventArgs args)
|
||||||
{
|
{
|
||||||
Must.NotNull(configuration!).IsInputActive = args.WindowActivationState != WindowActivationState.Deactivated;
|
configuration!.IsInputActive = args.WindowActivationState != WindowActivationState.Deactivated;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnWindowClosed(object sender, WindowEventArgs args)
|
private void OnWindowClosed(object sender, WindowEventArgs args)
|
||||||
|
|||||||
@@ -52,9 +52,10 @@ internal class WindowSubclassManager<TWindow> : IDisposable
|
|||||||
|
|
||||||
bool titleBarHooked = true;
|
bool titleBarHooked = true;
|
||||||
|
|
||||||
// only hook up drag bar proc when use legacy Window.ExtendsContentIntoTitleBar
|
// only hook up drag bar proc when not use legacy Window.ExtendsContentIntoTitleBar
|
||||||
if (isLegacyDragBar)
|
if (isLegacyDragBar)
|
||||||
{
|
{
|
||||||
|
titleBarHooked = false;
|
||||||
hwndDragBar = FindWindowEx(hwnd, default, "DRAG_BAR_WINDOW_CLASS", string.Empty);
|
hwndDragBar = FindWindowEx(hwnd, default, "DRAG_BAR_WINDOW_CLASS", string.Empty);
|
||||||
|
|
||||||
if (!hwndDragBar.IsNull)
|
if (!hwndDragBar.IsNull)
|
||||||
@@ -90,6 +91,12 @@ internal class WindowSubclassManager<TWindow> : IDisposable
|
|||||||
window.ProcessMinMaxInfo((MINMAXINFO*)lParam.Value, scalingFactor);
|
window.ProcessMinMaxInfo((MINMAXINFO*)lParam.Value, scalingFactor);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case WM_NCRBUTTONDOWN:
|
||||||
|
case WM_NCRBUTTONUP:
|
||||||
|
{
|
||||||
|
return new(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return DefSubclassProc(hwnd, uMsg, wParam, lParam);
|
return DefSubclassProc(hwnd, uMsg, wParam, lParam);
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Extension;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <see cref="Collection{T}"/> 部分
|
||||||
|
/// </summary>
|
||||||
|
public static partial class EnumerableExtension
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 移除集合中满足条件的项
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">集合项类型</typeparam>
|
||||||
|
/// <param name="collection">集合</param>
|
||||||
|
/// <param name="shouldRemovePredicate">是否应当移除</param>
|
||||||
|
/// <returns>移除的个数</returns>
|
||||||
|
public static int RemoveWhere<T>(this Collection<T> collection, Func<T, bool> shouldRemovePredicate)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
foreach (T item in collection.ToList())
|
||||||
|
{
|
||||||
|
if (shouldRemovePredicate.Invoke(item))
|
||||||
|
{
|
||||||
|
collection.Remove(item);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Extension;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <see cref="Dictionary{TKey, TValue}"/> 部分
|
||||||
|
/// </summary>
|
||||||
|
public static partial class EnumerableExtension
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 获取值或默认值
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TKey">键类型</typeparam>
|
||||||
|
/// <typeparam name="TValue">值类型</typeparam>
|
||||||
|
/// <param name="dictionary">字典</param>
|
||||||
|
/// <param name="key">键</param>
|
||||||
|
/// <param name="defaultValue">默认值</param>
|
||||||
|
/// <returns>结果值</returns>
|
||||||
|
public static TValue? GetValueOrDefault2<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, TValue? defaultValue = default)
|
||||||
|
where TKey : notnull
|
||||||
|
{
|
||||||
|
if (dictionary.TryGetValue(key, out TValue? value))
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 增加计数
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TKey">键类型</typeparam>
|
||||||
|
/// <param name="dict">字典</param>
|
||||||
|
/// <param name="key">键</param>
|
||||||
|
public static void Increase<TKey>(this Dictionary<TKey, int> dict, TKey key)
|
||||||
|
where TKey : notnull
|
||||||
|
{
|
||||||
|
++CollectionsMarshal.GetValueRefOrAddDefault(dict, key, out _);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 增加计数
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TKey">键类型</typeparam>
|
||||||
|
/// <param name="dict">字典</param>
|
||||||
|
/// <param name="key">键</param>
|
||||||
|
/// <param name="value">增加的值</param>
|
||||||
|
public static void Increase<TKey>(this Dictionary<TKey, int> dict, TKey key, int value)
|
||||||
|
where TKey : notnull
|
||||||
|
{
|
||||||
|
// ref the value, so that we can manipulate it outside the dict.
|
||||||
|
ref int current = ref CollectionsMarshal.GetValueRefOrAddDefault(dict, key, out _);
|
||||||
|
current += value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 增加计数
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TKey">键类型</typeparam>
|
||||||
|
/// <param name="dict">字典</param>
|
||||||
|
/// <param name="key">键</param>
|
||||||
|
/// <returns>是否存在键值</returns>
|
||||||
|
public static bool TryIncrease<TKey>(this Dictionary<TKey, int> dict, TKey key)
|
||||||
|
where TKey : notnull
|
||||||
|
{
|
||||||
|
ref int value = ref CollectionsMarshal.GetValueRefOrNullRef(dict, key);
|
||||||
|
if (!Unsafe.IsNullRef(ref value))
|
||||||
|
{
|
||||||
|
++value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Extension;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <see cref="List{T}"/> 部分
|
||||||
|
/// </summary>
|
||||||
|
public static partial class EnumerableExtension
|
||||||
|
{
|
||||||
|
/// <inheritdoc cref="Enumerable.Average(IEnumerable{int})"/>
|
||||||
|
public static double AverageNoThrow(this List<int> source)
|
||||||
|
{
|
||||||
|
Span<int> span = CollectionsMarshal.AsSpan(source);
|
||||||
|
|
||||||
|
if (span.IsEmpty)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
long sum = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < span.Length; i++)
|
||||||
|
{
|
||||||
|
sum += span[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return (double)sum / span.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 如果传入列表不为空则原路返回,
|
||||||
|
/// 如果传入列表为空返回一个空的列表
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TSource">源类型</typeparam>
|
||||||
|
/// <param name="source">源</param>
|
||||||
|
/// <returns>源列表或空列表</returns>
|
||||||
|
public static List<TSource> EmptyIfNull<TSource>(this List<TSource>? source)
|
||||||
|
{
|
||||||
|
return source ?? new();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 移除表中首个满足条件的项
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">项的类型</typeparam>
|
||||||
|
/// <param name="list">表</param>
|
||||||
|
/// <param name="shouldRemovePredicate">是否应当移除</param>
|
||||||
|
/// <returns>是否移除了元素</returns>
|
||||||
|
public static bool RemoveFirstWhere<T>(this IList<T> list, Func<T, bool> shouldRemovePredicate)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < list.Count; i++)
|
||||||
|
{
|
||||||
|
if (shouldRemovePredicate.Invoke(list[i]))
|
||||||
|
{
|
||||||
|
list.RemoveAt(i);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,6 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Extension;
|
namespace Snap.Hutao.Extension;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -11,26 +8,6 @@ namespace Snap.Hutao.Extension;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static partial class EnumerableExtension
|
public static partial class EnumerableExtension
|
||||||
{
|
{
|
||||||
/// <inheritdoc cref="Enumerable.Average(IEnumerable{int})"/>
|
|
||||||
public static double AverageNoThrow(this List<int> source)
|
|
||||||
{
|
|
||||||
Span<int> span = CollectionsMarshal.AsSpan(source);
|
|
||||||
|
|
||||||
if (span.IsEmpty)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
long sum = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < span.Length; i++)
|
|
||||||
{
|
|
||||||
sum += span[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return (double)sum / span.Length;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 计数
|
/// 计数
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -63,18 +40,6 @@ public static partial class EnumerableExtension
|
|||||||
return source ?? Enumerable.Empty<TSource>();
|
return source ?? Enumerable.Empty<TSource>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 如果传入列表不为空则原路返回,
|
|
||||||
/// 如果传入列表为空返回一个空的列表
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TSource">源类型</typeparam>
|
|
||||||
/// <param name="source">源</param>
|
|
||||||
/// <returns>源列表或空列表</returns>
|
|
||||||
public static List<TSource> EmptyIfNull<TSource>(this List<TSource>? source)
|
|
||||||
{
|
|
||||||
return source ?? new();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 将源转换为仅包含单个元素的枚举
|
/// 将源转换为仅包含单个元素的枚举
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -99,94 +64,6 @@ public static partial class EnumerableExtension
|
|||||||
return source.FirstOrDefault(predicate) ?? source.FirstOrDefault();
|
return source.FirstOrDefault(predicate) ?? source.FirstOrDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取值或默认值
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TKey">键类型</typeparam>
|
|
||||||
/// <typeparam name="TValue">值类型</typeparam>
|
|
||||||
/// <param name="dictionary">字典</param>
|
|
||||||
/// <param name="key">键</param>
|
|
||||||
/// <param name="defaultValue">默认值</param>
|
|
||||||
/// <returns>结果值</returns>
|
|
||||||
public static TValue? GetValueOrDefault2<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, TValue? defaultValue = default)
|
|
||||||
where TKey : notnull
|
|
||||||
{
|
|
||||||
if (dictionary.TryGetValue(key, out TValue? value))
|
|
||||||
{
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 增加计数
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TKey">键类型</typeparam>
|
|
||||||
/// <param name="dict">字典</param>
|
|
||||||
/// <param name="key">键</param>
|
|
||||||
public static void Increase<TKey>(this Dictionary<TKey, int> dict, TKey key)
|
|
||||||
where TKey : notnull
|
|
||||||
{
|
|
||||||
++CollectionsMarshal.GetValueRefOrAddDefault(dict, key, out _);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 增加计数
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TKey">键类型</typeparam>
|
|
||||||
/// <param name="dict">字典</param>
|
|
||||||
/// <param name="key">键</param>
|
|
||||||
/// <param name="value">增加的值</param>
|
|
||||||
public static void Increase<TKey>(this Dictionary<TKey, int> dict, TKey key, int value)
|
|
||||||
where TKey : notnull
|
|
||||||
{
|
|
||||||
// ref the value, so that we can manipulate it outside the dict.
|
|
||||||
ref int current = ref CollectionsMarshal.GetValueRefOrAddDefault(dict, key, out _);
|
|
||||||
current += value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 增加计数
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TKey">键类型</typeparam>
|
|
||||||
/// <param name="dict">字典</param>
|
|
||||||
/// <param name="key">键</param>
|
|
||||||
/// <returns>是否存在键值</returns>
|
|
||||||
public static bool TryIncrease<TKey>(this Dictionary<TKey, int> dict, TKey key)
|
|
||||||
where TKey : notnull
|
|
||||||
{
|
|
||||||
ref int value = ref CollectionsMarshal.GetValueRefOrNullRef(dict, key);
|
|
||||||
if (!Unsafe.IsNullRef(ref value))
|
|
||||||
{
|
|
||||||
++value;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 移除表中首个满足条件的项
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">项的类型</typeparam>
|
|
||||||
/// <param name="list">表</param>
|
|
||||||
/// <param name="shouldRemovePredicate">是否应当移除</param>
|
|
||||||
/// <returns>是否移除了元素</returns>
|
|
||||||
public static bool RemoveFirstWhere<T>(this IList<T> list, Func<T, bool> shouldRemovePredicate)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < list.Count; i++)
|
|
||||||
{
|
|
||||||
if (shouldRemovePredicate.Invoke(list[i]))
|
|
||||||
{
|
|
||||||
list.RemoveAt(i);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="Enumerable.ToDictionary{TSource, TKey}(IEnumerable{TSource}, Func{TSource, TKey})"/>
|
/// <inheritdoc cref="Enumerable.ToDictionary{TSource, TKey}(IEnumerable{TSource}, Func{TSource, TKey})"/>
|
||||||
public static Dictionary<TKey, TSource> ToDictionaryOverride<TKey, TSource>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
|
public static Dictionary<TKey, TSource> ToDictionaryOverride<TKey, TSource>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
|
||||||
where TKey : notnull
|
where TKey : notnull
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Extension;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <see cref="StringBuilder"/> 扩展方法
|
||||||
|
/// </summary>
|
||||||
|
public static class StringBuilderExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 当条件符合时执行 <see cref="StringBuilder.Append(string?)"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sb">字符串建造器</param>
|
||||||
|
/// <param name="condition">条件</param>
|
||||||
|
/// <param name="value">附加的字符串</param>
|
||||||
|
/// <returns>同一个字符串建造器</returns>
|
||||||
|
public static StringBuilder AppendIf(this StringBuilder sb, bool condition, string? value)
|
||||||
|
{
|
||||||
|
return condition ? sb.Append(value) : sb;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -35,6 +35,7 @@ public sealed partial class LaunchGameWindow : Window, IDisposable, IExtendedWin
|
|||||||
|
|
||||||
scope = scopeFactory.CreateScope();
|
scope = scopeFactory.CreateScope();
|
||||||
RootGrid.DataContext = scope.ServiceProvider.GetRequiredService<LaunchGameViewModel>();
|
RootGrid.DataContext = scope.ServiceProvider.GetRequiredService<LaunchGameViewModel>();
|
||||||
|
Closed += (s, e) => Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Core.Windowing;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Message;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 背景类型改变消息
|
||||||
|
/// </summary>
|
||||||
|
internal class BackdropTypeChangedMessage
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 构造一个新的背景类型改变消息
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="backdropType">背景类型</param>
|
||||||
|
public BackdropTypeChangedMessage(BackdropType backdropType)
|
||||||
|
{
|
||||||
|
BackdropType = backdropType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 背景类型
|
||||||
|
/// </summary>
|
||||||
|
public BackdropType BackdropType { get; set; }
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using Snap.Hutao.Model.Binding;
|
using Snap.Hutao.Model.Binding.User;
|
||||||
|
|
||||||
namespace Snap.Hutao.Message;
|
namespace Snap.Hutao.Message;
|
||||||
|
|
||||||
|
|||||||
282
src/Snap.Hutao/Snap.Hutao/Migrations/20221108081525_DailyNoteEntry.Designer.cs
generated
Normal file
282
src/Snap.Hutao/Snap.Hutao/Migrations/20221108081525_DailyNoteEntry.Designer.cs
generated
Normal file
@@ -0,0 +1,282 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using Snap.Hutao.Context.Database;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(AppDbContext))]
|
||||||
|
[Migration("20221108081525_DailyNoteEntry")]
|
||||||
|
partial class DailyNoteEntry
|
||||||
|
{
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder.HasAnnotation("ProductVersion", "6.0.10");
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.Achievement", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("InnerId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid>("ArchiveId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Current")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Status")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Time")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
|
b.HasIndex("ArchiveId");
|
||||||
|
|
||||||
|
b.ToTable("achievements");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.AchievementArchive", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("InnerId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("IsSelected")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
|
b.ToTable("achievement_archives");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.AvatarInfo", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("InnerId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Info")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Uid")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
|
b.ToTable("avatar_infos");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.DailyNoteEntry", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("InnerId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("DailyNote")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("DailyTaskNotify")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("DailyTaskNotifySuppressed")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("ExpeditionNotify")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("ExpeditionNotifySuppressed")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("HomeCoinNotifySuppressed")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("HomeCoinNotifyThreshold")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("ResinNotifySuppressed")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("ResinNotifyThreshold")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("ShowInHomeWidget")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("TransformerNotify")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("TransformerNotifySuppressed")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Uid")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("daily_notes");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.GachaArchive", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("InnerId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("IsSelected")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Uid")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
|
b.ToTable("gacha_archives");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.GachaItem", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("InnerId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid>("ArchiveId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("GachaType")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("ItemId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("QueryType")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Time")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
|
b.HasIndex("ArchiveId");
|
||||||
|
|
||||||
|
b.ToTable("gacha_items");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.GameAccount", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("InnerId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("AttachUid")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("MihoyoSDK")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Type")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
|
b.ToTable("game_accounts");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.SettingEntry", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Key")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Value")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Key");
|
||||||
|
|
||||||
|
b.ToTable("settings");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.User", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("InnerId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Cookie")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("IsSelected")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
|
b.ToTable("users");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.Achievement", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Snap.Hutao.Model.Entity.AchievementArchive", "Archive")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ArchiveId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Archive");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.DailyNoteEntry", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Snap.Hutao.Model.Entity.User", "User")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.GachaItem", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Snap.Hutao.Model.Entity.GachaArchive", "Archive")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ArchiveId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Archive");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Migrations
|
||||||
|
{
|
||||||
|
public partial class DailyNoteEntry : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "daily_notes",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
InnerId = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||||
|
UserId = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||||
|
Uid = table.Column<string>(type: "TEXT", nullable: false),
|
||||||
|
DailyNote = table.Column<string>(type: "TEXT", nullable: true),
|
||||||
|
ResinNotifyThreshold = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
ResinNotifySuppressed = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||||
|
HomeCoinNotifyThreshold = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
HomeCoinNotifySuppressed = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||||
|
TransformerNotify = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||||
|
TransformerNotifySuppressed = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||||
|
DailyTaskNotify = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||||
|
DailyTaskNotifySuppressed = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||||
|
ExpeditionNotify = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||||
|
ExpeditionNotifySuppressed = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||||
|
ShowInHomeWidget = table.Column<bool>(type: "INTEGER", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_daily_notes", x => x.InnerId);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_daily_notes_users_UserId",
|
||||||
|
column: x => x.UserId,
|
||||||
|
principalTable: "users",
|
||||||
|
principalColumn: "InnerId",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_daily_notes_UserId",
|
||||||
|
table: "daily_notes",
|
||||||
|
column: "UserId");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "daily_notes");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -82,6 +82,62 @@ namespace Snap.Hutao.Migrations
|
|||||||
b.ToTable("avatar_infos");
|
b.ToTable("avatar_infos");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.DailyNoteEntry", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("InnerId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("DailyNote")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("DailyTaskNotify")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("DailyTaskNotifySuppressed")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("ExpeditionNotify")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("ExpeditionNotifySuppressed")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("HomeCoinNotifySuppressed")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("HomeCoinNotifyThreshold")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("ResinNotifySuppressed")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("ResinNotifyThreshold")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("ShowInHomeWidget")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("TransformerNotify")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("TransformerNotifySuppressed")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Uid")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("daily_notes");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.GachaArchive", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.GachaArchive", b =>
|
||||||
{
|
{
|
||||||
b.Property<Guid>("InnerId")
|
b.Property<Guid>("InnerId")
|
||||||
@@ -197,6 +253,17 @@ namespace Snap.Hutao.Migrations
|
|||||||
b.Navigation("Archive");
|
b.Navigation("Archive");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.DailyNoteEntry", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Snap.Hutao.Model.Entity.User", "User")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.GachaItem", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.GachaItem", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("Snap.Hutao.Model.Entity.GachaArchive", "Archive")
|
b.HasOne("Snap.Hutao.Model.Entity.GachaArchive", "Archive")
|
||||||
|
|||||||
@@ -18,11 +18,13 @@ public class LaunchScheme
|
|||||||
/// <param name="channel">通道</param>
|
/// <param name="channel">通道</param>
|
||||||
/// <param name="cps">通道描述字符串</param>
|
/// <param name="cps">通道描述字符串</param>
|
||||||
/// <param name="subChannel">子通道</param>
|
/// <param name="subChannel">子通道</param>
|
||||||
public LaunchScheme(string name, string channel, string subChannel)
|
/// <param name="launcherId">启动器Id</param>
|
||||||
|
public LaunchScheme(string name, string channel, string subChannel, string launcherId)
|
||||||
{
|
{
|
||||||
Name = name;
|
Name = name;
|
||||||
Channel = channel;
|
Channel = channel;
|
||||||
SubChannel = subChannel;
|
SubChannel = subChannel;
|
||||||
|
LauncherId = launcherId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -39,4 +41,9 @@ public class LaunchScheme
|
|||||||
/// 子通道
|
/// 子通道
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string SubChannel { get; set; }
|
public string SubChannel { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 启动器Id
|
||||||
|
/// </summary>
|
||||||
|
public string LauncherId { get; set; }
|
||||||
}
|
}
|
||||||
@@ -8,7 +8,7 @@ using Snap.Hutao.Web.Hoyolab.Bbs.User;
|
|||||||
using Snap.Hutao.Web.Hoyolab.Takumi.Binding;
|
using Snap.Hutao.Web.Hoyolab.Takumi.Binding;
|
||||||
using EntityUser = Snap.Hutao.Model.Entity.User;
|
using EntityUser = Snap.Hutao.Model.Entity.User;
|
||||||
|
|
||||||
namespace Snap.Hutao.Model.Binding;
|
namespace Snap.Hutao.Model.Binding.User;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 用于视图绑定的用户
|
/// 用于视图绑定的用户
|
||||||
34
src/Snap.Hutao/Snap.Hutao/Model/Binding/User/UserAndRole.cs
Normal file
34
src/Snap.Hutao/Snap.Hutao/Model/Binding/User/UserAndRole.cs
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Web.Hoyolab.Takumi.Binding;
|
||||||
|
using EntityUser = Snap.Hutao.Model.Entity.User;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Model.Binding.User;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 角色与实体用户
|
||||||
|
/// </summary>
|
||||||
|
public class UserAndRole
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 构造一个新的实体用户与角色
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="user">实体用户</param>
|
||||||
|
/// <param name="role">角色</param>
|
||||||
|
public UserAndRole(EntityUser user, UserGameRole role)
|
||||||
|
{
|
||||||
|
User = user;
|
||||||
|
Role = role;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 实体用户
|
||||||
|
/// </summary>
|
||||||
|
public EntityUser User { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 角色
|
||||||
|
/// </summary>
|
||||||
|
public UserGameRole Role { get; private set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Model.Entity.Configuration;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 实时便笺入口配置
|
||||||
|
/// </summary>
|
||||||
|
internal class DailyNoteEntryConfiguration : IEntityTypeConfiguration<DailyNoteEntry>
|
||||||
|
{
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public void Configure(EntityTypeBuilder<DailyNoteEntry> builder)
|
||||||
|
{
|
||||||
|
builder.Property(e => e.DailyNote)
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasConversion<JsonTextValueConverter<Web.Hoyolab.Takumi.GameRecord.DailyNote.DailyNote>>();
|
||||||
|
}
|
||||||
|
}
|
||||||
98
src/Snap.Hutao/Snap.Hutao/Model/Entity/DailyNoteEntry.cs
Normal file
98
src/Snap.Hutao/Snap.Hutao/Model/Entity/DailyNoteEntry.cs
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.DailyNote;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Model.Entity;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 实时便笺入口
|
||||||
|
/// </summary>
|
||||||
|
[Table("daily_notes")]
|
||||||
|
public class DailyNoteEntry
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 内部Id
|
||||||
|
/// </summary>
|
||||||
|
[Key]
|
||||||
|
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||||
|
public Guid InnerId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 用户Id
|
||||||
|
/// </summary>
|
||||||
|
[ForeignKey(nameof(UserId))]
|
||||||
|
public Guid UserId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 用户
|
||||||
|
/// </summary>
|
||||||
|
public User User { get; set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Uid
|
||||||
|
/// </summary>
|
||||||
|
public string Uid { get; set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Json!!! 实时便笺
|
||||||
|
/// </summary>
|
||||||
|
public DailyNote? DailyNote { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 树脂提醒阈值
|
||||||
|
/// </summary>
|
||||||
|
public int ResinNotifyThreshold { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 用于判断树脂是否继续提醒
|
||||||
|
/// </summary>
|
||||||
|
public bool ResinNotifySuppressed { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 洞天宝钱提醒阈值
|
||||||
|
/// </summary>
|
||||||
|
public int HomeCoinNotifyThreshold { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 用于判断洞天宝钱是否继续提醒
|
||||||
|
/// </summary>
|
||||||
|
public bool HomeCoinNotifySuppressed { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 参量质变仪提醒
|
||||||
|
/// </summary>
|
||||||
|
public bool TransformerNotify { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 用于判断参量质变仪是否继续提醒
|
||||||
|
/// </summary>
|
||||||
|
public bool TransformerNotifySuppressed { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 每日委托提醒
|
||||||
|
/// </summary>
|
||||||
|
public bool DailyTaskNotify { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 用于判断每日委托是否继续提醒
|
||||||
|
/// </summary>
|
||||||
|
public bool DailyTaskNotifySuppressed { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 探索派遣提醒
|
||||||
|
/// </summary>
|
||||||
|
public bool ExpeditionNotify { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 用于判断探索派遣是否继续提醒
|
||||||
|
/// </summary>
|
||||||
|
public bool ExpeditionNotifySuppressed { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否在主页显示小组件
|
||||||
|
/// </summary>
|
||||||
|
public bool ShowInHomeWidget { get; set; }
|
||||||
|
}
|
||||||
@@ -26,6 +26,7 @@ public class GachaItem
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 存档
|
/// 存档
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[ForeignKey(nameof(ArchiveId))]
|
||||||
public GachaArchive Archive { get; set; } = default!;
|
public GachaArchive Archive { get; set; } = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -22,6 +22,11 @@ public class SettingEntry
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public const string IsEmptyHistoryWishVisible = "IsEmptyHistoryWishVisible";
|
public const string IsEmptyHistoryWishVisible = "IsEmptyHistoryWishVisible";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 窗口背景类型
|
||||||
|
/// </summary>
|
||||||
|
public const string SystemBackdropType = "SystemBackdropType";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 启动游戏 全屏
|
/// 启动游戏 全屏
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -43,11 +43,6 @@ public class Achievement
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public int Progress { get; set; }
|
public int Progress { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 触发器
|
|
||||||
/// </summary>
|
|
||||||
public IEnumerable<AchievementTrigger>? Triggers { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 图标
|
/// 图标
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Model.Metadata.Achievement;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 成就触发器
|
|
||||||
/// </summary>
|
|
||||||
public class AchievementTrigger
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 触发器类型
|
|
||||||
/// </summary>
|
|
||||||
public AchievementTriggerType Type { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Id
|
|
||||||
/// </summary>
|
|
||||||
public string Id { get; set; } = default!;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 标题
|
|
||||||
/// </summary>
|
|
||||||
public string Title { get; set; } = default!;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 描述
|
|
||||||
/// </summary>
|
|
||||||
public string Description { get; set; } = default!;
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Snap.Hutao.Context.Database;
|
||||||
|
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Service.DailyNote;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 实时便笺服务
|
||||||
|
/// </summary>
|
||||||
|
[Injection(InjectAs.Singleton)]
|
||||||
|
internal class DailyNoteService
|
||||||
|
{
|
||||||
|
private readonly AppDbContext appDbContext;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 构造一个新的实时便笺服务
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="appDbContext">数据库上下文</param>
|
||||||
|
public DailyNoteService(AppDbContext appDbContext)
|
||||||
|
{
|
||||||
|
this.appDbContext = appDbContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask RefreshDailyNotesAndNotifyAsync()
|
||||||
|
{
|
||||||
|
GameRecordClient gameRecordClient = Ioc.Default.GetRequiredService<GameRecordClient>();
|
||||||
|
|
||||||
|
foreach (Model.Entity.DailyNoteEntry entry in appDbContext.DailyNotes.Include(n => n.User))
|
||||||
|
{
|
||||||
|
entry.DailyNote = await gameRecordClient.GetDialyNoteAsync(entry.User, entry.Uid).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
await appDbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private async ValueTask NotifyDailyNoteAsync()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -35,7 +35,7 @@ internal class GachaLogUrlStokenProvider : IGachaLogUrlProvider
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public async Task<ValueResult<bool, string>> GetQueryAsync()
|
public async Task<ValueResult<bool, string>> GetQueryAsync()
|
||||||
{
|
{
|
||||||
Model.Binding.User? user = userService.Current;
|
Model.Binding.User.User? user = userService.Current;
|
||||||
if (user != null && user.SelectedUserGameRole != null)
|
if (user != null && user.SelectedUserGameRole != null)
|
||||||
{
|
{
|
||||||
if (user.Cookie!.ContainsSToken())
|
if (user.Cookie!.ContainsSToken())
|
||||||
|
|||||||
@@ -168,27 +168,40 @@ internal class GameService : IGameService
|
|||||||
elements = IniSerializer.Deserialize(readStream).ToList();
|
elements = IniSerializer.Deserialize(readStream).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool changed = false;
|
||||||
|
|
||||||
foreach (IniElement element in elements)
|
foreach (IniElement element in elements)
|
||||||
{
|
{
|
||||||
if (element is IniParameter parameter)
|
if (element is IniParameter parameter)
|
||||||
{
|
{
|
||||||
if (parameter.Key == "channel")
|
if (parameter.Key == "channel")
|
||||||
|
{
|
||||||
|
if (parameter.Value != scheme.Channel)
|
||||||
{
|
{
|
||||||
parameter.Value = scheme.Channel;
|
parameter.Value = scheme.Channel;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parameter.Key == "sub_channel")
|
if (parameter.Key == "sub_channel")
|
||||||
|
{
|
||||||
|
if (parameter.Value != scheme.SubChannel)
|
||||||
{
|
{
|
||||||
parameter.Value = scheme.SubChannel;
|
parameter.Value = scheme.SubChannel;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (changed)
|
||||||
|
{
|
||||||
using (FileStream writeStream = File.Create(configPath))
|
using (FileStream writeStream = File.Create(configPath))
|
||||||
{
|
{
|
||||||
IniSerializer.Serialize(writeStream, elements);
|
IniSerializer.Serialize(writeStream, elements);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public bool IsGameRunning()
|
public bool IsGameRunning()
|
||||||
@@ -340,6 +353,7 @@ internal class GameService : IGameService
|
|||||||
|
|
||||||
if (isOk)
|
if (isOk)
|
||||||
{
|
{
|
||||||
|
await ThreadHelper.SwitchToMainThreadAsync();
|
||||||
gameAccount.UpdateName(name);
|
gameAccount.UpdateName(name);
|
||||||
|
|
||||||
// sync database
|
// sync database
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ internal class ManualGameLocator : IGameLocator
|
|||||||
{
|
{
|
||||||
FileOpenPicker picker = pickerFactory.GetFileOpenPicker();
|
FileOpenPicker picker = pickerFactory.GetFileOpenPicker();
|
||||||
picker.FileTypeFilter.Add(".exe");
|
picker.FileTypeFilter.Add(".exe");
|
||||||
picker.SuggestedStartLocation = PickerLocationId.ComputerFolder;
|
picker.SuggestedStartLocation = PickerLocationId.Desktop;
|
||||||
|
|
||||||
// System.Runtime.InteropServices.COMException (0x80004005): Error HRESULT E_FAIL has been returned from a call to a COM component.
|
// System.Runtime.InteropServices.COMException (0x80004005): Error HRESULT E_FAIL has been returned from a call to a COM component.
|
||||||
// Not sure what's going on here.
|
// Not sure what's going on here.
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using Microsoft.UI.Xaml.Controls;
|
using Microsoft.UI.Xaml.Controls;
|
||||||
using Snap.Hutao.Core.Threading;
|
|
||||||
using Snap.Hutao.Service.Abstraction;
|
using Snap.Hutao.Service.Abstraction;
|
||||||
|
|
||||||
namespace Snap.Hutao.Service;
|
namespace Snap.Hutao.Service;
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using Snap.Hutao.Core.Threading;
|
|
||||||
using Snap.Hutao.Web.Hoyolab;
|
using Snap.Hutao.Web.Hoyolab;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using BindingUser = Snap.Hutao.Model.Binding.User;
|
using BindingUser = Snap.Hutao.Model.Binding.User.User;
|
||||||
|
|
||||||
namespace Snap.Hutao.Service.User;
|
namespace Snap.Hutao.Service.User;
|
||||||
|
|
||||||
@@ -18,6 +17,12 @@ public interface IUserService
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
BindingUser? Current { get; set; }
|
BindingUser? Current { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步获取角色与用户集合
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>角色与用户集合</returns>
|
||||||
|
Task<ObservableCollection<Model.Binding.User.UserAndRole>> GetRoleCollectionAsync();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 初始化用户服务及所有用户
|
/// 初始化用户服务及所有用户
|
||||||
/// 异步获取同步的用户信息集合
|
/// 异步获取同步的用户信息集合
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using BindingUser = Snap.Hutao.Model.Binding.User;
|
using BindingUser = Snap.Hutao.Model.Binding.User.User;
|
||||||
|
|
||||||
namespace Snap.Hutao.Service.User;
|
namespace Snap.Hutao.Service.User;
|
||||||
|
|
||||||
|
|||||||
@@ -5,13 +5,12 @@ using CommunityToolkit.Mvvm.Messaging;
|
|||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Snap.Hutao.Context.Database;
|
using Snap.Hutao.Context.Database;
|
||||||
using Snap.Hutao.Core.Database;
|
using Snap.Hutao.Core.Database;
|
||||||
using Snap.Hutao.Core.Threading;
|
using Snap.Hutao.Extension;
|
||||||
using Snap.Hutao.Web.Hoyolab;
|
using Snap.Hutao.Web.Hoyolab;
|
||||||
using Snap.Hutao.Web.Hoyolab.Bbs.User;
|
using Snap.Hutao.Web.Hoyolab.Bbs.User;
|
||||||
using Snap.Hutao.Web.Hoyolab.Takumi.Auth;
|
|
||||||
using Snap.Hutao.Web.Hoyolab.Takumi.Binding;
|
using Snap.Hutao.Web.Hoyolab.Takumi.Binding;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using BindingUser = Snap.Hutao.Model.Binding.User;
|
using BindingUser = Snap.Hutao.Model.Binding.User.User;
|
||||||
|
|
||||||
namespace Snap.Hutao.Service.User;
|
namespace Snap.Hutao.Service.User;
|
||||||
|
|
||||||
@@ -27,6 +26,7 @@ internal class UserService : IUserService
|
|||||||
|
|
||||||
private BindingUser? currentUser;
|
private BindingUser? currentUser;
|
||||||
private ObservableCollection<BindingUser>? userCollection;
|
private ObservableCollection<BindingUser>? userCollection;
|
||||||
|
private ObservableCollection<Model.Binding.User.UserAndRole>? roleCollection;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 构造一个新的用户服务
|
/// 构造一个新的用户服务
|
||||||
@@ -86,15 +86,17 @@ internal class UserService : IUserService
|
|||||||
public async Task RemoveUserAsync(BindingUser user)
|
public async Task RemoveUserAsync(BindingUser user)
|
||||||
{
|
{
|
||||||
await Task.Yield();
|
await Task.Yield();
|
||||||
Must.NotNull(userCollection!);
|
|
||||||
|
|
||||||
// Sync cache
|
// Sync cache
|
||||||
userCollection.Remove(user);
|
userCollection!.Remove(user);
|
||||||
|
roleCollection!.RemoveWhere(r => r.User.InnerId == user.Entity.InnerId);
|
||||||
|
|
||||||
// Sync database
|
// Sync database
|
||||||
using (IServiceScope scope = scopeFactory.CreateScope())
|
using (IServiceScope scope = scopeFactory.CreateScope())
|
||||||
{
|
{
|
||||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||||
|
|
||||||
|
// Note: cascade deleted dailynotes
|
||||||
appDbContext.Users.RemoveAndSave(user.Entity);
|
appDbContext.Users.RemoveAndSave(user.Entity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -137,6 +139,27 @@ internal class UserService : IUserService
|
|||||||
return userCollection;
|
return userCollection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public async Task<ObservableCollection<Model.Binding.User.UserAndRole>> GetRoleCollectionAsync()
|
||||||
|
{
|
||||||
|
if (roleCollection == null)
|
||||||
|
{
|
||||||
|
List<Model.Binding.User.UserAndRole> userAndRoles = new();
|
||||||
|
ObservableCollection<BindingUser> observableUsers = await GetUserCollectionAsync().ConfigureAwait(false);
|
||||||
|
foreach (BindingUser user in observableUsers.ToList())
|
||||||
|
{
|
||||||
|
foreach (UserGameRole role in user.UserGameRoles)
|
||||||
|
{
|
||||||
|
userAndRoles.Add(new(user.Entity, role));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
roleCollection = new(userAndRoles);
|
||||||
|
}
|
||||||
|
|
||||||
|
return roleCollection;
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public async Task<ValueResult<UserOptionResult, string>> ProcessInputCookieAsync(Cookie cookie)
|
public async Task<ValueResult<UserOptionResult, string>> ProcessInputCookieAsync(Cookie cookie)
|
||||||
{
|
{
|
||||||
@@ -148,7 +171,7 @@ internal class UserService : IUserService
|
|||||||
{
|
{
|
||||||
// 检查 login ticket 是否存在
|
// 检查 login ticket 是否存在
|
||||||
// 若存在则尝试升级至 stoken
|
// 若存在则尝试升级至 stoken
|
||||||
await TryAddMultiTokenAsync(cookie, uid).ConfigureAwait(false);
|
await cookie.TryAddMultiTokenAsync(uid).ConfigureAwait(false);
|
||||||
|
|
||||||
// 检查 uid 对应用户是否存在
|
// 检查 uid 对应用户是否存在
|
||||||
if (UserHelper.TryGetUserByUid(userCollection, uid, out BindingUser? userWithSameUid))
|
if (UserHelper.TryGetUserByUid(userCollection, uid, out BindingUser? userWithSameUid))
|
||||||
@@ -180,32 +203,14 @@ internal class UserService : IUserService
|
|||||||
}
|
}
|
||||||
else if (cookie.ContainsLTokenAndCookieToken())
|
else if (cookie.ContainsLTokenAndCookieToken())
|
||||||
{
|
{
|
||||||
return await TryCreateUserAndAddAsync(userCollection, cookie).ConfigureAwait(false);
|
return await TryCreateUserAndAddAsync(cookie).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new(UserOptionResult.Incomplete, null!);
|
return new(UserOptionResult.Incomplete, null!);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task TryAddMultiTokenAsync(Cookie cookie, string uid)
|
private async Task<ValueResult<UserOptionResult, string>> TryCreateUserAndAddAsync(Cookie cookie)
|
||||||
{
|
|
||||||
if (cookie.TryGetLoginTicket(out string? loginTicket))
|
|
||||||
{
|
|
||||||
// get multitoken
|
|
||||||
Dictionary<string, string> multiToken = await Ioc.Default
|
|
||||||
.GetRequiredService<AuthClient>()
|
|
||||||
.GetMultiTokenByLoginTicketAsync(loginTicket, uid, default)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (multiToken.Count >= 2)
|
|
||||||
{
|
|
||||||
cookie.InsertMultiToken(uid, multiToken);
|
|
||||||
cookie.RemoveLoginTicket();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<ValueResult<UserOptionResult, string>> TryCreateUserAndAddAsync(ObservableCollection<BindingUser> users, Cookie cookie)
|
|
||||||
{
|
{
|
||||||
using (IServiceScope scope = scopeFactory.CreateScope())
|
using (IServiceScope scope = scopeFactory.CreateScope())
|
||||||
{
|
{
|
||||||
@@ -217,8 +222,19 @@ internal class UserService : IUserService
|
|||||||
if (newUser != null)
|
if (newUser != null)
|
||||||
{
|
{
|
||||||
// Sync cache
|
// Sync cache
|
||||||
|
if (userCollection != null)
|
||||||
|
{
|
||||||
await ThreadHelper.SwitchToMainThreadAsync();
|
await ThreadHelper.SwitchToMainThreadAsync();
|
||||||
users.Add(newUser);
|
userCollection!.Add(newUser);
|
||||||
|
|
||||||
|
if (roleCollection != null)
|
||||||
|
{
|
||||||
|
foreach (UserGameRole role in newUser.UserGameRoles)
|
||||||
|
{
|
||||||
|
roleCollection.Add(new(newUser.Entity, role));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Sync database
|
// Sync database
|
||||||
appDbContext.Users.AddAndSave(newUser.Entity);
|
appDbContext.Users.AddAndSave(newUser.Entity);
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||||
<DebugSymbols>true</DebugSymbols>
|
<DebugSymbols>true</DebugSymbols>
|
||||||
<DebugType>embedded</DebugType>
|
<DebugType>embedded</DebugType>
|
||||||
|
<ApplicationIcon>Assets\Logo.ico</ApplicationIcon>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -115,28 +116,31 @@
|
|||||||
<PackageReference Include="CommunityToolkit.WinUI.Notifications" Version="7.1.2" />
|
<PackageReference Include="CommunityToolkit.WinUI.Notifications" Version="7.1.2" />
|
||||||
<PackageReference Include="CommunityToolkit.WinUI.UI.Behaviors" Version="7.1.2" />
|
<PackageReference Include="CommunityToolkit.WinUI.UI.Behaviors" Version="7.1.2" />
|
||||||
<PackageReference Include="CommunityToolkit.WinUI.UI.Controls" Version="7.1.2" />
|
<PackageReference Include="CommunityToolkit.WinUI.UI.Controls" Version="7.1.2" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.10" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.0" />
|
||||||
<!-- The PrivateAssets & IncludeAssets of Microsoft.EntityFrameworkCore.Tools should be remove to prevent multiple deps files-->
|
<!-- The PrivateAssets & IncludeAssets of Microsoft.EntityFrameworkCore.Tools should be remove to prevent multiple deps files-->
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.10" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.0">
|
||||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="6.0.1" />
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="6.0.0" />
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" Version="17.3.44">
|
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="7.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Http" Version="7.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="7.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" Version="17.3.48">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.VisualStudio.Validation" Version="17.0.64" />
|
<PackageReference Include="Microsoft.VisualStudio.Validation" Version="17.0.64" />
|
||||||
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.2.63-beta">
|
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.2.104-beta">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.25211-preview" />
|
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.25231-preview" />
|
||||||
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.2.220930.4-preview2" />
|
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.2.220930.4-preview2" />
|
||||||
<PackageReference Include="MiniExcel" Version="1.28.0" />
|
|
||||||
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.435">
|
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.435">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
<PackageReference Include="TaskScheduler" Version="2.10.1" />
|
||||||
<Manifest Include="$(ApplicationManifest)" />
|
<Manifest Include="$(ApplicationManifest)" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -148,7 +148,7 @@
|
|||||||
BorderThickness="{ThemeResource CardBorderThickness}"
|
BorderThickness="{ThemeResource CardBorderThickness}"
|
||||||
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
|
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
|
||||||
Padding="8"
|
Padding="8"
|
||||||
Margin="0,16,0,0"
|
Margin="0,8,0,0"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
MinHeight="48">
|
MinHeight="48">
|
||||||
|
|||||||
@@ -23,21 +23,8 @@
|
|||||||
</mxi:Interaction.Behaviors>
|
</mxi:Interaction.Behaviors>
|
||||||
<shc:ScopedPage.Resources>
|
<shc:ScopedPage.Resources>
|
||||||
<shc:BindingProxy x:Key="BindingProxy" DataContext="{Binding}"/>
|
<shc:BindingProxy x:Key="BindingProxy" DataContext="{Binding}"/>
|
||||||
</shc:ScopedPage.Resources>
|
|
||||||
<Grid>
|
<DataTemplate x:Key="AnnouncementTemplate">
|
||||||
<ScrollViewer Padding="0,0,4,0">
|
|
||||||
<ItemsControl
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
ItemsSource="{Binding Announcement.List}"
|
|
||||||
Padding="0"
|
|
||||||
Margin="16,16,0,-6">
|
|
||||||
<ItemsControl.ItemTemplate>
|
|
||||||
<DataTemplate>
|
|
||||||
<StackPanel>
|
|
||||||
<TextBlock
|
|
||||||
Text="{Binding TypeLabel}"
|
|
||||||
Margin="0,0,0,12"
|
|
||||||
Style="{StaticResource TitleTextBlockStyle}"/>
|
|
||||||
<cwucont:AdaptiveGridView
|
<cwucont:AdaptiveGridView
|
||||||
cwua:ItemsReorderAnimation.Duration="0:0:0.1"
|
cwua:ItemsReorderAnimation.Duration="0:0:0.1"
|
||||||
SelectionMode="None"
|
SelectionMode="None"
|
||||||
@@ -45,7 +32,7 @@
|
|||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
ItemContainerStyle="{StaticResource LargeGridViewItemStyle}"
|
ItemContainerStyle="{StaticResource LargeGridViewItemStyle}"
|
||||||
ItemsSource="{Binding List}"
|
ItemsSource="{Binding List}"
|
||||||
Margin="0,0,2,0">
|
Margin="16,16,0,-4">
|
||||||
<cwucont:AdaptiveGridView.ItemTemplate>
|
<cwucont:AdaptiveGridView.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<Border
|
<Border
|
||||||
@@ -158,10 +145,22 @@
|
|||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</cwucont:AdaptiveGridView.ItemTemplate>
|
</cwucont:AdaptiveGridView.ItemTemplate>
|
||||||
</cwucont:AdaptiveGridView>
|
</cwucont:AdaptiveGridView>
|
||||||
</StackPanel>
|
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ItemsControl.ItemTemplate>
|
</shc:ScopedPage.Resources>
|
||||||
</ItemsControl>
|
<Grid>
|
||||||
|
<ScrollViewer Padding="0,0,4,0">
|
||||||
|
<StackPanel>
|
||||||
|
<Pivot>
|
||||||
|
<PivotItem
|
||||||
|
Header="活动公告"
|
||||||
|
Content="{Binding Announcement.List[0]}"
|
||||||
|
ContentTemplate="{StaticResource AnnouncementTemplate}"/>
|
||||||
|
<PivotItem
|
||||||
|
Header="游戏公告"
|
||||||
|
Content="{Binding Announcement.List[1]}"
|
||||||
|
ContentTemplate="{StaticResource AnnouncementTemplate}"/>
|
||||||
|
</Pivot>
|
||||||
|
</StackPanel>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</Grid>
|
</Grid>
|
||||||
</shc:ScopedPage>
|
</shc:ScopedPage>
|
||||||
@@ -4,13 +4,26 @@
|
|||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:shc="using:Snap.Hutao.Control"
|
xmlns:mxi="using:Microsoft.Xaml.Interactivity"
|
||||||
xmlns:shcm="using:Snap.Hutao.Control.Markup"
|
|
||||||
xmlns:sc="using:SettingsUI.Controls"
|
xmlns:sc="using:SettingsUI.Controls"
|
||||||
|
xmlns:shc="using:Snap.Hutao.Control"
|
||||||
|
xmlns:shcb="using:Snap.Hutao.Control.Behavior"
|
||||||
|
xmlns:shcm="using:Snap.Hutao.Control.Markup"
|
||||||
xmlns:shv="using:Snap.Hutao.ViewModel"
|
xmlns:shv="using:Snap.Hutao.ViewModel"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DataContext="{d:DesignInstance shv:DailyNoteViewModel}"
|
d:DataContext="{d:DesignInstance shv:DailyNoteViewModel}"
|
||||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||||
|
|
||||||
|
<mxi:Interaction.Behaviors>
|
||||||
|
<shcb:InvokeCommandOnLoadedBehavior Command="{Binding OpenUICommand}"/>
|
||||||
|
</mxi:Interaction.Behaviors>
|
||||||
|
|
||||||
|
<Page.Resources>
|
||||||
|
<shc:BindingProxy
|
||||||
|
x:Key="ViewModelBindingProxy"
|
||||||
|
DataContext="{Binding}"/>
|
||||||
|
</Page.Resources>
|
||||||
|
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="auto"/>
|
<RowDefinition Height="auto"/>
|
||||||
@@ -20,11 +33,62 @@
|
|||||||
<CommandBar
|
<CommandBar
|
||||||
Background="{StaticResource CardBackgroundFillColorDefaultBrush}"
|
Background="{StaticResource CardBackgroundFillColorDefaultBrush}"
|
||||||
DefaultLabelPosition="Right">
|
DefaultLabelPosition="Right">
|
||||||
<AppBarButton Label="添加角色" Icon="{shcm:FontIcon Glyph=}"/>
|
|
||||||
<AppBarButton Label="立即刷新" Icon="{shcm:FontIcon Glyph=}"/>
|
<AppBarButton Label="立即刷新" Icon="{shcm:FontIcon Glyph=}"/>
|
||||||
|
<AppBarButton Label="添加角色" Icon="{shcm:FontIcon Glyph=}">
|
||||||
|
<AppBarButton.Flyout>
|
||||||
|
<Flyout Placement="Bottom">
|
||||||
|
<Flyout.FlyoutPresenterStyle>
|
||||||
|
<Style
|
||||||
|
TargetType="FlyoutPresenter"
|
||||||
|
BasedOn="{StaticResource DefaultFlyoutPresenterStyle}">
|
||||||
|
<Setter Property="Padding" Value="0,2,0,2"/>
|
||||||
|
<Setter Property="Background" Value="{ThemeResource FlyoutPresenterBackground}" />
|
||||||
|
</Style>
|
||||||
|
</Flyout.FlyoutPresenterStyle>
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock
|
||||||
|
Margin="16,12,16,16"
|
||||||
|
Text="添加角色以定时刷新"
|
||||||
|
Style="{StaticResource BaseTextBlockStyle}"/>
|
||||||
|
<ScrollViewer MaxHeight="320" Padding="16,0">
|
||||||
|
<ItemsControl ItemsSource="{Binding UserAndRoles}">
|
||||||
|
<ItemsControl.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<Grid Padding="0,0,0,16">
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock Text="{Binding Role.Nickname}"/>
|
||||||
|
<TextBlock
|
||||||
|
Margin="0,2,0,0"
|
||||||
|
Opacity="0.6"
|
||||||
|
Text="{Binding Role.Description}"
|
||||||
|
Style="{StaticResource CaptionTextBlockStyle}"/>
|
||||||
|
</StackPanel>
|
||||||
|
<Button
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
Content=""
|
||||||
|
FontFamily="{StaticResource SymbolThemeFontFamily}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Background="Transparent"
|
||||||
|
BorderThickness="0"
|
||||||
|
BorderBrush="{x:Null}"
|
||||||
|
Margin="16,0,0,0"
|
||||||
|
Padding="12"
|
||||||
|
Command="{Binding DataContext.TrackRoleCommand,Source={StaticResource ViewModelBindingProxy}}"
|
||||||
|
CommandParameter="{Binding}"
|
||||||
|
ToolTipService.ToolTip="添加"/>
|
||||||
|
</Grid>
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsControl.ItemTemplate>
|
||||||
|
</ItemsControl>
|
||||||
|
</ScrollViewer>
|
||||||
|
|
||||||
|
</StackPanel>
|
||||||
|
</Flyout>
|
||||||
|
</AppBarButton.Flyout>
|
||||||
|
</AppBarButton>
|
||||||
<AppBarButton Label="通知设置" Icon="{shcm:FontIcon Glyph=}">
|
<AppBarButton Label="通知设置" Icon="{shcm:FontIcon Glyph=}">
|
||||||
<AppBarButton.Flyout>
|
<AppBarButton.Flyout>
|
||||||
<Flyout>
|
<Flyout Placement="BottomEdgeAlignedRight">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<RadioButtons ItemsSource="{Binding RefreshTimes}">
|
<RadioButtons ItemsSource="{Binding RefreshTimes}">
|
||||||
<RadioButtons.Header>
|
<RadioButtons.Header>
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
<Rectangle
|
<Rectangle
|
||||||
Height="48"
|
Height="48"
|
||||||
VerticalAlignment="Top"
|
VerticalAlignment="Top"
|
||||||
Fill="{StaticResource CardBackgroundFillColorSecondary}"/>
|
Fill="{StaticResource CardBackgroundFillColorDefaultBrush}"/>
|
||||||
<Pivot Grid.RowSpan="2">
|
<Pivot Grid.RowSpan="2">
|
||||||
<Pivot.LeftHeader>
|
<Pivot.LeftHeader>
|
||||||
<ComboBox
|
<ComboBox
|
||||||
|
|||||||
@@ -23,10 +23,16 @@
|
|||||||
<shc:BindingProxy x:Key="BindingProxy" DataContext="{Binding}"/>
|
<shc:BindingProxy x:Key="BindingProxy" DataContext="{Binding}"/>
|
||||||
|
|
||||||
<Style TargetType="Button" BasedOn="{StaticResource SettingButtonStyle}">
|
<Style TargetType="Button" BasedOn="{StaticResource SettingButtonStyle}">
|
||||||
<Setter Property="MinWidth" Value="160"/>
|
<Setter Property="MinWidth" Value="156"/>
|
||||||
</Style>
|
</Style>
|
||||||
<Style TargetType="HyperlinkButton" BasedOn="{StaticResource HyperlinkButtonStyle}">
|
<Style TargetType="HyperlinkButton" BasedOn="{StaticResource HyperlinkButtonStyle}">
|
||||||
<Setter Property="MinWidth" Value="160"/>
|
<Setter Property="MinWidth" Value="156"/>
|
||||||
|
</Style>
|
||||||
|
<Style TargetType="ComboBox" BasedOn="{StaticResource DefaultComboBoxStyle}">
|
||||||
|
<Setter Property="MinWidth" Value="156"/>
|
||||||
|
</Style>
|
||||||
|
<Style TargetType="NumberBox">
|
||||||
|
<Setter Property="MinWidth" Value="158"/>
|
||||||
</Style>
|
</Style>
|
||||||
</Page.Resources>
|
</Page.Resources>
|
||||||
<Grid>
|
<Grid>
|
||||||
@@ -48,7 +54,6 @@
|
|||||||
Description="切换游戏服务器,B服用户需要自备额外的 PCGameSDK.dll 文件">
|
Description="切换游戏服务器,B服用户需要自备额外的 PCGameSDK.dll 文件">
|
||||||
<sc:Setting.ActionContent>
|
<sc:Setting.ActionContent>
|
||||||
<ComboBox
|
<ComboBox
|
||||||
Width="160"
|
|
||||||
ItemsSource="{Binding KnownSchemes}"
|
ItemsSource="{Binding KnownSchemes}"
|
||||||
SelectedItem="{Binding SelectedScheme,Mode=TwoWay}"
|
SelectedItem="{Binding SelectedScheme,Mode=TwoWay}"
|
||||||
DisplayMemberPath="Name"/>
|
DisplayMemberPath="Name"/>
|
||||||
@@ -56,30 +61,20 @@
|
|||||||
</sc:Setting>
|
</sc:Setting>
|
||||||
<sc:SettingExpander IsExpanded="True">
|
<sc:SettingExpander IsExpanded="True">
|
||||||
<sc:SettingExpander.Header>
|
<sc:SettingExpander.Header>
|
||||||
<Grid Padding="0,16">
|
<sc:Setting
|
||||||
<StackPanel Orientation="Horizontal">
|
Icon=""
|
||||||
<FontIcon Glyph=""/>
|
Header="账号"
|
||||||
<StackPanel VerticalAlignment="Center">
|
Description="在游戏内切换账号,网络环境发生变化后需要重新手动检测">
|
||||||
<TextBlock
|
<sc:Setting.ActionContent>
|
||||||
Margin="20,0,0,0"
|
|
||||||
Text="账号"/>
|
|
||||||
<TextBlock
|
|
||||||
Opacity="0.8"
|
|
||||||
Margin="20,0,0,0"
|
|
||||||
Style="{StaticResource CaptionTextBlockStyle}"
|
|
||||||
Text="在游戏内切换账号,网络环境发生变化后需要重新手动检测"/>
|
|
||||||
</StackPanel>
|
|
||||||
</StackPanel>
|
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
Command="{Binding DetectGameAccountCommand}"
|
Command="{Binding DetectGameAccountCommand}"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Margin="0,0,8,0"
|
Margin="0,0,8,0"
|
||||||
Width="128"
|
MinWidth="124"
|
||||||
MinWidth="128"
|
|
||||||
Content="检测"/>
|
Content="检测"/>
|
||||||
</Grid>
|
</sc:Setting.ActionContent>
|
||||||
|
</sc:Setting>
|
||||||
</sc:SettingExpander.Header>
|
</sc:SettingExpander.Header>
|
||||||
<ListView
|
<ListView
|
||||||
ItemsSource="{Binding GameAccounts}"
|
ItemsSource="{Binding GameAccounts}"
|
||||||
@@ -118,7 +113,7 @@
|
|||||||
CommandParameter="{Binding}"
|
CommandParameter="{Binding}"
|
||||||
FontFamily="{StaticResource SymbolThemeFontFamily}"/>
|
FontFamily="{StaticResource SymbolThemeFontFamily}"/>
|
||||||
<Button
|
<Button
|
||||||
Margin="4,8"
|
Margin="4,8,0,8"
|
||||||
MinWidth="48"
|
MinWidth="48"
|
||||||
VerticalAlignment="Stretch"
|
VerticalAlignment="Stretch"
|
||||||
ToolTipService.ToolTip="删除"
|
ToolTipService.ToolTip="删除"
|
||||||
|
|||||||
@@ -16,6 +16,9 @@
|
|||||||
<Style TargetType="HyperlinkButton" BasedOn="{StaticResource HyperlinkButtonStyle}">
|
<Style TargetType="HyperlinkButton" BasedOn="{StaticResource HyperlinkButtonStyle}">
|
||||||
<Setter Property="MinWidth" Value="160"/>
|
<Setter Property="MinWidth" Value="160"/>
|
||||||
</Style>
|
</Style>
|
||||||
|
<Style TargetType="ComboBox" BasedOn="{StaticResource DefaultComboBoxStyle}">
|
||||||
|
<Setter Property="MinWidth" Value="160"/>
|
||||||
|
</Style>
|
||||||
</Page.Resources>
|
</Page.Resources>
|
||||||
<ScrollViewer>
|
<ScrollViewer>
|
||||||
<Grid>
|
<Grid>
|
||||||
@@ -90,6 +93,19 @@
|
|||||||
</sc:SettingExpander>
|
</sc:SettingExpander>
|
||||||
</sc:SettingsGroup>
|
</sc:SettingsGroup>
|
||||||
|
|
||||||
|
<sc:SettingsGroup Header="外观">
|
||||||
|
<sc:Setting
|
||||||
|
Icon=""
|
||||||
|
Header="背景材质"
|
||||||
|
Description="更改窗体的背景材质">
|
||||||
|
<ComboBox
|
||||||
|
SelectedItem="{Binding SelectedBackdropType,Mode=TwoWay}"
|
||||||
|
ItemsSource="{Binding BackdropTypes}"
|
||||||
|
DisplayMemberPath="Name"/>
|
||||||
|
</sc:Setting>
|
||||||
|
|
||||||
|
</sc:SettingsGroup>
|
||||||
|
|
||||||
<sc:SettingsGroup Header="祈愿记录">
|
<sc:SettingsGroup Header="祈愿记录">
|
||||||
<sc:Setting
|
<sc:Setting
|
||||||
Icon=""
|
Icon=""
|
||||||
|
|||||||
@@ -198,7 +198,6 @@
|
|||||||
</mxic:EventTriggerBehavior>
|
</mxic:EventTriggerBehavior>
|
||||||
</mxi:Interaction.Behaviors>
|
</mxi:Interaction.Behaviors>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ListView.ItemTemplate>
|
</ListView.ItemTemplate>
|
||||||
</ListView>
|
</ListView>
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using Snap.Hutao.Control;
|
|||||||
using Snap.Hutao.Core.Threading;
|
using Snap.Hutao.Core.Threading;
|
||||||
using Snap.Hutao.Factory.Abstraction;
|
using Snap.Hutao.Factory.Abstraction;
|
||||||
using Snap.Hutao.Model.Binding.AvatarProperty;
|
using Snap.Hutao.Model.Binding.AvatarProperty;
|
||||||
|
using Snap.Hutao.Model.Binding.User;
|
||||||
using Snap.Hutao.Service.Abstraction;
|
using Snap.Hutao.Service.Abstraction;
|
||||||
using Snap.Hutao.Service.AvatarInfo;
|
using Snap.Hutao.Service.AvatarInfo;
|
||||||
using Snap.Hutao.Service.User;
|
using Snap.Hutao.Service.User;
|
||||||
@@ -79,7 +80,7 @@ internal class AvatarPropertyViewModel : ObservableObject, ISupportCancellation
|
|||||||
|
|
||||||
private Task OpenUIAsync()
|
private Task OpenUIAsync()
|
||||||
{
|
{
|
||||||
if (userService.Current is Model.Binding.User user)
|
if (userService.Current is User user)
|
||||||
{
|
{
|
||||||
if (user.SelectedUserGameRole is UserGameRole role)
|
if (user.SelectedUserGameRole is UserGameRole role)
|
||||||
{
|
{
|
||||||
@@ -92,7 +93,7 @@ internal class AvatarPropertyViewModel : ObservableObject, ISupportCancellation
|
|||||||
|
|
||||||
private Task RefreshByUserGameRoleAsync()
|
private Task RefreshByUserGameRoleAsync()
|
||||||
{
|
{
|
||||||
if (userService.Current is Model.Binding.User user)
|
if (userService.Current is User user)
|
||||||
{
|
{
|
||||||
if (user.SelectedUserGameRole is UserGameRole role)
|
if (user.SelectedUserGameRole is UserGameRole role)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,7 +3,11 @@
|
|||||||
|
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using Snap.Hutao.Control;
|
using Snap.Hutao.Control;
|
||||||
|
using Snap.Hutao.Factory.Abstraction;
|
||||||
using Snap.Hutao.Model;
|
using Snap.Hutao.Model;
|
||||||
|
using Snap.Hutao.Model.Binding.User;
|
||||||
|
using Snap.Hutao.Service.User;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
|
||||||
namespace Snap.Hutao.ViewModel;
|
namespace Snap.Hutao.ViewModel;
|
||||||
|
|
||||||
@@ -11,8 +15,10 @@ namespace Snap.Hutao.ViewModel;
|
|||||||
/// 实时便笺视图模型
|
/// 实时便笺视图模型
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Injection(InjectAs.Scoped)]
|
[Injection(InjectAs.Scoped)]
|
||||||
internal class DailyNoteViewModel : ObservableObject, ISupportCancellation
|
internal class DailyNoteViewModel : ObservableObject, ISupportCancellation, IDisposable
|
||||||
{
|
{
|
||||||
|
private readonly IUserService userService;
|
||||||
|
|
||||||
private readonly List<NamedValue<int>> refreshTimes = new()
|
private readonly List<NamedValue<int>> refreshTimes = new()
|
||||||
{
|
{
|
||||||
new("4 分钟 | 0.5 树脂", 240),
|
new("4 分钟 | 0.5 树脂", 240),
|
||||||
@@ -22,6 +28,23 @@ internal class DailyNoteViewModel : ObservableObject, ISupportCancellation
|
|||||||
new("60 分钟 | 7.5 树脂", 3600),
|
new("60 分钟 | 7.5 树脂", 3600),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private bool isReminderNotification;
|
||||||
|
private NamedValue<int>? selectedRefreshTime;
|
||||||
|
private ObservableCollection<UserAndRole>? userAndRoles;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 构造一个新的实时便笺视图模型
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="userService">用户服务</param>
|
||||||
|
/// <param name="asyncRelayCommandFactory">异步命令工厂</param>
|
||||||
|
public DailyNoteViewModel(IUserService userService, IAsyncRelayCommandFactory asyncRelayCommandFactory)
|
||||||
|
{
|
||||||
|
this.userService = userService;
|
||||||
|
|
||||||
|
OpenUICommand = asyncRelayCommandFactory.Create(OpenUIAsync);
|
||||||
|
TrackRoleCommand = asyncRelayCommandFactory.Create(TrackRoleAsync);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public CancellationToken CancellationToken { get; set; }
|
public CancellationToken CancellationToken { get; set; }
|
||||||
|
|
||||||
@@ -29,4 +52,44 @@ internal class DailyNoteViewModel : ObservableObject, ISupportCancellation
|
|||||||
/// 刷新时间
|
/// 刷新时间
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<NamedValue<int>> RefreshTimes { get => refreshTimes; }
|
public List<NamedValue<int>> RefreshTimes { get => refreshTimes; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 选中的刷新时间
|
||||||
|
/// </summary>
|
||||||
|
public NamedValue<int>? SelectedRefreshTime { get => selectedRefreshTime; set => SetProperty(ref selectedRefreshTime, value); }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 提醒式通知
|
||||||
|
/// </summary>
|
||||||
|
public bool IsReminderNotification { get => isReminderNotification; set => SetProperty(ref isReminderNotification, value); }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 用户与角色集合
|
||||||
|
/// </summary>
|
||||||
|
public ObservableCollection<UserAndRole>? UserAndRoles { get => userAndRoles; set => userAndRoles = value; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 打开界面命令
|
||||||
|
/// </summary>
|
||||||
|
public ICommand OpenUICommand { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 跟踪角色命令
|
||||||
|
/// </summary>
|
||||||
|
public ICommand TrackRoleCommand { get; }
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task OpenUIAsync()
|
||||||
|
{
|
||||||
|
UserAndRoles = await userService.GetRoleCollectionAsync().ConfigureAwait(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task TrackRoleAsync()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -68,7 +68,7 @@ internal class ExperimentalFeaturesViewModel : ObservableObject
|
|||||||
IUserService userService = Ioc.Default.GetRequiredService<IUserService>();
|
IUserService userService = Ioc.Default.GetRequiredService<IUserService>();
|
||||||
IInfoBarService infoBarService = Ioc.Default.GetRequiredService<IInfoBarService>();
|
IInfoBarService infoBarService = Ioc.Default.GetRequiredService<IInfoBarService>();
|
||||||
|
|
||||||
if (userService.Current is Model.Binding.User user)
|
if (userService.Current is Model.Binding.User.User user)
|
||||||
{
|
{
|
||||||
if (user.SelectedUserGameRole == null)
|
if (user.SelectedUserGameRole == null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -35,8 +35,8 @@ internal class LaunchGameViewModel : ObservableObject, ISupportCancellation
|
|||||||
|
|
||||||
private readonly List<LaunchScheme> knownSchemes = new()
|
private readonly List<LaunchScheme> knownSchemes = new()
|
||||||
{
|
{
|
||||||
new LaunchScheme(name: "官方服 | 天空岛", channel: "1", subChannel: "1"),
|
new LaunchScheme(name: "官方服 | 天空岛", channel: "1", subChannel: "1", launcherId: "18"),
|
||||||
new LaunchScheme(name: "渠道服 | 世界树", channel: "14", subChannel: "0"),
|
new LaunchScheme(name: "渠道服 | 世界树", channel: "14", subChannel: "0", launcherId: "17"),
|
||||||
|
|
||||||
// new LaunchScheme(name: "国际服 | 暂不支持", channel: "1", subChannel: "0"),
|
// new LaunchScheme(name: "国际服 | 暂不支持", channel: "1", subChannel: "0"),
|
||||||
};
|
};
|
||||||
@@ -231,7 +231,7 @@ internal class LaunchGameViewModel : ObservableObject, ISupportCancellation
|
|||||||
}
|
}
|
||||||
catch (UnauthorizedAccessException)
|
catch (UnauthorizedAccessException)
|
||||||
{
|
{
|
||||||
infoBarService.Warning("切换服务器失败,保存配置文件时发生异常\n请以管理员模式启动胡桃。");
|
infoBarService.Warning("读取或保存配置文件时发生异常,请以管理员模式启动胡桃。");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -239,7 +239,7 @@ internal class LaunchGameViewModel : ObservableObject, ISupportCancellation
|
|||||||
{
|
{
|
||||||
if (!gameService.SetGameAccount(SelectedGameAccount))
|
if (!gameService.SetGameAccount(SelectedGameAccount))
|
||||||
{
|
{
|
||||||
Ioc.Default.GetRequiredService<IInfoBarService>().Warning("切换账号失败");
|
infoBarService.Warning("切换账号失败");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,10 +3,12 @@
|
|||||||
|
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
using CommunityToolkit.Mvvm.Messaging;
|
||||||
using Snap.Hutao.Context.Database;
|
using Snap.Hutao.Context.Database;
|
||||||
using Snap.Hutao.Core.Database;
|
using Snap.Hutao.Core.Database;
|
||||||
using Snap.Hutao.Core.Threading;
|
using Snap.Hutao.Core.Windowing;
|
||||||
using Snap.Hutao.Factory.Abstraction;
|
using Snap.Hutao.Factory.Abstraction;
|
||||||
|
using Snap.Hutao.Model;
|
||||||
using Snap.Hutao.Model.Entity;
|
using Snap.Hutao.Model.Entity;
|
||||||
using Snap.Hutao.Service.Game;
|
using Snap.Hutao.Service.Game;
|
||||||
using Snap.Hutao.Service.Game.Locator;
|
using Snap.Hutao.Service.Game.Locator;
|
||||||
@@ -22,9 +24,17 @@ internal class SettingViewModel : ObservableObject
|
|||||||
private readonly AppDbContext appDbContext;
|
private readonly AppDbContext appDbContext;
|
||||||
private readonly IGameService gameService;
|
private readonly IGameService gameService;
|
||||||
private readonly SettingEntry isEmptyHistoryWishVisibleEntry;
|
private readonly SettingEntry isEmptyHistoryWishVisibleEntry;
|
||||||
|
private readonly SettingEntry selectedBackdropTypeEntry;
|
||||||
|
private readonly List<NamedValue<BackdropType>> backdropTypes = new()
|
||||||
|
{
|
||||||
|
new("亚克力", BackdropType.Acrylic),
|
||||||
|
new("云母", BackdropType.Mica),
|
||||||
|
new("变种云母", BackdropType.MicaAlt),
|
||||||
|
};
|
||||||
|
|
||||||
private bool isEmptyHistoryWishVisible;
|
private bool isEmptyHistoryWishVisible;
|
||||||
private string gamePath;
|
private string gamePath;
|
||||||
|
private NamedValue<BackdropType> selectedBackdropType;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 构造一个新的测试视图模型
|
/// 构造一个新的测试视图模型
|
||||||
@@ -40,10 +50,16 @@ internal class SettingViewModel : ObservableObject
|
|||||||
|
|
||||||
Experimental = experimental;
|
Experimental = experimental;
|
||||||
|
|
||||||
isEmptyHistoryWishVisibleEntry = appDbContext.Settings
|
isEmptyHistoryWishVisibleEntry = appDbContext.Settings.SingleOrAdd(SettingEntry.IsEmptyHistoryWishVisible, true.ToString());
|
||||||
.SingleOrAdd(e => e.Key == SettingEntry.IsEmptyHistoryWishVisible, () => new(SettingEntry.IsEmptyHistoryWishVisible, true.ToString()), out _);
|
|
||||||
IsEmptyHistoryWishVisible = bool.Parse(isEmptyHistoryWishVisibleEntry.Value!);
|
IsEmptyHistoryWishVisible = bool.Parse(isEmptyHistoryWishVisibleEntry.Value!);
|
||||||
|
|
||||||
|
selectedBackdropTypeEntry = appDbContext.Settings.SingleOrAdd(SettingEntry.SystemBackdropType, BackdropType.Mica.ToString());
|
||||||
|
BackdropType type = Enum.Parse<BackdropType>(selectedBackdropTypeEntry.Value!);
|
||||||
|
|
||||||
|
// prevent unnecessary backdrop setting.
|
||||||
|
selectedBackdropType = backdropTypes.Single(t => t.Value == type);
|
||||||
|
OnPropertyChanged(nameof(SelectedBackdropType));
|
||||||
|
|
||||||
GamePath = gameService.GetGamePathSkipLocator();
|
GamePath = gameService.GetGamePathSkipLocator();
|
||||||
|
|
||||||
SetGamePathCommand = asyncRelayCommandFactory.Create(SetGamePathAsync);
|
SetGamePathCommand = asyncRelayCommandFactory.Create(SetGamePathAsync);
|
||||||
@@ -67,11 +83,13 @@ internal class SettingViewModel : ObservableObject
|
|||||||
get => isEmptyHistoryWishVisible;
|
get => isEmptyHistoryWishVisible;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
SetProperty(ref isEmptyHistoryWishVisible, value);
|
if (SetProperty(ref isEmptyHistoryWishVisible, value))
|
||||||
|
{
|
||||||
isEmptyHistoryWishVisibleEntry.Value = value.ToString();
|
isEmptyHistoryWishVisibleEntry.Value = value.ToString();
|
||||||
appDbContext.Settings.UpdateAndSave(isEmptyHistoryWishVisibleEntry);
|
appDbContext.Settings.UpdateAndSave(isEmptyHistoryWishVisibleEntry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 游戏路径
|
/// 游戏路径
|
||||||
@@ -83,6 +101,29 @@ internal class SettingViewModel : ObservableObject
|
|||||||
set => SetProperty(ref gamePath, value);
|
set => SetProperty(ref gamePath, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 背景类型
|
||||||
|
/// </summary>
|
||||||
|
public List<NamedValue<BackdropType>> BackdropTypes { get => backdropTypes; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 选中的背景类型
|
||||||
|
/// </summary>
|
||||||
|
public NamedValue<BackdropType> SelectedBackdropType
|
||||||
|
{
|
||||||
|
get => selectedBackdropType;
|
||||||
|
[MemberNotNull(nameof(selectedBackdropType))]
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (SetProperty(ref selectedBackdropType, value))
|
||||||
|
{
|
||||||
|
selectedBackdropTypeEntry.Value = value.Value.ToString();
|
||||||
|
appDbContext.Settings.UpdateAndSave(selectedBackdropTypeEntry);
|
||||||
|
Ioc.Default.GetRequiredService<IMessenger>().Send(new Message.BackdropTypeChangedMessage(value.Value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 实验性功能
|
/// 实验性功能
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ using CommunityToolkit.Mvvm.Input;
|
|||||||
using Snap.Hutao.Core.IO.DataTransfer;
|
using Snap.Hutao.Core.IO.DataTransfer;
|
||||||
using Snap.Hutao.Core.Threading;
|
using Snap.Hutao.Core.Threading;
|
||||||
using Snap.Hutao.Factory.Abstraction;
|
using Snap.Hutao.Factory.Abstraction;
|
||||||
using Snap.Hutao.Model.Binding;
|
using Snap.Hutao.Model.Binding.User;
|
||||||
using Snap.Hutao.Service.Abstraction;
|
using Snap.Hutao.Service.Abstraction;
|
||||||
using Snap.Hutao.Service.Navigation;
|
using Snap.Hutao.Service.Navigation;
|
||||||
using Snap.Hutao.Service.User;
|
using Snap.Hutao.Service.User;
|
||||||
|
|||||||
@@ -43,6 +43,17 @@ internal static class ApiEndpoints
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public const string GameRecordCharacter = $"{ApiTakumiRecordApi}/character";
|
public const string GameRecordCharacter = $"{ApiTakumiRecordApi}/character";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 游戏记录实时便笺
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="uid">uid</param>
|
||||||
|
/// <param name="server">服务器区域</param>
|
||||||
|
/// <returns>游戏记录实时便笺字符串</returns>
|
||||||
|
public static string GameRecordDailyNote(string uid, string server)
|
||||||
|
{
|
||||||
|
return $"{ApiTakumiRecordApi}/dailyNote?server={server}&role_id={uid}";
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 游戏记录主页
|
/// 游戏记录主页
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -121,12 +132,13 @@ internal static class ApiEndpoints
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 启动器资源
|
/// 启动器资源
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="launcherId">启动器Id</param>
|
||||||
/// <param name="channel">通道</param>
|
/// <param name="channel">通道</param>
|
||||||
/// <param name="subChannel">子通道</param>
|
/// <param name="subChannel">子通道</param>
|
||||||
/// <returns>启动器资源字符串</returns>
|
/// <returns>启动器资源字符串</returns>
|
||||||
public static string SdkStaticLauncherResource(string channel, string subChannel)
|
public static string SdkStaticLauncherResource(string launcherId, string channel, string subChannel)
|
||||||
{
|
{
|
||||||
return $"{SdkStaticLauncherApi}/resource?key=eYd89JmJ&launcher_id=18&channel_id={channel}&sub_channel_id={subChannel}";
|
return $"{SdkStaticLauncherApi}/resource?key=eYd89JmJ&launcher_id={launcherId}&channel_id={channel}&sub_channel_id={subChannel}";
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://sdk-static.mihoyo.com/hk4e_cn/mdk/launcher/api/content?filter_adv=true&key=eYd89JmJ&language=zh-cn&launcher_id=18
|
// https://sdk-static.mihoyo.com/hk4e_cn/mdk/launcher/api/content?filter_adv=true&key=eYd89JmJ&language=zh-cn&launcher_id=18
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ internal class UserClient
|
|||||||
/// <param name="user">用户</param>
|
/// <param name="user">用户</param>
|
||||||
/// <param name="token">取消令牌</param>
|
/// <param name="token">取消令牌</param>
|
||||||
/// <returns>详细信息</returns>
|
/// <returns>详细信息</returns>
|
||||||
public async Task<UserInfo?> GetUserFullInfoAsync(Model.Binding.User user, CancellationToken token = default)
|
public async Task<UserInfo?> GetUserFullInfoAsync(Model.Binding.User.User user, CancellationToken token = default)
|
||||||
{
|
{
|
||||||
Response<UserFullInfoWrapper>? resp = await httpClient
|
Response<UserFullInfoWrapper>? resp = await httpClient
|
||||||
.SetUser(user)
|
.SetUser(user)
|
||||||
|
|||||||
24
src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Cookie.Constant.cs
Normal file
24
src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Cookie.Constant.cs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Web.Hoyolab;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 键部分
|
||||||
|
/// </summary>
|
||||||
|
[SuppressMessage("", "SA1310")]
|
||||||
|
[SuppressMessage("", "SA1600")]
|
||||||
|
public partial class Cookie
|
||||||
|
{
|
||||||
|
public const string COOKIE_TOKEN = "cookie_token";
|
||||||
|
public const string ACCOUNT_ID = "account_id";
|
||||||
|
|
||||||
|
public const string LOGIN_TICKET = "login_ticket";
|
||||||
|
public const string LOGIN_UID = "login_uid";
|
||||||
|
|
||||||
|
public const string LTOKEN = "ltoken";
|
||||||
|
public const string LTUID = "ltuid";
|
||||||
|
|
||||||
|
public const string STOKEN = "stoken";
|
||||||
|
public const string STUID = "stuid";
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using Microsoft.Web.WebView2.Core;
|
using Microsoft.Web.WebView2.Core;
|
||||||
using Snap.Hutao.Extension;
|
using Snap.Hutao.Extension;
|
||||||
|
using Snap.Hutao.Web.Hoyolab.Takumi.Auth;
|
||||||
|
|
||||||
namespace Snap.Hutao.Web.Hoyolab;
|
namespace Snap.Hutao.Web.Hoyolab;
|
||||||
|
|
||||||
@@ -90,20 +91,6 @@ public partial class Cookie
|
|||||||
return inner.ContainsKey(STOKEN);
|
return inner.ContainsKey(STOKEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插入Stoken
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="uid">uid</param>
|
|
||||||
/// <param name="multiToken">tokens</param>
|
|
||||||
public void InsertMultiToken(string uid, Dictionary<string, string> multiToken)
|
|
||||||
{
|
|
||||||
inner[STUID] = uid;
|
|
||||||
inner[STOKEN] = multiToken[STOKEN];
|
|
||||||
|
|
||||||
inner[LTUID] = uid;
|
|
||||||
inner[LTOKEN] = multiToken[LTOKEN];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 插入 Stoken
|
/// 插入 Stoken
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -115,15 +102,6 @@ public partial class Cookie
|
|||||||
inner[STOKEN] = cookie.inner[STOKEN];
|
inner[STOKEN] = cookie.inner[STOKEN];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 移除 LoginTicket
|
|
||||||
/// </summary>
|
|
||||||
public void RemoveLoginTicket()
|
|
||||||
{
|
|
||||||
inner.Remove(LOGIN_TICKET);
|
|
||||||
inner.Remove(LOGIN_UID);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 移除无效的键
|
/// 移除无效的键
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -186,6 +164,34 @@ public partial class Cookie
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步尝试添加MultiToken
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="uid">uid</param>
|
||||||
|
/// <returns>任务</returns>
|
||||||
|
public async Task TryAddMultiTokenAsync(string uid)
|
||||||
|
{
|
||||||
|
if (TryGetLoginTicket(out string? loginTicket))
|
||||||
|
{
|
||||||
|
// get multitoken
|
||||||
|
Dictionary<string, string> multiToken = await Ioc.Default
|
||||||
|
.GetRequiredService<AuthClient>()
|
||||||
|
.GetMultiTokenByLoginTicketAsync(loginTicket, uid, default)
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (multiToken.Count >= 2)
|
||||||
|
{
|
||||||
|
inner[STUID] = uid;
|
||||||
|
inner[STOKEN] = multiToken[STOKEN];
|
||||||
|
inner[LTUID] = uid;
|
||||||
|
inner[LTOKEN] = multiToken[LTOKEN];
|
||||||
|
|
||||||
|
inner.Remove(LOGIN_TICKET);
|
||||||
|
inner.Remove(LOGIN_UID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 转换为Cookie的字符串表示
|
/// 转换为Cookie的字符串表示
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -195,23 +201,3 @@ public partial class Cookie
|
|||||||
return string.Join(';', inner.Select(kvp => $"{kvp.Key}={kvp.Value}"));
|
return string.Join(';', inner.Select(kvp => $"{kvp.Key}={kvp.Value}"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 键部分
|
|
||||||
/// </summary>
|
|
||||||
[SuppressMessage("", "SA1310")]
|
|
||||||
[SuppressMessage("", "SA1600")]
|
|
||||||
public partial class Cookie
|
|
||||||
{
|
|
||||||
public const string COOKIE_TOKEN = "cookie_token";
|
|
||||||
public const string ACCOUNT_ID = "account_id";
|
|
||||||
|
|
||||||
public const string LOGIN_TICKET = "login_ticket";
|
|
||||||
public const string LOGIN_UID = "login_uid";
|
|
||||||
|
|
||||||
public const string LTOKEN = "ltoken";
|
|
||||||
public const string LTUID = "ltuid";
|
|
||||||
|
|
||||||
public const string STOKEN = "stoken";
|
|
||||||
public const string STUID = "stuid";
|
|
||||||
}
|
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using Snap.Hutao.Core.Logging;
|
using Snap.Hutao.Core.Logging;
|
||||||
using Snap.Hutao.Model.Binding;
|
using Snap.Hutao.Model.Binding.User;
|
||||||
using Snap.Hutao.Web.Request;
|
using Snap.Hutao.Web.Request;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Net.Http.Json;
|
using System.Net.Http.Json;
|
||||||
@@ -64,7 +64,7 @@ internal static class HttpClientExtensions
|
|||||||
/// 设置用户的Cookie
|
/// 设置用户的Cookie
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="httpClient">http客户端</param>
|
/// <param name="httpClient">http客户端</param>
|
||||||
/// <param name="user">用户</param>
|
/// <param name="user">绑定用户</param>
|
||||||
/// <returns>客户端</returns>
|
/// <returns>客户端</returns>
|
||||||
internal static HttpClient SetUser(this HttpClient httpClient, User user)
|
internal static HttpClient SetUser(this HttpClient httpClient, User user)
|
||||||
{
|
{
|
||||||
@@ -72,6 +72,18 @@ internal static class HttpClientExtensions
|
|||||||
return httpClient;
|
return httpClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置用户的Cookie
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="httpClient">http客户端</param>
|
||||||
|
/// <param name="user">实体用户</param>
|
||||||
|
/// <returns>客户端</returns>
|
||||||
|
internal static HttpClient SetUser(this HttpClient httpClient, Model.Entity.User user)
|
||||||
|
{
|
||||||
|
httpClient.DefaultRequestHeaders.Set("Cookie", user.Cookie!.ToString());
|
||||||
|
return httpClient;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 设置Referer
|
/// 设置Referer
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -41,6 +41,11 @@ public struct PlayerUid
|
|||||||
get => region ??= EvaluateRegion(Value[0]);
|
get => region ??= EvaluateRegion(Value[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static implicit operator PlayerUid(string source)
|
||||||
|
{
|
||||||
|
return new(source);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -39,8 +39,9 @@ internal class ResourceClient
|
|||||||
/// <returns>游戏资源</returns>
|
/// <returns>游戏资源</returns>
|
||||||
public async Task<GameResource?> GetResourceAsync(LaunchScheme scheme, CancellationToken token = default)
|
public async Task<GameResource?> GetResourceAsync(LaunchScheme scheme, CancellationToken token = default)
|
||||||
{
|
{
|
||||||
|
string url = ApiEndpoints.SdkStaticLauncherResource(scheme.LauncherId, scheme.Channel, scheme.SubChannel);
|
||||||
Response<GameResource>? response = await httpClient
|
Response<GameResource>? response = await httpClient
|
||||||
.TryCatchGetFromJsonAsync<Response<GameResource>>(ApiEndpoints.SdkStaticLauncherResource(scheme.Channel, scheme.SubChannel), options, logger, token)
|
.TryCatchGetFromJsonAsync<Response<GameResource>>(url, options, logger, token)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
return response?.Data;
|
return response?.Data;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
|
using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
|
||||||
using Snap.Hutao.Extension;
|
using Snap.Hutao.Extension;
|
||||||
using Snap.Hutao.Model.Binding;
|
using Snap.Hutao.Model.Binding.User;
|
||||||
using Snap.Hutao.Web.Response;
|
using Snap.Hutao.Web.Response;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
|
using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
|
||||||
using Snap.Hutao.Model.Binding;
|
using Snap.Hutao.Model.Binding.User;
|
||||||
using Snap.Hutao.Web.Hoyolab.DynamicSecret;
|
using Snap.Hutao.Web.Hoyolab.DynamicSecret;
|
||||||
using Snap.Hutao.Web.Response;
|
using Snap.Hutao.Web.Response;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ public class UserGameRole
|
|||||||
get => $"{RegionName} | Lv.{Level}";
|
get => $"{RegionName} | Lv.{Level}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static explicit operator PlayerUid(UserGameRole userGameRole)
|
public static implicit operator PlayerUid(UserGameRole userGameRole)
|
||||||
{
|
{
|
||||||
return new PlayerUid(userGameRole.GameUid, userGameRole.Region);
|
return new PlayerUid(userGameRole.GameUid, userGameRole.Region);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,171 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.DailyNote;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 实时便笺
|
||||||
|
/// </summary>
|
||||||
|
public class DailyNote
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 当前树脂
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("current_resin")]
|
||||||
|
public int CurrentResin { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 最大树脂
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("max_resin")]
|
||||||
|
public int MaxResin { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 树脂恢复时间 <see cref="string"/>类型的秒数
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("resin_recovery_time")]
|
||||||
|
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString)]
|
||||||
|
public int ResinRecoveryTime { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 格式化的树脂恢复时间
|
||||||
|
/// </summary>
|
||||||
|
public string ResinRecoveryTargetTime
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
DateTime tt = DateTime.Now.AddSeconds(ResinRecoveryTime);
|
||||||
|
int totalDays = (tt - DateTime.Today).Days;
|
||||||
|
string day = totalDays switch
|
||||||
|
{
|
||||||
|
0 => "今天",
|
||||||
|
1 => "明天",
|
||||||
|
2 => "后天",
|
||||||
|
_ => $"{totalDays}天",
|
||||||
|
};
|
||||||
|
return $"{day} {tt:HH:mm}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 委托完成数
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("finished_task_num")]
|
||||||
|
public int FinishedTaskNum { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 委托总数
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("total_task_num")]
|
||||||
|
public int TotalTaskNum { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 4次委托额外奖励是否领取
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("is_extra_task_reward_received")]
|
||||||
|
public bool IsExtraTaskRewardReceived { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 每日委托奖励字符串
|
||||||
|
/// </summary>
|
||||||
|
public string ExtraTaskRewardDescription
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return IsExtraTaskRewardReceived
|
||||||
|
? "已领取「每日委托」奖励"
|
||||||
|
: FinishedTaskNum == TotalTaskNum
|
||||||
|
? "「每日委托」奖励待领取"
|
||||||
|
: "今日完成委托次数不足";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 剩余周本折扣次数
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("remain_resin_discount_num")]
|
||||||
|
public int RemainResinDiscountNum { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 周本树脂减免使用次数
|
||||||
|
/// </summary>
|
||||||
|
public int ResinDiscountUsedNum
|
||||||
|
{
|
||||||
|
get => ResinDiscountNumLimit - RemainResinDiscountNum;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 周本折扣总次数
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("resin_discount_num_limit")]
|
||||||
|
public int ResinDiscountNumLimit { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 当前派遣数
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("current_expedition_num")]
|
||||||
|
public int CurrentExpeditionNum { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 最大派遣数
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("max_expedition_num")]
|
||||||
|
public int MaxExpeditionNum { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 派遣
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("expeditions")]
|
||||||
|
public List<Expedition> Expeditions { get; set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 当前洞天宝钱
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("current_home_coin")]
|
||||||
|
public int CurrentHomeCoin { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 最大洞天宝钱
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("max_home_coin")]
|
||||||
|
public int MaxHomeCoin { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 洞天宝钱恢复时间 <see cref="string"/>类型的秒数
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("home_coin_recovery_time")]
|
||||||
|
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString)]
|
||||||
|
public int HomeCoinRecoveryTime { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 格式化的洞天宝钱恢复时间
|
||||||
|
/// </summary>
|
||||||
|
public string HomeCoinRecoveryTargetTimeFormatted
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
DateTime reach = DateTime.Now.AddSeconds(HomeCoinRecoveryTime);
|
||||||
|
int totalDays = (reach - DateTime.Today).Days;
|
||||||
|
string day = totalDays switch
|
||||||
|
{
|
||||||
|
0 => "今天",
|
||||||
|
1 => "明天",
|
||||||
|
2 => "后天",
|
||||||
|
_ => $"{totalDays}天",
|
||||||
|
};
|
||||||
|
return $"{day} {reach:HH:mm}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 日历链接
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("calendar_url")]
|
||||||
|
public string CalendarUrl { get; set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 参量质变仪
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("transformer")]
|
||||||
|
public Transformer Transformer { get; set; } = default!;
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.DailyNote;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 探索派遣
|
||||||
|
/// </summary>
|
||||||
|
public class Expedition
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 图标
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("avatar_side_icon")]
|
||||||
|
public Uri AvatarSideIcon { get; set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 状态 Ongoing:派遣中 Finished:已完成
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("status")]
|
||||||
|
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||||||
|
public ExpeditionStatus Status { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 剩余时间
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("remained_time")]
|
||||||
|
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString)]
|
||||||
|
public int RemainedTime { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 格式化的剩余时间
|
||||||
|
/// </summary>
|
||||||
|
public string RemainedTimeFormatted
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (Status == ExpeditionStatus.Finished)
|
||||||
|
{
|
||||||
|
return "已完成";
|
||||||
|
}
|
||||||
|
|
||||||
|
TimeSpan ts = new(0, 0, RemainedTime);
|
||||||
|
return ts.Hours > 0 ? $"{ts.Hours}时" : $"{ts.Minutes}分";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.DailyNote;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 探索派遣状态
|
||||||
|
/// </summary>
|
||||||
|
public enum ExpeditionStatus
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 进行中
|
||||||
|
/// </summary>
|
||||||
|
Ongoing,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 完成
|
||||||
|
/// </summary>
|
||||||
|
Finished,
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Extension;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.DailyNote;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 参量质变仪恢复时间包装
|
||||||
|
/// 已准备完成 $后可再次使用
|
||||||
|
/// 冷却中 可使用
|
||||||
|
/// </summary>
|
||||||
|
public class RecoveryTime
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 日
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("Day")]
|
||||||
|
public int Day { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 时
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("Hour")]
|
||||||
|
public int Hour { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 分
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("Minute")]
|
||||||
|
public int Minute { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 秒
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("Second")]
|
||||||
|
public int Second { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否已经到达
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("reached")]
|
||||||
|
public bool Reached { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取格式化的剩余时间
|
||||||
|
/// </summary>
|
||||||
|
public string TimeFormatted
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (Reached)
|
||||||
|
{
|
||||||
|
return "已准备完成";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new StringBuilder()
|
||||||
|
.AppendIf(Day > 0, $"{Day}天")
|
||||||
|
.AppendIf(Hour > 0, $"{Hour}时")
|
||||||
|
.AppendIf(Minute > 0, $"{Minute}分")
|
||||||
|
.AppendIf(Second > 0, $"{Second}秒")
|
||||||
|
.Append(" 后可再次使用")
|
||||||
|
.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取格式化的状态
|
||||||
|
/// </summary>
|
||||||
|
public string ReachedFormatted
|
||||||
|
{
|
||||||
|
get => Reached ? "可使用" : "冷却中";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.DailyNote;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 参量质变仪
|
||||||
|
/// </summary>
|
||||||
|
public class Transformer
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 是否拥有该道具
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("obtained")]
|
||||||
|
public bool Obtained { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 恢复时间包装
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("recovery_time")]
|
||||||
|
public RecoveryTime? RecoveryTime { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Wiki链接
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("wiki")]
|
||||||
|
public Uri Wiki { get; set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否提醒
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("noticed")]
|
||||||
|
public bool Noticed { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 上个任务的Id
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("latest_job_id")]
|
||||||
|
public string LastJobId { get; set; } = default!;
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
|
using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
|
||||||
using Snap.Hutao.Extension;
|
using Snap.Hutao.Extension;
|
||||||
using Snap.Hutao.Model.Binding;
|
using Snap.Hutao.Model.Binding.User;
|
||||||
using Snap.Hutao.Web.Hoyolab.DynamicSecret;
|
using Snap.Hutao.Web.Hoyolab.DynamicSecret;
|
||||||
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.Avatar;
|
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.Avatar;
|
||||||
using Snap.Hutao.Web.Response;
|
using Snap.Hutao.Web.Response;
|
||||||
@@ -34,6 +34,42 @@ internal class GameRecordClient
|
|||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步获取实时便笺
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="user">用户</param>
|
||||||
|
/// <param name="uid">查询uid</param>
|
||||||
|
/// <param name="token">取消令牌</param>
|
||||||
|
/// <returns>实时便笺</returns>
|
||||||
|
public async Task<DailyNote.DailyNote?> GetDialyNoteAsync(User user, PlayerUid uid, CancellationToken token = default)
|
||||||
|
{
|
||||||
|
Response<DailyNote.DailyNote>? resp = await httpClient
|
||||||
|
.SetUser(user)
|
||||||
|
.UsingDynamicSecret(options, ApiEndpoints.GameRecordDailyNote(uid.Value, uid.Region))
|
||||||
|
.GetFromJsonAsync<Response<DailyNote.DailyNote>>(token)
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
return resp?.Data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步获取实时便笺
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="user">用户</param>
|
||||||
|
/// <param name="uid">查询uid</param>
|
||||||
|
/// <param name="token">取消令牌</param>
|
||||||
|
/// <returns>实时便笺</returns>
|
||||||
|
public async Task<DailyNote.DailyNote?> GetDialyNoteAsync(Model.Entity.User user, PlayerUid uid, CancellationToken token = default)
|
||||||
|
{
|
||||||
|
Response<DailyNote.DailyNote>? resp = await httpClient
|
||||||
|
.SetUser(user)
|
||||||
|
.UsingDynamicSecret(options, ApiEndpoints.GameRecordDailyNote(uid.Value, uid.Region))
|
||||||
|
.GetFromJsonAsync<Response<DailyNote.DailyNote>>(token)
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
return resp?.Data;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取玩家基础信息
|
/// 获取玩家基础信息
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -68,7 +104,7 @@ internal class GameRecordClient
|
|||||||
/// 获取玩家深渊信息
|
/// 获取玩家深渊信息
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="user">用户</param>
|
/// <param name="user">用户</param>
|
||||||
/// <param name="schedule">1:当期,2:上期</param>
|
/// <param name="schedule">期</param>
|
||||||
/// <param name="token">取消令牌</param>
|
/// <param name="token">取消令牌</param>
|
||||||
/// <returns>深渊信息</returns>
|
/// <returns>深渊信息</returns>
|
||||||
public Task<SpiralAbyss.SpiralAbyss?> GetSpiralAbyssAsync(User user, SpiralAbyssSchedule schedule, CancellationToken token = default)
|
public Task<SpiralAbyss.SpiralAbyss?> GetSpiralAbyssAsync(User user, SpiralAbyssSchedule schedule, CancellationToken token = default)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
|
using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
|
||||||
using Snap.Hutao.Extension;
|
using Snap.Hutao.Extension;
|
||||||
|
using Snap.Hutao.Model.Binding.User;
|
||||||
using Snap.Hutao.Web.Hoyolab;
|
using Snap.Hutao.Web.Hoyolab;
|
||||||
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord;
|
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord;
|
||||||
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.Avatar;
|
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.Avatar;
|
||||||
@@ -172,7 +173,7 @@ internal class HomaClient
|
|||||||
/// <param name="user">用户</param>
|
/// <param name="user">用户</param>
|
||||||
/// <param name="token">取消令牌</param>
|
/// <param name="token">取消令牌</param>
|
||||||
/// <returns>玩家记录</returns>
|
/// <returns>玩家记录</returns>
|
||||||
public async Task<SimpleRecord> GetPlayerRecordAsync(Snap.Hutao.Model.Binding.User user, CancellationToken token = default)
|
public async Task<SimpleRecord> GetPlayerRecordAsync(User user, CancellationToken token = default)
|
||||||
{
|
{
|
||||||
PlayerInfo? playerInfo = await gameRecordClient
|
PlayerInfo? playerInfo = await gameRecordClient
|
||||||
.GetPlayerInfoAsync(user, token)
|
.GetPlayerInfoAsync(user, token)
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ public enum KnownReturnCode : int
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 访问过于频繁
|
/// 访问过于频繁
|
||||||
/// </summary>
|
/// </summary>
|
||||||
VIsitTooFrequently = -110,
|
VisitTooFrequently = -110,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 应用Id错误
|
/// 应用Id错误
|
||||||
|
|||||||
@@ -89,14 +89,4 @@ public class Response<TData> : Response
|
|||||||
{
|
{
|
||||||
return ReturnCode == 0;
|
return ReturnCode == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override int GetHashCode()
|
|
||||||
{
|
|
||||||
int j = ReturnCode.GetHashCode();
|
|
||||||
int k = Message == null ? 0 : Message.GetHashCode();
|
|
||||||
int i = Data == null ? 0 : Data.GetHashCode();
|
|
||||||
|
|
||||||
return (((j * 31) + k) * 31) + i;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user