fix several issues

This commit is contained in:
DismissedLight
2023-10-01 11:08:24 +08:00
parent 500888c2d1
commit bfe9837b36
18 changed files with 121 additions and 31 deletions

View File

@@ -5,5 +5,5 @@ namespace Snap.Hutao.Core.Shell;
internal interface IShellLinkInterop internal interface IShellLinkInterop
{ {
void CreateDesktopShoutcutForElevatedLaunch(); bool TryCreateDesktopShoutcutForElevatedLaunch();
} }

View File

@@ -15,11 +15,20 @@ internal sealed partial class ShellLinkInterop : IShellLinkInterop
{ {
private readonly RuntimeOptions runtimeOptions; private readonly RuntimeOptions runtimeOptions;
public void CreateDesktopShoutcutForElevatedLaunch() public bool TryCreateDesktopShoutcutForElevatedLaunch()
{ {
string sourceLogoPath = Path.Combine(runtimeOptions.InstalledLocation, "Assets/Logo.ico"); string sourceLogoPath = Path.Combine(runtimeOptions.InstalledLocation, "Assets/Logo.ico");
string targetLogoPath = Path.Combine(runtimeOptions.DataFolder, "ShellLinkLogo.ico"); string targetLogoPath = Path.Combine(runtimeOptions.DataFolder, "ShellLinkLogo.ico");
try
{
// System.IO.IOException: 无法加密指定的文件。
File.Copy(sourceLogoPath, targetLogoPath, true); File.Copy(sourceLogoPath, targetLogoPath, true);
}
catch
{
return false;
}
IShellLinkW shellLink = (IShellLinkW)new ShellLink(); IShellLinkW shellLink = (IShellLinkW)new ShellLink();
shellLink.SetPath("powershell"); shellLink.SetPath("powershell");
@@ -34,5 +43,7 @@ internal sealed partial class ShellLinkInterop : IShellLinkInterop
IPersistFile persistFile = (IPersistFile)shellLink; IPersistFile persistFile = (IPersistFile)shellLink;
persistFile.Save(target, false); persistFile.Save(target, false);
return true;
} }
} }

View File

@@ -18,6 +18,7 @@ internal sealed class UIGF
/// <summary> /// <summary>
/// 信息 /// 信息
/// </summary> /// </summary>
[JsonRequired]
[JsonPropertyName("info")] [JsonPropertyName("info")]
public UIGFInfo Info { get; set; } = default!; public UIGFInfo Info { get; set; } = default!;

View File

@@ -3741,6 +3741,15 @@ namespace Snap.Hutao.Resource.Localization {
} }
} }
/// <summary>
/// 查找类似 创建桌面快捷方式失败 的本地化字符串。
/// </summary>
internal static string ViewModelSettingCreateDesktopShortcutFailed {
get {
return ResourceManager.GetString("ViewModelSettingCreateDesktopShortcutFailed", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 设置数据目录成功,重启以应用更改 的本地化字符串。 /// 查找类似 设置数据目录成功,重启以应用更改 的本地化字符串。
/// </summary> /// </summary>
@@ -5325,6 +5334,15 @@ namespace Snap.Hutao.Resource.Localization {
} }
} }
/// <summary>
/// 查找类似 版本更新前需要提前转换至与启动器匹配的服务器 的本地化字符串。
/// </summary>
internal static string ViewPageLaunchGameSwitchSchemeWarning {
get {
return ResourceManager.GetString("ViewPageLaunchGameSwitchSchemeWarning", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 请在游戏内关闭垂直同步选项,需要高性能的显卡以支持更高的帧率 的本地化字符串。 /// 查找类似 请在游戏内关闭垂直同步选项,需要高性能的显卡以支持更高的帧率 的本地化字符串。
/// </summary> /// </summary>

View File

@@ -1400,6 +1400,9 @@
<data name="ViewModelSettingCopyDeviceIdSuccess" xml:space="preserve"> <data name="ViewModelSettingCopyDeviceIdSuccess" xml:space="preserve">
<value>复制成功</value> <value>复制成功</value>
</data> </data>
<data name="ViewModelSettingCreateDesktopShortcutFailed" xml:space="preserve">
<value>创建桌面快捷方式失败</value>
</data>
<data name="ViewModelSettingSetDataFolderSuccess" xml:space="preserve"> <data name="ViewModelSettingSetDataFolderSuccess" xml:space="preserve">
<value>设置数据目录成功,重启以应用更改</value> <value>设置数据目录成功,重启以应用更改</value>
</data> </data>
@@ -1928,6 +1931,9 @@
<data name="ViewPageLaunchGameSwitchSchemeHeader" xml:space="preserve"> <data name="ViewPageLaunchGameSwitchSchemeHeader" xml:space="preserve">
<value>服务器</value> <value>服务器</value>
</data> </data>
<data name="ViewPageLaunchGameSwitchSchemeWarning" xml:space="preserve">
<value>版本更新前需要提前转换至与启动器匹配的服务器</value>
</data>
<data name="ViewPageLaunchGameUnlockFpsDescription" xml:space="preserve"> <data name="ViewPageLaunchGameUnlockFpsDescription" xml:space="preserve">
<value>请在游戏内关闭垂直同步选项,需要高性能的显卡以支持更高的帧率</value> <value>请在游戏内关闭垂直同步选项,需要高性能的显卡以支持更高的帧率</value>
</data> </data>

View File

@@ -99,10 +99,18 @@ internal sealed partial class GachaLogHutaoCloudService : IGachaLogHutaoCloudSer
HutaoStatisticsFactoryMetadataContext context = new(idAvatarMap, idWeaponMap, gachaEvents); HutaoStatisticsFactoryMetadataContext context = new(idAvatarMap, idWeaponMap, gachaEvents);
GachaEventStatistics raw = response.Data; GachaEventStatistics raw = response.Data;
try
{
HutaoStatisticsFactory factory = new(context); HutaoStatisticsFactory factory = new(context);
HutaoStatistics statistics = factory.Create(raw); HutaoStatistics statistics = factory.Create(raw);
return new(true, statistics); return new(true, statistics);
} }
catch
{
// 元数据未能即时更新导致异常?
return new(false, default!);
}
}
} }
return new(false, default!); return new(false, default!);

View File

@@ -194,6 +194,7 @@ internal sealed partial class UserService : IUserService, IUserServiceUnsafe
private static bool TryGetUser(ObservableCollection<BindingUser> users, string mid, [NotNullWhen(true)] out BindingUser? user) private static bool TryGetUser(ObservableCollection<BindingUser> users, string mid, [NotNullWhen(true)] out BindingUser? user)
{ {
// TODO: System.InvalidOperationException: Sequence contains more than one matching element
user = users.SingleOrDefault(u => u.Entity.Mid == mid); user = users.SingleOrDefault(u => u.Entity.Mid == mid);
return user is not null; return user is not null;
} }

View File

@@ -260,7 +260,7 @@
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="7.0.0" /> <PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="7.0.0" /> <PackageReference Include="Microsoft.Extensions.Http" Version="7.0.0" />
<PackageReference Include="Microsoft.VisualStudio.Validation" Version="17.6.11" /> <PackageReference Include="Microsoft.VisualStudio.Validation" Version="17.6.11" />
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.3.18-beta"> <PackageReference Include="Microsoft.Windows.CsWin32" Version="0.3.46-beta">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>

View File

@@ -67,10 +67,18 @@
Severity="Informational"/> Severity="Informational"/>
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" Text="{shcm:ResourceString Name=ViewPageLaunchGameCommonHeader}"/> <TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" Text="{shcm:ResourceString Name=ViewPageLaunchGameCommonHeader}"/>
<cwc:SettingsCard <cwc:SettingsCard
Description="{shcm:ResourceString Name=ViewPageLaunchGameSwitchSchemeDescription}"
Header="{shcm:ResourceString Name=ViewPageLaunchGameSwitchSchemeHeader}" Header="{shcm:ResourceString Name=ViewPageLaunchGameSwitchSchemeHeader}"
HeaderIcon="{shcm:FontIcon Glyph=&#xE8AB;}" HeaderIcon="{shcm:FontIcon Glyph=&#xE8AB;}"
IsEnabled="{Binding HutaoOptions.IsElevated}"> IsEnabled="{Binding HutaoOptions.IsElevated}">
<cwc:SettingsCard.Description>
<StackPanel>
<TextBlock Style="{StaticResource CaptionTextBlockStyle}" Text="{shcm:ResourceString Name=ViewPageLaunchGameSwitchSchemeDescription}"/>
<TextBlock
Foreground="{ThemeResource SystemControlErrorTextForegroundBrush}"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{shcm:ResourceString Name=ViewPageLaunchGameSwitchSchemeWarning}"/>
</StackPanel>
</cwc:SettingsCard.Description>
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<shvc:Elevation Margin="0,0,36,0" Visibility="{Binding HutaoOptions.IsElevated, Converter={StaticResource BoolToVisibilityRevertConverter}}"/> <shvc:Elevation Margin="0,0,36,0" Visibility="{Binding HutaoOptions.IsElevated, Converter={StaticResource BoolToVisibilityRevertConverter}}"/>
<shccs:ComboBox2 <shccs:ComboBox2

View File

@@ -40,12 +40,7 @@ internal sealed partial class LoginHoyoverseUserPage : Microsoft.UI.Xaml.Control
.TryCatchGetFromJsonAsync<WebApiResponse<AccountInfoWrapper>>(ApiOsEndpoints.WebApiOsAccountLoginByCookie, options, logger, token) .TryCatchGetFromJsonAsync<WebApiResponse<AccountInfoWrapper>>(ApiOsEndpoints.WebApiOsAccountLoginByCookie, options, logger, token)
.ConfigureAwait(false); .ConfigureAwait(false);
if (resp is not null) return $"{resp?.Data?.AccountInfo?.AccountId}";
{
return $"{resp.Data?.AccountInfo?.AccountId}";
}
return string.Empty;
} }
private async void OnRootLoaded(object sender, RoutedEventArgs e) private async void OnRootLoaded(object sender, RoutedEventArgs e)
@@ -81,6 +76,11 @@ internal sealed partial class LoginHoyoverseUserPage : Microsoft.UI.Xaml.Control
IInfoBarService infoBarService = Ioc.Default.GetRequiredService<IInfoBarService>(); IInfoBarService infoBarService = Ioc.Default.GetRequiredService<IInfoBarService>();
Cookie loginTicketCookie = Cookie.FromCoreWebView2Cookies(cookies); Cookie loginTicketCookie = Cookie.FromCoreWebView2Cookies(cookies);
if (loginTicketCookie.IsEmpty())
{
return;
}
string uid = await GetUidFromCookieAsync(Ioc.Default, loginTicketCookie).ConfigureAwait(false); string uid = await GetUidFromCookieAsync(Ioc.Default, loginTicketCookie).ConfigureAwait(false);
loginTicketCookie[Cookie.LOGIN_UID] = uid; loginTicketCookie[Cookie.LOGIN_UID] = uid;

View File

@@ -255,6 +255,12 @@ internal sealed partial class AvatarPropertyViewModel : Abstraction.ViewModel, I
{ {
baseline.AvatarId = avatar.Id; baseline.AvatarId = avatar.Id;
baseline.AvatarLevelCurrent = Math.Min(avatar.LevelNumber, baseline.AvatarLevelTarget); baseline.AvatarLevelCurrent = Math.Min(avatar.LevelNumber, baseline.AvatarLevelTarget);
if (avatar.Skills.Count < 3)
{
continue;
}
baseline.SkillList[0].Id = avatar.Skills[0].GroupId; baseline.SkillList[0].Id = avatar.Skills[0].GroupId;
baseline.SkillList[0].LevelCurrent = Math.Min(avatar.Skills[0].LevelNumber, baseline.SkillList[0].LevelTarget); baseline.SkillList[0].LevelCurrent = Math.Min(avatar.Skills[0].LevelNumber, baseline.SkillList[0].LevelTarget);
baseline.SkillList[1].Id = avatar.Skills[1].GroupId; baseline.SkillList[1].Id = avatar.Skills[1].GroupId;

View File

@@ -2,6 +2,7 @@
// Licensed under the MIT license. // Licensed under the MIT license.
using Snap.Hutao.Service.GachaLog; using Snap.Hutao.Service.GachaLog;
using Snap.Hutao.Service.Notification;
namespace Snap.Hutao.ViewModel.GachaLog; namespace Snap.Hutao.ViewModel.GachaLog;
@@ -12,6 +13,7 @@ namespace Snap.Hutao.ViewModel.GachaLog;
[ConstructorGenerated(CallBaseConstructor = true)] [ConstructorGenerated(CallBaseConstructor = true)]
internal sealed partial class GachaLogViewModelSlim : Abstraction.ViewModelSlim<View.Page.GachaLogPage> internal sealed partial class GachaLogViewModelSlim : Abstraction.ViewModelSlim<View.Page.GachaLogPage>
{ {
private readonly IInfoBarService infoBarService;
private readonly ITaskContext taskContext; private readonly ITaskContext taskContext;
private List<GachaStatisticsSlim>? statisticsList; private List<GachaStatisticsSlim>? statisticsList;
@@ -29,6 +31,8 @@ internal sealed partial class GachaLogViewModelSlim : Abstraction.ViewModelSlim<
IGachaLogService gachaLogService = scope.ServiceProvider.GetRequiredService<IGachaLogService>(); IGachaLogService gachaLogService = scope.ServiceProvider.GetRequiredService<IGachaLogService>();
if (await gachaLogService.InitializeAsync().ConfigureAwait(false)) if (await gachaLogService.InitializeAsync().ConfigureAwait(false))
{
try
{ {
List<GachaStatisticsSlim> list = await gachaLogService.GetStatisticsSlimListAsync().ConfigureAwait(false); List<GachaStatisticsSlim> list = await gachaLogService.GetStatisticsSlimListAsync().ConfigureAwait(false);
@@ -36,6 +40,11 @@ internal sealed partial class GachaLogViewModelSlim : Abstraction.ViewModelSlim<
StatisticsList = list; StatisticsList = list;
IsInitialized = true; IsInitialized = true;
} }
catch (Exception ex)
{
infoBarService.Error(ex);
}
}
} }
} }
} }

View File

@@ -270,7 +270,14 @@ internal sealed partial class SettingViewModel : Abstraction.ViewModel
[Command("CreateDesktopShortcutCommand")] [Command("CreateDesktopShortcutCommand")]
private void CreateDesktopShortcutForElevatedLaunch() private void CreateDesktopShortcutForElevatedLaunch()
{ {
shellLinkInterop.CreateDesktopShoutcutForElevatedLaunch(); bool created = shellLinkInterop.TryCreateDesktopShoutcutForElevatedLaunch();
if (created)
{
infoBarService.Information(SH.ViewModelSettingActionComplete); infoBarService.Information(SH.ViewModelSettingActionComplete);
} }
else
{
infoBarService.Warning(SH.ViewModelSettingCreateDesktopShortcutFailed);
}
}
} }

View File

@@ -37,6 +37,11 @@ internal sealed partial class Cookie
set => inner[key] = value; set => inner[key] = value;
} }
public bool IsEmpty()
{
return inner.Count <= 0;
}
/// <summary> /// <summary>
/// 解析Cookie字符串 /// 解析Cookie字符串
/// </summary> /// </summary>

View File

@@ -54,16 +54,20 @@ internal sealed partial class AuthClient
/// <returns>包含token的字典</returns> /// <returns>包含token的字典</returns>
public async ValueTask<Response<ListWrapper<NameToken>>> GetMultiTokenByLoginTicketAsync(Cookie cookie, bool isOversea, CancellationToken token = default) public async ValueTask<Response<ListWrapper<NameToken>>> GetMultiTokenByLoginTicketAsync(Cookie cookie, bool isOversea, CancellationToken token = default)
{ {
string loginTicket = cookie[Cookie.LOGIN_TICKET]; Response<ListWrapper<NameToken>>? resp = null;
string loginUid = cookie[Cookie.LOGIN_UID]; if (cookie.TryGetLoginTicket(out Cookie? loginTicketCookie))
{
string loginTicket = loginTicketCookie[Cookie.LOGIN_TICKET];
string loginUid = loginTicketCookie[Cookie.LOGIN_UID];
string url = isOversea string url = isOversea
? ApiOsEndpoints.AuthMultiToken(loginTicket, loginUid) ? ApiOsEndpoints.AuthMultiToken(loginTicket, loginUid)
: ApiEndpoints.AuthMultiToken(loginTicket, loginUid); : ApiEndpoints.AuthMultiToken(loginTicket, loginUid);
Response<ListWrapper<NameToken>>? resp = await httpClient resp = await httpClient
.TryCatchGetFromJsonAsync<Response<ListWrapper<NameToken>>>(url, options, logger, token) .TryCatchGetFromJsonAsync<Response<ListWrapper<NameToken>>>(url, options, logger, token)
.ConfigureAwait(false); .ConfigureAwait(false);
}
return Response.Response.DefaultIfNull(resp); return Response.Response.DefaultIfNull(resp);
} }

View File

@@ -5,6 +5,8 @@ namespace Snap.Hutao.Web.Hutao.Geetest;
internal sealed class GeetestResponse internal sealed class GeetestResponse
{ {
public static GeetestResponse InternalFailure { get; } = new() { Code = Response.Response.InternalFailure };
[JsonPropertyName("code")] [JsonPropertyName("code")]
public int Code { get; set; } public int Code { get; set; }

View File

@@ -22,14 +22,18 @@ internal sealed partial class HomaGeetestClient
if (string.IsNullOrEmpty(template)) if (string.IsNullOrEmpty(template))
{ {
return new() { Code = Response.Response.InternalFailure }; return GeetestResponse.InternalFailure;
} }
GeetestResponse? resp = await httpClient GeetestResponse? resp = await httpClient
.TryCatchGetFromJsonAsync<GeetestResponse>(template.Format(gt, challenge), options, logger, token) .TryCatchGetFromJsonAsync<GeetestResponse>(template.Format(gt, challenge), options, logger, token)
.ConfigureAwait(false); .ConfigureAwait(false);
ArgumentNullException.ThrowIfNull(resp); if (resp is null)
{
return GeetestResponse.InternalFailure;
}
return resp; return resp;
} }
} }