mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
update to was 1.3 and fix upload spiralabyss
This commit is contained in:
@@ -26,6 +26,7 @@ internal sealed class ExceptionRecorder
|
|||||||
|
|
||||||
application.UnhandledException += OnAppUnhandledException;
|
application.UnhandledException += OnAppUnhandledException;
|
||||||
application.DebugSettings.BindingFailed += OnXamlBindingFailed;
|
application.DebugSettings.BindingFailed += OnXamlBindingFailed;
|
||||||
|
application.DebugSettings.XamlResourceReferenceFailed += OnXamlResourceReferenceFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnAppUnhandledException(object? sender, Microsoft.UI.Xaml.UnhandledExceptionEventArgs e)
|
private void OnAppUnhandledException(object? sender, Microsoft.UI.Xaml.UnhandledExceptionEventArgs e)
|
||||||
@@ -51,4 +52,9 @@ internal sealed class ExceptionRecorder
|
|||||||
{
|
{
|
||||||
logger.LogCritical("XAML绑定失败: {message}", e.Message);
|
logger.LogCritical("XAML绑定失败: {message}", e.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnXamlResourceReferenceFailed(DebugSettings sender, XamlResourceReferenceFailedEventArgs e)
|
||||||
|
{
|
||||||
|
logger.LogCritical("XAML资源引用失败: {message}", e.Message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -3,9 +3,12 @@
|
|||||||
|
|
||||||
using CommunityToolkit.Mvvm.Messaging;
|
using CommunityToolkit.Mvvm.Messaging;
|
||||||
using Microsoft.UI;
|
using Microsoft.UI;
|
||||||
|
using Microsoft.UI.Composition.SystemBackdrops;
|
||||||
using Microsoft.UI.Windowing;
|
using Microsoft.UI.Windowing;
|
||||||
using Microsoft.UI.Xaml;
|
using Microsoft.UI.Xaml;
|
||||||
|
using Microsoft.UI.Xaml.Media;
|
||||||
using Snap.Hutao.Message;
|
using Snap.Hutao.Message;
|
||||||
|
using Snap.Hutao.Service;
|
||||||
using Snap.Hutao.Win32;
|
using Snap.Hutao.Win32;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Windows.Graphics;
|
using Windows.Graphics;
|
||||||
@@ -27,8 +30,6 @@ internal sealed class ExtendedWindow<TWindow> : IRecipient<FlyoutOpenCloseMessag
|
|||||||
private readonly ILogger<ExtendedWindow<TWindow>> logger;
|
private readonly ILogger<ExtendedWindow<TWindow>> logger;
|
||||||
private readonly WindowSubclass<TWindow> subclass;
|
private readonly WindowSubclass<TWindow> subclass;
|
||||||
|
|
||||||
private SystemBackdrop? systemBackdrop;
|
|
||||||
|
|
||||||
private ExtendedWindow(TWindow window, FrameworkElement titleBar, IServiceProvider serviceProvider)
|
private ExtendedWindow(TWindow window, FrameworkElement titleBar, IServiceProvider serviceProvider)
|
||||||
{
|
{
|
||||||
options = new(window, titleBar);
|
options = new(window, titleBar);
|
||||||
@@ -54,7 +55,7 @@ internal sealed class ExtendedWindow<TWindow> : IRecipient<FlyoutOpenCloseMessag
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void Receive(FlyoutOpenCloseMessage message)
|
public void Receive(FlyoutOpenCloseMessage message)
|
||||||
{
|
{
|
||||||
UpdateDragRectangles(options.AppWindow.TitleBar, message.IsOpen);
|
UpdateDragRectangles(message.IsOpen);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitializeWindow()
|
private void InitializeWindow()
|
||||||
@@ -69,9 +70,9 @@ internal sealed class ExtendedWindow<TWindow> : IRecipient<FlyoutOpenCloseMessag
|
|||||||
// appWindow.Show can't bring window to top.
|
// appWindow.Show can't bring window to top.
|
||||||
options.Window.Activate();
|
options.Window.Activate();
|
||||||
|
|
||||||
systemBackdrop = new(options.Window, serviceProvider);
|
AppOptions appOptions = serviceProvider.GetRequiredService<AppOptions>();
|
||||||
bool micaApplied = systemBackdrop.Update();
|
UpdateSystemBackdrop(appOptions.BackdropType);
|
||||||
logger.LogInformation("Apply {name} : {result}", nameof(SystemBackdrop), micaApplied ? "succeed" : "failed");
|
appOptions.PropertyChanged += OnOptionsPropertyChanged;
|
||||||
|
|
||||||
bool subClassApplied = subclass.Initialize();
|
bool subClassApplied = subclass.Initialize();
|
||||||
logger.LogInformation("Apply {name} : {result}", nameof(WindowSubclass<TWindow>), subClassApplied ? "succeed" : "failed");
|
logger.LogInformation("Apply {name} : {result}", nameof(WindowSubclass<TWindow>), subClassApplied ? "succeed" : "failed");
|
||||||
@@ -82,6 +83,14 @@ internal sealed class ExtendedWindow<TWindow> : IRecipient<FlyoutOpenCloseMessag
|
|||||||
options.Window.Closed += OnWindowClosed;
|
options.Window.Closed += OnWindowClosed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnOptionsPropertyChanged(object? sender, PropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.PropertyName == nameof(AppOptions.BackdropType))
|
||||||
|
{
|
||||||
|
UpdateSystemBackdrop(((AppOptions)sender!).BackdropType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void OnWindowClosed(object sender, WindowEventArgs args)
|
private void OnWindowClosed(object sender, WindowEventArgs args)
|
||||||
{
|
{
|
||||||
if (options.Window.PersistSize)
|
if (options.Window.PersistSize)
|
||||||
@@ -106,15 +115,28 @@ internal sealed class ExtendedWindow<TWindow> : IRecipient<FlyoutOpenCloseMessag
|
|||||||
appTitleBar.IconShowOptions = IconShowOptions.HideIconAndSystemMenu;
|
appTitleBar.IconShowOptions = IconShowOptions.HideIconAndSystemMenu;
|
||||||
appTitleBar.ExtendsContentIntoTitleBar = true;
|
appTitleBar.ExtendsContentIntoTitleBar = true;
|
||||||
|
|
||||||
UpdateTitleButtonColor(appTitleBar);
|
UpdateTitleButtonColor();
|
||||||
UpdateDragRectangles(appTitleBar);
|
UpdateDragRectangles();
|
||||||
options.TitleBar.ActualThemeChanged += (s, e) => UpdateTitleButtonColor(appTitleBar);
|
options.TitleBar.ActualThemeChanged += (s, e) => UpdateTitleButtonColor();
|
||||||
options.TitleBar.SizeChanged += (s, e) => UpdateDragRectangles(appTitleBar);
|
options.TitleBar.SizeChanged += (s, e) => UpdateDragRectangles();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateTitleButtonColor(AppWindowTitleBar appTitleBar)
|
private void UpdateSystemBackdrop(BackdropType backdropType)
|
||||||
{
|
{
|
||||||
|
options.Window.SystemBackdrop = backdropType switch
|
||||||
|
{
|
||||||
|
BackdropType.MicaAlt => new MicaBackdrop() { Kind = MicaKind.BaseAlt },
|
||||||
|
BackdropType.Mica => new MicaBackdrop() { Kind = MicaKind.Base },
|
||||||
|
BackdropType.Acrylic => new DesktopAcrylicBackdrop(),
|
||||||
|
_ => null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateTitleButtonColor()
|
||||||
|
{
|
||||||
|
AppWindowTitleBar appTitleBar = options.AppWindow.TitleBar;
|
||||||
|
|
||||||
appTitleBar.ButtonBackgroundColor = Colors.Transparent;
|
appTitleBar.ButtonBackgroundColor = Colors.Transparent;
|
||||||
appTitleBar.ButtonInactiveBackgroundColor = Colors.Transparent;
|
appTitleBar.ButtonInactiveBackgroundColor = Colors.Transparent;
|
||||||
|
|
||||||
@@ -137,8 +159,10 @@ internal sealed class ExtendedWindow<TWindow> : IRecipient<FlyoutOpenCloseMessag
|
|||||||
appTitleBar.ButtonPressedForegroundColor = systemBaseHighColor;
|
appTitleBar.ButtonPressedForegroundColor = systemBaseHighColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateDragRectangles(AppWindowTitleBar appTitleBar, bool isFlyoutOpened = false)
|
private void UpdateDragRectangles(bool isFlyoutOpened = false)
|
||||||
{
|
{
|
||||||
|
AppWindowTitleBar appTitleBar = options.AppWindow.TitleBar;
|
||||||
|
|
||||||
if (isFlyoutOpened)
|
if (isFlyoutOpened)
|
||||||
{
|
{
|
||||||
// set to 0
|
// set to 0
|
||||||
|
|||||||
@@ -1,181 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
using Microsoft.UI.Composition;
|
|
||||||
using Microsoft.UI.Composition.SystemBackdrops;
|
|
||||||
using Microsoft.UI.Xaml;
|
|
||||||
using Snap.Hutao.Control.Theme;
|
|
||||||
using Snap.Hutao.Core.Database;
|
|
||||||
using Snap.Hutao.Model.Entity;
|
|
||||||
using Snap.Hutao.Model.Entity.Database;
|
|
||||||
using Snap.Hutao.Service;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using Windows.System;
|
|
||||||
using WinRT;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Core.Windowing;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 系统背景帮助类
|
|
||||||
/// </summary>
|
|
||||||
internal sealed class SystemBackdrop
|
|
||||||
{
|
|
||||||
private readonly Window window;
|
|
||||||
|
|
||||||
private DispatcherQueueHelper? dispatcherQueueHelper;
|
|
||||||
private ISystemBackdropControllerWithTargets? backdropController;
|
|
||||||
private SystemBackdropConfiguration? configuration;
|
|
||||||
|
|
||||||
private BackdropType type;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 构造一个新的系统背景帮助类
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="window">窗体</param>
|
|
||||||
/// <param name="serviceProvider">服务提供器</param>
|
|
||||||
public SystemBackdrop(Window window, IServiceProvider serviceProvider)
|
|
||||||
{
|
|
||||||
this.window = window;
|
|
||||||
AppOptions appOptions = serviceProvider.GetRequiredService<AppOptions>();
|
|
||||||
type = appOptions.BackdropType;
|
|
||||||
appOptions.PropertyChanged += OnOptionsPropertyChanged;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 尝试设置背景
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>是否设置成功</returns>
|
|
||||||
public bool Update()
|
|
||||||
{
|
|
||||||
bool isSupport = type switch
|
|
||||||
{
|
|
||||||
BackdropType.Acrylic => DesktopAcrylicController.IsSupported(),
|
|
||||||
BackdropType.Mica or BackdropType.MicaAlt => MicaController.IsSupported(),
|
|
||||||
_ => false,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!isSupport)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Previous one
|
|
||||||
if (backdropController != null)
|
|
||||||
{
|
|
||||||
backdropController.RemoveAllSystemBackdropTargets();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dispatcherQueueHelper = new();
|
|
||||||
dispatcherQueueHelper.Ensure();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hooking up the policy object
|
|
||||||
configuration = new()
|
|
||||||
{
|
|
||||||
IsInputActive = true, // Initial configuration state.
|
|
||||||
};
|
|
||||||
SetConfigurationSourceTheme(configuration);
|
|
||||||
|
|
||||||
window.Activated += OnWindowActivated;
|
|
||||||
window.Closed += OnWindowClosed;
|
|
||||||
((FrameworkElement)window.Content).ActualThemeChanged += OnWindowThemeChanged;
|
|
||||||
|
|
||||||
backdropController = type switch
|
|
||||||
{
|
|
||||||
BackdropType.Acrylic => new DesktopAcrylicController(),
|
|
||||||
BackdropType.Mica => new MicaController() { Kind = MicaKind.Base },
|
|
||||||
BackdropType.MicaAlt => new MicaController() { Kind = MicaKind.BaseAlt },
|
|
||||||
_ => throw Must.NeverHappen(),
|
|
||||||
};
|
|
||||||
|
|
||||||
backdropController.AddSystemBackdropTarget(window.As<ICompositionSupportsSystemBackdrop>());
|
|
||||||
backdropController.SetSystemBackdropConfiguration(configuration);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnOptionsPropertyChanged(object? sender, PropertyChangedEventArgs e)
|
|
||||||
{
|
|
||||||
if (e.PropertyName == nameof(AppOptions.BackdropType))
|
|
||||||
{
|
|
||||||
type = ((AppOptions)sender!).BackdropType;
|
|
||||||
Update();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnWindowActivated(object sender, WindowActivatedEventArgs args)
|
|
||||||
{
|
|
||||||
configuration!.IsInputActive = args.WindowActivationState != WindowActivationState.Deactivated;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnWindowClosed(object sender, WindowEventArgs args)
|
|
||||||
{
|
|
||||||
// Make sure any Mica/Acrylic controller is disposed so it doesn't try to
|
|
||||||
// use this closed window.
|
|
||||||
if (backdropController != null)
|
|
||||||
{
|
|
||||||
backdropController.Dispose();
|
|
||||||
backdropController = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
window.Activated -= OnWindowActivated;
|
|
||||||
configuration = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnWindowThemeChanged(FrameworkElement sender, object args)
|
|
||||||
{
|
|
||||||
if (configuration != null)
|
|
||||||
{
|
|
||||||
SetConfigurationSourceTheme(configuration);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetConfigurationSourceTheme(SystemBackdropConfiguration configuration)
|
|
||||||
{
|
|
||||||
configuration.Theme = ThemeHelper.ElementToSystemBackdrop(((FrameworkElement)window.Content).ActualTheme);
|
|
||||||
}
|
|
||||||
|
|
||||||
private class DispatcherQueueHelper
|
|
||||||
{
|
|
||||||
private object? dispatcherQueueController;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 确保系统调度队列控制器存在
|
|
||||||
/// </summary>
|
|
||||||
public unsafe void Ensure()
|
|
||||||
{
|
|
||||||
if (DispatcherQueue.GetForCurrentThread() != null)
|
|
||||||
{
|
|
||||||
// one already exists, so we'll just use it.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dispatcherQueueController == null)
|
|
||||||
{
|
|
||||||
DispatcherQueueOptions options = new()
|
|
||||||
{
|
|
||||||
DwSize = sizeof(DispatcherQueueOptions),
|
|
||||||
ThreadType = 2, // DQTYPE_THREAD_CURRENT
|
|
||||||
ApartmentType = 2, // DQTAT_COM_STA
|
|
||||||
};
|
|
||||||
|
|
||||||
_ = CreateDispatcherQueueController(options, ref dispatcherQueueController);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[DllImport("CoreMessaging.dll")]
|
|
||||||
private static extern int CreateDispatcherQueueController(
|
|
||||||
[In] DispatcherQueueOptions options,
|
|
||||||
[In, Out, MarshalAs(UnmanagedType.IUnknown)] ref object? dispatcherQueueController);
|
|
||||||
|
|
||||||
private struct DispatcherQueueOptions
|
|
||||||
{
|
|
||||||
internal int DwSize;
|
|
||||||
internal int ThreadType;
|
|
||||||
internal int ApartmentType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -41,13 +41,16 @@ internal readonly struct WindowOptions<TWindow>
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly bool UseLegacyDragBarImplementation = !AppWindowTitleBar.IsCustomizationSupported();
|
public readonly bool UseLegacyDragBarImplementation = !AppWindowTitleBar.IsCustomizationSupported();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 构造一个新的窗体选项
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="window">窗体</param>
|
||||||
|
/// <param name="titleBar">标题栏</param>
|
||||||
public WindowOptions(TWindow window, FrameworkElement titleBar)
|
public WindowOptions(TWindow window, FrameworkElement titleBar)
|
||||||
{
|
{
|
||||||
Window = window;
|
Window = window;
|
||||||
Hwnd = (HWND)WindowNative.GetWindowHandle(window);
|
Hwnd = (HWND)WindowNative.GetWindowHandle(window);
|
||||||
WindowId windowId = Win32Interop.GetWindowIdFromWindow(Hwnd);
|
AppWindow = window.AppWindow;
|
||||||
AppWindow = AppWindow.GetFromWindowId(windowId);
|
|
||||||
|
|
||||||
TitleBar = titleBar;
|
TitleBar = titleBar;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,8 @@
|
|||||||
// 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.Database;
|
|
||||||
using Snap.Hutao.Core.ExceptionService;
|
using Snap.Hutao.Core.ExceptionService;
|
||||||
using Snap.Hutao.Model.Entity;
|
using Snap.Hutao.Model.Entity;
|
||||||
using Snap.Hutao.Model.Entity.Database;
|
|
||||||
using Snap.Hutao.Model.Intrinsic;
|
using Snap.Hutao.Model.Intrinsic;
|
||||||
using Snap.Hutao.Model.Metadata;
|
using Snap.Hutao.Model.Metadata;
|
||||||
using Snap.Hutao.Model.Metadata.Avatar;
|
using Snap.Hutao.Model.Metadata.Avatar;
|
||||||
@@ -37,31 +35,22 @@ internal sealed class GachaStatisticsFactory : IGachaStatisticsFactory
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public async Task<GachaStatistics> CreateAsync(IEnumerable<GachaItem> items)
|
public async Task<GachaStatistics> CreateAsync(IOrderedQueryable<GachaItem> items, GachaLogServiceContext context)
|
||||||
{
|
{
|
||||||
Dictionary<AvatarId, Avatar> idAvatarMap = await metadataService.GetIdToAvatarMapAsync().ConfigureAwait(false);
|
|
||||||
Dictionary<WeaponId, Weapon> idWeaponMap = await metadataService.GetIdToWeaponMapAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
Dictionary<string, Avatar> nameAvatarMap = await metadataService.GetNameToAvatarMapAsync().ConfigureAwait(false);
|
|
||||||
Dictionary<string, Weapon> nameWeaponMap = await metadataService.GetNameToWeaponMapAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
List<GachaEvent> gachaEvents = await metadataService.GetGachaEventsAsync().ConfigureAwait(false);
|
List<GachaEvent> gachaEvents = await metadataService.GetGachaEventsAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
List<HistoryWishBuilder> historyWishBuilders = gachaEvents.Select(g => new HistoryWishBuilder(g, nameAvatarMap, nameWeaponMap)).ToList();
|
List<HistoryWishBuilder> historyWishBuilders = gachaEvents.Select(g => new HistoryWishBuilder(g, context)).ToList();
|
||||||
|
|
||||||
IOrderedEnumerable<GachaItem> orderedItems = items.OrderBy(i => i.Id);
|
return CreateCore(items, historyWishBuilders, context, options.IsEmptyHistoryWishVisible);
|
||||||
await ThreadHelper.SwitchToBackgroundAsync();
|
|
||||||
return CreateCore(orderedItems, historyWishBuilders, idAvatarMap, idWeaponMap, options.IsEmptyHistoryWishVisible);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static GachaStatistics CreateCore(
|
private static GachaStatistics CreateCore(
|
||||||
IOrderedEnumerable<GachaItem> items,
|
IOrderedQueryable<GachaItem> items,
|
||||||
List<HistoryWishBuilder> historyWishBuilders,
|
List<HistoryWishBuilder> historyWishBuilders,
|
||||||
Dictionary<AvatarId, Avatar> avatarMap,
|
GachaLogServiceContext context,
|
||||||
Dictionary<WeaponId, Weapon> weaponMap,
|
|
||||||
bool isEmptyHistoryWishVisible)
|
bool isEmptyHistoryWishVisible)
|
||||||
{
|
{
|
||||||
TypedWishSummaryBuilder standardWishBuilder = new(SH.ServiceGachaLogFactoryPermanentWishName, TypedWishSummaryBuilder.IsPermanentWish, 90, 10);
|
TypedWishSummaryBuilder standardWishBuilder = new(SH.ServiceGachaLogFactoryPermanentWishName, TypedWishSummaryBuilder.IsStandardWish, 90, 10);
|
||||||
TypedWishSummaryBuilder avatarWishBuilder = new(SH.ServiceGachaLogFactoryAvatarWishName, TypedWishSummaryBuilder.IsAvatarEventWish, 90, 10);
|
TypedWishSummaryBuilder avatarWishBuilder = new(SH.ServiceGachaLogFactoryAvatarWishName, TypedWishSummaryBuilder.IsAvatarEventWish, 90, 10);
|
||||||
TypedWishSummaryBuilder weaponWishBuilder = new(SH.ServiceGachaLogFactoryWeaponWishName, TypedWishSummaryBuilder.IsWeaponEventWish, 80, 10);
|
TypedWishSummaryBuilder weaponWishBuilder = new(SH.ServiceGachaLogFactoryWeaponWishName, TypedWishSummaryBuilder.IsWeaponEventWish, 80, 10);
|
||||||
|
|
||||||
@@ -81,58 +70,62 @@ internal sealed class GachaStatisticsFactory : IGachaStatisticsFactory
|
|||||||
.SingleOrDefault(w => w.From <= item.Time && w.To >= item.Time);
|
.SingleOrDefault(w => w.From <= item.Time && w.To >= item.Time);
|
||||||
|
|
||||||
// It's an avatar
|
// It's an avatar
|
||||||
if (item.ItemId.Place() == 8)
|
switch (item.ItemId.Place())
|
||||||
{
|
{
|
||||||
Avatar avatar = avatarMap[item.ItemId];
|
case 8:
|
||||||
|
{
|
||||||
|
Avatar avatar = context.IdAvatarMap[item.ItemId];
|
||||||
|
|
||||||
bool isUp = false;
|
bool isUp = false;
|
||||||
switch (avatar.Quality)
|
switch (avatar.Quality)
|
||||||
{
|
{
|
||||||
case ItemQuality.QUALITY_ORANGE:
|
case ItemQuality.QUALITY_ORANGE:
|
||||||
orangeAvatarCounter.Increase(avatar);
|
orangeAvatarCounter.Increase(avatar);
|
||||||
isUp = targetHistoryWishBuilder?.IncreaseOrange(avatar) ?? false;
|
isUp = targetHistoryWishBuilder?.IncreaseOrange(avatar) ?? false;
|
||||||
break;
|
break;
|
||||||
case ItemQuality.QUALITY_PURPLE:
|
case ItemQuality.QUALITY_PURPLE:
|
||||||
purpleAvatarCounter.Increase(avatar);
|
purpleAvatarCounter.Increase(avatar);
|
||||||
targetHistoryWishBuilder?.IncreasePurple(avatar);
|
targetHistoryWishBuilder?.IncreasePurple(avatar);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
standardWishBuilder.Track(item, avatar, isUp);
|
standardWishBuilder.Track(item, avatar, isUp);
|
||||||
avatarWishBuilder.Track(item, avatar, isUp);
|
avatarWishBuilder.Track(item, avatar, isUp);
|
||||||
weaponWishBuilder.Track(item, avatar, isUp);
|
weaponWishBuilder.Track(item, avatar, isUp);
|
||||||
}
|
|
||||||
|
|
||||||
// It's a weapon
|
|
||||||
else if (item.ItemId.Place() == 5)
|
|
||||||
{
|
|
||||||
Weapon weapon = weaponMap[item.ItemId];
|
|
||||||
|
|
||||||
bool isUp = false;
|
|
||||||
switch (weapon.RankLevel)
|
|
||||||
{
|
|
||||||
case ItemQuality.QUALITY_ORANGE:
|
|
||||||
isUp = targetHistoryWishBuilder?.IncreaseOrange(weapon) ?? false;
|
|
||||||
orangeWeaponCounter.Increase(weapon);
|
|
||||||
break;
|
break;
|
||||||
case ItemQuality.QUALITY_PURPLE:
|
}
|
||||||
targetHistoryWishBuilder?.IncreasePurple(weapon);
|
|
||||||
purpleWeaponCounter.Increase(weapon);
|
|
||||||
break;
|
|
||||||
case ItemQuality.QUALITY_BLUE:
|
|
||||||
targetHistoryWishBuilder?.IncreaseBlue(weapon);
|
|
||||||
blueWeaponCounter.Increase(weapon);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
standardWishBuilder.Track(item, weapon, isUp);
|
case 5:
|
||||||
avatarWishBuilder.Track(item, weapon, isUp);
|
{
|
||||||
weaponWishBuilder.Track(item, weapon, isUp);
|
Weapon weapon = context.IdWeaponMap[item.ItemId];
|
||||||
}
|
|
||||||
else
|
bool isUp = false;
|
||||||
{
|
switch (weapon.RankLevel)
|
||||||
// ItemId place not correct.
|
{
|
||||||
ThrowHelper.UserdataCorrupted(string.Format(SH.ServiceGachaStatisticsFactoryItemIdInvalid, item.ItemId), null!);
|
case ItemQuality.QUALITY_ORANGE:
|
||||||
|
isUp = targetHistoryWishBuilder?.IncreaseOrange(weapon) ?? false;
|
||||||
|
orangeWeaponCounter.Increase(weapon);
|
||||||
|
break;
|
||||||
|
case ItemQuality.QUALITY_PURPLE:
|
||||||
|
targetHistoryWishBuilder?.IncreasePurple(weapon);
|
||||||
|
purpleWeaponCounter.Increase(weapon);
|
||||||
|
break;
|
||||||
|
case ItemQuality.QUALITY_BLUE:
|
||||||
|
targetHistoryWishBuilder?.IncreaseBlue(weapon);
|
||||||
|
blueWeaponCounter.Increase(weapon);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
standardWishBuilder.Track(item, weapon, isUp);
|
||||||
|
avatarWishBuilder.Track(item, weapon, isUp);
|
||||||
|
weaponWishBuilder.Track(item, weapon, isUp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
// ItemId place not correct.
|
||||||
|
ThrowHelper.UserdataCorrupted(string.Format(SH.ServiceGachaStatisticsFactoryItemIdInvalid, item.ItemId), null!);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Model.Entity;
|
||||||
|
using Snap.Hutao.Model.Intrinsic;
|
||||||
|
using Snap.Hutao.Model.Metadata.Abstraction;
|
||||||
|
using Snap.Hutao.ViewModel.GachaLog;
|
||||||
|
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Service.GachaLog.Factory;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 简化的祈愿统计工厂
|
||||||
|
/// </summary>
|
||||||
|
[Injection(InjectAs.Scoped, typeof(IGachaStatisticsSlimFactory))]
|
||||||
|
internal sealed class GachaStatisticsSlimFactory : IGachaStatisticsSlimFactory
|
||||||
|
{
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public async Task<GachaStatisticsSlim> CreateAsync(IOrderedQueryable<GachaItem> items, GachaLogServiceContext context)
|
||||||
|
{
|
||||||
|
await ThreadHelper.SwitchToBackgroundAsync();
|
||||||
|
|
||||||
|
int standardOrangeTracker = 0;
|
||||||
|
int standardPurpleTracker = 0;
|
||||||
|
TypedWishSummarySlim standardWish = new(SH.ServiceGachaLogFactoryPermanentWishName, 90, 10);
|
||||||
|
|
||||||
|
int avatarOrangeTracker = 0;
|
||||||
|
int avatarPurpleTracker = 0;
|
||||||
|
TypedWishSummarySlim avatarWish = new(SH.ServiceGachaLogFactoryAvatarWishName, 90, 10);
|
||||||
|
|
||||||
|
int weaponOrangeTracker = 0;
|
||||||
|
int weaponPurpleTracker = 0;
|
||||||
|
TypedWishSummarySlim weaponWish = new(SH.ServiceGachaLogFactoryWeaponWishName, 80, 10);
|
||||||
|
|
||||||
|
// O(n) operation
|
||||||
|
foreach (GachaItem item in items)
|
||||||
|
{
|
||||||
|
INameQuality nameQuality = context.GetNameQualityByItemId(item.ItemId);
|
||||||
|
switch (item.QueryType)
|
||||||
|
{
|
||||||
|
case GachaConfigType.StandardWish:
|
||||||
|
Track(nameQuality, ref standardOrangeTracker, ref standardPurpleTracker);
|
||||||
|
break;
|
||||||
|
case GachaConfigType.AvatarEventWish:
|
||||||
|
case GachaConfigType.AvatarEventWish2:
|
||||||
|
Track(nameQuality, ref avatarOrangeTracker, ref avatarPurpleTracker);
|
||||||
|
break;
|
||||||
|
case GachaConfigType.WeaponEventWish:
|
||||||
|
Track(nameQuality, ref weaponOrangeTracker, ref weaponPurpleTracker);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
standardWish.LastOrangePull = standardOrangeTracker;
|
||||||
|
standardWish.LastPurplePull = standardPurpleTracker;
|
||||||
|
avatarWish.LastOrangePull = avatarOrangeTracker;
|
||||||
|
avatarWish.LastPurplePull = avatarPurpleTracker;
|
||||||
|
weaponWish.LastOrangePull = weaponOrangeTracker;
|
||||||
|
weaponWish.LastPurplePull = weaponPurpleTracker;
|
||||||
|
|
||||||
|
return new()
|
||||||
|
{
|
||||||
|
AvatarWish = avatarWish,
|
||||||
|
WeaponWish = weaponWish,
|
||||||
|
StandardWish = standardWish,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Track(INameQuality nameQuality, ref int orangeTracker, ref int purpleTracker)
|
||||||
|
{
|
||||||
|
switch (nameQuality.Quality)
|
||||||
|
{
|
||||||
|
case ItemQuality.QUALITY_ORANGE:
|
||||||
|
orangeTracker = 0;
|
||||||
|
++purpleTracker;
|
||||||
|
break;
|
||||||
|
case ItemQuality.QUALITY_PURPLE:
|
||||||
|
++orangeTracker;
|
||||||
|
purpleTracker = 0;
|
||||||
|
break;
|
||||||
|
case ItemQuality.QUALITY_BLUE:
|
||||||
|
++orangeTracker;
|
||||||
|
++purpleTracker;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -31,22 +31,21 @@ internal sealed class HistoryWishBuilder
|
|||||||
/// 构造一个新的卡池历史记录建造器
|
/// 构造一个新的卡池历史记录建造器
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="gachaEvent">卡池配置</param>
|
/// <param name="gachaEvent">卡池配置</param>
|
||||||
/// <param name="nameAvatarMap">命名角色映射</param>
|
/// <param name="context">祈愿记录上下文</param>
|
||||||
/// <param name="nameWeaponMap">命名武器映射</param>
|
public HistoryWishBuilder(GachaEvent gachaEvent, GachaLogServiceContext context)
|
||||||
public HistoryWishBuilder(GachaEvent gachaEvent, Dictionary<string, Avatar> nameAvatarMap, Dictionary<string, Weapon> nameWeaponMap)
|
|
||||||
{
|
{
|
||||||
this.gachaEvent = gachaEvent;
|
this.gachaEvent = gachaEvent;
|
||||||
configType = gachaEvent.Type;
|
configType = gachaEvent.Type;
|
||||||
|
|
||||||
if (configType == GachaConfigType.AvatarEventWish || configType == GachaConfigType.AvatarEventWish2)
|
if (configType == GachaConfigType.AvatarEventWish || configType == GachaConfigType.AvatarEventWish2)
|
||||||
{
|
{
|
||||||
orangeUpCounter = gachaEvent.UpOrangeList.Select(name => nameAvatarMap[name]).ToDictionary(a => (IStatisticsItemSource)a, a => 0);
|
orangeUpCounter = gachaEvent.UpOrangeList.Select(name => context.NameAvatarMap[name]).ToDictionary(a => (IStatisticsItemSource)a, a => 0);
|
||||||
purpleUpCounter = gachaEvent.UpPurpleList.Select(name => nameAvatarMap[name]).ToDictionary(a => (IStatisticsItemSource)a, a => 0);
|
purpleUpCounter = gachaEvent.UpPurpleList.Select(name => context.NameAvatarMap[name]).ToDictionary(a => (IStatisticsItemSource)a, a => 0);
|
||||||
}
|
}
|
||||||
else if (configType == GachaConfigType.WeaponEventWish)
|
else if (configType == GachaConfigType.WeaponEventWish)
|
||||||
{
|
{
|
||||||
orangeUpCounter = gachaEvent.UpOrangeList.Select(name => nameWeaponMap[name]).ToDictionary(w => (IStatisticsItemSource)w, w => 0);
|
orangeUpCounter = gachaEvent.UpOrangeList.Select(name => context.NameWeaponMap[name]).ToDictionary(w => (IStatisticsItemSource)w, w => 0);
|
||||||
purpleUpCounter = gachaEvent.UpPurpleList.Select(name => nameWeaponMap[name]).ToDictionary(w => (IStatisticsItemSource)w, w => 0);
|
purpleUpCounter = gachaEvent.UpPurpleList.Select(name => context.NameWeaponMap[name]).ToDictionary(w => (IStatisticsItemSource)w, w => 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ internal interface IGachaStatisticsFactory
|
|||||||
/// 异步创建祈愿统计对象
|
/// 异步创建祈愿统计对象
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="items">物品列表</param>
|
/// <param name="items">物品列表</param>
|
||||||
|
/// <param name="context">祈愿记录上下文</param>
|
||||||
/// <returns>祈愿统计对象</returns>
|
/// <returns>祈愿统计对象</returns>
|
||||||
Task<GachaStatistics> CreateAsync(IEnumerable<GachaItem> items);
|
Task<GachaStatistics> CreateAsync(IOrderedQueryable<GachaItem> items, GachaLogServiceContext context);
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Model.Entity;
|
||||||
|
using Snap.Hutao.ViewModel.GachaLog;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Service.GachaLog.Factory;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 简化的祈愿统计工厂
|
||||||
|
/// </summary>
|
||||||
|
internal interface IGachaStatisticsSlimFactory
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 异步创建一个新的简化的祈愿统计
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="items">排序的物品</param>
|
||||||
|
/// <param name="context">祈愿记录服务上下文</param>
|
||||||
|
/// <returns>简化的祈愿统计</returns>
|
||||||
|
Task<GachaStatisticsSlim> CreateAsync(IOrderedQueryable<GachaItem> items, GachaLogServiceContext context);
|
||||||
|
}
|
||||||
@@ -18,7 +18,7 @@ internal sealed class TypedWishSummaryBuilder
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 常驻祈愿
|
/// 常驻祈愿
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static readonly Func<GachaConfigType, bool> IsPermanentWish = type => type is GachaConfigType.StandardWish;
|
public static readonly Func<GachaConfigType, bool> IsStandardWish = type => type is GachaConfigType.StandardWish;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 角色活动
|
/// 角色活动
|
||||||
|
|||||||
@@ -1,26 +1,10 @@
|
|||||||
// 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.Data.Sqlite;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Snap.Hutao.Core.Database;
|
using Snap.Hutao.Core.Database;
|
||||||
using Snap.Hutao.Core.Diagnostics;
|
|
||||||
using Snap.Hutao.Core.ExceptionService;
|
|
||||||
using Snap.Hutao.Model.Binding;
|
|
||||||
using Snap.Hutao.Model.Entity;
|
using Snap.Hutao.Model.Entity;
|
||||||
using Snap.Hutao.Model.Entity.Database;
|
using Snap.Hutao.Model.Entity.Database;
|
||||||
using Snap.Hutao.Model.InterChange.GachaLog;
|
using Snap.Hutao.Model.InterChange.GachaLog;
|
||||||
using Snap.Hutao.Model.Metadata.Abstraction;
|
|
||||||
using Snap.Hutao.Model.Primitive;
|
|
||||||
using Snap.Hutao.Service.GachaLog.Factory;
|
|
||||||
using Snap.Hutao.Service.GachaLog.QueryProvider;
|
|
||||||
using Snap.Hutao.Service.Metadata;
|
|
||||||
using Snap.Hutao.ViewModel.GachaLog;
|
|
||||||
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
|
||||||
using Snap.Hutao.Web.Response;
|
|
||||||
using System.Collections.Immutable;
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Service.GachaLog;
|
namespace Snap.Hutao.Service.GachaLog;
|
||||||
|
|
||||||
@@ -61,19 +45,9 @@ internal sealed class GachaLogImportService : IGachaLogImportService
|
|||||||
IEnumerable<GachaItem> toAdd = list
|
IEnumerable<GachaItem> toAdd = list
|
||||||
.OrderByDescending(i => i.Id)
|
.OrderByDescending(i => i.Id)
|
||||||
.Where(i => i.Id < trimId)
|
.Where(i => i.Id < trimId)
|
||||||
.Select(i => GachaItem.Create(archiveId, i, GetItemId(context, i)));
|
.Select(i => GachaItem.Create(archiveId, i, context.GetItemId(i)));
|
||||||
|
|
||||||
await appDbContext.GachaItems.AddRangeAndSaveAsync(toAdd).ConfigureAwait(false);
|
await appDbContext.GachaItems.AddRangeAndSaveAsync(toAdd).ConfigureAwait(false);
|
||||||
return archive;
|
return archive;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int GetItemId(GachaLogServiceContext context, GachaLogItem item)
|
|
||||||
{
|
|
||||||
return item.ItemType switch
|
|
||||||
{
|
|
||||||
"角色" => context.NameAvatarMap.GetValueOrDefault(item.Name)?.Id ?? 0,
|
|
||||||
"武器" => context.NameWeaponMap.GetValueOrDefault(item.Name)?.Id ?? 0,
|
|
||||||
_ => 0,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -34,11 +34,10 @@ internal sealed class GachaLogService : IGachaLogService
|
|||||||
private readonly AppDbContext appDbContext;
|
private readonly AppDbContext appDbContext;
|
||||||
private readonly IGachaLogExportService gachaLogExportService;
|
private readonly IGachaLogExportService gachaLogExportService;
|
||||||
private readonly IGachaLogImportService gachaLogImportService;
|
private readonly IGachaLogImportService gachaLogImportService;
|
||||||
|
|
||||||
private readonly IEnumerable<IGachaLogQueryProvider> urlProviders;
|
|
||||||
private readonly GachaInfoClient gachaInfoClient;
|
private readonly GachaInfoClient gachaInfoClient;
|
||||||
private readonly IMetadataService metadataService;
|
private readonly IMetadataService metadataService;
|
||||||
private readonly IGachaStatisticsFactory gachaStatisticsFactory;
|
private readonly IGachaStatisticsFactory gachaStatisticsFactory;
|
||||||
|
private readonly IGachaStatisticsSlimFactory gachaStatisticsSlimFactory;
|
||||||
private readonly ILogger<GachaLogService> logger;
|
private readonly ILogger<GachaLogService> logger;
|
||||||
private readonly DbCurrent<GachaArchive, Message.GachaArchiveChangedMessage> dbCurrent;
|
private readonly DbCurrent<GachaArchive, Message.GachaArchiveChangedMessage> dbCurrent;
|
||||||
|
|
||||||
@@ -48,32 +47,17 @@ internal sealed class GachaLogService : IGachaLogService
|
|||||||
/// 构造一个新的祈愿记录服务
|
/// 构造一个新的祈愿记录服务
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="serviceProvider">服务提供器</param>
|
/// <param name="serviceProvider">服务提供器</param>
|
||||||
/// <param name="appDbContext">数据库上下文</param>
|
|
||||||
/// <param name="urlProviders">Url提供器集合</param>
|
|
||||||
/// <param name="gachaInfoClient">祈愿记录客户端</param>
|
|
||||||
/// <param name="metadataService">元数据服务</param>
|
|
||||||
/// <param name="gachaStatisticsFactory">祈愿统计工厂</param>
|
|
||||||
/// <param name="logger">日志器</param>
|
|
||||||
/// <param name="messenger">消息器</param>
|
/// <param name="messenger">消息器</param>
|
||||||
public GachaLogService(
|
public GachaLogService(IServiceProvider serviceProvider, IMessenger messenger)
|
||||||
IServiceProvider serviceProvider,
|
|
||||||
AppDbContext appDbContext,
|
|
||||||
IEnumerable<IGachaLogQueryProvider> urlProviders,
|
|
||||||
GachaInfoClient gachaInfoClient,
|
|
||||||
IMetadataService metadataService,
|
|
||||||
IGachaStatisticsFactory gachaStatisticsFactory,
|
|
||||||
ILogger<GachaLogService> logger,
|
|
||||||
IMessenger messenger)
|
|
||||||
{
|
{
|
||||||
gachaLogExportService = serviceProvider.GetRequiredService<IGachaLogExportService>();
|
gachaLogExportService = serviceProvider.GetRequiredService<IGachaLogExportService>();
|
||||||
gachaLogImportService = serviceProvider.GetRequiredService<IGachaLogImportService>();
|
gachaLogImportService = serviceProvider.GetRequiredService<IGachaLogImportService>();
|
||||||
|
appDbContext = serviceProvider.GetRequiredService<AppDbContext>();
|
||||||
this.appDbContext = appDbContext;
|
gachaInfoClient = serviceProvider.GetRequiredService<GachaInfoClient>();
|
||||||
this.urlProviders = urlProviders;
|
metadataService = serviceProvider.GetRequiredService<IMetadataService>();
|
||||||
this.gachaInfoClient = gachaInfoClient;
|
logger = serviceProvider.GetRequiredService<ILogger<GachaLogService>>();
|
||||||
this.metadataService = metadataService;
|
gachaStatisticsFactory = serviceProvider.GetRequiredService<IGachaStatisticsFactory>();
|
||||||
this.logger = logger;
|
gachaStatisticsSlimFactory = serviceProvider.GetRequiredService<IGachaStatisticsSlimFactory>();
|
||||||
this.gachaStatisticsFactory = gachaStatisticsFactory;
|
|
||||||
|
|
||||||
dbCurrent = new(appDbContext.GachaArchives, messenger);
|
dbCurrent = new(appDbContext.GachaArchives, messenger);
|
||||||
}
|
}
|
||||||
@@ -127,8 +111,8 @@ internal sealed class GachaLogService : IGachaLogService
|
|||||||
{
|
{
|
||||||
using (ValueStopwatch.MeasureExecution(logger))
|
using (ValueStopwatch.MeasureExecution(logger))
|
||||||
{
|
{
|
||||||
IQueryable<GachaItem> items = appDbContext.GachaItems.Where(i => i.ArchiveId == archive.InnerId);
|
IOrderedQueryable<GachaItem> items = appDbContext.GachaItems.Where(i => i.ArchiveId == archive.InnerId).OrderBy(i => i.Id);
|
||||||
return await gachaStatisticsFactory.CreateAsync(items).ConfigureAwait(false);
|
return await gachaStatisticsFactory.CreateAsync(items, context).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -137,6 +121,24 @@ internal sealed class GachaLogService : IGachaLogService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public async Task<List<GachaStatisticsSlim>> GetStatisticsSlimsAsync()
|
||||||
|
{
|
||||||
|
List<GachaStatisticsSlim> statistics = new();
|
||||||
|
foreach (GachaArchive archive in appDbContext.GachaArchives)
|
||||||
|
{
|
||||||
|
IOrderedQueryable<GachaItem> items = appDbContext.GachaItems
|
||||||
|
.Where(i => i.ArchiveId == archive.InnerId)
|
||||||
|
.OrderBy(i => i.Id);
|
||||||
|
|
||||||
|
GachaStatisticsSlim slim = await gachaStatisticsSlimFactory.CreateAsync(items, context).ConfigureAwait(false);
|
||||||
|
slim.Uid = archive.Uid;
|
||||||
|
statistics.Add(slim);
|
||||||
|
}
|
||||||
|
|
||||||
|
return statistics;
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public Task<UIGF> ExportToUIGFAsync(GachaArchive archive)
|
public Task<UIGF> ExportToUIGFAsync(GachaArchive archive)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -40,6 +40,12 @@ internal interface IGachaLogService
|
|||||||
/// <returns>祈愿统计</returns>
|
/// <returns>祈愿统计</returns>
|
||||||
Task<GachaStatistics> GetStatisticsAsync(GachaArchive? archive);
|
Task<GachaStatistics> GetStatisticsAsync(GachaArchive? archive);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步获取简化的祈愿统计列表
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>简化的祈愿统计列表</returns>
|
||||||
|
Task<List<GachaStatisticsSlim>> GetStatisticsSlimsAsync();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异步从UIGF导入数据
|
/// 异步从UIGF导入数据
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ internal sealed class HutaoUserOptions : ObservableObject, IOptions<HutaoUserOpt
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 真正的用户名
|
/// 真正的用户名
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string? ActualUserName { get => IsLoggedIn ? null : UserName; }
|
public string? ActualUserName { get => IsLoggedIn ? UserName : null; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 访问令牌
|
/// 访问令牌
|
||||||
|
|||||||
@@ -51,7 +51,6 @@ internal sealed class HutaoUserService : IHutaoUserService, IHutaoUserServiceIni
|
|||||||
{
|
{
|
||||||
await ThreadHelper.SwitchToMainThreadAsync();
|
await ThreadHelper.SwitchToMainThreadAsync();
|
||||||
options.LoginSucceed(userName, response.Data);
|
options.LoginSucceed(userName, response.Data);
|
||||||
|
|
||||||
isInitialized = true;
|
isInitialized = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -106,12 +106,15 @@
|
|||||||
<None Remove="Resource\Segoe Fluent Icons.ttf" />
|
<None Remove="Resource\Segoe Fluent Icons.ttf" />
|
||||||
<None Remove="Resource\WelcomeView_Background.png" />
|
<None Remove="Resource\WelcomeView_Background.png" />
|
||||||
<None Remove="stylecop.json" />
|
<None Remove="stylecop.json" />
|
||||||
|
<None Remove="View\Card\GachaStatisticsCard.xaml" />
|
||||||
|
<None Remove="View\Card\LaunchGameCard.xaml" />
|
||||||
<None Remove="View\Control\BaseValueSlider.xaml" />
|
<None Remove="View\Control\BaseValueSlider.xaml" />
|
||||||
<None Remove="View\Control\BottomTextControl.xaml" />
|
<None Remove="View\Control\BottomTextControl.xaml" />
|
||||||
<None Remove="View\Control\DescParamComboBox.xaml" />
|
<None Remove="View\Control\DescParamComboBox.xaml" />
|
||||||
<None Remove="View\Control\ItemIcon.xaml" />
|
<None Remove="View\Control\ItemIcon.xaml" />
|
||||||
<None Remove="View\Control\LaunchGameResourceExpander.xaml" />
|
<None Remove="View\Control\LaunchGameResourceExpander.xaml" />
|
||||||
<None Remove="View\Control\LoadingView.xaml" />
|
<None Remove="View\Control\LoadingView.xaml" />
|
||||||
|
<None Remove="View\Control\LoadingViewSlim.xaml" />
|
||||||
<None Remove="View\Control\SkillPivot.xaml" />
|
<None Remove="View\Control\SkillPivot.xaml" />
|
||||||
<None Remove="View\Control\StatisticsCard.xaml" />
|
<None Remove="View\Control\StatisticsCard.xaml" />
|
||||||
<None Remove="View\Dialog\AchievementArchiveCreateDialog.xaml" />
|
<None Remove="View\Dialog\AchievementArchiveCreateDialog.xaml" />
|
||||||
@@ -236,8 +239,8 @@
|
|||||||
<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="7.0.4" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.5" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.4">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.5">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
@@ -254,7 +257,7 @@
|
|||||||
<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.22621.756" />
|
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.756" />
|
||||||
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.2.230313.1" />
|
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.3.230331000" />
|
||||||
<PackageReference Include="StyleCop.Analyzers.Unstable" Version="1.2.0.435">
|
<PackageReference Include="StyleCop.Analyzers.Unstable" Version="1.2.0.435">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
@@ -293,6 +296,18 @@
|
|||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Page Update="View\Card\GachaStatisticsCard.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Page Update="View\Control\LoadingViewSlim.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Page Update="View\Page\HutaoPassportPage.xaml">
|
<Page Update="View\Page\HutaoPassportPage.xaml">
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
@@ -540,4 +555,9 @@
|
|||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
</Page>
|
</Page>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Page Update="View\Card\LaunchGameCard.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
286
src/Snap.Hutao/Snap.Hutao/View/Card/GachaStatisticsCard.xaml
Normal file
286
src/Snap.Hutao/Snap.Hutao/View/Card/GachaStatisticsCard.xaml
Normal file
@@ -0,0 +1,286 @@
|
|||||||
|
<Button
|
||||||
|
x:Class="Snap.Hutao.View.Card.GachaStatisticsCard"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:mxi="using:Microsoft.Xaml.Interactivity"
|
||||||
|
xmlns:shcb="using:Snap.Hutao.Control.Behavior"
|
||||||
|
xmlns:shcm="using:Snap.Hutao.Control.Markup"
|
||||||
|
xmlns:shvco="using:Snap.Hutao.View.Control"
|
||||||
|
xmlns:shvg="using:Snap.Hutao.ViewModel.GachaLog"
|
||||||
|
Padding="0"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
|
HorizontalContentAlignment="Stretch"
|
||||||
|
d:DataContext="{d:DesignInstance shvg:GachaLogViewModelSlim}"
|
||||||
|
Style="{ThemeResource DefaultButtonStyle}"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
|
||||||
|
<mxi:Interaction.Behaviors>
|
||||||
|
<shcb:InvokeCommandOnLoadedBehavior Command="{Binding OpenUICommand}"/>
|
||||||
|
</mxi:Interaction.Behaviors>
|
||||||
|
<Grid>
|
||||||
|
<FlipView
|
||||||
|
Background="{x:Null}"
|
||||||
|
ItemsSource="{Binding StatisticsList}"
|
||||||
|
Visibility="{Binding IsInitialized, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||||
|
<FlipView.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<Grid Margin="12" ColumnSpacing="6">
|
||||||
|
<Grid.Resources>
|
||||||
|
<SolidColorBrush x:Key="PurpleBrush" Color="#FFA156E0"/>
|
||||||
|
<SolidColorBrush x:Key="OrangeBrush" Color="#FFBC6932"/>
|
||||||
|
</Grid.Resources>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition/>
|
||||||
|
<RowDefinition Height="auto"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition/>
|
||||||
|
<ColumnDefinition/>
|
||||||
|
<ColumnDefinition/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<StackPanel Grid.Column="0" DataContext="{Binding AvatarWish}">
|
||||||
|
<TextBlock
|
||||||
|
Margin="0,0,0,6"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
Style="{StaticResource BaseTextBlockStyle}"
|
||||||
|
Text="{Binding Name}"
|
||||||
|
TextTrimming="CharacterEllipsis"
|
||||||
|
TextWrapping="NoWrap"/>
|
||||||
|
|
||||||
|
<Border Grid.Column="0" Style="{StaticResource BorderCardStyle}">
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="auto"/>
|
||||||
|
<ColumnDefinition/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<ProgressRing
|
||||||
|
Grid.Column="0"
|
||||||
|
Width="40"
|
||||||
|
Height="40"
|
||||||
|
Margin="4"
|
||||||
|
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||||
|
Foreground="{StaticResource OrangeBrush}"
|
||||||
|
IsIndeterminate="False"
|
||||||
|
Maximum="{Binding GuaranteeOrangeThreshold}"
|
||||||
|
Value="{Binding LastOrangePull}"/>
|
||||||
|
<TextBlock
|
||||||
|
Grid.Column="0"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Foreground="{StaticResource OrangeBrush}"
|
||||||
|
Style="{StaticResource BodyTextBlockStyle}"
|
||||||
|
Text="{Binding LastOrangePull}"/>
|
||||||
|
<TextBlock
|
||||||
|
Grid.Column="1"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Foreground="{StaticResource OrangeBrush}"
|
||||||
|
Style="{StaticResource BaseTextBlockStyle}"
|
||||||
|
Text="{shcm:ResourceString Name=ViewControlStatisticsCardOrangeText}"/>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
<Border
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="0,6,0,0"
|
||||||
|
Style="{StaticResource BorderCardStyle}">
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="auto"/>
|
||||||
|
<ColumnDefinition/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<ProgressRing
|
||||||
|
Grid.Column="0"
|
||||||
|
Width="40"
|
||||||
|
Height="40"
|
||||||
|
Margin="4"
|
||||||
|
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||||
|
Foreground="{StaticResource PurpleBrush}"
|
||||||
|
IsIndeterminate="False"
|
||||||
|
Maximum="{Binding GuaranteePurpleThreshold}"
|
||||||
|
Value="{Binding LastPurplePull}"/>
|
||||||
|
<TextBlock
|
||||||
|
Grid.Column="0"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Foreground="{StaticResource PurpleBrush}"
|
||||||
|
Style="{StaticResource BodyTextBlockStyle}"
|
||||||
|
Text="{Binding LastPurplePull}"/>
|
||||||
|
<TextBlock
|
||||||
|
Grid.Column="1"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Foreground="{StaticResource PurpleBrush}"
|
||||||
|
Style="{StaticResource BaseTextBlockStyle}"
|
||||||
|
Text="{shcm:ResourceString Name=ViewControlStatisticsCardPurpleText}"/>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Grid.Column="1" DataContext="{Binding WeaponWish}">
|
||||||
|
<TextBlock
|
||||||
|
Margin="0,0,0,6"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
Style="{StaticResource BaseTextBlockStyle}"
|
||||||
|
Text="{Binding Name}"
|
||||||
|
TextTrimming="CharacterEllipsis"
|
||||||
|
TextWrapping="NoWrap"/>
|
||||||
|
|
||||||
|
<Border Grid.Column="0" Style="{StaticResource BorderCardStyle}">
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="auto"/>
|
||||||
|
<ColumnDefinition/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<ProgressRing
|
||||||
|
Grid.Column="0"
|
||||||
|
Width="40"
|
||||||
|
Height="40"
|
||||||
|
Margin="4"
|
||||||
|
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||||
|
Foreground="{StaticResource OrangeBrush}"
|
||||||
|
IsIndeterminate="False"
|
||||||
|
Maximum="{Binding GuaranteeOrangeThreshold}"
|
||||||
|
Value="{Binding LastOrangePull}"/>
|
||||||
|
<TextBlock
|
||||||
|
Grid.Column="0"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Foreground="{StaticResource OrangeBrush}"
|
||||||
|
Style="{StaticResource BodyTextBlockStyle}"
|
||||||
|
Text="{Binding LastOrangePull}"/>
|
||||||
|
<TextBlock
|
||||||
|
Grid.Column="1"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Foreground="{StaticResource OrangeBrush}"
|
||||||
|
Style="{StaticResource BaseTextBlockStyle}"
|
||||||
|
Text="{shcm:ResourceString Name=ViewControlStatisticsCardOrangeText}"/>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
<Border
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="0,6,0,0"
|
||||||
|
Style="{StaticResource BorderCardStyle}">
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="auto"/>
|
||||||
|
<ColumnDefinition/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<ProgressRing
|
||||||
|
Grid.Column="0"
|
||||||
|
Width="40"
|
||||||
|
Height="40"
|
||||||
|
Margin="4"
|
||||||
|
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||||
|
Foreground="{StaticResource PurpleBrush}"
|
||||||
|
IsIndeterminate="False"
|
||||||
|
Maximum="{Binding GuaranteePurpleThreshold}"
|
||||||
|
Value="{Binding LastPurplePull}"/>
|
||||||
|
<TextBlock
|
||||||
|
Grid.Column="0"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Foreground="{StaticResource PurpleBrush}"
|
||||||
|
Style="{StaticResource BodyTextBlockStyle}"
|
||||||
|
Text="{Binding LastPurplePull}"/>
|
||||||
|
<TextBlock
|
||||||
|
Grid.Column="1"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Foreground="{StaticResource PurpleBrush}"
|
||||||
|
Style="{StaticResource BaseTextBlockStyle}"
|
||||||
|
Text="{shcm:ResourceString Name=ViewControlStatisticsCardPurpleText}"/>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Grid.Column="2" DataContext="{Binding StandardWish}">
|
||||||
|
<TextBlock
|
||||||
|
Margin="0,0,0,6"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
Style="{StaticResource BaseTextBlockStyle}"
|
||||||
|
Text="{Binding Name}"
|
||||||
|
TextTrimming="CharacterEllipsis"
|
||||||
|
TextWrapping="NoWrap"/>
|
||||||
|
|
||||||
|
<Border Grid.Column="0" Style="{StaticResource BorderCardStyle}">
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="auto"/>
|
||||||
|
<ColumnDefinition/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<ProgressRing
|
||||||
|
Grid.Column="0"
|
||||||
|
Width="40"
|
||||||
|
Height="40"
|
||||||
|
Margin="4"
|
||||||
|
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||||
|
Foreground="{StaticResource OrangeBrush}"
|
||||||
|
IsIndeterminate="False"
|
||||||
|
Maximum="{Binding GuaranteeOrangeThreshold}"
|
||||||
|
Value="{Binding LastOrangePull}"/>
|
||||||
|
<TextBlock
|
||||||
|
Grid.Column="0"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Foreground="{StaticResource OrangeBrush}"
|
||||||
|
Style="{StaticResource BodyTextBlockStyle}"
|
||||||
|
Text="{Binding LastOrangePull}"/>
|
||||||
|
<TextBlock
|
||||||
|
Grid.Column="1"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Foreground="{StaticResource OrangeBrush}"
|
||||||
|
Style="{StaticResource BaseTextBlockStyle}"
|
||||||
|
Text="{shcm:ResourceString Name=ViewControlStatisticsCardOrangeText}"/>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
<Border
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="0,6,0,0"
|
||||||
|
Style="{StaticResource BorderCardStyle}">
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="auto"/>
|
||||||
|
<ColumnDefinition/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<ProgressRing
|
||||||
|
Grid.Column="0"
|
||||||
|
Width="40"
|
||||||
|
Height="40"
|
||||||
|
Margin="4"
|
||||||
|
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||||
|
Foreground="{StaticResource PurpleBrush}"
|
||||||
|
IsIndeterminate="False"
|
||||||
|
Maximum="{Binding GuaranteePurpleThreshold}"
|
||||||
|
Value="{Binding LastPurplePull}"/>
|
||||||
|
<TextBlock
|
||||||
|
Grid.Column="0"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Foreground="{StaticResource PurpleBrush}"
|
||||||
|
Style="{StaticResource BodyTextBlockStyle}"
|
||||||
|
Text="{Binding LastPurplePull}"/>
|
||||||
|
<TextBlock
|
||||||
|
Grid.Column="1"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Foreground="{StaticResource PurpleBrush}"
|
||||||
|
Style="{StaticResource BaseTextBlockStyle}"
|
||||||
|
Text="{shcm:ResourceString Name=ViewControlStatisticsCardPurpleText}"/>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="1"
|
||||||
|
Grid.ColumnSpan="3"
|
||||||
|
Text="{Binding Uid}"/>
|
||||||
|
</Grid>
|
||||||
|
</DataTemplate>
|
||||||
|
</FlipView.ItemTemplate>
|
||||||
|
</FlipView>
|
||||||
|
<shvco:LoadingViewSlim IsLoading="{Binding IsInitialized, Converter={StaticResource BoolNegationConverter}}"/>
|
||||||
|
</Grid>
|
||||||
|
</Button>
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Microsoft.UI.Xaml.Controls;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.View.Card;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <20><>Ը<EFBFBD><D4B8>¼<EFBFBD><C2BC>Ƭ
|
||||||
|
/// </summary>
|
||||||
|
internal sealed partial class GachaStatisticsCard : Button
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// <20><><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD>µ<EFBFBD><C2B5><EFBFBD>Ը<EFBFBD><D4B8>¼<EFBFBD><C2BC>Ƭ
|
||||||
|
/// </summary>
|
||||||
|
public GachaStatisticsCard()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
73
src/Snap.Hutao/Snap.Hutao/View/Card/LaunchGameCard.xaml
Normal file
73
src/Snap.Hutao/Snap.Hutao/View/Card/LaunchGameCard.xaml
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
<Button
|
||||||
|
x:Class="Snap.Hutao.View.Card.LaunchGameCard"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:mxi="using:Microsoft.Xaml.Interactivity"
|
||||||
|
xmlns:shcb="using:Snap.Hutao.Control.Behavior"
|
||||||
|
xmlns:shcm="using:Snap.Hutao.Control.Markup"
|
||||||
|
xmlns:shvg="using:Snap.Hutao.ViewModel.Game"
|
||||||
|
Padding="0"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
|
HorizontalContentAlignment="Stretch"
|
||||||
|
d:DataContext="{d:DesignInstance shvg:LaunchGameViewModelSlim}"
|
||||||
|
Command="{Binding LaunchCommand}"
|
||||||
|
Style="{ThemeResource DefaultButtonStyle}"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
<mxi:Interaction.Behaviors>
|
||||||
|
<shcb:InvokeCommandOnLoadedBehavior Command="{Binding OpenUICommand}"/>
|
||||||
|
</mxi:Interaction.Behaviors>
|
||||||
|
<Grid CornerRadius="{ThemeResource ControlCornerRadius}">
|
||||||
|
<Image
|
||||||
|
Margin="0,40,0,0"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
Opacity="0.4"
|
||||||
|
Source="ms-appx:///Resource/HutaoIconSourceTransparentBackgroundGradient1.png"
|
||||||
|
Stretch="Uniform"/>
|
||||||
|
<Grid Margin="12" ColumnSpacing="16">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="auto"/>
|
||||||
|
<ColumnDefinition/>
|
||||||
|
<ColumnDefinition Width="auto"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="auto"/>
|
||||||
|
<RowDefinition Height="auto"/>
|
||||||
|
<RowDefinition/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<FontIcon
|
||||||
|
Grid.Row="0"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
FontSize="{ThemeResource TitleTextBlockFontSize}"
|
||||||
|
Glyph=""/>
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="1"
|
||||||
|
Grid.Column="0"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Foreground="{ThemeResource SystemAccentColorLight3}"
|
||||||
|
Style="{StaticResource SubtitleTextBlockStyle}"
|
||||||
|
Text="{shcm:ResourceString Name=ViewLaunchGameHeader}"/>
|
||||||
|
<Button
|
||||||
|
Grid.Column="2"
|
||||||
|
MinHeight="37.2"
|
||||||
|
Background="Transparent"
|
||||||
|
BorderBrush="{x:Null}"
|
||||||
|
BorderThickness="0"
|
||||||
|
Command="{Binding NavigateCommand}"
|
||||||
|
Content=""
|
||||||
|
FontFamily="{StaticResource SymbolThemeFontFamily}"
|
||||||
|
ToolTipService.ToolTip="{shcm:ResourceString Name=ViewPageHomeLaunchGameSettingAction}"/>
|
||||||
|
<ComboBox
|
||||||
|
Grid.Row="2"
|
||||||
|
Grid.ColumnSpan="3"
|
||||||
|
VerticalAlignment="Bottom"
|
||||||
|
DisplayMemberPath="Name"
|
||||||
|
ItemsSource="{Binding GameAccounts}"
|
||||||
|
PlaceholderText="选择账号或直接启动"
|
||||||
|
SelectedItem="{Binding SelectedGameAccount, Mode=TwoWay}"/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Button>
|
||||||
20
src/Snap.Hutao/Snap.Hutao/View/Card/LaunchGameCard.xaml.cs
Normal file
20
src/Snap.Hutao/Snap.Hutao/View/Card/LaunchGameCard.xaml.cs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Microsoft.UI.Xaml.Controls;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.View.Card;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 启动游戏卡片
|
||||||
|
/// </summary>
|
||||||
|
internal sealed partial class LaunchGameCard : Button
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 构造一个新的启动游戏卡片
|
||||||
|
/// </summary>
|
||||||
|
public LaunchGameCard()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
13
src/Snap.Hutao/Snap.Hutao/View/Control/LoadingViewSlim.xaml
Normal file
13
src/Snap.Hutao/Snap.Hutao/View/Control/LoadingViewSlim.xaml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<cwuc:Loading
|
||||||
|
x:Class="Snap.Hutao.View.Control.LoadingViewSlim"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:cwuc="using:CommunityToolkit.WinUI.UI.Controls"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
|
||||||
|
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||||
|
<ProgressRing IsActive="True"/>
|
||||||
|
</StackPanel>
|
||||||
|
</cwuc:Loading>
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using CommunityToolkit.WinUI.UI.Controls;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.View.Control;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <20>ļ<F2B5A5B5><C4BC><EFBFBD><EFBFBD><EFBFBD>ͼ
|
||||||
|
/// </summary>
|
||||||
|
public sealed partial class LoadingViewSlim : Loading
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// <20><><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD>µļļ<F2B5A5B5><C4BC><EFBFBD><EFBFBD><EFBFBD>ͼ
|
||||||
|
/// </summary>
|
||||||
|
public LoadingViewSlim()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,7 +17,8 @@
|
|||||||
xmlns:shci="using:Snap.Hutao.Control.Image"
|
xmlns:shci="using:Snap.Hutao.Control.Image"
|
||||||
xmlns:shcm="using:Snap.Hutao.Control.Markup"
|
xmlns:shcm="using:Snap.Hutao.Control.Markup"
|
||||||
xmlns:shv="using:Snap.Hutao.ViewModel"
|
xmlns:shv="using:Snap.Hutao.ViewModel"
|
||||||
xmlns:shvc="using:Snap.Hutao.View.Control"
|
xmlns:shvca="using:Snap.Hutao.View.Card"
|
||||||
|
xmlns:shvco="using:Snap.Hutao.View.Control"
|
||||||
d:DataContext="{d:DesignInstance shv:AnnouncementViewModel}"
|
d:DataContext="{d:DesignInstance shv:AnnouncementViewModel}"
|
||||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
|
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
@@ -132,7 +133,7 @@
|
|||||||
<Setter Property="MaxWidth" Value="640"/>
|
<Setter Property="MaxWidth" Value="640"/>
|
||||||
</Style>
|
</Style>
|
||||||
</Flyout.FlyoutPresenterStyle>
|
</Flyout.FlyoutPresenterStyle>
|
||||||
<shvc:AnnouncementContentViewer Announcement="{Binding}"/>
|
<shvco:AnnouncementContentViewer Announcement="{Binding}"/>
|
||||||
</Flyout>
|
</Flyout>
|
||||||
</FlyoutBase.AttachedFlyout>
|
</FlyoutBase.AttachedFlyout>
|
||||||
<mxi:Interaction.Behaviors>
|
<mxi:Interaction.Behaviors>
|
||||||
@@ -168,137 +169,8 @@
|
|||||||
DesiredWidth="300"
|
DesiredWidth="300"
|
||||||
ItemContainerStyle="{StaticResource LargeGridViewItemStyle}"
|
ItemContainerStyle="{StaticResource LargeGridViewItemStyle}"
|
||||||
SelectionMode="None">
|
SelectionMode="None">
|
||||||
<!-- 启动游戏 -->
|
<shvca:LaunchGameCard Height="186" DataContext="{Binding LaunchGameViewModelSlim}"/>
|
||||||
<Button
|
<shvca:GachaStatisticsCard DataContext="{Binding GachaLogViewModelSlim}"/>
|
||||||
Height="120"
|
|
||||||
Padding="0"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
VerticalAlignment="Stretch"
|
|
||||||
HorizontalContentAlignment="Stretch"
|
|
||||||
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
|
|
||||||
Command="{Binding LaunchGameViewModelSlim.LaunchCommand}"
|
|
||||||
Style="{StaticResource AccentButtonStyle}">
|
|
||||||
<mxi:Interaction.Behaviors>
|
|
||||||
<shcb:InvokeCommandOnLoadedBehavior Command="{Binding LaunchGameViewModelSlim.OpenUICommand}"/>
|
|
||||||
</mxi:Interaction.Behaviors>
|
|
||||||
|
|
||||||
<Grid CornerRadius="{ThemeResource ControlCornerRadius}">
|
|
||||||
<Image
|
|
||||||
Margin="0,40,0,0"
|
|
||||||
HorizontalAlignment="Right"
|
|
||||||
Source="ms-appx:///Resource/HutaoIconSourceTransparentBackgroundGradient1.png"
|
|
||||||
Stretch="Uniform"/>
|
|
||||||
<Grid Margin="12" ColumnSpacing="16">
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="auto"/>
|
|
||||||
<ColumnDefinition/>
|
|
||||||
<ColumnDefinition Width="auto"/>
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="auto"/>
|
|
||||||
<RowDefinition/>
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
<FontIcon
|
|
||||||
Grid.Row="0"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Glyph=""/>
|
|
||||||
<TextBlock
|
|
||||||
Grid.Column="1"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Text="{shcm:ResourceString Name=ViewLaunchGameHeader}"/>
|
|
||||||
<Button
|
|
||||||
Grid.Column="2"
|
|
||||||
MinHeight="37.2"
|
|
||||||
Background="Transparent"
|
|
||||||
BorderBrush="{x:Null}"
|
|
||||||
BorderThickness="0"
|
|
||||||
Command="{Binding LaunchGameViewModelSlim.NavigateCommand}"
|
|
||||||
Content=""
|
|
||||||
FontFamily="{StaticResource SymbolThemeFontFamily}"
|
|
||||||
Foreground="{ThemeResource AccentButtonForeground}"
|
|
||||||
ToolTipService.ToolTip="{shcm:ResourceString Name=ViewPageHomeLaunchGameSettingAction}"/>
|
|
||||||
<ComboBox
|
|
||||||
Grid.Row="1"
|
|
||||||
Grid.ColumnSpan="3"
|
|
||||||
VerticalAlignment="Bottom"
|
|
||||||
DisplayMemberPath="Name"
|
|
||||||
ItemsSource="{Binding LaunchGameViewModelSlim.GameAccounts}"
|
|
||||||
PlaceholderText="选择账号或直接启动"
|
|
||||||
SelectedItem="{Binding LaunchGameViewModelSlim.SelectedGameAccount, Mode=TwoWay}"/>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<Border Style="{StaticResource BorderCardStyle}">
|
|
||||||
<FlipView Background="{x:Null}">
|
|
||||||
<Grid Margin="12">
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition/>
|
|
||||||
<ColumnDefinition/>
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<StackPanel>
|
|
||||||
<TextBlock Style="{StaticResource BaseTextBlockStyle}" Text="卡池名称 1"/>
|
|
||||||
|
|
||||||
<shvc:ItemIcon
|
|
||||||
Width="40"
|
|
||||||
Height="40"
|
|
||||||
Margin="0,12,0,0"
|
|
||||||
HorizontalAlignment="Left"
|
|
||||||
Icon="{Binding Icon}"
|
|
||||||
Quality="QUALITY_ORANGE"/>
|
|
||||||
|
|
||||||
<TextBlock Margin="0,6,0,0" Text="XX 抽"/>
|
|
||||||
</StackPanel>
|
|
||||||
|
|
||||||
<StackPanel Grid.Column="1">
|
|
||||||
<TextBlock Style="{StaticResource BaseTextBlockStyle}" Text="卡池名称 1"/>
|
|
||||||
|
|
||||||
<shvc:ItemIcon
|
|
||||||
Width="40"
|
|
||||||
Height="40"
|
|
||||||
Margin="0,12,0,0"
|
|
||||||
HorizontalAlignment="Left"
|
|
||||||
Icon="{Binding Icon}"
|
|
||||||
Quality="QUALITY_ORANGE"/>
|
|
||||||
|
|
||||||
<TextBlock Margin="0,6,0,0" Text="XX 抽"/>
|
|
||||||
</StackPanel>
|
|
||||||
</Grid>
|
|
||||||
<Grid Margin="12">
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition/>
|
|
||||||
<ColumnDefinition/>
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<StackPanel>
|
|
||||||
<TextBlock Style="{StaticResource BaseTextBlockStyle}" Text="卡池名称 1"/>
|
|
||||||
|
|
||||||
<shvc:ItemIcon
|
|
||||||
Width="40"
|
|
||||||
Height="40"
|
|
||||||
Margin="0,12,0,0"
|
|
||||||
HorizontalAlignment="Left"
|
|
||||||
Icon="{Binding Icon}"
|
|
||||||
Quality="QUALITY_ORANGE"/>
|
|
||||||
|
|
||||||
<TextBlock Margin="0,6,0,0" Text="XX 抽"/>
|
|
||||||
</StackPanel>
|
|
||||||
|
|
||||||
<StackPanel Grid.Column="1">
|
|
||||||
<TextBlock Style="{StaticResource BaseTextBlockStyle}" Text="卡池名称 1"/>
|
|
||||||
|
|
||||||
<shvc:ItemIcon
|
|
||||||
Width="40"
|
|
||||||
Height="40"
|
|
||||||
Margin="0,12,0,0"
|
|
||||||
HorizontalAlignment="Left"
|
|
||||||
Icon="{Binding Icon}"
|
|
||||||
Quality="QUALITY_ORANGE"/>
|
|
||||||
|
|
||||||
<TextBlock Margin="0,6,0,0" Text="XX 抽"/>
|
|
||||||
</StackPanel>
|
|
||||||
</Grid>
|
|
||||||
</FlipView>
|
|
||||||
</Border>
|
|
||||||
|
|
||||||
<Border Style="{StaticResource BorderCardStyle}">
|
<Border Style="{StaticResource BorderCardStyle}">
|
||||||
<FlipView Background="{x:Null}">
|
<FlipView Background="{x:Null}">
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using Snap.Hutao.Service.Navigation;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.ViewModel.Abstraction;
|
namespace Snap.Hutao.ViewModel.Abstraction;
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ namespace Snap.Hutao.ViewModel.Abstraction;
|
|||||||
internal abstract class ViewModelSlim<TPage> : ObservableObject
|
internal abstract class ViewModelSlim<TPage> : ObservableObject
|
||||||
where TPage : Microsoft.UI.Xaml.Controls.Page
|
where TPage : Microsoft.UI.Xaml.Controls.Page
|
||||||
{
|
{
|
||||||
|
private bool isInitialized;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 构造一个新的简化的视图模型抽象类
|
/// 构造一个新的简化的视图模型抽象类
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -26,6 +28,11 @@ internal abstract class ViewModelSlim<TPage> : ObservableObject
|
|||||||
NavigateCommand = new RelayCommand(Navigate);
|
NavigateCommand = new RelayCommand(Navigate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否初始化完成
|
||||||
|
/// </summary>
|
||||||
|
public bool IsInitialized { get => isInitialized; set => SetProperty(ref isInitialized, value); }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 打开页面命令
|
/// 打开页面命令
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ internal sealed class AnnouncementViewModel : Abstraction.ViewModel
|
|||||||
announcementService = serviceProvider.GetRequiredService<IAnnouncementService>();
|
announcementService = serviceProvider.GetRequiredService<IAnnouncementService>();
|
||||||
|
|
||||||
LaunchGameViewModelSlim = serviceProvider.GetRequiredService<Game.LaunchGameViewModelSlim>();
|
LaunchGameViewModelSlim = serviceProvider.GetRequiredService<Game.LaunchGameViewModelSlim>();
|
||||||
|
GachaLogViewModelSlim = serviceProvider.GetRequiredService<GachaLog.GachaLogViewModelSlim>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -38,6 +39,11 @@ internal sealed class AnnouncementViewModel : Abstraction.ViewModel
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public Game.LaunchGameViewModelSlim LaunchGameViewModelSlim { get; }
|
public Game.LaunchGameViewModelSlim LaunchGameViewModelSlim { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 祈愿记录视图模型
|
||||||
|
/// </summary>
|
||||||
|
public GachaLog.GachaLogViewModelSlim GachaLogViewModelSlim { get; }
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
protected override async Task OpenUIAsync()
|
protected override async Task OpenUIAsync()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
// 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.Service.GachaLog;
|
||||||
|
|
||||||
namespace Snap.Hutao.ViewModel.GachaLog;
|
namespace Snap.Hutao.ViewModel.GachaLog;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -26,8 +28,16 @@ internal sealed class GachaLogViewModelSlim : Abstraction.ViewModelSlim<View.Pag
|
|||||||
public List<GachaStatisticsSlim>? StatisticsList { get => statisticsList; set => SetProperty(ref statisticsList, value); }
|
public List<GachaStatisticsSlim>? StatisticsList { get => statisticsList; set => SetProperty(ref statisticsList, value); }
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
protected override Task OpenUIAsync()
|
protected override async Task OpenUIAsync()
|
||||||
{
|
{
|
||||||
return Task.CompletedTask;
|
IGachaLogService gachaLogService = ServiceProvider.GetRequiredService<IGachaLogService>();
|
||||||
|
|
||||||
|
if (await gachaLogService.InitializeAsync(default).ConfigureAwait(false))
|
||||||
|
{
|
||||||
|
List<GachaStatisticsSlim> list = await gachaLogService.GetStatisticsSlimsAsync().ConfigureAwait(false);
|
||||||
|
await ThreadHelper.SwitchToMainThreadAsync();
|
||||||
|
StatisticsList = list;
|
||||||
|
IsInitialized = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -16,15 +16,15 @@ internal sealed class GachaStatisticsSlim
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 角色活动
|
/// 角色活动
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TypedWishSummary AvatarWish { get; set; } = default!;
|
public TypedWishSummarySlim AvatarWish { get; set; } = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 神铸赋形
|
/// 神铸赋形
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TypedWishSummary WeaponWish { get; set; } = default!;
|
public TypedWishSummarySlim WeaponWish { get; set; } = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 奔行世间
|
/// 奔行世间
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TypedWishSummary StandardWish { get; set; } = default!;
|
public TypedWishSummarySlim StandardWish { get; set; } = default!;
|
||||||
}
|
}
|
||||||
@@ -8,6 +8,19 @@ namespace Snap.Hutao.ViewModel.GachaLog;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal sealed class TypedWishSummarySlim
|
internal sealed class TypedWishSummarySlim
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 构造一个新的简化的类型化的祈愿概览
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">卡池名称</param>
|
||||||
|
/// <param name="guaranteeOrangeThreshold">五星保底阈值</param>
|
||||||
|
/// <param name="guaranteePurpleThreshold">四星保底阈值</param>
|
||||||
|
public TypedWishSummarySlim(string name, int guaranteeOrangeThreshold, int guaranteePurpleThreshold)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
GuaranteeOrangeThreshold = guaranteeOrangeThreshold;
|
||||||
|
GuaranteePurpleThreshold = guaranteePurpleThreshold;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 卡池名称
|
/// 卡池名称
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -23,6 +23,14 @@ internal struct GachaLogQueryOptions
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly bool IsOversea;
|
public readonly bool IsOversea;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 结束Id
|
||||||
|
/// 控制API返回的分页
|
||||||
|
/// 米哈游使用了 keyset pagination 来实现这一目标
|
||||||
|
/// https://learn.microsoft.com/en-us/ef/core/querying/pagination#keyset-pagination
|
||||||
|
/// </summary>
|
||||||
|
public long EndId;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Keys required:
|
/// Keys required:
|
||||||
/// authkey_ver
|
/// authkey_ver
|
||||||
@@ -37,14 +45,6 @@ internal struct GachaLogQueryOptions
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly QueryString innerQuery;
|
private readonly QueryString innerQuery;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 结束Id
|
|
||||||
/// 控制API返回的分页
|
|
||||||
/// 米哈游使用了 keyset pagination 来实现这一目标
|
|
||||||
/// https://learn.microsoft.com/en-us/ef/core/querying/pagination#keyset-pagination
|
|
||||||
/// </summary>
|
|
||||||
public long EndId;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 构造一个新的祈愿记录请求配置
|
/// 构造一个新的祈愿记录请求配置
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ internal sealed class SimpleRecord
|
|||||||
/// <param name="uid">uid</param>
|
/// <param name="uid">uid</param>
|
||||||
/// <param name="characters">详细的角色信息</param>
|
/// <param name="characters">详细的角色信息</param>
|
||||||
/// <param name="spiralAbyss">深渊信息</param>
|
/// <param name="spiralAbyss">深渊信息</param>
|
||||||
|
/// <param name="reservedUserName">用户名</param>
|
||||||
public SimpleRecord(string uid, List<Character> characters, SpiralAbyss spiralAbyss, string? reservedUserName)
|
public SimpleRecord(string uid, List<Character> characters, SpiralAbyss spiralAbyss, string? reservedUserName)
|
||||||
{
|
{
|
||||||
Uid = uid;
|
Uid = uid;
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ internal static class HutaoEndpoints
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 删除祈愿记录
|
/// 删除祈愿记录
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="uid">uid</param>
|
||||||
/// <returns>删除祈愿记录 Url</returns>
|
/// <returns>删除祈愿记录 Url</returns>
|
||||||
public static string GachaLogDelete(string uid)
|
public static string GachaLogDelete(string uid)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user