mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
support language switch
This commit is contained in:
@@ -49,9 +49,11 @@
|
||||
<!-- Brushes -->
|
||||
<SolidColorBrush x:Key="AvatarPropertyAddValueBrush" Color="{ThemeResource AvatarPropertyAddValueColor}"/>
|
||||
<!-- Uris -->
|
||||
<x:String x:Key="DocumentLink_MhyAccountSwitch">https://hut.ao/features/mhy-account-switch.html#%E5%A6%82%E4%BD%95%E8%8E%B7%E5%8F%96-cookie</x:String>
|
||||
<x:String x:Key="DocumentLink_MhyAccountSwitch">https://hut.ao/features/mhy-account-switch.html</x:String>
|
||||
<x:String x:Key="DocumentLink_BugReport">https://hut.ao/statements/bug-report.html</x:String>
|
||||
<x:String x:Key="HolographicHat_GetToken_Release">https://github.com/HolographicHat/GetToken/releases/latest</x:String>
|
||||
<x:String x:Key="DocumentLink_Translate">https://translate.hut.ao</x:String>
|
||||
<x:String x:Key="Sponsor_Afadian">https://afdian.net/a/DismissedLight</x:String>
|
||||
|
||||
<x:String x:Key="UI_ItemIcon_None">https://static.snapgenshin.com/Bg/UI_ItemIcon_None.png</x:String>
|
||||
<x:String x:Key="UI_ImgSign_ItemIcon">https://static.snapgenshin.com/Bg/UI_ImgSign_ItemIcon.png</x:String>
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Snap.Hutao.Control;
|
||||
/// when object is not used anymore.
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
public class BindingProxy : DependencyObject
|
||||
internal sealed class BindingProxy : DependencyObject
|
||||
{
|
||||
private static readonly DependencyProperty DataContextProperty = Property<BindingProxy>.Depend<object>(nameof(DataContext));
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace Snap.Hutao.Control.Image;
|
||||
/// 为其他图像类控件提供基类
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
public abstract class CompositionImage : Microsoft.UI.Xaml.Controls.Control
|
||||
internal abstract class CompositionImage : Microsoft.UI.Xaml.Controls.Control
|
||||
{
|
||||
private static readonly DependencyProperty SourceProperty = Property<CompositionImage>.Depend(nameof(Source), default(Uri), OnSourceChanged);
|
||||
private static readonly DependencyProperty EnableLazyLoadingProperty = Property<CompositionImage>.DependBoxed<bool>(nameof(EnableLazyLoading), BoxedValues.True);
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace Snap.Hutao.Control.Theme;
|
||||
/// 主题帮助工具类
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
public static class ThemeHelper
|
||||
internal static class ThemeHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 判断主题是否相等
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace Snap.Hutao.Core.Caching;
|
||||
[Injection(InjectAs.Singleton, typeof(IImageCache))]
|
||||
[HttpClient(HttpClientConfigration.Default)]
|
||||
[PrimaryHttpMessageHandler(MaxConnectionsPerServer = 8)]
|
||||
public sealed class ImageCache : IImageCache, IImageCacheFilePathOperation
|
||||
internal sealed class ImageCache : IImageCache, IImageCacheFilePathOperation
|
||||
{
|
||||
private const string CacheFolderName = nameof(ImageCache);
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Snap.Hutao.Core.Database;
|
||||
/// 数据库集合扩展
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
public static class DbSetExtension
|
||||
internal static class DbSetExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取对应的数据库上下文
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace Snap.Hutao.Core.Database;
|
||||
/// 可枚举扩展
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
public static class EnumerableExtension
|
||||
internal static class EnumerableExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取选中的值或默认值
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace Snap.Hutao.Core.Database;
|
||||
/// 必须实现该接口
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
public interface ISelectable
|
||||
internal interface ISelectable
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取或设置当前项的选中状态
|
||||
|
||||
@@ -19,7 +19,6 @@ internal static class QueryableExtension
|
||||
/// <typeparam name="TSource">源类型</typeparam>
|
||||
/// <param name="source">源</param>
|
||||
/// <param name="predicate">条件</param>
|
||||
/// <param name="token">取消令牌</param>
|
||||
/// <returns>SQL返回个数</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int ExecuteDeleteWhere<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate)
|
||||
|
||||
@@ -6,7 +6,8 @@ namespace Snap.Hutao.Core.DependencyInjection.Annotation;
|
||||
/// <summary>
|
||||
/// 注入方法
|
||||
/// </summary>
|
||||
public enum InjectAs
|
||||
[HighQuality]
|
||||
internal enum InjectAs
|
||||
{
|
||||
/// <summary>
|
||||
/// 指示应注册为单例对象
|
||||
|
||||
@@ -7,8 +7,9 @@ namespace Snap.Hutao.Core.DependencyInjection.Annotation;
|
||||
/// 指示被标注的类型可注入
|
||||
/// 由源生成器生成注入代码
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
|
||||
public class InjectionAttribute : Attribute
|
||||
internal sealed class InjectionAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// 指示该类将注入为不带有接口实现的类
|
||||
|
||||
@@ -3,8 +3,12 @@
|
||||
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Snap.Hutao.Core.Database;
|
||||
using Snap.Hutao.Core.Setting;
|
||||
using Snap.Hutao.Model.Entity;
|
||||
using Snap.Hutao.Model.Entity.Database;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Snap.Hutao.Core.DependencyInjection;
|
||||
|
||||
@@ -44,6 +48,9 @@ internal static class IocConfiguration
|
||||
#endif
|
||||
context.Database.Migrate();
|
||||
}
|
||||
|
||||
SettingEntry entry = context.Settings.SingleOrAdd(SettingEntry.Culture, CultureInfo.CurrentCulture.Name);
|
||||
Localization.Initialize(entry.Value!);
|
||||
}
|
||||
|
||||
return services.AddDbContext<AppDbContext>(builder =>
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace Snap.Hutao.Core.ExpressionService;
|
||||
/// </summary>
|
||||
/// <typeparam name="TTo">Target type</typeparam>
|
||||
[HighQuality]
|
||||
public static class CastTo<TTo>
|
||||
internal static class CastTo<TTo>
|
||||
{
|
||||
/// <summary>
|
||||
/// Casts <see cref="s"/> to <see cref="TTo"/>.
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace Snap.Hutao.Core.IO.Bits;
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
[DebuggerDisplay("{BytesRead}/{TotalBytes}")]
|
||||
public class ProgressUpdateStatus
|
||||
internal sealed class ProgressUpdateStatus
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造一个新的进度更新状态
|
||||
|
||||
@@ -23,10 +23,16 @@ internal static class Clipboard
|
||||
{
|
||||
await ThreadHelper.SwitchToMainThreadAsync();
|
||||
DataPackageView view = Windows.ApplicationModel.DataTransfer.Clipboard.GetContent();
|
||||
string json = await view.GetTextAsync();
|
||||
|
||||
await ThreadHelper.SwitchToBackgroundAsync();
|
||||
return JsonSerializer.Deserialize<T>(json, options);
|
||||
if (view.Contains(StandardDataFormats.Text))
|
||||
{
|
||||
string json = await view.GetTextAsync();
|
||||
|
||||
await ThreadHelper.SwitchToBackgroundAsync();
|
||||
return JsonSerializer.Deserialize<T>(json, options);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
31
src/Snap.Hutao/Snap.Hutao/Core/IO/StreamCopyState.cs
Normal file
31
src/Snap.Hutao/Snap.Hutao/Core/IO/StreamCopyState.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Core.IO;
|
||||
|
||||
/// <summary>
|
||||
/// 流复制状态
|
||||
/// </summary>
|
||||
internal sealed class StreamCopyState
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造一个新的流复制状态
|
||||
/// </summary>
|
||||
/// <param name="bytesCopied">已复制字节</param>
|
||||
/// <param name="totalBytes">总字节数</param>
|
||||
public StreamCopyState(long bytesCopied, long totalBytes)
|
||||
{
|
||||
BytesCopied = bytesCopied;
|
||||
TotalBytes = totalBytes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 已复制字节
|
||||
/// </summary>
|
||||
public long BytesCopied { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 总字节数
|
||||
/// </summary>
|
||||
public long TotalBytes { get; }
|
||||
}
|
||||
57
src/Snap.Hutao/Snap.Hutao/Core/IO/StreamCopyWorker.cs
Normal file
57
src/Snap.Hutao/Snap.Hutao/Core/IO/StreamCopyWorker.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.IO;
|
||||
|
||||
namespace Snap.Hutao.Core.IO;
|
||||
|
||||
/// <summary>
|
||||
/// 流复制器
|
||||
/// </summary>
|
||||
internal sealed class StreamCopyWorker
|
||||
{
|
||||
private readonly Stream source;
|
||||
private readonly Stream destination;
|
||||
private readonly long totalBytes;
|
||||
private readonly int bufferSize;
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个新的流复制器
|
||||
/// </summary>
|
||||
/// <param name="source">源</param>
|
||||
/// <param name="destination">目标</param>
|
||||
/// <param name="totalBytes">总字节</param>
|
||||
/// <param name="bufferSize">字节尺寸</param>
|
||||
public StreamCopyWorker(Stream source, Stream destination, long totalBytes, int bufferSize = 81920)
|
||||
{
|
||||
Verify.Operation(source.CanRead, "Source Stream can't read");
|
||||
Verify.Operation(destination.CanWrite, "Destination Stream can't write");
|
||||
|
||||
this.source = source;
|
||||
this.destination = destination;
|
||||
this.totalBytes = totalBytes;
|
||||
this.bufferSize = bufferSize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步复制
|
||||
/// </summary>
|
||||
/// <param name="progress">进度</param>
|
||||
/// <returns>任务</returns>
|
||||
public async Task CopyAsync(IProgress<StreamCopyState> progress)
|
||||
{
|
||||
long totalBytesRead = 0;
|
||||
int bytesRead;
|
||||
Memory<byte> buffer = new byte[bufferSize];
|
||||
|
||||
do
|
||||
{
|
||||
bytesRead = await source.ReadAsync(buffer).ConfigureAwait(false);
|
||||
await destination.WriteAsync(buffer[..bytesRead]).ConfigureAwait(false);
|
||||
|
||||
totalBytesRead += bytesRead;
|
||||
progress.Report(new(totalBytesRead, totalBytes));
|
||||
}
|
||||
while (bytesRead > 0);
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,8 @@ namespace Snap.Hutao.Core.Json.Annotation;
|
||||
/// <summary>
|
||||
/// Json 序列化类型
|
||||
/// </summary>
|
||||
public enum JsonSerializeType
|
||||
[HighQuality]
|
||||
internal enum JsonSerializeType
|
||||
{
|
||||
/// <summary>
|
||||
/// Int32
|
||||
|
||||
@@ -10,6 +10,7 @@ using Snap.Hutao.Service.DailyNote;
|
||||
using Snap.Hutao.Service.Metadata;
|
||||
using Snap.Hutao.Service.Navigation;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Security.Principal;
|
||||
|
||||
namespace Snap.Hutao.Core.LifeCycle;
|
||||
@@ -25,11 +26,6 @@ internal static class Activation
|
||||
/// </summary>
|
||||
public const string Action = nameof(Action);
|
||||
|
||||
/// <summary>
|
||||
/// 无操作
|
||||
/// </summary>
|
||||
public const string NoAction = "";
|
||||
|
||||
/// <summary>
|
||||
/// Uid
|
||||
/// </summary>
|
||||
@@ -146,7 +142,13 @@ internal static class Activation
|
||||
{
|
||||
switch (arguments)
|
||||
{
|
||||
case NoAction:
|
||||
case LaunchGame:
|
||||
{
|
||||
await HandleLaunchGameActionAsync().ConfigureAwait(false);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
// Increase launch times
|
||||
LocalSetting.Set(SettingKeys.LaunchTimes, LocalSetting.Get(SettingKeys.LaunchTimes, 0) + 1);
|
||||
@@ -154,12 +156,6 @@ internal static class Activation
|
||||
await WaitMainWindowAsync().ConfigureAwait(false);
|
||||
break;
|
||||
}
|
||||
|
||||
case LaunchGame:
|
||||
{
|
||||
await HandleLaunchGameActionAsync().ConfigureAwait(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
23
src/Snap.Hutao/Snap.Hutao/Core/Setting/Localization.cs
Normal file
23
src/Snap.Hutao/Snap.Hutao/Core/Setting/Localization.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.Globalization;
|
||||
|
||||
namespace Snap.Hutao.Core.Setting;
|
||||
|
||||
/// <summary>
|
||||
/// 本地化
|
||||
/// </summary>
|
||||
internal static class Localization
|
||||
{
|
||||
/// <summary>
|
||||
/// 初始化本地化语言
|
||||
/// </summary>
|
||||
/// <param name="culture">语言代码</param>
|
||||
public static void Initialize(string culture)
|
||||
{
|
||||
CultureInfo cultureInfo = CultureInfo.CreateSpecificCulture(culture);
|
||||
CultureInfo.CurrentCulture = cultureInfo;
|
||||
CultureInfo.CurrentUICulture = cultureInfo;
|
||||
}
|
||||
}
|
||||
@@ -15,18 +15,24 @@
|
||||
Margin="48,0,0,0"/>
|
||||
|
||||
<cwuc:SwitchPresenter x:Name="ContentSwitchPresenter">
|
||||
<cwuc:Case>
|
||||
<cwuc:Case.Value>
|
||||
<x:Boolean>False</x:Boolean>
|
||||
</cwuc:Case.Value>
|
||||
<shv:MainView/>
|
||||
</cwuc:Case>
|
||||
<cwuc:SwitchPresenter.ContentTransitions>
|
||||
<TransitionCollection>
|
||||
<EntranceThemeTransition/>
|
||||
<ContentThemeTransition/>
|
||||
</TransitionCollection>
|
||||
</cwuc:SwitchPresenter.ContentTransitions>
|
||||
<cwuc:Case>
|
||||
<cwuc:Case.Value>
|
||||
<x:Boolean>True</x:Boolean>
|
||||
</cwuc:Case.Value>
|
||||
<shv:WelcomeView/>
|
||||
</cwuc:Case>
|
||||
<cwuc:Case>
|
||||
<cwuc:Case.Value>
|
||||
<x:Boolean>False</x:Boolean>
|
||||
</cwuc:Case.Value>
|
||||
<shv:MainView/>
|
||||
</cwuc:Case>
|
||||
</cwuc:SwitchPresenter>
|
||||
</Grid>
|
||||
</Window>
|
||||
|
||||
@@ -1,24 +1,50 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Model.Intrinsic;
|
||||
using System.Collections.Immutable;
|
||||
|
||||
namespace Snap.Hutao.Model.Binding.AvatarProperty;
|
||||
|
||||
/// <summary>
|
||||
/// 角色属性值
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
internal sealed class AvatarProperty
|
||||
internal sealed class AvatarProperty : INameIcon
|
||||
{
|
||||
private static readonly ImmutableDictionary<FightProperty, Uri> PropertyIcons = new Dictionary<FightProperty, Uri>()
|
||||
{
|
||||
[FightProperty.FIGHT_PROP_SKILL_CD_MINUS_RATIO] = Web.HutaoEndpoints.StaticFile("Property", "UI_Icon_CDReduce.png").ToUri(),
|
||||
[FightProperty.FIGHT_PROP_CHARGE_EFFICIENCY] = Web.HutaoEndpoints.StaticFile("Property", "UI_Icon_ChargeEfficiency.png").ToUri(),
|
||||
[FightProperty.FIGHT_PROP_CRITICAL] = Web.HutaoEndpoints.StaticFile("Property", "UI_Icon_Critical.png").ToUri(),
|
||||
[FightProperty.FIGHT_PROP_CUR_ATTACK] = Web.HutaoEndpoints.StaticFile("Property", "UI_Icon_CurAttack.png").ToUri(),
|
||||
[FightProperty.FIGHT_PROP_CUR_DEFENSE] = Web.HutaoEndpoints.StaticFile("Property", "UI_Icon_CurDefense.png").ToUri(),
|
||||
[FightProperty.FIGHT_PROP_ELEMENT_MASTERY] = Web.HutaoEndpoints.StaticFile("Property", "UI_Icon_Element.png").ToUri(),
|
||||
[FightProperty.FIGHT_PROP_ELEC_ADD_HURT] = Web.HutaoEndpoints.StaticFile("Property", "UI_Icon_Element_Electric.png").ToUri(),
|
||||
[FightProperty.FIGHT_PROP_FIRE_ADD_HURT] = Web.HutaoEndpoints.StaticFile("Property", "UI_Icon_Element_Fire.png").ToUri(),
|
||||
[FightProperty.FIGHT_PROP_GRASS_ADD_HURT] = Web.HutaoEndpoints.StaticFile("Property", "UI_Icon_Element_Grass.png").ToUri(),
|
||||
[FightProperty.FIGHT_PROP_ICE_ADD_HURT] = Web.HutaoEndpoints.StaticFile("Property", "UI_Icon_Element_Ice.png").ToUri(),
|
||||
[FightProperty.FIGHT_PROP_ROCK_ADD_HURT] = Web.HutaoEndpoints.StaticFile("Property", "UI_Icon_Element_Rock.png").ToUri(),
|
||||
[FightProperty.FIGHT_PROP_WATER_ADD_HURT] = Web.HutaoEndpoints.StaticFile("Property", "UI_Icon_Element_Water.png").ToUri(),
|
||||
[FightProperty.FIGHT_PROP_WIND_ADD_HURT] = Web.HutaoEndpoints.StaticFile("Property", "UI_Icon_Element_Wind.png").ToUri(),
|
||||
[FightProperty.FIGHT_PROP_HEAL_ADD] = Web.HutaoEndpoints.StaticFile("Property", "UI_Icon_Heal.png").ToUri(),
|
||||
[FightProperty.FIGHT_PROP_MAX_HP] = Web.HutaoEndpoints.StaticFile("Property", "UI_Icon_MaxHp.png").ToUri(),
|
||||
[FightProperty.FIGHT_PROP_PHYSICAL_ADD_HURT] = Web.HutaoEndpoints.StaticFile("Property", "UI_Icon_PhysicalAttackUp.png").ToUri(),
|
||||
[FightProperty.FIGHT_PROP_SHIELD_COST_MINUS_RATIO] = Web.HutaoEndpoints.StaticFile("Property", "UI_Icon_ShieldCostMinus.png").ToUri(),
|
||||
}.ToImmutableDictionary();
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的角色属性值
|
||||
/// </summary>
|
||||
/// <param name="property">战斗属性</param>
|
||||
/// <param name="name">名称</param>
|
||||
/// <param name="value">白字</param>
|
||||
/// <param name="addValue">绿字</param>
|
||||
public AvatarProperty(string name, string value, string? addValue = null)
|
||||
public AvatarProperty(FightProperty property, string name, string value, string? addValue = null)
|
||||
{
|
||||
Name = name;
|
||||
Value = value;
|
||||
Icon = PropertyIcons.GetValueOrDefault(property)!;
|
||||
AddValue = addValue;
|
||||
}
|
||||
|
||||
@@ -27,6 +53,11 @@ internal sealed class AvatarProperty
|
||||
/// </summary>
|
||||
public string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 图标
|
||||
/// </summary>
|
||||
public Uri Icon { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 白字
|
||||
/// </summary>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Model.Intrinsic;
|
||||
|
||||
namespace Snap.Hutao.Model.Binding.AvatarProperty;
|
||||
|
||||
/// <summary>
|
||||
@@ -22,7 +24,7 @@ internal sealed class ReliquarySubProperty
|
||||
Score = score;
|
||||
|
||||
// only 0.25 | 0.50 | 0.75 | 1.00
|
||||
Opacity = Math.Ceiling(score / 25) / 4;
|
||||
Opacity = score == 0 ? 0.25 : Math.Ceiling(score / 25) / 4;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -25,22 +25,6 @@ internal sealed class TypedWishSummary : Wish
|
||||
get => string.Format(SH.ModelBindingGachaTypedWishSummaryMinOrangePullFormat, MinOrangePull);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 据上个五星抽数格式化
|
||||
/// </summary>
|
||||
public string LastOrangePullFormatted
|
||||
{
|
||||
get => string.Format(SH.ModelBindingGachaTypedWishSummaryLastPullFormat, LastOrangePull);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 据上个四星抽数格式化
|
||||
/// </summary>
|
||||
public string LastPurplePullFormatted
|
||||
{
|
||||
get => string.Format(SH.ModelBindingGachaTypedWishSummaryLastPullFormat, LastPurplePull);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 据上个五星抽数
|
||||
/// </summary>
|
||||
|
||||
@@ -80,6 +80,11 @@ internal sealed class SettingEntry
|
||||
/// 启动游戏 目标帧率
|
||||
/// </summary>
|
||||
public const string LaunchTargetFps = "Launch.TargetFps";
|
||||
|
||||
/// <summary>
|
||||
/// 语言
|
||||
/// </summary>
|
||||
public const string Culture = "Culture";
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -28,26 +28,28 @@ internal sealed class PropertyDescriptor : ValueConverter<PropertiesParameters,
|
||||
/// <summary>
|
||||
/// 格式化有绿字的角色属性
|
||||
/// </summary>
|
||||
/// <param name="property">战斗属性</param>
|
||||
/// <param name="name">属性名称</param>
|
||||
/// <param name="method">方法</param>
|
||||
/// <param name="baseValue">值1</param>
|
||||
/// <param name="addValue">值2</param>
|
||||
/// <returns>对2</returns>
|
||||
public static AvatarProperty FormatAvatarProperty(string name, FormatMethod method, double baseValue, double addValue)
|
||||
public static AvatarProperty FormatAvatarProperty(FightProperty property, string name, FormatMethod method, double baseValue, double addValue)
|
||||
{
|
||||
return new(name, FormatValue(method, baseValue + addValue), $"[{FormatValue(method, baseValue)}+{FormatValue(method, addValue)}]");
|
||||
return new(property, name, FormatValue(method, baseValue + addValue), $"[{FormatValue(method, baseValue)}+{FormatValue(method, addValue)}]");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 格式化无绿字的角色属性
|
||||
/// </summary>
|
||||
/// <param name="property">战斗属性</param>
|
||||
/// <param name="name">属性名称</param>
|
||||
/// <param name="method">方法</param>
|
||||
/// <param name="value">值</param>
|
||||
/// <returns>对2</returns>
|
||||
public static AvatarProperty FormatAvatarProperty(string name, FormatMethod method, double value)
|
||||
public static AvatarProperty FormatAvatarProperty(FightProperty property, string name, FormatMethod method, double value)
|
||||
{
|
||||
return new(name, FormatValue(method, value));
|
||||
return new(property, name, FormatValue(method, value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1248,6 +1248,15 @@ namespace Snap.Hutao.Resource.Localization {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 重命名数据文件夹名称失败 的本地化字符串。
|
||||
/// </summary>
|
||||
internal static string ServiceGamePackageRenameDataFolderFailed {
|
||||
get {
|
||||
return ResourceManager.GetString("ServiceGamePackageRenameDataFolderFailed", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 获取 Package Version 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -3768,6 +3777,24 @@ namespace Snap.Hutao.Resource.Localization {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 设置呈现语言 的本地化字符串。
|
||||
/// </summary>
|
||||
internal static string ViewPageSettingApperanceLanguageDescription {
|
||||
get {
|
||||
return ResourceManager.GetString("ViewPageSettingApperanceLanguageDescription", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 语言 的本地化字符串。
|
||||
/// </summary>
|
||||
internal static string ViewPageSettingApperanceLanguageHeader {
|
||||
get {
|
||||
return ResourceManager.GetString("ViewPageSettingApperanceLanguageHeader", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 更改窗体的背景材质 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -4002,6 +4029,15 @@ namespace Snap.Hutao.Resource.Localization {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 相关链接 的本地化字符串。
|
||||
/// </summary>
|
||||
internal static string ViewPageSettingLinks {
|
||||
get {
|
||||
return ResourceManager.GetString("ViewPageSettingLinks", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 重置 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -4083,6 +4119,15 @@ namespace Snap.Hutao.Resource.Localization {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 赞助我们 的本地化字符串。
|
||||
/// </summary>
|
||||
internal static string ViewPageSettingSponsorNavigate {
|
||||
get {
|
||||
return ResourceManager.GetString("ViewPageSettingSponsorNavigate", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 存储空间 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -4110,6 +4155,15 @@ namespace Snap.Hutao.Resource.Localization {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 贡献翻译 的本地化字符串。
|
||||
/// </summary>
|
||||
internal static string ViewPageSettingTranslateNavigate {
|
||||
get {
|
||||
return ResourceManager.GetString("ViewPageSettingTranslateNavigate", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 前往商店 的本地化字符串。
|
||||
/// </summary>
|
||||
|
||||
@@ -513,6 +513,9 @@
|
||||
<data name="ServiceGameLocatorUnityLogGamePathNotFound" xml:space="preserve">
|
||||
<value>在 Unity 日志文件中找不到游戏路径</value>
|
||||
</data>
|
||||
<data name="ServiceGamePackageRenameDataFolderFailed" xml:space="preserve">
|
||||
<value>重命名数据文件夹名称失败</value>
|
||||
</data>
|
||||
<data name="ServiceGamePackageRequestPackageVerion" xml:space="preserve">
|
||||
<value>获取 Package Version</value>
|
||||
</data>
|
||||
@@ -1353,6 +1356,12 @@
|
||||
<data name="ViewPageSettingApperanceHeader" xml:space="preserve">
|
||||
<value>外观</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingApperanceLanguageDescription" xml:space="preserve">
|
||||
<value>设置呈现语言</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingApperanceLanguageHeader" xml:space="preserve">
|
||||
<value>语言</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingBackdropMaterialDescription" xml:space="preserve">
|
||||
<value>更改窗体的背景材质</value>
|
||||
</data>
|
||||
@@ -1431,6 +1440,9 @@
|
||||
<data name="ViewPageSettingGameHeader" xml:space="preserve">
|
||||
<value>游戏</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingLinks" xml:space="preserve">
|
||||
<value>相关链接</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingResetAction" xml:space="preserve">
|
||||
<value>重置</value>
|
||||
</data>
|
||||
@@ -1458,6 +1470,9 @@
|
||||
<data name="ViewPageSettingSetGamePathHint" xml:space="preserve">
|
||||
<value>设置游戏路径时,请选择游戏本体(YuanShen.exe 或 GenshinImpact.exe)而不是启动器(launcher.exe)</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingSponsorNavigate" xml:space="preserve">
|
||||
<value>赞助我们</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingStorageHeader" xml:space="preserve">
|
||||
<value>存储空间</value>
|
||||
</data>
|
||||
@@ -1467,6 +1482,9 @@
|
||||
<data name="ViewPageSettingStorageSetAction" xml:space="preserve">
|
||||
<value>更改</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingTranslateNavigate" xml:space="preserve">
|
||||
<value>贡献翻译</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingUpdateCheckAction" xml:space="preserve">
|
||||
<value>前往商店</value>
|
||||
</data>
|
||||
|
||||
@@ -30,16 +30,20 @@ internal static class SummaryFightPropertyMapHelper
|
||||
AvatarProperty defProp = GetDefProperty(fightPropMap);
|
||||
|
||||
double em = fightPropMap.GetValueOrDefault(FightProperty.FIGHT_PROP_ELEMENT_MASTERY); // 28
|
||||
AvatarProperty emProp = Model.Metadata.Converter.PropertyDescriptor.FormatAvatarProperty(SH.ServiceAvatarInfoPropertyEM, FormatMethod.Integer, em);
|
||||
AvatarProperty emProp = Model.Metadata.Converter.PropertyDescriptor.FormatAvatarProperty(
|
||||
FightProperty.FIGHT_PROP_ELEMENT_MASTERY, SH.ServiceAvatarInfoPropertyEM, FormatMethod.Integer, em);
|
||||
|
||||
double critRate = fightPropMap.GetValueOrDefault(FightProperty.FIGHT_PROP_CRITICAL); // 20
|
||||
AvatarProperty critRateProp = Model.Metadata.Converter.PropertyDescriptor.FormatAvatarProperty(SH.ServiceAvatarInfoPropertyCR, FormatMethod.Percent, critRate);
|
||||
AvatarProperty critRateProp = Model.Metadata.Converter.PropertyDescriptor.FormatAvatarProperty(
|
||||
FightProperty.FIGHT_PROP_CRITICAL, SH.ServiceAvatarInfoPropertyCR, FormatMethod.Percent, critRate);
|
||||
|
||||
double critDMG = fightPropMap.GetValueOrDefault(FightProperty.FIGHT_PROP_CRITICAL_HURT); // 22
|
||||
AvatarProperty critDMGProp = Model.Metadata.Converter.PropertyDescriptor.FormatAvatarProperty(SH.ServiceAvatarInfoPropertyCDmg, FormatMethod.Percent, critDMG);
|
||||
AvatarProperty critDMGProp = Model.Metadata.Converter.PropertyDescriptor.FormatAvatarProperty(
|
||||
FightProperty.FIGHT_PROP_CRITICAL_HURT, SH.ServiceAvatarInfoPropertyCDmg, FormatMethod.Percent, critDMG);
|
||||
|
||||
double chargeEff = fightPropMap.GetValueOrDefault(FightProperty.FIGHT_PROP_CHARGE_EFFICIENCY); // 23
|
||||
AvatarProperty chargeEffProp = Model.Metadata.Converter.PropertyDescriptor.FormatAvatarProperty(SH.ServiceAvatarInfoPropertyCE, FormatMethod.Percent, chargeEff);
|
||||
AvatarProperty chargeEffProp = Model.Metadata.Converter.PropertyDescriptor.FormatAvatarProperty(
|
||||
FightProperty.FIGHT_PROP_CHARGE_EFFICIENCY, SH.ServiceAvatarInfoPropertyCE, FormatMethod.Percent, chargeEff);
|
||||
|
||||
List<AvatarProperty> properties = new(9) { hpProp, atkProp, defProp, emProp, critRateProp, critDMGProp, chargeEffProp };
|
||||
|
||||
@@ -50,7 +54,8 @@ internal static class SummaryFightPropertyMapHelper
|
||||
double value = fightPropMap[bonusProperty];
|
||||
if (value > 0)
|
||||
{
|
||||
AvatarProperty bonusProp = Model.Metadata.Converter.PropertyDescriptor.FormatAvatarProperty(bonusProperty.GetLocalizedDescription(), FormatMethod.Percent, value);
|
||||
AvatarProperty bonusProp = Model.Metadata.Converter.PropertyDescriptor.FormatAvatarProperty(
|
||||
bonusProperty, bonusProperty.GetLocalizedDescription(), FormatMethod.Percent, value);
|
||||
properties.Add(bonusProp);
|
||||
}
|
||||
}
|
||||
@@ -61,7 +66,8 @@ internal static class SummaryFightPropertyMapHelper
|
||||
if (addValue > 0)
|
||||
{
|
||||
string description = FightProperty.FIGHT_PROP_PHYSICAL_ADD_HURT.GetLocalizedDescription();
|
||||
AvatarProperty physicalBonusProp = Model.Metadata.Converter.PropertyDescriptor.FormatAvatarProperty(description, FormatMethod.Percent, addValue);
|
||||
AvatarProperty physicalBonusProp = Model.Metadata.Converter.PropertyDescriptor.FormatAvatarProperty(
|
||||
FightProperty.FIGHT_PROP_PHYSICAL_ADD_HURT, description, FormatMethod.Percent, addValue);
|
||||
properties.Add(physicalBonusProp);
|
||||
}
|
||||
}
|
||||
@@ -69,36 +75,39 @@ internal static class SummaryFightPropertyMapHelper
|
||||
return properties;
|
||||
}
|
||||
|
||||
private static AvatarProperty GetDefProperty(Dictionary<FightProperty, double> fightPropMap)
|
||||
{
|
||||
double baseDef = fightPropMap.GetValueOrDefault(FightProperty.FIGHT_PROP_BASE_DEFENSE); // 7
|
||||
double def = fightPropMap.GetValueOrDefault(FightProperty.FIGHT_PROP_DEFENSE); // 8
|
||||
double defPercent = fightPropMap.GetValueOrDefault(FightProperty.FIGHT_PROP_DEFENSE_PERCENT); // 9
|
||||
double defAdd = def + (baseDef * defPercent);
|
||||
AvatarProperty defProp = Model.Metadata.Converter.PropertyDescriptor.FormatAvatarProperty(SH.ServiceAvatarInfoPropertyDef, FormatMethod.Integer, baseDef, defAdd);
|
||||
return defProp;
|
||||
}
|
||||
|
||||
private static AvatarProperty GetAtkProperty(Dictionary<FightProperty, double> fightPropMap)
|
||||
{
|
||||
double baseAtk = fightPropMap.GetValueOrDefault(FightProperty.FIGHT_PROP_BASE_ATTACK); // 4
|
||||
double atk = fightPropMap.GetValueOrDefault(FightProperty.FIGHT_PROP_ATTACK); // 5
|
||||
double atkPrecent = fightPropMap.GetValueOrDefault(FightProperty.FIGHT_PROP_ATTACK_PERCENT); // 6
|
||||
double atkAdd = atk + (baseAtk * atkPrecent);
|
||||
AvatarProperty atkProp = Model.Metadata.Converter.PropertyDescriptor.FormatAvatarProperty(SH.ServiceAvatarInfoPropertyAtk, FormatMethod.Integer, baseAtk, atkAdd);
|
||||
return atkProp;
|
||||
}
|
||||
|
||||
private static AvatarProperty GetHpProperty(Dictionary<FightProperty, double> fightPropMap)
|
||||
{
|
||||
double baseHp = fightPropMap.GetValueOrDefault(FightProperty.FIGHT_PROP_BASE_HP); // 1
|
||||
double hp = fightPropMap.GetValueOrDefault(FightProperty.FIGHT_PROP_HP); // 2
|
||||
double hpPercent = fightPropMap.GetValueOrDefault(FightProperty.FIGHT_PROP_HP_PERCENT); // 3
|
||||
double hpAdd = hp + (baseHp * hpPercent);
|
||||
AvatarProperty hpProp = Model.Metadata.Converter.PropertyDescriptor.FormatAvatarProperty(SH.ServiceAvatarInfoPropertyHp, FormatMethod.Integer, baseHp, hpAdd);
|
||||
AvatarProperty hpProp = Model.Metadata.Converter.PropertyDescriptor.FormatAvatarProperty(
|
||||
FightProperty.FIGHT_PROP_MAX_HP, SH.ServiceAvatarInfoPropertyHp, FormatMethod.Integer, baseHp, hpAdd);
|
||||
return hpProp;
|
||||
}
|
||||
|
||||
private static AvatarProperty GetAtkProperty(Dictionary<FightProperty, double> fightPropMap)
|
||||
{
|
||||
double baseAtk = fightPropMap.GetValueOrDefault(FightProperty.FIGHT_PROP_BASE_ATTACK); // 4
|
||||
double atk = fightPropMap.GetValueOrDefault(FightProperty.FIGHT_PROP_ATTACK); // 5
|
||||
double atkPrecent = fightPropMap.GetValueOrDefault(FightProperty.FIGHT_PROP_ATTACK_PERCENT); // 6
|
||||
double atkAdd = atk + (baseAtk * atkPrecent);
|
||||
AvatarProperty atkProp = Model.Metadata.Converter.PropertyDescriptor.FormatAvatarProperty(
|
||||
FightProperty.FIGHT_PROP_CUR_ATTACK, SH.ServiceAvatarInfoPropertyAtk, FormatMethod.Integer, baseAtk, atkAdd);
|
||||
return atkProp;
|
||||
}
|
||||
|
||||
private static AvatarProperty GetDefProperty(Dictionary<FightProperty, double> fightPropMap)
|
||||
{
|
||||
double baseDef = fightPropMap.GetValueOrDefault(FightProperty.FIGHT_PROP_BASE_DEFENSE); // 7
|
||||
double def = fightPropMap.GetValueOrDefault(FightProperty.FIGHT_PROP_DEFENSE); // 8
|
||||
double defPercent = fightPropMap.GetValueOrDefault(FightProperty.FIGHT_PROP_DEFENSE_PERCENT); // 9
|
||||
double defAdd = def + (baseDef * defPercent);
|
||||
AvatarProperty defProp = Model.Metadata.Converter.PropertyDescriptor.FormatAvatarProperty(
|
||||
FightProperty.FIGHT_PROP_CUR_DEFENSE, SH.ServiceAvatarInfoPropertyDef, FormatMethod.Integer, baseDef, defAdd);
|
||||
return defProp;
|
||||
}
|
||||
|
||||
private static FightProperty GetBonusFightProperty(IDictionary<FightProperty, double> fightPropMap)
|
||||
{
|
||||
if (fightPropMap.ContainsKey(FightProperty.FIGHT_PROP_MAX_FIRE_ENERGY))
|
||||
|
||||
@@ -45,7 +45,7 @@ internal sealed class SummaryReliquaryFactory
|
||||
public PropertyReliquary CreateReliquary()
|
||||
{
|
||||
MetadataReliquary reliquary = metadataContext.Reliquaries.Single(r => r.Ids.Contains(equip.ItemId));
|
||||
List<ReliquarySubProperty> subProperty = equip.Reliquary!.AppendPropIdList.EmptyIfNull().Select(CreateSubProperty).ToList();
|
||||
List<ReliquarySubProperty> subProperty = equip.Reliquary!.AppendPropIdList.EmptyIfNull().SelectList(CreateSubProperty);
|
||||
|
||||
int affixCount = GetSecondaryAffixCount(reliquary);
|
||||
if (subProperty.Count == 0)
|
||||
@@ -67,7 +67,7 @@ internal sealed class SummaryReliquaryFactory
|
||||
List<ReliquarySubProperty> primary = new(span[..^affixCount].ToArray());
|
||||
List<ReliquarySubProperty> secondary = new(span[^affixCount..].ToArray());
|
||||
|
||||
List<ReliquarySubProperty> composed = equip.Flat.ReliquarySubstats!.Select(CreateComposedSubProperty).ToList();
|
||||
List<ReliquarySubProperty> composed = equip.Flat.ReliquarySubstats!.SelectList(CreateComposedSubProperty);
|
||||
|
||||
ReliquaryLevel relicLevel = metadataContext.ReliqueryLevels.Single(r => r.Level == equip.Reliquary!.Level && r.Quality == reliquary.RankLevel);
|
||||
FightProperty property = metadataContext.IdRelicMainPropMap[equip.Reliquary.MainPropId];
|
||||
|
||||
@@ -9,18 +9,18 @@ namespace Snap.Hutao.Service.Game.Package;
|
||||
[HighQuality]
|
||||
internal enum ItemOperationType
|
||||
{
|
||||
/// <summary>
|
||||
/// 添加
|
||||
/// </summary>
|
||||
Add,
|
||||
|
||||
/// <summary>
|
||||
/// 删除
|
||||
/// </summary>
|
||||
Remove,
|
||||
Remove = 0,
|
||||
|
||||
/// <summary>
|
||||
/// 替换
|
||||
/// </summary>
|
||||
Replace,
|
||||
Replace = 1,
|
||||
|
||||
/// <summary>
|
||||
/// 添加
|
||||
/// </summary>
|
||||
Add = 2,
|
||||
}
|
||||
@@ -48,53 +48,42 @@ internal sealed class PackageConverter
|
||||
{
|
||||
await ThreadHelper.SwitchToBackgroundAsync();
|
||||
string scatteredFilesUrl = gameResouce.Game.Latest.DecompressedPath;
|
||||
Uri pkgVersionUri = new($"{scatteredFilesUrl}/pkg_version");
|
||||
Uri pkgVersionUri = $"{scatteredFilesUrl}/pkg_version".ToUri();
|
||||
ConvertDirection direction = targetScheme.IsOversea ? ConvertDirection.ChineseToOversea : ConvertDirection.OverseaToChinese;
|
||||
|
||||
progress.Report(new(SH.ServiceGamePackageRequestPackageVerion));
|
||||
Dictionary<string, VersionItem> remoteItems = default!;
|
||||
Dictionary<string, VersionItem> remoteItems;
|
||||
try
|
||||
{
|
||||
using (Stream remoteSteam = await httpClient.GetStreamAsync(pkgVersionUri).ConfigureAwait(false))
|
||||
{
|
||||
remoteItems = await GetVersionItemsAsync(remoteSteam).ConfigureAwait(false);
|
||||
remoteItems = await GetRemoteVersionItemsAsync(remoteSteam).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
ThrowHelper.PackageConvert(SH.ServiceGamePackageRequestPackageVerionFailed, ex);
|
||||
throw ThrowHelper.PackageConvert(SH.ServiceGamePackageRequestPackageVerionFailed, ex);
|
||||
}
|
||||
|
||||
Dictionary<string, VersionItem> localItems;
|
||||
using (FileStream localSteam = File.OpenRead(Path.Combine(gameFolder, "pkg_version")))
|
||||
{
|
||||
localItems = await GetVersionItemsAsync(localSteam, direction, ConvertRemoteName).ConfigureAwait(false);
|
||||
localItems = await GetLocalVersionItemsAsync(localSteam, direction, ConvertRemoteName).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
IEnumerable<ItemOperationInfo> diffOperations = GetItemOperationInfos(remoteItems, localItems);
|
||||
IEnumerable<ItemOperationInfo> diffOperations = GetItemOperationInfos(remoteItems, localItems).OrderBy(i => (int)i.Type);
|
||||
return await ReplaceGameResourceAsync(diffOperations, gameFolder, scatteredFilesUrl, direction, progress).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查过时文件与Sdk
|
||||
/// 只在国服环境有效
|
||||
/// </summary>
|
||||
/// <param name="resource">游戏资源</param>
|
||||
/// <param name="gameFolder">游戏文件夹</param>
|
||||
/// <returns>任务</returns>
|
||||
public async Task EnsureDeprecatedFilesAndSdkAsync(GameResource resource, string gameFolder)
|
||||
{
|
||||
if (resource.DeprecatedFiles != null)
|
||||
{
|
||||
foreach (NameMd5 file in resource.DeprecatedFiles)
|
||||
{
|
||||
string filePath = Path.Combine(gameFolder, file.Name);
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
File.Move(filePath, $"{filePath}.backup");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string sdkDllBackup = Path.Combine(gameFolder, YuanShenData, "Plugins\\PCGameSDK.dll.backup");
|
||||
string sdkDll = Path.Combine(gameFolder, YuanShenData, "Plugins\\PCGameSDK.dll");
|
||||
string sdkVersionBackup = Path.Combine(gameFolder, YuanShenData, "sdk_pkg_version.backup");
|
||||
@@ -103,6 +92,7 @@ internal sealed class PackageConverter
|
||||
// Only bilibili's sdk is not null
|
||||
if (resource.Sdk != null)
|
||||
{
|
||||
// TODO: verify sdk md5
|
||||
if (File.Exists(sdkDllBackup) && File.Exists(sdkVersionBackup))
|
||||
{
|
||||
FileOperation.Move(sdkDllBackup, sdkDll, false);
|
||||
@@ -133,6 +123,15 @@ internal sealed class PackageConverter
|
||||
FileOperation.Move(sdkDll, sdkDllBackup, true);
|
||||
FileOperation.Move(sdkVersion, sdkVersionBackup, true);
|
||||
}
|
||||
|
||||
if (resource.DeprecatedFiles != null)
|
||||
{
|
||||
foreach (NameMd5 file in resource.DeprecatedFiles)
|
||||
{
|
||||
string filePath = Path.Combine(gameFolder, file.Name);
|
||||
FileOperation.Move(filePath, $"{filePath}.backup", true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string ConvertRemoteName(string remoteName, ConvertDirection direction)
|
||||
@@ -216,6 +215,7 @@ internal sealed class PackageConverter
|
||||
long totalBytesRead = 0;
|
||||
int bytesRead;
|
||||
Memory<byte> buffer = new byte[bufferSize];
|
||||
|
||||
do
|
||||
{
|
||||
bytesRead = await source.ReadAsync(buffer).ConfigureAwait(false);
|
||||
@@ -223,11 +223,6 @@ internal sealed class PackageConverter
|
||||
|
||||
totalBytesRead += bytesRead;
|
||||
progress.Report(new(name, totalBytesRead, totalBytes));
|
||||
|
||||
if (bytesRead <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (bytesRead > 0);
|
||||
}
|
||||
@@ -239,11 +234,11 @@ internal sealed class PackageConverter
|
||||
{
|
||||
RenameDataFolder(gameFolder, direction);
|
||||
}
|
||||
catch (IOException)
|
||||
catch (IOException ex)
|
||||
{
|
||||
// Access to the path is denied.
|
||||
// When user install the game in special folder like 'Program Files'
|
||||
return false;
|
||||
throw ThrowHelper.GameFileOperation(SH.ServiceGamePackageRenameDataFolderFailed, ex);
|
||||
}
|
||||
|
||||
// Cache folder
|
||||
@@ -260,20 +255,16 @@ internal sealed class PackageConverter
|
||||
|
||||
switch (info.Type)
|
||||
{
|
||||
case ItemOperationType.Add:
|
||||
await ReplaceFromCacheOrWebAsync(cacheFilePath, targetFilePath, scatteredFilesUrl, info, progress).ConfigureAwait(false);
|
||||
break;
|
||||
case ItemOperationType.Replace:
|
||||
{
|
||||
MoveToCache(moveToFilePath, targetFilePath);
|
||||
await ReplaceFromCacheOrWebAsync(cacheFilePath, targetFilePath, scatteredFilesUrl, info, progress).ConfigureAwait(false);
|
||||
break;
|
||||
}
|
||||
|
||||
case ItemOperationType.Remove:
|
||||
MoveToCache(moveToFilePath, targetFilePath);
|
||||
break;
|
||||
|
||||
case ItemOperationType.Replace:
|
||||
MoveToCache(moveToFilePath, targetFilePath);
|
||||
await ReplaceFromCacheOrWebAsync(cacheFilePath, targetFilePath, scatteredFilesUrl, info, progress).ConfigureAwait(false);
|
||||
break;
|
||||
case ItemOperationType.Add:
|
||||
await ReplaceFromCacheOrWebAsync(cacheFilePath, targetFilePath, scatteredFilesUrl, info, progress).ConfigureAwait(false);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -316,7 +307,6 @@ internal sealed class PackageConverter
|
||||
try
|
||||
{
|
||||
await CopyToWithProgressAsync(webStream, fileStream, info.Target, totalBytes, progress).ConfigureAwait(false);
|
||||
fileStream.Seek(0, SeekOrigin.Begin);
|
||||
string remoteMd5 = await Digest.GetStreamMD5Async(fileStream).ConfigureAwait(false);
|
||||
if (info.Md5 == remoteMd5.ToLowerInvariant())
|
||||
{
|
||||
@@ -359,7 +349,7 @@ internal sealed class PackageConverter
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<Dictionary<string, VersionItem>> GetVersionItemsAsync(Stream stream)
|
||||
private async Task<Dictionary<string, VersionItem>> GetRemoteVersionItemsAsync(Stream stream)
|
||||
{
|
||||
Dictionary<string, VersionItem> results = new();
|
||||
using (StreamReader reader = new(stream))
|
||||
@@ -377,7 +367,7 @@ internal sealed class PackageConverter
|
||||
return results;
|
||||
}
|
||||
|
||||
private async Task<Dictionary<string, VersionItem>> GetVersionItemsAsync(Stream stream, ConvertDirection direction, Func<string, ConvertDirection, string> nameConverter)
|
||||
private async Task<Dictionary<string, VersionItem>> GetLocalVersionItemsAsync(Stream stream, ConvertDirection direction, Func<string, ConvertDirection, string> nameConverter)
|
||||
{
|
||||
Dictionary<string, VersionItem> results = new();
|
||||
|
||||
|
||||
@@ -44,14 +44,12 @@ internal static class RegistryInterop
|
||||
Set-ItemProperty -Path '{path}' -Name '{SdkKey}' -Value $value -Force;
|
||||
""";
|
||||
|
||||
string psExecutablePath = @"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe";
|
||||
|
||||
ProcessStartInfo startInfo = new()
|
||||
{
|
||||
Arguments = command,
|
||||
WorkingDirectory = Path.GetDirectoryName(psExecutablePath),
|
||||
WorkingDirectory = Path.GetDirectoryName(PsExecutablePath),
|
||||
CreateNoWindow = true,
|
||||
FileName = psExecutablePath,
|
||||
FileName = PsExecutablePath,
|
||||
};
|
||||
|
||||
try
|
||||
|
||||
@@ -6,7 +6,8 @@ namespace Snap.Hutao.Service.User;
|
||||
/// <summary>
|
||||
/// 用户添加操作结果
|
||||
/// </summary>
|
||||
public enum UserOptionResult
|
||||
[HighQuality]
|
||||
internal enum UserOptionResult
|
||||
{
|
||||
/// <summary>
|
||||
/// 添加成功
|
||||
|
||||
@@ -160,15 +160,15 @@
|
||||
<PackageReference Include="CommunityToolkit.WinUI.Notifications" Version="7.1.2" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.UI.Behaviors" Version="7.1.2" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.UI.Controls" Version="7.1.2" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.2" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.2">
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.3" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.3">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" Version="17.5.10-alpha">
|
||||
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" Version="17.5.22">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
@@ -184,7 +184,7 @@
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="TaskScheduler" Version="2.10.1" />
|
||||
<PackageReference Include="WinUICommunity.SettingsUI" Version="3.0.2" />
|
||||
<PackageReference Include="WinUICommunity.SettingsUI" Version="3.0.4" />
|
||||
<Manifest Include="$(ApplicationManifest)" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Snap.Hutao.Control;
|
||||
using Snap.Hutao.Model.Metadata.Avatar;
|
||||
using System.Collections;
|
||||
|
||||
namespace Snap.Hutao.View.Control;
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace Snap.Hutao.View.Control;
|
||||
[HighQuality]
|
||||
internal sealed partial class SkillPivot : UserControl
|
||||
{
|
||||
private static readonly DependencyProperty SkillsProperty = Property<SkillPivot>.Depend<List<Skill>>(nameof(Skills));
|
||||
private static readonly DependencyProperty SkillsProperty = Property<SkillPivot>.Depend<IList>(nameof(Skills));
|
||||
private static readonly DependencyProperty SelectedProperty = Property<SkillPivot>.Depend<object>(nameof(Selected));
|
||||
private static readonly DependencyProperty ItemTemplateProperty = Property<SkillPivot>.Depend<DataTemplate>(nameof(ItemTemplate));
|
||||
|
||||
@@ -29,9 +29,9 @@ internal sealed partial class SkillPivot : UserControl
|
||||
/// <summary>
|
||||
/// 技能列表
|
||||
/// </summary>
|
||||
public List<Skill> Skills
|
||||
public IList Skills
|
||||
{
|
||||
get => (List<Skill>)GetValue(SkillsProperty);
|
||||
get => (IList)GetValue(SkillsProperty);
|
||||
set => SetValue(SkillsProperty, value);
|
||||
}
|
||||
|
||||
@@ -52,4 +52,4 @@ internal sealed partial class SkillPivot : UserControl
|
||||
get => (DataTemplate)GetValue(ItemTemplateProperty);
|
||||
set => SetValue(ItemTemplateProperty, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -119,11 +119,21 @@
|
||||
</Expander.Resources>
|
||||
<Expander.Header>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource SubtitleTextBlockStyle}"
|
||||
Text="{Binding Name}"/>
|
||||
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
|
||||
Text="{Binding Name}"
|
||||
TextTrimming="CharacterEllipsis"
|
||||
TextWrapping="NoWrap"/>
|
||||
<StackPanel
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Right"
|
||||
Orientation="Horizontal">
|
||||
<TextBlock
|
||||
Margin="0,0,6,0"
|
||||
VerticalAlignment="Center"
|
||||
|
||||
@@ -18,7 +18,6 @@ namespace Snap.Hutao.View.Dialog;
|
||||
internal sealed partial class CommunityGameRecordDialog : ContentDialog
|
||||
{
|
||||
private readonly IServiceScope scope;
|
||||
[SuppressMessage("", "IDE0052")]
|
||||
private MiHoYoJSInterface? jsInterface;
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -254,6 +254,7 @@
|
||||
MaxWidth="800"
|
||||
HorizontalAlignment="Left"
|
||||
Background="Transparent">
|
||||
<!-- 卡片面板 -->
|
||||
<Border Margin="16" Style="{StaticResource BorderCardStyle}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
@@ -537,41 +538,63 @@
|
||||
</ItemsControl>
|
||||
</Grid>
|
||||
</Border>
|
||||
<!-- 角色属性 -->
|
||||
<Expander
|
||||
Margin="16,0,16,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
Background="{x:Null}"
|
||||
Header="{shcm:ResourceString Name=ViewPageAvatarPropertyHeader}">
|
||||
<ItemsControl ItemsSource="{Binding SelectedAvatar.Properties}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<wsc:Setting
|
||||
Margin="0,2,0,0"
|
||||
BorderBrush="{x:Null}"
|
||||
BorderThickness="0"
|
||||
Header="{Binding Key}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="100"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock
|
||||
Grid.Column="0"
|
||||
HorizontalAlignment="Right"
|
||||
Text="{Binding Value1}"/>
|
||||
<TextBlock
|
||||
Grid.Column="1"
|
||||
Margin="6,0,0,0"
|
||||
HorizontalAlignment="Left"
|
||||
Foreground="{StaticResource AvatarPropertyAddValueBrush}"
|
||||
Text="{Binding Value2}"/>
|
||||
</Grid>
|
||||
</wsc:Setting>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
<Border Background="{ThemeResource CardBackgroundFillColorSecondaryBrush}" CornerRadius="0,0,4,4">
|
||||
<ItemsControl Margin="0,0,0,-2" ItemsSource="{Binding SelectedAvatar.Properties}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border Margin="16,8,16,0">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition Width="108"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition Height="auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<shci:MonoChrome
|
||||
Width="16"
|
||||
Height="16"
|
||||
Source="{Binding Icon}"/>
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Margin="16,0,0,0"
|
||||
HorizontalAlignment="Left"
|
||||
Text="{Binding Name}"/>
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="2"
|
||||
HorizontalAlignment="Right"
|
||||
Text="{Binding Value}"/>
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="3"
|
||||
Margin="8,0,0,0"
|
||||
HorizontalAlignment="Left"
|
||||
Foreground="{StaticResource AvatarPropertyAddValueBrush}"
|
||||
Text="{Binding AddValue}"/>
|
||||
<MenuFlyoutSeparator
|
||||
Grid.Row="1"
|
||||
Grid.ColumnSpan="4"
|
||||
Margin="4,8,4,0"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</Border>
|
||||
</Expander>
|
||||
<!-- 圣遗物 -->
|
||||
<ItemsControl Margin="16,16,16,0" ItemsSource="{Binding SelectedAvatar.Reliquaries}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
@@ -581,7 +604,7 @@
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Stretch">
|
||||
<Expander.Header>
|
||||
<Grid Margin="0,16">
|
||||
<Grid Margin="0,8,8,8">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition/>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
x:Class="Snap.Hutao.View.Page.SettingPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:cwuc="using:CommunityToolkit.WinUI.UI.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:shc="using:Snap.Hutao.Control"
|
||||
@@ -16,7 +17,7 @@
|
||||
<Setter Property="MinWidth" Value="160"/>
|
||||
</Style>
|
||||
<Style BasedOn="{StaticResource HyperlinkButtonStyle}" TargetType="HyperlinkButton">
|
||||
<Setter Property="MinWidth" Value="160"/>
|
||||
<Setter Property="MinWidth" Value="120"/>
|
||||
<Setter Property="CornerRadius" Value="{StaticResource ControlCornerRadius}"/>
|
||||
</Style>
|
||||
<Style BasedOn="{StaticResource DefaultComboBoxStyle}" TargetType="ComboBox">
|
||||
@@ -46,8 +47,39 @@
|
||||
</Border>
|
||||
|
||||
<Grid Grid.Column="1" Margin="16,0,0,0">
|
||||
<TextBlock Text="Copyright © 2022 - 2023 DGP Studio. All Rights Reserved." TextWrapping="Wrap"/>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition Height="auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Text="Copyright © 2022 - 2023 DGP Studio. All Rights Reserved."
|
||||
TextWrapping="Wrap"/>
|
||||
|
||||
<StackPanel
|
||||
Grid.Row="1"
|
||||
VerticalAlignment="Bottom"
|
||||
Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center" Text="{shcm:ResourceString Name=ViewPageSettingLinks}"/>
|
||||
<HyperlinkButton
|
||||
Margin="12,0,0,0"
|
||||
Command="{Binding UpdateCheckCommand}"
|
||||
Content="{shcm:ResourceString Name=ViewPageSettingUpdateCheckAction}"/>
|
||||
<HyperlinkButton
|
||||
Margin="12,0,0,0"
|
||||
Content="{shcm:ResourceString Name=ViewPageSettingFeedbackNavigate}"
|
||||
NavigateUri="{StaticResource DocumentLink_BugReport}"/>
|
||||
<HyperlinkButton
|
||||
Margin="12,0,0,0"
|
||||
Content="{shcm:ResourceString Name=ViewPageSettingTranslateNavigate}"
|
||||
NavigateUri="{StaticResource DocumentLink_Translate}"/>
|
||||
<HyperlinkButton
|
||||
Margin="12,0,0,0"
|
||||
Content="{shcm:ResourceString Name=ViewPageSettingSponsorNavigate}"
|
||||
NavigateUri="{StaticResource Sponsor_Afadian}"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
<wsc:Setting
|
||||
Description="{Binding AppVersion}"
|
||||
@@ -65,23 +97,19 @@
|
||||
Description="{Binding WebView2Version}"
|
||||
Header="{shcm:ResourceString Name=ViewPageSettingWebview2Header}"
|
||||
Icon=""/>
|
||||
<wsc:Setting
|
||||
Description="{shcm:ResourceString Name=ViewPageSettingFeedbackDescription}"
|
||||
Header="{shcm:ResourceString Name=ViewPageSettingFeedbackHeader}"
|
||||
Icon="">
|
||||
<HyperlinkButton Content="{shcm:ResourceString Name=ViewPageSettingFeedbackNavigate}" NavigateUri="{StaticResource DocumentLink_BugReport}"/>
|
||||
</wsc:Setting>
|
||||
<wsc:Setting
|
||||
Description="{shcm:ResourceString Name=ViewPageSettingUpdateCheckDescription}"
|
||||
Header="{shcm:ResourceString Name=ViewPageSettingUpdateCheckHeader}"
|
||||
Icon="">
|
||||
<wsc:Setting.ActionContent>
|
||||
<HyperlinkButton Command="{Binding UpdateCheckCommand}" Content="{shcm:ResourceString Name=ViewPageSettingUpdateCheckAction}"/>
|
||||
</wsc:Setting.ActionContent>
|
||||
</wsc:Setting>
|
||||
</wsc:SettingsGroup>
|
||||
|
||||
<wsc:SettingsGroup Header="{shcm:ResourceString Name=ViewPageSettingApperanceHeader}">
|
||||
<wsc:Setting
|
||||
Description="{shcm:ResourceString Name=ViewPageSettingApperanceLanguageDescription}"
|
||||
Header="{shcm:ResourceString Name=ViewPageSettingApperanceLanguageHeader}"
|
||||
Icon="">
|
||||
<ComboBox
|
||||
MinWidth="180"
|
||||
DisplayMemberPath="Name"
|
||||
ItemsSource="{Binding Cultures}"
|
||||
SelectedItem="{Binding SelectedCulture, Mode=TwoWay}"/>
|
||||
</wsc:Setting>
|
||||
<wsc:Setting
|
||||
Description="{shcm:ResourceString Name=ViewPageSettingBackdropMaterialDescription}"
|
||||
Header="{shcm:ResourceString Name=ViewPageSettingBackdropMaterialHeader}"
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
Grid.Row="1"
|
||||
DisplayMode="Inline"
|
||||
IsPaneOpen="True"
|
||||
OpenPaneLength="96"
|
||||
OpenPaneLength="120"
|
||||
PaneBackground="Transparent"
|
||||
Visibility="{Binding SpiralAbyssView, Converter={StaticResource EmptyObjectToVisibilityConverter}}">
|
||||
<SplitView.Pane>
|
||||
|
||||
@@ -32,6 +32,16 @@
|
||||
<wsc:Setting Header="DownloadStaticFileTest">
|
||||
<Button Command="{Binding DownloadStaticFileCommand}" Content="Download"/>
|
||||
</wsc:Setting>
|
||||
|
||||
<wsc:Setting Header="RestartTest">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<ToggleSwitch Name="ElevatedSwitch" Style="{StaticResource DefaultToggleSwitchStyle}"/>
|
||||
<Button
|
||||
Command="{Binding RestartAppCommand}"
|
||||
CommandParameter="{Binding ElementName=ElevatedSwitch, Path=IsOn}"
|
||||
Content="Restart"/>
|
||||
</StackPanel>
|
||||
</wsc:Setting>
|
||||
</wsc:SettingsGroup>
|
||||
</ScrollViewer>
|
||||
</shc:ScopedPage>
|
||||
|
||||
@@ -20,11 +20,27 @@
|
||||
<StackPanel>
|
||||
<Button
|
||||
Grid.Column="2"
|
||||
MaxHeight="40"
|
||||
Margin="4,4,4,6"
|
||||
Background="Transparent"
|
||||
BorderBrush="{x:Null}">
|
||||
<Button.Resources>
|
||||
<shc:BindingProxy x:Key="ViewModelBindingProxy" DataContext="{Binding}"/>
|
||||
|
||||
<StaticResource x:Key="ButtonBackground" ResourceKey="NavigationViewItemBackground"/>
|
||||
<StaticResource x:Key="ButtonBackgroundDisabled" ResourceKey="NavigationViewItemBackgroundDisabled"/>
|
||||
<StaticResource x:Key="ButtonBackgroundPointerOver" ResourceKey="NavigationViewItemBackgroundPointerOver"/>
|
||||
<StaticResource x:Key="ButtonBackgroundPressed" ResourceKey="NavigationViewItemBackgroundPressed"/>
|
||||
|
||||
<StaticResource x:Key="ButtonBorderBrush" ResourceKey="NavigationViewItemBorderBrush"/>
|
||||
<StaticResource x:Key="ButtonBorderBrushDisabled" ResourceKey="NavigationViewItemBorderBrushDisabled"/>
|
||||
<StaticResource x:Key="ButtonBorderBrushPointerOver" ResourceKey="NavigationViewItemBorderBrushPointerOver"/>
|
||||
<StaticResource x:Key="ButtonBorderBrushPressed" ResourceKey="NavigationViewItemBorderBrushPressed"/>
|
||||
|
||||
<StaticResource x:Key="ButtonForeground" ResourceKey="NavigationViewItemForeground"/>
|
||||
<StaticResource x:Key="ButtonForegroundDisabled" ResourceKey="NavigationViewItemForegroundDisabled"/>
|
||||
<StaticResource x:Key="ButtonForegroundPointerOver" ResourceKey="NavigationViewItemForegroundPointerOver"/>
|
||||
<StaticResource x:Key="ButtonForegroundPressed" ResourceKey="NavigationViewItemForegroundPressed"/>
|
||||
</Button.Resources>
|
||||
<Button.Content>
|
||||
<Grid>
|
||||
@@ -217,6 +233,7 @@
|
||||
<Setter Property="Padding" Value="0"/>
|
||||
<Setter Property="HorizontalAlignment" Value="Stretch"/>
|
||||
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
|
||||
<Setter Property="BorderThickness" Value="0"/>
|
||||
</Style>
|
||||
</Button.Style>
|
||||
</Button>
|
||||
|
||||
@@ -42,18 +42,20 @@
|
||||
</ItemsControl.ItemContainerTransitions>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<StackPanel Margin="0,8,0,0">
|
||||
<TextBlock Text="{Binding DisplayName}"/>
|
||||
<ProgressBar
|
||||
Width="240"
|
||||
Margin="0,4,0,0"
|
||||
Maximum="1"
|
||||
Value="{Binding ProgressValue}"/>
|
||||
<TextBlock
|
||||
Opacity="0.6"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{Binding Description}"/>
|
||||
</StackPanel>
|
||||
<Border Style="{StaticResource BorderCardStyle}">
|
||||
<StackPanel Margin="0,8,0,0">
|
||||
<TextBlock Text="{Binding DisplayName}"/>
|
||||
<ProgressBar
|
||||
Width="240"
|
||||
Margin="0,4,0,0"
|
||||
Maximum="1"
|
||||
Value="{Binding ProgressValue}"/>
|
||||
<TextBlock
|
||||
Opacity="0.6"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{Binding Description}"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
|
||||
@@ -5,6 +5,7 @@ using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Windows.AppLifecycle;
|
||||
using Snap.Hutao.Model.Entity.Database;
|
||||
using Snap.Hutao.Service.Abstraction;
|
||||
using Windows.Storage;
|
||||
@@ -65,9 +66,7 @@ internal sealed class ExperimentalFeaturesViewModel : ObservableObject
|
||||
{
|
||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
await appDbContext.Users.ExecuteDeleteAsync().ConfigureAwait(false);
|
||||
|
||||
IInfoBarService infoBarService = scope.ServiceProvider.GetRequiredService<IInfoBarService>();
|
||||
infoBarService.Success(SH.ViewModelExperimentalDeleteUserSuccess);
|
||||
AppInstance.Restart(string.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Windows.AppLifecycle;
|
||||
using Snap.Hutao.Core.Database;
|
||||
using Snap.Hutao.Core.IO;
|
||||
using Snap.Hutao.Core.Setting;
|
||||
@@ -17,6 +18,7 @@ using Snap.Hutao.Service.GachaLog.QueryProvider;
|
||||
using Snap.Hutao.Service.Game;
|
||||
using Snap.Hutao.Service.Game.Locator;
|
||||
using Snap.Hutao.View.Dialog;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using Windows.Storage.Pickers;
|
||||
|
||||
@@ -42,9 +44,18 @@ internal sealed class SettingViewModel : Abstraction.ViewModel
|
||||
new("MicaAlt", BackdropType.MicaAlt),
|
||||
};
|
||||
|
||||
private readonly List<NameValue<string>> cultures = new()
|
||||
{
|
||||
new("简体中文", "zh-CN"),
|
||||
new("繁體中文", "zh-TW"),
|
||||
new("English (United States)", "en-US"),
|
||||
new("한국인", "ko-KR"),
|
||||
};
|
||||
|
||||
private bool isEmptyHistoryWishVisible;
|
||||
private string gamePath;
|
||||
private NameValue<BackdropType> selectedBackdropType;
|
||||
private NameValue<string>? selectedCulture;
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的设置视图模型
|
||||
@@ -61,6 +72,9 @@ internal sealed class SettingViewModel : Abstraction.ViewModel
|
||||
isEmptyHistoryWishVisibleEntry = appDbContext.Settings.SingleOrAdd(SettingEntry.IsEmptyHistoryWishVisible, Core.StringLiterals.False);
|
||||
IsEmptyHistoryWishVisible = bool.Parse(isEmptyHistoryWishVisibleEntry.Value!);
|
||||
|
||||
string? cultureName = appDbContext.Settings.SingleOrAdd(SettingEntry.Culture, CultureInfo.CurrentCulture.Name).Value;
|
||||
selectedCulture = cultures.FirstOrDefault(c => c.Value == cultureName);
|
||||
|
||||
selectedBackdropTypeEntry = appDbContext.Settings.SingleOrAdd(SettingEntry.SystemBackdropType, BackdropType.Mica.ToString());
|
||||
BackdropType type = Enum.Parse<BackdropType>(selectedBackdropTypeEntry.Value!);
|
||||
|
||||
@@ -154,6 +168,29 @@ internal sealed class SettingViewModel : Abstraction.ViewModel
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 语言
|
||||
/// </summary>
|
||||
public List<NameValue<string>> Cultures { get => cultures; }
|
||||
|
||||
/// <summary>
|
||||
/// 选中的语言
|
||||
/// </summary>
|
||||
public NameValue<string>? SelectedCulture
|
||||
{
|
||||
get => selectedCulture;
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref selectedCulture, value))
|
||||
{
|
||||
SettingEntry entry = appDbContext.Settings.SingleOrAdd(SettingEntry.Culture, CultureInfo.CurrentCulture.Name);
|
||||
entry.Value = selectedCulture.Value;
|
||||
appDbContext.Settings.UpdateAndSave(entry);
|
||||
AppInstance.Restart(string.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 实验性功能
|
||||
/// </summary>
|
||||
@@ -271,6 +308,6 @@ internal sealed class SettingViewModel : Abstraction.ViewModel
|
||||
private void ResetStaticResource()
|
||||
{
|
||||
StaticResource.UnfulfillAllContracts();
|
||||
serviceProvider.GetRequiredService<IInfoBarService>().Success(SH.ViewPageSettingResetSuccessMessage);
|
||||
AppInstance.Restart(string.Empty);
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Windows.AppLifecycle;
|
||||
using Snap.Hutao.Core.IO;
|
||||
using Snap.Hutao.Core.IO.Bits;
|
||||
using Snap.Hutao.View.Dialog;
|
||||
@@ -29,6 +30,7 @@ internal sealed class TestViewModel : Abstraction.ViewModel
|
||||
ShowCommunityGameRecordDialogCommand = new AsyncRelayCommand(ShowCommunityGameRecordDialogAsync);
|
||||
ShowAdoptCalculatorDialogCommand = new AsyncRelayCommand(ShowAdoptCalculatorDialogAsync);
|
||||
DownloadStaticFileCommand = new AsyncRelayCommand(DownloadStaticFileAsync);
|
||||
RestartAppCommand = new RelayCommand<bool>(RestartApp);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -46,6 +48,11 @@ internal sealed class TestViewModel : Abstraction.ViewModel
|
||||
/// </summary>
|
||||
public ICommand DownloadStaticFileCommand { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 重启命令
|
||||
/// </summary>
|
||||
public ICommand RestartAppCommand { get; }
|
||||
|
||||
private async Task ShowCommunityGameRecordDialogAsync()
|
||||
{
|
||||
// ContentDialog must be created by main thread.
|
||||
@@ -80,4 +87,9 @@ internal sealed class TestViewModel : Abstraction.ViewModel
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RestartApp(bool elevated)
|
||||
{
|
||||
AppInstance.Restart(string.Empty);
|
||||
}
|
||||
}
|
||||
@@ -57,12 +57,11 @@ internal sealed class WelcomeViewModel : ObservableObject
|
||||
|
||||
// Cancel all previous created jobs
|
||||
serviceProvider.GetRequiredService<BitsManager>().CancelAllJobs();
|
||||
await Task.WhenAll(downloadSummaries.Select(async downloadTask =>
|
||||
await Parallel.ForEachAsync(downloadSummaries, async (summary, token) =>
|
||||
{
|
||||
await downloadTask.DownloadAndExtractAsync().ConfigureAwait(false);
|
||||
await ThreadHelper.SwitchToMainThreadAsync();
|
||||
DownloadSummaries.Remove(downloadTask);
|
||||
})).ConfigureAwait(true);
|
||||
await summary.DownloadAndExtractAsync().ConfigureAwait(false);
|
||||
ThreadHelper.InvokeOnMainThread(() => DownloadSummaries.Remove(summary));
|
||||
}).ConfigureAwait(true);
|
||||
|
||||
serviceProvider.GetRequiredService<IMessenger>().Send(new Message.WelcomeStateCompleteMessage());
|
||||
StaticResource.FulfillAllContracts();
|
||||
@@ -123,7 +122,7 @@ internal sealed class WelcomeViewModel : ObservableObject
|
||||
/// 下载信息
|
||||
/// </summary>
|
||||
[SuppressMessage("", "CA1067")]
|
||||
public class DownloadSummary : ObservableObject, IEquatable<DownloadSummary>
|
||||
internal sealed class DownloadSummary : ObservableObject, IEquatable<DownloadSummary>
|
||||
{
|
||||
private readonly IServiceProvider serviceProvider;
|
||||
private readonly BitsManager bitsManager;
|
||||
|
||||
@@ -202,6 +202,7 @@ internal class MiHoYoJSInterface
|
||||
await userService.RefreshCookieTokenAsync(user).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
await ThreadHelper.SwitchToMainThreadAsync();
|
||||
webView.SetCookie(user.CookieToken, user.Ltoken);
|
||||
return new() { Data = new() { [Cookie.COOKIE_TOKEN] = user.CookieToken![Cookie.COOKIE_TOKEN] } };
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ internal sealed class Flat
|
||||
/// List of Artifact Substats
|
||||
/// </summary>
|
||||
[JsonPropertyName("reliquarySubstats")]
|
||||
public IList<ReliquarySubstat>? ReliquarySubstats { get; set; }
|
||||
public List<ReliquarySubstat>? ReliquarySubstats { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 物品类型
|
||||
|
||||
@@ -42,9 +42,7 @@ internal static class StructMarshal
|
||||
public static unsafe Windows.UI.Color Color(uint value)
|
||||
{
|
||||
Unsafe.SkipInit(out Windows.UI.Color color);
|
||||
uint reversed = BinaryPrimitives.ReverseEndianness(value);
|
||||
Unsafe.WriteUnaligned(&color, reversed);
|
||||
|
||||
*(uint*)&color = BinaryPrimitives.ReverseEndianness(value); // Unsafe.WriteUnaligned(&color, reversed);
|
||||
return color;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user