gacha part 1

This commit is contained in:
DismissedLight
2022-09-13 12:47:04 +08:00
parent bd3430386b
commit 6ce6d9ac0f
25 changed files with 548 additions and 87 deletions

View File

@@ -0,0 +1,34 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Markup;
namespace Snap.Hutao.Control.Markup;
/// <summary>
/// Custom <see cref="Markup"/> which can provide <see cref="BitmapIcon"/> values.
/// </summary>
[MarkupExtensionReturnType(ReturnType = typeof(BitmapIcon))]
public sealed class BitmapIconExtension : MarkupExtension
{
/// <summary>
/// Gets or sets the <see cref="Uri"/> representing the image to display.
/// </summary>
public Uri Source { get; set; } = default!;
/// <summary>
/// Gets or sets a value indicating whether to display the icon as monochrome.
/// </summary>
public bool ShowAsMonochrome { get; set; } = true;
/// <inheritdoc/>
protected override object ProvideValue()
{
return new BitmapIcon
{
ShowAsMonochrome = ShowAsMonochrome,
UriSource = Source,
};
}
}

View File

@@ -0,0 +1,28 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Markup;
namespace Snap.Hutao.Control.Markup;
/// <summary>
/// Custom <see cref="Microsoft.UI.Xaml.Markup.MarkupExtension"/> which can provide <see cref="FontIcon"/> values.
/// </summary>
[MarkupExtensionReturnType(ReturnType = typeof(FontIcon))]
internal class FontIconExtension : MarkupExtension
{
/// <summary>
/// Gets or sets the <see cref="string"/> value representing the icon to display.
/// </summary>
public string Glyph { get; set; } = default!;
/// <inheritdoc/>
protected override object ProvideValue()
{
return new FontIcon()
{
Glyph = Glyph,
};
}
}

View File

@@ -8,6 +8,7 @@ namespace Snap.Hutao.Core.Database;
/// <summary>
/// 数据库当前项
/// 简化对数据库中选中项的管理
/// </summary>
/// <typeparam name="TEntity">实体的类型</typeparam>
/// <typeparam name="TMessage">消息的类型</typeparam>
@@ -35,7 +36,7 @@ internal class DbCurrent<TEntity, TMessage>
}
/// <summary>
/// 当前项
/// 当前选中的
/// </summary>
public TEntity? Current
{

View File

@@ -58,6 +58,40 @@ internal sealed class WindowManager : IDisposable
subclassManager?.Dispose();
}
private static void UpdateTitleButtonColor(AppWindowTitleBar appTitleBar)
{
appTitleBar.ButtonBackgroundColor = Colors.Transparent;
appTitleBar.ButtonInactiveBackgroundColor = Colors.Transparent;
App app = Ioc.Default.GetRequiredService<App>();
Color systemBaseLowColor = (Color)app.Resources["SystemBaseLowColor"];
appTitleBar.ButtonHoverBackgroundColor = systemBaseLowColor;
Color systemBaseMediumLowColor = (Color)app.Resources["SystemBaseMediumLowColor"];
appTitleBar.ButtonPressedBackgroundColor = systemBaseMediumLowColor;
// The Foreground doesn't accept Alpha channel. So we translate it to gray.
byte light = (byte)((systemBaseMediumLowColor.R + systemBaseMediumLowColor.G + systemBaseMediumLowColor.B) / 3);
byte result = (byte)((systemBaseMediumLowColor.A / 255.0) * light);
appTitleBar.ButtonInactiveForegroundColor = Color.FromArgb(0xFF, result, result, result);
Color systemBaseHighColor = (Color)app.Resources["SystemBaseHighColor"];
appTitleBar.ButtonForegroundColor = systemBaseHighColor;
appTitleBar.ButtonHoverForegroundColor = systemBaseHighColor;
appTitleBar.ButtonPressedForegroundColor = systemBaseHighColor;
}
private static (string PosString, string SizeString) GetPostionAndSize(AppWindow appWindow)
{
PointInt32 pos = appWindow.Position;
string posString = $"{pos.X},{pos.Y}";
SizeInt32 size = appWindow.Size;
string sizeString = $"{size.Width},{size.Height}";
return (posString, sizeString);
}
private void InitializeWindow()
{
appWindow.Title = "胡桃";
@@ -66,11 +100,8 @@ internal sealed class WindowManager : IDisposable
Persistence.RecoverOrInit(appWindow);
// Log basic window state here.
PointInt32 pos = appWindow.Position;
string posString = $"{pos.X},{pos.Y}";
SizeInt32 size = appWindow.Size;
string sizeString = $"{size.Width},{size.Height}";
logger.LogInformation(EventIds.WindowState, "Postion: [{pos}], Size: [{size}]", posString, sizeString);
(string pos, string size) = GetPostionAndSize(appWindow);
logger.LogInformation(EventIds.WindowState, "Postion: [{pos}], Size: [{size}]", pos, size);
appWindow.Show(true);
@@ -116,29 +147,4 @@ internal sealed class WindowManager : IDisposable
appTitleBar.SetDragRectangles(dragRects);
}
[SuppressMessage("", "CA1822")]
private void UpdateTitleButtonColor(AppWindowTitleBar appTitleBar)
{
appTitleBar.ButtonBackgroundColor = Colors.Transparent;
appTitleBar.ButtonInactiveBackgroundColor = Colors.Transparent;
App app = Ioc.Default.GetRequiredService<App>();
Color systemBaseLowColor = (Color)app.Resources["SystemBaseLowColor"];
appTitleBar.ButtonHoverBackgroundColor = systemBaseLowColor;
Color systemBaseMediumLowColor = (Color)app.Resources["SystemBaseMediumLowColor"];
appTitleBar.ButtonPressedBackgroundColor = systemBaseMediumLowColor;
// The Foreground doesn't accept Alpha channel. So we translate it to gray.
byte light = (byte)((systemBaseMediumLowColor.R + systemBaseMediumLowColor.G + systemBaseMediumLowColor.B) / 3);
byte result = (byte)((systemBaseMediumLowColor.A / 255.0) * light);
appTitleBar.ButtonInactiveForegroundColor = Color.FromArgb(0xFF, result, result, result);
Color systemBaseHighColor = (Color)app.Resources["SystemBaseHighColor"];
appTitleBar.ButtonForegroundColor = systemBaseHighColor;
appTitleBar.ButtonHoverForegroundColor = systemBaseHighColor;
appTitleBar.ButtonPressedForegroundColor = systemBaseHighColor;
}
}

View File

@@ -0,0 +1,23 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Model.Entity;
namespace Snap.Hutao.Message;
/// <summary>
/// 祈愿记录存档切换消息
/// </summary>
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
internal class GachaArchiveChangedMessage : ValueChangedMessage<GachaArchive>
{
/// <summary>
/// 构造一个新的用户切换消息
/// </summary>
/// <param name="oldArchive">老用户</param>
/// <param name="newArchive">新用户</param>
public GachaArchiveChangedMessage(GachaArchive? oldArchive, GachaArchive? newArchive)
: base(oldArchive, newArchive)
{
}
}

View File

@@ -0,0 +1,11 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Model.Binding;
/// <summary>
/// 祈愿统计
/// </summary>
public class GachaStatistics
{
}

View File

@@ -15,7 +15,7 @@ public class User : Observable
private readonly Entity.User inner;
private UserGameRole? selectedUserGameRole;
private bool isInitialized = false;
private bool isInitialized;
/// <summary>
/// 构造一个新的绑定视图用户
@@ -105,4 +105,4 @@ public class User : Observable
return UserInfo != null && UserGameRoles.Any();
}
}
}

View File

@@ -5,6 +5,7 @@ namespace Snap.Hutao.Model.InterChange.Achievement;
/// <summary>
/// 统一可交换成就格式
/// https://www.snapgenshin.com/development/UIAF.html
/// </summary>
public class UIAF
{

View File

@@ -0,0 +1,37 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Model.InterChange.GachaLog;
/// <summary>
/// 统一可交换祈愿格式
/// https://www.snapgenshin.com/development/UIGF.html
/// </summary>
public class UIGF
{
private static readonly List<string> SupportedVersion = new()
{
"v2.2",
};
/// <summary>
/// 信息
/// </summary>
[JsonPropertyName("info")]
public UIGFInfo Info { get; set; } = default!;
/// <summary>
/// 列表
/// </summary>
[JsonPropertyName("list")]
public List<UIGFItem> List { get; set; } = default!;
/// <summary>
/// 确认当前UIGF对象的版本是否受支持
/// </summary>
/// <returns>当前UIAF对象是否受支持</returns>
public bool IsCurrentVersionSupported()
{
return SupportedVersion.Contains(Info.UIGFVersion ?? string.Empty);
}
}

View File

@@ -0,0 +1,56 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Extension;
namespace Snap.Hutao.Model.InterChange.GachaLog;
/// <summary>
/// UIGF格式的信息
/// </summary>
public class UIGFInfo
{
/// <summary>
/// 用户Uid
/// </summary>
[JsonPropertyName("uid")]
public string Uid { get; set; } = default!;
/// <summary>
/// 语言
/// </summary>
[JsonPropertyName("lang")]
public string Language { get; set; } = default!;
/// <summary>
/// 导出的时间戳
/// </summary>
[JsonPropertyName("export_timestamp")]
public long? ExportTimestamp { get; set; }
/// <summary>
/// 导出时间
/// </summary>
public DateTimeOffset ExportDateTime
{
get => DateTimeOffsetExtensions.FromUnixTime(ExportTimestamp, DateTimeOffset.MinValue);
}
/// <summary>
/// 导出的 App 名称
/// </summary>
[JsonPropertyName("export_app")]
public string ExportApp { get; set; } = default!;
/// <summary>
/// 导出的 App 版本
/// </summary>
[JsonPropertyName("export_app_version")]
public string ExportAppVersion { get; set; } = default!;
/// <summary>
/// 使用的UIGF版本
/// </summary>
[JsonPropertyName("uigf_version")]
public string UIGFVersion { get; set; } = default!;
}

View File

@@ -0,0 +1,21 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using MiniExcelLibs.Attributes;
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
namespace Snap.Hutao.Model.InterChange.GachaLog;
/// <summary>
/// UIGF物品
/// </summary>
public class UIGFItem : GachaLogItem
{
/// <summary>
/// 额外祈愿映射
/// </summary>
[ExcelColumn(Name = "uigf_gacha_type")]
[JsonPropertyName("uigf_gacha_type")]
[JsonConverter(typeof(JsonStringEnumConverter))]
public GachaConfigType UIGFGachaType { get; set; } = default!;
}

View File

@@ -1,6 +1,12 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.Mvvm.Messaging;
using Snap.Hutao.Context.Database;
using Snap.Hutao.Core.Database;
using Snap.Hutao.Model.Entity;
using System.Collections.ObjectModel;
namespace Snap.Hutao.Service.GachaLog;
/// <summary>
@@ -9,10 +15,32 @@ namespace Snap.Hutao.Service.GachaLog;
[Injection(InjectAs.Transient, typeof(IGachaLogService))]
internal class GachaLogService : IGachaLogService
{
public GachaLogService()
{
private readonly AppDbContext appDbContext;
private readonly DbCurrent<GachaArchive, Message.GachaArchiveChangedMessage> dbCurrent;
private ObservableCollection<GachaArchive>? archiveCollection;
/// <summary>
/// 构造一个新的祈愿记录服务
/// </summary>
/// <param name="appDbContext">数据库上下文</param>
/// <param name="messenger">消息器</param>
public GachaLogService(AppDbContext appDbContext, IMessenger messenger)
{
this.appDbContext = appDbContext;
dbCurrent = new(appDbContext, appDbContext.GachaArchives, messenger);
}
/// <inheritdoc/>
public GachaArchive? CurrentArchive
{
get => dbCurrent.Current;
set => dbCurrent.Current = value;
}
/// <inheritdoc/>
public ObservableCollection<GachaArchive> GetArchiveCollection()
{
return archiveCollection ??= new(appDbContext.GachaArchives.ToList());
}
}

View File

@@ -1,6 +1,9 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Model.Entity;
using System.Collections.ObjectModel;
namespace Snap.Hutao.Service.GachaLog;
/// <summary>
@@ -8,5 +11,14 @@ namespace Snap.Hutao.Service.GachaLog;
/// </summary>
internal interface IGachaLogService
{
/// <summary>
/// 当前存档
/// </summary>
GachaArchive? CurrentArchive { get; set; }
/// <summary>
/// 获取可用于绑定的存档集合
/// </summary>
/// <returns>存档集合</returns>
ObservableCollection<GachaArchive> GetArchiveCollection();
}

View File

@@ -41,7 +41,7 @@ internal class MetadataService : IMetadataService, IMetadataInitializer, ISuppor
/// </summary>
private readonly TaskCompletionSource initializeCompletionSource = new();
private bool isInitialized = false;
private bool isInitialized;
/// <summary>
/// 构造一个新的元数据服务

View File

@@ -100,6 +100,7 @@
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.2.46-beta" />
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.1" />
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.1.4" />
<PackageReference Include="MiniExcel" Version="1.26.7" />
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.435">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
@@ -203,7 +204,6 @@
</ItemGroup>
<ItemGroup>
<Folder Include="Web\Hoyolab\Takumi\Event\" />
<Folder Include="Win32\UI\WindowsAndMessaging\" />
</ItemGroup>
<ItemGroup>
<Page Update="View\Page\GachaLogPage.xaml">

View File

@@ -8,6 +8,7 @@
xmlns:shv="using:Snap.Hutao.View"
xmlns:shvh="using:Snap.Hutao.View.Helper"
xmlns:shvp="using:Snap.Hutao.View.Page"
xmlns:shcm="using:Snap.Hutao.Control.Markup"
mc:Ignorable="d">
<UserControl.Resources>
<Thickness x:Key="NavigationViewContentMargin">0,44,0,0</Thickness>
@@ -24,22 +25,22 @@
<NavigationViewItem
Content="活动"
shvh:NavHelper.NavigateTo="shvp:AnnouncementPage"
Icon="{cwu:BitmapIcon ShowAsMonochrome=True,Source=ms-appx:///Resource/Icon/UI_BtnIcon_ActivityEntry.png}"/>
Icon="{shcm:BitmapIcon Source=ms-appx:///Resource/Icon/UI_BtnIcon_ActivityEntry.png}"/>
<NavigationViewItem
Content="成就"
shvh:NavHelper.NavigateTo="shvp:AchievementPage"
Icon="{cwu:BitmapIcon ShowAsMonochrome=True,Source=ms-appx:///Resource/Icon/UI_Icon_Achievement.png}"/>
Icon="{shcm:BitmapIcon Source=ms-appx:///Resource/Icon/UI_Icon_Achievement.png}"/>
<NavigationViewItem
Content="角色"
shvh:NavHelper.NavigateTo="shvp:WikiAvatarPage"
Icon="{cwu:BitmapIcon ShowAsMonochrome=True,Source=ms-appx:///Resource/Icon/UI_BagTabIcon_Avatar.png}"/>
Icon="{shcm:BitmapIcon Source=ms-appx:///Resource/Icon/UI_BagTabIcon_Avatar.png}"/>
<NavigationViewItem
Content="祈愿记录"
shvh:NavHelper.NavigateTo="shvp:GachaLogPage"
Icon="{cwu:BitmapIcon ShowAsMonochrome=True,Source=ms-appx:///Resource/Icon/UI_BtnIcon_Gacha.png}"/>
Icon="{shcm:BitmapIcon Source=ms-appx:///Resource/Icon/UI_BtnIcon_Gacha.png}"/>
</NavigationView.MenuItems>
<NavigationView.PaneFooter>

View File

@@ -10,6 +10,7 @@
xmlns:shci="using:Snap.Hutao.Control.Image"
xmlns:shmmc="using:Snap.Hutao.Model.Metadata.Converter"
xmlns:shv="using:Snap.Hutao.ViewModel"
xmlns:shcm="using:Snap.Hutao.Control.Markup"
xmlns:cwuc="using:CommunityToolkit.WinUI.UI.Converters"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
@@ -37,7 +38,6 @@
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<CommandBar
Grid.Column="1"
DefaultLabelPosition="Right">
<CommandBar.Content>
@@ -61,42 +61,37 @@
</AppBarElementContainer>
<AppBarButton
Label="创建新存档"
Command="{Binding AddArchiveCommand}">
<AppBarButton.Icon>
<FontIcon Glyph="&#xE710;"/>
</AppBarButton.Icon>
</AppBarButton>
Icon="{shcm:FontIcon Glyph=&#xE710;}"
Command="{Binding AddArchiveCommand}"/>
<AppBarButton
Label="删除当前存档"
Command="{Binding RemoveArchiveCommand}">
<AppBarButton.Icon>
<FontIcon Glyph="&#xE74D;"/>
</AppBarButton.Icon>
</AppBarButton>
Icon="{shcm:FontIcon Glyph=&#xE74D;}"
Command="{Binding RemoveArchiveCommand}"/>
<AppBarSeparator/>
<AppBarButton
Label="从剪贴板导入"
Command="{Binding ImportUIAFFromClipboardCommand}">
<AppBarButton.Icon>
<FontIcon Glyph="&#xE8B5;"/>
</AppBarButton.Icon>
</AppBarButton>
<AppBarButton
Label="从UIAF文件导入"
Command="{Binding ImportUIAFFromFileCommand}">
<AppBarButton.Icon>
<FontIcon Glyph="&#xE8E5;"/>
</AppBarButton.Icon>
Label="导入"
Icon="{shcm:FontIcon Glyph=&#xE8B5;}">
<AppBarButton.Flyout>
<MenuFlyout Placement="BottomEdgeAlignedRight">
<MenuFlyoutItem
Text="从剪贴板导入"
Icon="{shcm:FontIcon Glyph=&#xE77F;}"
Command="{Binding ImportUIAFFromClipboardCommand}"/>
<MenuFlyoutItem
Text="从 UIAF 文件导入"
Icon="{shcm:FontIcon Glyph=&#xE8E5;}"
Command="{Binding ImportUIAFFromFileCommand}"/>
</MenuFlyout>
</AppBarButton.Flyout>
</AppBarButton>
<AppBarSeparator/>
<AppBarToggleButton
Label="优先未完成"
Icon="{shcm:FontIcon Glyph=&#xE8CB;}"
IsChecked="{Binding IsIncompletedItemsFirst}"
Command="{Binding SortIncompletedSwitchCommand}">
<AppBarToggleButton.Icon>
<FontIcon Glyph="&#xE8CB;"/>
</AppBarToggleButton.Icon>
</AppBarToggleButton>
Command="{Binding SortIncompletedSwitchCommand}"/>
</CommandBar>
</Grid>

View File

@@ -1,14 +1,70 @@
<control:ScopedPage
<shc:ScopedPage
x:Class="Snap.Hutao.View.Page.GachaLogPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:shcm="using:Snap.Hutao.Control.Markup"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:control="using:Snap.Hutao.Control"
xmlns:shc="using:Snap.Hutao.Control"
xmlns:shv="using:Snap.Hutao.ViewModel"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance shv:GachaLogViewModel}"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<CommandBar DefaultLabelPosition="Right">
<CommandBar.Background>
<SolidColorBrush Color="{ThemeResource CardBackgroundFillColorSecondary}"/>
</CommandBar.Background>
<CommandBar.Content>
<ComboBox
MinWidth="120"
Height="36"
Margin="2,6,3,6"/>
</CommandBar.Content>
<AppBarButton Label="刷新" Icon="{shcm:FontIcon Glyph=&#xE72C;}">
<AppBarButton.Flyout>
<MenuFlyout Placement="Bottom">
<MenuFlyoutItem
Text="从缓存刷新"
Icon="{shcm:FontIcon Glyph=&#xE721;}"
Command="{Binding RefreshByWebCacheCommand}"/>
<MenuFlyoutItem
Text="手动输入Url"
Icon="{shcm:FontIcon Glyph=&#xE765;}"
Command="{Binding RefreshByManualInputCommand}"/>
</MenuFlyout>
</AppBarButton.Flyout>
</AppBarButton>
<AppBarSeparator/>
<AppBarButton Label="导入" Icon="{shcm:FontIcon Glyph=&#xE8B5;}">
<AppBarButton.Flyout>
<MenuFlyout Placement="Bottom">
<MenuFlyoutItem
Text="从 UIGF Json 文件导入"
Command="{Binding ImportFromUIGFJsonCommand}"/>
<MenuFlyoutItem
Text="从 UIGF Excel 文件导入"
Command="{Binding ImportFromUIGFExcelCommand}"/>
</MenuFlyout>
</AppBarButton.Flyout>
</AppBarButton>
<AppBarButton Label="导出" Icon="{shcm:FontIcon Glyph=&#xEDE1;}">
<AppBarButton.Flyout>
<MenuFlyout Placement="Bottom">
<MenuFlyoutItem
Text="导出到 UIGF Json 文件"
Command="{Binding ExportToUIGFJsonCommand}"/>
<MenuFlyoutItem
Text="导出到 UIGF Excel 文件"
Command="{Binding ExportToUIGFExcelCommand}"/>
</MenuFlyout>
</AppBarButton.Flyout>
</AppBarButton>
</CommandBar>
</Grid>
</control:ScopedPage>
</shc:ScopedPage>

View File

@@ -269,7 +269,6 @@ internal class AchievementViewModel
AchievementGoals = goals.OrderBy(goal => goal.Order).ToList();
Archives = achievementService.GetArchiveCollection();
SelectedArchive = Archives.SingleOrDefault(a => a.IsSelected == true);
if (SelectedArchive == null)

View File

@@ -1,7 +1,16 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.Mvvm.ComponentModel;
using Snap.Hutao.Control;
using Snap.Hutao.Factory.Abstraction;
using Snap.Hutao.Model.Binding;
using Snap.Hutao.Model.Entity;
using Snap.Hutao.Service;
using Snap.Hutao.Service.Abstraction;
using Snap.Hutao.Service.GachaLog;
using Snap.Hutao.Service.Metadata;
using System.Collections.ObjectModel;
namespace Snap.Hutao.ViewModel;
@@ -9,8 +18,136 @@ namespace Snap.Hutao.ViewModel;
/// 祈愿记录视图模型
/// </summary>
[Injection(InjectAs.Transient)]
internal class GachaLogViewModel : ISupportCancellation
internal class GachaLogViewModel : ObservableObject, ISupportCancellation
{
private readonly IMetadataService metadataService;
private readonly IGachaLogService gachaLogService;
private readonly IInfoBarService infoBarService;
private ObservableCollection<GachaArchive>? archives;
private GachaArchive? selectedArchive;
private GachaStatistics? statistics;
/// <summary>
/// 构造一个新的祈愿记录视图模型
/// </summary>
/// <param name="metadataService">元数据服务</param>
/// <param name="gachaLogService">祈愿记录服务</param>
/// <param name="infoBarService">信息</param>
/// <param name="asyncRelayCommandFactory">异步命令工厂</param>
public GachaLogViewModel(
IMetadataService metadataService,
IGachaLogService gachaLogService,
IInfoBarService infoBarService,
IAsyncRelayCommandFactory asyncRelayCommandFactory)
{
this.metadataService = metadataService;
this.gachaLogService = gachaLogService;
this.infoBarService = infoBarService;
OpenUICommand = asyncRelayCommandFactory.Create(OpenUIAsync);
RefreshByWebCacheCommand = asyncRelayCommandFactory.Create(RefreshByWebCacheAsync);
RefreshByManualInputCommand = asyncRelayCommandFactory.Create(RefreshByManualInputAsync);
ImportFromUIGFExcelCommand = asyncRelayCommandFactory.Create(ImportFromUIGFExcelAsync);
ImportFromUIGFJsonCommand = asyncRelayCommandFactory.Create(ImportFromUIGFJsonAsync);
ExportToUIGFExcelCommand = asyncRelayCommandFactory.Create(ExportToUIGFExcelAsync);
ExportToUIGFJsonCommand = asyncRelayCommandFactory.Create(ExportToUIGFJsonAsync);
}
/// <inheritdoc/>
public CancellationToken CancellationToken { get; set; }
}
/// <summary>
/// 存档集合
/// </summary>
public ObservableCollection<GachaArchive>? Archives { get => archives; set => SetProperty(ref archives, value); }
/// <summary>
/// 选中的存档
/// </summary>
public GachaArchive? SelectedArchive { get => selectedArchive; set => SetProperty(ref selectedArchive, value); }
/// <summary>
/// 当前统计信息
/// </summary>
public GachaStatistics? Statistics { get => statistics; set => SetProperty(ref statistics, value); }
/// <summary>
/// 页面加载命令
/// </summary>
public ICommand OpenUICommand { get; }
/// <summary>
/// 浏览器缓存刷新命令
/// </summary>
public ICommand RefreshByWebCacheCommand { get; }
/// <summary>
/// 手动输入Url刷新命令
/// </summary>
public ICommand RefreshByManualInputCommand { get; }
/// <summary>
/// 从 UIGF Excel 导入命令
/// </summary>
public ICommand ImportFromUIGFExcelCommand { get; }
/// <summary>
/// 从 UIGF Json 导入命令
/// </summary>
public ICommand ImportFromUIGFJsonCommand { get; }
/// <summary>
/// 导出到 UIGF Excel 命令
/// </summary>
public ICommand ExportToUIGFExcelCommand { get; }
/// <summary>
/// 导出到 UIGF Json 命令
/// </summary>
public ICommand ExportToUIGFJsonCommand { get; }
private async Task OpenUIAsync()
{
if (await metadataService.InitializeAsync().ConfigureAwait(false))
{
Archives = gachaLogService.GetArchiveCollection();
SelectedArchive = Archives.SingleOrDefault(a => a.IsSelected == true);
if (SelectedArchive == null)
{
//infoBarService.Warning("请创建一个成就存档");
}
}
}
private async Task RefreshByWebCacheAsync()
{
Statistics = await gachaLogService.RefreshAsync();
}
private async Task RefreshByManualInputAsync()
{
}
private async Task ImportFromUIGFExcelAsync()
{
}
private async Task ImportFromUIGFJsonAsync()
{
}
private async Task ExportToUIGFExcelAsync()
{
}
private async Task ExportToUIGFJsonAsync()
{
}
}

View File

@@ -1,6 +1,7 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using MiniExcelLibs.Attributes;
using Snap.Hutao.Model.Intrinsic;
namespace Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
@@ -13,12 +14,14 @@ public class GachaLogItem
/// <summary>
/// 玩家Uid
/// </summary>
[ExcelColumn(Name = "uid")]
[JsonPropertyName("uid")]
public string Uid { get; set; } = default!;
/// <summary>
/// 祈愿类型
/// </summary>
[ExcelColumn(Name = "gacha_type")]
[JsonPropertyName("gacha_type")]
[JsonConverter(typeof(JsonStringEnumConverter))]
public GachaConfigType GachaType { get; set; } = default!;
@@ -26,14 +29,15 @@ public class GachaLogItem
/// <summary>
/// 总为 <see cref="string.Empty"/>
/// </summary>
[ExcelColumn(Name = "item_id")]
[Obsolete("API clear this property")]
[JsonPropertyName("item_id")]
public string ItemId { get; set; } = default!;
/// <summary>
/// 个数
/// 一般为 1
/// 个数 一般为 1
/// </summary>
[ExcelColumn(Name = "count")]
[JsonPropertyName("count")]
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString)]
public int Count { get; set; }
@@ -41,6 +45,7 @@ public class GachaLogItem
/// <summary>
/// 时间
/// </summary>
[ExcelColumn(Name = "time", Format = "yyyy-MM-dd HH:mm:ss")]
[JsonPropertyName("time")]
[JsonConverter(typeof(Core.Json.Converter.DateTimeOffsetConverter))]
public DateTimeOffset Time { get; set; }
@@ -48,24 +53,28 @@ public class GachaLogItem
/// <summary>
/// 物品名称
/// </summary>
[ExcelColumn(Name = "name")]
[JsonPropertyName("name")]
public string Name { get; set; } = default!;
/// <summary>
/// 语言
/// </summary>
[ExcelColumn(Name = "lang")]
[JsonPropertyName("lang")]
public string Language { get; set; } = default!;
/// <summary>
/// 物品类型
/// </summary>
[ExcelColumn(Name = "item_type")]
[JsonPropertyName("item_type")]
public string ItemType { get; set; } = default!;
/// <summary>
/// 物品稀有等级
/// </summary>
[ExcelColumn(Name = "rank_type")]
[JsonPropertyName("rank_type")]
[JsonConverter(typeof(JsonStringEnumConverter))]
public ItemQuality Rank { get; set; } = default!;
@@ -73,6 +82,7 @@ public class GachaLogItem
/// <summary>
/// Id
/// </summary>
[ExcelColumn(Name = "id")]
[JsonPropertyName("id")]
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString)]
public long Id { get; set; } = default!;

View File

@@ -19,8 +19,7 @@ internal static class MemoryExtensions
public static unsafe string AsString(this MODULEENTRY32.__winmdroot_Foundation_CHAR_256 char256)
{
byte* pszModule = (byte*)&char256;
string szModule = Encoding.UTF8.GetString(pszModule, StringLength(pszModule));
return szModule;
return Encoding.UTF8.GetString(pszModule, StringLength(pszModule));
}
private static unsafe int StringLength(byte* pszStr)

View File

@@ -13,7 +13,7 @@ internal static class StructMarshal
/// <summary>
/// 构造一个新的 <see cref="Windows.Win32.System.Diagnostics.ToolHelp.MODULEENTRY32"/>
/// </summary>
/// <returns>实例</returns>
/// <returns>新的实例</returns>
public static unsafe MODULEENTRY32 MODULEENTRY32()
{
return new() { dwSize = (uint)sizeof(MODULEENTRY32) };