3
.github/dependabot.yml
vendored
@@ -7,9 +7,10 @@ version: 2
|
|||||||
updates:
|
updates:
|
||||||
- package-ecosystem: "nuget"
|
- package-ecosystem: "nuget"
|
||||||
directory: "/src/Snap.Hutao" # Snap.Hutao.csproj
|
directory: "/src/Snap.Hutao" # Snap.Hutao.csproj
|
||||||
|
target-branch: "develop"
|
||||||
schedule:
|
schedule:
|
||||||
interval: "weekly"
|
interval: "weekly"
|
||||||
groups:
|
groups:
|
||||||
main-dependencies:
|
packages:
|
||||||
patterns:
|
patterns:
|
||||||
- "*"
|
- "*"
|
||||||
@@ -35,7 +35,6 @@ Snap Hutao is an open-source Genshin Impact toolbox on Windows platform, aim to
|
|||||||
* [dotnet/runtime](https://github.com/dotnet/runtime)
|
* [dotnet/runtime](https://github.com/dotnet/runtime)
|
||||||
* [DotNetAnalyzers/StyleCopAnalyzers](https://github.com/DotNetAnalyzers/StyleCopAnalyzers)
|
* [DotNetAnalyzers/StyleCopAnalyzers](https://github.com/DotNetAnalyzers/StyleCopAnalyzers)
|
||||||
* [microsoft/CsWin32](https://github.com/microsoft/CsWin32)
|
* [microsoft/CsWin32](https://github.com/microsoft/CsWin32)
|
||||||
* [microsoft/vs-threading](https://github.com/microsoft/vs-threading)
|
|
||||||
* [microsoft/vs-validation](https://github.com/microsoft/vs-validation)
|
* [microsoft/vs-validation](https://github.com/microsoft/vs-validation)
|
||||||
* [microsoft/WindowsAppSDK](https://github.com/microsoft/WindowsAppSDK)
|
* [microsoft/WindowsAppSDK](https://github.com/microsoft/WindowsAppSDK)
|
||||||
* [microsoft/microsoft-ui-xaml](https://github.com/microsoft/microsoft-ui-xaml)
|
* [microsoft/microsoft-ui-xaml](https://github.com/microsoft/microsoft-ui-xaml)
|
||||||
|
|||||||
@@ -2,13 +2,10 @@
|
|||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using Microsoft.CodeAnalysis;
|
using Microsoft.CodeAnalysis;
|
||||||
using Microsoft.CodeAnalysis.CSharp;
|
|
||||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
using Snap.Hutao.SourceGeneration.Primitive;
|
using Snap.Hutao.SourceGeneration.Primitive;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
namespace Snap.Hutao.SourceGeneration.Automation;
|
namespace Snap.Hutao.SourceGeneration.Automation;
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using Microsoft.CodeAnalysis;
|
using Microsoft.CodeAnalysis;
|
||||||
using Microsoft.CodeAnalysis.CSharp;
|
|
||||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
using Snap.Hutao.SourceGeneration.Primitive;
|
using Snap.Hutao.SourceGeneration.Primitive;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@@ -75,7 +74,7 @@ internal sealed class ConstructorGenerator : IIncrementalGenerator
|
|||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("{{nameof(ConstructorGenerator)}}", "1.0.0.0")]
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("{{nameof(ConstructorGenerator)}}", "1.0.0.0")]
|
||||||
partial class {{context2.Symbol.ToDisplayString(SymbolDisplayFormats.QualifiedNonNullableFormat)}}
|
partial class {{context2.Symbol.ToDisplayString(SymbolDisplayFormats.QualifiedNonNullableFormat)}}
|
||||||
{
|
{
|
||||||
public {{context2.Symbol.Name}}(System.IServiceProvider serviceProvider{{httpclient}}){{(options.CallBaseConstructor? " : base(serviceProvider)" : string.Empty)}}
|
public {{context2.Symbol.Name}}(System.IServiceProvider serviceProvider{{httpclient}}){{(options.CallBaseConstructor ? " : base(serviceProvider)" : string.Empty)}}
|
||||||
{
|
{
|
||||||
|
|
||||||
""");
|
""");
|
||||||
@@ -180,7 +179,7 @@ internal sealed class ConstructorGenerator : IIncrementalGenerator
|
|||||||
|
|
||||||
public FieldValueAssignmentOptions(bool resolveHttpClient, bool callBaseConstructor)
|
public FieldValueAssignmentOptions(bool resolveHttpClient, bool callBaseConstructor)
|
||||||
{
|
{
|
||||||
ResolveHttpClient = resolveHttpClient;
|
ResolveHttpClient = resolveHttpClient;
|
||||||
CallBaseConstructor = callBaseConstructor;
|
CallBaseConstructor = callBaseConstructor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ using Microsoft.CodeAnalysis;
|
|||||||
using Microsoft.CodeAnalysis.CSharp;
|
using Microsoft.CodeAnalysis.CSharp;
|
||||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
using Snap.Hutao.SourceGeneration.Primitive;
|
using Snap.Hutao.SourceGeneration.Primitive;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ using Microsoft.CodeAnalysis.CSharp;
|
|||||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
using Microsoft.CodeAnalysis.Diagnostics;
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
using Snap.Hutao.SourceGeneration.Primitive;
|
using Snap.Hutao.SourceGeneration.Primitive;
|
||||||
using System;
|
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
@@ -15,11 +14,14 @@ internal class ServiceAnalyzer : DiagnosticAnalyzer
|
|||||||
private static readonly DiagnosticDescriptor NonSingletonUseServiceProviderDescriptor = new("SH301", "Non Singleton service should avoid direct use of IServiceProvider", "Non Singleton service should avoid direct use of IServiceProvider", "Quality", DiagnosticSeverity.Info, true);
|
private static readonly DiagnosticDescriptor NonSingletonUseServiceProviderDescriptor = new("SH301", "Non Singleton service should avoid direct use of IServiceProvider", "Non Singleton service should avoid direct use of IServiceProvider", "Quality", DiagnosticSeverity.Info, true);
|
||||||
private static readonly DiagnosticDescriptor SingletonServiceCaptureNonSingletonServiceDescriptor = new("SH302", "Singleton service should avoid keep reference of non singleton service", "Singleton service should avoid keep reference of non singleton service", "Quality", DiagnosticSeverity.Info, true);
|
private static readonly DiagnosticDescriptor SingletonServiceCaptureNonSingletonServiceDescriptor = new("SH302", "Singleton service should avoid keep reference of non singleton service", "Singleton service should avoid keep reference of non singleton service", "Quality", DiagnosticSeverity.Info, true);
|
||||||
|
|
||||||
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get => new DiagnosticDescriptor[]
|
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
|
||||||
|
{
|
||||||
|
get => new DiagnosticDescriptor[]
|
||||||
{
|
{
|
||||||
NonSingletonUseServiceProviderDescriptor,
|
NonSingletonUseServiceProviderDescriptor,
|
||||||
SingletonServiceCaptureNonSingletonServiceDescriptor,
|
SingletonServiceCaptureNonSingletonServiceDescriptor,
|
||||||
}.ToImmutableArray(); }
|
}.ToImmutableArray();
|
||||||
|
}
|
||||||
|
|
||||||
public override void Initialize(AnalysisContext context)
|
public override void Initialize(AnalysisContext context)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ internal class LocalizedEnumGenerator : IIncrementalGenerator
|
|||||||
.Where(m => m.Kind == SymbolKind.Field)
|
.Where(m => m.Kind == SymbolKind.Field)
|
||||||
.Cast<IFieldSymbol>();
|
.Cast<IFieldSymbol>();
|
||||||
|
|
||||||
foreach(IFieldSymbol fieldSymbol in fields)
|
foreach (IFieldSymbol fieldSymbol in fields)
|
||||||
{
|
{
|
||||||
AttributeData? localizationKeyInfo = fieldSymbol.GetAttributes()
|
AttributeData? localizationKeyInfo = fieldSymbol.GetAttributes()
|
||||||
.SingleOrDefault(data => data.AttributeClass!.ToDisplayString() == LocalizationKeyName);
|
.SingleOrDefault(data => data.AttributeClass!.ToDisplayString() == LocalizationKeyName);
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ namespace Snap.Hutao.SourceGeneration.Primitive;
|
|||||||
|
|
||||||
internal static class GeneratorSyntaxContextExtension
|
internal static class GeneratorSyntaxContextExtension
|
||||||
{
|
{
|
||||||
public static bool TryGetDeclaredSymbol<TSymbol>(this GeneratorSyntaxContext context, System.Threading.CancellationToken token,[NotNullWhen(true)] out TSymbol? symbol)
|
public static bool TryGetDeclaredSymbol<TSymbol>(this GeneratorSyntaxContext context, System.Threading.CancellationToken token, [NotNullWhen(true)] out TSymbol? symbol)
|
||||||
where TSymbol : class, ISymbol
|
where TSymbol : class, ISymbol
|
||||||
{
|
{
|
||||||
symbol = context.SemanticModel.GetDeclaredSymbol(context.Node, token) as TSymbol;
|
symbol = context.SemanticModel.GetDeclaredSymbol(context.Node, token) as TSymbol;
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ using Microsoft.CodeAnalysis.CSharp;
|
|||||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
using Microsoft.CodeAnalysis.Diagnostics;
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
using Snap.Hutao.SourceGeneration.Primitive;
|
using Snap.Hutao.SourceGeneration.Primitive;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -129,7 +128,7 @@ internal sealed class UniversalAnalyzer : DiagnosticAnalyzer
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ICommand can only use Task or Task<T>
|
// ICommand can only use Task or Task<T>
|
||||||
if (methodSymbol.GetAttributes().Any(attr=>attr.AttributeClass!.ToDisplayString() == Automation.CommandGenerator.AttributeName))
|
if (methodSymbol.GetAttributes().Any(attr => attr.AttributeClass!.ToDisplayString() == Automation.CommandGenerator.AttributeName))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -241,7 +240,7 @@ internal sealed class UniversalAnalyzer : DiagnosticAnalyzer
|
|||||||
Diagnostic diagnostic = Diagnostic.Create(useIsNotNullPatternMatchingDescriptor, location);
|
Diagnostic diagnostic = Diagnostic.Create(useIsNotNullPatternMatchingDescriptor, location);
|
||||||
context.ReportDiagnostic(diagnostic);
|
context.ReportDiagnostic(diagnostic);
|
||||||
}
|
}
|
||||||
else if(syntax.IsKind(SyntaxKind.EqualsExpression) && syntax.Right.IsKind(SyntaxKind.NullLiteralExpression))
|
else if (syntax.IsKind(SyntaxKind.EqualsExpression) && syntax.Right.IsKind(SyntaxKind.NullLiteralExpression))
|
||||||
{
|
{
|
||||||
Location location = syntax.OperatorToken.GetLocation();
|
Location location = syntax.OperatorToken.GetLocation();
|
||||||
Diagnostic diagnostic = Diagnostic.Create(useIsNullPatternMatchingDescriptor, location);
|
Diagnostic diagnostic = Diagnostic.Create(useIsNullPatternMatchingDescriptor, location);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
xmlns:cwcw="using:CommunityToolkit.WinUI.Controls"
|
xmlns:cwcw="using:CommunityToolkit.WinUI.Controls"
|
||||||
xmlns:cwuc="using:CommunityToolkit.WinUI.UI.Converters"
|
xmlns:cwuc="using:CommunityToolkit.WinUI.UI.Converters"
|
||||||
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
|
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
|
||||||
|
xmlns:shci="using:Snap.Hutao.Control.Image"
|
||||||
xmlns:shmmc="using:Snap.Hutao.Model.Metadata.Converter"
|
xmlns:shmmc="using:Snap.Hutao.Model.Metadata.Converter"
|
||||||
xmlns:shvc="using:Snap.Hutao.View.Converter">
|
xmlns:shvc="using:Snap.Hutao.View.Converter">
|
||||||
<Application.Resources>
|
<Application.Resources>
|
||||||
@@ -43,14 +44,14 @@
|
|||||||
<CornerRadius x:Key="CompatCornerRadiusRight">0,6,6,0</CornerRadius>
|
<CornerRadius x:Key="CompatCornerRadiusRight">0,6,6,0</CornerRadius>
|
||||||
<CornerRadius x:Key="CompatCornerRadiusBottom">0,0,6,6</CornerRadius>
|
<CornerRadius x:Key="CompatCornerRadiusBottom">0,0,6,6</CornerRadius>
|
||||||
<CornerRadius x:Key="CompatCornerRadiusSmall">2</CornerRadius>
|
<CornerRadius x:Key="CompatCornerRadiusSmall">2</CornerRadius>
|
||||||
<!-- OpenPaneLength -->
|
<!-- Length -->
|
||||||
<x:Double x:Key="CompatSplitViewOpenPaneLength">212</x:Double>
|
|
||||||
|
|
||||||
<x:Double x:Key="CompatSplitViewOpenPaneLength2">304</x:Double>
|
|
||||||
<GridLength x:Key="CompatGridLength2">288</GridLength>
|
<GridLength x:Key="CompatGridLength2">288</GridLength>
|
||||||
|
<x:Double x:Key="CompatSplitViewOpenPaneLength">212</x:Double>
|
||||||
|
<x:Double x:Key="CompatSplitViewOpenPaneLength2">304</x:Double>
|
||||||
|
<x:Double x:Key="CompatSplitViewOpenPaneLength3">320</x:Double>
|
||||||
<x:Double x:Key="HomeAdaptiveCardHeight">180</x:Double>
|
<x:Double x:Key="HomeAdaptiveCardHeight">180</x:Double>
|
||||||
|
<x:Double x:Key="ContentDialogMinHeight">64</x:Double>
|
||||||
|
<x:Double x:Key="LargeAppBarButtonWidth">100</x:Double>
|
||||||
<!-- ProgressBar -->
|
<!-- ProgressBar -->
|
||||||
<x:Double x:Key="LargeBackgroundProgressBarOpacity">0.2</x:Double>
|
<x:Double x:Key="LargeBackgroundProgressBarOpacity">0.2</x:Double>
|
||||||
|
|
||||||
@@ -493,7 +494,83 @@
|
|||||||
</Setter.Value>
|
</Setter.Value>
|
||||||
</Setter>
|
</Setter>
|
||||||
</Style>
|
</Style>
|
||||||
|
<Style TargetType="shci:CachedImage">
|
||||||
|
<Setter Property="Background" Value="Transparent"/>
|
||||||
|
<Setter Property="Foreground" Value="{ThemeResource ApplicationForegroundThemeBrush}"/>
|
||||||
|
<Setter Property="IsTabStop" Value="False"/>
|
||||||
|
<Setter Property="LazyLoadingThreshold" Value="300"/>
|
||||||
|
<Setter Property="Template">
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate TargetType="shci:CachedImage">
|
||||||
|
<Grid
|
||||||
|
Background="{TemplateBinding Background}"
|
||||||
|
BorderBrush="{TemplateBinding BorderBrush}"
|
||||||
|
BorderThickness="{TemplateBinding BorderThickness}"
|
||||||
|
CornerRadius="{TemplateBinding CornerRadius}">
|
||||||
|
<Image
|
||||||
|
Name="PlaceholderImage"
|
||||||
|
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
|
||||||
|
VerticalAlignment="{TemplateBinding VerticalAlignment}"
|
||||||
|
Opacity="1.0"
|
||||||
|
Source="{TemplateBinding PlaceholderSource}"
|
||||||
|
Stretch="{TemplateBinding PlaceholderStretch}"/>
|
||||||
|
<Image
|
||||||
|
Name="Image"
|
||||||
|
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
|
||||||
|
VerticalAlignment="{TemplateBinding VerticalAlignment}"
|
||||||
|
NineGrid="{TemplateBinding NineGrid}"
|
||||||
|
Opacity="0.0"
|
||||||
|
Stretch="{TemplateBinding Stretch}"/>
|
||||||
|
<VisualStateManager.VisualStateGroups>
|
||||||
|
<VisualStateGroup x:Name="CommonStates">
|
||||||
|
<VisualState x:Name="Failed">
|
||||||
|
<Storyboard>
|
||||||
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Image" Storyboard.TargetProperty="Opacity">
|
||||||
|
<DiscreteObjectKeyFrame KeyTime="0" Value="0"/>
|
||||||
|
</ObjectAnimationUsingKeyFrames>
|
||||||
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PlaceholderImage" Storyboard.TargetProperty="Opacity">
|
||||||
|
<DiscreteObjectKeyFrame KeyTime="0" Value="1"/>
|
||||||
|
</ObjectAnimationUsingKeyFrames>
|
||||||
|
</Storyboard>
|
||||||
|
</VisualState>
|
||||||
|
<VisualState x:Name="Loading">
|
||||||
|
<Storyboard>
|
||||||
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Image" Storyboard.TargetProperty="Opacity">
|
||||||
|
<DiscreteObjectKeyFrame KeyTime="0" Value="0"/>
|
||||||
|
</ObjectAnimationUsingKeyFrames>
|
||||||
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PlaceholderImage" Storyboard.TargetProperty="Opacity">
|
||||||
|
<DiscreteObjectKeyFrame KeyTime="0" Value="1"/>
|
||||||
|
</ObjectAnimationUsingKeyFrames>
|
||||||
|
</Storyboard>
|
||||||
|
</VisualState>
|
||||||
|
<VisualState x:Name="Loaded">
|
||||||
|
<Storyboard>
|
||||||
|
<DoubleAnimation
|
||||||
|
AutoReverse="False"
|
||||||
|
BeginTime="0"
|
||||||
|
Storyboard.TargetName="Image"
|
||||||
|
Storyboard.TargetProperty="Opacity"
|
||||||
|
From="0"
|
||||||
|
To="1"
|
||||||
|
Duration="0:0:0.5"/>
|
||||||
|
<DoubleAnimation
|
||||||
|
AutoReverse="False"
|
||||||
|
BeginTime="0"
|
||||||
|
Storyboard.TargetName="PlaceholderImage"
|
||||||
|
Storyboard.TargetProperty="Opacity"
|
||||||
|
From="1"
|
||||||
|
To="0"
|
||||||
|
Duration="0:0:0.5"/>
|
||||||
|
</Storyboard>
|
||||||
|
</VisualState>
|
||||||
|
<VisualState x:Name="Unloaded"/>
|
||||||
|
</VisualStateGroup>
|
||||||
|
</VisualStateManager.VisualStateGroups>
|
||||||
|
</Grid>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
<!-- ItemsPanelTemplate -->
|
<!-- ItemsPanelTemplate -->
|
||||||
<ItemsPanelTemplate x:Key="ItemsStackPanelTemplate">
|
<ItemsPanelTemplate x:Key="ItemsStackPanelTemplate">
|
||||||
<ItemsStackPanel/>
|
<ItemsStackPanel/>
|
||||||
|
|||||||
@@ -22,17 +22,18 @@ internal sealed partial class AutoHeightBehavior : BehaviorBase<FrameworkElement
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
protected override void OnAssociatedObjectLoaded()
|
protected override bool Initialize()
|
||||||
{
|
{
|
||||||
UpdateElement();
|
UpdateElement();
|
||||||
AssociatedObject.SizeChanged += sizeChangedEventHandler;
|
AssociatedObject.SizeChanged += sizeChangedEventHandler;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
protected override void OnDetaching()
|
protected override bool Uninitialize()
|
||||||
{
|
{
|
||||||
AssociatedObject.SizeChanged -= sizeChangedEventHandler;
|
AssociatedObject.SizeChanged -= sizeChangedEventHandler;
|
||||||
base.OnDetaching();
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnSizeChanged(object sender, SizeChangedEventArgs e)
|
private void OnSizeChanged(object sender, SizeChangedEventArgs e)
|
||||||
|
|||||||
@@ -22,17 +22,18 @@ internal sealed partial class AutoWidthBehavior : BehaviorBase<FrameworkElement>
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
protected override void OnAssociatedObjectLoaded()
|
protected override bool Initialize()
|
||||||
{
|
{
|
||||||
UpdateElement();
|
UpdateElement();
|
||||||
AssociatedObject.SizeChanged += sizeChangedEventHandler;
|
AssociatedObject.SizeChanged += sizeChangedEventHandler;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
protected override void OnDetaching()
|
protected override bool Uninitialize()
|
||||||
{
|
{
|
||||||
AssociatedObject.SizeChanged -= sizeChangedEventHandler;
|
AssociatedObject.SizeChanged -= sizeChangedEventHandler;
|
||||||
base.OnDetaching();
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnSizeChanged(object sender, SizeChangedEventArgs e)
|
private void OnSizeChanged(object sender, SizeChangedEventArgs e)
|
||||||
|
|||||||
@@ -28,19 +28,19 @@ internal sealed class ComboBoxExtendsContentIntoTitleBarWorkaroundBehavior : Beh
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
protected override void OnAssociatedObjectLoaded()
|
protected override bool Initialize()
|
||||||
{
|
{
|
||||||
AssociatedObject.DropDownOpened += dropDownOpenedHandler;
|
AssociatedObject.DropDownOpened += dropDownOpenedHandler;
|
||||||
AssociatedObject.DropDownClosed += dropDownClosedHandler;
|
AssociatedObject.DropDownClosed += dropDownClosedHandler;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
protected override void OnDetaching()
|
protected override bool Uninitialize()
|
||||||
{
|
{
|
||||||
AssociatedObject.DropDownOpened -= dropDownOpenedHandler;
|
AssociatedObject.DropDownOpened -= dropDownOpenedHandler;
|
||||||
AssociatedObject.DropDownClosed -= dropDownClosedHandler;
|
AssociatedObject.DropDownClosed -= dropDownClosedHandler;
|
||||||
|
return true;
|
||||||
base.OnDetaching();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnDropDownOpened(object? sender, object e)
|
private void OnDropDownOpened(object? sender, object e)
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using CommunityToolkit.WinUI.Behaviors;
|
||||||
|
using Microsoft.UI.Xaml.Controls;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Control.Behavior;
|
||||||
|
|
||||||
|
internal sealed class SelectedItemInViewBehavior : BehaviorBase<ListViewBase>
|
||||||
|
{
|
||||||
|
protected override bool Initialize()
|
||||||
|
{
|
||||||
|
if (AssociatedObject.SelectedItem is { } item)
|
||||||
|
{
|
||||||
|
AssociatedObject.ScrollIntoView(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,21 +9,6 @@ namespace Snap.Hutao.Control;
|
|||||||
[HighQuality]
|
[HighQuality]
|
||||||
internal static class BoxedValues
|
internal static class BoxedValues
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// <see cref="double"/> 0
|
|
||||||
/// </summary>
|
|
||||||
public static readonly object DoubleZero = 0D;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <see cref="double"/> 1
|
|
||||||
/// </summary>
|
|
||||||
public static readonly object DoubleOne = 1D;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <see cref="int"/> 0
|
|
||||||
/// </summary>
|
|
||||||
public static readonly object Int32Zero = 0;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <see cref="true"/>
|
/// <see cref="true"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ using Snap.Hutao.Control.Animation;
|
|||||||
using Snap.Hutao.Control.Extension;
|
using Snap.Hutao.Control.Extension;
|
||||||
using Snap.Hutao.Core.Caching;
|
using Snap.Hutao.Core.Caching;
|
||||||
using Snap.Hutao.Service.Notification;
|
using Snap.Hutao.Service.Notification;
|
||||||
using System.Globalization;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ internal sealed class BitmapIconExtension : MarkupExtension
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating whether to display the icon as monochrome.
|
/// Gets or sets a value indicating whether to display the icon as monochrome.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool ShowAsMonochrome { get; set; } = true;
|
public bool ShowAsMonochrome { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
protected override object ProvideValue()
|
protected override object ProvideValue()
|
||||||
|
|||||||
@@ -3,9 +3,7 @@
|
|||||||
// Some part of this file came from:
|
// Some part of this file came from:
|
||||||
// https://github.com/xunkong/desktop/tree/main/src/Desktop/Desktop/Pages/CharacterInfoPage.xaml.cs
|
// https://github.com/xunkong/desktop/tree/main/src/Desktop/Desktop/Pages/CharacterInfoPage.xaml.cs
|
||||||
|
|
||||||
using CommunityToolkit.WinUI;
|
|
||||||
using System.Buffers.Binary;
|
using System.Buffers.Binary;
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using Windows.UI;
|
using Windows.UI;
|
||||||
|
|
||||||
namespace Snap.Hutao.Control.Media;
|
namespace Snap.Hutao.Control.Media;
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using CommunityToolkit.WinUI;
|
|
||||||
using CommunityToolkit.WinUI.Helpers;
|
|
||||||
using Microsoft.UI.Xaml;
|
using Microsoft.UI.Xaml;
|
||||||
using Microsoft.UI.Xaml.Controls;
|
using Microsoft.UI.Xaml.Controls;
|
||||||
using Microsoft.UI.Xaml.Documents;
|
using Microsoft.UI.Xaml.Documents;
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace Snap.Hutao.Core.Annotation;
|
namespace Snap.Hutao.Core.Annotation;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 高质量代码
|
/// 高质量代码
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[AttributeUsage(AttributeTargets.All, Inherited = false)]
|
[AttributeUsage(AttributeTargets.All, Inherited = false)]
|
||||||
|
[Conditional("DEBUG")]
|
||||||
internal sealed class HighQualityAttribute : Attribute
|
internal sealed class HighQualityAttribute : Attribute
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -196,13 +196,13 @@ internal sealed class ImageCache : IImageCache, IImageCacheFilePathOperation
|
|||||||
retryCount += 3;
|
retryCount += 3;
|
||||||
break;
|
break;
|
||||||
case HttpStatusCode.TooManyRequests:
|
case HttpStatusCode.TooManyRequests:
|
||||||
{
|
{
|
||||||
retryCount++;
|
retryCount++;
|
||||||
TimeSpan delay = message.Headers.RetryAfter?.Delta ?? RetryCountToDelay[retryCount];
|
TimeSpan delay = message.Headers.RetryAfter?.Delta ?? RetryCountToDelay[retryCount];
|
||||||
logger.LogInformation("Retry {Uri} after {Delay}.", uri, delay);
|
logger.LogInformation("Retry {Uri} after {Delay}.", uri, delay);
|
||||||
await Task.Delay(delay).ConfigureAwait(false);
|
await Task.Delay(delay).ConfigureAwait(false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ internal sealed partial class ExceptionRecorder
|
|||||||
#if RELEASE
|
#if RELEASE
|
||||||
#pragma warning disable VSTHRD002
|
#pragma warning disable VSTHRD002
|
||||||
serviceProvider
|
serviceProvider
|
||||||
.GetRequiredService<Web.Hutao.HomaLogUploadClient>()
|
.GetRequiredService<Web.Hutao.Log.HomaLogUploadClient>()
|
||||||
.UploadLogAsync(serviceProvider, e.Exception)
|
.UploadLogAsync(serviceProvider, e.Exception)
|
||||||
.GetAwaiter()
|
.GetAwaiter()
|
||||||
.GetResult();
|
.GetResult();
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Microsoft.VisualBasic.FileIO;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace Snap.Hutao.Core.IO;
|
namespace Snap.Hutao.Core.IO;
|
||||||
@@ -14,7 +15,7 @@ internal static class DirectoryOperation
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Directory.Move(sourceDirName, destDirName);
|
FileSystem.MoveDirectory(sourceDirName, destDirName, true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -241,10 +241,21 @@ internal sealed class Activation : IActivation
|
|||||||
{
|
{
|
||||||
case UrlActionRefresh:
|
case UrlActionRefresh:
|
||||||
{
|
{
|
||||||
await serviceProvider
|
try
|
||||||
.GetRequiredService<IDailyNoteService>()
|
{
|
||||||
.RefreshDailyNotesAsync()
|
if (serviceProvider.GetRequiredService<IHutaoUserService>() is IHutaoUserServiceInitialization hutaoUserServiceInitialization)
|
||||||
.ConfigureAwait(false);
|
{
|
||||||
|
await hutaoUserServiceInitialization.InitializeInternalAsync().ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
await serviceProvider
|
||||||
|
.GetRequiredService<IDailyNoteService>()
|
||||||
|
.RefreshDailyNotesAsync()
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
// Check if it's redirected.
|
// Check if it's redirected.
|
||||||
if (!isRedirected)
|
if (!isRedirected)
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ internal static class AppInstanceExtension
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="appInstance">app实例</param>
|
/// <param name="appInstance">app实例</param>
|
||||||
/// <param name="args">参数</param>
|
/// <param name="args">参数</param>
|
||||||
[SuppressMessage("", "VSTHRD002")]
|
|
||||||
public static unsafe void RedirectActivationTo(this AppInstance appInstance, AppActivationArguments args)
|
public static unsafe void RedirectActivationTo(this AppInstance appInstance, AppActivationArguments args)
|
||||||
{
|
{
|
||||||
redirectEventHandle = CreateEvent(default(SECURITY_ATTRIBUTES*), true, false, null);
|
redirectEventHandle = CreateEvent(default(SECURITY_ATTRIBUTES*), true, false, null);
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ using Snap.Hutao.Core.Setting;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Security.Principal;
|
using System.Security.Principal;
|
||||||
using Windows.ApplicationModel;
|
using Windows.ApplicationModel;
|
||||||
using Windows.Foundation.Metadata;
|
|
||||||
using Windows.Storage;
|
using Windows.Storage;
|
||||||
|
|
||||||
namespace Snap.Hutao.Core;
|
namespace Snap.Hutao.Core;
|
||||||
@@ -131,15 +130,11 @@ internal sealed class RuntimeOptions : IOptions<RuntimeOptions>
|
|||||||
|
|
||||||
private static bool GetElevated()
|
private static bool GetElevated()
|
||||||
{
|
{
|
||||||
#if DEBUG_AS_FAKE_ELEVATED
|
|
||||||
return true;
|
|
||||||
#else
|
|
||||||
using (WindowsIdentity identity = WindowsIdentity.GetCurrent())
|
using (WindowsIdentity identity = WindowsIdentity.GetCurrent())
|
||||||
{
|
{
|
||||||
WindowsPrincipal principal = new(identity);
|
WindowsPrincipal principal = new(identity);
|
||||||
return principal.IsInRole(WindowsBuiltInRole.Administrator);
|
return principal.IsInRole(WindowsBuiltInRole.Administrator);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DetectWebView2Environment(ref string webView2Version, ref bool isWebView2Supported)
|
private void DetectWebView2Environment(ref string webView2Version, ref bool isWebView2Supported)
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ namespace Snap.Hutao.Core.Shell;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal interface IScheduleTaskInterop
|
internal interface IScheduleTaskInterop
|
||||||
{
|
{
|
||||||
|
bool IsDailyNoteRefreshEnabled();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 注册实时便笺刷新任务
|
/// 注册实时便笺刷新任务
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -20,4 +22,6 @@ internal interface IScheduleTaskInterop
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>是否卸载成功</returns>
|
/// <returns>是否卸载成功</returns>
|
||||||
bool UnregisterAllTasks();
|
bool UnregisterAllTasks();
|
||||||
|
|
||||||
|
bool UnregisterForDailyNoteRefresh();
|
||||||
}
|
}
|
||||||
@@ -16,6 +16,7 @@ namespace Snap.Hutao.Core.Shell;
|
|||||||
internal sealed class ScheduleTaskInterop : IScheduleTaskInterop
|
internal sealed class ScheduleTaskInterop : IScheduleTaskInterop
|
||||||
{
|
{
|
||||||
private const string DailyNoteRefreshTaskName = "SnapHutaoDailyNoteRefreshTask";
|
private const string DailyNoteRefreshTaskName = "SnapHutaoDailyNoteRefreshTask";
|
||||||
|
private const string DailyNoteRefreshScriptName = "DailyNoteRefresh";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 注册实时便笺刷新任务
|
/// 注册实时便笺刷新任务
|
||||||
@@ -30,7 +31,7 @@ internal sealed class ScheduleTaskInterop : IScheduleTaskInterop
|
|||||||
task.RegistrationInfo.Description = SH.CoreScheduleTaskHelperDailyNoteRefreshTaskDescription;
|
task.RegistrationInfo.Description = SH.CoreScheduleTaskHelperDailyNoteRefreshTaskDescription;
|
||||||
task.Triggers.Add(new TimeTrigger() { Repetition = new(TimeSpan.FromSeconds(interval), TimeSpan.Zero), });
|
task.Triggers.Add(new TimeTrigger() { Repetition = new(TimeSpan.FromSeconds(interval), TimeSpan.Zero), });
|
||||||
|
|
||||||
string scriptPath = EnsureWScriptCreated("DailyNoteRefresh", "hutao://DailyNote/Refresh");
|
string scriptPath = EnsureWScriptCreated(DailyNoteRefreshScriptName, "hutao://DailyNote/Refresh");
|
||||||
task.Actions.Add("wscript", $@"/b ""{scriptPath}""");
|
task.Actions.Add("wscript", $@"/b ""{scriptPath}""");
|
||||||
|
|
||||||
TaskService.Instance.RootFolder.RegisterTaskDefinition(DailyNoteRefreshTaskName, task);
|
TaskService.Instance.RootFolder.RegisterTaskDefinition(DailyNoteRefreshTaskName, task);
|
||||||
@@ -42,6 +43,29 @@ internal sealed class ScheduleTaskInterop : IScheduleTaskInterop
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool UnregisterForDailyNoteRefresh()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
TaskService.Instance.RootFolder.DeleteTask(DailyNoteRefreshTaskName, false);
|
||||||
|
if (WScriptExists(DailyNoteRefreshScriptName, out string fullPath))
|
||||||
|
{
|
||||||
|
File.Delete(fullPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsDailyNoteRefreshEnabled()
|
||||||
|
{
|
||||||
|
return WScriptExists(DailyNoteRefreshScriptName, out _);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 卸载全部注册的任务
|
/// 卸载全部注册的任务
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -65,18 +89,22 @@ internal sealed class ScheduleTaskInterop : IScheduleTaskInterop
|
|||||||
|
|
||||||
private static string EnsureWScriptCreated(string name, string url, bool forceCreate = false)
|
private static string EnsureWScriptCreated(string name, string url, bool forceCreate = false)
|
||||||
{
|
{
|
||||||
string tempFolder = ApplicationData.Current.TemporaryFolder.Path;
|
if (WScriptExists(name, out string fullName) && !forceCreate)
|
||||||
string fullName = Path.Combine(tempFolder, "Script", $"{name}.vbs");
|
|
||||||
|
|
||||||
if (File.Exists(fullName) && !forceCreate)
|
|
||||||
{
|
{
|
||||||
return fullName;
|
return fullName;
|
||||||
}
|
}
|
||||||
|
|
||||||
Directory.CreateDirectory(Path.Combine(tempFolder, "Script"));
|
|
||||||
string script = $"""CreateObject("WScript.Shell").Run "cmd /c start {url}", 0, False""";
|
string script = $"""CreateObject("WScript.Shell").Run "cmd /c start {url}", 0, False""";
|
||||||
File.WriteAllText(fullName, script);
|
File.WriteAllText(fullName, script);
|
||||||
|
|
||||||
return fullName;
|
return fullName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool WScriptExists(string name, out string fullName)
|
||||||
|
{
|
||||||
|
string tempFolder = ApplicationData.Current.TemporaryFolder.Path;
|
||||||
|
fullName = Path.Combine(tempFolder, "Script", $"{name}.vbs");
|
||||||
|
Directory.CreateDirectory(Path.Combine(tempFolder, "Script"));
|
||||||
|
return File.Exists(fullName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -11,19 +11,16 @@ internal readonly struct Delay
|
|||||||
/// <param name="minMilliSeconds">最小,闭</param>
|
/// <param name="minMilliSeconds">最小,闭</param>
|
||||||
/// <param name="maxMilliSeconds">最小,开</param>
|
/// <param name="maxMilliSeconds">最小,开</param>
|
||||||
/// <returns>任务</returns>
|
/// <returns>任务</returns>
|
||||||
[SuppressMessage("", "VSTHRD200")]
|
|
||||||
public static ValueTask Random(int minMilliSeconds, int maxMilliSeconds)
|
public static ValueTask Random(int minMilliSeconds, int maxMilliSeconds)
|
||||||
{
|
{
|
||||||
return Task.Delay((int)(System.Random.Shared.NextDouble() * (maxMilliSeconds - minMilliSeconds)) + minMilliSeconds).AsValueTask();
|
return Task.Delay((int)(System.Random.Shared.NextDouble() * (maxMilliSeconds - minMilliSeconds)) + minMilliSeconds).AsValueTask();
|
||||||
}
|
}
|
||||||
|
|
||||||
[SuppressMessage("", "VSTHRD200")]
|
|
||||||
public static ValueTask FromSeconds(int seconds)
|
public static ValueTask FromSeconds(int seconds)
|
||||||
{
|
{
|
||||||
return Task.Delay(TimeSpan.FromSeconds(seconds)).AsValueTask();
|
return Task.Delay(TimeSpan.FromSeconds(seconds)).AsValueTask();
|
||||||
}
|
}
|
||||||
|
|
||||||
[SuppressMessage("", "VSTHRD200")]
|
|
||||||
public static ValueTask FromMilliSeconds(int seconds)
|
public static ValueTask FromMilliSeconds(int seconds)
|
||||||
{
|
{
|
||||||
return Task.Delay(TimeSpan.FromMilliseconds(seconds)).AsValueTask();
|
return Task.Delay(TimeSpan.FromMilliseconds(seconds)).AsValueTask();
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Core.Threading;
|
||||||
|
|
||||||
|
internal class DispatcherQueueProgress<T> : IProgress<T>
|
||||||
|
{
|
||||||
|
private readonly SynchronizationContext synchronizationContext;
|
||||||
|
private readonly Action<T>? handler;
|
||||||
|
private readonly SendOrPostCallback invokeHandlers;
|
||||||
|
|
||||||
|
public DispatcherQueueProgress(Action<T> handler, SynchronizationContext synchronizationContext)
|
||||||
|
{
|
||||||
|
this.synchronizationContext = synchronizationContext;
|
||||||
|
invokeHandlers = new SendOrPostCallback(InvokeHandlers);
|
||||||
|
|
||||||
|
ArgumentNullException.ThrowIfNull(handler);
|
||||||
|
|
||||||
|
this.handler = handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
public event EventHandler<T>? ProgressChanged;
|
||||||
|
|
||||||
|
public void Report(T value)
|
||||||
|
{
|
||||||
|
Action<T>? handler = this.handler;
|
||||||
|
EventHandler<T>? changedEvent = ProgressChanged;
|
||||||
|
if (handler is not null || changedEvent is not null)
|
||||||
|
{
|
||||||
|
synchronizationContext.Post(invokeHandlers, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[SuppressMessage("", "SH007")]
|
||||||
|
private void InvokeHandlers(object? state)
|
||||||
|
{
|
||||||
|
T value = (T)state!;
|
||||||
|
|
||||||
|
Action<T>? handler = this.handler;
|
||||||
|
EventHandler<T>? changedEvent = ProgressChanged;
|
||||||
|
|
||||||
|
handler?.Invoke(value);
|
||||||
|
changedEvent?.Invoke(this, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,7 +11,7 @@ namespace Snap.Hutao.Core.Threading;
|
|||||||
/// 等待此类型对象后上下文会被切换至主线程
|
/// 等待此类型对象后上下文会被切换至主线程
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[HighQuality]
|
[HighQuality]
|
||||||
internal readonly struct DispatherQueueSwitchOperation : IAwaitable<DispatherQueueSwitchOperation>, ICriticalAwaiter
|
internal readonly struct DispatcherQueueSwitchOperation : IAwaitable<DispatcherQueueSwitchOperation>, ICriticalAwaiter
|
||||||
{
|
{
|
||||||
private readonly DispatcherQueue dispatherQueue;
|
private readonly DispatcherQueue dispatherQueue;
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ internal readonly struct DispatherQueueSwitchOperation : IAwaitable<DispatherQue
|
|||||||
/// 构造一个新的调度器队列等待器
|
/// 构造一个新的调度器队列等待器
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="dispatherQueue">调度器队列</param>
|
/// <param name="dispatherQueue">调度器队列</param>
|
||||||
public DispatherQueueSwitchOperation(DispatcherQueue dispatherQueue)
|
public DispatcherQueueSwitchOperation(DispatcherQueue dispatherQueue)
|
||||||
{
|
{
|
||||||
this.dispatherQueue = dispatherQueue;
|
this.dispatherQueue = dispatherQueue;
|
||||||
}
|
}
|
||||||
@@ -31,7 +31,7 @@ internal readonly struct DispatherQueueSwitchOperation : IAwaitable<DispatherQue
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public DispatherQueueSwitchOperation GetAwaiter()
|
public DispatcherQueueSwitchOperation GetAwaiter()
|
||||||
{
|
{
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -8,6 +8,8 @@ namespace Snap.Hutao.Core.Threading;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal interface ITaskContext
|
internal interface ITaskContext
|
||||||
{
|
{
|
||||||
|
IProgress<T> CreateProgressForMainThread<T>(Action<T> handler);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 在主线程上同步等待执行操作
|
/// 在主线程上同步等待执行操作
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -26,5 +28,5 @@ internal interface ITaskContext
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>使用 <see cref="SwitchToBackgroundAsync"/> 异步切换到 后台线程</remarks>
|
/// <remarks>使用 <see cref="SwitchToBackgroundAsync"/> 异步切换到 后台线程</remarks>
|
||||||
/// <returns>等待体</returns>
|
/// <returns>等待体</returns>
|
||||||
DispatherQueueSwitchOperation SwitchToMainThreadAsync();
|
DispatcherQueueSwitchOperation SwitchToMainThreadAsync();
|
||||||
}
|
}
|
||||||
@@ -11,6 +11,7 @@ namespace Snap.Hutao.Core.Threading;
|
|||||||
[Injection(InjectAs.Singleton, typeof(ITaskContext))]
|
[Injection(InjectAs.Singleton, typeof(ITaskContext))]
|
||||||
internal sealed class TaskContext : ITaskContext
|
internal sealed class TaskContext : ITaskContext
|
||||||
{
|
{
|
||||||
|
private readonly DispatcherQueueSynchronizationContext dispatcherQueueSynchronizationContext;
|
||||||
private readonly DispatcherQueue dispatcherQueue;
|
private readonly DispatcherQueue dispatcherQueue;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -19,8 +20,8 @@ internal sealed class TaskContext : ITaskContext
|
|||||||
public TaskContext()
|
public TaskContext()
|
||||||
{
|
{
|
||||||
dispatcherQueue = DispatcherQueue.GetForCurrentThread();
|
dispatcherQueue = DispatcherQueue.GetForCurrentThread();
|
||||||
DispatcherQueueSynchronizationContext context = new(dispatcherQueue);
|
dispatcherQueueSynchronizationContext = new(dispatcherQueue);
|
||||||
SynchronizationContext.SetSynchronizationContext(context);
|
SynchronizationContext.SetSynchronizationContext(dispatcherQueueSynchronizationContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
@@ -30,7 +31,7 @@ internal sealed class TaskContext : ITaskContext
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public DispatherQueueSwitchOperation SwitchToMainThreadAsync()
|
public DispatcherQueueSwitchOperation SwitchToMainThreadAsync()
|
||||||
{
|
{
|
||||||
return new(dispatcherQueue);
|
return new(dispatcherQueue);
|
||||||
}
|
}
|
||||||
@@ -47,4 +48,9 @@ internal sealed class TaskContext : ITaskContext
|
|||||||
dispatcherQueue.Invoke(action);
|
dispatcherQueue.Invoke(action);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IProgress<T> CreateProgressForMainThread<T>(Action<T> handler)
|
||||||
|
{
|
||||||
|
return new DispatcherQueueProgress<T>(handler, dispatcherQueueSynchronizationContext);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -10,18 +10,14 @@ namespace Snap.Hutao.Core.Threading;
|
|||||||
/// 任务扩展
|
/// 任务扩展
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[HighQuality]
|
[HighQuality]
|
||||||
[SuppressMessage("", "VSTHRD003")]
|
|
||||||
[SuppressMessage("", "VSTHRD100")]
|
|
||||||
internal static class TaskExtension
|
internal static class TaskExtension
|
||||||
{
|
{
|
||||||
[SuppressMessage("", "VSTHRD200")]
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ValueTask AsValueTask(this Task task)
|
public static ValueTask AsValueTask(this Task task)
|
||||||
{
|
{
|
||||||
return new(task);
|
return new(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
[SuppressMessage("", "VSTHRD200")]
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ValueTask<T> AsValueTask<T>(this Task<T> task)
|
public static ValueTask<T> AsValueTask<T>(this Task<T> task)
|
||||||
{
|
{
|
||||||
|
|||||||
19
src/Snap.Hutao/Snap.Hutao/Core/Threading/Throttler.cs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Core.Threading;
|
||||||
|
|
||||||
|
internal sealed class Throttler
|
||||||
|
{
|
||||||
|
private readonly ConcurrentDictionary<string, SemaphoreSlim> methodSemaphoreMap = new();
|
||||||
|
|
||||||
|
public ValueTask<SemaphoreSlimToken> ThrottleAsync(CancellationToken token = default, [CallerMemberName] string callerName = default!, [CallerLineNumber] int callerLine = 0)
|
||||||
|
{
|
||||||
|
string key = $"{callerName}L{callerLine}";
|
||||||
|
SemaphoreSlim semaphore = methodSemaphoreMap.GetOrAdd(key, name => new SemaphoreSlim(1));
|
||||||
|
return semaphore.EnterAsync(token);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,7 +7,6 @@ using Snap.Hutao.Core.Setting;
|
|||||||
using Snap.Hutao.Win32;
|
using Snap.Hutao.Win32;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using Windows.Graphics;
|
using Windows.Graphics;
|
||||||
using Windows.Win32.Foundation;
|
|
||||||
using Windows.Win32.UI.WindowsAndMessaging;
|
using Windows.Win32.UI.WindowsAndMessaging;
|
||||||
using static Windows.Win32.PInvoke;
|
using static Windows.Win32.PInvoke;
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using Microsoft.UI.Xaml;
|
using Microsoft.UI.Xaml;
|
||||||
using Windows.Win32.Foundation;
|
using Windows.Win32.Foundation;
|
||||||
using Windows.Win32.UI.Shell;
|
using Windows.Win32.UI.Shell;
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ namespace Snap.Hutao.Extension;
|
|||||||
[HighQuality]
|
[HighQuality]
|
||||||
internal static class DateTimeOffsetExtension
|
internal static class DateTimeOffsetExtension
|
||||||
{
|
{
|
||||||
|
public static readonly DateTimeOffset DatebaseDefaultTime = new(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0));
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 从Unix时间戳转换
|
/// 从Unix时间戳转换
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -130,6 +130,19 @@ internal static partial class EnumerableExtension
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static TSource SingleOrAdd<TSource>(this List<TSource> list, Func<TSource, bool> predicate, Func<TSource> valueFactory)
|
||||||
|
where TSource : class
|
||||||
|
{
|
||||||
|
if (list.SingleOrDefault(predicate) is { } source)
|
||||||
|
{
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
TSource value = valueFactory();
|
||||||
|
list.Add(value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
|
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
|
||||||
public static List<TSource> SortBy<TSource, TKey>(this List<TSource> list, Func<TSource, TKey> keySelector)
|
public static List<TSource> SortBy<TSource, TKey>(this List<TSource> list, Func<TSource, TKey> keySelector)
|
||||||
where TKey : IComparable
|
where TKey : IComparable
|
||||||
|
|||||||
@@ -94,18 +94,4 @@ internal static partial class EnumerableExtension
|
|||||||
string result = string.Join(separator, collection);
|
string result = string.Join(separator, collection);
|
||||||
return result.Length > 0 ? result : string.Empty;
|
return result.Length > 0 ? result : string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Concatenates each element from the collection into single string.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">Type of array elements.</typeparam>
|
|
||||||
/// <param name="collection">Collection to convert. Cannot be <see langword="null"/>.</param>
|
|
||||||
/// <param name="separator">Delimiter between elements in the final string.</param>
|
|
||||||
/// <param name="defaultValue">A string to be returned if collection has no elements.</param>
|
|
||||||
/// <returns>Converted collection into string.</returns>
|
|
||||||
public static string ToString<T>(this IEnumerable<T> collection, char separator, string defaultValue)
|
|
||||||
{
|
|
||||||
string result = string.Join(separator, collection);
|
|
||||||
return result.Length > 0 ? result : defaultValue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using Microsoft.UI.Xaml.Controls;
|
using Microsoft.UI.Xaml.Controls;
|
||||||
using Snap.Hutao.Factory.Abstraction;
|
using Snap.Hutao.Factory.Abstraction;
|
||||||
using System.Security.Authentication;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Factory;
|
namespace Snap.Hutao.Factory;
|
||||||
|
|
||||||
@@ -68,12 +67,12 @@ internal sealed partial class ContentDialogFactory : IContentDialogFactory
|
|||||||
where TContentDialog : ContentDialog
|
where TContentDialog : ContentDialog
|
||||||
{
|
{
|
||||||
await taskContext.SwitchToMainThreadAsync();
|
await taskContext.SwitchToMainThreadAsync();
|
||||||
return serviceProvider.CreateInstance<TContentDialog>();
|
return serviceProvider.CreateInstance<TContentDialog>(parameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TContentDialog CreateInstance<TContentDialog>(params object[] parameters)
|
public TContentDialog CreateInstance<TContentDialog>(params object[] parameters)
|
||||||
where TContentDialog : ContentDialog
|
where TContentDialog : ContentDialog
|
||||||
{
|
{
|
||||||
return serviceProvider.CreateInstance<TContentDialog>();
|
return serviceProvider.CreateInstance<TContentDialog>(parameters);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,7 @@ using Microsoft.UI.Xaml;
|
|||||||
using Snap.Hutao.Core.Setting;
|
using Snap.Hutao.Core.Setting;
|
||||||
using Snap.Hutao.Core.Windowing;
|
using Snap.Hutao.Core.Windowing;
|
||||||
using Snap.Hutao.Message;
|
using Snap.Hutao.Message;
|
||||||
|
using Windows.Foundation;
|
||||||
using Windows.Win32.UI.WindowsAndMessaging;
|
using Windows.Win32.UI.WindowsAndMessaging;
|
||||||
|
|
||||||
namespace Snap.Hutao;
|
namespace Snap.Hutao;
|
||||||
@@ -22,6 +23,8 @@ internal sealed partial class MainWindow : Window, IWindowOptionsSource, IRecipi
|
|||||||
private const int MinHeight = 524;
|
private const int MinHeight = 524;
|
||||||
|
|
||||||
private readonly WindowOptions windowOptions;
|
private readonly WindowOptions windowOptions;
|
||||||
|
private readonly ILogger<MainWindow> logger;
|
||||||
|
private readonly TypedEventHandler<object, WindowEventArgs> closedEventHander;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 构造一个新的主窗体
|
/// 构造一个新的主窗体
|
||||||
@@ -33,9 +36,12 @@ internal sealed partial class MainWindow : Window, IWindowOptionsSource, IRecipi
|
|||||||
windowOptions = new(this, TitleBarView.DragArea, new(1200, 741), true);
|
windowOptions = new(this, TitleBarView.DragArea, new(1200, 741), true);
|
||||||
ExtendedWindow<MainWindow>.Initialize(this, serviceProvider);
|
ExtendedWindow<MainWindow>.Initialize(this, serviceProvider);
|
||||||
serviceProvider.GetRequiredService<IMessenger>().Register(this);
|
serviceProvider.GetRequiredService<IMessenger>().Register(this);
|
||||||
|
logger = serviceProvider.GetRequiredService<ILogger<MainWindow>>();
|
||||||
|
|
||||||
// If not complete we should present the welcome view.
|
// If not complete we should present the welcome view.
|
||||||
ContentSwitchPresenter.Value = StaticResource.IsAnyUnfulfilledContractPresent();
|
ContentSwitchPresenter.Value = StaticResource.IsAnyUnfulfilledContractPresent();
|
||||||
|
closedEventHander = OnClosed;
|
||||||
|
Closed += closedEventHander;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
@@ -53,4 +59,9 @@ internal sealed partial class MainWindow : Window, IWindowOptionsSource, IRecipi
|
|||||||
{
|
{
|
||||||
ContentSwitchPresenter.Value = false;
|
ContentSwitchPresenter.Value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnClosed(object sender, WindowEventArgs args)
|
||||||
|
{
|
||||||
|
logger.LogInformation("MainWindow Closed");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
537
src/Snap.Hutao/Snap.Hutao/Migrations/20230824084447_AddRefreshTimeOnDailyNoteEntry.Designer.cs
generated
Normal file
@@ -0,0 +1,537 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using Snap.Hutao.Model.Entity.Database;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(AppDbContext))]
|
||||||
|
[Migration("20230824084447_AddRefreshTimeOnDailyNoteEntry")]
|
||||||
|
partial class AddRefreshTimeOnDailyNoteEntry
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder.HasAnnotation("ProductVersion", "7.0.10");
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.Achievement", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("InnerId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid>("ArchiveId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<uint>("Current")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("Id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Status")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Time")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
|
b.HasIndex("ArchiveId");
|
||||||
|
|
||||||
|
b.ToTable("achievements");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.AchievementArchive", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("InnerId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("IsSelected")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
|
b.ToTable("achievement_archives");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.AvatarInfo", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("InnerId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Info")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Uid")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
|
b.ToTable("avatar_infos");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.CultivateEntry", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("InnerId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<uint>("Id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<Guid>("ProjectId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Type")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
|
b.HasIndex("ProjectId");
|
||||||
|
|
||||||
|
b.ToTable("cultivate_entries");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.CultivateItem", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("InnerId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Count")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<Guid>("EntryId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("IsFinished")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("ItemId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
|
b.HasIndex("EntryId");
|
||||||
|
|
||||||
|
b.ToTable("cultivate_items");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.CultivateProject", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("InnerId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("AttachedUid")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("IsSelected")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
|
b.ToTable("cultivate_projects");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.DailyNoteEntry", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("InnerId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("DailyNote")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("DailyTaskNotify")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("DailyTaskNotifySuppressed")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("ExpeditionNotify")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("ExpeditionNotifySuppressed")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("HomeCoinNotifySuppressed")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("HomeCoinNotifyThreshold")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("RefreshTime")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("ResinNotifySuppressed")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("ResinNotifyThreshold")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("TransformerNotify")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("TransformerNotifySuppressed")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Uid")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("daily_notes");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.GachaArchive", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("InnerId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("IsSelected")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Uid")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
|
b.ToTable("gacha_archives");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.GachaItem", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("InnerId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid>("ArchiveId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("GachaType")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("ItemId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("QueryType")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Time")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
|
b.HasIndex("ArchiveId");
|
||||||
|
|
||||||
|
b.ToTable("gacha_items");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.GameAccount", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("InnerId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("AttachUid")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("MihoyoSDK")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Type")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
|
b.ToTable("game_accounts");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.InventoryItem", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("InnerId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<uint>("Count")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("ItemId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<Guid>("ProjectId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
|
b.HasIndex("ProjectId");
|
||||||
|
|
||||||
|
b.ToTable("inventory_items");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.InventoryReliquary", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("InnerId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("AppendPropIdList")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("ItemId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Level")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("MainPropId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<Guid>("ProjectId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
|
b.HasIndex("ProjectId");
|
||||||
|
|
||||||
|
b.ToTable("inventory_reliquaries");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.InventoryWeapon", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("InnerId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("ItemId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Level")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<Guid>("ProjectId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("PromoteLevel")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
|
b.HasIndex("ProjectId");
|
||||||
|
|
||||||
|
b.ToTable("inventory_weapons");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.ObjectCacheEntry", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Key")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("ExpireTime")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Value")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Key");
|
||||||
|
|
||||||
|
b.ToTable("object_cache");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.SettingEntry", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Key")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Value")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Key");
|
||||||
|
|
||||||
|
b.ToTable("settings");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.SpiralAbyssEntry", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("InnerId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("ScheduleId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("SpiralAbyss")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Uid")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
|
b.ToTable("spiral_abysses");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.User", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("InnerId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Aid")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("CookieToken")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("IsOversea")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("IsSelected")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("LToken")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("Ltoken");
|
||||||
|
|
||||||
|
b.Property<string>("Mid")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("SToken")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("Stoken");
|
||||||
|
|
||||||
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
|
b.ToTable("users");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.Achievement", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Snap.Hutao.Model.Entity.AchievementArchive", "Archive")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ArchiveId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Archive");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.CultivateEntry", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Snap.Hutao.Model.Entity.CultivateProject", "Project")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ProjectId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Project");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.CultivateItem", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Snap.Hutao.Model.Entity.CultivateEntry", "Entry")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("EntryId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Entry");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.DailyNoteEntry", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Snap.Hutao.Model.Entity.User", "User")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.GachaItem", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Snap.Hutao.Model.Entity.GachaArchive", "Archive")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ArchiveId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Archive");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.InventoryItem", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Snap.Hutao.Model.Entity.CultivateProject", "Project")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ProjectId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Project");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.InventoryReliquary", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Snap.Hutao.Model.Entity.CultivateProject", "Project")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ProjectId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Project");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.InventoryWeapon", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Snap.Hutao.Model.Entity.CultivateProject", "Project")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ProjectId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Project");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddRefreshTimeOnDailyNoteEntry : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<DateTimeOffset>(
|
||||||
|
name: "RefreshTime",
|
||||||
|
table: "daily_notes",
|
||||||
|
type: "TEXT",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "RefreshTime",
|
||||||
|
table: "daily_notes");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
546
src/Snap.Hutao/Snap.Hutao/Migrations/20230827040435_AddRefreshTimeOnAvatarInfo.Designer.cs
generated
Normal file
@@ -0,0 +1,546 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using Snap.Hutao.Model.Entity.Database;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(AppDbContext))]
|
||||||
|
[Migration("20230827040435_AddRefreshTimeOnAvatarInfo")]
|
||||||
|
partial class AddRefreshTimeOnAvatarInfo
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder.HasAnnotation("ProductVersion", "7.0.10");
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.Achievement", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("InnerId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid>("ArchiveId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<uint>("Current")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("Id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Status")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Time")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
|
b.HasIndex("ArchiveId");
|
||||||
|
|
||||||
|
b.ToTable("achievements");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.AchievementArchive", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("InnerId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("IsSelected")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
|
b.ToTable("achievement_archives");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.AvatarInfo", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("InnerId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CalculatorRefreshTime")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("GameRecordRefreshTime")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Info")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("ShowcaseRefreshTime")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Uid")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
|
b.ToTable("avatar_infos");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.CultivateEntry", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("InnerId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<uint>("Id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<Guid>("ProjectId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Type")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
|
b.HasIndex("ProjectId");
|
||||||
|
|
||||||
|
b.ToTable("cultivate_entries");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.CultivateItem", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("InnerId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Count")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<Guid>("EntryId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("IsFinished")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("ItemId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
|
b.HasIndex("EntryId");
|
||||||
|
|
||||||
|
b.ToTable("cultivate_items");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.CultivateProject", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("InnerId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("AttachedUid")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("IsSelected")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
|
b.ToTable("cultivate_projects");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.DailyNoteEntry", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("InnerId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("DailyNote")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("DailyTaskNotify")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("DailyTaskNotifySuppressed")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("ExpeditionNotify")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("ExpeditionNotifySuppressed")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("HomeCoinNotifySuppressed")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("HomeCoinNotifyThreshold")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("RefreshTime")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("ResinNotifySuppressed")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("ResinNotifyThreshold")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("TransformerNotify")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("TransformerNotifySuppressed")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Uid")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("daily_notes");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.GachaArchive", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("InnerId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("IsSelected")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Uid")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
|
b.ToTable("gacha_archives");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.GachaItem", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("InnerId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid>("ArchiveId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("GachaType")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("ItemId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("QueryType")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Time")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
|
b.HasIndex("ArchiveId");
|
||||||
|
|
||||||
|
b.ToTable("gacha_items");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.GameAccount", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("InnerId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("AttachUid")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("MihoyoSDK")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Type")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
|
b.ToTable("game_accounts");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.InventoryItem", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("InnerId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<uint>("Count")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("ItemId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<Guid>("ProjectId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
|
b.HasIndex("ProjectId");
|
||||||
|
|
||||||
|
b.ToTable("inventory_items");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.InventoryReliquary", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("InnerId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("AppendPropIdList")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("ItemId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Level")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("MainPropId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<Guid>("ProjectId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
|
b.HasIndex("ProjectId");
|
||||||
|
|
||||||
|
b.ToTable("inventory_reliquaries");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.InventoryWeapon", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("InnerId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("ItemId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Level")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<Guid>("ProjectId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("PromoteLevel")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
|
b.HasIndex("ProjectId");
|
||||||
|
|
||||||
|
b.ToTable("inventory_weapons");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.ObjectCacheEntry", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Key")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("ExpireTime")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Value")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Key");
|
||||||
|
|
||||||
|
b.ToTable("object_cache");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.SettingEntry", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Key")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Value")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Key");
|
||||||
|
|
||||||
|
b.ToTable("settings");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.SpiralAbyssEntry", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("InnerId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("ScheduleId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("SpiralAbyss")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Uid")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
|
b.ToTable("spiral_abysses");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.User", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("InnerId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Aid")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("CookieToken")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("IsOversea")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("IsSelected")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("LToken")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("Ltoken");
|
||||||
|
|
||||||
|
b.Property<string>("Mid")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("SToken")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("Stoken");
|
||||||
|
|
||||||
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
|
b.ToTable("users");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.Achievement", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Snap.Hutao.Model.Entity.AchievementArchive", "Archive")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ArchiveId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Archive");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.CultivateEntry", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Snap.Hutao.Model.Entity.CultivateProject", "Project")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ProjectId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Project");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.CultivateItem", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Snap.Hutao.Model.Entity.CultivateEntry", "Entry")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("EntryId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Entry");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.DailyNoteEntry", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Snap.Hutao.Model.Entity.User", "User")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.GachaItem", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Snap.Hutao.Model.Entity.GachaArchive", "Archive")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ArchiveId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Archive");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.InventoryItem", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Snap.Hutao.Model.Entity.CultivateProject", "Project")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ProjectId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Project");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.InventoryReliquary", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Snap.Hutao.Model.Entity.CultivateProject", "Project")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ProjectId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Project");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.InventoryWeapon", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Snap.Hutao.Model.Entity.CultivateProject", "Project")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ProjectId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Project");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddRefreshTimeOnAvatarInfo : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<DateTimeOffset>(
|
||||||
|
name: "CalculatorRefreshTime",
|
||||||
|
table: "avatar_infos",
|
||||||
|
type: "TEXT",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)));
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTimeOffset>(
|
||||||
|
name: "GameRecordRefreshTime",
|
||||||
|
table: "avatar_infos",
|
||||||
|
type: "TEXT",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)));
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTimeOffset>(
|
||||||
|
name: "ShowcaseRefreshTime",
|
||||||
|
table: "avatar_infos",
|
||||||
|
type: "TEXT",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "CalculatorRefreshTime",
|
||||||
|
table: "avatar_infos");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "GameRecordRefreshTime",
|
||||||
|
table: "avatar_infos");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "ShowcaseRefreshTime",
|
||||||
|
table: "avatar_infos");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,7 +15,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
protected override void BuildModel(ModelBuilder modelBuilder)
|
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||||
{
|
{
|
||||||
#pragma warning disable 612, 618
|
#pragma warning disable 612, 618
|
||||||
modelBuilder.HasAnnotation("ProductVersion", "7.0.5");
|
modelBuilder.HasAnnotation("ProductVersion", "7.0.10");
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.Achievement", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.Achievement", b =>
|
||||||
{
|
{
|
||||||
@@ -26,10 +26,10 @@ namespace Snap.Hutao.Migrations
|
|||||||
b.Property<Guid>("ArchiveId")
|
b.Property<Guid>("ArchiveId")
|
||||||
.HasColumnType("TEXT");
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
b.Property<int>("Current")
|
b.Property<uint>("Current")
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
b.Property<int>("Id")
|
b.Property<uint>("Id")
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
b.Property<int>("Status")
|
b.Property<int>("Status")
|
||||||
@@ -42,7 +42,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasIndex("ArchiveId");
|
b.HasIndex("ArchiveId");
|
||||||
|
|
||||||
b.ToTable("achievements", (string)null);
|
b.ToTable("achievements");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.AchievementArchive", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.AchievementArchive", b =>
|
||||||
@@ -60,7 +60,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasKey("InnerId");
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
b.ToTable("achievement_archives", (string)null);
|
b.ToTable("achievement_archives");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.AvatarInfo", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.AvatarInfo", b =>
|
||||||
@@ -69,17 +69,26 @@ namespace Snap.Hutao.Migrations
|
|||||||
.ValueGeneratedOnAdd()
|
.ValueGeneratedOnAdd()
|
||||||
.HasColumnType("TEXT");
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CalculatorRefreshTime")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("GameRecordRefreshTime")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
b.Property<string>("Info")
|
b.Property<string>("Info")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasColumnType("TEXT");
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("ShowcaseRefreshTime")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
b.Property<string>("Uid")
|
b.Property<string>("Uid")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasColumnType("TEXT");
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
b.HasKey("InnerId");
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
b.ToTable("avatar_infos", (string)null);
|
b.ToTable("avatar_infos");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.CultivateEntry", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.CultivateEntry", b =>
|
||||||
@@ -88,7 +97,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
.ValueGeneratedOnAdd()
|
.ValueGeneratedOnAdd()
|
||||||
.HasColumnType("TEXT");
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
b.Property<int>("Id")
|
b.Property<uint>("Id")
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
b.Property<Guid>("ProjectId")
|
b.Property<Guid>("ProjectId")
|
||||||
@@ -101,7 +110,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasIndex("ProjectId");
|
b.HasIndex("ProjectId");
|
||||||
|
|
||||||
b.ToTable("cultivate_entries", (string)null);
|
b.ToTable("cultivate_entries");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.CultivateItem", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.CultivateItem", b =>
|
||||||
@@ -126,7 +135,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasIndex("EntryId");
|
b.HasIndex("EntryId");
|
||||||
|
|
||||||
b.ToTable("cultivate_items", (string)null);
|
b.ToTable("cultivate_items");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.CultivateProject", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.CultivateProject", b =>
|
||||||
@@ -147,7 +156,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasKey("InnerId");
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
b.ToTable("cultivate_projects", (string)null);
|
b.ToTable("cultivate_projects");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.DailyNoteEntry", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.DailyNoteEntry", b =>
|
||||||
@@ -177,6 +186,9 @@ namespace Snap.Hutao.Migrations
|
|||||||
b.Property<int>("HomeCoinNotifyThreshold")
|
b.Property<int>("HomeCoinNotifyThreshold")
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("RefreshTime")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
b.Property<bool>("ResinNotifySuppressed")
|
b.Property<bool>("ResinNotifySuppressed")
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
@@ -200,7 +212,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasIndex("UserId");
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
b.ToTable("daily_notes", (string)null);
|
b.ToTable("daily_notes");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.GachaArchive", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.GachaArchive", b =>
|
||||||
@@ -218,7 +230,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasKey("InnerId");
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
b.ToTable("gacha_archives", (string)null);
|
b.ToTable("gacha_archives");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.GachaItem", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.GachaItem", b =>
|
||||||
@@ -236,7 +248,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
b.Property<long>("Id")
|
b.Property<long>("Id")
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
b.Property<int>("ItemId")
|
b.Property<uint>("ItemId")
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
b.Property<int>("QueryType")
|
b.Property<int>("QueryType")
|
||||||
@@ -249,7 +261,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasIndex("ArchiveId");
|
b.HasIndex("ArchiveId");
|
||||||
|
|
||||||
b.ToTable("gacha_items", (string)null);
|
b.ToTable("gacha_items");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.GameAccount", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.GameAccount", b =>
|
||||||
@@ -274,7 +286,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasKey("InnerId");
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
b.ToTable("game_accounts", (string)null);
|
b.ToTable("game_accounts");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.InventoryItem", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.InventoryItem", b =>
|
||||||
@@ -286,7 +298,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
b.Property<uint>("Count")
|
b.Property<uint>("Count")
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
b.Property<int>("ItemId")
|
b.Property<uint>("ItemId")
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
b.Property<Guid>("ProjectId")
|
b.Property<Guid>("ProjectId")
|
||||||
@@ -296,7 +308,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasIndex("ProjectId");
|
b.HasIndex("ProjectId");
|
||||||
|
|
||||||
b.ToTable("inventory_items", (string)null);
|
b.ToTable("inventory_items");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.InventoryReliquary", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.InventoryReliquary", b =>
|
||||||
@@ -325,7 +337,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasIndex("ProjectId");
|
b.HasIndex("ProjectId");
|
||||||
|
|
||||||
b.ToTable("inventory_reliquaries", (string)null);
|
b.ToTable("inventory_reliquaries");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.InventoryWeapon", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.InventoryWeapon", b =>
|
||||||
@@ -350,7 +362,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasIndex("ProjectId");
|
b.HasIndex("ProjectId");
|
||||||
|
|
||||||
b.ToTable("inventory_weapons", (string)null);
|
b.ToTable("inventory_weapons");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.ObjectCacheEntry", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.ObjectCacheEntry", b =>
|
||||||
@@ -366,7 +378,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasKey("Key");
|
b.HasKey("Key");
|
||||||
|
|
||||||
b.ToTable("object_cache", (string)null);
|
b.ToTable("object_cache");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.SettingEntry", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.SettingEntry", b =>
|
||||||
@@ -379,7 +391,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasKey("Key");
|
b.HasKey("Key");
|
||||||
|
|
||||||
b.ToTable("settings", (string)null);
|
b.ToTable("settings");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.SpiralAbyssEntry", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.SpiralAbyssEntry", b =>
|
||||||
@@ -401,7 +413,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasKey("InnerId");
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
b.ToTable("spiral_abysses", (string)null);
|
b.ToTable("spiral_abysses");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.User", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.User", b =>
|
||||||
@@ -435,7 +447,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasKey("InnerId");
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
b.ToTable("users", (string)null);
|
b.ToTable("users");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.Achievement", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.Achievement", b =>
|
||||||
|
|||||||
@@ -31,6 +31,12 @@ internal sealed class AvatarInfo : IMappingFrom<AvatarInfo, string, Web.Enka.Mod
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public Web.Enka.Model.AvatarInfo Info { get; set; } = default!;
|
public Web.Enka.Model.AvatarInfo Info { get; set; } = default!;
|
||||||
|
|
||||||
|
public DateTimeOffset ShowcaseRefreshTime { get; set; }
|
||||||
|
|
||||||
|
public DateTimeOffset GameRecordRefreshTime { get; set; }
|
||||||
|
|
||||||
|
public DateTimeOffset CalculatorRefreshTime { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 创建一个新的实体角色信息
|
/// 创建一个新的实体角色信息
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -4,10 +4,8 @@
|
|||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using Snap.Hutao.Core.Abstraction;
|
using Snap.Hutao.Core.Abstraction;
|
||||||
using Snap.Hutao.ViewModel.User;
|
using Snap.Hutao.ViewModel.User;
|
||||||
using Snap.Hutao.Web.Hoyolab;
|
|
||||||
using Snap.Hutao.Web.Hoyolab.Takumi.Binding;
|
using Snap.Hutao.Web.Hoyolab.Takumi.Binding;
|
||||||
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.DailyNote;
|
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.DailyNote;
|
||||||
using Snap.Hutao.Web.Request.QueryString;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
@@ -54,7 +52,21 @@ internal sealed class DailyNoteEntry : ObservableObject, IMappingFrom<DailyNoteE
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public DailyNote? DailyNote { get; set; }
|
public DailyNote? DailyNote { get; set; }
|
||||||
|
|
||||||
// TODO: Add RefreshTime
|
/// <summary>
|
||||||
|
/// 刷新时间
|
||||||
|
/// </summary>
|
||||||
|
public DateTimeOffset RefreshTime { get; set; }
|
||||||
|
|
||||||
|
[NotMapped]
|
||||||
|
public string RefreshTimeFormatted
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return RefreshTime == DateTimeOffsetExtension.DatebaseDefaultTime
|
||||||
|
? SH.ModelEntityDailyNoteNotRefreshed
|
||||||
|
: SH.ModelEntityDailyNoteRefreshTimeFormat.Format(RefreshTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 树脂提醒阈值
|
/// 树脂提醒阈值
|
||||||
@@ -130,5 +142,8 @@ internal sealed class DailyNoteEntry : ObservableObject, IMappingFrom<DailyNoteE
|
|||||||
{
|
{
|
||||||
DailyNote = dailyNote;
|
DailyNote = dailyNote;
|
||||||
OnPropertyChanged(nameof(DailyNote));
|
OnPropertyChanged(nameof(DailyNote));
|
||||||
|
|
||||||
|
RefreshTime = DateTimeOffset.Now;
|
||||||
|
OnPropertyChanged(nameof(RefreshTimeFormatted));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,13 +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 Microsoft.Data.Sqlite;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Snap.Hutao.Core.Abstraction;
|
using Snap.Hutao.Core.Abstraction;
|
||||||
using Snap.Hutao.Core.Database;
|
using Snap.Hutao.Core.Database;
|
||||||
using Snap.Hutao.Core.ExceptionService;
|
|
||||||
using Snap.Hutao.Service.GachaLog;
|
|
||||||
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using Snap.Hutao.Model.Entity.Abstraction;
|
using Snap.Hutao.Model.Entity.Abstraction;
|
||||||
using Snap.Hutao.Model.InterChange.GachaLog;
|
using Snap.Hutao.Model.InterChange.GachaLog;
|
||||||
using Snap.Hutao.Model.Metadata.Abstraction;
|
|
||||||
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using Snap.Hutao.Core.Json.Annotation;
|
|
||||||
using Snap.Hutao.Model.Intrinsic;
|
using Snap.Hutao.Model.Intrinsic;
|
||||||
|
|
||||||
namespace Snap.Hutao.Model.Metadata.Avatar;
|
namespace Snap.Hutao.Model.Metadata.Avatar;
|
||||||
|
|||||||
@@ -89,6 +89,8 @@ internal static class AvatarIds
|
|||||||
public static readonly AvatarId Lynette = 10000083;
|
public static readonly AvatarId Lynette = 10000083;
|
||||||
public static readonly AvatarId Lyney = 10000084;
|
public static readonly AvatarId Lyney = 10000084;
|
||||||
public static readonly AvatarId Freminet = 10000085;
|
public static readonly AvatarId Freminet = 10000085;
|
||||||
|
public static readonly AvatarId Wriothesley = 10000086;
|
||||||
|
public static readonly AvatarId Neuvillette = 10000087;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 检查该角色是否为主角
|
/// 检查该角色是否为主角
|
||||||
@@ -111,7 +113,7 @@ internal static class AvatarIds
|
|||||||
{
|
{
|
||||||
[PlayerBoy] = new()
|
[PlayerBoy] = new()
|
||||||
{
|
{
|
||||||
Name = "旅行者",
|
Name = SH.ModelMetadataAvatarPlayerName,
|
||||||
Icon = "UI_AvatarIcon_PlayerBoy",
|
Icon = "UI_AvatarIcon_PlayerBoy",
|
||||||
SideIcon = "UI_AvatarIcon_Side_PlayerBoy",
|
SideIcon = "UI_AvatarIcon_Side_PlayerBoy",
|
||||||
Quality = Intrinsic.QualityType.QUALITY_ORANGE,
|
Quality = Intrinsic.QualityType.QUALITY_ORANGE,
|
||||||
@@ -119,7 +121,7 @@ internal static class AvatarIds
|
|||||||
|
|
||||||
[PlayerGirl] = new()
|
[PlayerGirl] = new()
|
||||||
{
|
{
|
||||||
Name = "旅行者",
|
Name = SH.ModelMetadataAvatarPlayerName,
|
||||||
Icon = "UI_AvatarIcon_PlayerGirl",
|
Icon = "UI_AvatarIcon_PlayerGirl",
|
||||||
SideIcon = "UI_AvatarIcon_Side_PlayerGirl",
|
SideIcon = "UI_AvatarIcon_Side_PlayerGirl",
|
||||||
Quality = Intrinsic.QualityType.QUALITY_ORANGE,
|
Quality = Intrinsic.QualityType.QUALITY_ORANGE,
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using Snap.Hutao.Model.Intrinsic;
|
|
||||||
using Snap.Hutao.Model.Primitive;
|
using Snap.Hutao.Model.Primitive;
|
||||||
using Snap.Hutao.ViewModel.Cultivation;
|
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
|
|
||||||
namespace Snap.Hutao.Model.Metadata.Item;
|
namespace Snap.Hutao.Model.Metadata.Item;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using Snap.Hutao.Model.Calculable;
|
|||||||
using Snap.Hutao.Model.Intrinsic;
|
using Snap.Hutao.Model.Intrinsic;
|
||||||
using Snap.Hutao.Model.Metadata.Abstraction;
|
using Snap.Hutao.Model.Metadata.Abstraction;
|
||||||
using Snap.Hutao.Model.Metadata.Converter;
|
using Snap.Hutao.Model.Metadata.Converter;
|
||||||
|
using Snap.Hutao.Model.Metadata.Item;
|
||||||
using Snap.Hutao.ViewModel.Complex;
|
using Snap.Hutao.ViewModel.Complex;
|
||||||
using Snap.Hutao.ViewModel.GachaLog;
|
using Snap.Hutao.ViewModel.GachaLog;
|
||||||
|
|
||||||
@@ -22,6 +23,12 @@ internal sealed partial class Weapon : IStatisticsItemSource, ISummaryItemSource
|
|||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public WeaponCollocationView? Collocation { get; set; }
|
public WeaponCollocationView? Collocation { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// [非元数据] 养成物品视图
|
||||||
|
/// </summary>
|
||||||
|
[JsonIgnore]
|
||||||
|
public List<Material>? CultivationItemsView { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc cref="INameQuality.Quality" />
|
/// <inheritdoc cref="INameQuality.Quality" />
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public QualityType Quality
|
public QualityType Quality
|
||||||
|
|||||||
@@ -61,4 +61,9 @@ internal sealed partial class Weapon
|
|||||||
/// 被动信息, 无被动的武器为 <see langword="null"/>
|
/// 被动信息, 无被动的武器为 <see langword="null"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public NameDescriptions? Affix { get; set; } = default!;
|
public NameDescriptions? Affix { get; set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 养成物品
|
||||||
|
/// </summary>
|
||||||
|
public List<MaterialId> CultivationItems { get; set; } = default!;
|
||||||
}
|
}
|
||||||
@@ -420,6 +420,24 @@ namespace Snap.Hutao.Resource.Localization {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 尚未刷新 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
internal static string ModelEntityDailyNoteNotRefreshed {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ModelEntityDailyNoteNotRefreshed", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 刷新于 {0:yyyy/MM/dd HH:mm:ss} 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
internal static string ModelEntityDailyNoteRefreshTimeFormat {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ModelEntityDailyNoteRefreshTimeFormat", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 第 {0} 期 的本地化字符串。
|
/// 查找类似 第 {0} 期 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -744,6 +762,15 @@ namespace Snap.Hutao.Resource.Localization {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 旅行者 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
internal static string ModelMetadataAvatarPlayerName {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ModelMetadataAvatarPlayerName", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 {0} 月 {1} 日 的本地化字符串。
|
/// 查找类似 {0} 月 {1} 日 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1104,6 +1131,60 @@ namespace Snap.Hutao.Resource.Localization {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 养成计算:尚未刷新 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
internal static string ServiceAvatarInfoSummaryCalculatorNotRefreshed {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ServiceAvatarInfoSummaryCalculatorNotRefreshed", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 养成计算:{0:MM-dd HH:mm} 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
internal static string ServiceAvatarInfoSummaryCalculatorRefreshTimeFormat {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ServiceAvatarInfoSummaryCalculatorRefreshTimeFormat", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 我的角色:尚未刷新 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
internal static string ServiceAvatarInfoSummaryGameRecordNotRefreshed {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ServiceAvatarInfoSummaryGameRecordNotRefreshed", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 我的角色:{0:MM-dd HH:mm} 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
internal static string ServiceAvatarInfoSummaryGameRecordRefreshTimeFormat {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ServiceAvatarInfoSummaryGameRecordRefreshTimeFormat", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 角色橱窗:尚未刷新 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
internal static string ServiceAvatarInfoSummaryShowcaseNotRefreshed {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ServiceAvatarInfoSummaryShowcaseNotRefreshed", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 角色橱窗:{0:MM-dd HH:mm} 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
internal static string ServiceAvatarInfoSummaryShowcaseRefreshTimeFormat {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ServiceAvatarInfoSummaryShowcaseRefreshTimeFormat", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 保存养成计划状态失败 的本地化字符串。
|
/// 查找类似 保存养成计划状态失败 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1338,6 +1419,15 @@ namespace Snap.Hutao.Resource.Localization {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 数据包含异常物品, Id:{0} 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
internal static string ServiceGachaLogUIGFImportItemInvalidFormat {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ServiceGachaLogUIGFImportItemInvalidFormat", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 请求验证密钥失败 的本地化字符串。
|
/// 查找类似 请求验证密钥失败 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1473,6 +1563,33 @@ namespace Snap.Hutao.Resource.Localization {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 备份:{0} 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
internal static string ServiceGamePackageConvertMoveFileBackupFormat {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ServiceGamePackageConvertMoveFileBackupFormat", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 重命名:{0} 到:{1} 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
internal static string ServiceGamePackageConvertMoveFileRenameFormat {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ServiceGamePackageConvertMoveFileRenameFormat", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 替换:{0} 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
internal static string ServiceGamePackageConvertMoveFileRestoreFormat {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ServiceGamePackageConvertMoveFileRestoreFormat", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 重命名数据文件夹名称失败 的本地化字符串。
|
/// 查找类似 重命名数据文件夹名称失败 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1653,6 +1770,33 @@ namespace Snap.Hutao.Resource.Localization {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 签到失败,{0} 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
internal static string ServiceSignInClaimRewardFailedFormat {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ServiceSignInClaimRewardFailedFormat", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 获取奖励列表失败 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
internal static string ServiceSignInRewardListRequestFailed {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ServiceSignInRewardListRequestFailed", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 签到成功,{0}×{1} 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
internal static string ServiceSignInSuccessRewardFormat {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ServiceSignInSuccessRewardFormat", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 多个用户记录为选中状态 的本地化字符串。
|
/// 查找类似 多个用户记录为选中状态 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -2589,6 +2733,15 @@ namespace Snap.Hutao.Resource.Localization {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 正在获取实时便笺信息,请稍候 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
internal static string ViewModelDailyNoteRequestProgressTitle {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ViewModelDailyNoteRequestProgressTitle", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 成功保存到指定位置 的本地化字符串。
|
/// 查找类似 成功保存到指定位置 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -3462,6 +3615,42 @@ namespace Snap.Hutao.Resource.Localization {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 自动刷新 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
internal static string ViewPageDailyNoteSettingAutoRefresh {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ViewPageDailyNoteSettingAutoRefresh", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 间隔选定的时间后刷新添加的实时便笺 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
internal static string ViewPageDailyNoteSettingAutoRefreshDescription {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ViewPageDailyNoteSettingAutoRefreshDescription", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 这些选项仅允许在非管理员模式下更改 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
internal static string ViewPageDailyNoteSettingRefreshElevatedHint {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ViewPageDailyNoteSettingRefreshElevatedHint", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 刷新 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
internal static string ViewPageDailyNoteSettingRefreshHeader {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ViewPageDailyNoteSettingRefreshHeader", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 在我游玩原神时不通知我 的本地化字符串。
|
/// 查找类似 在我游玩原神时不通知我 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -5317,7 +5506,7 @@ namespace Snap.Hutao.Resource.Localization {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 HoYoLab 的本地化字符串。
|
/// 查找类似 HoYoLAB 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static string ViewUserCookieOperation2 {
|
internal static string ViewUserCookieOperation2 {
|
||||||
get {
|
get {
|
||||||
@@ -5325,6 +5514,15 @@ namespace Snap.Hutao.Resource.Localization {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 当前用户 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
internal static string ViewUserCookieOperation3 {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ViewUserCookieOperation3", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 网页登录 的本地化字符串。
|
/// 查找类似 网页登录 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -5352,6 +5550,15 @@ namespace Snap.Hutao.Resource.Localization {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 领取签到奖励 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
internal static string ViewUserCookieOperationSignInRewardAction {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ViewUserCookieOperationSignInRewardAction", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 复制 Cookie 的本地化字符串。
|
/// 查找类似 复制 Cookie 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -5478,6 +5685,51 @@ namespace Snap.Hutao.Resource.Localization {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 (?:〓活动时间〓|〓任务开放时间〓).*?\d\.\d版本更新(?:完成|)后永久开放 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
internal static string WebAnnouncementMatchPermanentActivityTime {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("WebAnnouncementMatchPermanentActivityTime", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 〓活动时间〓.*?\d\.\d版本期间持续开放 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
internal static string WebAnnouncementMatchPersistentActivityTime {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("WebAnnouncementMatchPersistentActivityTime", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 (?:〓活动时间〓|祈愿时间|【上架时间】).*?(\d\.\d版本更新后|\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}).*?~.*?&lt;t class="t_(?:gl|lc)".*?&gt;(.*?)&lt;/t&gt; 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
internal static string WebAnnouncementMatchTransientActivityTime {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("WebAnnouncementMatchTransientActivityTime", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 〓更新时间〓.+?&lt;t class=\"t_(?:gl|lc)\".*?&gt;(.*?)&lt;/t&gt; 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
internal static string WebAnnouncementMatchVersionUpdateTime {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("WebAnnouncementMatchVersionUpdateTime", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 \d\.\d版本更新说明 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
internal static string WebAnnouncementMatchVersionUpdateTitle {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("WebAnnouncementMatchVersionUpdateTitle", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 {0} 天后开始 的本地化字符串。
|
/// 查找类似 {0} 天后开始 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -5568,6 +5820,15 @@ namespace Snap.Hutao.Resource.Localization {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 尚未解锁洞天 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
internal static string WebDailyNoteHomeLocked {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("WebDailyNoteHomeLocked", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 今天 的本地化字符串。
|
/// 查找类似 今天 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -5658,6 +5919,24 @@ namespace Snap.Hutao.Resource.Localization {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 尚未获得 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
internal static string WebDailyNoteTransformerNotObtained {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("WebDailyNoteTransformerNotObtained", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 尚未获得参量质变仪 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
internal static string WebDailyNoteTransformerNotObtainedDetail {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("WebDailyNoteTransformerNotObtainedDetail", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 冷却中 的本地化字符串。
|
/// 查找类似 冷却中 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -5820,6 +6099,15 @@ namespace Snap.Hutao.Resource.Localization {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 请刷新 Cookie,原始消息:{0} 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
internal static string WebResponseRefreshCookieHintFormat {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("WebResponseRefreshCookieHintFormat", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 [{0}] 中的 [{1}] 网络请求异常,请稍后再试 的本地化字符串。
|
/// 查找类似 [{0}] 中的 [{1}] 网络请求异常,请稍后再试 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -237,6 +237,12 @@
|
|||||||
<data name="ModelBindingUserInitializationFailed" xml:space="preserve">
|
<data name="ModelBindingUserInitializationFailed" xml:space="preserve">
|
||||||
<value>网络异常</value>
|
<value>网络异常</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="ModelEntityDailyNoteNotRefreshed" xml:space="preserve">
|
||||||
|
<value>尚未刷新</value>
|
||||||
|
</data>
|
||||||
|
<data name="ModelEntityDailyNoteRefreshTimeFormat" xml:space="preserve">
|
||||||
|
<value>刷新于 {0:yyyy/MM/dd HH:mm:ss}</value>
|
||||||
|
</data>
|
||||||
<data name="ModelEntitySpiralAbyssScheduleFormat" xml:space="preserve">
|
<data name="ModelEntitySpiralAbyssScheduleFormat" xml:space="preserve">
|
||||||
<value>第 {0} 期</value>
|
<value>第 {0} 期</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -366,6 +372,9 @@
|
|||||||
<value>单手剑</value>
|
<value>单手剑</value>
|
||||||
<comment>Need EXACT same string in game</comment>
|
<comment>Need EXACT same string in game</comment>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="ModelMetadataAvatarPlayerName" xml:space="preserve">
|
||||||
|
<value>旅行者</value>
|
||||||
|
</data>
|
||||||
<data name="ModelMetadataFetterInfoBirthdayFormat" xml:space="preserve">
|
<data name="ModelMetadataFetterInfoBirthdayFormat" xml:space="preserve">
|
||||||
<value>{0} 月 {1} 日</value>
|
<value>{0} 月 {1} 日</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -521,6 +530,24 @@
|
|||||||
<value>风元素抗性</value>
|
<value>风元素抗性</value>
|
||||||
<comment>Need EXACT same string in game</comment>
|
<comment>Need EXACT same string in game</comment>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="ServiceAvatarInfoSummaryCalculatorNotRefreshed" xml:space="preserve">
|
||||||
|
<value>养成计算:尚未刷新</value>
|
||||||
|
</data>
|
||||||
|
<data name="ServiceAvatarInfoSummaryCalculatorRefreshTimeFormat" xml:space="preserve">
|
||||||
|
<value>养成计算:{0:MM-dd HH:mm}</value>
|
||||||
|
</data>
|
||||||
|
<data name="ServiceAvatarInfoSummaryGameRecordNotRefreshed" xml:space="preserve">
|
||||||
|
<value>我的角色:尚未刷新</value>
|
||||||
|
</data>
|
||||||
|
<data name="ServiceAvatarInfoSummaryGameRecordRefreshTimeFormat" xml:space="preserve">
|
||||||
|
<value>我的角色:{0:MM-dd HH:mm}</value>
|
||||||
|
</data>
|
||||||
|
<data name="ServiceAvatarInfoSummaryShowcaseNotRefreshed" xml:space="preserve">
|
||||||
|
<value>角色橱窗:尚未刷新</value>
|
||||||
|
</data>
|
||||||
|
<data name="ServiceAvatarInfoSummaryShowcaseRefreshTimeFormat" xml:space="preserve">
|
||||||
|
<value>角色橱窗:{0:MM-dd HH:mm}</value>
|
||||||
|
</data>
|
||||||
<data name="ServiceCultivationProjectCurrentUserdataCourrpted" xml:space="preserve">
|
<data name="ServiceCultivationProjectCurrentUserdataCourrpted" xml:space="preserve">
|
||||||
<value>保存养成计划状态失败</value>
|
<value>保存养成计划状态失败</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -599,6 +626,9 @@
|
|||||||
<data name="ServiceGachaLogHutaoCloudServiceNotAllowed" xml:space="preserve">
|
<data name="ServiceGachaLogHutaoCloudServiceNotAllowed" xml:space="preserve">
|
||||||
<value>祈愿记录上传服务不可用</value>
|
<value>祈愿记录上传服务不可用</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="ServiceGachaLogUIGFImportItemInvalidFormat" xml:space="preserve">
|
||||||
|
<value>数据包含异常物品, Id:{0}</value>
|
||||||
|
</data>
|
||||||
<data name="ServiceGachaLogUrlProviderAuthkeyRequestFailed" xml:space="preserve">
|
<data name="ServiceGachaLogUrlProviderAuthkeyRequestFailed" xml:space="preserve">
|
||||||
<value>请求验证密钥失败</value>
|
<value>请求验证密钥失败</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -644,6 +674,15 @@
|
|||||||
<data name="ServiceGameLocatorUnityLogGamePathNotFound" xml:space="preserve">
|
<data name="ServiceGameLocatorUnityLogGamePathNotFound" xml:space="preserve">
|
||||||
<value>在 Unity 日志文件中找不到游戏路径</value>
|
<value>在 Unity 日志文件中找不到游戏路径</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="ServiceGamePackageConvertMoveFileBackupFormat" xml:space="preserve">
|
||||||
|
<value>备份:{0}</value>
|
||||||
|
</data>
|
||||||
|
<data name="ServiceGamePackageConvertMoveFileRenameFormat" xml:space="preserve">
|
||||||
|
<value>重命名:{0} 到:{1}</value>
|
||||||
|
</data>
|
||||||
|
<data name="ServiceGamePackageConvertMoveFileRestoreFormat" xml:space="preserve">
|
||||||
|
<value>替换:{0}</value>
|
||||||
|
</data>
|
||||||
<data name="ServiceGamePackageRenameDataFolderFailed" xml:space="preserve">
|
<data name="ServiceGamePackageRenameDataFolderFailed" xml:space="preserve">
|
||||||
<value>重命名数据文件夹名称失败</value>
|
<value>重命名数据文件夹名称失败</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -704,6 +743,15 @@
|
|||||||
<data name="ServiceMetadataVersionNotSupported" xml:space="preserve">
|
<data name="ServiceMetadataVersionNotSupported" xml:space="preserve">
|
||||||
<value>你的胡桃版本过低,请尽快升级</value>
|
<value>你的胡桃版本过低,请尽快升级</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="ServiceSignInClaimRewardFailedFormat" xml:space="preserve">
|
||||||
|
<value>签到失败,{0}</value>
|
||||||
|
</data>
|
||||||
|
<data name="ServiceSignInRewardListRequestFailed" xml:space="preserve">
|
||||||
|
<value>获取奖励列表失败</value>
|
||||||
|
</data>
|
||||||
|
<data name="ServiceSignInSuccessRewardFormat" xml:space="preserve">
|
||||||
|
<value>签到成功,{0}×{1}</value>
|
||||||
|
</data>
|
||||||
<data name="ServiceUserCurrentMultiMatched" xml:space="preserve">
|
<data name="ServiceUserCurrentMultiMatched" xml:space="preserve">
|
||||||
<value>多个用户记录为选中状态</value>
|
<value>多个用户记录为选中状态</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -1016,6 +1064,9 @@
|
|||||||
<data name="ViewModelDailyNoteRegisterTaskFail" xml:space="preserve">
|
<data name="ViewModelDailyNoteRegisterTaskFail" xml:space="preserve">
|
||||||
<value>注册计划任务失败,请使用管理员模式重试</value>
|
<value>注册计划任务失败,请使用管理员模式重试</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="ViewModelDailyNoteRequestProgressTitle" xml:space="preserve">
|
||||||
|
<value>正在获取实时便笺信息,请稍候</value>
|
||||||
|
</data>
|
||||||
<data name="ViewModelExportSuccessMessage" xml:space="preserve">
|
<data name="ViewModelExportSuccessMessage" xml:space="preserve">
|
||||||
<value>成功保存到指定位置</value>
|
<value>成功保存到指定位置</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -1307,6 +1358,18 @@
|
|||||||
<data name="ViewPageDailyNoteResinDiscountUsed" xml:space="preserve">
|
<data name="ViewPageDailyNoteResinDiscountUsed" xml:space="preserve">
|
||||||
<value>本周已消耗减半次数</value>
|
<value>本周已消耗减半次数</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="ViewPageDailyNoteSettingAutoRefresh" xml:space="preserve">
|
||||||
|
<value>自动刷新</value>
|
||||||
|
</data>
|
||||||
|
<data name="ViewPageDailyNoteSettingAutoRefreshDescription" xml:space="preserve">
|
||||||
|
<value>间隔选定的时间后刷新添加的实时便笺</value>
|
||||||
|
</data>
|
||||||
|
<data name="ViewPageDailyNoteSettingRefreshElevatedHint" xml:space="preserve">
|
||||||
|
<value>这些选项仅允许在非管理员模式下更改</value>
|
||||||
|
</data>
|
||||||
|
<data name="ViewPageDailyNoteSettingRefreshHeader" xml:space="preserve">
|
||||||
|
<value>刷新</value>
|
||||||
|
</data>
|
||||||
<data name="ViewPageDailyNoteSlientModeDescription" xml:space="preserve">
|
<data name="ViewPageDailyNoteSlientModeDescription" xml:space="preserve">
|
||||||
<value>在我游玩原神时不通知我</value>
|
<value>在我游玩原神时不通知我</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -1926,7 +1989,10 @@
|
|||||||
<value>米游社</value>
|
<value>米游社</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewUserCookieOperation2" xml:space="preserve">
|
<data name="ViewUserCookieOperation2" xml:space="preserve">
|
||||||
<value>HoYoLab</value>
|
<value>HoYoLAB</value>
|
||||||
|
</data>
|
||||||
|
<data name="ViewUserCookieOperation3" xml:space="preserve">
|
||||||
|
<value>当前用户</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewUserCookieOperationLoginMihoyoUserAction" xml:space="preserve">
|
<data name="ViewUserCookieOperationLoginMihoyoUserAction" xml:space="preserve">
|
||||||
<value>网页登录</value>
|
<value>网页登录</value>
|
||||||
@@ -1937,6 +2003,9 @@
|
|||||||
<data name="ViewUserCookieOperationRefreshCookieAction" xml:space="preserve">
|
<data name="ViewUserCookieOperationRefreshCookieAction" xml:space="preserve">
|
||||||
<value>刷新 Cookie</value>
|
<value>刷新 Cookie</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="ViewUserCookieOperationSignInRewardAction" xml:space="preserve">
|
||||||
|
<value>领取签到奖励</value>
|
||||||
|
</data>
|
||||||
<data name="ViewUserCopyCookieAction" xml:space="preserve">
|
<data name="ViewUserCopyCookieAction" xml:space="preserve">
|
||||||
<value>复制 Cookie</value>
|
<value>复制 Cookie</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -1979,6 +2048,21 @@
|
|||||||
<data name="ViewWikiWeaponHeader" xml:space="preserve">
|
<data name="ViewWikiWeaponHeader" xml:space="preserve">
|
||||||
<value>武器资料</value>
|
<value>武器资料</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="WebAnnouncementMatchPermanentActivityTime" xml:space="preserve">
|
||||||
|
<value>(?:〓活动时间〓|〓任务开放时间〓).*?\d\.\d版本更新(?:完成|)后永久开放</value>
|
||||||
|
</data>
|
||||||
|
<data name="WebAnnouncementMatchPersistentActivityTime" xml:space="preserve">
|
||||||
|
<value>〓活动时间〓.*?\d\.\d版本期间持续开放</value>
|
||||||
|
</data>
|
||||||
|
<data name="WebAnnouncementMatchTransientActivityTime" xml:space="preserve">
|
||||||
|
<value>(?:〓活动时间〓|祈愿时间|【上架时间】).*?(\d\.\d版本更新后|\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}).*?~.*?&lt;t class="t_(?:gl|lc)".*?&gt;(.*?)&lt;/t&gt;</value>
|
||||||
|
</data>
|
||||||
|
<data name="WebAnnouncementMatchVersionUpdateTime" xml:space="preserve">
|
||||||
|
<value>〓更新时间〓.+?&lt;t class=\"t_(?:gl|lc)\".*?&gt;(.*?)&lt;/t&gt;</value>
|
||||||
|
</data>
|
||||||
|
<data name="WebAnnouncementMatchVersionUpdateTitle" xml:space="preserve">
|
||||||
|
<value>\d\.\d版本更新说明</value>
|
||||||
|
</data>
|
||||||
<data name="WebAnnouncementTimeDaysBeginFormat" xml:space="preserve">
|
<data name="WebAnnouncementTimeDaysBeginFormat" xml:space="preserve">
|
||||||
<value>{0} 天后开始</value>
|
<value>{0} 天后开始</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -2009,6 +2093,9 @@
|
|||||||
<data name="WebDailyNoteHomeCoinRecoveryFormat" xml:space="preserve">
|
<data name="WebDailyNoteHomeCoinRecoveryFormat" xml:space="preserve">
|
||||||
<value>预计 {0} {1:HH:mm} 达到存储上限</value>
|
<value>预计 {0} {1:HH:mm} 达到存储上限</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="WebDailyNoteHomeLocked" xml:space="preserve">
|
||||||
|
<value>尚未解锁洞天</value>
|
||||||
|
</data>
|
||||||
<data name="WebDailyNoteRecoveryTimeDay0" xml:space="preserve">
|
<data name="WebDailyNoteRecoveryTimeDay0" xml:space="preserve">
|
||||||
<value>今天</value>
|
<value>今天</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -2039,6 +2126,12 @@
|
|||||||
<data name="WebDailyNoteTransformerMinutesFormat" xml:space="preserve">
|
<data name="WebDailyNoteTransformerMinutesFormat" xml:space="preserve">
|
||||||
<value>{0} 分</value>
|
<value>{0} 分</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="WebDailyNoteTransformerNotObtained" xml:space="preserve">
|
||||||
|
<value>尚未获得</value>
|
||||||
|
</data>
|
||||||
|
<data name="WebDailyNoteTransformerNotObtainedDetail" xml:space="preserve">
|
||||||
|
<value>尚未获得参量质变仪</value>
|
||||||
|
</data>
|
||||||
<data name="WebDailyNoteTransformerNotReached" xml:space="preserve">
|
<data name="WebDailyNoteTransformerNotReached" xml:space="preserve">
|
||||||
<value>冷却中</value>
|
<value>冷却中</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -2093,6 +2186,9 @@
|
|||||||
<data name="WebResponseFormat" xml:space="preserve">
|
<data name="WebResponseFormat" xml:space="preserve">
|
||||||
<value>状态:{0} | 信息:{1}</value>
|
<value>状态:{0} | 信息:{1}</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="WebResponseRefreshCookieHintFormat" xml:space="preserve">
|
||||||
|
<value>请刷新 Cookie,原始消息:{0}</value>
|
||||||
|
</data>
|
||||||
<data name="WebResponseRequestExceptionFormat" xml:space="preserve">
|
<data name="WebResponseRequestExceptionFormat" xml:space="preserve">
|
||||||
<value>[{0}] 中的 [{1}] 网络请求异常,请稍后再试</value>
|
<value>[{0}] 中的 [{1}] 网络请求异常,请稍后再试</value>
|
||||||
</data>
|
</data>
|
||||||
|
|||||||
BIN
src/Snap.Hutao/Snap.Hutao/Resource/Navigation/Achievement.png
Normal file
|
After Width: | Height: | Size: 43 KiB |
BIN
src/Snap.Hutao/Snap.Hutao/Resource/Navigation/Announcement.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
src/Snap.Hutao/Snap.Hutao/Resource/Navigation/AvatarProperty.png
Normal file
|
After Width: | Height: | Size: 7.8 KiB |
BIN
src/Snap.Hutao/Snap.Hutao/Resource/Navigation/Cultivation.png
Normal file
|
After Width: | Height: | Size: 5.6 KiB |
BIN
src/Snap.Hutao/Snap.Hutao/Resource/Navigation/DailyNote.png
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
src/Snap.Hutao/Snap.Hutao/Resource/Navigation/Database.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
src/Snap.Hutao/Snap.Hutao/Resource/Navigation/GachaLog.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
src/Snap.Hutao/Snap.Hutao/Resource/Navigation/LaunchGame.png
Normal file
|
After Width: | Height: | Size: 5.5 KiB |
BIN
src/Snap.Hutao/Snap.Hutao/Resource/Navigation/SpiralAbyss.png
Normal file
|
After Width: | Height: | Size: 5.1 KiB |
BIN
src/Snap.Hutao/Snap.Hutao/Resource/Navigation/WikiAvatar.png
Normal file
|
After Width: | Height: | Size: 9.1 KiB |
BIN
src/Snap.Hutao/Snap.Hutao/Resource/Navigation/WikiMonster.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
src/Snap.Hutao/Snap.Hutao/Resource/Navigation/WikiWeapon.png
Normal file
|
After Width: | Height: | Size: 8.6 KiB |
@@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using Snap.Hutao.Core.Database;
|
using Snap.Hutao.Core.Database;
|
||||||
using Snap.Hutao.Model.Entity;
|
using Snap.Hutao.Model.Entity;
|
||||||
using Snap.Hutao.Model.Entity.Database;
|
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
|
||||||
namespace Snap.Hutao.Service.Achievement;
|
namespace Snap.Hutao.Service.Achievement;
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using Snap.Hutao.Model.Entity;
|
using Snap.Hutao.Model.Entity;
|
||||||
using Snap.Hutao.Model.Entity.Database;
|
|
||||||
using Snap.Hutao.Model.InterChange.Achievement;
|
using Snap.Hutao.Model.InterChange.Achievement;
|
||||||
using EntityAchievement = Snap.Hutao.Model.Entity.Achievement;
|
using EntityAchievement = Snap.Hutao.Model.Entity.Achievement;
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,7 @@
|
|||||||
|
|
||||||
using Snap.Hutao.Core;
|
using Snap.Hutao.Core;
|
||||||
using Snap.Hutao.Core.Database;
|
using Snap.Hutao.Core.Database;
|
||||||
using Snap.Hutao.Core.Diagnostics;
|
|
||||||
using Snap.Hutao.Model.Entity;
|
using Snap.Hutao.Model.Entity;
|
||||||
using Snap.Hutao.Model.Entity.Database;
|
|
||||||
using Snap.Hutao.Model.Primitive;
|
using Snap.Hutao.Model.Primitive;
|
||||||
using Snap.Hutao.ViewModel.Achievement;
|
using Snap.Hutao.ViewModel.Achievement;
|
||||||
using EntityAchievement = Snap.Hutao.Model.Entity.Achievement;
|
using EntityAchievement = Snap.Hutao.Model.Entity.Achievement;
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using Snap.Hutao.Model.Entity;
|
using Snap.Hutao.Model.Entity;
|
||||||
using Snap.Hutao.Model.Entity.Database;
|
|
||||||
using Snap.Hutao.Model.Primitive;
|
using Snap.Hutao.Model.Primitive;
|
||||||
using Snap.Hutao.ViewModel.Achievement;
|
using Snap.Hutao.ViewModel.Achievement;
|
||||||
using EntityAchievement = Snap.Hutao.Model.Entity.Achievement;
|
using EntityAchievement = Snap.Hutao.Model.Entity.Achievement;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using Microsoft.Extensions.Caching.Memory;
|
|||||||
using Snap.Hutao.Service.Abstraction;
|
using Snap.Hutao.Service.Abstraction;
|
||||||
using Snap.Hutao.Web.Hoyolab.Hk4e.Common.Announcement;
|
using Snap.Hutao.Web.Hoyolab.Hk4e.Common.Announcement;
|
||||||
using Snap.Hutao.Web.Response;
|
using Snap.Hutao.Web.Response;
|
||||||
|
using System.Globalization;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
@@ -55,8 +56,7 @@ internal sealed partial class AnnouncementService : IAnnouncementService
|
|||||||
// 将活动公告置于前方
|
// 将活动公告置于前方
|
||||||
wrapper.List.Reverse();
|
wrapper.List.Reverse();
|
||||||
|
|
||||||
// 将公告内容联入公告列表
|
PreprocessAnnouncements(contentMap, wrapper.List);
|
||||||
JoinAnnouncements(contentMap, wrapper.List);
|
|
||||||
|
|
||||||
return memoryCache.Set(CacheKey, wrapper, TimeSpan.FromMinutes(30));
|
return memoryCache.Set(CacheKey, wrapper, TimeSpan.FromMinutes(30));
|
||||||
}
|
}
|
||||||
@@ -65,29 +65,92 @@ internal sealed partial class AnnouncementService : IAnnouncementService
|
|||||||
return default!;
|
return default!;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void JoinAnnouncements(Dictionary<int, string> contentMap, List<AnnouncementListWrapper> announcementListWrappers)
|
private static void PreprocessAnnouncements(Dictionary<int, string> contentMap, List<AnnouncementListWrapper> announcementListWrappers)
|
||||||
{
|
{
|
||||||
Regex timeTagRegex = XmlTagRegex();
|
// 将公告内容联入公告列表
|
||||||
|
foreach (ref AnnouncementListWrapper listWrapper in CollectionsMarshal.AsSpan(announcementListWrappers))
|
||||||
|
{
|
||||||
|
foreach (ref Announcement item in CollectionsMarshal.AsSpan(listWrapper.List))
|
||||||
|
{
|
||||||
|
contentMap.TryGetValue(item.AnnId, out string? rawContent);
|
||||||
|
item.Content = rawContent ?? string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AdjustAnnouncementTime(announcementListWrappers);
|
||||||
|
|
||||||
foreach (ref AnnouncementListWrapper listWrapper in CollectionsMarshal.AsSpan(announcementListWrappers))
|
foreach (ref AnnouncementListWrapper listWrapper in CollectionsMarshal.AsSpan(announcementListWrappers))
|
||||||
{
|
{
|
||||||
foreach (ref Announcement item in CollectionsMarshal.AsSpan(listWrapper.List))
|
foreach (ref Announcement item in CollectionsMarshal.AsSpan(listWrapper.List))
|
||||||
{
|
{
|
||||||
if (contentMap.TryGetValue(item.AnnId, out string? rawContent))
|
item.Content = AnnouncementRegex.XmlTimeTagRegex.Replace(item.Content, x => x.Groups[1].Value);
|
||||||
{
|
|
||||||
// remove <t/> tag
|
|
||||||
rawContent = timeTagRegex.Replace(rawContent, x => x.Groups[1].Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
item.Content = rawContent ?? string.Empty;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
private static void AdjustAnnouncementTime(List<AnnouncementListWrapper> announcementListWrappers)
|
||||||
/// 匹配特殊的时间格式: <t.*?>(.*?)</t>
|
{
|
||||||
/// </summary>
|
// 活动公告
|
||||||
/// <returns>正则</returns>
|
List<Announcement> activities = announcementListWrappers
|
||||||
[GeneratedRegex("<t class=\"t_(?:gl|lc)\".*?>(.*?)</t>", RegexOptions.Multiline)]
|
.Single(wrapper => wrapper.TypeId == 1)
|
||||||
private static partial Regex XmlTagRegex();
|
.List;
|
||||||
|
|
||||||
|
// 更新公告
|
||||||
|
Announcement versionUpdate = announcementListWrappers
|
||||||
|
.Single(wrapper => wrapper.TypeId == 2)
|
||||||
|
.List
|
||||||
|
.Single(ann => AnnouncementRegex.VersionUpdateTitleRegex.IsMatch(ann.Title));
|
||||||
|
|
||||||
|
if (AnnouncementRegex.VersionUpdateTimeRegex.Match(versionUpdate.Content) is { Success: true } match)
|
||||||
|
{
|
||||||
|
DateTimeOffset versionUpdateTime = DateTimeOffset.Parse(match.Groups[1].ValueSpan, CultureInfo.InvariantCulture);
|
||||||
|
_ = 1;
|
||||||
|
foreach (ref readonly Announcement announcement in CollectionsMarshal.AsSpan(activities))
|
||||||
|
{
|
||||||
|
if (AnnouncementRegex.PermanentActivityTimeRegex.Match(announcement.Content) is { Success: true } permanent)
|
||||||
|
{
|
||||||
|
announcement.StartTime = versionUpdateTime;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (AnnouncementRegex.PersistentActivityTimeRegex.Match(announcement.Content) is { Success: true } persistent)
|
||||||
|
{
|
||||||
|
announcement.StartTime = versionUpdateTime;
|
||||||
|
announcement.EndTime = versionUpdateTime + TimeSpan.FromDays(42);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (AnnouncementRegex.TransientActivityTimeRegex.Match(announcement.Content) is { Success: true } transient)
|
||||||
|
{
|
||||||
|
announcement.StartTime = versionUpdateTime;
|
||||||
|
announcement.EndTime = DateTimeOffset.Parse(transient.Groups[2].ValueSpan, CultureInfo.InvariantCulture);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
MatchCollection matches = AnnouncementRegex.XmlTimeTagRegex.Matches(announcement.Content);
|
||||||
|
if (matches.Count >= 2)
|
||||||
|
{
|
||||||
|
List<DateTimeOffset> dateTimes = matches.Select(match => DateTimeOffset.Parse(match.Groups[1].ValueSpan, CultureInfo.InvariantCulture)).ToList();
|
||||||
|
DateTimeOffset min = DateTimeOffset.MaxValue;
|
||||||
|
DateTimeOffset max = DateTimeOffset.MinValue;
|
||||||
|
|
||||||
|
foreach (DateTimeOffset time in dateTimes)
|
||||||
|
{
|
||||||
|
if (time < min)
|
||||||
|
{
|
||||||
|
min = time;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (time > max)
|
||||||
|
{
|
||||||
|
max = time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
announcement.StartTime = min;
|
||||||
|
announcement.EndTime = max;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -13,9 +13,10 @@ using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord;
|
|||||||
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.Avatar;
|
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.Avatar;
|
||||||
using Snap.Hutao.Web.Response;
|
using Snap.Hutao.Web.Response;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
using Windows.Perception.Spatial;
|
||||||
using CalculateAvatar = Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate.Avatar;
|
using CalculateAvatar = Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate.Avatar;
|
||||||
using EnkaAvatarInfo = Snap.Hutao.Web.Enka.Model.AvatarInfo;
|
using EnkaAvatarInfo = Snap.Hutao.Web.Enka.Model.AvatarInfo;
|
||||||
using ModelAvatarInfo = Snap.Hutao.Model.Entity.AvatarInfo;
|
using EntityAvatarInfo = Snap.Hutao.Model.Entity.AvatarInfo;
|
||||||
using RecordCharacter = Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.Avatar.Character;
|
using RecordCharacter = Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.Avatar.Character;
|
||||||
using RecordPlayerInfo = Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.PlayerInfo;
|
using RecordPlayerInfo = Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.PlayerInfo;
|
||||||
|
|
||||||
@@ -39,10 +40,10 @@ internal sealed partial class AvatarInfoDbBulkOperation
|
|||||||
/// <param name="webInfos">Enka信息</param>
|
/// <param name="webInfos">Enka信息</param>
|
||||||
/// <param name="token">取消令牌</param>
|
/// <param name="token">取消令牌</param>
|
||||||
/// <returns>角色列表</returns>
|
/// <returns>角色列表</returns>
|
||||||
public List<EnkaAvatarInfo> UpdateDbAvatarInfos(string uid, IEnumerable<EnkaAvatarInfo> webInfos, CancellationToken token)
|
public List<EntityAvatarInfo> UpdateDbAvatarInfosByShowcase(string uid, IEnumerable<EnkaAvatarInfo> webInfos, CancellationToken token)
|
||||||
{
|
{
|
||||||
token.ThrowIfCancellationRequested();
|
token.ThrowIfCancellationRequested();
|
||||||
List<ModelAvatarInfo> dbInfos = avatarInfoDbService.GetAvatarInfoListByUid(uid);
|
List<EntityAvatarInfo> dbInfos = avatarInfoDbService.GetAvatarInfoListByUid(uid);
|
||||||
EnsureItemsAvatarIdDistinct(ref dbInfos, uid);
|
EnsureItemsAvatarIdDistinct(ref dbInfos, uid);
|
||||||
|
|
||||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||||
@@ -57,12 +58,12 @@ internal sealed partial class AvatarInfoDbBulkOperation
|
|||||||
}
|
}
|
||||||
|
|
||||||
token.ThrowIfCancellationRequested();
|
token.ThrowIfCancellationRequested();
|
||||||
ModelAvatarInfo? entity = dbInfos.SingleOrDefault(i => i.Info.AvatarId == webInfo.AvatarId);
|
EntityAvatarInfo? entity = dbInfos.SingleOrDefault(i => i.Info.AvatarId == webInfo.AvatarId);
|
||||||
AddOrUpdateAvatarInfo(entity, uid, appDbContext, webInfo);
|
AddOrUpdateAvatarInfo(entity, uid, appDbContext, webInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
token.ThrowIfCancellationRequested();
|
token.ThrowIfCancellationRequested();
|
||||||
return avatarInfoDbService.GetAvatarInfoInfoListByUid(uid);
|
return avatarInfoDbService.GetAvatarInfoListByUid(uid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,11 +73,11 @@ internal sealed partial class AvatarInfoDbBulkOperation
|
|||||||
/// <param name="userAndUid">用户与角色</param>
|
/// <param name="userAndUid">用户与角色</param>
|
||||||
/// <param name="token">取消令牌</param>
|
/// <param name="token">取消令牌</param>
|
||||||
/// <returns>角色列表</returns>
|
/// <returns>角色列表</returns>
|
||||||
public async ValueTask<List<EnkaAvatarInfo>> UpdateDbAvatarInfosByGameRecordCharacterAsync(UserAndUid userAndUid, CancellationToken token)
|
public async ValueTask<List<EntityAvatarInfo>> UpdateDbAvatarInfosByGameRecordCharacterAsync(UserAndUid userAndUid, CancellationToken token)
|
||||||
{
|
{
|
||||||
token.ThrowIfCancellationRequested();
|
token.ThrowIfCancellationRequested();
|
||||||
string uid = userAndUid.Uid.Value;
|
string uid = userAndUid.Uid.Value;
|
||||||
List<ModelAvatarInfo> dbInfos = avatarInfoDbService.GetAvatarInfoListByUid(uid);
|
List<EntityAvatarInfo> dbInfos = avatarInfoDbService.GetAvatarInfoListByUid(uid);
|
||||||
EnsureItemsAvatarIdDistinct(ref dbInfos, uid);
|
EnsureItemsAvatarIdDistinct(ref dbInfos, uid);
|
||||||
|
|
||||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||||
@@ -113,14 +114,14 @@ internal sealed partial class AvatarInfoDbBulkOperation
|
|||||||
}
|
}
|
||||||
|
|
||||||
token.ThrowIfCancellationRequested();
|
token.ThrowIfCancellationRequested();
|
||||||
ModelAvatarInfo? entity = dbInfos.SingleOrDefault(i => i.Info.AvatarId == character.Id);
|
EntityAvatarInfo? entity = dbInfos.SingleOrDefault(i => i.Info.AvatarId == character.Id);
|
||||||
AddOrUpdateAvatarInfo(entity, character.Id, uid, appDbContext, transformer, character);
|
AddOrUpdateAvatarInfo(entity, character.Id, uid, appDbContext, transformer, character);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return avatarInfoDbService.GetAvatarInfoInfoListByUid(uid);
|
return avatarInfoDbService.GetAvatarInfoListByUid(uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -129,11 +130,11 @@ internal sealed partial class AvatarInfoDbBulkOperation
|
|||||||
/// <param name="userAndUid">用户与角色</param>
|
/// <param name="userAndUid">用户与角色</param>
|
||||||
/// <param name="token">取消令牌</param>
|
/// <param name="token">取消令牌</param>
|
||||||
/// <returns>角色列表</returns>
|
/// <returns>角色列表</returns>
|
||||||
public async ValueTask<List<EnkaAvatarInfo>> UpdateDbAvatarInfosByCalculateAvatarDetailAsync(UserAndUid userAndUid, CancellationToken token)
|
public async ValueTask<List<EntityAvatarInfo>> UpdateDbAvatarInfosByCalculateAvatarDetailAsync(UserAndUid userAndUid, CancellationToken token)
|
||||||
{
|
{
|
||||||
token.ThrowIfCancellationRequested();
|
token.ThrowIfCancellationRequested();
|
||||||
string uid = userAndUid.Uid.Value;
|
string uid = userAndUid.Uid.Value;
|
||||||
List<ModelAvatarInfo> dbInfos = avatarInfoDbService.GetAvatarInfoListByUid(uid);
|
List<EntityAvatarInfo> dbInfos = avatarInfoDbService.GetAvatarInfoListByUid(uid);
|
||||||
EnsureItemsAvatarIdDistinct(ref dbInfos, uid);
|
EnsureItemsAvatarIdDistinct(ref dbInfos, uid);
|
||||||
|
|
||||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||||
@@ -167,22 +168,40 @@ internal sealed partial class AvatarInfoDbBulkOperation
|
|||||||
}
|
}
|
||||||
|
|
||||||
token.ThrowIfCancellationRequested();
|
token.ThrowIfCancellationRequested();
|
||||||
ModelAvatarInfo? entity = dbInfos.SingleOrDefault(i => i.Info.AvatarId == avatar.Id);
|
EntityAvatarInfo? entity = dbInfos.SingleOrDefault(i => i.Info.AvatarId == avatar.Id);
|
||||||
AddOrUpdateAvatarInfo(entity, avatar.Id, uid, appDbContext, transformer, detailAvatarResponse.Data);
|
AddOrUpdateAvatarInfo(entity, avatar.Id, uid, appDbContext, transformer, detailAvatarResponse.Data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return avatarInfoDbService.GetAvatarInfoInfoListByUid(uid);
|
return avatarInfoDbService.GetAvatarInfoListByUid(uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static void AddOrUpdateAvatarInfo<TSource>(ModelAvatarInfo? entity, in AvatarId avatarId, string uid, AppDbContext appDbContext, IAvatarInfoTransformer<TSource> transformer, TSource source)
|
private static void AddOrUpdateAvatarInfo(EntityAvatarInfo? entity, string uid, AppDbContext appDbContext, EnkaAvatarInfo webInfo)
|
||||||
|
{
|
||||||
|
if (entity is null)
|
||||||
|
{
|
||||||
|
entity = EntityAvatarInfo.From(uid, webInfo);
|
||||||
|
entity.ShowcaseRefreshTime = DateTimeOffset.Now;
|
||||||
|
appDbContext.AvatarInfos.AddAndSave(entity);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
entity.Info = webInfo;
|
||||||
|
entity.ShowcaseRefreshTime = DateTimeOffset.Now;
|
||||||
|
appDbContext.AvatarInfos.UpdateAndSave(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static void AddOrUpdateAvatarInfo(EntityAvatarInfo? entity, in AvatarId avatarId, string uid, AppDbContext appDbContext, CalculateAvatarDetailAvatarInfoTransformer transformer, AvatarDetail source)
|
||||||
{
|
{
|
||||||
if (entity is null)
|
if (entity is null)
|
||||||
{
|
{
|
||||||
EnkaAvatarInfo avatarInfo = new() { AvatarId = avatarId };
|
EnkaAvatarInfo avatarInfo = new() { AvatarId = avatarId };
|
||||||
transformer.Transform(ref avatarInfo, source);
|
transformer.Transform(ref avatarInfo, source);
|
||||||
entity = ModelAvatarInfo.From(uid, avatarInfo);
|
entity = EntityAvatarInfo.From(uid, avatarInfo);
|
||||||
|
entity.CalculatorRefreshTime = DateTimeOffset.Now;
|
||||||
appDbContext.AvatarInfos.AddAndSave(entity);
|
appDbContext.AvatarInfos.AddAndSave(entity);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -190,26 +209,33 @@ internal sealed partial class AvatarInfoDbBulkOperation
|
|||||||
EnkaAvatarInfo avatarInfo = entity.Info;
|
EnkaAvatarInfo avatarInfo = entity.Info;
|
||||||
transformer.Transform(ref avatarInfo, source);
|
transformer.Transform(ref avatarInfo, source);
|
||||||
entity.Info = avatarInfo;
|
entity.Info = avatarInfo;
|
||||||
|
entity.CalculatorRefreshTime = DateTimeOffset.Now;
|
||||||
appDbContext.AvatarInfos.UpdateAndSave(entity);
|
appDbContext.AvatarInfos.UpdateAndSave(entity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static void AddOrUpdateAvatarInfo(ModelAvatarInfo? entity, string uid, AppDbContext appDbContext, EnkaAvatarInfo webInfo)
|
private static void AddOrUpdateAvatarInfo(EntityAvatarInfo? entity, in AvatarId avatarId, string uid, AppDbContext appDbContext, GameRecordCharacterAvatarInfoTransformer transformer, Character source)
|
||||||
{
|
{
|
||||||
if (entity is null)
|
if (entity is null)
|
||||||
{
|
{
|
||||||
entity = ModelAvatarInfo.From(uid, webInfo);
|
EnkaAvatarInfo avatarInfo = new() { AvatarId = avatarId };
|
||||||
|
transformer.Transform(ref avatarInfo, source);
|
||||||
|
entity = EntityAvatarInfo.From(uid, avatarInfo);
|
||||||
|
entity.GameRecordRefreshTime = DateTimeOffset.Now;
|
||||||
appDbContext.AvatarInfos.AddAndSave(entity);
|
appDbContext.AvatarInfos.AddAndSave(entity);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
entity.Info = webInfo;
|
EnkaAvatarInfo avatarInfo = entity.Info;
|
||||||
|
transformer.Transform(ref avatarInfo, source);
|
||||||
|
entity.Info = avatarInfo;
|
||||||
|
entity.GameRecordRefreshTime = DateTimeOffset.Now;
|
||||||
appDbContext.AvatarInfos.UpdateAndSave(entity);
|
appDbContext.AvatarInfos.UpdateAndSave(entity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EnsureItemsAvatarIdDistinct(ref List<ModelAvatarInfo> dbInfos, string uid)
|
private void EnsureItemsAvatarIdDistinct(ref List<EntityAvatarInfo> dbInfos, string uid)
|
||||||
{
|
{
|
||||||
int distinctCount = dbInfos.Select(info => info.Info.AvatarId).ToHashSet().Count;
|
int distinctCount = dbInfos.Select(info => info.Info.AvatarId).ToHashSet().Count;
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ using Microsoft.EntityFrameworkCore;
|
|||||||
using Snap.Hutao.Core.Database;
|
using Snap.Hutao.Core.Database;
|
||||||
using Snap.Hutao.Model.Entity.Database;
|
using Snap.Hutao.Model.Entity.Database;
|
||||||
using EnkaAvatarInfo = Snap.Hutao.Web.Enka.Model.AvatarInfo;
|
using EnkaAvatarInfo = Snap.Hutao.Web.Enka.Model.AvatarInfo;
|
||||||
using ModelAvatarInfo = Snap.Hutao.Model.Entity.AvatarInfo;
|
using EntityAvatarInfo = Snap.Hutao.Model.Entity.AvatarInfo;
|
||||||
|
|
||||||
namespace Snap.Hutao.Service.AvatarInfo;
|
namespace Snap.Hutao.Service.AvatarInfo;
|
||||||
|
|
||||||
@@ -15,7 +15,7 @@ internal sealed partial class AvatarInfoDbService : IAvatarInfoDbService
|
|||||||
{
|
{
|
||||||
private readonly IServiceProvider serviceProvider;
|
private readonly IServiceProvider serviceProvider;
|
||||||
|
|
||||||
public List<ModelAvatarInfo> GetAvatarInfoListByUid(string uid)
|
public List<EntityAvatarInfo> GetAvatarInfoListByUid(string uid)
|
||||||
{
|
{
|
||||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||||
{
|
{
|
||||||
@@ -24,19 +24,6 @@ internal sealed partial class AvatarInfoDbService : IAvatarInfoDbService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<EnkaAvatarInfo> GetAvatarInfoInfoListByUid(string uid)
|
|
||||||
{
|
|
||||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
|
||||||
{
|
|
||||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
|
||||||
return appDbContext.AvatarInfos
|
|
||||||
.AsNoTracking()
|
|
||||||
.Where(i => i.Uid == uid)
|
|
||||||
.Select(i => i.Info)
|
|
||||||
.ToList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void DeleteAvatarInfoRangeByUid(string uid)
|
public void DeleteAvatarInfoRangeByUid(string uid)
|
||||||
{
|
{
|
||||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ using Snap.Hutao.Web.Enka;
|
|||||||
using Snap.Hutao.Web.Enka.Model;
|
using Snap.Hutao.Web.Enka.Model;
|
||||||
using Snap.Hutao.Web.Hoyolab;
|
using Snap.Hutao.Web.Hoyolab;
|
||||||
using EnkaAvatarInfo = Snap.Hutao.Web.Enka.Model.AvatarInfo;
|
using EnkaAvatarInfo = Snap.Hutao.Web.Enka.Model.AvatarInfo;
|
||||||
|
using EntityAvatarInfo = Snap.Hutao.Model.Entity.AvatarInfo;
|
||||||
|
|
||||||
namespace Snap.Hutao.Service.AvatarInfo;
|
namespace Snap.Hutao.Service.AvatarInfo;
|
||||||
|
|
||||||
@@ -56,28 +57,28 @@ internal sealed partial class AvatarInfoService : IAvatarInfoService
|
|||||||
return new(RefreshResult.ShowcaseNotOpen, default);
|
return new(RefreshResult.ShowcaseNotOpen, default);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<EnkaAvatarInfo> list = avatarInfoDbBulkOperation.UpdateDbAvatarInfos(userAndUid.Uid.Value, resp.AvatarInfoList, token);
|
List<EntityAvatarInfo> list = avatarInfoDbBulkOperation.UpdateDbAvatarInfosByShowcase(userAndUid.Uid.Value, resp.AvatarInfoList, token);
|
||||||
Summary summary = await GetSummaryCoreAsync(list, token).ConfigureAwait(false);
|
Summary summary = await GetSummaryCoreAsync(list, token).ConfigureAwait(false);
|
||||||
return new(RefreshResult.Ok, summary);
|
return new(RefreshResult.Ok, summary);
|
||||||
}
|
}
|
||||||
|
|
||||||
case RefreshOption.RequestFromHoyolabGameRecord:
|
case RefreshOption.RequestFromHoyolabGameRecord:
|
||||||
{
|
{
|
||||||
List<EnkaAvatarInfo> list = await avatarInfoDbBulkOperation.UpdateDbAvatarInfosByGameRecordCharacterAsync(userAndUid, token).ConfigureAwait(false);
|
List<EntityAvatarInfo> list = await avatarInfoDbBulkOperation.UpdateDbAvatarInfosByGameRecordCharacterAsync(userAndUid, token).ConfigureAwait(false);
|
||||||
Summary summary = await GetSummaryCoreAsync(list, token).ConfigureAwait(false);
|
Summary summary = await GetSummaryCoreAsync(list, token).ConfigureAwait(false);
|
||||||
return new(RefreshResult.Ok, summary);
|
return new(RefreshResult.Ok, summary);
|
||||||
}
|
}
|
||||||
|
|
||||||
case RefreshOption.RequestFromHoyolabCalculate:
|
case RefreshOption.RequestFromHoyolabCalculate:
|
||||||
{
|
{
|
||||||
List<EnkaAvatarInfo> list = await avatarInfoDbBulkOperation.UpdateDbAvatarInfosByCalculateAvatarDetailAsync(userAndUid, token).ConfigureAwait(false);
|
List<EntityAvatarInfo> list = await avatarInfoDbBulkOperation.UpdateDbAvatarInfosByCalculateAvatarDetailAsync(userAndUid, token).ConfigureAwait(false);
|
||||||
Summary summary = await GetSummaryCoreAsync(list, token).ConfigureAwait(false);
|
Summary summary = await GetSummaryCoreAsync(list, token).ConfigureAwait(false);
|
||||||
return new(RefreshResult.Ok, summary);
|
return new(RefreshResult.Ok, summary);
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
List<EnkaAvatarInfo> list = avatarInfoDbService.GetAvatarInfoInfoListByUid(userAndUid.Uid.Value);
|
List<EntityAvatarInfo> list = avatarInfoDbService.GetAvatarInfoListByUid(userAndUid.Uid.Value);
|
||||||
Summary summary = await GetSummaryCoreAsync(list, token).ConfigureAwait(false);
|
Summary summary = await GetSummaryCoreAsync(list, token).ConfigureAwait(false);
|
||||||
token.ThrowIfCancellationRequested();
|
token.ThrowIfCancellationRequested();
|
||||||
return new(RefreshResult.Ok, summary.Avatars.Count == 0 ? null : summary);
|
return new(RefreshResult.Ok, summary.Avatars.Count == 0 ? null : summary);
|
||||||
@@ -96,7 +97,7 @@ internal sealed partial class AvatarInfoService : IAvatarInfoService
|
|||||||
?? await enkaClient.GetDataAsync(uid, token).ConfigureAwait(false);
|
?? await enkaClient.GetDataAsync(uid, token).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async ValueTask<Summary> GetSummaryCoreAsync(IEnumerable<EnkaAvatarInfo> avatarInfos, CancellationToken token)
|
private async ValueTask<Summary> GetSummaryCoreAsync(IEnumerable<Model.Entity.AvatarInfo> avatarInfos, CancellationToken token)
|
||||||
{
|
{
|
||||||
using (ValueStopwatch.MeasureExecution(logger))
|
using (ValueStopwatch.MeasureExecution(logger))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -17,5 +17,5 @@ internal interface ISummaryFactory
|
|||||||
/// <param name="avatarInfos">角色列表</param>
|
/// <param name="avatarInfos">角色列表</param>
|
||||||
/// <param name="token">取消令牌</param>
|
/// <param name="token">取消令牌</param>
|
||||||
/// <returns>简述对象</returns>
|
/// <returns>简述对象</returns>
|
||||||
ValueTask<Summary> CreateAsync(IEnumerable<Web.Enka.Model.AvatarInfo> avatarInfos, CancellationToken token);
|
ValueTask<Summary> CreateAsync(IEnumerable<Model.Entity.AvatarInfo> avatarInfos, CancellationToken token);
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,7 @@ using Snap.Hutao.Model.Metadata.Converter;
|
|||||||
using Snap.Hutao.Model.Primitive;
|
using Snap.Hutao.Model.Primitive;
|
||||||
using Snap.Hutao.ViewModel.AvatarProperty;
|
using Snap.Hutao.ViewModel.AvatarProperty;
|
||||||
using Snap.Hutao.Web.Enka.Model;
|
using Snap.Hutao.Web.Enka.Model;
|
||||||
|
using EntityAvatarInfo = Snap.Hutao.Model.Entity.AvatarInfo;
|
||||||
using MetadataAvatar = Snap.Hutao.Model.Metadata.Avatar.Avatar;
|
using MetadataAvatar = Snap.Hutao.Model.Metadata.Avatar.Avatar;
|
||||||
using MetadataWeapon = Snap.Hutao.Model.Metadata.Weapon.Weapon;
|
using MetadataWeapon = Snap.Hutao.Model.Metadata.Weapon.Weapon;
|
||||||
using ModelAvatarInfo = Snap.Hutao.Web.Enka.Model.AvatarInfo;
|
using ModelAvatarInfo = Snap.Hutao.Web.Enka.Model.AvatarInfo;
|
||||||
@@ -21,7 +22,12 @@ namespace Snap.Hutao.Service.AvatarInfo.Factory;
|
|||||||
[HighQuality]
|
[HighQuality]
|
||||||
internal sealed class SummaryAvatarFactory
|
internal sealed class SummaryAvatarFactory
|
||||||
{
|
{
|
||||||
|
private static readonly DateTimeOffset DefaultRefreshTime = new(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0));
|
||||||
|
|
||||||
private readonly ModelAvatarInfo avatarInfo;
|
private readonly ModelAvatarInfo avatarInfo;
|
||||||
|
private readonly DateTimeOffset showcaseRefreshTime;
|
||||||
|
private readonly DateTimeOffset gameRecordRefreshTime;
|
||||||
|
private readonly DateTimeOffset calculatorRefreshTime;
|
||||||
private readonly SummaryMetadataContext metadataContext;
|
private readonly SummaryMetadataContext metadataContext;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -29,10 +35,14 @@ internal sealed class SummaryAvatarFactory
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="metadataContext">元数据上下文</param>
|
/// <param name="metadataContext">元数据上下文</param>
|
||||||
/// <param name="avatarInfo">角色信息</param>
|
/// <param name="avatarInfo">角色信息</param>
|
||||||
public SummaryAvatarFactory(SummaryMetadataContext metadataContext, ModelAvatarInfo avatarInfo)
|
public SummaryAvatarFactory(SummaryMetadataContext metadataContext, EntityAvatarInfo avatarInfo)
|
||||||
{
|
{
|
||||||
this.metadataContext = metadataContext;
|
this.metadataContext = metadataContext;
|
||||||
this.avatarInfo = avatarInfo;
|
this.avatarInfo = avatarInfo.Info;
|
||||||
|
|
||||||
|
showcaseRefreshTime = avatarInfo.ShowcaseRefreshTime;
|
||||||
|
gameRecordRefreshTime = avatarInfo.GameRecordRefreshTime;
|
||||||
|
calculatorRefreshTime = avatarInfo.CalculatorRefreshTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -67,6 +77,17 @@ internal sealed class SummaryAvatarFactory
|
|||||||
Weapon = reliquaryAndWeapon.Weapon,
|
Weapon = reliquaryAndWeapon.Weapon,
|
||||||
Reliquaries = reliquaryAndWeapon.Reliquaries,
|
Reliquaries = reliquaryAndWeapon.Reliquaries,
|
||||||
Score = $"{reliquaryAndWeapon.Reliquaries.Sum(r => r.Score):F2}",
|
Score = $"{reliquaryAndWeapon.Reliquaries.Sum(r => r.Score):F2}",
|
||||||
|
|
||||||
|
// times
|
||||||
|
ShowcaseRefreshTimeFormat = showcaseRefreshTime == DateTimeOffsetExtension.DatebaseDefaultTime
|
||||||
|
? SH.ServiceAvatarInfoSummaryShowcaseNotRefreshed
|
||||||
|
: SH.ServiceAvatarInfoSummaryShowcaseRefreshTimeFormat.Format(showcaseRefreshTime),
|
||||||
|
GameRecordRefreshTimeFormat = gameRecordRefreshTime == DateTimeOffsetExtension.DatebaseDefaultTime
|
||||||
|
? SH.ServiceAvatarInfoSummaryGameRecordNotRefreshed
|
||||||
|
: SH.ServiceAvatarInfoSummaryGameRecordRefreshTimeFormat.Format(gameRecordRefreshTime),
|
||||||
|
CalculatorRefreshTimeFormat = calculatorRefreshTime == DateTimeOffsetExtension.DatebaseDefaultTime
|
||||||
|
? SH.ServiceAvatarInfoSummaryCalculatorNotRefreshed
|
||||||
|
: SH.ServiceAvatarInfoSummaryCalculatorRefreshTimeFormat.Format(calculatorRefreshTime),
|
||||||
};
|
};
|
||||||
|
|
||||||
ApplyCostumeIconOrDefault(ref propertyAvatar, avatar);
|
ApplyCostumeIconOrDefault(ref propertyAvatar, avatar);
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
using Snap.Hutao.Model.Metadata;
|
using Snap.Hutao.Model.Metadata;
|
||||||
using Snap.Hutao.Service.Metadata;
|
using Snap.Hutao.Service.Metadata;
|
||||||
using Snap.Hutao.ViewModel.AvatarProperty;
|
using Snap.Hutao.ViewModel.AvatarProperty;
|
||||||
using ModelAvatarInfo = Snap.Hutao.Web.Enka.Model.AvatarInfo;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Service.AvatarInfo.Factory;
|
namespace Snap.Hutao.Service.AvatarInfo.Factory;
|
||||||
|
|
||||||
@@ -19,7 +18,7 @@ internal sealed partial class SummaryFactory : ISummaryFactory
|
|||||||
private readonly IMetadataService metadataService;
|
private readonly IMetadataService metadataService;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public async ValueTask<Summary> CreateAsync(IEnumerable<ModelAvatarInfo> avatarInfos, CancellationToken token)
|
public async ValueTask<Summary> CreateAsync(IEnumerable<Model.Entity.AvatarInfo> avatarInfos, CancellationToken token)
|
||||||
{
|
{
|
||||||
SummaryMetadataContext metadataContext = new()
|
SummaryMetadataContext metadataContext = new()
|
||||||
{
|
{
|
||||||
@@ -35,14 +34,14 @@ internal sealed partial class SummaryFactory : ISummaryFactory
|
|||||||
return new()
|
return new()
|
||||||
{
|
{
|
||||||
Avatars = avatarInfos
|
Avatars = avatarInfos
|
||||||
.Where(a => !AvatarIds.IsPlayer(a.AvatarId))
|
.Where(a => !AvatarIds.IsPlayer(a.Info.AvatarId))
|
||||||
.Select(a => new SummaryAvatarFactory(metadataContext, a).Create())
|
.Select(a => new SummaryAvatarFactory(metadataContext, a).Create())
|
||||||
.OrderByDescending(a => a.LevelNumber)
|
.OrderByDescending(a => a.LevelNumber)
|
||||||
.ThenByDescending(a => a.Name)
|
.ThenBy(a => a.Name)
|
||||||
.ToList(),
|
.ToList(),
|
||||||
|
|
||||||
// .ThenByDescending(a => a.Quality)
|
// .ThenByDescending(a => a.Quality)
|
||||||
// .ThenByDescending(a => a.ActivatedConstellationCount)
|
// .ThenByDescending(a => a.ActivatedConstellationCount)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -23,10 +23,7 @@ internal static class SummaryHelper
|
|||||||
/// <returns>命之座</returns>
|
/// <returns>命之座</returns>
|
||||||
public static List<ConstellationView> CreateConstellations(List<Skill> talents, List<SkillId>? talentIds)
|
public static List<ConstellationView> CreateConstellations(List<Skill> talents, List<SkillId>? talentIds)
|
||||||
{
|
{
|
||||||
if (talentIds.IsNullOrEmpty())
|
talentIds ??= new();
|
||||||
{
|
|
||||||
return new();
|
|
||||||
}
|
|
||||||
|
|
||||||
return talents.SelectList(talent => new ConstellationView()
|
return talents.SelectList(talent => new ConstellationView()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Core.ExceptionService;
|
||||||
using Snap.Hutao.Model.Intrinsic;
|
using Snap.Hutao.Model.Intrinsic;
|
||||||
using Snap.Hutao.Model.Intrinsic.Format;
|
|
||||||
using Snap.Hutao.Model.Metadata.Converter;
|
using Snap.Hutao.Model.Metadata.Converter;
|
||||||
using Snap.Hutao.Model.Metadata.Reliquary;
|
using Snap.Hutao.Model.Metadata.Reliquary;
|
||||||
using Snap.Hutao.Model.Primitive;
|
using Snap.Hutao.Model.Primitive;
|
||||||
using Snap.Hutao.ViewModel.AvatarProperty;
|
using Snap.Hutao.ViewModel.AvatarProperty;
|
||||||
using Snap.Hutao.Web.Enka.Model;
|
using System.Runtime.InteropServices;
|
||||||
using MetadataReliquary = Snap.Hutao.Model.Metadata.Reliquary.Reliquary;
|
using MetadataReliquary = Snap.Hutao.Model.Metadata.Reliquary.Reliquary;
|
||||||
using ModelAvatarInfo = Snap.Hutao.Web.Enka.Model.AvatarInfo;
|
using ModelAvatarInfo = Snap.Hutao.Web.Enka.Model.AvatarInfo;
|
||||||
|
|
||||||
@@ -57,7 +57,7 @@ internal sealed class SummaryReliquaryFactory
|
|||||||
Description = reliquary.Description,
|
Description = reliquary.Description,
|
||||||
|
|
||||||
// EquipBase
|
// EquipBase
|
||||||
Level = $"+{equip.Reliquary.Level - 1}",
|
Level = $"+{equip.Reliquary.Level - 1U}",
|
||||||
Quality = reliquary.RankLevel,
|
Quality = reliquary.RankLevel,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -67,7 +67,7 @@ internal sealed class SummaryReliquaryFactory
|
|||||||
result.SecondarySubProperties = subProperty.GetRange(^affixCount..);
|
result.SecondarySubProperties = subProperty.GetRange(^affixCount..);
|
||||||
|
|
||||||
ArgumentNullException.ThrowIfNull(equip.Flat.ReliquarySubstats);
|
ArgumentNullException.ThrowIfNull(equip.Flat.ReliquarySubstats);
|
||||||
result.ComposedSubProperties = equip.Flat.ReliquarySubstats.SelectList(CreateComposedSubProperty);
|
result.ComposedSubProperties = CreateComposedSubProperties(equip.Reliquary.AppendPropIdList);
|
||||||
|
|
||||||
ReliquaryMainAffixLevel relicLevel = metadataContext.ReliquaryLevels.Single(r => r.Level == equip.Reliquary.Level && r.Rank == reliquary.RankLevel);
|
ReliquaryMainAffixLevel relicLevel = metadataContext.ReliquaryLevels.Single(r => r.Level == equip.Reliquary.Level && r.Rank == reliquary.RankLevel);
|
||||||
FightProperty property = metadataContext.IdReliquaryMainAffixMap[equip.Reliquary.MainPropId];
|
FightProperty property = metadataContext.IdReliquaryMainAffixMap[equip.Reliquary.MainPropId];
|
||||||
@@ -112,11 +112,36 @@ internal sealed class SummaryReliquaryFactory
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<ReliquaryComposedSubProperty> CreateComposedSubProperties(List<ReliquarySubAffixId> appendProps)
|
||||||
|
{
|
||||||
|
List<SummaryReliquarySubPropertyCompositionInfo> infos = new();
|
||||||
|
foreach (ref readonly ReliquarySubAffixId subAffixId in CollectionsMarshal.AsSpan(appendProps))
|
||||||
|
{
|
||||||
|
ReliquarySubAffix subAffix = metadataContext.IdReliquarySubAffixMap[subAffixId];
|
||||||
|
SummaryReliquarySubPropertyCompositionInfo info = infos.SingleOrAdd(prop => prop.Type == subAffix.Type, () => new(subAffix.Type));
|
||||||
|
info.Count += 1;
|
||||||
|
info.Value += subAffix.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (infos.Count > 4)
|
||||||
|
{
|
||||||
|
ThrowHelper.InvalidOperation("无效的圣遗物数据");
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ReliquaryComposedSubProperty> results = new();
|
||||||
|
foreach (ref readonly SummaryReliquarySubPropertyCompositionInfo info in CollectionsMarshal.AsSpan(infos))
|
||||||
|
{
|
||||||
|
results.Add(info.ToReliquaryComposedSubProperty());
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
private float ScoreReliquary(FightProperty property, MetadataReliquary reliquary, ReliquaryMainAffixLevel relicLevel, List<ReliquarySubProperty> subProperties)
|
private float ScoreReliquary(FightProperty property, MetadataReliquary reliquary, ReliquaryMainAffixLevel relicLevel, List<ReliquarySubProperty> subProperties)
|
||||||
{
|
{
|
||||||
// 沙/杯/头
|
// 沙/杯/头
|
||||||
// equip.Flat.EquipType is EquipType.EQUIP_SHOES or EquipType.EQUIP_RING or EquipType.EQUIP_DRESS
|
// equip.Flat.EquipType is EquipType.EQUIP_SHOES or EquipType.EQUIP_RING or EquipType.EQUIP_DRESS
|
||||||
if (equip.Flat.EquipType > EquipType.EQUIP_SHOES)
|
if (equip.Flat.EquipType >= EquipType.EQUIP_SHOES)
|
||||||
{
|
{
|
||||||
// 从喵插件抓取的圣遗物评分权重
|
// 从喵插件抓取的圣遗物评分权重
|
||||||
// 部分复杂的角色暂时使用了默认值
|
// 部分复杂的角色暂时使用了默认值
|
||||||
@@ -138,29 +163,13 @@ internal sealed class SummaryReliquaryFactory
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ReliquarySubProperty CreateComposedSubProperty(ReliquarySubstat substat)
|
|
||||||
{
|
|
||||||
FormatMethod method = substat.AppendPropId.GetFormatMethod();
|
|
||||||
string valueFormatted = method switch
|
|
||||||
{
|
|
||||||
FormatMethod.Integer => $"{MathF.Round(substat.StatValue, MidpointRounding.AwayFromZero)}",
|
|
||||||
FormatMethod.Percent => $"{substat.StatValue}%",
|
|
||||||
_ => $"{substat.StatValue}",
|
|
||||||
};
|
|
||||||
|
|
||||||
return new(substat.AppendPropId.GetLocalizedDescription(), valueFormatted, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
[SuppressMessage("", "SH002")]
|
[SuppressMessage("", "SH002")]
|
||||||
private ReliquarySubProperty CreateSubProperty(ReliquarySubAffixId appendPropId)
|
private ReliquarySubProperty CreateSubProperty(ReliquarySubAffixId appendPropId)
|
||||||
{
|
{
|
||||||
ReliquarySubAffix affix = metadataContext.IdReliquarySubAffixMap[appendPropId];
|
ReliquarySubAffix affix = metadataContext.IdReliquarySubAffixMap[appendPropId];
|
||||||
FightProperty property = affix.Type;
|
FightProperty property = affix.Type;
|
||||||
|
|
||||||
return new(
|
return new(property, FightPropertyFormat.FormatValue(property, affix.Value), ScoreSubAffix(appendPropId));
|
||||||
property.GetLocalizedDescription(),
|
|
||||||
FightPropertyFormat.FormatValue(property, affix.Value),
|
|
||||||
ScoreSubAffix(appendPropId));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private float ScoreSubAffix(in ReliquarySubAffixId appendId)
|
private float ScoreSubAffix(in ReliquarySubAffixId appendId)
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Model.Intrinsic;
|
||||||
|
using Snap.Hutao.Model.Metadata.Converter;
|
||||||
|
using Snap.Hutao.ViewModel.AvatarProperty;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Service.AvatarInfo.Factory;
|
||||||
|
|
||||||
|
internal sealed class SummaryReliquarySubPropertyCompositionInfo
|
||||||
|
{
|
||||||
|
public SummaryReliquarySubPropertyCompositionInfo(FightProperty type)
|
||||||
|
{
|
||||||
|
Type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FightProperty Type { get; set; }
|
||||||
|
|
||||||
|
public float Value { get; set; }
|
||||||
|
|
||||||
|
public uint Count { get; set; }
|
||||||
|
|
||||||
|
public ReliquaryComposedSubProperty ToReliquaryComposedSubProperty()
|
||||||
|
{
|
||||||
|
return new(Type, FightPropertyFormat.FormatValue(Type, Value), 0) { EnhancedCount = Count };
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using EnkaAvatarInfo = Snap.Hutao.Web.Enka.Model.AvatarInfo;
|
using EntityAvatarInfo = Snap.Hutao.Model.Entity.AvatarInfo;
|
||||||
using ModelAvatarInfo = Snap.Hutao.Model.Entity.AvatarInfo;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Service.AvatarInfo;
|
namespace Snap.Hutao.Service.AvatarInfo;
|
||||||
|
|
||||||
@@ -10,7 +9,5 @@ internal interface IAvatarInfoDbService
|
|||||||
{
|
{
|
||||||
void DeleteAvatarInfoRangeByUid(string uid);
|
void DeleteAvatarInfoRangeByUid(string uid);
|
||||||
|
|
||||||
List<EnkaAvatarInfo> GetAvatarInfoInfoListByUid(string uid);
|
List<EntityAvatarInfo> GetAvatarInfoListByUid(string uid);
|
||||||
|
|
||||||
List<ModelAvatarInfo> GetAvatarInfoListByUid(string uid);
|
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,6 @@
|
|||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using Snap.Hutao.Model.Intrinsic;
|
using Snap.Hutao.Model.Intrinsic;
|
||||||
using Snap.Hutao.Model.Primitive;
|
|
||||||
using Snap.Hutao.Web.Enka.Model;
|
using Snap.Hutao.Web.Enka.Model;
|
||||||
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.Avatar;
|
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.Avatar;
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,13 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Snap.Hutao.Core.Database;
|
using Snap.Hutao.Core.Database;
|
||||||
using Snap.Hutao.Core.ExceptionService;
|
|
||||||
using Snap.Hutao.Model;
|
using Snap.Hutao.Model;
|
||||||
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.Entity.Primitive;
|
using Snap.Hutao.Model.Entity.Primitive;
|
||||||
using Snap.Hutao.Model.Metadata.Item;
|
using Snap.Hutao.Model.Metadata.Item;
|
||||||
using Snap.Hutao.Model.Primitive;
|
using Snap.Hutao.Model.Primitive;
|
||||||
using Snap.Hutao.Service.Metadata;
|
|
||||||
using Snap.Hutao.ViewModel.Cultivation;
|
using Snap.Hutao.ViewModel.Cultivation;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
|
||||||
|
|||||||
@@ -6,12 +6,9 @@ using Snap.Hutao.Core;
|
|||||||
using Snap.Hutao.Core.LifeCycle;
|
using Snap.Hutao.Core.LifeCycle;
|
||||||
using Snap.Hutao.Model.Entity;
|
using Snap.Hutao.Model.Entity;
|
||||||
using Snap.Hutao.Service.Game;
|
using Snap.Hutao.Service.Game;
|
||||||
using Snap.Hutao.Web.Hoyolab.Takumi.Auth;
|
|
||||||
using Snap.Hutao.Web.Hoyolab.Takumi.Binding;
|
using Snap.Hutao.Web.Hoyolab.Takumi.Binding;
|
||||||
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.DailyNote;
|
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.DailyNote;
|
||||||
using Snap.Hutao.Web.Response;
|
using Snap.Hutao.Web.Response;
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using Windows.Foundation.Metadata;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Service.DailyNote;
|
namespace Snap.Hutao.Service.DailyNote;
|
||||||
|
|
||||||
@@ -49,14 +46,21 @@ internal sealed partial class DailyNoteNotificationOperation
|
|||||||
|
|
||||||
string? attribution = SH.ServiceDailyNoteNotifierAttribution;
|
string? attribution = SH.ServiceDailyNoteNotifierAttribution;
|
||||||
|
|
||||||
Response<ListWrapper<UserGameRole>> rolesResponse = await bindingClient
|
if (entry.UserGameRole is not null)
|
||||||
.GetUserGameRolesOverseaAwareAsync(entry.User)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (rolesResponse.IsOk())
|
|
||||||
{
|
{
|
||||||
List<UserGameRole> roles = rolesResponse.Data.List;
|
attribution = entry.UserGameRole.ToString();
|
||||||
attribution = roles.SingleOrDefault(r => r.GameUid == entry.Uid)?.ToString() ?? ToastAttributionUnknown;
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Response<ListWrapper<UserGameRole>> rolesResponse = await bindingClient
|
||||||
|
.GetUserGameRolesOverseaAwareAsync(entry.User)
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (rolesResponse.IsOk())
|
||||||
|
{
|
||||||
|
List<UserGameRole> roles = rolesResponse.Data.List;
|
||||||
|
attribution = roles.SingleOrDefault(r => r.GameUid == entry.Uid)?.ToString() ?? ToastAttributionUnknown;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ToastContentBuilder builder = new ToastContentBuilder()
|
ToastContentBuilder builder = new ToastContentBuilder()
|
||||||
|
|||||||
@@ -48,6 +48,27 @@ internal sealed class DailyNoteOptions : DbStoreOptions
|
|||||||
new(SH.ViewModelDailyNoteRefreshTime60, OneMinute * 60),
|
new(SH.ViewModelDailyNoteRefreshTime60, OneMinute * 60),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public bool IsAutoRefreshEnabled
|
||||||
|
{
|
||||||
|
get => scheduleTaskInterop.IsDailyNoteRefreshEnabled();
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value)
|
||||||
|
{
|
||||||
|
if (SelectedRefreshTime is not null)
|
||||||
|
{
|
||||||
|
scheduleTaskInterop.RegisterForDailyNoteRefresh(SelectedRefreshTime.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
scheduleTaskInterop.UnregisterForDailyNoteRefresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 选中的刷新时间
|
/// 选中的刷新时间
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -2,13 +2,9 @@
|
|||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using CommunityToolkit.Mvvm.Messaging;
|
using CommunityToolkit.Mvvm.Messaging;
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Snap.Hutao.Core.Database;
|
|
||||||
using Snap.Hutao.Core.DependencyInjection.Abstraction;
|
using Snap.Hutao.Core.DependencyInjection.Abstraction;
|
||||||
using Snap.Hutao.Message;
|
using Snap.Hutao.Message;
|
||||||
using Snap.Hutao.Model.Entity;
|
using Snap.Hutao.Model.Entity;
|
||||||
using Snap.Hutao.Model.Entity.Database;
|
|
||||||
using Snap.Hutao.Service.Notification;
|
|
||||||
using Snap.Hutao.Service.User;
|
using Snap.Hutao.Service.User;
|
||||||
using Snap.Hutao.ViewModel.User;
|
using Snap.Hutao.ViewModel.User;
|
||||||
using Snap.Hutao.Web.Hoyolab;
|
using Snap.Hutao.Web.Hoyolab;
|
||||||
@@ -71,13 +67,13 @@ internal sealed partial class DailyNoteService : IDailyNoteService, IRecipient<U
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public async ValueTask<ObservableCollection<DailyNoteEntry>> GetDailyNoteEntryCollectionAsync()
|
public async ValueTask<ObservableCollection<DailyNoteEntry>> GetDailyNoteEntryCollectionAsync(bool forceRefresh = false)
|
||||||
{
|
{
|
||||||
if (entries is null)
|
if (entries is null)
|
||||||
{
|
{
|
||||||
// IUserService.GetUserGameRoleByUid only usable after call IUserService.GetRoleCollectionAsync
|
// IUserService.GetUserGameRoleByUid only usable after call IUserService.GetRoleCollectionAsync
|
||||||
await userService.GetRoleCollectionAsync().ConfigureAwait(false);
|
await userService.GetRoleCollectionAsync().ConfigureAwait(false);
|
||||||
await RefreshDailyNotesAsync().ConfigureAwait(false);
|
await RefreshDailyNotesCoreAsync(forceRefresh).ConfigureAwait(false);
|
||||||
|
|
||||||
List<DailyNoteEntry> entryList = dailyNoteDbService.GetDailyNoteEntryIncludeUserList();
|
List<DailyNoteEntry> entryList = dailyNoteDbService.GetDailyNoteEntryIncludeUserList();
|
||||||
entryList.ForEach(entry => { entry.UserGameRole = userService.GetUserGameRoleByUid(entry.Uid); });
|
entryList.ForEach(entry => { entry.UserGameRole = userService.GetUserGameRoleByUid(entry.Uid); });
|
||||||
@@ -88,30 +84,9 @@ internal sealed partial class DailyNoteService : IDailyNoteService, IRecipient<U
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public async ValueTask RefreshDailyNotesAsync()
|
public ValueTask RefreshDailyNotesAsync()
|
||||||
{
|
{
|
||||||
foreach (DailyNoteEntry entry in dailyNoteDbService.GetDailyNoteEntryIncludeUserList())
|
return RefreshDailyNotesCoreAsync(true);
|
||||||
{
|
|
||||||
Web.Response.Response<WebDailyNote> dailyNoteResponse = await serviceProvider
|
|
||||||
.GetRequiredService<IOverseaSupportFactory<IGameRecordClient>>()
|
|
||||||
.Create(PlayerUid.IsOversea(entry.Uid))
|
|
||||||
.GetDailyNoteAsync(new(entry.User, entry.Uid))
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (dailyNoteResponse.IsOk())
|
|
||||||
{
|
|
||||||
WebDailyNote dailyNote = dailyNoteResponse.Data;
|
|
||||||
|
|
||||||
// cache
|
|
||||||
await taskContext.SwitchToMainThreadAsync();
|
|
||||||
entries?.SingleOrDefault(e => e.UserId == entry.UserId && e.Uid == entry.Uid)?.UpdateDailyNote(dailyNote);
|
|
||||||
|
|
||||||
// database
|
|
||||||
await dailyNoteNotificationOperation.SendAsync(entry).ConfigureAwait(false);
|
|
||||||
entry.DailyNote = dailyNote;
|
|
||||||
await dailyNoteDbService.UpdateDailyNoteEntryAsync(entry).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
@@ -130,4 +105,38 @@ internal sealed partial class DailyNoteService : IDailyNoteService, IRecipient<U
|
|||||||
await taskContext.SwitchToBackgroundAsync();
|
await taskContext.SwitchToBackgroundAsync();
|
||||||
await dailyNoteDbService.UpdateDailyNoteEntryAsync(entry).ConfigureAwait(false);
|
await dailyNoteDbService.UpdateDailyNoteEntryAsync(entry).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async ValueTask RefreshDailyNotesCoreAsync(bool forceRefresh)
|
||||||
|
{
|
||||||
|
foreach (DailyNoteEntry entry in dailyNoteDbService.GetDailyNoteEntryIncludeUserList())
|
||||||
|
{
|
||||||
|
if (!forceRefresh && entry.DailyNote is not null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Web.Response.Response<WebDailyNote> dailyNoteResponse = await serviceProvider
|
||||||
|
.GetRequiredService<IOverseaSupportFactory<IGameRecordClient>>()
|
||||||
|
.Create(PlayerUid.IsOversea(entry.Uid))
|
||||||
|
.GetDailyNoteAsync(new(entry.User, entry.Uid))
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (dailyNoteResponse.IsOk())
|
||||||
|
{
|
||||||
|
WebDailyNote dailyNote = dailyNoteResponse.Data;
|
||||||
|
|
||||||
|
// 集合内的实时便笺与数据库取出的非同一个对象,需要分别更新
|
||||||
|
// cache
|
||||||
|
await taskContext.SwitchToMainThreadAsync();
|
||||||
|
entries?.SingleOrDefault(e => e.UserId == entry.UserId && e.Uid == entry.Uid)?.UpdateDailyNote(dailyNote);
|
||||||
|
|
||||||
|
// 发送通知
|
||||||
|
await dailyNoteNotificationOperation.SendAsync(entry).ConfigureAwait(false);
|
||||||
|
|
||||||
|
// database
|
||||||
|
entry.UpdateDailyNote(dailyNote);
|
||||||
|
await dailyNoteDbService.UpdateDailyNoteEntryAsync(entry).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -20,11 +20,7 @@ internal interface IDailyNoteService
|
|||||||
/// <returns>任务</returns>
|
/// <returns>任务</returns>
|
||||||
ValueTask AddDailyNoteAsync(UserAndUid userAndUid);
|
ValueTask AddDailyNoteAsync(UserAndUid userAndUid);
|
||||||
|
|
||||||
/// <summary>
|
ValueTask<ObservableCollection<DailyNoteEntry>> GetDailyNoteEntryCollectionAsync(bool forceRefresh = false);
|
||||||
/// 异步获取实时便笺列表
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>实时便笺列表</returns>
|
|
||||||
ValueTask<ObservableCollection<DailyNoteEntry>> GetDailyNoteEntryCollectionAsync();
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异步刷新实时便笺
|
/// 异步刷新实时便笺
|
||||||
|
|||||||
@@ -2,14 +2,13 @@
|
|||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using Snap.Hutao.Core.ExceptionService;
|
using Snap.Hutao.Core.ExceptionService;
|
||||||
using Snap.Hutao.Model.Entity;
|
|
||||||
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;
|
||||||
using Snap.Hutao.Model.Metadata.Weapon;
|
using Snap.Hutao.Model.Metadata.Weapon;
|
||||||
using Snap.Hutao.Service.Metadata;
|
using Snap.Hutao.Service.Metadata;
|
||||||
using Snap.Hutao.ViewModel.GachaLog;
|
using Snap.Hutao.ViewModel.GachaLog;
|
||||||
using Snap.Hutao.Web.Hutao;
|
using Snap.Hutao.Web.Hutao.GachaLog;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Snap.Hutao.Service.GachaLog.Factory;
|
namespace Snap.Hutao.Service.GachaLog.Factory;
|
||||||
@@ -28,7 +27,7 @@ internal sealed partial class GachaStatisticsFactory : IGachaStatisticsFactory
|
|||||||
private readonly AppOptions options;
|
private readonly AppOptions options;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public async ValueTask<GachaStatistics> CreateAsync(List<GachaItem> items, GachaLogServiceMetadataContext context)
|
public async ValueTask<GachaStatistics> CreateAsync(List<Model.Entity.GachaItem> items, GachaLogServiceMetadataContext context)
|
||||||
{
|
{
|
||||||
await taskContext.SwitchToBackgroundAsync();
|
await taskContext.SwitchToBackgroundAsync();
|
||||||
List<GachaEvent> gachaEvents = await metadataService.GetGachaEventsAsync().ConfigureAwait(false);
|
List<GachaEvent> gachaEvents = await metadataService.GetGachaEventsAsync().ConfigureAwait(false);
|
||||||
@@ -40,7 +39,7 @@ internal sealed partial class GachaStatisticsFactory : IGachaStatisticsFactory
|
|||||||
private static GachaStatistics CreateCore(
|
private static GachaStatistics CreateCore(
|
||||||
ITaskContext taskContext,
|
ITaskContext taskContext,
|
||||||
HomaGachaLogClient gachaLogClient,
|
HomaGachaLogClient gachaLogClient,
|
||||||
List<GachaItem> items,
|
List<Model.Entity.GachaItem> items,
|
||||||
List<HistoryWishBuilder> historyWishBuilders,
|
List<HistoryWishBuilder> historyWishBuilders,
|
||||||
in GachaLogServiceMetadataContext context,
|
in GachaLogServiceMetadataContext context,
|
||||||
bool isEmptyHistoryWishVisible)
|
bool isEmptyHistoryWishVisible)
|
||||||
@@ -62,7 +61,7 @@ internal sealed partial class GachaStatisticsFactory : IGachaStatisticsFactory
|
|||||||
|
|
||||||
// Items are ordered by precise time, first is oldest
|
// Items are ordered by precise time, first is oldest
|
||||||
// 'ref' is not allowed here because we have lambda below
|
// 'ref' is not allowed here because we have lambda below
|
||||||
foreach (GachaItem item in CollectionsMarshal.AsSpan(items))
|
foreach (Model.Entity.GachaItem item in CollectionsMarshal.AsSpan(items))
|
||||||
{
|
{
|
||||||
// Find target history wish to operate.
|
// Find target history wish to operate.
|
||||||
HistoryWishBuilder? targetHistoryWishBuilder = historyWishBuilders
|
HistoryWishBuilder? targetHistoryWishBuilder = historyWishBuilders
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using Snap.Hutao.ViewModel.GachaLog;
|
using Snap.Hutao.ViewModel.GachaLog;
|
||||||
using Snap.Hutao.Web.Hutao;
|
|
||||||
using Snap.Hutao.Web.Hutao.GachaLog;
|
using Snap.Hutao.Web.Hutao.GachaLog;
|
||||||
using Snap.Hutao.Web.Response;
|
using Snap.Hutao.Web.Response;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
@@ -28,9 +27,9 @@ internal sealed class PullPrediction
|
|||||||
await context.TaskContext.SwitchToBackgroundAsync();
|
await context.TaskContext.SwitchToBackgroundAsync();
|
||||||
Response<GachaDistribution> response = await context.GetGachaDistributionAsync().ConfigureAwait(false);
|
Response<GachaDistribution> response = await context.GetGachaDistributionAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
if (response.IsOk())
|
if (response is { ReturnCode: 0, Data: GachaDistribution data })
|
||||||
{
|
{
|
||||||
PredictResult result = PredictCore(response.Data.Distribution, typedWishSummary);
|
PredictResult result = PredictCore(data.Distribution, typedWishSummary);
|
||||||
await barrier.SignalAndWaitAsync().ConfigureAwait(false);
|
await barrier.SignalAndWaitAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
await context.TaskContext.SwitchToMainThreadAsync();
|
await context.TaskContext.SwitchToMainThreadAsync();
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ using Snap.Hutao.Model.Intrinsic;
|
|||||||
using Snap.Hutao.Model.Metadata.Abstraction;
|
using Snap.Hutao.Model.Metadata.Abstraction;
|
||||||
using Snap.Hutao.ViewModel.GachaLog;
|
using Snap.Hutao.ViewModel.GachaLog;
|
||||||
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
||||||
using Snap.Hutao.Web.Hutao;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Service.GachaLog.Factory;
|
namespace Snap.Hutao.Service.GachaLog.Factory;
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
||||||
using Snap.Hutao.Web.Hutao;
|
|
||||||
using Snap.Hutao.Web.Hutao.GachaLog;
|
using Snap.Hutao.Web.Hutao.GachaLog;
|
||||||
using Snap.Hutao.Web.Response;
|
using Snap.Hutao.Web.Response;
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Snap.Hutao.Model.Entity;
|
using Snap.Hutao.Model.Entity;
|
||||||
|
|
||||||
namespace Snap.Hutao.Service.GachaLog;
|
namespace Snap.Hutao.Service.GachaLog;
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using Snap.Hutao.Model.Entity;
|
using Snap.Hutao.Model.Entity;
|
||||||
using Snap.Hutao.Model.Entity.Database;
|
|
||||||
using Snap.Hutao.Service.GachaLog.QueryProvider;
|
using Snap.Hutao.Service.GachaLog.QueryProvider;
|
||||||
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
|||||||
@@ -34,4 +34,14 @@ internal sealed class GachaLogFetchStatus
|
|||||||
/// 当前获取的物品
|
/// 当前获取的物品
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<Item> Items { get; set; } = new(20);
|
public List<Item> Items { get; set; } = new(20);
|
||||||
|
|
||||||
|
public string Header
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return AuthKeyTimeout
|
||||||
|
? SH.ViewDialogGachaLogRefreshProgressAuthkeyTimeout
|
||||||
|
: SH.ViewDialogGachaLogRefreshProgressDescription.Format(ConfigType.GetLocalizedDescription());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,7 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using Snap.Hutao.Core.Database;
|
|
||||||
using Snap.Hutao.Model.Entity;
|
using Snap.Hutao.Model.Entity;
|
||||||
using Snap.Hutao.Model.Entity.Database;
|
|
||||||
using Snap.Hutao.Model.Metadata;
|
using Snap.Hutao.Model.Metadata;
|
||||||
using Snap.Hutao.Model.Metadata.Avatar;
|
using Snap.Hutao.Model.Metadata.Avatar;
|
||||||
using Snap.Hutao.Model.Metadata.Weapon;
|
using Snap.Hutao.Model.Metadata.Weapon;
|
||||||
@@ -12,7 +10,6 @@ using Snap.Hutao.Service.GachaLog.Factory;
|
|||||||
using Snap.Hutao.Service.Metadata;
|
using Snap.Hutao.Service.Metadata;
|
||||||
using Snap.Hutao.ViewModel.GachaLog;
|
using Snap.Hutao.ViewModel.GachaLog;
|
||||||
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
||||||
using Snap.Hutao.Web.Hutao;
|
|
||||||
using Snap.Hutao.Web.Hutao.GachaLog;
|
using Snap.Hutao.Web.Hutao.GachaLog;
|
||||||
using Snap.Hutao.Web.Response;
|
using Snap.Hutao.Web.Response;
|
||||||
|
|
||||||
|
|||||||
@@ -2,13 +2,11 @@
|
|||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using Snap.Hutao.Model;
|
using Snap.Hutao.Model;
|
||||||
using Snap.Hutao.Model.Entity;
|
|
||||||
using Snap.Hutao.Model.Metadata.Abstraction;
|
using Snap.Hutao.Model.Metadata.Abstraction;
|
||||||
using Snap.Hutao.Model.Metadata.Avatar;
|
using Snap.Hutao.Model.Metadata.Avatar;
|
||||||
using Snap.Hutao.Model.Metadata.Weapon;
|
using Snap.Hutao.Model.Metadata.Weapon;
|
||||||
using Snap.Hutao.Model.Primitive;
|
using Snap.Hutao.Model.Primitive;
|
||||||
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Service.GachaLog;
|
namespace Snap.Hutao.Service.GachaLog;
|
||||||
|
|
||||||
|
|||||||