support game resource download switch

This commit is contained in:
DismissedLight
2023-03-07 16:28:00 +08:00
parent 128b985609
commit c71ecd89e3
14 changed files with 553 additions and 291 deletions

View File

@@ -66,6 +66,7 @@
<!-- Converters --> <!-- Converters -->
<cwuc:BoolNegationConverter x:Key="BoolNegationConverter"/> <cwuc:BoolNegationConverter x:Key="BoolNegationConverter"/>
<cwuc:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter"/> <cwuc:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
<cwuc:FileSizeToFriendlyStringConverter x:Key="FileSizeToFriendlyStringConverter"/>
<shmmc:AchievementIconConverter x:Key="AchievementIconConverter"/> <shmmc:AchievementIconConverter x:Key="AchievementIconConverter"/>
<shmmc:AvatarCardConverter x:Key="AvatarCardConverter"/> <shmmc:AvatarCardConverter x:Key="AvatarCardConverter"/>
<shmmc:AvatarIconConverter x:Key="AvatarIconConverter"/> <shmmc:AvatarIconConverter x:Key="AvatarIconConverter"/>

View File

@@ -8,6 +8,7 @@ using Snap.Hutao.Core;
using Snap.Hutao.Core.ExceptionService; using Snap.Hutao.Core.ExceptionService;
using Snap.Hutao.Core.LifeCycle; using Snap.Hutao.Core.LifeCycle;
using System.Diagnostics; using System.Diagnostics;
using Windows.ApplicationModel.Background;
using Windows.Storage; using Windows.Storage;
namespace Snap.Hutao; namespace Snap.Hutao;

View File

@@ -10,7 +10,6 @@ using Snap.Hutao.Service.DailyNote;
using Snap.Hutao.Service.Metadata; using Snap.Hutao.Service.Metadata;
using Snap.Hutao.Service.Navigation; using Snap.Hutao.Service.Navigation;
using System.Diagnostics; using System.Diagnostics;
using System.IO;
using System.Security.Principal; using System.Security.Principal;
using Windows.ApplicationModel; using Windows.ApplicationModel;
@@ -164,10 +163,7 @@ internal static class Activation
default: default:
{ {
// Increase launch times await HandleNormalLaunchActionAsync().ConfigureAwait(false);
LocalSetting.Set(SettingKeys.LaunchTimes, LocalSetting.Get(SettingKeys.LaunchTimes, 0) + 1);
await WaitMainWindowAsync().ConfigureAwait(false);
break; break;
} }
} }
@@ -175,6 +171,14 @@ internal static class Activation
} }
} }
private static async Task HandleNormalLaunchActionAsync()
{
// Increase launch times
LocalSetting.Set(SettingKeys.LaunchTimes, LocalSetting.Get(SettingKeys.LaunchTimes, 0) + 1);
await WaitMainWindowAsync().ConfigureAwait(false);
}
private static async Task WaitMainWindowAsync() private static async Task WaitMainWindowAsync()
{ {
await ThreadHelper.SwitchToMainThreadAsync(); await ThreadHelper.SwitchToMainThreadAsync();
@@ -211,6 +215,12 @@ internal static class Activation
await HandleDailyNoteActionAsync(action, parameter, isRedirected).ConfigureAwait(false); await HandleDailyNoteActionAsync(action, parameter, isRedirected).ConfigureAwait(false);
break; break;
} }
default:
{
await HandleNormalLaunchActionAsync().ConfigureAwait(false);
break;
}
} }
} }

View File

@@ -3714,6 +3714,51 @@ namespace Snap.Hutao.Resource.Localization {
} }
} }
/// <summary>
/// 查找类似 游戏选项 的本地化字符串。
/// </summary>
internal static string ViewPageLaunchGameOptionsHeader {
get {
return ResourceManager.GetString("ViewPageLaunchGameOptionsHeader", resourceCulture);
}
}
/// <summary>
/// 查找类似 增量包 的本地化字符串。
/// </summary>
internal static string ViewPageLaunchGameResourceDiffHeader {
get {
return ResourceManager.GetString("ViewPageLaunchGameResourceDiffHeader", resourceCulture);
}
}
/// <summary>
/// 查找类似 资源下载 的本地化字符串。
/// </summary>
internal static string ViewPageLaunchGameResourceHeader {
get {
return ResourceManager.GetString("ViewPageLaunchGameResourceHeader", resourceCulture);
}
}
/// <summary>
/// 查找类似 客户端 的本地化字符串。
/// </summary>
internal static string ViewPageLaunchGameResourceLatestHeader {
get {
return ResourceManager.GetString("ViewPageLaunchGameResourceLatestHeader", resourceCulture);
}
}
/// <summary>
/// 查找类似 预下载 的本地化字符串。
/// </summary>
internal static string ViewPageLaunchGameResourcePreDownloadHeader {
get {
return ResourceManager.GetString("ViewPageLaunchGameResourcePreDownloadHeader", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 在游戏时可以随时调整 的本地化字符串。 /// 查找类似 在游戏时可以随时调整 的本地化字符串。
/// </summary> /// </summary>

View File

@@ -1335,6 +1335,21 @@
<data name="ViewPageLaunchGameMonitorsHeader" xml:space="preserve"> <data name="ViewPageLaunchGameMonitorsHeader" xml:space="preserve">
<value>显示器</value> <value>显示器</value>
</data> </data>
<data name="ViewPageLaunchGameOptionsHeader" xml:space="preserve">
<value>游戏选项</value>
</data>
<data name="ViewPageLaunchGameResourceDiffHeader" xml:space="preserve">
<value>增量包</value>
</data>
<data name="ViewPageLaunchGameResourceHeader" xml:space="preserve">
<value>资源下载</value>
</data>
<data name="ViewPageLaunchGameResourceLatestHeader" xml:space="preserve">
<value>客户端</value>
</data>
<data name="ViewPageLaunchGameResourcePreDownloadHeader" xml:space="preserve">
<value>预下载</value>
</data>
<data name="ViewPageLaunchGameSetFpsDescription" xml:space="preserve"> <data name="ViewPageLaunchGameSetFpsDescription" xml:space="preserve">
<value>在游戏时可以随时调整</value> <value>在游戏时可以随时调整</value>
</data> </data>

View File

@@ -237,10 +237,14 @@ internal sealed class GameService : IGameService
string gameFileName = Path.GetFileName(gamePath); string gameFileName = Path.GetFileName(gamePath);
progress.Report(new(SH.ServiceGameEnsureGameResourceQueryResourceInformation)); progress.Report(new(SH.ServiceGameEnsureGameResourceQueryResourceInformation));
Response<GameResource> response = await Ioc.Default Response<GameResource> response;
.GetRequiredService<ResourceClient>() using (IServiceScope scope = scopeFactory.CreateScope())
.GetResourceAsync(launchScheme) {
.ConfigureAwait(false); response = await scope.ServiceProvider
.GetRequiredService<ResourceClient>()
.GetResourceAsync(launchScheme)
.ConfigureAwait(false);
}
if (response.IsOk()) if (response.IsOk())
{ {

View File

@@ -40,14 +40,14 @@ internal sealed class PackageConverter
/// 调用前需要确认本地文件与服务器上的不同 /// 调用前需要确认本地文件与服务器上的不同
/// </summary> /// </summary>
/// <param name="targetScheme">目标启动方案</param> /// <param name="targetScheme">目标启动方案</param>
/// <param name="gameResouce">游戏资源</param> /// <param name="gameResource">游戏资源</param>
/// <param name="gameFolder">游戏目录</param> /// <param name="gameFolder">游戏目录</param>
/// <param name="progress">进度</param> /// <param name="progress">进度</param>
/// <returns>替换结果与资源</returns> /// <returns>替换结果与资源</returns>
public async Task<bool> EnsureGameResourceAsync(LaunchScheme targetScheme, GameResource gameResouce, string gameFolder, IProgress<PackageReplaceStatus> progress) public async Task<bool> EnsureGameResourceAsync(LaunchScheme targetScheme, GameResource gameResource, string gameFolder, IProgress<PackageReplaceStatus> progress)
{ {
await ThreadHelper.SwitchToBackgroundAsync(); await ThreadHelper.SwitchToBackgroundAsync();
string scatteredFilesUrl = gameResouce.Game.Latest.DecompressedPath; string scatteredFilesUrl = gameResource.Game.Latest.DecompressedPath;
Uri pkgVersionUri = $"{scatteredFilesUrl}/pkg_version".ToUri(); Uri pkgVersionUri = $"{scatteredFilesUrl}/pkg_version".ToUri();
ConvertDirection direction = targetScheme.IsOversea ? ConvertDirection.ChineseToOversea : ConvertDirection.OverseaToChinese; ConvertDirection direction = targetScheme.IsOversea ? ConvertDirection.ChineseToOversea : ConvertDirection.OverseaToChinese;
@@ -68,7 +68,7 @@ internal sealed class PackageConverter
Dictionary<string, VersionItem> localItems; Dictionary<string, VersionItem> localItems;
using (FileStream localSteam = File.OpenRead(Path.Combine(gameFolder, "pkg_version"))) using (FileStream localSteam = File.OpenRead(Path.Combine(gameFolder, "pkg_version")))
{ {
localItems = await GetLocalVersionItemsAsync(localSteam, direction, ConvertRemoteName).ConfigureAwait(false); localItems = await GetLocalVersionItemsAsync(localSteam, direction).ConfigureAwait(false);
} }
IEnumerable<ItemOperationInfo> diffOperations = GetItemOperationInfos(remoteItems, localItems).OrderBy(i => (int)i.Type); IEnumerable<ItemOperationInfo> diffOperations = GetItemOperationInfos(remoteItems, localItems).OrderBy(i => (int)i.Type);
@@ -134,22 +134,6 @@ internal sealed class PackageConverter
} }
} }
private static string ConvertRemoteName(string remoteName, ConvertDirection direction)
{
// 我们已经提前重命名了整个 Data 文件夹 所以需要将 RemoteName 中的 Data 同样替换
if (remoteName.StartsWith(YuanShenData) || remoteName.StartsWith(GenshinImpactData))
{
return direction switch
{
ConvertDirection.OverseaToChinese => $"{YuanShenData}{remoteName[GenshinImpactData.Length..]}",
ConvertDirection.ChineseToOversea => $"{GenshinImpactData}{remoteName[YuanShenData.Length..]}",
_ => remoteName,
};
}
return remoteName;
}
private static IEnumerable<ItemOperationInfo> GetItemOperationInfos(Dictionary<string, VersionItem> remote, Dictionary<string, VersionItem> local) private static IEnumerable<ItemOperationInfo> GetItemOperationInfos(Dictionary<string, VersionItem> remote, Dictionary<string, VersionItem> local)
{ {
foreach ((string remoteName, VersionItem remoteItem) in remote) foreach ((string remoteName, VersionItem remoteItem) in remote)
@@ -368,7 +352,7 @@ internal sealed class PackageConverter
return results; return results;
} }
private async Task<Dictionary<string, VersionItem>> GetLocalVersionItemsAsync(Stream stream, ConvertDirection direction, Func<string, ConvertDirection, string> nameConverter) private async Task<Dictionary<string, VersionItem>> GetLocalVersionItemsAsync(Stream stream, ConvertDirection direction)
{ {
Dictionary<string, VersionItem> results = new(); Dictionary<string, VersionItem> results = new();
@@ -379,7 +363,21 @@ internal sealed class PackageConverter
if (!string.IsNullOrEmpty(raw)) if (!string.IsNullOrEmpty(raw))
{ {
VersionItem item = JsonSerializer.Deserialize<VersionItem>(raw, options)!; VersionItem item = JsonSerializer.Deserialize<VersionItem>(raw, options)!;
results.Add(nameConverter(item.RemoteName, direction), item);
string remoteName = item.RemoteName;
// 我们已经提前重命名了整个 Data 文件夹 所以需要将 RemoteName 中的 Data 同样替换
if (remoteName.StartsWith(YuanShenData) || remoteName.StartsWith(GenshinImpactData))
{
remoteName = direction switch
{
ConvertDirection.OverseaToChinese => $"{YuanShenData}{remoteName[GenshinImpactData.Length..]}",
ConvertDirection.ChineseToOversea => $"{GenshinImpactData}{remoteName[YuanShenData.Length..]}",
_ => remoteName,
};
}
results.Add(remoteName, item);
} }
} }
} }

View File

@@ -76,6 +76,7 @@
<None Remove="View\Control\BottomTextControl.xaml" /> <None Remove="View\Control\BottomTextControl.xaml" />
<None Remove="View\Control\DescParamComboBox.xaml" /> <None Remove="View\Control\DescParamComboBox.xaml" />
<None Remove="View\Control\ItemIcon.xaml" /> <None Remove="View\Control\ItemIcon.xaml" />
<None Remove="View\Control\LaunchGameResourceExpander.xaml" />
<None Remove="View\Control\LoadingView.xaml" /> <None Remove="View\Control\LoadingView.xaml" />
<None Remove="View\Control\SkillPivot.xaml" /> <None Remove="View\Control\SkillPivot.xaml" />
<None Remove="View\Control\StatisticsCard.xaml" /> <None Remove="View\Control\StatisticsCard.xaml" />
@@ -446,6 +447,11 @@
<LastGenOutput>SH.Designer.cs</LastGenOutput> <LastGenOutput>SH.Designer.cs</LastGenOutput>
</EmbeddedResource> </EmbeddedResource>
</ItemGroup> </ItemGroup>
<ItemGroup>
<Page Update="View\Control\LaunchGameResourceExpander.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup> <ItemGroup>
<Page Update="View\Page\WikiMonsterPage.xaml"> <Page Update="View\Page\WikiMonsterPage.xaml">
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>

View File

@@ -0,0 +1,99 @@
<Expander
x:Class="Snap.Hutao.View.Control.LaunchGameResourceExpander"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
IsExpanded="True"
mc:Ignorable="d">
<Grid Margin="16,16,16,16">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<TextBlock Text="{Binding DisplayName}"/>
<StackPanel
Grid.Row="1"
Margin="0,4,0,0"
Orientation="Horizontal">
<FontIcon FontSize="{StaticResource CaptionTextBlockFontSize}" Glyph="&#xF012;"/>
<TextBlock
Width="80"
Margin="8,0,0,0"
HorizontalAlignment="Left"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{Binding PackageSize, Converter={StaticResource FileSizeToFriendlyStringConverter}}"/>
<FontIcon FontSize="{StaticResource CaptionTextBlockFontSize}" Glyph="&#xE8B7;"/>
<TextBlock
Width="80"
Margin="8,0,0,0"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{Binding Size, Converter={StaticResource FileSizeToFriendlyStringConverter}}"/>
<FontIcon FontSize="{StaticResource CaptionTextBlockFontSize}" Glyph="&#xEDAD;"/>
<TextBlock
Margin="8,0,0,0"
IsTextSelectionEnabled="True"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{Binding Md5}"/>
</StackPanel>
<HyperlinkButton
Grid.RowSpan="2"
Height="38.4"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Content="&#xE8A7;"
FontFamily="{StaticResource SymbolThemeFontFamily}"
NavigateUri="{Binding Path}"/>
<MenuFlyoutSeparator Grid.Row="2" Margin="4,16,4,0"/>
<ItemsControl Grid.Row="3" ItemsSource="{Binding VoicePacks}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Margin="0,16,0,0">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Text="{Binding DisplayName}"/>
<StackPanel
Grid.Row="1"
Margin="0,4,0,0"
Orientation="Horizontal">
<FontIcon FontSize="{StaticResource CaptionTextBlockFontSize}" Glyph="&#xF012;"/>
<TextBlock
Width="80"
Margin="8,0,0,0"
HorizontalAlignment="Left"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{Binding PackageSize, Converter={StaticResource FileSizeToFriendlyStringConverter}}"/>
<FontIcon FontSize="{StaticResource CaptionTextBlockFontSize}" Glyph="&#xE8B7;"/>
<TextBlock
Width="80"
Margin="8,0,0,0"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{Binding Size, Converter={StaticResource FileSizeToFriendlyStringConverter}}"/>
<FontIcon FontSize="{StaticResource CaptionTextBlockFontSize}" Glyph="&#xEDAD;"/>
<TextBlock
Margin="8,0,0,0"
IsTextSelectionEnabled="True"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{Binding Md5}"/>
</StackPanel>
<HyperlinkButton
Grid.RowSpan="2"
Height="38.4"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Content="&#xE8A7;"
FontFamily="{StaticResource SymbolThemeFontFamily}"
NavigateUri="{Binding Path}"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</Expander>

View File

@@ -0,0 +1,20 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Xaml.Controls;
namespace Snap.Hutao.View.Control;
/// <summary>
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϸ<EFBFBD><CFB7>Դ Expander
/// </summary>
internal sealed partial class LaunchGameResourceExpander : Expander
{
/// <summary>
/// <20><><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD>µ<EFBFBD><C2B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϸ<EFBFBD><CFB7>Դ Expander
/// </summary>
public LaunchGameResourceExpander()
{
InitializeComponent();
}
}

View File

@@ -12,6 +12,7 @@
xmlns:shcb="using:Snap.Hutao.Control.Behavior" xmlns:shcb="using:Snap.Hutao.Control.Behavior"
xmlns:shcm="using:Snap.Hutao.Control.Markup" xmlns:shcm="using:Snap.Hutao.Control.Markup"
xmlns:shv="using:Snap.Hutao.ViewModel" xmlns:shv="using:Snap.Hutao.ViewModel"
xmlns:shvc="using:Snap.Hutao.View.Control"
xmlns:wsc="using:WinUICommunity.SettingsUI.Controls" xmlns:wsc="using:WinUICommunity.SettingsUI.Controls"
d:DataContext="{d:DesignInstance shv:LaunchGameViewModel}" d:DataContext="{d:DesignInstance shv:LaunchGameViewModel}"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
@@ -23,13 +24,10 @@
<Page.Resources> <Page.Resources>
<shc:BindingProxy x:Key="BindingProxy" DataContext="{Binding}"/> <shc:BindingProxy x:Key="BindingProxy" DataContext="{Binding}"/>
<Visibility x:Key="VisibilityCollapsed">Collapsed</Visibility>
<Style BasedOn="{StaticResource SettingButtonStyle}" TargetType="Button"> <Style BasedOn="{StaticResource SettingButtonStyle}" TargetType="Button">
<Setter Property="MinWidth" Value="156"/> <Setter Property="MinWidth" Value="156"/>
</Style> </Style>
<Style BasedOn="{StaticResource HyperlinkButtonStyle}" TargetType="HyperlinkButton">
<Setter Property="MinWidth" Value="156"/>
</Style>
<Style BasedOn="{StaticResource DefaultComboBoxStyle}" TargetType="ComboBox"> <Style BasedOn="{StaticResource DefaultComboBoxStyle}" TargetType="ComboBox">
<Setter Property="MinWidth" Value="156"/> <Setter Property="MinWidth" Value="156"/>
</Style> </Style>
@@ -38,267 +36,291 @@
</Style> </Style>
</Page.Resources> </Page.Resources>
<Grid> <Grid>
<Grid.RowDefinitions> <Rectangle
<RowDefinition/> Height="48"
<RowDefinition Height="auto"/> VerticalAlignment="Top"
</Grid.RowDefinitions> Fill="{ThemeResource CardBackgroundFillColorDefaultBrush}"
<ScrollViewer Grid.RowSpan="2"> IsHitTestVisible="False"/>
<Grid> <Pivot>
<Grid.ColumnDefinitions> <Pivot.RightHeader>
<ColumnDefinition MaxWidth="800"/> <CommandBar DefaultLabelPosition="Right">
<ColumnDefinition Width="auto"/> <AppBarButton
</Grid.ColumnDefinitions> Command="{Binding LaunchCommand}"
<StackPanel Margin="16"> Icon="{shcm:FontIcon Glyph=&#xE7FC;}"
<InfoBar Label="{shcm:ResourceString Name=ViewPageLaunchGameAction}"/>
IsClosable="False" </CommandBar>
IsOpen="True" </Pivot.RightHeader>
Message="{shcm:ResourceString Name=ViewPageLaunchGameConfigurationSaveHint}"
Severity="Informational"/> <PivotItem Header="{shcm:ResourceString Name=ViewPageLaunchGameOptionsHeader}">
<InfoBar <ScrollViewer Grid.RowSpan="2">
Margin="0,2,0,0" <Grid>
IsClosable="False" <Grid.ColumnDefinitions>
IsOpen="{Binding IsElevated, Converter={StaticResource BoolNegationConverter}}" <ColumnDefinition MaxWidth="1000"/>
Message="{shcm:ResourceString Name=ViewPageLaunchGameElevationHint}" <ColumnDefinition Width="auto"/>
Severity="Warning"/> </Grid.ColumnDefinitions>
<wsc:SettingsGroup Margin="0,0,0,0" Header="{shcm:ResourceString Name=ViewPageLaunchGameCommonHeader}"> <StackPanel Margin="16">
<InfoBar <InfoBar
IsClosable="False" IsClosable="False"
IsOpen="{Binding IsElevated}" IsOpen="True"
Message="{shcm:ResourceString Name=ViewPageLaunchGameSwitchSchemeHint}" Message="{shcm:ResourceString Name=ViewPageLaunchGameConfigurationSaveHint}"
Severity="Informational"/> Severity="Informational"/>
<wsc:Setting <InfoBar
Description="{shcm:ResourceString Name=ViewPageLaunchGameSwitchSchemeDescription}" Margin="0,2,0,0"
Header="{shcm:ResourceString Name=ViewPageLaunchGameSwitchSchemeHeader}" IsClosable="False"
Icon="&#xE8AB;" IsOpen="{Binding IsElevated, Converter={StaticResource BoolNegationConverter}}"
IsEnabled="{Binding IsElevated}"> Message="{shcm:ResourceString Name=ViewPageLaunchGameElevationHint}"
<wsc:Setting.ActionContent> Severity="Warning"/>
<ComboBox <wsc:SettingsGroup Margin="0,0,0,0" Header="{shcm:ResourceString Name=ViewPageLaunchGameCommonHeader}">
DisplayMemberPath="DisplayName"
ItemsSource="{Binding KnownSchemes}"
SelectedItem="{Binding SelectedScheme, Mode=TwoWay}"/>
</wsc:Setting.ActionContent>
</wsc:Setting>
<wsc:SettingExpander IsExpanded="True">
<wsc:SettingExpander.Header>
<wsc:Setting <wsc:Setting
Description="{shcm:ResourceString Name=ViewPageLaunchGameSwitchAccountDescription}" Description="{shcm:ResourceString Name=ViewPageLaunchGameSwitchSchemeDescription}"
Header="{shcm:ResourceString Name=ViewPageLaunchGameSwitchAccountHeader}" Header="{shcm:ResourceString Name=ViewPageLaunchGameSwitchSchemeHeader}"
Icon="&#xE748;"> Icon="&#xE8AB;"
IsEnabled="{Binding IsElevated}">
<wsc:Setting.ActionContent> <wsc:Setting.ActionContent>
<Button <ComboBox
Grid.Column="1" DisplayMemberPath="DisplayName"
MinWidth="124" ItemsSource="{Binding KnownSchemes}"
Margin="0,0,8,0" SelectedItem="{Binding SelectedScheme, Mode=TwoWay}"/>
HorizontalAlignment="Right"
Command="{Binding DetectGameAccountCommand}"
Content="{shcm:ResourceString Name=ViewPageLaunchGameSwitchAccountDetectAction}"/>
</wsc:Setting.ActionContent> </wsc:Setting.ActionContent>
</wsc:Setting> </wsc:Setting>
</wsc:SettingExpander.Header> <wsc:SettingExpander IsExpanded="True">
<ListView ItemsSource="{Binding GameAccounts}" SelectedItem="{Binding SelectedGameAccount, Mode=TwoWay}"> <wsc:SettingExpander.Header>
<ListView.ItemTemplate> <wsc:Setting
<DataTemplate> Description="{shcm:ResourceString Name=ViewPageLaunchGameSwitchAccountDescription}"
<Grid> Header="{shcm:ResourceString Name=ViewPageLaunchGameSwitchAccountHeader}"
<StackPanel Margin="0,12"> Icon="&#xE748;">
<TextBlock Text="{Binding Name}"/> <wsc:Setting.ActionContent>
<TextBlock
Opacity="0.8"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{Binding AttachUid, TargetNullValue={shcm:ResourceString Name=ViewPageLaunchGameSwitchAccountAttachUidNull}}"/>
</StackPanel>
<StackPanel
x:Name="ButtonPanel"
HorizontalAlignment="Right"
Orientation="Horizontal"
Visibility="Collapsed">
<Button <Button
MinWidth="48" Grid.Column="1"
Margin="4,8" MinWidth="124"
VerticalAlignment="Stretch" Margin="0,0,8,0"
Command="{Binding DataContext.AttachGameAccountCommand, Source={StaticResource BindingProxy}}" HorizontalAlignment="Right"
CommandParameter="{Binding}" Command="{Binding DetectGameAccountCommand}"
Content="&#xE723;" Content="{shcm:ResourceString Name=ViewPageLaunchGameSwitchAccountDetectAction}"/>
FontFamily="{StaticResource SymbolThemeFontFamily}" </wsc:Setting.ActionContent>
ToolTipService.ToolTip="{shcm:ResourceString Name=ViewPageLaunchGameSwitchAccountAttachUidToolTip}"/> </wsc:Setting>
<Button </wsc:SettingExpander.Header>
MinWidth="48" <ListView ItemsSource="{Binding GameAccounts}" SelectedItem="{Binding SelectedGameAccount, Mode=TwoWay}">
Margin="4,8" <ListView.ItemTemplate>
VerticalAlignment="Stretch" <DataTemplate>
Command="{Binding DataContext.ModifyGameAccountCommand, Source={StaticResource BindingProxy}}" <Grid>
CommandParameter="{Binding}" <StackPanel Margin="0,12">
Content="&#xE8AC;" <TextBlock Text="{Binding Name}"/>
FontFamily="{StaticResource SymbolThemeFontFamily}" <TextBlock
ToolTipService.ToolTip="{shcm:ResourceString Name=ViewPageLaunchGameSwitchAccountRenameToolTip}"/> Opacity="0.8"
<Button Style="{StaticResource CaptionTextBlockStyle}"
MinWidth="48" Text="{Binding AttachUid, TargetNullValue={shcm:ResourceString Name=ViewPageLaunchGameSwitchAccountAttachUidNull}}"/>
Margin="4,8,0,8" </StackPanel>
VerticalAlignment="Stretch" <StackPanel
Command="{Binding DataContext.RemoveGameAccountCommand, Source={StaticResource BindingProxy}}" x:Name="ButtonPanel"
CommandParameter="{Binding}" HorizontalAlignment="Right"
Content="&#xE74D;" Orientation="Horizontal"
FontFamily="{StaticResource SymbolThemeFontFamily}" Visibility="Collapsed">
ToolTipService.ToolTip="{shcm:ResourceString Name=ViewPageLaunchGameSwitchAccountRemoveToolTip}"/> <Button
</StackPanel> MinWidth="48"
Margin="4,8"
VerticalAlignment="Stretch"
Command="{Binding DataContext.AttachGameAccountCommand, Source={StaticResource BindingProxy}}"
CommandParameter="{Binding}"
Content="&#xE723;"
FontFamily="{StaticResource SymbolThemeFontFamily}"
ToolTipService.ToolTip="{shcm:ResourceString Name=ViewPageLaunchGameSwitchAccountAttachUidToolTip}"/>
<Button
MinWidth="48"
Margin="4,8"
VerticalAlignment="Stretch"
Command="{Binding DataContext.ModifyGameAccountCommand, Source={StaticResource BindingProxy}}"
CommandParameter="{Binding}"
Content="&#xE8AC;"
FontFamily="{StaticResource SymbolThemeFontFamily}"
ToolTipService.ToolTip="{shcm:ResourceString Name=ViewPageLaunchGameSwitchAccountRenameToolTip}"/>
<Button
MinWidth="48"
Margin="4,8,0,8"
VerticalAlignment="Stretch"
Command="{Binding DataContext.RemoveGameAccountCommand, Source={StaticResource BindingProxy}}"
CommandParameter="{Binding}"
Content="&#xE74D;"
FontFamily="{StaticResource SymbolThemeFontFamily}"
ToolTipService.ToolTip="{shcm:ResourceString Name=ViewPageLaunchGameSwitchAccountRemoveToolTip}"/>
</StackPanel>
<Grid.Resources> <Grid.Resources>
<Storyboard x:Name="ButtonPanelVisibleStoryboard"> <Storyboard x:Name="ButtonPanelVisibleStoryboard">
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ButtonPanel" Storyboard.TargetProperty="Visibility"> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ButtonPanel" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0"> <DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value> <DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility> <Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value> </DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame> </DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames> </ObjectAnimationUsingKeyFrames>
</Storyboard> </Storyboard>
<Storyboard x:Name="ButtonPanelCollapsedStoryboard"> <Storyboard x:Name="ButtonPanelCollapsedStoryboard">
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ButtonPanel" Storyboard.TargetProperty="Visibility"> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ButtonPanel" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0"> <DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value> <DiscreteObjectKeyFrame.Value>
<Visibility>Collapsed</Visibility> <Visibility>Collapsed</Visibility>
</DiscreteObjectKeyFrame.Value> </DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame> </DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames> </ObjectAnimationUsingKeyFrames>
</Storyboard> </Storyboard>
</Grid.Resources> </Grid.Resources>
<mxi:Interaction.Behaviors> <mxi:Interaction.Behaviors>
<mxic:EventTriggerBehavior EventName="PointerEntered"> <mxic:EventTriggerBehavior EventName="PointerEntered">
<mxim:ControlStoryboardAction Storyboard="{StaticResource ButtonPanelVisibleStoryboard}"/> <mxim:ControlStoryboardAction Storyboard="{StaticResource ButtonPanelVisibleStoryboard}"/>
</mxic:EventTriggerBehavior> </mxic:EventTriggerBehavior>
<mxic:EventTriggerBehavior EventName="PointerExited"> <mxic:EventTriggerBehavior EventName="PointerExited">
<mxim:ControlStoryboardAction Storyboard="{StaticResource ButtonPanelCollapsedStoryboard}"/> <mxim:ControlStoryboardAction Storyboard="{StaticResource ButtonPanelCollapsedStoryboard}"/>
</mxic:EventTriggerBehavior> </mxic:EventTriggerBehavior>
</mxi:Interaction.Behaviors> </mxi:Interaction.Behaviors>
</Grid> </Grid>
</DataTemplate> </DataTemplate>
</ListView.ItemTemplate> </ListView.ItemTemplate>
</ListView> </ListView>
</wsc:SettingExpander> </wsc:SettingExpander>
</wsc:SettingsGroup> </wsc:SettingsGroup>
<wsc:SettingsGroup Header="{shcm:ResourceString Name=ViewPageLaunchGameAppearanceHeader}"> <wsc:SettingsGroup Header="{shcm:ResourceString Name=ViewPageLaunchGameAppearanceHeader}">
<wsc:Setting <wsc:Setting
Description="{shcm:ResourceString Name=ViewPageLaunchGameAppearanceExclusiveDescription}" Description="{shcm:ResourceString Name=ViewPageLaunchGameAppearanceExclusiveDescription}"
Header="{shcm:ResourceString Name=ViewPageLaunchGameAppearanceExclusiveHeader}" Header="{shcm:ResourceString Name=ViewPageLaunchGameAppearanceExclusiveHeader}"
Icon="&#xE740;"> Icon="&#xE740;">
<wsc:Setting.ActionContent> <wsc:Setting.ActionContent>
<ToggleSwitch <ToggleSwitch
Width="120" Width="120"
IsOn="{Binding Options.IsExclusive, Mode=TwoWay}" IsOn="{Binding Options.IsExclusive, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchSettingStyle}"/> Style="{StaticResource ToggleSwitchSettingStyle}"/>
</wsc:Setting.ActionContent> </wsc:Setting.ActionContent>
</wsc:Setting> </wsc:Setting>
<wsc:Setting <wsc:Setting
Description="{shcm:ResourceString Name=ViewPageLaunchGameAppearanceFullscreenDescription}" Description="{shcm:ResourceString Name=ViewPageLaunchGameAppearanceFullscreenDescription}"
Header="{shcm:ResourceString Name=ViewPageLaunchGameAppearanceFullscreenHeader}" Header="{shcm:ResourceString Name=ViewPageLaunchGameAppearanceFullscreenHeader}"
Icon="&#xE740;"> Icon="&#xE740;">
<wsc:Setting.ActionContent> <wsc:Setting.ActionContent>
<ToggleSwitch <ToggleSwitch
Width="120" Width="120"
IsOn="{Binding Options.IsFullScreen, Mode=TwoWay}" IsOn="{Binding Options.IsFullScreen, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchSettingStyle}"/> Style="{StaticResource ToggleSwitchSettingStyle}"/>
</wsc:Setting.ActionContent> </wsc:Setting.ActionContent>
</wsc:Setting> </wsc:Setting>
<wsc:Setting <wsc:Setting
Description="{shcm:ResourceString Name=ViewPageLaunchGameAppearanceBorderlessDescription}" Description="{shcm:ResourceString Name=ViewPageLaunchGameAppearanceBorderlessDescription}"
Header="{shcm:ResourceString Name=ViewPageLaunchGameAppearanceBorderlessHeader}" Header="{shcm:ResourceString Name=ViewPageLaunchGameAppearanceBorderlessHeader}"
Icon="&#xE737;"> Icon="&#xE737;">
<wsc:Setting.ActionContent> <wsc:Setting.ActionContent>
<ToggleSwitch <ToggleSwitch
Width="120" Width="120"
IsOn="{Binding Options.IsBorderless, Mode=TwoWay}" IsOn="{Binding Options.IsBorderless, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchSettingStyle}"/> Style="{StaticResource ToggleSwitchSettingStyle}"/>
</wsc:Setting.ActionContent> </wsc:Setting.ActionContent>
</wsc:Setting> </wsc:Setting>
<wsc:Setting <wsc:Setting
Margin="0,6,0,0" Margin="0,6,0,0"
Description="{shcm:ResourceString Name=ViewPageLaunchGameAppearanceScreenWidthDescription}" Description="{shcm:ResourceString Name=ViewPageLaunchGameAppearanceScreenWidthDescription}"
Header="{shcm:ResourceString Name=ViewPageLaunchGameAppearanceScreenWidthHeader}" Header="{shcm:ResourceString Name=ViewPageLaunchGameAppearanceScreenWidthHeader}"
Icon="&#xE76F;"> Icon="&#xE76F;">
<wsc:Setting.ActionContent> <wsc:Setting.ActionContent>
<NumberBox Width="156" Value="{Binding Options.ScreenWidth, Mode=TwoWay}"/> <NumberBox Width="156" Value="{Binding Options.ScreenWidth, Mode=TwoWay}"/>
</wsc:Setting.ActionContent> </wsc:Setting.ActionContent>
</wsc:Setting> </wsc:Setting>
<wsc:Setting <wsc:Setting
Description="{shcm:ResourceString Name=ViewPageLaunchGameAppearanceScreenHeightDescription}" Description="{shcm:ResourceString Name=ViewPageLaunchGameAppearanceScreenHeightDescription}"
Header="{shcm:ResourceString Name=ViewPageLaunchGameAppearanceScreenHeightHeader}" Header="{shcm:ResourceString Name=ViewPageLaunchGameAppearanceScreenHeightHeader}"
Icon="&#xE784;"> Icon="&#xE784;">
<wsc:Setting.ActionContent> <wsc:Setting.ActionContent>
<NumberBox Width="156" Value="{Binding Options.ScreenHeight, Mode=TwoWay}"/> <NumberBox Width="156" Value="{Binding Options.ScreenHeight, Mode=TwoWay}"/>
</wsc:Setting.ActionContent> </wsc:Setting.ActionContent>
</wsc:Setting> </wsc:Setting>
<wsc:Setting <wsc:Setting
Description="{shcm:ResourceString Name=ViewPageLaunchGameMonitorsDescription}" Description="{shcm:ResourceString Name=ViewPageLaunchGameMonitorsDescription}"
Header="{shcm:ResourceString Name=ViewPageLaunchGameMonitorsHeader}" Header="{shcm:ResourceString Name=ViewPageLaunchGameMonitorsHeader}"
Icon="&#xE975;"> Icon="&#xE975;">
<wsc:Setting.ActionContent> <wsc:Setting.ActionContent>
<ComboBox <ComboBox
DisplayMemberPath="Name" DisplayMemberPath="Name"
ItemsSource="{Binding Options.Monitors}" ItemsSource="{Binding Options.Monitors}"
SelectedItem="{Binding Options.Monitor, Mode=TwoWay}"/> SelectedItem="{Binding Options.Monitor, Mode=TwoWay}"/>
</wsc:Setting.ActionContent> </wsc:Setting.ActionContent>
</wsc:Setting> </wsc:Setting>
</wsc:SettingsGroup> </wsc:SettingsGroup>
<wsc:SettingsGroup Header="{shcm:ResourceString Name=ViewPageLaunchGameAdvanceHeader}" IsEnabled="{Binding IsElevated}"> <wsc:SettingsGroup Header="{shcm:ResourceString Name=ViewPageLaunchGameAdvanceHeader}" IsEnabled="{Binding IsElevated}">
<InfoBar <InfoBar
IsClosable="False" IsClosable="False"
IsOpen="{Binding IsElevated}" IsOpen="{Binding IsElevated}"
Message="{shcm:ResourceString Name=ViewPageLaunchGameAdvanceHint}" Message="{shcm:ResourceString Name=ViewPageLaunchGameAdvanceHint}"
Severity="Error"/> Severity="Error"/>
<wsc:Setting <wsc:Setting
Description="{shcm:ResourceString Name=ViewPageLaunchGameUnlockFpsDescription}" Description="{shcm:ResourceString Name=ViewPageLaunchGameUnlockFpsDescription}"
Header="{shcm:ResourceString Name=ViewPageLaunchGameUnlockFpsHeader}" Header="{shcm:ResourceString Name=ViewPageLaunchGameUnlockFpsHeader}"
Icon="&#xE785;"> Icon="&#xE785;">
<wsc:Setting.ActionContent> <wsc:Setting.ActionContent>
<ToggleSwitch <ToggleSwitch
Width="120" Width="120"
IsOn="{Binding Options.UnlockFps, Mode=TwoWay}" IsOn="{Binding Options.UnlockFps, Mode=TwoWay}"
OffContent="{shcm:ResourceString Name=ViewPageLaunchGameUnlockFpsOff}" OffContent="{shcm:ResourceString Name=ViewPageLaunchGameUnlockFpsOff}"
OnContent="{shcm:ResourceString Name=ViewPageLaunchGameUnlockFpsOn}" OnContent="{shcm:ResourceString Name=ViewPageLaunchGameUnlockFpsOn}"
Style="{StaticResource ToggleSwitchSettingStyle}"/> Style="{StaticResource ToggleSwitchSettingStyle}"/>
</wsc:Setting.ActionContent> </wsc:Setting.ActionContent>
</wsc:Setting> </wsc:Setting>
<wsc:Setting Header="{shcm:ResourceString Name=ViewPageLaunchGameSetFpsHeader}"> <wsc:Setting Header="{shcm:ResourceString Name=ViewPageLaunchGameSetFpsHeader}">
<wsc:Setting.Description> <wsc:Setting.Description>
<StackPanel> <StackPanel>
<TextBlock Text="{shcm:ResourceString Name=ViewPageLaunchGameSetFpsDescription}"/> <TextBlock Text="{shcm:ResourceString Name=ViewPageLaunchGameSetFpsDescription}"/>
<TextBlock Text="{Binding Options.TargetFps}"/> <TextBlock Text="{Binding Options.TargetFps}"/>
</StackPanel> </StackPanel>
</wsc:Setting.Description> </wsc:Setting.Description>
<wsc:Setting.ActionContent> <wsc:Setting.ActionContent>
<Slider <Slider
Width="400" Width="400"
Maximum="360" Maximum="360"
Minimum="60" Minimum="60"
Value="{Binding Options.TargetFps, Mode=TwoWay}"/> Value="{Binding Options.TargetFps, Mode=TwoWay}"/>
</wsc:Setting.ActionContent> </wsc:Setting.ActionContent>
</wsc:Setting> </wsc:Setting>
</wsc:SettingsGroup> </wsc:SettingsGroup>
</StackPanel> </StackPanel>
</Grid> </Grid>
</ScrollViewer>
<mxi:Interaction.Behaviors> </PivotItem>
<cwub:AutoFocusBehavior/> <PivotItem Header="{shcm:ResourceString Name=ViewPageLaunchGameResourceHeader}">
</mxi:Interaction.Behaviors> <Grid>
</ScrollViewer> <ScrollViewer Visibility="{Binding GameResource, Converter={StaticResource EmptyObjectToBoolConverter}}">
<Grid Grid.Row="1" VerticalAlignment="Bottom"> <Grid>
<Button <Grid.ColumnDefinitions>
Grid.Column="3" <ColumnDefinition MaxWidth="1000"/>
Width="100" <ColumnDefinition Width="auto"/>
Height="80" </Grid.ColumnDefinitions>
MinWidth="80" <StackPanel>
Margin="24" <shvc:LaunchGameResourceExpander
HorizontalAlignment="Right" Margin="16,16,16,0"
Command="{Binding LaunchCommand}" DataContext="{Binding GameResource.PreDownloadGame.Latest, Mode=OneWay}"
Style="{StaticResource AccentButtonStyle}"> Header="{shcm:ResourceString Name=ViewPageLaunchGameResourcePreDownloadHeader}"
<StackPanel> Visibility="{Binding FallbackValue={StaticResource VisibilityCollapsed}, Converter={StaticResource EmptyObjectToVisibilityConverter}}"/>
<FontIcon FontSize="36" Glyph="&#xE7FC;"/> <shvc:LaunchGameResourceExpander
<TextBlock Margin="0,4,0,0" Text="{shcm:ResourceString Name=ViewPageLaunchGameAction}"/> Margin="16,16,16,0"
</StackPanel> DataContext="{Binding GameResource.Game.Latest, Mode=OneWay}"
</Button> Header="{shcm:ResourceString Name=ViewPageLaunchGameResourceLatestHeader}"/>
</Grid> <ItemsControl Margin="0,0,0,16" ItemsSource="{Binding GameResource.Game.Diffs, Mode=OneWay}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<shvc:LaunchGameResourceExpander
Margin="16,16,16,0"
DataContext="{Binding Mode=OneWay}"
Header="{shcm:ResourceString Name=ViewPageLaunchGameResourceDiffHeader}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Grid>
</ScrollViewer>
<shvc:LoadingView IsLoading="{Binding GameResource, Converter={StaticResource EmptyObjectToBoolRevertConverter}}"/>
</Grid>
</PivotItem>
</Pivot>
</Grid> </Grid>
</shc:ScopedPage> </shc:ScopedPage>

View File

@@ -15,6 +15,7 @@ using Snap.Hutao.Service.Game;
using Snap.Hutao.Service.Navigation; using Snap.Hutao.Service.Navigation;
using Snap.Hutao.Service.User; using Snap.Hutao.Service.User;
using Snap.Hutao.View.Dialog; using Snap.Hutao.View.Dialog;
using Snap.Hutao.Web.Hoyolab.SdkStatic.Hk4e.Launcher;
using Snap.Hutao.Web.Hoyolab.Takumi.Binding; using Snap.Hutao.Web.Hoyolab.Takumi.Binding;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.IO; using System.IO;
@@ -35,7 +36,6 @@ internal sealed class LaunchGameViewModel : Abstraction.ViewModel
private readonly IServiceProvider serviceProvider; private readonly IServiceProvider serviceProvider;
private readonly IGameService gameService; private readonly IGameService gameService;
private readonly AppDbContext appDbContext;
private readonly IMemoryCache memoryCache; private readonly IMemoryCache memoryCache;
private readonly List<LaunchScheme> knownSchemes = LaunchScheme.KnownSchemes.ToList(); private readonly List<LaunchScheme> knownSchemes = LaunchScheme.KnownSchemes.ToList();
@@ -43,6 +43,7 @@ internal sealed class LaunchGameViewModel : Abstraction.ViewModel
private LaunchScheme? selectedScheme; private LaunchScheme? selectedScheme;
private ObservableCollection<GameAccount>? gameAccounts; private ObservableCollection<GameAccount>? gameAccounts;
private GameAccount? selectedGameAccount; private GameAccount? selectedGameAccount;
private GameResource? gameResource;
/// <summary> /// <summary>
/// 构造一个新的启动游戏视图模型 /// 构造一个新的启动游戏视图模型
@@ -51,7 +52,6 @@ internal sealed class LaunchGameViewModel : Abstraction.ViewModel
public LaunchGameViewModel(IServiceProvider serviceProvider) public LaunchGameViewModel(IServiceProvider serviceProvider)
{ {
gameService = serviceProvider.GetRequiredService<IGameService>(); gameService = serviceProvider.GetRequiredService<IGameService>();
appDbContext = serviceProvider.GetRequiredService<AppDbContext>();
memoryCache = serviceProvider.GetRequiredService<IMemoryCache>(); memoryCache = serviceProvider.GetRequiredService<IMemoryCache>();
Options = serviceProvider.GetRequiredService<LaunchOptions>(); Options = serviceProvider.GetRequiredService<LaunchOptions>();
this.serviceProvider = serviceProvider; this.serviceProvider = serviceProvider;
@@ -71,7 +71,19 @@ internal sealed class LaunchGameViewModel : Abstraction.ViewModel
/// <summary> /// <summary>
/// 当前选择的服务器方案 /// 当前选择的服务器方案
/// </summary> /// </summary>
public LaunchScheme? SelectedScheme { get => selectedScheme; set => SetProperty(ref selectedScheme, value); } public LaunchScheme? SelectedScheme
{
get => selectedScheme; set
{
if (SetProperty(ref selectedScheme, value))
{
if (value != null)
{
UpdateGameResourceAsync(value).SafeForget();
}
}
}
}
/// <summary> /// <summary>
/// 游戏账号集合 /// 游戏账号集合
@@ -88,6 +100,11 @@ internal sealed class LaunchGameViewModel : Abstraction.ViewModel
/// </summary> /// </summary>
public LaunchOptions Options { get; } public LaunchOptions Options { get; }
/// <summary>
/// 游戏资源
/// </summary>
public GameResource? GameResource { get => gameResource; set => SetProperty(ref gameResource, value); }
/// <summary> /// <summary>
/// 是否提权 /// 是否提权
/// </summary> /// </summary>
@@ -122,6 +139,7 @@ internal sealed class LaunchGameViewModel : Abstraction.ViewModel
/// <inheritdoc/> /// <inheritdoc/>
protected override async Task OpenUIAsync() protected override async Task OpenUIAsync()
{ {
await ThreadHelper.SwitchToBackgroundAsync();
if (File.Exists(gameService.GetGamePathSkipLocator())) if (File.Exists(gameService.GetGamePathSkipLocator()))
{ {
try try
@@ -131,6 +149,7 @@ internal sealed class LaunchGameViewModel : Abstraction.ViewModel
MultiChannel multi = gameService.GetMultiChannel(); MultiChannel multi = gameService.GetMultiChannel();
if (string.IsNullOrEmpty(multi.ConfigFilePath)) if (string.IsNullOrEmpty(multi.ConfigFilePath))
{ {
await ThreadHelper.SwitchToMainThreadAsync();
SelectedScheme = KnownSchemes.FirstOrDefault(s => s.Channel == multi.Channel && s.SubChannel == multi.SubChannel); SelectedScheme = KnownSchemes.FirstOrDefault(s => s.Channel == multi.Channel && s.SubChannel == multi.SubChannel);
} }
else else
@@ -138,8 +157,10 @@ internal sealed class LaunchGameViewModel : Abstraction.ViewModel
serviceProvider.GetRequiredService<IInfoBarService>().Warning(SH.ViewModelLaunchGameMultiChannelReadFail); serviceProvider.GetRequiredService<IInfoBarService>().Warning(SH.ViewModelLaunchGameMultiChannelReadFail);
} }
GameAccounts = await gameService.GetGameAccountCollectionAsync().ConfigureAwait(true); ObservableCollection<GameAccount> accounts = await gameService.GetGameAccountCollectionAsync().ConfigureAwait(false);
await ThreadHelper.SwitchToMainThreadAsync();
GameAccounts = accounts;
// Sync uid // Sync uid
if (memoryCache.TryGetValue(DesiredUid, out object? value) && value is string uid) if (memoryCache.TryGetValue(DesiredUid, out object? value) && value is string uid)
{ {
@@ -155,12 +176,28 @@ internal sealed class LaunchGameViewModel : Abstraction.ViewModel
else else
{ {
serviceProvider.GetRequiredService<IInfoBarService>().Warning(SH.ViewModelLaunchGamePathInvalid); serviceProvider.GetRequiredService<IInfoBarService>().Warning(SH.ViewModelLaunchGamePathInvalid);
await ThreadHelper.SwitchToMainThreadAsync();
await serviceProvider.GetRequiredService<INavigationService>() await serviceProvider.GetRequiredService<INavigationService>()
.NavigateAsync<View.Page.SettingPage>(INavigationAwaiter.Default, true) .NavigateAsync<View.Page.SettingPage>(INavigationAwaiter.Default, true)
.ConfigureAwait(false); .ConfigureAwait(false);
} }
} }
private async Task UpdateGameResourceAsync(LaunchScheme scheme)
{
await ThreadHelper.SwitchToBackgroundAsync();
Web.Response.Response<GameResource> response = await serviceProvider
.GetRequiredService<ResourceClient>()
.GetResourceAsync(scheme)
.ConfigureAwait(false);
if (response.IsOk())
{
await ThreadHelper.SwitchToMainThreadAsync();
GameResource = response.Data;
}
}
private async Task LaunchAsync() private async Task LaunchAsync()
{ {
IInfoBarService infoBarService = serviceProvider.GetRequiredService<IInfoBarService>(); IInfoBarService infoBarService = serviceProvider.GetRequiredService<IInfoBarService>();

View File

@@ -20,4 +20,9 @@ internal class PathMd5
/// </summary> /// </summary>
[JsonPropertyName("md5")] [JsonPropertyName("md5")]
public string Md5 { get; set; } = default!; public string Md5 { get; set; } = default!;
/// <summary>
/// 显示名称
/// </summary>
public string DisplayName { get => System.IO.Path.GetFileName(Path.ToUri().LocalPath); }
} }

View File

@@ -5,7 +5,6 @@ using System.Buffers.Binary;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using Windows.Graphics; using Windows.Graphics;
using Windows.Win32.Graphics.Gdi;
using Windows.Win32.System.Diagnostics.ToolHelp; using Windows.Win32.System.Diagnostics.ToolHelp;
using Windows.Win32.UI.WindowsAndMessaging; using Windows.Win32.UI.WindowsAndMessaging;