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.DebugSettings.BindingFailed += OnXamlBindingFailed;
|
||||
application.DebugSettings.XamlResourceReferenceFailed += OnXamlResourceReferenceFailed;
|
||||
}
|
||||
|
||||
private void OnAppUnhandledException(object? sender, Microsoft.UI.Xaml.UnhandledExceptionEventArgs e)
|
||||
@@ -51,4 +52,9 @@ internal sealed class ExceptionRecorder
|
||||
{
|
||||
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 Microsoft.UI;
|
||||
using Microsoft.UI.Composition.SystemBackdrops;
|
||||
using Microsoft.UI.Windowing;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
using Snap.Hutao.Message;
|
||||
using Snap.Hutao.Service;
|
||||
using Snap.Hutao.Win32;
|
||||
using System.IO;
|
||||
using Windows.Graphics;
|
||||
@@ -27,8 +30,6 @@ internal sealed class ExtendedWindow<TWindow> : IRecipient<FlyoutOpenCloseMessag
|
||||
private readonly ILogger<ExtendedWindow<TWindow>> logger;
|
||||
private readonly WindowSubclass<TWindow> subclass;
|
||||
|
||||
private SystemBackdrop? systemBackdrop;
|
||||
|
||||
private ExtendedWindow(TWindow window, FrameworkElement titleBar, IServiceProvider serviceProvider)
|
||||
{
|
||||
options = new(window, titleBar);
|
||||
@@ -54,7 +55,7 @@ internal sealed class ExtendedWindow<TWindow> : IRecipient<FlyoutOpenCloseMessag
|
||||
/// <inheritdoc/>
|
||||
public void Receive(FlyoutOpenCloseMessage message)
|
||||
{
|
||||
UpdateDragRectangles(options.AppWindow.TitleBar, message.IsOpen);
|
||||
UpdateDragRectangles(message.IsOpen);
|
||||
}
|
||||
|
||||
private void InitializeWindow()
|
||||
@@ -69,9 +70,9 @@ internal sealed class ExtendedWindow<TWindow> : IRecipient<FlyoutOpenCloseMessag
|
||||
// appWindow.Show can't bring window to top.
|
||||
options.Window.Activate();
|
||||
|
||||
systemBackdrop = new(options.Window, serviceProvider);
|
||||
bool micaApplied = systemBackdrop.Update();
|
||||
logger.LogInformation("Apply {name} : {result}", nameof(SystemBackdrop), micaApplied ? "succeed" : "failed");
|
||||
AppOptions appOptions = serviceProvider.GetRequiredService<AppOptions>();
|
||||
UpdateSystemBackdrop(appOptions.BackdropType);
|
||||
appOptions.PropertyChanged += OnOptionsPropertyChanged;
|
||||
|
||||
bool subClassApplied = subclass.Initialize();
|
||||
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;
|
||||
}
|
||||
|
||||
private void OnOptionsPropertyChanged(object? sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName == nameof(AppOptions.BackdropType))
|
||||
{
|
||||
UpdateSystemBackdrop(((AppOptions)sender!).BackdropType);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnWindowClosed(object sender, WindowEventArgs args)
|
||||
{
|
||||
if (options.Window.PersistSize)
|
||||
@@ -106,15 +115,28 @@ internal sealed class ExtendedWindow<TWindow> : IRecipient<FlyoutOpenCloseMessag
|
||||
appTitleBar.IconShowOptions = IconShowOptions.HideIconAndSystemMenu;
|
||||
appTitleBar.ExtendsContentIntoTitleBar = true;
|
||||
|
||||
UpdateTitleButtonColor(appTitleBar);
|
||||
UpdateDragRectangles(appTitleBar);
|
||||
options.TitleBar.ActualThemeChanged += (s, e) => UpdateTitleButtonColor(appTitleBar);
|
||||
options.TitleBar.SizeChanged += (s, e) => UpdateDragRectangles(appTitleBar);
|
||||
UpdateTitleButtonColor();
|
||||
UpdateDragRectangles();
|
||||
options.TitleBar.ActualThemeChanged += (s, e) => UpdateTitleButtonColor();
|
||||
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.ButtonInactiveBackgroundColor = Colors.Transparent;
|
||||
|
||||
@@ -137,8 +159,10 @@ internal sealed class ExtendedWindow<TWindow> : IRecipient<FlyoutOpenCloseMessag
|
||||
appTitleBar.ButtonPressedForegroundColor = systemBaseHighColor;
|
||||
}
|
||||
|
||||
private void UpdateDragRectangles(AppWindowTitleBar appTitleBar, bool isFlyoutOpened = false)
|
||||
private void UpdateDragRectangles(bool isFlyoutOpened = false)
|
||||
{
|
||||
AppWindowTitleBar appTitleBar = options.AppWindow.TitleBar;
|
||||
|
||||
if (isFlyoutOpened)
|
||||
{
|
||||
// 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>
|
||||
public readonly bool UseLegacyDragBarImplementation = !AppWindowTitleBar.IsCustomizationSupported();
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的窗体选项
|
||||
/// </summary>
|
||||
/// <param name="window">窗体</param>
|
||||
/// <param name="titleBar">标题栏</param>
|
||||
public WindowOptions(TWindow window, FrameworkElement titleBar)
|
||||
{
|
||||
Window = window;
|
||||
Hwnd = (HWND)WindowNative.GetWindowHandle(window);
|
||||
WindowId windowId = Win32Interop.GetWindowIdFromWindow(Hwnd);
|
||||
AppWindow = AppWindow.GetFromWindowId(windowId);
|
||||
|
||||
AppWindow = window.AppWindow;
|
||||
TitleBar = titleBar;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Core.Database;
|
||||
using Snap.Hutao.Core.ExceptionService;
|
||||
using Snap.Hutao.Model.Entity;
|
||||
using Snap.Hutao.Model.Entity.Database;
|
||||
using Snap.Hutao.Model.Intrinsic;
|
||||
using Snap.Hutao.Model.Metadata;
|
||||
using Snap.Hutao.Model.Metadata.Avatar;
|
||||
@@ -37,31 +35,22 @@ internal sealed class GachaStatisticsFactory : IGachaStatisticsFactory
|
||||
}
|
||||
|
||||
/// <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<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);
|
||||
await ThreadHelper.SwitchToBackgroundAsync();
|
||||
return CreateCore(orderedItems, historyWishBuilders, idAvatarMap, idWeaponMap, options.IsEmptyHistoryWishVisible);
|
||||
return CreateCore(items, historyWishBuilders, context, options.IsEmptyHistoryWishVisible);
|
||||
}
|
||||
|
||||
private static GachaStatistics CreateCore(
|
||||
IOrderedEnumerable<GachaItem> items,
|
||||
IOrderedQueryable<GachaItem> items,
|
||||
List<HistoryWishBuilder> historyWishBuilders,
|
||||
Dictionary<AvatarId, Avatar> avatarMap,
|
||||
Dictionary<WeaponId, Weapon> weaponMap,
|
||||
GachaLogServiceContext context,
|
||||
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 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);
|
||||
|
||||
// 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;
|
||||
switch (avatar.Quality)
|
||||
{
|
||||
case ItemQuality.QUALITY_ORANGE:
|
||||
orangeAvatarCounter.Increase(avatar);
|
||||
isUp = targetHistoryWishBuilder?.IncreaseOrange(avatar) ?? false;
|
||||
break;
|
||||
case ItemQuality.QUALITY_PURPLE:
|
||||
purpleAvatarCounter.Increase(avatar);
|
||||
targetHistoryWishBuilder?.IncreasePurple(avatar);
|
||||
break;
|
||||
}
|
||||
bool isUp = false;
|
||||
switch (avatar.Quality)
|
||||
{
|
||||
case ItemQuality.QUALITY_ORANGE:
|
||||
orangeAvatarCounter.Increase(avatar);
|
||||
isUp = targetHistoryWishBuilder?.IncreaseOrange(avatar) ?? false;
|
||||
break;
|
||||
case ItemQuality.QUALITY_PURPLE:
|
||||
purpleAvatarCounter.Increase(avatar);
|
||||
targetHistoryWishBuilder?.IncreasePurple(avatar);
|
||||
break;
|
||||
}
|
||||
|
||||
standardWishBuilder.Track(item, avatar, isUp);
|
||||
avatarWishBuilder.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);
|
||||
standardWishBuilder.Track(item, avatar, isUp);
|
||||
avatarWishBuilder.Track(item, avatar, isUp);
|
||||
weaponWishBuilder.Track(item, avatar, isUp);
|
||||
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);
|
||||
}
|
||||
else
|
||||
{
|
||||
// ItemId place not correct.
|
||||
ThrowHelper.UserdataCorrupted(string.Format(SH.ServiceGachaStatisticsFactoryItemIdInvalid, item.ItemId), null!);
|
||||
case 5:
|
||||
{
|
||||
Weapon weapon = context.IdWeaponMap[item.ItemId];
|
||||
|
||||
bool isUp = false;
|
||||
switch (weapon.RankLevel)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,4 +154,4 @@ internal sealed class GachaStatisticsFactory : IGachaStatisticsFactory
|
||||
WeaponWish = weaponWishBuilder.ToTypedWishSummary(),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
/// <param name="gachaEvent">卡池配置</param>
|
||||
/// <param name="nameAvatarMap">命名角色映射</param>
|
||||
/// <param name="nameWeaponMap">命名武器映射</param>
|
||||
public HistoryWishBuilder(GachaEvent gachaEvent, Dictionary<string, Avatar> nameAvatarMap, Dictionary<string, Weapon> nameWeaponMap)
|
||||
/// <param name="context">祈愿记录上下文</param>
|
||||
public HistoryWishBuilder(GachaEvent gachaEvent, GachaLogServiceContext context)
|
||||
{
|
||||
this.gachaEvent = gachaEvent;
|
||||
configType = gachaEvent.Type;
|
||||
|
||||
if (configType == GachaConfigType.AvatarEventWish || configType == GachaConfigType.AvatarEventWish2)
|
||||
{
|
||||
orangeUpCounter = gachaEvent.UpOrangeList.Select(name => nameAvatarMap[name]).ToDictionary(a => (IStatisticsItemSource)a, a => 0);
|
||||
purpleUpCounter = gachaEvent.UpPurpleList.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 => context.NameAvatarMap[name]).ToDictionary(a => (IStatisticsItemSource)a, a => 0);
|
||||
}
|
||||
else if (configType == GachaConfigType.WeaponEventWish)
|
||||
{
|
||||
orangeUpCounter = gachaEvent.UpOrangeList.Select(name => nameWeaponMap[name]).ToDictionary(w => (IStatisticsItemSource)w, w => 0);
|
||||
purpleUpCounter = gachaEvent.UpPurpleList.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 => context.NameWeaponMap[name]).ToDictionary(w => (IStatisticsItemSource)w, w => 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ internal interface IGachaStatisticsFactory
|
||||
/// 异步创建祈愿统计对象
|
||||
/// </summary>
|
||||
/// <param name="items">物品列表</param>
|
||||
/// <param name="context">祈愿记录上下文</param>
|
||||
/// <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>
|
||||
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>
|
||||
/// 角色活动
|
||||
|
||||
@@ -1,26 +1,10 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// 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.Diagnostics;
|
||||
using Snap.Hutao.Core.ExceptionService;
|
||||
using Snap.Hutao.Model.Binding;
|
||||
using Snap.Hutao.Model.Entity;
|
||||
using Snap.Hutao.Model.Entity.Database;
|
||||
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;
|
||||
|
||||
@@ -61,19 +45,9 @@ internal sealed class GachaLogImportService : IGachaLogImportService
|
||||
IEnumerable<GachaItem> toAdd = list
|
||||
.OrderByDescending(i => i.Id)
|
||||
.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);
|
||||
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 IGachaLogExportService gachaLogExportService;
|
||||
private readonly IGachaLogImportService gachaLogImportService;
|
||||
|
||||
private readonly IEnumerable<IGachaLogQueryProvider> urlProviders;
|
||||
private readonly GachaInfoClient gachaInfoClient;
|
||||
private readonly IMetadataService metadataService;
|
||||
private readonly IGachaStatisticsFactory gachaStatisticsFactory;
|
||||
private readonly IGachaStatisticsSlimFactory gachaStatisticsSlimFactory;
|
||||
private readonly ILogger<GachaLogService> logger;
|
||||
private readonly DbCurrent<GachaArchive, Message.GachaArchiveChangedMessage> dbCurrent;
|
||||
|
||||
@@ -48,32 +47,17 @@ internal sealed class GachaLogService : IGachaLogService
|
||||
/// 构造一个新的祈愿记录服务
|
||||
/// </summary>
|
||||
/// <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>
|
||||
public GachaLogService(
|
||||
IServiceProvider serviceProvider,
|
||||
AppDbContext appDbContext,
|
||||
IEnumerable<IGachaLogQueryProvider> urlProviders,
|
||||
GachaInfoClient gachaInfoClient,
|
||||
IMetadataService metadataService,
|
||||
IGachaStatisticsFactory gachaStatisticsFactory,
|
||||
ILogger<GachaLogService> logger,
|
||||
IMessenger messenger)
|
||||
public GachaLogService(IServiceProvider serviceProvider, IMessenger messenger)
|
||||
{
|
||||
gachaLogExportService = serviceProvider.GetRequiredService<IGachaLogExportService>();
|
||||
gachaLogImportService = serviceProvider.GetRequiredService<IGachaLogImportService>();
|
||||
|
||||
this.appDbContext = appDbContext;
|
||||
this.urlProviders = urlProviders;
|
||||
this.gachaInfoClient = gachaInfoClient;
|
||||
this.metadataService = metadataService;
|
||||
this.logger = logger;
|
||||
this.gachaStatisticsFactory = gachaStatisticsFactory;
|
||||
appDbContext = serviceProvider.GetRequiredService<AppDbContext>();
|
||||
gachaInfoClient = serviceProvider.GetRequiredService<GachaInfoClient>();
|
||||
metadataService = serviceProvider.GetRequiredService<IMetadataService>();
|
||||
logger = serviceProvider.GetRequiredService<ILogger<GachaLogService>>();
|
||||
gachaStatisticsFactory = serviceProvider.GetRequiredService<IGachaStatisticsFactory>();
|
||||
gachaStatisticsSlimFactory = serviceProvider.GetRequiredService<IGachaStatisticsSlimFactory>();
|
||||
|
||||
dbCurrent = new(appDbContext.GachaArchives, messenger);
|
||||
}
|
||||
@@ -127,8 +111,8 @@ internal sealed class GachaLogService : IGachaLogService
|
||||
{
|
||||
using (ValueStopwatch.MeasureExecution(logger))
|
||||
{
|
||||
IQueryable<GachaItem> items = appDbContext.GachaItems.Where(i => i.ArchiveId == archive.InnerId);
|
||||
return await gachaStatisticsFactory.CreateAsync(items).ConfigureAwait(false);
|
||||
IOrderedQueryable<GachaItem> items = appDbContext.GachaItems.Where(i => i.ArchiveId == archive.InnerId).OrderBy(i => i.Id);
|
||||
return await gachaStatisticsFactory.CreateAsync(items, context).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
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/>
|
||||
public Task<UIGF> ExportToUIGFAsync(GachaArchive archive)
|
||||
{
|
||||
|
||||
@@ -40,6 +40,12 @@ internal interface IGachaLogService
|
||||
/// <returns>祈愿统计</returns>
|
||||
Task<GachaStatistics> GetStatisticsAsync(GachaArchive? archive);
|
||||
|
||||
/// <summary>
|
||||
/// 异步获取简化的祈愿统计列表
|
||||
/// </summary>
|
||||
/// <returns>简化的祈愿统计列表</returns>
|
||||
Task<List<GachaStatisticsSlim>> GetStatisticsSlimsAsync();
|
||||
|
||||
/// <summary>
|
||||
/// 异步从UIGF导入数据
|
||||
/// </summary>
|
||||
|
||||
@@ -25,7 +25,7 @@ internal sealed class HutaoUserOptions : ObservableObject, IOptions<HutaoUserOpt
|
||||
/// <summary>
|
||||
/// 真正的用户名
|
||||
/// </summary>
|
||||
public string? ActualUserName { get => IsLoggedIn ? null : UserName; }
|
||||
public string? ActualUserName { get => IsLoggedIn ? UserName : null; }
|
||||
|
||||
/// <summary>
|
||||
/// 访问令牌
|
||||
|
||||
@@ -51,7 +51,6 @@ internal sealed class HutaoUserService : IHutaoUserService, IHutaoUserServiceIni
|
||||
{
|
||||
await ThreadHelper.SwitchToMainThreadAsync();
|
||||
options.LoginSucceed(userName, response.Data);
|
||||
|
||||
isInitialized = true;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -106,12 +106,15 @@
|
||||
<None Remove="Resource\Segoe Fluent Icons.ttf" />
|
||||
<None Remove="Resource\WelcomeView_Background.png" />
|
||||
<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\BottomTextControl.xaml" />
|
||||
<None Remove="View\Control\DescParamComboBox.xaml" />
|
||||
<None Remove="View\Control\ItemIcon.xaml" />
|
||||
<None Remove="View\Control\LaunchGameResourceExpander.xaml" />
|
||||
<None Remove="View\Control\LoadingView.xaml" />
|
||||
<None Remove="View\Control\LoadingViewSlim.xaml" />
|
||||
<None Remove="View\Control\SkillPivot.xaml" />
|
||||
<None Remove="View\Control\StatisticsCard.xaml" />
|
||||
<None Remove="View\Dialog\AchievementArchiveCreateDialog.xaml" />
|
||||
@@ -236,8 +239,8 @@
|
||||
<PackageReference Include="CommunityToolkit.WinUI.Notifications" 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="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.4" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.4">
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.5" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.5">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
@@ -254,7 +257,7 @@
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<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">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
@@ -293,6 +296,18 @@
|
||||
</EmbeddedResource>
|
||||
</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>
|
||||
<Page Update="View\Page\HutaoPassportPage.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
@@ -540,4 +555,9 @@
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="View\Card\LaunchGameCard.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
</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:shcm="using:Snap.Hutao.Control.Markup"
|
||||
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}"
|
||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
|
||||
mc:Ignorable="d">
|
||||
@@ -132,7 +133,7 @@
|
||||
<Setter Property="MaxWidth" Value="640"/>
|
||||
</Style>
|
||||
</Flyout.FlyoutPresenterStyle>
|
||||
<shvc:AnnouncementContentViewer Announcement="{Binding}"/>
|
||||
<shvco:AnnouncementContentViewer Announcement="{Binding}"/>
|
||||
</Flyout>
|
||||
</FlyoutBase.AttachedFlyout>
|
||||
<mxi:Interaction.Behaviors>
|
||||
@@ -168,137 +169,8 @@
|
||||
DesiredWidth="300"
|
||||
ItemContainerStyle="{StaticResource LargeGridViewItemStyle}"
|
||||
SelectionMode="None">
|
||||
<!-- 启动游戏 -->
|
||||
<Button
|
||||
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>
|
||||
<shvca:LaunchGameCard Height="186" DataContext="{Binding LaunchGameViewModelSlim}"/>
|
||||
<shvca:GachaStatisticsCard DataContext="{Binding GachaLogViewModelSlim}"/>
|
||||
|
||||
<Border Style="{StaticResource BorderCardStyle}">
|
||||
<FlipView Background="{x:Null}">
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Snap.Hutao.Service.Navigation;
|
||||
|
||||
namespace Snap.Hutao.ViewModel.Abstraction;
|
||||
|
||||
|
||||
@@ -14,6 +14,8 @@ namespace Snap.Hutao.ViewModel.Abstraction;
|
||||
internal abstract class ViewModelSlim<TPage> : ObservableObject
|
||||
where TPage : Microsoft.UI.Xaml.Controls.Page
|
||||
{
|
||||
private bool isInitialized;
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的简化的视图模型抽象类
|
||||
/// </summary>
|
||||
@@ -26,6 +28,11 @@ internal abstract class ViewModelSlim<TPage> : ObservableObject
|
||||
NavigateCommand = new RelayCommand(Navigate);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否初始化完成
|
||||
/// </summary>
|
||||
public bool IsInitialized { get => isInitialized; set => SetProperty(ref isInitialized, value); }
|
||||
|
||||
/// <summary>
|
||||
/// 打开页面命令
|
||||
/// </summary>
|
||||
|
||||
@@ -26,6 +26,7 @@ internal sealed class AnnouncementViewModel : Abstraction.ViewModel
|
||||
announcementService = serviceProvider.GetRequiredService<IAnnouncementService>();
|
||||
|
||||
LaunchGameViewModelSlim = serviceProvider.GetRequiredService<Game.LaunchGameViewModelSlim>();
|
||||
GachaLogViewModelSlim = serviceProvider.GetRequiredService<GachaLog.GachaLogViewModelSlim>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -38,6 +39,11 @@ internal sealed class AnnouncementViewModel : Abstraction.ViewModel
|
||||
/// </summary>
|
||||
public Game.LaunchGameViewModelSlim LaunchGameViewModelSlim { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 祈愿记录视图模型
|
||||
/// </summary>
|
||||
public GachaLog.GachaLogViewModelSlim GachaLogViewModelSlim { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override async Task OpenUIAsync()
|
||||
{
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Service.GachaLog;
|
||||
|
||||
namespace Snap.Hutao.ViewModel.GachaLog;
|
||||
|
||||
/// <summary>
|
||||
@@ -26,8 +28,16 @@ internal sealed class GachaLogViewModelSlim : Abstraction.ViewModelSlim<View.Pag
|
||||
public List<GachaStatisticsSlim>? StatisticsList { get => statisticsList; set => SetProperty(ref statisticsList, value); }
|
||||
|
||||
/// <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>
|
||||
public TypedWishSummary AvatarWish { get; set; } = default!;
|
||||
public TypedWishSummarySlim AvatarWish { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 神铸赋形
|
||||
/// </summary>
|
||||
public TypedWishSummary WeaponWish { get; set; } = default!;
|
||||
public TypedWishSummarySlim WeaponWish { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 奔行世间
|
||||
/// </summary>
|
||||
public TypedWishSummary StandardWish { get; set; } = default!;
|
||||
public TypedWishSummarySlim StandardWish { get; set; } = default!;
|
||||
}
|
||||
@@ -8,6 +8,19 @@ namespace Snap.Hutao.ViewModel.GachaLog;
|
||||
/// </summary>
|
||||
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>
|
||||
|
||||
@@ -23,6 +23,14 @@ internal struct GachaLogQueryOptions
|
||||
/// </summary>
|
||||
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>
|
||||
/// Keys required:
|
||||
/// authkey_ver
|
||||
@@ -37,14 +45,6 @@ internal struct GachaLogQueryOptions
|
||||
/// </summary>
|
||||
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>
|
||||
|
||||
@@ -18,6 +18,7 @@ internal sealed class SimpleRecord
|
||||
/// <param name="uid">uid</param>
|
||||
/// <param name="characters">详细的角色信息</param>
|
||||
/// <param name="spiralAbyss">深渊信息</param>
|
||||
/// <param name="reservedUserName">用户名</param>
|
||||
public SimpleRecord(string uid, List<Character> characters, SpiralAbyss spiralAbyss, string? reservedUserName)
|
||||
{
|
||||
Uid = uid;
|
||||
|
||||
@@ -48,6 +48,7 @@ internal static class HutaoEndpoints
|
||||
/// <summary>
|
||||
/// 删除祈愿记录
|
||||
/// </summary>
|
||||
/// <param name="uid">uid</param>
|
||||
/// <returns>删除祈愿记录 Url</returns>
|
||||
public static string GachaLogDelete(string uid)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user