diff --git a/src/Snap.Hutao/Snap.Hutao/App.xaml.cs b/src/Snap.Hutao/Snap.Hutao/App.xaml.cs
index b2bc6c45..352a682c 100644
--- a/src/Snap.Hutao/Snap.Hutao/App.xaml.cs
+++ b/src/Snap.Hutao/Snap.Hutao/App.xaml.cs
@@ -45,12 +45,19 @@ public partial class App : Application
public static Window? Window { get => window; set => window = value; }
///
- public static new App Current => (App)Application.Current;
+ public static new App Current
+ {
+ get => (App)Application.Current;
+ }
///
///
///
- public static Windows.Storage.ApplicationData AppData => Windows.Storage.ApplicationData.Current;
+ [SuppressMessage("", "CA1822")]
+ public Windows.Storage.ApplicationData AppData
+ {
+ get => Windows.Storage.ApplicationData.Current;
+ }
///
/// Invoked when the application is launched.
@@ -60,12 +67,13 @@ public partial class App : Application
protected override async void OnLaunched(LaunchActivatedEventArgs args)
{
AppActivationArguments activatedEventArgs = AppInstance.GetCurrent().GetActivatedEventArgs();
- AppInstance mainInstance = AppInstance.FindOrRegisterForKey("main");
+ AppInstance firstInstance = AppInstance.FindOrRegisterForKey("main");
+ firstInstance.Activated += OnActivated;
- if (!mainInstance.IsCurrent)
+ if (!firstInstance.IsCurrent)
{
// Redirect the activation (and args) to the "main" instance, and exit.
- await mainInstance.RedirectActivationToAsync(activatedEventArgs);
+ await firstInstance.RedirectActivationToAsync(activatedEventArgs);
Process.GetCurrentProcess().Kill();
}
else
@@ -73,11 +81,6 @@ public partial class App : Application
Window = Ioc.Default.GetRequiredService();
Window.Activate();
- if (activatedEventArgs.TryGetProtocolActivatedUri(out Uri? uri))
- {
- Ioc.Default.GetRequiredService().Information(uri.ToString());
- }
-
logger.LogInformation(EventIds.CommonLog, "Cache folder : {folder}", AppData.TemporaryFolder.Path);
Ioc.Default
@@ -117,6 +120,14 @@ public partial class App : Application
logger.LogError(EventIds.UnhandledException, e.Exception, "未经处理的异常");
}
+ private void OnActivated(object? sender, AppActivationArguments args)
+ {
+ if (args.TryGetProtocolActivatedUri(out Uri? uri))
+ {
+ Ioc.Default.GetRequiredService().Information(uri.ToString());
+ }
+ }
+
private void XamlBindingFailed(object sender, BindingFailedEventArgs e)
{
logger.LogCritical(EventIds.XamlBindingError, "XAML绑定失败: {message}", e.Message);
diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Image/CachedImage.cs b/src/Snap.Hutao/Snap.Hutao/Control/Image/CachedImage.cs
index 896cb4cb..e9943272 100644
--- a/src/Snap.Hutao/Snap.Hutao/Control/Image/CachedImage.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Control/Image/CachedImage.cs
@@ -31,6 +31,7 @@ public class CachedImage : ImageEx
try
{
+ Verify.Operation(imageUri.Host != string.Empty, "可能是空绑定产生的 [ms-appx:///]");
StorageFile file = await imageCache.GetFileFromCacheAsync(imageUri);
// check token state to determine whether the operation should be canceled.
diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Caching/CacheBase.cs b/src/Snap.Hutao/Snap.Hutao/Core/Caching/CacheBase.cs
index e04dff26..83d5c661 100644
--- a/src/Snap.Hutao/Snap.Hutao/Core/Caching/CacheBase.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Core/Caching/CacheBase.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using Snap.Hutao.Core.Logging;
+using Snap.Hutao.Extension;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@@ -236,25 +237,17 @@ public abstract class CacheBase
return;
}
- await cacheFolderSemaphore.WaitAsync().ConfigureAwait(false);
-
- baseFolder ??= ApplicationData.Current.TemporaryFolder;
-
- if (string.IsNullOrWhiteSpace(cacheFolderName))
+ using (await cacheFolderSemaphore.EnterAsync().ConfigureAwait(false))
{
- cacheFolderName = GetType().Name;
- }
+ baseFolder ??= ApplicationData.Current.TemporaryFolder;
- try
- {
- cacheFolder = await baseFolder
- .CreateFolderAsync(cacheFolderName, CreationCollisionOption.OpenIfExists)
- .AsTask()
- .ConfigureAwait(false);
- }
- finally
- {
- cacheFolderSemaphore.Release();
+ if (string.IsNullOrWhiteSpace(cacheFolderName))
+ {
+ cacheFolderName = GetType().Name;
+ }
+
+ cacheFolder = await baseFolder.CreateFolderAsync(cacheFolderName, CreationCollisionOption.OpenIfExists)
+ .AsTask().ConfigureAwait(false);
}
}
diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Caching/IImageCache.cs b/src/Snap.Hutao/Snap.Hutao/Core/Caching/IImageCache.cs
index 41c3c549..77dd6a93 100644
--- a/src/Snap.Hutao/Snap.Hutao/Core/Caching/IImageCache.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Core/Caching/IImageCache.cs
@@ -1,7 +1,6 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
-using Microsoft.UI.Xaml.Media.Imaging;
using System.Collections.Generic;
using Windows.Storage;
diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Logging/DatebaseLoggerProvider.cs b/src/Snap.Hutao/Snap.Hutao/Core/Logging/DatebaseLoggerProvider.cs
index 7e566002..87dc972e 100644
--- a/src/Snap.Hutao/Snap.Hutao/Core/Logging/DatebaseLoggerProvider.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Core/Logging/DatebaseLoggerProvider.cs
@@ -13,11 +13,12 @@ namespace Snap.Hutao.Core.Logging;
/// The provider for the .
///
[ProviderAlias("Database")]
-public class DatebaseLoggerProvider : ILoggerProvider
+public sealed class DatebaseLoggerProvider : ILoggerProvider
{
+ private static readonly object LogDbContextLock = new();
+
// the provider is created per logger, we don't want to create to much
private static volatile LogDbContext? logDbContext;
- private static readonly object logDbContextLock = new();
private static LogDbContext LogDbContext
{
@@ -25,7 +26,7 @@ public class DatebaseLoggerProvider : ILoggerProvider
{
if (logDbContext == null)
{
- lock (logDbContextLock)
+ lock (LogDbContextLock)
{
// prevent re-entry call
if (logDbContext == null)
@@ -34,7 +35,7 @@ public class DatebaseLoggerProvider : ILoggerProvider
logDbContext = LogDbContext.Create($"Data Source={myDocument.Locate("Log.db")}");
if (logDbContext.Database.GetPendingMigrations().Any())
{
- Debug.WriteLine("Performing LogDbContext Migrations");
+ Debug.WriteLine("[Debug] Performing LogDbContext Migrations");
logDbContext.Database.Migrate();
}
@@ -51,11 +52,12 @@ public class DatebaseLoggerProvider : ILoggerProvider
///
public ILogger CreateLogger(string name)
{
- return new DatebaseLogger(name, LogDbContext, logDbContextLock);
+ return new DatebaseLogger(name, LogDbContext, LogDbContextLock);
}
///
public void Dispose()
{
+ LogDbContext.Dispose();
}
}
diff --git a/src/Snap.Hutao/Snap.Hutao/Extension/SemaphoreSlimExtensions.cs b/src/Snap.Hutao/Snap.Hutao/Extension/SemaphoreSlimExtensions.cs
new file mode 100644
index 00000000..b42b1315
--- /dev/null
+++ b/src/Snap.Hutao/Snap.Hutao/Extension/SemaphoreSlimExtensions.cs
@@ -0,0 +1,36 @@
+// Copyright (c) DGP Studio. All rights reserved.
+// Licensed under the MIT license.
+
+namespace Snap.Hutao.Extension;
+
+///
+/// 信号量扩展
+///
+public static class SemaphoreSlimExtensions
+{
+ ///
+ /// 异步进入信号量
+ ///
+ /// 信号量
+ /// 可释放的对象,用于释放信号量
+ public static async Task EnterAsync(this SemaphoreSlim semaphoreSlim)
+ {
+ await semaphoreSlim.WaitAsync();
+ return new SemaphoreSlimReleaser(semaphoreSlim);
+ }
+
+ private struct SemaphoreSlimReleaser : IDisposable
+ {
+ private readonly SemaphoreSlim semaphoreSlim;
+
+ public SemaphoreSlimReleaser(SemaphoreSlim semaphoreSlim)
+ {
+ this.semaphoreSlim = semaphoreSlim;
+ }
+
+ public void Dispose()
+ {
+ semaphoreSlim.Release();
+ }
+ }
+}
diff --git a/src/Snap.Hutao/Snap.Hutao/IocConfiguration.cs b/src/Snap.Hutao/Snap.Hutao/IocConfiguration.cs
index 8e7857dc..98338f20 100644
--- a/src/Snap.Hutao/Snap.Hutao/IocConfiguration.cs
+++ b/src/Snap.Hutao/Snap.Hutao/IocConfiguration.cs
@@ -51,7 +51,7 @@ internal static class IocConfiguration
{
if (context.Database.GetPendingMigrations().Any())
{
- Debug.WriteLine("Performing AppDbContext Migrations");
+ Debug.WriteLine("[Debug] Performing AppDbContext Migrations");
context.Database.Migrate();
}
}
diff --git a/src/Snap.Hutao/Snap.Hutao/IocHttpClientConfiguration.cs b/src/Snap.Hutao/Snap.Hutao/IocHttpClientConfiguration.cs
index e26699ff..d4cbb5c4 100644
--- a/src/Snap.Hutao/Snap.Hutao/IocHttpClientConfiguration.cs
+++ b/src/Snap.Hutao/Snap.Hutao/IocHttpClientConfiguration.cs
@@ -2,6 +2,7 @@
// Licensed under the MIT license.
using Microsoft.Extensions.DependencyInjection;
+using Snap.Hutao.Core.Caching;
using Snap.Hutao.Service.Metadata;
using Snap.Hutao.Web.Enka;
using Snap.Hutao.Web.Hoyolab.Bbs.User;
@@ -29,7 +30,7 @@ internal static class IocHttpClientConfiguration
{
// services
services.AddHttpClient(DefaultConfiguration);
- // services.AddHttpClient(DefaultConfiguration);
+ services.AddHttpClient(DefaultConfiguration).ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler() { MaxConnectionsPerServer = 20 });
// normal clients
services.AddHttpClient(DefaultConfiguration);
diff --git a/src/Snap.Hutao/Snap.Hutao/MainWindow.xaml.cs b/src/Snap.Hutao/Snap.Hutao/MainWindow.xaml.cs
index d276af60..aa9e9787 100644
--- a/src/Snap.Hutao/Snap.Hutao/MainWindow.xaml.cs
+++ b/src/Snap.Hutao/Snap.Hutao/MainWindow.xaml.cs
@@ -7,7 +7,6 @@ using Snap.Hutao.Control.HostBackdrop;
using Snap.Hutao.Core.Logging;
using Snap.Hutao.Core.Setting;
using Snap.Hutao.Core.Win32;
-using System.Runtime.InteropServices;
using WinRT.Interop;
namespace Snap.Hutao;
diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Annotation/FormatMethod.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Annotation/FormatMethod.cs
index 560ccd99..e54ca6a5 100644
--- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Annotation/FormatMethod.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Annotation/FormatMethod.cs
@@ -1,4 +1,7 @@
-namespace Snap.Hutao.Model.Metadata.Annotation;
+// Copyright (c) DGP Studio. All rights reserved.
+// Licensed under the MIT license.
+
+namespace Snap.Hutao.Model.Metadata.Annotation;
///
/// 格式化方法
diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/DescParam.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/DescParam.cs
index 52157c4b..983fca33 100644
--- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/DescParam.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/DescParam.cs
@@ -13,10 +13,10 @@ public class DescParam
///
/// 描述
///
- public IEnumerable Descriptions { get; set; } = default!;
+ public IList Descriptions { get; set; } = default!;
///
/// 参数
///
- public IEnumerable> Parameters { get; set; } = default!;
-}
\ No newline at end of file
+ public IList> Parameters { get; set; } = default!;
+}
diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/SkillDepot.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/SkillDepot.cs
index a61e6604..c2570364 100644
--- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/SkillDepot.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/SkillDepot.cs
@@ -2,6 +2,7 @@
// Licensed under the MIT license.
using System.Collections.Generic;
+using System.Linq;
namespace Snap.Hutao.Model.Metadata.Avatar;
@@ -13,7 +14,7 @@ public class SkillDepot
///
/// 技能天赋
///
- public IEnumerable Skills { get; set; } = default!;
+ public IList Skills { get; set; } = default!;
///
/// 大招
@@ -23,10 +24,30 @@ public class SkillDepot
///
/// 固有天赋
///
- public IEnumerable Inherents { get; set; } = default!;
+ public IList Inherents { get; set; } = default!;
+
+ ///
+ /// 全部天赋
+ ///
+ public IList CompositeSkills => GetCompositeSkills().ToList();
///
/// 命之座
///
- public IEnumerable Talents { get; set; } = default!;
+ public IList Talents { get; set; } = default!;
+
+ private IEnumerable GetCompositeSkills()
+ {
+ foreach (ProudableSkill skill in Skills)
+ {
+ yield return skill;
+ }
+
+ yield return EnergySkill;
+
+ foreach (ProudableSkill skill in Inherents)
+ {
+ yield return skill;
+ }
+ }
}
diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/AvatarIconConverter.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/AvatarIconConverter.cs
index c3fa3dee..57055dd6 100644
--- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/AvatarIconConverter.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/AvatarIconConverter.cs
@@ -23,4 +23,4 @@ internal class AvatarIconConverter : IValueConverter
{
throw Must.NeverHappen();
}
-}
+}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/DescParamDescriptor.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/DescParamDescriptor.cs
index 08ec486d..36ec798d 100644
--- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/DescParamDescriptor.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/DescParamDescriptor.cs
@@ -17,25 +17,26 @@ internal class DescParamDescriptor : IValueConverter
///
public object Convert(object value, Type targetType, object parameter, string language)
{
- DescParam descParam = (DescParam)value;
- IEnumerable parsedDescriptions = descParam.Descriptions.Select(desc =>
- {
- string[] parts = desc.Split('|', 2);
- return new DescFormat(parts[0], parts[1]);
- });
+ DescParam rawDescParam = (DescParam)value;
- IList> parameters = descParam.Parameters
- .Select(param =>
+ // Spilt rawDesc into two parts: desc and format
+ IList parsedDescriptions = rawDescParam.Descriptions
+ .Select(desc =>
{
- IList parameters = GetFormattedParameters(parsedDescriptions, param.Parameters);
- parameters.Insert(0, param.Level.ToString());
- return parameters;
+ string[] parts = desc.Split('|', 2);
+ return new DescFormat(parts[0], parts[1]);
})
.ToList();
- List descList = parsedDescriptions.Select(p => p.Description).ToList();
- descList.Insert(0, "等级");
- return new DescParamInternal(descList, parameters);
+ IList> parameters = rawDescParam.Parameters
+ .Select(param =>
+ {
+ IList parameters = GetFormattedParameters(parsedDescriptions, param.Parameters);
+ return new LevelParam() { Level = param.Level.ToString(), Parameters = parameters };
+ })
+ .ToList();
+
+ return parameters;
}
///
@@ -44,6 +45,22 @@ internal class DescParamDescriptor : IValueConverter
throw Must.NeverHappen();
}
+ private static IList GetFormattedParameters(IList formats, IList param)
+ {
+ List results = new();
+
+ for (int index = 0; index < formats.Count; index++)
+ {
+ DescFormat descFormat = formats[index];
+
+ string format = descFormat.Format;
+ string resultFormatted = Regex.Replace(format, @"{param\d+.*?}", match => EvaluateMatch(match, param));
+ results.Add(new ParameterInfo { Description = descFormat.Description, Parameter = resultFormatted });
+ }
+
+ return results;
+ }
+
private static string EvaluateMatch(Match match, IList param)
{
if (match.Success)
@@ -74,19 +91,6 @@ internal class DescParamDescriptor : IValueConverter
}
}
- private IList GetFormattedParameters(IEnumerable formats, IList param)
- {
- List results = new();
- foreach (DescFormat descFormat in formats)
- {
- string format = descFormat.Format;
- string resultFormatted = Regex.Replace(format, @"{param\d+.*?}", match => EvaluateMatch(match, param));
- results.Add(resultFormatted);
- }
-
- return results;
- }
-
private class DescFormat
{
public DescFormat(string description, string format)
@@ -99,17 +103,4 @@ internal class DescParamDescriptor : IValueConverter
public string Format { get; set; }
}
-
- private class DescParamInternal
- {
- public DescParamInternal(IList descriptions, IList> parameters)
- {
- Descriptions = descriptions;
- Parameters = parameters;
- }
-
- public IList Descriptions { get; set; }
-
- public IList> Parameters { get; set; }
- }
-}
\ No newline at end of file
+}
diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/FightPropertyConverter.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/FightPropertyConverter.cs
deleted file mode 100644
index c7530a5d..00000000
--- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/FightPropertyConverter.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright (c) DGP Studio. All rights reserved.
-// Licensed under the MIT license.
-
-using Microsoft.UI.Xaml.Data;
-using Snap.Hutao.Extension;
-using Snap.Hutao.Model.Intrinsic;
-
-namespace Snap.Hutao.Model.Metadata.Converter;
-
-///
-/// 战斗属性转换器
-///
-internal class FightPropertyConverter : IValueConverter
-{
- ///
- public object Convert(object value, Type targetType, object parameter, string language)
- {
- return ((FightProperty)value).GetDescription();
- }
-
- ///
- public object ConvertBack(object value, Type targetType, object parameter, string language)
- {
- throw Must.NeverHappen();
- }
-}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/PropertyInfoDescriptor.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/PropertyInfoDescriptor.cs
new file mode 100644
index 00000000..d0433e83
--- /dev/null
+++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/PropertyInfoDescriptor.cs
@@ -0,0 +1,61 @@
+// Copyright (c) DGP Studio. All rights reserved.
+// Licensed under the MIT license.
+
+using Microsoft.UI.Xaml.Data;
+using Snap.Hutao.Extension;
+using Snap.Hutao.Model.Intrinsic;
+using Snap.Hutao.Model.Metadata.Annotation;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Snap.Hutao.Model.Metadata.Converter;
+
+///
+/// 基础属性翻译器
+///
+internal class PropertyInfoDescriptor : IValueConverter
+{
+ ///
+ public object Convert(object value, Type targetType, object parameter, string language)
+ {
+ PropertyInfo rawDescParam = (PropertyInfo)value;
+
+ IList> parameters = rawDescParam.Parameters
+ .Select(param =>
+ {
+ IList parameters = GetFormattedParameters(param.Parameters, rawDescParam.Properties);
+ return new LevelParam() { Level = param.Level, Parameters = parameters };
+ })
+ .ToList();
+
+ return parameters;
+ }
+
+ ///
+ public object ConvertBack(object value, Type targetType, object parameter, string language)
+ {
+ throw Must.NeverHappen();
+ }
+
+ private static IList GetFormattedParameters(IList parameters, IList properties)
+ {
+ List results = new();
+
+ for (int index = 0; index < parameters.Count; index++)
+ {
+ double param = parameters[index];
+ FormatMethod method = properties[index].GetFormat();
+
+ string valueFormatted = method switch
+ {
+ FormatMethod.Integer => Math.Round((double)param, MidpointRounding.AwayFromZero).ToString(),
+ FormatMethod.Percent => string.Format("{0:P1}", param),
+ _ => param.ToString(),
+ };
+
+ results.Add(new ParameterInfo { Description = properties[index].GetDescription(), Parameter = valueFormatted });
+ }
+
+ return results;
+ }
+}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/FightPropertyValueFormatter.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/SkillIconConverter.cs
similarity index 50%
rename from src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/FightPropertyValueFormatter.cs
rename to src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/SkillIconConverter.cs
index ca241949..3117efe5 100644
--- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/FightPropertyValueFormatter.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/SkillIconConverter.cs
@@ -2,27 +2,30 @@
// Licensed under the MIT license.
using Microsoft.UI.Xaml.Data;
-using Snap.Hutao.Model.Intrinsic;
-using Snap.Hutao.Model.Metadata.Annotation;
namespace Snap.Hutao.Model.Metadata.Converter;
///
-/// 战斗属性数值格式化器
+/// 技能图标转换器
///
-internal class FightPropertyValueFormatter : IValueConverter
+internal class SkillIconConverter : IValueConverter
{
+ private const string SkillUrl = "https://static.snapgenshin.com/Skill/{0}.png";
+ private const string TalentUrl = "https://static.snapgenshin.com/Talent/{0}.png";
+
///
public object Convert(object value, Type targetType, object parameter, string language)
{
- FormatMethod method = ((FightProperty)parameter).GetFormat();
+ string target = (string)value;
- return method switch
+ if (target.StartsWith("UI_Talent_"))
{
- FormatMethod.Integer => Math.Round((double)value, MidpointRounding.AwayFromZero),
- FormatMethod.Percent => string.Format("{0:P1}", value),
- _ => value,
- };
+ return new Uri(string.Format(TalentUrl, target));
+ }
+ else
+ {
+ return new Uri(string.Format(SkillUrl, target));
+ }
}
///
diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/ParameterInfo.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/ParameterInfo.cs
new file mode 100644
index 00000000..dc3fa7a8
--- /dev/null
+++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/ParameterInfo.cs
@@ -0,0 +1,21 @@
+// Copyright (c) DGP Studio. All rights reserved.
+// Licensed under the MIT license.
+
+namespace Snap.Hutao.Model.Metadata;
+
+///
+/// 包装一个描述参数
+/// 专用于绑定
+///
+public class ParameterInfo
+{
+ ///
+ /// 描述
+ ///
+ public string Description { get; set; } = default!;
+
+ ///
+ /// 参数
+ ///
+ public string Parameter { get; set; } = default!;
+}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/PropertyInfo.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/PropertyInfo.cs
index 3d31796d..5781fa82 100644
--- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/PropertyInfo.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/PropertyInfo.cs
@@ -14,10 +14,10 @@ public class PropertyInfo
///
/// 提升的属性
///
- public IEnumerable Properties { get; set; } = default!;
+ public IList Properties { get; set; } = default!;
///
/// 参数
///
- public IEnumerable> Parameters { get; set; } = default!;
+ public IList> Parameters { get; set; } = default!;
}
diff --git a/src/Snap.Hutao/Snap.Hutao/Package.appxmanifest b/src/Snap.Hutao/Snap.Hutao/Package.appxmanifest
index 30d59408..d9c235f7 100644
--- a/src/Snap.Hutao/Snap.Hutao/Package.appxmanifest
+++ b/src/Snap.Hutao/Snap.Hutao/Package.appxmanifest
@@ -9,7 +9,7 @@
+ Version="1.0.18.0" />
胡桃
diff --git a/src/Snap.Hutao/Snap.Hutao/Properties/launchSettings.json b/src/Snap.Hutao/Snap.Hutao/Properties/launchSettings.json
index 14b37087..dc55a580 100644
--- a/src/Snap.Hutao/Snap.Hutao/Properties/launchSettings.json
+++ b/src/Snap.Hutao/Snap.Hutao/Properties/launchSettings.json
@@ -1,7 +1,8 @@
{
"profiles": {
"Snap.Hutao (Package)": {
- "commandName": "MsixPackage"
+ "commandName": "MsixPackage",
+ "nativeDebugging": false
},
"Snap.Hutao (Unpackaged)": {
"commandName": "Project"
diff --git a/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj b/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj
index 1b8ae0f0..af073e01 100644
--- a/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj
+++ b/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj
@@ -34,7 +34,9 @@
+
+
@@ -104,6 +106,16 @@
+
+
+ MSBuild:Compile
+
+
+
+
+ MSBuild:Compile
+
+
MSBuild:Compile
diff --git a/src/Snap.Hutao/Snap.Hutao/View/Control/DescParamComboBox.xaml b/src/Snap.Hutao/Snap.Hutao/View/Control/DescParamComboBox.xaml
new file mode 100644
index 00000000..a5f2e757
--- /dev/null
+++ b/src/Snap.Hutao/Snap.Hutao/View/Control/DescParamComboBox.xaml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Snap.Hutao/Snap.Hutao/View/Control/DescParamComboBox.xaml.cs b/src/Snap.Hutao/Snap.Hutao/View/Control/DescParamComboBox.xaml.cs
new file mode 100644
index 00000000..8972472b
--- /dev/null
+++ b/src/Snap.Hutao/Snap.Hutao/View/Control/DescParamComboBox.xaml.cs
@@ -0,0 +1,61 @@
+// Copyright (c) DGP Studio. All rights reserved.
+// Licensed under the MIT license.
+
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Snap.Hutao.Core;
+using Snap.Hutao.Model.Metadata;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Snap.Hutao.View.Control;
+
+///
+/// 描述参数组合框
+///
+public sealed partial class DescParamComboBox : UserControl
+{
+ private static readonly DependencyProperty SourceProperty = Property
+ .Depend>>(nameof(Source), default!, OnSourceChanged);
+
+ ///
+ /// 构造一个新的描述参数组合框
+ ///
+ public DescParamComboBox()
+ {
+ InitializeComponent();
+ }
+
+ ///
+ /// 技能列表
+ ///
+ public IList> Source
+ {
+ get { return (IList>)GetValue(SourceProperty); }
+ set { SetValue(SourceProperty, value); }
+ }
+
+ private static void OnSourceChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
+ {
+ // Some of the {x:Bind} feature is not working properly,
+ // so we use this simple code behind approach to achieve selection function
+ if (sender is DescParamComboBox descParamComboBox)
+ {
+ if (args.NewValue != args.OldValue && args.NewValue is IList> list)
+ {
+ descParamComboBox.ItemHost.ItemsSource = list;
+ descParamComboBox.ItemHost.SelectedIndex = 0;
+
+ descParamComboBox.DetailsHost.ItemsSource = list.FirstOrDefault()?.Parameters;
+ }
+ }
+ }
+
+ private void ItemHostSelectionChanged(object sender, SelectionChangedEventArgs e)
+ {
+ if (sender is ComboBox comboBox && comboBox.SelectedIndex >= 0)
+ {
+ DetailsHost.ItemsSource = Source[comboBox.SelectedIndex]?.Parameters;
+ }
+ }
+}
diff --git a/src/Snap.Hutao/Snap.Hutao/View/Control/SkillPivot.xaml b/src/Snap.Hutao/Snap.Hutao/View/Control/SkillPivot.xaml
new file mode 100644
index 00000000..9502f10a
--- /dev/null
+++ b/src/Snap.Hutao/Snap.Hutao/View/Control/SkillPivot.xaml
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+ 0,0,16,0
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Snap.Hutao/Snap.Hutao/View/Control/SkillPivot.xaml.cs b/src/Snap.Hutao/Snap.Hutao/View/Control/SkillPivot.xaml.cs
new file mode 100644
index 00000000..c049bf72
--- /dev/null
+++ b/src/Snap.Hutao/Snap.Hutao/View/Control/SkillPivot.xaml.cs
@@ -0,0 +1,54 @@
+// Copyright (c) DGP Studio. All rights reserved.
+// Licensed under the MIT license.
+
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Snap.Hutao.Core;
+using System.Collections;
+
+namespace Snap.Hutao.View.Control;
+
+///
+/// 技能展柜
+///
+public sealed partial class SkillPivot : UserControl
+{
+ private static readonly DependencyProperty SkillsProperty = Property.Depend(nameof(Skills));
+ private static readonly DependencyProperty SelectedProperty = Property.Depend
public ICommand OpenDataFolderCommand { get; }
- private Task OpenCacheFolderAsync()
+ private Task OpenCacheFolderAsync(CancellationToken token)
{
- return Launcher.LaunchFolderAsync(App.AppData.TemporaryFolder).AsTask();
+ return Launcher.LaunchFolderAsync(App.Current.AppData.TemporaryFolder).AsTask(token);
}
- private async Task OpenDataFolderAsync()
+ private async Task OpenDataFolderAsync(CancellationToken token)
{
- StorageFolder folder = await KnownFolders.DocumentsLibrary.GetFolderAsync("Hutao").AsTask().ConfigureAwait(false);
- await Launcher.LaunchFolderAsync(folder).AsTask().ConfigureAwait(false);
+ StorageFolder folder = await KnownFolders.DocumentsLibrary.GetFolderAsync("Hutao").AsTask(token).ConfigureAwait(false);
+ await Launcher.LaunchFolderAsync(folder).AsTask(token).ConfigureAwait(false);
}
}
\ No newline at end of file