Compare commits

..

29 Commits

Author SHA1 Message Date
RMBGAME 67209f3861 🚧 Misc 2024-06-25 14:16:31 +08:00
RMBGAME 110c92d909 🐛⬆️ Avalonia 11.0-rc1 2024-06-24 14:26:48 +08:00
Aigio Liu cdc773ba74 📝 System.ArgumentException: Decoded string is not a valid IDN name. (Parameter 'unicode') 2024-06-16 00:48:32 +08:00
Aigio Liu 8ea8b73aab 🐛 System.ArgumentException: Decoded string is not a valid IDN name. (Parameter 'unicode')
at System.Globalization.IdnMapping.IcuGetAsciiCore(String unicodeString, Char* unicode, Int32 count)
   at System.Globalization.IdnMapping.GetAscii(String unicode, Int32 index, Int32 count)
   at System.Security.Cryptography.X509Certificates.SubjectAlternativeNameBuilder.AddDnsName(String dnsName)
   at BD.WTTS.Services.Implementation.CertGenerator.Add(SubjectAlternativeNameBuilder builder, String name)
2024-06-16 00:46:51 +08:00
RMBGAME 0614e172b8 ✨ 账号切换新增显示用户名设置项 2024-06-07 23:58:49 +08:00
yingpanwang 4c73a5b622 Feautre/joinsteamauthenticator (#3362)
* ✨ 导入steam令牌 新增添加 联合steam 令牌方式
2024-06-06 15:01:15 +08:00
RMBGAME 34341172b8 🚧 ItemsRepeater 2024-05-29 19:15:59 +08:00
RMBGAME 6813ed9ece ⬆️ FA 2.1.0-preview5 2024-05-27 18:23:02 +08:00
RMBGAME 3eb916e78a 🐛 蒸汽平台切换账号支持 2024-05-18 21:37:25 +08:00
RMBGAME 7424d05f54 💄 Avalonia_Edit 2024-05-17 20:27:04 +08:00
RMBGAME 76829b0ca2 🐛 fixed 挂时长启动暂停按钮显示问题 2024-05-10 17:24:43 +08:00
RMBGAME bbe98f68f6 🐛 游戏已加速情况下启动程序闪退问题修复 2024-05-06 19:04:46 +08:00
john.jiang 96025c9ef5 🎨 fixs 2024-05-06 17:12:18 +08:00
john.jiang 2fb12f1b7f 🎨 修复快速掉卡模式剩最后一个游戏闪退Bug 2024-05-06 17:07:07 +08:00
Mossimo 542b528b93 🐛 修复 Ubuntu 版本文件不存在中断问题 2024-04-30 16:28:23 +08:00
RMBGAME 0a4326924d 💄 修复加速模式文本显示错误 2024-04-30 16:13:49 +08:00
john.jiang e8a9990354 🎨 挂卡列表虚拟化缓存加长 2024-04-30 15:25:43 +08:00
Aigio Liu 4e72f9ccf9 🐛 ClickAdvertisement 2024-04-30 13:54:13 +08:00
Aigio Liu 6df6ed93cb 🐛 ClickAdvertisement 2024-04-30 13:42:09 +08:00
Aigio Liu 605beeb918 🐛 CopyToClipboardCommand 2024-04-30 13:38:13 +08:00
Aigio Liu 2bdfbefda9 🐛 OpenAuthUrl 2024-04-30 13:30:34 +08:00
Aigio Liu 6747549cbc 🐛 App.OpenBrowserCommand & IPartialGameAccountSettings null 2024-04-30 12:43:47 +08:00
Mossimo 0d4c0b27f7 🐛 fix 修复2月与新版本差异 2024-04-30 11:58:31 +08:00
Mossimo c501066a3d 🐛 fix 回退 websocket macos 使用 url 协议 2024-04-30 11:47:02 +08:00
john.jiang 57a6b24dad 🎨 修复挂卡价格显示 2024-04-30 11:40:37 +08:00
john.jiang 143011fbd0 🎨 挂卡帐号不一致 Toast 警告,账号登录页登陆成功先跳转主页再获取数据 2024-04-30 11:23:34 +08:00
RMBGAME 11bc9cd440 💄 略微缩减标题栏高度 2024-04-30 00:02:06 +08:00
RMBGAME 72e9068571 💄 简单的加速疑难解答 2024-04-29 19:28:28 +08:00
yingpanwang 5842d5f80f Merge pull request #3321 from BeyondDimension/fix/authenticator-ui
🐛 修复替换令牌时恢复代码不显示的问题
2024-04-29 18:08:06 +08:00
67 changed files with 2342 additions and 1381 deletions
+3 -1
View File
@@ -213,7 +213,9 @@ Get_NewVer() {
sleep 1
#本地版本 Hash
o_sha384=$(cat "AppVer")
if [ -f "AppVer" ]; then
o_sha384=$(cat "AppVer")
fi
if [ -e "AppVer" ]; then
if [ "${o_sha384,,}" = "${n_sha384,,}" ]; then
Show_Run "已是最新版本,是否启动程序?"
+18
View File
@@ -496,6 +496,15 @@
"Summary": "账号平台设置集合",
"IsRegionOrEndregion": null,
"IsValueType": null
},
{
"TypeName": "bool",
"PropertyName": "IsShowAccountName",
"DefaultValue": "false",
"DefaultValueIsConst": false,
"Summary": "是否显示账号用户名",
"IsRegionOrEndregion": null,
"IsValueType": null
}
],
"Usings": ""
@@ -970,6 +979,15 @@
"Summary": "自定义 DNS over HTTPS 地址",
"IsRegionOrEndregion": null,
"IsValueType": null
},
{
"TypeName": "int",
"PropertyName": "AcceleratorTabsSelectedIndex",
"DefaultValue": "0",
"DefaultValueIsConst": false,
"Summary": "加速页面 Tab 选项卡选中下标",
"IsRegionOrEndregion": null,
"IsValueType": null
}
],
"Usings": ""
@@ -81,8 +81,10 @@
<PackageReference Include="Avalonia" />
<PackageReference Include="Avalonia.ReactiveUI" />
<PackageReference Include="Avalonia.Controls.DataGrid" />
<PackageReference Include="Avalonia.Controls.ItemsRepeater" />
<PackageReference Include="Avalonia.Xaml.Behaviors" />
<!--<PackageReference Include="Avalonia.AvaloniaEdit" />-->
<PackageReference Include="Avalonia.AvaloniaEdit" />
<PackageReference Include="AvaloniaEdit.TextMate" />
<!--<PackageReference Include="Markdown.Avalonia" />-->
<PackageReference Include="FluentAvaloniaUI" />
<PackageReference Include="LiveChartsCore.SkiaSharpView.Avalonia" />
+12 -2
View File
@@ -11,6 +11,12 @@ public sealed partial class App : Application
{
const string TAG = "AvaApp";
public App()
{
OpenBrowserCommand = ReactiveCommand.Create<object?>(OpenBrowserCommandCore);
CopyToClipboardCommand = ReactiveCommand.Create<object?>(CopyToClipboardCommandCore);
}
/// <summary>
/// 获取当前主窗口
/// </summary>
@@ -225,7 +231,9 @@ public sealed partial class App : Application
public static FontFamily DefaultFontFamily => _DefaultFontFamily.Value;
public async void OpenBrowserCommand(object? url)
public ICommand OpenBrowserCommand { get; }
public async void OpenBrowserCommandCore(object? url)
{
try
{
@@ -256,7 +264,9 @@ public sealed partial class App : Application
}
}
public async void CopyToClipboardCommand(object text)
public ICommand CopyToClipboardCommand { get; }
public async void CopyToClipboardCommandCore(object? text)
{
try
{
@@ -6,8 +6,8 @@
x:CompileBindings="True">
<Styles.Resources>
<ResourceDictionary>
<sys:Double x:Key="TitleBarHeight">60</sys:Double>
<Thickness x:Key="TitleBarAfterMargin">0,60,0,0</Thickness>
<sys:Double x:Key="TitleBarHeight">50</sys:Double>
<Thickness x:Key="TitleBarAfterMargin">0,50,0,0</Thickness>
<sys:Double x:Key="SplashScreenImageWidth">100</sys:Double>
<Thickness x:Key="PageMargin">10</Thickness>
@@ -87,7 +87,7 @@
<Setter Property="CornerRadius" Value="{DynamicResource ControlCornerRadius}" />
<Setter Property="Template">
<ControlTemplate>
<ui:FABorder
<Border
Name="Root"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
@@ -101,19 +101,19 @@
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
RecognizesAccessKey="True" />
</ui:FABorder>
</Border>
</ControlTemplate>
</Setter>
<Style Selector="^:pointerover">
<Style Selector="^ /template/ ui|FABorder#Root">
<Style Selector="^ /template/ Border#Root">
<Setter Property="Background" Value="{DynamicResource SubtleFillColorSecondaryBrush}" />
</Style>
</Style>
<Style Selector="^:pressed">
<Style Selector="^ /template/ ui|FABorder#Root">
<Style Selector="^ /template/ Border#Root">
<Setter Property="Background" Value="{DynamicResource SubtleFillColorTertiaryBrush}" />
</Style>
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
@@ -122,7 +122,7 @@
</Style>
<Style Selector="^:disabled">
<Style Selector="^ /template/ ui|FABorder#Root">
<Style Selector="^ /template/ Border#Root">
<Setter Property="Background" Value="{DynamicResource SubtleFillColorDisabledBrush}" />
</Style>
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
@@ -131,7 +131,7 @@
</Style>
<Style Selector="^:checked">
<Style Selector="^ /template/ ui|FABorder#Root">
<Style Selector="^ /template/ Border#Root">
<Setter Property="Background" Value="{DynamicResource ToggleButtonBackgroundChecked}" />
</Style>
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
@@ -140,7 +140,7 @@
<Style Selector="^:pointerover">
<Style Selector="^ /template/ ui|FABorder#Root">
<Style Selector="^ /template/ Border#Root">
<Setter Property="Background" Value="{DynamicResource ToggleButtonBackgroundCheckedPointerOver}" />
</Style>
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
@@ -149,7 +149,7 @@
</Style>
<Style Selector="^:pressed">
<Style Selector="^ /template/ ui|FABorder#Root">
<Style Selector="^ /template/ Border#Root">
<Setter Property="Background" Value="{DynamicResource ToggleButtonBackgroundCheckedPressed}" />
</Style>
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
@@ -158,7 +158,7 @@
</Style>
<Style Selector="^:disabled">
<Style Selector="^ /template/ ui|FABorder#Root">
<Style Selector="^ /template/ Border#Root">
<Setter Property="Background" Value="{DynamicResource SubtleFillColorDisabledBrush}" />
</Style>
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
@@ -168,19 +168,19 @@
</Style>
<Style Selector="^:indeterminate">
<Style Selector="^ /template/ ui|FABorder#Root">
<Style Selector="^ /template/ Border#Root">
<Setter Property="Background" Value="{DynamicResource SubtleFillColorTransparentBrush}" />
</Style>
<Style Selector="^:pointerover">
<Style Selector="^ /template/ ui|FABorder#Root">
<Style Selector="^ /template/ Border#Root">
<Setter Property="Background" Value="{DynamicResource SubtleFillColorSecondaryBrush}" />
</Style>
</Style>
<Style Selector="^:pressed">
<Style Selector="^ /template/ ui|FABorder#Root">
<Style Selector="^ /template/ Border#Root">
<Setter Property="Background" Value="{DynamicResource SubtleFillColorTertiaryBrush}" />
</Style>
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
@@ -189,7 +189,7 @@
</Style>
<Style Selector="^:disabled">
<Style Selector="^ /template/ ui|FABorder#Root">
<Style Selector="^ /template/ Border#Root">
<Setter Property="Background" Value="{DynamicResource SubtleFillColorDisabledBrush}" />
</Style>
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
@@ -214,7 +214,7 @@
<Style Selector="Button.Plain:pointerover">
<Setter Property="Background" Value="Transparent" />
</Style>
<Style Selector="Button.Plain:pointerover /template/ ui|FABorder#Root">
<Style Selector="Button.Plain:pointerover /template/ Border#Root">
<Setter Property="Background" Value="Transparent" />
</Style>
<Style Selector="Button.Plain:pointerover /template/ ContentPresenter">
@@ -63,14 +63,13 @@
Height="10"
HorizontalAlignment="Center"
VerticalAlignment="Bottom">
<ItemsRepeater Name="Swiper" IsVisible="False">
<ItemsRepeater.Layout>
<StackLayout
DisableVirtualization="True"
Orientation="Horizontal"
Spacing="8" />
</ItemsRepeater.Layout>
<ItemsRepeater.ItemTemplate>
<ItemsControl Name="Swiper" IsVisible="False">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" Spacing="8" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<DataTemplate.DataType>
<x:Type x:TypeArguments="x:Int32, x:String" TypeName="generic:KeyValuePair" />
@@ -91,8 +90,8 @@
StrokeThickness="0" />
</Button>
</DataTemplate>
</ItemsRepeater.ItemTemplate>
</ItemsRepeater>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Panel>
</Grid>
</Border>
@@ -46,19 +46,19 @@
<Setter Property="Template">
<ControlTemplate>
<StackPanel>
<ui:FABorder
<Border
Name="LayoutRoot"
Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}">
<ui:FABorder.Transitions>
<Border.Transitions>
<Transitions>
<BrushTransition Property="Background" Duration="00:00:00.083" />
<BrushTransition Property="BorderBrush" Duration="00:00:00.083" />
</Transitions>
</ui:FABorder.Transitions>
</Border.Transitions>
<Grid MinHeight="{TemplateBinding MinHeight}" ColumnDefinitions="Auto,*,Auto,Auto">
<Viewbox
Name="IconHost"
@@ -113,7 +113,7 @@
VerticalAlignment="Center"
FontSize="18" />
</Grid>
</ui:FABorder>
</Border>
<ContentPresenter
Name="ExpandedContentPresenter"
@@ -144,10 +144,10 @@
<Setter Property="IsVisible" Value="False" />
</Style>
<Style Selector="spp|OptionsDisplayItem /template/ ui|FABorder#LayoutRoot:pointerover">
<Style Selector="spp|OptionsDisplayItem /template/ Border#LayoutRoot:pointerover">
<Setter Property="Background" Value="{DynamicResource ControlFillColorSecondaryBrush}" />
</Style>
<Style Selector="spp|OptionsDisplayItem:pressed /template/ ui|FABorder#LayoutRoot:pointerover">
<Style Selector="spp|OptionsDisplayItem:pressed /template/ Border#LayoutRoot:pointerover">
<Setter Property="Background" Value="{DynamicResource ControlFillColorTertiaryBrush}" />
</Style>
@@ -179,7 +179,7 @@
<Setter Property="CornerRadius" Value="{Binding CornerRadius, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource BottomCornerRadiusFilterConverter}}" />
</Style>
<Style Selector="spp|OptionsDisplayItem:expanded /template/ ui|FABorder#LayoutRoot">
<Style Selector="spp|OptionsDisplayItem:expanded /template/ Border#LayoutRoot">
<Setter Property="CornerRadius" Value="{Binding CornerRadius, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource TopCornerRadiusFilterConverter}}" />
</Style>
@@ -195,19 +195,19 @@
<Style Selector="spp|OptionsDisplayItem.Vertical">
<Setter Property="Template">
<ControlTemplate>
<ui:FABorder
<Border
Name="LayoutRoot"
Padding="12"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}">
<ui:FABorder.Transitions>
<Border.Transitions>
<Transitions>
<BrushTransition Property="Background" Duration="00:00:00.083" />
<BrushTransition Property="BorderBrush" Duration="00:00:00.083" />
</Transitions>
</ui:FABorder.Transitions>
</Border.Transitions>
<Grid RowDefinitions="*,*">
<Border
Width="72"
@@ -241,7 +241,7 @@
TextWrapping="Wrap" />
</StackPanel>
</Grid>
</ui:FABorder>
</Border>
</ControlTemplate>
</Setter>
</Style>
@@ -38,18 +38,18 @@
<Setter Property="MinHeight" Value="{DynamicResource SettingsExpanderItemMinHeight}" />
<Setter Property="Template">
<ControlTemplate>
<ui:FABorder
<Border
Name="Root"
Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ui:FABorder.Transitions>
<Border.Transitions>
<Transitions>
<BrushTransition Property="Background" Duration="00:00:00.083" />
<BrushTransition Property="BorderBrush" Duration="00:00:00.083" />
</Transitions>
</ui:FABorder.Transitions>
</Border.Transitions>
<Grid ColumnDefinitions="*,Auto,Auto" RowDefinitions="*,Auto">
<Viewbox
@@ -102,7 +102,7 @@
<ContentPresenter Name="ExpandChevronActionIconContainer" Content="{Binding TemplateSettings.ActionIcon, RelativeSource={RelativeSource TemplatedParent}}" />
</Viewbox>
</Grid>
</ui:FABorder>
</Border>
</ControlTemplate>
</Setter>
@@ -110,7 +110,7 @@
<Setter Property="IsVisible" Value="False" />
</Style>
<Style Selector="^:nth-last-child(1) /template/ ui|FABorder#Root">
<Style Selector="^:nth-last-child(1) /template/ Border#Root">
<Setter Property="CornerRadius" Value="{Binding Source={StaticResource ControlCornerRadius}, Converter={StaticResource BottomCornerRadiusFilterConverter}}" />
</Style>
@@ -152,11 +152,11 @@
</Style>
<Style Selector="^:allowClick">
<Style Selector="^:pointerover /template/ ui|FABorder#Root">
<Style Selector="^:pointerover /template/ Border#Root">
<Setter Property="Background" Value="{DynamicResource ControlFillColorSecondaryBrush}" />
<Setter Property="BorderBrush" Value="{DynamicResource ControlFillColorSecondaryBrush}" />
</Style>
<Style Selector="^:pressed /template/ ui|FABorder#Root">
<Style Selector="^:pressed /template/ Border#Root">
<Setter Property="Background" Value="{DynamicResource ControlFillColorTertiaryBrush}" />
<Setter Property="BorderBrush" Value="{DynamicResource ControlStrokeColorDefaultBrush}" />
<Setter Property="TextElement.Foreground" Value="{DynamicResource TextFillColorSecondaryBrush}" />
@@ -164,7 +164,7 @@
</Style>
<Style Selector="^:disabled">
<Style Selector="^ /template/ ui|FABorder#Root">
<Style Selector="^ /template/ Border#Root">
<Setter Property="Background" Value="{DynamicResource ControlFillColorDisabledBrush}" />
<Setter Property="BorderBrush" Value="{DynamicResource ControlStrokeColorDefaultBrush}" />
<Setter Property="TextElement.Foreground" Value="{DynamicResource TextFillColorDisabledBrush}" />
@@ -95,7 +95,7 @@
<Setter Property="Template">
<ControlTemplate>
<LayoutTransformControl Name="PART_LayoutTransformControl" UseRenderTransform="True">
<ui:FABorder
<Border
Name="ContentRoot"
VerticalAlignment="Top"
BorderBrush="{DynamicResource InfoBarBorderBrush}"
@@ -205,13 +205,13 @@
</Button>
</Grid>
</Panel>
</ui:FABorder>
</Border>
</LayoutTransformControl>
</ControlTemplate>
</Setter>
<Style Selector="^:informational">
<Style Selector="^ /template/ ui|FABorder#ContentRoot">
<Style Selector="^ /template/ Border#ContentRoot">
<!--<Setter Property="Background" Value="{DynamicResource InfoBarInformationalSeverityBackgroundBrush}" />-->
<Setter Property="Background" Value="{DynamicResource SolidBackgroundFillColorBaseBrush}" />
</Style>
@@ -226,7 +226,7 @@
</Style>
<Style Selector="^:error">
<Style Selector="^ /template/ ui|FABorder#ContentRoot">
<Style Selector="^ /template/ Border#ContentRoot">
<Setter Property="Background" Value="{DynamicResource InfoBarErrorSeverityBackgroundBrush}" />
</Style>
<Style Selector="^ /template/ Ellipse#IconBackground">
@@ -241,7 +241,7 @@
</Style>
<Style Selector="^:warning">
<Style Selector="^ /template/ ui|FABorder#ContentRoot">
<Style Selector="^ /template/ Border#ContentRoot">
<Setter Property="Background" Value="{DynamicResource InfoBarWarningSeverityBackgroundBrush}" />
</Style>
<Style Selector="^ /template/ Ellipse#IconBackground">
@@ -255,7 +255,7 @@
</Style>
<Style Selector="^:success">
<Style Selector="^ /template/ ui|FABorder#ContentRoot">
<Style Selector="^ /template/ Border#ContentRoot">
<Setter Property="Background" Value="{DynamicResource InfoBarSuccessSeverityBackgroundBrush}" />
</Style>
<Style Selector="^ /template/ Ellipse#IconBackground">
@@ -294,7 +294,7 @@
</Style>
<!-- Visible -->
<Style Selector="^:hidden /template/ ui|FABorder#ContentRoot">
<Style Selector="^:hidden /template/ Border#ContentRoot">
<Setter Property="IsVisible" Value="False" />
</Style>
@@ -75,7 +75,7 @@
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="Template">
<ControlTemplate>
<ui:FABorder
<Border
Name="Root"
VerticalAlignment="{TemplateBinding VerticalAlignment}"
Background="{TemplateBinding Background}"
@@ -83,19 +83,19 @@
BorderThickness="1"
CornerRadius="{TemplateBinding CornerRadius}"
TemplatedControl.IsTemplateFocusTarget="True">
<ui:FABorder.Transitions>
<Border.Transitions>
<Transitions>
<BrushTransition Property="Background" Duration="00:00:00.083" />
</Transitions>
</ui:FABorder.Transitions>
</Border.Transitions>
<Panel>
<ui:FABorder
<Border
Name="Hover"
Margin="3"
Background="Transparent"
CornerRadius="{TemplateBinding CornerRadius}">
<ui:FABorder.Transitions>
<Border.Transitions>
<Transitions>
<BrushTransition Property="Background" Duration="00:00:00.083" />
<TransformOperationsTransition
@@ -103,8 +103,8 @@
Property="RenderTransform"
Duration="00:00:00.167" />
</Transitions>
</ui:FABorder.Transitions>
</ui:FABorder>
</Border.Transitions>
</Border>
<ContentPresenter
Name="PART_ContentPresenter"
@@ -139,19 +139,19 @@
</Rectangle>
</Panel>
</ui:FABorder>
</Border>
</ControlTemplate>
</Setter>
<Style Selector="^:pointerover">
<Style Selector="^ /template/ ui|FABorder#Hover">
<Style Selector="^ /template/ Border#Hover">
<Setter Property="Background" Value="{DynamicResource SubtleFillColorSecondaryBrush}" />
</Style>
</Style>
<Style Selector="^:pressed">
<Style Selector="^ /template/ ui|FABorder#Hover">
<Style Selector="^ /template/ Border#Hover">
<Setter Property="Background" Value="{DynamicResource SubtleFillColorTertiaryBrush}" />
<Setter Property="RenderTransform" Value="scale(0.96)" />
</Style>
@@ -161,10 +161,10 @@
</Style>
<Style Selector="^:selected">
<Style Selector="^ /template/ ui|FABorder#Hover">
<Style Selector="^ /template/ Border#Hover">
<Setter Property="IsVisible" Value="False" />
</Style>
<Style Selector="^ /template/ ui|FABorder#Root">
<Style Selector="^ /template/ Border#Root">
<Setter Property="Background" Value="{DynamicResource ControlFillColorDefaultBrush}" />
<Setter Property="BorderBrush" Value="{DynamicResource ControlElevationBorderBrush}" />
</Style>
@@ -181,10 +181,10 @@
</Style>
<Style Selector="^:disabled">
<Style Selector="^ /template/ ui|FABorder#Hover">
<Style Selector="^ /template/ Border#Hover">
<Setter Property="IsVisible" Value="False" />
</Style>
<Style Selector="^ /template/ ui|FABorder#Root">
<Style Selector="^ /template/ Border#Root">
<Setter Property="Background" Value="{DynamicResource ControlFillColorDisabledBrush}" />
<Setter Property="BorderBrush" Value="{DynamicResource ControlAltFillColorSecondaryBrush}" />
</Style>
@@ -80,7 +80,7 @@
<Setter Property="Template">
<ControlTemplate>
<Panel Name="LayoutRoot" Background="{x:Null}">
<ui:FABorder
<Border
Name="ContentRoot"
MinWidth="{DynamicResource TaskDialogMinWidth}"
MinHeight="{DynamicResource TaskDialogMinHeight}"
@@ -216,7 +216,7 @@
</ItemsControl>
</Border>
</Grid>
</ui:FABorder>
</Border>
</Panel>
</ControlTemplate>
</Setter>
@@ -303,7 +303,7 @@
<Style Selector="^ /template/ Panel#LayoutRoot">
<Setter Property="Background" Value="{DynamicResource TaskDialogSmokeFill}" />
</Style>
<Style Selector="^ /template/ ui|FABorder#ContentRoot">
<Style Selector="^ /template/ Border#ContentRoot">
<Setter Property="BorderBrush" Value="{DynamicResource TaskDialogBorderBrush}" />
<Setter Property="CornerRadius" Value="{DynamicResource OverlayCornerRadius}" />
<Setter Property="BorderThickness" Value="{DynamicResource TaskDialogBorderWidth}" />
@@ -332,7 +332,7 @@
</Animation>
</Style.Animations>
</Style>
<Style Selector="^:hidden /template/ ui|FABorder#ContentRoot">
<Style Selector="^:hidden /template/ Border#ContentRoot">
<Style.Animations>
<Animation FillMode="Forward" Duration="00:00:00.167">
<KeyFrame Cue="0%">
@@ -368,7 +368,7 @@
</Animation>
</Style.Animations>
</Style>
<Style Selector="^:open /template/ ui|FABorder#ContentRoot">
<Style Selector="^:open /template/ Border#ContentRoot">
<Style.Animations>
<Animation FillMode="Forward" Duration="00:00:00.250">
<KeyFrame Cue="0%">
@@ -389,7 +389,7 @@
<Setter Property="Template">
<ControlTemplate>
<Panel Name="LayoutRoot" Background="{x:Null}">
<ui:FABorder
<Border
Name="ContentRoot"
MinWidth="{DynamicResource TaskDialogMinWidth}"
MinHeight="{DynamicResource TaskDialogMinHeight}"
@@ -521,7 +521,7 @@
</ItemsControl>
</Border>
</Grid>
</ui:FABorder>
</Border>
</Panel>
</ControlTemplate>
</Setter>
@@ -14,4 +14,5 @@
</Styles.Resources>
<StyleInclude Source="/UI/Styling/Controls.axaml" />
<StyleInclude Source="avares://AvaloniaEdit/Themes/Fluent/AvaloniaEdit.xaml" />
</Styles>
@@ -210,7 +210,7 @@
<wnd:MinMaxCloseControl
Name="SystemCaptionButtons"
Height="{Binding TemplateSettings.TitleBarHeight, RelativeSource={RelativeSource TemplatedParent}}"
Margin="18,0"
Margin="14,0"
HorizontalAlignment="Right"
VerticalAlignment="Top" />
@@ -1,5 +1,7 @@
using Avalonia.Markup.Xaml.MarkupExtensions;
using Avalonia.Rendering.Composition;
using FluentAvalonia.UI.Controls.Experimental;
using FluentAvalonia.UI.Navigation;
namespace BD.WTTS.UI.Views.Pages;
@@ -17,6 +19,7 @@ public class PageBase : UserControl
}
_disposables.Add(UISettings.WindowBackgroundCustomImage.Subscribe(x => IsShowBackgroundImage = !x));
//AddHandler(Frame.NavigatingFromEvent, FrameNavigatingFrom, RoutingStrategies.Direct);
//AddHandler(Frame.NavigatedToEvent, FrameNavigatedTo, RoutingStrategies.Direct);
}
@@ -142,6 +145,7 @@ public class PageBase : UserControl
//_previewImageHost = e.NameScope.Find<IconSourceElement>("PreviewImageElement");
//_detailsHost = e.NameScope.Find<StackPanel>("DetailsTextHost");
_optionsHost = e.NameScope.Find<Panel>("OptionsRegion");
_tabsHost = e.NameScope.Find<Border>("TabRegion");
_detailsPanel = e.NameScope.Find<Panel>("PageDetails");
@@ -270,33 +274,28 @@ public class PageBase : UserControl
ec.ImplicitAnimations = ani;
}
//private void FrameNavigatingFrom(object sender, NavigatingCancelEventArgs e)
//private void FrameNavigatingFrom(object? sender, NavigatingCancelEventArgs e)
//{
// // If TargetType is not set, we know we're currently on a CoreControls page since those
// // are grouped pages - whereas, FA controls only display one control per page and
// // set all the extra properties
// bool isFAControlPage = TargetType != null;
// // Only setup the ConnectedAnimation if it makes sense
// if ((!isFAControlPage && e.SourcePageType == typeof(CoreControlsPageViewModel)) ||
// (isFAControlPage && e.SourcePageType == typeof(FAControlsOverviewPageViewModel)))
// if ((e.SourcePageType == typeof(HomePageViewModel)) ||
// (e.SourcePageType == typeof(PluginStorePageViewModel)))
// {
// // Only setup the Back connected animation if we're going back to the
// // controls list pages
// var svc = ConnectedAnimationService.GetForView(TopLevel.GetTopLevel(this));
// svc.PrepareToAnimate("BackAnimation", (Control)_previewImageHost.Parent);
// NavigationService.Instance.PreviousPage = this;
// //NavigationService.Instance.PreviousPage = this;
// }
//}
//private void FrameNavigatedTo(object sender, NavigationEventArgs e)
//private void FrameNavigatedTo(object? sender, NavigationEventArgs e)
//{
// var svc = ConnectedAnimationService.GetForView(TopLevel.GetTopLevel(this));
// var animation = svc.GetAnimation("ForwardAnimation");
// if (animation != null)
// {
// var coordinated = new List<Visual>
// var coordinated = new List<Visual?>
// {
// _optionsHost,
// _detailsHost,
@@ -126,7 +126,7 @@ public class OptionsDisplayItem : TemplatedControl
{
base.OnApplyTemplate(e);
_layoutRoot = e.NameScope.Find<FABorder>("LayoutRoot");
_layoutRoot = e.NameScope.Find<Border>("LayoutRoot");
if (_layoutRoot != null)
{
_layoutRoot.PointerPressed += OnLayoutRootPointerPressed;
@@ -172,5 +172,5 @@ public class OptionsDisplayItem : TemplatedControl
private bool _isPressed;
private bool _isExpanded;
private FABorder? _layoutRoot;
private Border? _layoutRoot;
}
@@ -62,14 +62,13 @@
Margin="0,0,0,5"
HorizontalAlignment="Center"
VerticalAlignment="Bottom">
<ItemsRepeater Name="Swiper" IsVisible="False">
<ItemsRepeater.Layout>
<StackLayout
DisableVirtualization="True"
Orientation="Horizontal"
Spacing="8" />
</ItemsRepeater.Layout>
<ItemsRepeater.ItemTemplate>
<ItemsControl Name="Swiper" IsVisible="False">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" Spacing="8" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<DataTemplate.DataType>
<x:Type x:TypeArguments="x:Int32, x:String" TypeName="generic:KeyValuePair" />
@@ -110,8 +109,8 @@
</i:Interaction.Behaviors>-->
</Button>
</DataTemplate>
</ItemsRepeater.ItemTemplate>
</ItemsRepeater>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Panel>
</Panel>
</Border>
@@ -55,7 +55,7 @@ public class CarouselItems : ItemsControl
Carousel? _carouselControl;
Button? _leftButton;
Button? _rightButton;
ItemsRepeater? _swiper;
ItemsControl? _swiper;
Timer? _timer;
public ICommand? CarouselBannerIndexCommand { get; }
@@ -72,7 +72,7 @@ public class CarouselItems : ItemsControl
_carouselControl = e.NameScope.Find<Carousel>("CarouselControl");
_leftButton = e.NameScope.Find<Button>("Left");
_rightButton = e.NameScope.Find<Button>("Right");
_swiper = e.NameScope.Find<ItemsRepeater>("Swiper");
_swiper = e.NameScope.Find<Avalonia.Controls.ItemsControl>("Swiper");
if (_leftButton != null)
{
@@ -139,20 +139,24 @@
VerticalAlignment="Center"
Foreground="{DynamicResource TextFillColorPrimaryBrush}"
Text="{Binding Path=Res.Link, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
<ItemsRepeater Margin="0,0,6,6" ItemsSource="{Binding Hyperlinks, Mode=OneTime}">
<ItemsRepeater.Layout>
<UniformGridLayout MinItemWidth="166" />
</ItemsRepeater.Layout>
<ItemsRepeater.ItemTemplate>
<ItemsControl Margin="0,0,6,6" ItemsSource="{Binding Hyperlinks, Mode=OneTime}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="spp:HyperlinkModel">
<Button
Command="{Binding Command, Mode=OneWay}"
Content="{Binding Text, Mode=OneWay}"
Cursor="Hand"
Theme="{StaticResource HyperlinkButton}" />
<Border MinWidth="166">
<Button
Command="{Binding Command, Mode=OneWay}"
Content="{Binding Text, Mode=OneWay}"
Cursor="Hand"
Theme="{StaticResource HyperlinkButton}" />
</Border>
</DataTemplate>
</ItemsRepeater.ItemTemplate>
</ItemsRepeater>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Border
Height="1"
Margin="-50,0"
@@ -162,20 +166,24 @@
VerticalAlignment="Center"
Foreground="{DynamicResource TextFillColorPrimaryBrush}"
Text="{Binding Path=Res.OpenSourceLibrary, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
<ItemsRepeater Margin="0,0,6,6" ItemsSource="{Binding OSL, Mode=OneTime}">
<ItemsRepeater.Layout>
<UniformGridLayout MinItemWidth="290" />
</ItemsRepeater.Layout>
<ItemsRepeater.ItemTemplate>
<ItemsControl Margin="0,0,6,6" ItemsSource="{Binding OSL, Mode=OneTime}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="spp:HyperlinkModel">
<Button
Command="{Binding Command, Mode=OneWay}"
Content="{Binding Text, Mode=OneWay}"
Cursor="Hand"
Theme="{StaticResource HyperlinkButton}" />
<Border MinWidth="290">
<Button
Command="{Binding Command, Mode=OneWay}"
Content="{Binding Text, Mode=OneWay}"
Cursor="Hand"
Theme="{StaticResource HyperlinkButton}" />
</Border>
</DataTemplate>
</ItemsRepeater.ItemTemplate>
</ItemsRepeater>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</spp:OptionsDisplayItem.Content>
</spp:OptionsDisplayItem>
@@ -12,6 +12,7 @@
d:DesignWidth="800"
x:CompileBindings="True"
x:DataType="spp:DebugPageViewModel"
ScrollViewer.VerticalScrollBarVisibility="Disabled"
mc:Ignorable="d">
<Design.DataContext>
<spp:DebugPageViewModel />
@@ -176,7 +177,7 @@
CornerRadius="2"
IsActive="{Binding #active.IsChecked}"
IsLoading="{Binding #loading.IsChecked}">
<SelectableTextBlock Margin="0,2" Text="是先有鸡还是先有蛋" />
<SelectableTextBlock Margin="0,2" Text="不忘初心,方得始终" />
</spp:Skeleton>
<spp:Skeleton
Margin="0,0,100,0"
@@ -184,14 +185,14 @@
CornerRadius="2"
IsActive="{Binding #active.IsChecked}"
IsLoading="{Binding #loading.IsChecked}">
<SelectableTextBlock Margin="0,2" Text="什么是工匠精神" />
<SelectableTextBlock Margin="0,2" Text="---" />
</spp:Skeleton>
<spp:Skeleton
VerticalAlignment="Bottom"
CornerRadius="2"
IsActive="{Binding #active.IsChecked}"
IsLoading="{Binding #loading.IsChecked}">
<SelectableTextBlock Margin="0,2" Text="看山不是山,看水不是水,看山还是山,看水还是水" />
<SelectableTextBlock Margin="0,2" Text="路漫漫其修远兮,吾将上下而求索。" />
</spp:Skeleton>
</UniformGrid>
</Grid>
@@ -24,10 +24,10 @@
</Style>
<Style Selector="ui|NavigationView.AppNav[IsBackButtonVisible=False] SplitView /template/ ContentPresenter#PART_PanePresenter">
<Setter Property="Margin" Value="0 50 0 0" />
<Setter Property="Margin" Value="0 42 0 0" />
</Style>
<Style Selector="ui|NavigationView.AppNav[IsBackButtonVisible=True] SplitView /template/ ContentPresenter#PART_PanePresenter">
<Setter Property="Margin" Value="0 10 0 0" />
<Setter Property="Margin" Value="0 2 0 0" />
</Style>
<Style Selector="ui|NavigationViewItem.AppNav">
@@ -331,7 +331,7 @@
PaneDisplayMode="Left">
<ui:NavigationView.Resources>
<!-- Override this -->
<Thickness x:Key="NavigationViewContentMargin">0,60,0,0</Thickness>
<Thickness x:Key="NavigationViewContentMargin">0,50,0,0</Thickness>
</ui:NavigationView.Resources>
<ui:NavigationView.Styles>
<Style Selector="Button#NavigationViewBackButton">
@@ -342,7 +342,7 @@
<Setter Property="Content" Value="&#xF0D5;" />
</Style>
<Style Selector="Grid#PaneToggleButtonGrid">
<Setter Property="Margin" Value="5 5 0 0" />
<Setter Property="Margin" Value="5 0 0 0" />
<Setter Property="ToolTip.Tip" Value="{Binding Path=Res.Back, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
<Setter Property="ToolTip.Placement" Value="Bottom" />
</Style>
@@ -10,7 +10,7 @@
d:DesignHeight="450"
d:DesignWidth="800"
x:CompileBindings="True"
x:DataType="spp:HomePageViewModel"
x:DataType="spp:PluginStorePageViewModel"
mc:Ignorable="d">
<ScrollViewer Padding="20">
<!--<spp:ContentLoader IsLoading="False">-->
@@ -23,7 +23,7 @@
Text="插件商店是什么?"
Theme="{StaticResource TitleTextBlockStyle}" />
<TextBlock Text="3.0版本的计划是将所有功能插件化,拆分后按需下载安装,每个人都可以只下载自己需要的插件功能使用,并且支持所有人都可以开发插件,等等还有许多暂时不方便说的内容,因为计划的过于异想天开,且遇到的问题有点多,所以开发难度有点点大,这个功能上线还需要一点时间,对一直等待的大家说声抱歉麻烦在多等等了😭。" TextWrapping="WrapWithOverflow" />
<TextBlock Text="3.0 版本的计划是将所有功能插件化,拆分后按需下载安装,每个人都可以只下载自己需要的插件功能使用,并且支持所有人都可以开发插件,等等还有许多暂时不方便说的内容,因为计划的过于异想天开,且遇到的问题有点多,所以开发难度有点点大,这个功能上线还需要一点时间,上线后 3.0 也将正式发布正式版,对一直等待的大家说声抱歉麻烦在多等等了 😭,如果您不习惯启动后是插件商店页面也可以在界面设置中修改启动默认页。" TextWrapping="WrapWithOverflow" />
<TextBlock
Margin="-3,0,0,0"
Text="已安装功能"
@@ -55,11 +55,12 @@
<DataTemplate DataType="spp:TabItemViewModel">
<Border spp:Animations.EnableAnimations="True">
<Button
Command="{Binding $parent[spp:HomePage].((spp:HomePageViewModel)DataContext).NavgationToMenuPageCommand}"
Command="{Binding $parent[spp:PluginStorePage].((spp:PluginStorePageViewModel)DataContext).NavgationToMenuPageCommand}"
CommandParameter="{Binding}"
Theme="{StaticResource NavButtonStyle}">
<Grid RowDefinitions="3*,*">
<Border
Name="IconHost"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
CornerRadius="4 4 0 0"
@@ -1,3 +1,6 @@
using FluentAvalonia.UI.Controls.Experimental;
using FluentAvalonia.UI.Navigation;
namespace BD.WTTS.UI.Views.Pages;
public partial class PluginStorePage : UserControl
@@ -5,5 +8,85 @@ public partial class PluginStorePage : UserControl
public PluginStorePage()
{
InitializeComponent();
this.SetViewModel<PluginStorePageViewModel>(useCache: true);
// Use the frame events here to ensure ConnectedAnimations still work with
// Back/Forward navigation and not just explicit page invokes
//AddHandler(Frame.NavigatingFromEvent, OnNavigatingFrom, RoutingStrategies.Direct);
//AddHandler(Frame.NavigatedToEvent, OnNavigatedTo, RoutingStrategies.Direct);
}
//private void PluginStorePage_Click(object? sender, RoutedEventArgs e)
//{
// if (sender != null && sender is Button b && b.DataContext is TabItemViewModel fci)
// {
// _animationPage = fci;
// //NavigationService.Instance.NavigateFromContext(fci);
// }
//}
//private void OnNavigatedTo(object? sender, NavigationEventArgs e)
//{
// if (_animationPage == null)
// return;
// var svc = ConnectedAnimationService.GetForView(TopLevel.GetTopLevel(this));
// var anim = svc.GetAnimation("BackAnimation");
// if (anim == null)
// return;
// var item = this.GetVisualDescendants()
// ?.Where(x => x is Button && x.DataContext == _animationPage)
// ?.FirstOrDefault()
// ?.GetVisualDescendants()
// .Where(x => x is Border && x.Name == "IconHost")
// .FirstOrDefault();
// var presenter = item;// GetAnimationSource();
// // In WinUI, ConnectedAnimation is somehow exempt from all clipping behaviors
// // Here, we are not, so disable ClipToBounds on all elements in the SettingsExpander
// // The rest are taken care of in the xaml.
// // NOTE: The ScrollViewer is not changed here as that's important for scrolling - thus
// // the animation will be cut off, but the back animation is pretty fast and mostly is
// // only visible closer to the element so we're ok, I think
// var x = presenter?.GetVisualParent();
// while (!(x is ScrollContentPresenter) && x != null)
// {
// x.ClipToBounds = false;
// x = x.GetVisualParent();
// }
// anim.Configuration = new DirectConnectedAnimationConfiguration();
// anim.TryStart(presenter);
//}
//private void OnNavigatingFrom(object? sender, NavigatingCancelEventArgs e)
//{
// if (_animationPage == null)
// return;
// // We're not navigating to a control page, don't set up the animation & clear
// // the previous animation source
// if (!e.SourcePageType.Name.Equals(nameof(TabItemViewModel)))
// {
// _animationPage = null;
// _animationPage = null;
// return;
// }
// var item = this.GetVisualDescendants()
// ?.Where(x => x is ListBoxItem && x.DataContext == _animationPage)
// ?.FirstOrDefault()
// ?.GetVisualDescendants()
// .Where(x => x is Viewbox && x.Name == "IconHost")
// .FirstOrDefault();
// var svc = ConnectedAnimationService.GetForView(TopLevel.GetTopLevel(this));
// svc.PrepareToAnimate("ForwardAnimation", item);
//}
//private TabItemViewModel? _animationPage;
}
@@ -123,7 +123,7 @@ public static class KestrelServerOptionsExtensions
var httpsPort = IReverseProxyConfig.HttpsPort;
options.Listen(IReverseProxyService.Constants.Instance.ProxyIp, httpsPort, listen =>
{
listen.Protocols = HttpProtocols.Http1AndHttp2AndHttp3;
listen.Protocols = HttpProtocols.Http1AndHttp2;
listen.UseFlowAnalyze();
listen.UseTls();
});
@@ -155,7 +155,21 @@ public static class CertGenerator
}
else
{
builder.AddDnsName(name);
try
{
builder.AddDnsName(name);
}
catch
{
/* name = Environment.MachineName
* System.ArgumentException: Decoded string is not a valid IDN name. (Parameter 'unicode')
* at System.Globalization.IdnMapping.IcuGetAsciiCore(String unicodeString, Char* unicode, Int32 count)
* at System.Globalization.IdnMapping.GetAscii(String unicode, Int32 index, Int32 count)
* at System.Security.Cryptography.X509Certificates.SubjectAlternativeNameBuilder.AddDnsName(String dnsName)
* at BD.WTTS.Services.Implementation.CertGenerator.Add(SubjectAlternativeNameBuilder builder, String name)
* at BD.WTTS.Services.Implementation.CertGenerator.CreateEndCertificate(X509Certificate2 issuerCertificate, X500DistinguishedName subjectName, IEnumerable`1 extraDnsNames, Nullable`1 notBefore, Nullable`1 notAfter, Int32 rsaKeySizeInBits)
*/
}
}
}
@@ -425,6 +425,12 @@ public sealed class ScriptManager : GeneralHttpClientFactory, IScriptManager
//item.Content = string.Empty;
}
}
else
{
await TryReadFileAsync(item, true);
//item.Content = string.Empty;
}
}
}
return scripts;
@@ -503,7 +503,8 @@ public sealed partial class GameAcceleratorService
if (GameAcceleratorSettings.MyGames.Any_Nullable())
{
Games.Clear();
foreach (var item in GameAcceleratorSettings.MyGames.Value!.Values)
var temp = GameAcceleratorSettings.MyGames.Value!.Values.ToArray();
foreach (var item in temp)
{
if (item.PicInfo == null)
item.PicInfo = XunYouSDK.GetPicInfo(item.Id);
@@ -517,7 +518,8 @@ public sealed partial class GameAcceleratorService
{
Games.Clear();
GameAcceleratorSettings.MyGames.AddRange(games.Select(s => new KeyValuePair<int, XunYouGameViewModel>(s.Id, new XunYouGameViewModel(s))));
foreach (var item in GameAcceleratorSettings.MyGames.Value!.Values)
var temp = GameAcceleratorSettings.MyGames.Value!.Values.ToArray();
foreach (var item in temp)
{
if (item.PicInfo == null)
item.PicInfo = XunYouSDK.GetPicInfo(item.Id);
@@ -155,6 +155,11 @@ public partial interface IProxySettings
/// </summary>
string? CustomDohAddres { get; set; }
/// <summary>
/// 加速页面 Tab 选项卡选中下标
/// </summary>
int AcceleratorTabsSelectedIndex { get; set; }
/// <summary>
/// 启用脚本自动检查更新的默认值
/// </summary>
@@ -270,4 +275,9 @@ public partial interface IProxySettings
/// </summary>
const string? DefaultCustomDohAddres = null;
/// <summary>
/// 加速页面 Tab 选项卡选中下标的默认值
/// </summary>
static readonly int DefaultAcceleratorTabsSelectedIndex = 0;
}
@@ -201,7 +201,7 @@ public sealed partial class ProxySettings_ : IProxySettings, ISettings, ISetting
/// 加速页面 Tab 选项卡选中下标
/// </summary>
[MPKey(23), MP2Key(23), JsonPropertyOrder(23)]
public int AcceleratorTabsSelectedIndex { get; set; }
public int AcceleratorTabsSelectedIndex { get; set; } = IProxySettings.DefaultAcceleratorTabsSelectedIndex;
}
@@ -369,5 +369,6 @@ public static partial class ProxySettings
/// 加速页面 Tab 选项卡选中下标
/// </summary>
public static SettingsStructProperty<int, ProxySettings_> AcceleratorTabsSelectedIndex { get; }
= new();
= new(DefaultAcceleratorTabsSelectedIndex);
}
@@ -721,6 +721,7 @@
HorizontalAlignment="Right"
VerticalAlignment="Center"
IsVisible="{Binding Source={x:Static s:ProxyService.Current}, Path=ProxyStatus, Mode=OneWay}"
Orientation="Horizontal"
Spacing="8">
<StackPanel.IsVisible>
<MultiBinding Converter="{x:Static BoolConverters.And}">
@@ -736,15 +737,26 @@
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
</StackPanel.Styles>
<TextBlock>
<Run Text="{x:Static spp:Strings.CommunityFix_ProxyMode}" />
<Run Text="{Binding Source={x:Static ms:ProxySettings.ProxyMode}, Path=Value, Mode=OneWay, Converter={StaticResource EnumLocalizationNameConverter}}" />
<Button Theme="{StaticResource TransparentButton}">
<ToolTip.Tip>
<TextBlock>
<Run FontSize="16" Text="Q:为什么加速后流量一直显示 0KB ?" />
<LineBreak />
<Run Text="A:流量统计图表是用于查看实时流量数据信息,您需要先访问对应的网站,这边才会有相应的流量波动数据,请检查是否已经选择了对应的网站加速项目,如果确定有正常勾选加速项目并且访问网站依然无流量,则可能是加速的监听服务没有启用成功,尝试更换加速模式。" />
<LineBreak />
<LineBreak />
<Run FontSize="16" Text="Q:加速后对应网站打不开显示SSL错误或者Steam浏览器显示-100错误?" />
<LineBreak />
<Run Text="A:可以尝试执行以下操作进行修复,关闭加速,点击加速设置-移除证书再安装证书,重开加速。或者加速设置-代理设置-尝试更换doh地址或者关闭doh使用dns等方案。" />
</TextBlock>
</ToolTip.Tip>
<ui:FontIcon FontSize="22" Glyph="&#xE82F;" />
</Button>
<TextBlock Text="{x:Static spp:Strings.CommunityFix_ProxyMode}" />
<TextBlock Text="{Binding Source={x:Static ms:ProxySettings.ProxyMode}, Path=Value, Mode=OneWay, Converter={StaticResource EnumLocalizationNameConverter}}" />
<Run Text=" " />
<Run Text="{x:Static spp:Strings.CommunityFix_EnableScriptService}" />
<Run Text="{Binding Source={x:Static s:ProxyService.Current}, Path=IsEnableScript, Converter={StaticResource StringFormatConverter}}" />
</TextBlock>
<TextBlock Text="{x:Static spp:Strings.CommunityFix_EnableScriptService}" />
<TextBlock Text="{Binding Source={x:Static s:ProxyService.Current}, Path=IsEnableScript, Converter={StaticResource StringFormatConverter}}" />
</StackPanel>
<spp:AdControl
@@ -28,7 +28,6 @@ public sealed partial class ArchiSteamFarmPlusPageViewModel : ViewModelBase
var model = new ArchiSteamFarmExePathSettingsPageViewModel();
await IWindowManager.Instance.ShowTaskDialogAsync(model,
title: BDStrings.ASF_Settings,
subHeader: BDStrings.ASF_SetExePathFirst,
pageContent: new ArchiSteamFarmExePathSettingsPage(),
isCancelButton: true,
cancelCloseAction: () =>
@@ -2,6 +2,7 @@
x:Class="BD.WTTS.UI.Views.Controls.ConsoleShell"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:AvaloniaEdit="using:AvaloniaEdit"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ms="https://steampp.net/settings"
@@ -13,7 +14,7 @@
FontFamily="{StaticResource UnicodeFont}"
FontSize="16"
mc:Ignorable="d">
<UserControl.Styles>
<!--<UserControl.Styles>
<Style Selector="TextBox">
<Setter Property="FontSize" Value="{ReflectionBinding #u.FontSize}" />
<Setter Property="FontFamily" Value="{ReflectionBinding #u.FontFamily}" />
@@ -27,35 +28,15 @@
<Style Selector="TextBox /template/ TextBlock#PART_BorderElement">
<Setter Property="Margin" Value="0" />
</Style>
</UserControl.Styles>
</UserControl.Styles>-->
<Border Background="{DynamicResource CardBackgroundFillColorDefaultBrush}" CornerRadius="{DynamicResource ControlCornerRadius}">
<Grid RowDefinitions="*,Auto">
<ScrollViewer
x:Name="ConsoleScroll"
Grid.Row="0"
<AvaloniaEdit:TextEditor
x:Name="LogTextbox"
HorizontalScrollBarVisibility="Disabled"
IsScrollChainingEnabled="True"
VerticalScrollBarVisibility="Visible">
<TextBox
x:Name="LogTextbox"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
Classes="readonlybox"
Focusable="False"
IsReadOnly="True"
IsVisible="False"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Disabled"
Text="{ReflectionBinding #u.LogText}"
TextWrapping="Wrap" />
</ScrollViewer>
IsReadOnly="True"
ShowLineNumbers="True" />
<DockPanel Grid.Row="1">
<TextBlock
x:Name="InputIndicatorTextBlock"
Margin="10,0,10,0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
FontFamily="{ReflectionBinding #u.FontFamily}" />
<AutoCompleteBox
x:Name="CommandTextbox"
FilterMode="StartsWithOrdinal"
@@ -67,20 +48,12 @@
ValueMemberBinding="{ReflectionBinding Command}">
<AutoCompleteBox.Styles>
<Style Selector="AutoCompleteBox">
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Padding" Value="0" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Watermark" Value="请输入命令或消息内容" />
<Setter Property="Watermark" Value="输入指令或消息内容" />
</Style>
<Style Selector="AutoCompleteBox /template/ TextBox#PART_TextBox">
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="AcceptsReturn" Value="False" />
<Setter Property="IsReadOnly" Value="False" />
<Setter Property="Padding" Value="0" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="TextWrapping" Value="WrapWithOverflow" />
@@ -88,29 +61,19 @@
<Style Selector="AutoCompleteBox:password /template/ TextBox#PART_TextBox">
<Setter Property="PasswordChar" Value="{StaticResource PasswordChar}" />
</Style>
<Style Selector="AutoCompleteBox /template/ TextBox#PART_TextBox:pointerover /template/ Border#PART_BorderElement">
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="BorderThickness" Value="0" />
</Style>
<Style Selector="AutoCompleteBox /template/ TextBox#PART_TextBox:focus /template/ Border#PART_BorderElement">
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="BorderThickness" Value="0" />
</Style>
<Style Selector="AutoCompleteBox /template/ Popup#PART_Popup">
<Setter Property="MaxWidth" Value="{ReflectionBinding Bounds.Width, RelativeSource={RelativeSource TemplatedParent}}" />
</Style>
</AutoCompleteBox.Styles>
</AutoCompleteBox>
<ui:FontIcon
<!--<ui:FontIcon
HorizontalAlignment="Right"
VerticalAlignment="Center"
FontFamily="{StaticResource SymbolThemeFontFamily}"
FontSize="18"
Glyph="&#xEB97;"
ToolTip.Tip="回车键发送" />
ToolTip.Tip="回车键发送" />-->
</DockPanel>
</Grid>
@@ -5,6 +5,10 @@ using Avalonia.Controls.Templates;
using Avalonia.Layout;
using Avalonia.Markup.Xaml;
using Avalonia.Media;
using Avalonia.Styling;
using AvaloniaEdit;
using AvaloniaEdit.TextMate;
using TextMateSharp.Grammars;
namespace BD.WTTS.UI.Views.Controls;
@@ -122,10 +126,10 @@ public partial class ConsoleShell : UserControl
/// </summary>
public event EventHandler<CommandEventArgs>? CommandSubmit;
private readonly TextBlock inputIndicatorTextBlock;
//private readonly TextBlock inputIndicatorTextBlock;
private readonly AutoCompleteBox commandTextbox;
private readonly TextBox logTextbox;
private readonly ScrollViewer consoleScroll;
private readonly TextEditor logTextbox;
//private readonly ScrollViewer consoleScroll;
private readonly ArchiSteamFarmCommandHistory commandHistory;
/// <summary>
@@ -136,9 +140,9 @@ public partial class ConsoleShell : UserControl
InitializeComponent();
commandHistory = new();
inputIndicatorTextBlock = this.FindControl<TextBlock>("InputIndicatorTextBlock")!;
logTextbox = this.FindControl<TextBox>("LogTextbox")!;
consoleScroll = this.FindControl<ScrollViewer>("ConsoleScroll")!;
//inputIndicatorTextBlock = this.FindControl<TextBlock>("InputIndicatorTextBlock")!;
logTextbox = this.FindControl<TextEditor>("LogTextbox")!;
//consoleScroll = this.FindControl<ScrollViewer>("ConsoleScroll")!;
commandTextbox = this.FindControl<AutoCompleteBox>("CommandTextbox")!;
commandTextbox.KeyUp += CommandTextbox_KeyUp;
@@ -159,12 +163,22 @@ public partial class ConsoleShell : UserControl
}
});
this.GetObservable(InputIndicatorProperty)
.Subscribe(x => inputIndicatorTextBlock.Text = $"{InputIndicator}{InputIndicatorSuffix}");
//this.GetObservable(InputIndicatorProperty)
// .Subscribe(x => inputIndicatorTextBlock.Text = $"{InputIndicator}{InputIndicatorSuffix}");
this.GetObservable(IsMaskProperty)
.Subscribe(x => ((IPseudoClasses)commandTextbox.Classes).Set(":password", x));
//Here we initialize RegistryOptions with the theme we want to use.
var registryOptions = new TextMateSharp.Grammars.RegistryOptions(ThemeName.Dark);
//Initial setup of TextMate.
var textMateInstallation = logTextbox.InstallTextMate(registryOptions);
//Here we are getting the language by the extension and right after that we are initializing grammar with this language.
//And that's all 😀, you are ready to use AvaloniaEdit with syntax highlighting!
textMateInstallation.SetGrammar(registryOptions.GetScopeByLanguageId(registryOptions.GetLanguageByExtension(".log").Id));
this.GetObservable(LogTextProperty)
.Subscribe(x =>
{
@@ -172,19 +186,22 @@ public partial class ConsoleShell : UserControl
{
logTextbox.IsVisible = true;
}
//logTextbox.Text = x;
if (logTextbox.Width > 0)
logTextbox.MaxLength = (int)(logTextbox.Width / (logTextbox.FontSize + logTextbox.LetterSpacing)) * logTextbox.MaxLines;
//if (logTextbox.Width > 0)
// logTextbox.MaxLength = (int)(logTextbox.Width / (logTextbox.FontSize + logTextbox.LetterSpacing)) * logTextbox.MaxLines;
logTextbox.Text = LogText;
commandTextbox.Focus();
consoleScroll.ScrollToEnd();
logTextbox.ScrollToLine(logTextbox.Document.LineCount);
//logTextbox.ScrollToLine();
//consoleScroll.ScrollToEnd();
});
this.GetObservable(MaxLineProperty)
.Subscribe(x => logTextbox.MaxHeight = (logTextbox.LineHeight = logTextbox.FontSize) * (logTextbox.MaxLines = x));
//this.GetObservable(MaxLineProperty)
// .Subscribe(x => logTextbox.MaxHeight = (logTextbox.LineHeight = logTextbox.FontSize) * (logTextbox.MaxLines = x));
this.GetObservable(FontSizeProperty).Subscribe(x => logTextbox.MaxHeight = (logTextbox.LineHeight = logTextbox.FontSize = x) * logTextbox.MaxLines);
//this.GetObservable(FontSizeProperty).Subscribe(x => logTextbox.MaxHeight = (logTextbox.LineHeight = logTextbox.FontSize = x) * logTextbox.MaxLines);
}
private void CommandTextbox_KeyUp(object? sender, Avalonia.Input.KeyEventArgs e)
@@ -36,7 +36,7 @@
Margin="28,4,0,4"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Text="Json文件导入" />
Text="导入配置" />
</Panel>
</Button>
<Button
@@ -130,6 +130,77 @@
IsClickEnabled="True"
ToolTip.Tip="{Binding Path=., Mode=OneWay, Source={x:Static spp:Strings.Settings_General_BrowseCustomFolder}, Converter={StaticResource StringFormatConverter}, ConverterParameter=www}" />
</ui:SettingsExpander>
<!--<spp:OptionsDisplayItem Header="ASF 文件路径">
<spp:OptionsDisplayItem.Description>
<TextBlock
MaxWidth="120"
MaxLines="1"
Text="{Binding Source={x:Static ms:ASFSettings.ArchiSteamFarmExePath}, Path=Value, Mode=OneWay}"
TextTrimming="CharacterEllipsis" />
</spp:OptionsDisplayItem.Description>
<spp:OptionsDisplayItem.Icon>
<ui:FontIcon FontFamily="Segoe Fluent Icons" Glyph="&#xE756;" />
</spp:OptionsDisplayItem.Icon>
<spp:OptionsDisplayItem.ActionButton>
<Button Command="{Binding SelectASFExePath}" Content="选择路径" />
</spp:OptionsDisplayItem.ActionButton>
</spp:OptionsDisplayItem>-->
<spp:OptionsDisplayItem Header="自动启动 ASF">
<spp:OptionsDisplayItem.Icon>
<ui:FontIcon FontFamily="Segoe Fluent Icons" Glyph="&#xE770;" />
</spp:OptionsDisplayItem.Icon>
<spp:OptionsDisplayItem.ActionButton>
<ToggleSwitch Classes="LeftContent" IsChecked="{Binding Source={x:Static ms:ASFSettings.AutoRunArchiSteamFarm}, Path=Value, Mode=TwoWay}" />
</spp:OptionsDisplayItem.ActionButton>
</spp:OptionsDisplayItem>
<spp:OptionsDisplayItem Header="检查文件安全性">
<spp:OptionsDisplayItem.Icon>
<ui:FontIcon FontFamily="Segoe Fluent Icons" Glyph="&#xE83D;" />
</spp:OptionsDisplayItem.Icon>
<spp:OptionsDisplayItem.ActionButton>
<ToggleSwitch Classes="LeftContent" IsChecked="{Binding Source={x:Static ms:ASFSettings.CheckArchiSteamFarmExe}, Path=Value, Mode=TwoWay}" />
</spp:OptionsDisplayItem.ActionButton>
</spp:OptionsDisplayItem>
<spp:OptionsDisplayItem Header="ASF 监听端口">
<spp:OptionsDisplayItem.Icon>
<ui:FontIcon FontFamily="Segoe Fluent Icons" Glyph="&#xE704;" />
</spp:OptionsDisplayItem.Icon>
<spp:OptionsDisplayItem.ActionButton>
<ui:NumberBox Minimum="5000" Value="{Binding Source={x:Static ms:ASFSettings.IPCPortId}, Path=Value, Mode=TwoWay}" />
</spp:OptionsDisplayItem.ActionButton>
</spp:OptionsDisplayItem>
<spp:OptionsDisplayItem Header="端口被占时随机端口号">
<spp:OptionsDisplayItem.Icon>
<ui:FontIcon FontFamily="Segoe Fluent Icons" Glyph="&#xE770;" />
</spp:OptionsDisplayItem.Icon>
<spp:OptionsDisplayItem.ActionButton>
<ToggleSwitch Classes="LeftContent" IsChecked="{Binding Source={x:Static ms:ASFSettings.IPCPortOccupiedRandom}, Path=Value, Mode=TwoWay}" />
</spp:OptionsDisplayItem.ActionButton>
</spp:OptionsDisplayItem>
<spp:OptionsDisplayItem Header="控制台最大行数">
<spp:OptionsDisplayItem.Icon>
<ui:FontIcon FontFamily="Segoe Fluent Icons" Glyph="&#xF2B7;" />
</spp:OptionsDisplayItem.Icon>
<spp:OptionsDisplayItem.ActionButton>
<ui:NumberBox Minimum="1" Value="{Binding Source={x:Static ms:ASFSettings.ConsoleMaxLine}, Path=Value, Mode=TwoWay}" />
</spp:OptionsDisplayItem.ActionButton>
</spp:OptionsDisplayItem>
<spp:OptionsDisplayItem Header="控制台字体大小">
<spp:OptionsDisplayItem.Icon>
<ui:FontIcon FontFamily="Segoe Fluent Icons" Glyph="&#xE8E9;" />
</spp:OptionsDisplayItem.Icon>
<spp:OptionsDisplayItem.ActionButton>
<ui:NumberBox Minimum="1" Value="{Binding Source={x:Static ms:ASFSettings.ConsoleFontSize}, Path=Value, Mode=TwoWay}" />
</spp:OptionsDisplayItem.ActionButton>
</spp:OptionsDisplayItem>
</StackPanel>
</spp:ContentLoader>
</spp:PageBase>
@@ -14,6 +14,7 @@
x:CompileBindings="True"
x:DataType="spp:ArchiSteamFarmPlusPageViewModel"
Description="{Binding Description, Source={x:Static s:Plugin.Instance}, Mode=OneWay}"
ScrollViewer.VerticalScrollBarVisibility="Disabled"
Subtitle="{Binding Author, Source={x:Static s:Plugin.Instance}, Mode=OneWay, Converter={StaticResource StringFormatConverter}, ConverterParameter=Plugin_Author}"
mc:Ignorable="d">
<spp:PageBase.PreviewImage>
@@ -76,7 +77,7 @@
Margin="28,4,0,4"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Text="打开WebUI" />
Text="打开 WebUI" />
</Panel>
</Button>
<ToggleButton
@@ -204,9 +205,9 @@
</StackPanel>
</spp:PageBase.PaneContent>
<spp:ContentLoader IsLoading="False">
<StackPanel Orientation="Vertical" Spacing="2">
<!--<StackPanel Orientation="Horizontal" Spacing="2">
<!--<StackPanel Orientation="Horizontal" Spacing="2">
<Label
HorizontalAlignment="Center"
VerticalAlignment="Center"
@@ -221,34 +222,33 @@
<TextBlock Text="{Binding Source={x:Static s:ASFService.Current}, Path=ConsoleLogText, Mode=TwoWay}" />-->
<spp:ConsoleShell
AutoCompleteBoxItems="{ReflectionBinding Path=Value,
Source={x:Static spp:ArchiSteamFarmCommand.Commands}}"
CommandSubmit="ConsoleShell_CommandSubmit"
FontSize="{ReflectionBinding Source={x:Static ms:ASFSettings.ConsoleFontSize},
Path=Value,
Mode=OneWay}"
InputIndicator="用户输入"
IsMask="false"
LogText="{ReflectionBinding Source={x:Static s:ASFService.Current},
Path=ConsoleLogText,
Mode=TwoWay}"
MaxLine="{ReflectionBinding Source={x:Static ms:ASFSettings.ConsoleMaxLine},
Path=Value,
Mode=OneWay}">
<spp:ConsoleShell.AutoCompleteBoxItemTemplate>
<DataTemplate x:DataType="spp:ArchiSteamFarmCommand">
<DockPanel>
<TextBlock VerticalAlignment="Center" Text="{Binding CommandText}" />
<TextBlock
Margin="15,0,0,0"
VerticalAlignment="Center"
Text="{Binding Description}"
TextWrapping="Wrap" />
</DockPanel>
</DataTemplate>
</spp:ConsoleShell.AutoCompleteBoxItemTemplate>
</spp:ConsoleShell>
</StackPanel>
<spp:ConsoleShell
AutoCompleteBoxItems="{ReflectionBinding Path=Value,
Source={x:Static spp:ArchiSteamFarmCommand.Commands}}"
CommandSubmit="ConsoleShell_CommandSubmit"
FontSize="{ReflectionBinding Source={x:Static ms:ASFSettings.ConsoleFontSize},
Path=Value,
Mode=OneWay}"
InputIndicator="用户输入"
IsMask="false"
LogText="{ReflectionBinding Source={x:Static s:ASFService.Current},
Path=ConsoleLogText,
Mode=TwoWay}"
MaxLine="{ReflectionBinding Source={x:Static ms:ASFSettings.ConsoleMaxLine},
Path=Value,
Mode=OneWay}">
<spp:ConsoleShell.AutoCompleteBoxItemTemplate>
<DataTemplate x:DataType="spp:ArchiSteamFarmCommand">
<DockPanel>
<TextBlock VerticalAlignment="Center" Text="{Binding CommandText}" />
<TextBlock
Margin="15,0,0,0"
VerticalAlignment="Center"
Text="{Binding Description}"
TextWrapping="Wrap" />
</DockPanel>
</DataTemplate>
</spp:ConsoleShell.AutoCompleteBoxItemTemplate>
</spp:ConsoleShell>
</spp:ContentLoader>
</spp:PageBase>
@@ -30,7 +30,7 @@
Command="{Binding $parent[spp:PageBase].((spp:BotPageViewModel)DataContext).EditBotFile}"
CommandParameter="{Binding Bot}"
IconSource="Edit"
Text="编辑Json文件" />
Text="编辑 Json 文件" />
<ui:MenuFlyoutSeparator />
<ui:MenuFlyoutItem
Command="{Binding $parent[spp:PageBase].((spp:BotPageViewModel)DataContext).DeleteBot}"
@@ -58,7 +58,7 @@
Margin="28,4,0,4"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Text="Json文件导入" />
Text="导入 Bot" />
</Panel>
</Button>
<Button
@@ -103,7 +103,7 @@
</spp:PageBase.ActionContent>
<spp:ContentLoader
CustomLoadingText="请先启动 ArchiSteamFarm"
IsLoading="{Binding Source={x:Static s:ASFService.Current}, Path=!IsASFRuning, Mode=OneWay}"
IsLoading="False"
IsShowNoResultText="{Binding !!!SteamBots.Count}"
NoResultMessage="当前列表没有 Bot 账号">
<spp:ContentLoader.GestureRecognizers>
@@ -35,12 +35,12 @@
<x:Type TypeName="spp:ArchiSteamFarmPage" />
</TabStripItem.Tag>
</TabStripItem>
<TabStripItem Content="Bot">
<TabStripItem Content="Bot 配置">
<TabStripItem.Tag>
<x:Type TypeName="spp:BotPage" />
</TabStripItem.Tag>
</TabStripItem>
<TabStripItem Content="ASF">
<TabStripItem Content="ASF 配置">
<TabStripItem.Tag>
<x:Type TypeName="spp:ASFSettingsPage" />
</TabStripItem.Tag>
@@ -90,6 +90,9 @@
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Update="UI\Views\Pages\JoinSteamAuthenticatorPage.axaml.cs">
<DependentUpon>JoinSteamAuthenticatorPage.axaml</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
@@ -1,6 +1,6 @@
using SJsonSerializer = System.Text.Json.JsonSerializer;
using BD.WTTS.UI.Views.Pages;
using WinAuth;
using SJsonSerializer = System.Text.Json.JsonSerializer;
namespace BD.WTTS.UI.ViewModels;
@@ -26,6 +26,8 @@ public class AuthenticatorImportPageViewModel : ViewModelBase
if (await AuthenticatorHelper.VerifyMaxValue())
await ImportFromSdaFile();
})),
new AuthenticatorImportMethod(Strings.LocalAuth_Import.Format(Strings.LocalAuth_JoinSteamAuthenticator), Strings.LocalAuth_JoinSteamAuthenticatorDesc,
PageType: typeof(JoinSteamAuthenticatorPage)),
new AuthenticatorImportMethod(Strings.LocalAuth_Import.Format(Strings.WattToolKitV2), Strings.LocalAuth_WattToolKitV2Import,
Command: ReactiveCommand.Create(async () =>
{
@@ -123,6 +125,7 @@ public class AuthenticatorImportPageViewModel : ViewModelBase
? Strings.LocalAuth_AddAuthSuccess
: Strings.LocalAuth_AddAuth_PartSuccess);
break;
case IAccountPlatformAuthenticatorRepository.ImportResultCode.SecondaryPasswordFail:
Toast.Show(ToastIcon.Warning, Strings.LocalAuth_ProtectionAuth_PasswordErrorTip);
var textViewModel =
@@ -136,6 +139,7 @@ public class AuthenticatorImportPageViewModel : ViewModelBase
}
await ImportFromWattToolKitV2(exportPassword, password, isLocalProtect, filePath);
break;
default:
Toast.Show(ToastIcon.Error, Strings.LocalAuth_ExportAuth_Error.Format(result.resultCode));
break;
@@ -0,0 +1,442 @@
using BD.SteamClient.Models;
using BD.SteamClient.Services;
using WinAuth;
using AppResources = BD.WTTS.Client.Resources.Strings;
namespace BD.WTTS.UI.ViewModels;
/// <summary>
/// 联合Steam令牌页面
/// </summary>
public sealed partial class JoinSteamAuthenticatorPageViewModel : ViewModelBase
{
#region 步骤索引常量
const int STEPINDEX_LOGIN = 0;
const int STEPINDEX_VERIFY = 1;
const int STEPINDEX_DONE = 2;
#endregion 步骤索引常量
#region 页面属性
/// <summary>
/// 用户填入的 Steam 令牌验证码
/// </summary>
[Reactive]
public string? Code { get; set; }
/// <summary>
/// 用户名
/// </summary>
[Reactive]
public string? UserNameText { get; set; }
/// <summary>
/// 密码
/// </summary>
[Reactive]
public string? PasswordText { get; set; }
/// <summary>
/// 验证码
/// </summary>
[Reactive]
public string? VerifyCodeText { get; set; }
/// <summary>
/// 恢复代码
/// </summary>
[Reactive]
public string? RevocationCodeText { get; set; }
/// <summary>
/// 当前步骤
/// </summary>
[Reactive]
public int SelectIndex { get; set; } = STEPINDEX_LOGIN;
/// <summary>
/// 加载
/// </summary>
[Reactive]
public bool Loading { get; set; } = false;
/// <summary>
/// 是否需要验证码
/// </summary>
[Reactive]
public bool RequireVerifyCode { get; set; } = false;
#endregion 页面属性
#region 私有变量
/// <summary>
/// Steam 账号服务
/// </summary>
private static readonly ISteamAccountService _steamAccountService = Ioc.Get<ISteamAccountService>();
/// <summary>
/// 当前页面待导入的 Steam Authenticator
/// </summary>
private SteamAuthenticator? _currentSteamAuthenticator;
private SteamLoginState? _currentSteamLoginState;
#endregion 私有变量
#region 联合 Steam令牌 页面流程
/// <summary>
/// 登录
/// </summary>
/// <returns></returns>
public async Task LoginAsync()
{
if (Loading)
return;
Loading = true;
try
{
if (string.IsNullOrEmpty(UserNameText) || string.IsNullOrEmpty(PasswordText))
{
Toast.Show(ToastIcon.Error, AppResources.Error_PleaseEnterUsernamePassword);
return;
}
// 初始化登录状态
var loginState = _currentSteamLoginState ??= new SteamLoginState();
loginState.Username = UserNameText;
loginState.Password = PasswordText;
loginState.Language = ResourceService.GetCurrentCultureSteamLanguageName();
if (RequireVerifyCode && loginState.RequiresEmailAuth)
{
loginState.EmailCode = VerifyCodeText;
}
try
{
// 开始登录
await _steamAccountService.DoLoginV2Async(loginState);
}
catch (HttpRequestException)
{
Toast.Show(ToastIcon.Error, AppResources.LocalAuth_JoinSteamAuthenticator_LoginRequestError);
return;
}
// 登陆结果
if (!loginState.Success)
{
if (loginState.RequiresEmailAuth)
{
RequireVerifyCode = true;
Toast.Show(ToastIcon.Info, Strings.LocalAuth_EmailCodeTip);
return;
}
else if (loginState.Requires2FA)
{
Toast.Show(ToastIcon.Error, AppResources.LocalAuth_SteamUser_Requires2FA);
return;
}
else
{
Toast.Show(ToastIcon.Error, loginState.Message ?? string.Empty);
}
return;
}
// 根据登录信息 获取/初始化 TwoFA Steam Authenticator 信息
var (initialized, errMsg) = await InitTwoFASteamAuthenticatorAsync(loginState);
if (!initialized)
{
Toast.Show(ToastIcon.Error, errMsg);
return;
}
RevocationCodeText = _currentSteamAuthenticator!.RecoveryCode;
// 跳转到验证页面
SelectIndex = STEPINDEX_VERIFY;
}
finally
{
Loading = false;
}
}
/// <summary>
/// 校验验证码
/// </summary>
/// <returns></returns>
public async Task VerifyCodeAsync()
{
if (Loading)
return;
Loading = true;
try
{
if (string.IsNullOrWhiteSpace(Code))
{
Toast.Show(ToastIcon.Error, AppResources.LocalAuth_JoinSteamAuthenticator_SteamGuardCodeEmptyError);
return;
}
var equals = await CompareCodeAsync();
if (!equals)
{
Toast.Show(ToastIcon.Warning,
$@"{AppResources.LocalAuth_JoinSteamAuthenticator_VerifySteamGuardCodeError}: {Code} != {_currentSteamAuthenticator?.CurrentCode}");
return;
}
RevocationCodeText = _currentSteamAuthenticator!.RecoveryCode;
SelectIndex = STEPINDEX_DONE;
}
finally
{
Loading = false;
}
}
/// <summary>
/// 保存令牌
/// </summary>
/// <returns></returns>
public async Task SaveAsync()
{
if (Loading)
return;
Loading = true;
try
{
if (_currentSteamAuthenticator == null)
{
Toast.Show(ToastIcon.Error, AppResources.LocalAuth_JoinSteamAuthenticator_InitLocalAuthenticatorError);
SelectIndex = STEPINDEX_LOGIN;
return;
}
if (string.IsNullOrEmpty(Code))
{
Toast.Show(ToastIcon.Error, AppResources.LocalAuth_JoinSteamAuthenticator_SteamGuardCodeEmptyError);
SelectIndex = STEPINDEX_VERIFY;
return;
}
if (!await SaveAuthenticatorAsync(UserNameText!, _currentSteamAuthenticator))
{
Toast.Show(ToastIcon.Error, AppResources.LocalAuth_JoinSteamAuthenticator_SaveLocalAuthenticatorError);
return;
}
// 保存完成重置
Reset();
}
finally
{
Loading = false;
}
}
/// <summary>
/// 重置恢复代码
/// </summary>
/// <returns></returns>
public async Task ResetRevocationCodeAsync()
{
if (_currentSteamLoginState == null)
{
return;
}
// 根据登录信息 获取/初始化 TwoFA Steam Authenticator 信息
var (initialized, errMsg) = await InitTwoFASteamAuthenticatorAsync(_currentSteamLoginState);
if (!initialized)
{
Toast.Show(ToastIcon.Error, errMsg);
return;
}
RevocationCodeText = _currentSteamAuthenticator!.RecoveryCode;
}
#endregion 联合 Steam令牌 页面流程
#region 辅助方法
/// <summary>
/// 初始化 TwoFA Steam Authenticator 信息
/// </summary>
/// <param name="loginState"></param>
/// <returns></returns>
private async Task<(bool initialized, string errorMsg)> InitTwoFASteamAuthenticatorAsync(SteamLoginState loginState)
{
_currentSteamAuthenticator = new SteamAuthenticator();
string? steamId = loginState.SteamId != default
? loginState.SteamId.ToString()
: null;
if (string.IsNullOrEmpty(steamId))
return (false, $"{AppResources.LocalAuth_JoinSteamAuthenticator_InitLocalAuthenticatorError}:{nameof(steamId)}");
string deviceId = CreateNewDeviceId();
var client = _currentSteamAuthenticator.GetClient();
string authenticatorJson;
try
{
authenticatorJson = await client
.AddAuthenticatorAsync(
steamId,
DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(),
deviceId,
loginState.AccessToken ?? string.Empty
);
}
catch (Exception ex)
{
return (false, $"{AppResources.LocalAuth_JoinSteamAuthenticator_RequestUser2FAInfoError}:{ex.Message}");
}
if (string.IsNullOrEmpty(authenticatorJson))
return (false, AppResources.LocalAuth_JoinSteamAuthenticator_RequestUser2FAInfoError);
var (initialized, msg) = TryParseSteamAuthenticator(authenticatorJson, out var parsedSteamData)
? (true, string.Empty)
: (false, AppResources.LocalAuth_JoinSteamAuthenticator_ParseUser2FAInfoError);
// 解析响应之后赋值给当前本地令牌
if (initialized)
{
_currentSteamAuthenticator.DeviceId = deviceId;
_currentSteamAuthenticator.SteamData = SystemTextJsonSerializer.Serialize(parsedSteamData!, SteamJsonContext.Default.SteamConvertSteamDataJsonStruct);
_currentSteamAuthenticator.SecretKey = Base64Extensions.Base64DecodeToByteArray_Nullable(parsedSteamData!.SharedSecret);
_currentSteamAuthenticator.Serial = parsedSteamData.SerialNumber;
}
return (initialized, msg);
}
/// <summary>
/// 验证令牌验证码
/// </summary>
/// <returns></returns>
private async Task<bool> CompareCodeAsync()
{
if (_currentSteamAuthenticator == null)
{
return false;
}
try
{
await Task.Yield();
_currentSteamAuthenticator.Sync();
}
catch (Exception ex)
{
ex.LogAndShowT();
return false;
}
bool compareResult = string.Equals(Code, _currentSteamAuthenticator?.CurrentCode, StringComparison.OrdinalIgnoreCase);
return compareResult;
}
/// <summary>
/// 解析 Steam Authenticator json响应
/// </summary>
/// <param name="authenticatorJson"></param>
/// <param name="parsedSteamAuthenticator">已解析的响应信息</param>
/// <returns></returns>
private static bool TryParseSteamAuthenticator(string authenticatorJson, out SteamConvertSteamDataJsonStruct? parsedSteamAuthenticator)
{
parsedSteamAuthenticator = default;
SteamDoLoginTfaJsonStruct? authenticatorDataResp;
try
{
authenticatorDataResp = SystemTextJsonSerializer.Deserialize(
authenticatorJson,
SteamJsonContext.Default.SteamDoLoginTfaJsonStruct
);
}
catch (Exception)
{
return false;
}
if (authenticatorDataResp == null || authenticatorDataResp.Response == null)
return false;
parsedSteamAuthenticator = authenticatorDataResp.Response;
// 目前只需要知道是否含有令牌数据信息
// 不需要知道当前状态可不可以绑定,绑定操作在 Steam App 中完成
// 这里只是将令牌数据保存到本地 以便后续计算
return parsedSteamAuthenticator != null;
}
/// <summary>
/// 保存令牌
/// </summary>
/// <param name="authenticatorName"></param>
/// <param name="authenticator"></param>
/// <returns></returns>
private static Task<bool> SaveAuthenticatorAsync(string authenticatorName, SteamAuthenticator authenticator)
{
var iADTO = new AuthenticatorDTO
{
Name = $"Steam({authenticatorName})",
Value = authenticator,
Created = DateTimeOffset.Now,
};
return AuthenticatorHelper.SaveAuthenticator(iADTO);
}
/// <summary>
/// 创建新的设备ID
/// </summary>
/// <returns></returns>
private static string CreateNewDeviceId() => $"android:{Guid.NewGuid()}";
/// <summary>
/// 重置页面绑定信息
/// </summary>
public void Reset()
{
UserNameText = default;
PasswordText = default;
Code = default;
VerifyCodeText = default;
RequireVerifyCode = default;
RevocationCodeText = default;
SelectIndex = STEPINDEX_LOGIN;
_currentSteamAuthenticator = default;
_currentSteamLoginState = default;
}
#endregion 辅助方法
}
@@ -0,0 +1,149 @@
<UserControl
xmlns="https://github.com/avaloniaui"
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"
xmlns:s="https://steampp.net/services"
xmlns:spp="https://steampp.net/ui"
x:CompileBindings="True"
x:DataType="spp:JoinSteamAuthenticatorPageViewModel"
x:Class="BD.WTTS.UI.Views.Pages.JoinSteamAuthenticatorPage"
mc:Ignorable="d">
<Grid RowDefinitions="Auto,*">
<spp:Stepper SelectedIndex="{Binding SelectIndex}">
<spp:StepperItem Content="{Binding Path=Res.Steam_Login, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
<spp:StepperItem Content="{Binding Path=Res.LocalAuth_JoinSteamAuthenticator_ConfirmSteamAppAuthenticatorCode, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
<spp:StepperItem Content="{Binding Path=Res.Btn_Text_Complete, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
</spp:Stepper>
<spp:ContentLoader
Grid.Row="1"
MinWidth="600"
MinHeight="400"
IsLoading="{Binding Loading}"
IsShowNoResultText="False">
<Carousel IsVisible="{Binding !Loading}" SelectedIndex="{Binding SelectIndex}">
<Panel>
<spp:Snackbar
Title="{Binding Path=Res.Notice_Tray_Title, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
VerticalAlignment="Top"
IsClosable="False"
IsOpen="True"
IsVisible="{Binding RequireVerifyCode}"
Message="{Binding Path=Res.LocalAuth_EmailCodeTip, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
Severity="Warning" />
<StackPanel
HorizontalAlignment="Center"
VerticalAlignment="Center"
Spacing="10">
<PathIcon
Width="88"
Height="88"
Data="{StaticResource Steam}" />
<TextBox
MaxWidth="280"
Text="{Binding UserNameText}"
Watermark="{Binding Path=Res.Steam_User, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
<TextBox
Name="PasswordText"
MaxWidth="280"
Classes="revealPasswordButton"
PasswordChar="{StaticResource PasswordChar}"
Text="{Binding PasswordText}"
Watermark="{Binding Path=Res.Steam_Password, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
<TextBox
IsVisible="{Binding RequireVerifyCode}"
Watermark="{Binding Path=Res.EmailCode, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
Text="{Binding VerifyCodeText}" />
<Button
MinWidth="280"
HorizontalAlignment="Center"
VerticalAlignment="Bottom"
HorizontalContentAlignment="Center"
Command="{Binding LoginAsync}"
Content="{Binding Path=Res.Login, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
</StackPanel>
</Panel>
<Panel>
<spp:Snackbar
Title="{Binding Path=Res.Notice_Tray_Title, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
VerticalAlignment="Top"
IsClosable="False"
IsOpen="True"
Message="{Binding Path=Res.LocalAuth_JoinSteamAuthenticator_InputSteamAppAuthenticatorCodeTips, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
Severity="Warning" />
<StackPanel
HorizontalAlignment="Center"
VerticalAlignment="Center"
Spacing="10">
<DockPanel>
<TextBlock
Margin="0,0,0,6"
DockPanel.Dock="Top"
Text="{Binding Path=Res.RecoveryCode, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
<TextBox
MaxWidth="300"
Text="{Binding RevocationCodeText}"
IsReadOnly="True" />
<!--<Button
Content="重新生成"
Command="{Binding ResetRevocationCodeAsync}" />-->
</DockPanel>
<DockPanel>
<TextBlock
Margin="0,0,0,6"
DockPanel.Dock="Top"
Text="{Binding Path=Res.LocalAuth_JoinSteamAuthenticator_SteamAppAuthenticatorCode, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
<TextBox
MaxWidth="300"
Watermark="{Binding Path=Res.LocalAuth_JoinSteamAuthenticator_InputSteamAppAuthenticatorCode, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
Text="{Binding Code}" />
</DockPanel>
<Button
MinWidth="280"
HorizontalAlignment="Center"
HorizontalContentAlignment="Center"
Command="{Binding VerifyCodeAsync}"
Content="{Binding Path=Res.Continue, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
</StackPanel>
</Panel>
<Panel>
<spp:Snackbar
Title="{Binding Path=Res.Notice_Tray_Title, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
VerticalAlignment="Top"
IsClosable="False"
IsOpen="True"
Message="{Binding Path=Res.RecoveryCode_RememberTip, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
Severity="Success" />
<StackPanel
HorizontalAlignment="Center"
VerticalAlignment="Center"
Spacing="10">
<DockPanel>
<TextBlock
Margin="0,0,0,6"
DockPanel.Dock="Top"
Text="{Binding Path=Res.RecoveryCode, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
<TextBox
MaxWidth="300"
Text="{Binding RevocationCodeText}"
IsReadOnly="True" />
</DockPanel>
<Button
MinWidth="280"
HorizontalAlignment="Center"
HorizontalContentAlignment="Center"
Command="{Binding SaveAsync}"
Content="{Binding Path=Res.Confirm, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
</StackPanel>
</Panel>
</Carousel>
</spp:ContentLoader>
</Grid>
</UserControl>
@@ -0,0 +1,13 @@
using Avalonia.Controls;
namespace BD.WTTS.UI.Views.Pages;
public partial class JoinSteamAuthenticatorPage : UserControl
{
public JoinSteamAuthenticatorPage()
{
InitializeComponent();
DataContext = new JoinSteamAuthenticatorPageViewModel();
}
}
@@ -102,11 +102,13 @@
IsVisible="{Binding !!!Confirmations.Count}"
Text="{Binding Path=Res.LocalAuth_AuthTrade_Null, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
<ItemsRepeater ItemsSource="{Binding Confirmations}">
<ItemsRepeater.Layout>
<StackLayout Orientation="Vertical" Spacing="5" />
</ItemsRepeater.Layout>
<ItemsRepeater.ItemTemplate>
<ItemsControl ItemsSource="{Binding Confirmations}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" Spacing="5" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type spp:SteamTradeConfirmationModel}">
<ui:SettingsExpander>
<ui:SettingsExpander.Header>
@@ -210,8 +212,8 @@
IsClickEnabled="True" />-->
</ui:SettingsExpander>
</DataTemplate>
</ItemsRepeater.ItemTemplate>
</ItemsRepeater>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Panel>
</Grid>
@@ -696,7 +696,7 @@ Windows Registry Editor Version 5.00
var idsFile = Path.Combine(localCachePath, "ids.json");
var accountRemarks = Ioc.Get<IPartialGameAccountSettings>()?.AccountRemarks;
var accountRemarks = Ioc.Get_Nullable<IPartialGameAccountSettings>()?.AccountRemarks;
var accList = File.Exists(idsFile) ? JTokenHelper.ReadDict(idsFile).ToList() : null;
if (accList.Any_Nullable())
@@ -40,6 +40,11 @@ public partial interface IGameAccountSettings
/// </summary>
ConcurrentDictionary<string, PlatformSettings>? PlatformSettings { get; set; }
/// <summary>
/// 是否显示账号用户名
/// </summary>
bool IsShowAccountName { get; set; }
/// <summary>
/// 账号备注字典的默认值
/// </summary>
@@ -60,4 +65,9 @@ public partial interface IGameAccountSettings
/// </summary>
static readonly ConcurrentDictionary<string, PlatformSettings> DefaultPlatformSettings = new();
/// <summary>
/// 是否显示账号用户名的默认值
/// </summary>
static readonly bool DefaultIsShowAccountName = false;
}
@@ -67,6 +67,12 @@ public sealed partial class GameAccountSettings_ : IGameAccountSettings, ISettin
[MPKey(3), MP2Key(3), JsonPropertyOrder(3)]
public ConcurrentDictionary<string, PlatformSettings>? PlatformSettings { get; set; } = IGameAccountSettings.DefaultPlatformSettings;
/// <summary>
/// 是否显示账号用户名
/// </summary>
[MPKey(4), MP2Key(4), JsonPropertyOrder(4)]
public bool IsShowAccountName { get; set; } = IGameAccountSettings.DefaultIsShowAccountName;
}
public static partial class GameAccountSettings
@@ -95,4 +101,10 @@ public static partial class GameAccountSettings
public static SettingsProperty<string, PlatformSettings, ConcurrentDictionary<string, PlatformSettings>, GameAccountSettings_> PlatformSettings { get; }
= new(DefaultPlatformSettings);
/// <summary>
/// 是否显示账号用户名
/// </summary>
public static SettingsStructProperty<bool, GameAccountSettings_> IsShowAccountName { get; }
= new(DefaultIsShowAccountName);
}
@@ -6,6 +6,7 @@
xmlns:i="using:Avalonia.Xaml.Interactivity"
xmlns:ia="using:Avalonia.Xaml.Interactions.Core"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ms="https://steampp.net/settings"
xmlns:s="https://steampp.net/services"
xmlns:spp="https://steampp.net/ui"
xmlns:ui="using:FluentAvalonia.UI.Controls"
@@ -219,8 +220,13 @@
ContextFlyout="{StaticResource SharedMenuFlyout}"
Description="{Binding LastLoginTime, StringFormat={}{0:yyyy-MM-dd HH:mm:ss}}"
MoreFlyout="{StaticResource SharedMenuFlyout}"
Status="{Binding Path=Res.UserChange_RecentLogin, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
Tags="{Binding AliasName}">
Status="{Binding Path=Res.UserChange_RecentLogin, Mode=OneWay, Source={x:Static s:ResourceService.Current}}">
<spp:AppItem.Tags>
<WrapPanel>
<TextBlock IsVisible="{Binding Source={x:Static ms:GameAccountSettings.IsShowAccountName}, Path=Value, Mode=OneWay}" Text="{Binding AccountName}" />
<TextBlock IsVisible="{Binding AliasName, Converter={StaticResource IsNullConverter}, ConverterParameter=invert}" Text="{Binding AliasName, StringFormat={}({0})}" />
</WrapPanel>
</spp:AppItem.Tags>
<ToolTip.Tip>
<TextBlock>
<Run Text="双击可快速切换到此账号登录" />
@@ -58,7 +58,7 @@ public partial class AccountItems : ReactiveUserControl<PlatformAccount>
3 => idConvert.Id32,
_ => idConvert.Id64,
};
App.Instance.CopyToClipboardCommand(id);
App.Instance.CopyToClipboardCommandCore(id);
}
}
@@ -4,6 +4,7 @@
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"
xmlns:ms="https://steampp.net/settings"
xmlns:s="https://steampp.net/services"
xmlns:spp="https://steampp.net/ui"
xmlns:ui="using:FluentAvalonia.UI.Controls"
@@ -125,6 +126,10 @@
IsVisible="{Binding !IsSelectedSteam}"
Text="平台设置" />
<!--<ui:MenuFlyoutItem x:Name="PluginSettingButton" Text="{Binding Path=Res.Settings_Plugin, Mode=OneWay,Source={x:Static s:ResourceService.Current}}" />-->
<ui:ToggleMenuFlyoutItem
IsChecked="{Binding Source={x:Static ms:GameAccountSettings.IsShowAccountName}, Path=Value, Mode=TwoWay}"
IsVisible="{Binding IsSelectedSteam}"
Text="显示用户名" />
<ui:MenuFlyoutSeparator IsVisible="{Binding !IsSelectedSteam}" />
<ui:MenuFlyoutItem IsEnabled="False">
<ui:MenuFlyoutItem.Text>
@@ -394,11 +394,13 @@
<TabItem Header="{Binding Path=Res.LaunchItem, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" IsVisible="{Binding App.IsInstalled}">
<ScrollViewer>
<StackPanel Classes="InfoBox">
<ItemsRepeater ItemsSource="{Binding App.LaunchItems}">
<ItemsRepeater.Layout>
<StackLayout Orientation="Vertical" Spacing="{StaticResource SettingsSpacing}" />
</ItemsRepeater.Layout>
<ItemsRepeater.ItemTemplate>
<ItemsControl ItemsSource="{Binding App.LaunchItems}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" Spacing="{StaticResource SettingsSpacing}" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type spp:SteamAppLaunchItem}">
<Border Classes="Item">
<StackPanel Spacing="5">
@@ -460,8 +462,8 @@
</StackPanel>
</Border>
</DataTemplate>
</ItemsRepeater.ItemTemplate>
</ItemsRepeater>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Border Classes="Item">
<Button
HorizontalAlignment="Stretch"
@@ -502,11 +504,13 @@
</StackPanel>
</Border>
<ItemsRepeater ItemsSource="{Binding App.SaveFiles}">
<ItemsRepeater.Layout>
<StackLayout Orientation="Vertical" Spacing="{StaticResource SettingsSpacing}" />
</ItemsRepeater.Layout>
<ItemsRepeater.ItemTemplate>
<ItemsControl ItemsSource="{Binding App.SaveFiles}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" Spacing="{StaticResource SettingsSpacing}" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type spp:SteamAppSaveFile}">
<Border Classes="Item">
<StackPanel Spacing="5">
@@ -539,8 +543,8 @@
</StackPanel>
</Border>
</DataTemplate>
</ItemsRepeater.ItemTemplate>
</ItemsRepeater>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</ScrollViewer>
</TabItem>
@@ -349,63 +349,17 @@
<spp:ContentLoader.GestureRecognizers>
<ScrollGestureRecognizer CanHorizontallyScroll="True" CanVerticallyScroll="True" />
</spp:ContentLoader.GestureRecognizers>
<ItemsRepeater
x:Name="GameListRepeater"
ItemsSource="{Binding SteamApps}"
VerticalCacheLength="300">
<!--
Classes.Compact="{Binding Path=Value, Mode=OneWay, Source={x:Static ms:GameLibrarySettings.GameLibraryLayoutType}, Converter={StaticResource EnumEqualValueConverter}, ConverterParameter={x:Static spp:GridLayoutType.CompactGrid}}"
Classes.Grid="{Binding Path=Value, Mode=OneWay, Source={x:Static ms:GameLibrarySettings.GameLibraryLayoutType}, Converter={StaticResource EnumEqualValueConverter}, ConverterParameter={x:Static spp:GridLayoutType.Grid}}"
Classes.List="{Binding Path=Value, Mode=OneWay, Source={x:Static ms:GameLibrarySettings.GameLibraryLayoutType}, Converter={StaticResource EnumEqualValueConverter}, ConverterParameter={x:Static spp:GridLayoutType.List}}"
-->
<!--<ItemsRepeater.Styles>
<Style Selector="ItemsRepeater.Grid">
<Setter Property="Layout">
<Setter.Value>
<UniformGridLayout
ItemsJustification="Start"
ItemsStretch="Uniform"
MinColumnSpacing="10"
MinItemHeight="310"
MinItemWidth="150"
MinRowSpacing="10" />
</Setter.Value>
</Setter>
</Style>
<Style Selector="ItemsRepeater.List">
<Setter Property="Layout">
<Setter.Value>
<StackLayout Orientation="Vertical" Spacing="10" />
</Setter.Value>
</Setter>
</Style>
<Style Selector="ItemsRepeater.Compact">
<Setter Property="Layout">
<Setter.Value>
<UniformGridLayout
ItemsJustification="Start"
ItemsStretch="Uniform"
MinColumnSpacing="5"
MinItemHeight="65"
MinItemWidth="230"
MinRowSpacing="5" />
</Setter.Value>
</Setter>
</Style>
<Style Selector="spp|AppItem.List">
<Setter Property="MaxHeight" Value="65" />
</Style>
</ItemsRepeater.Styles>-->
<ItemsRepeater.Layout>
<UniformGridLayout
<ui:ItemsRepeater ItemsSource="{Binding SteamApps}">
<ui:ItemsRepeater.Layout>
<ui:UniformGridLayout
ItemsJustification="Start"
ItemsStretch="Uniform"
MinColumnSpacing="10"
MinItemHeight="310"
MinItemWidth="150"
MinRowSpacing="10" />
</ItemsRepeater.Layout>
<ItemsRepeater.ItemTemplate>
</ui:ItemsRepeater.Layout>
<ui:ItemsRepeater.ItemTemplate>
<DataTemplate DataType="spp:SteamApp">
<!-- Classes.Vertical="{Binding Path=Value, Mode=OneWay, Source={x:Static ms:GameLibrarySettings.GameLibraryLayoutType}, Converter={StaticResource EnumEqualValueConverter}, ConverterParameter={x:Static spp:GridLayoutType.Grid}}" -->
<spp:AppItem
@@ -465,8 +419,8 @@
</spp:AppItem.Image>
</spp:AppItem>
</DataTemplate>
</ItemsRepeater.ItemTemplate>
</ItemsRepeater>
</ui:ItemsRepeater.ItemTemplate>
</ui:ItemsRepeater>
</spp:ContentLoader>
</spp:PageBase>
@@ -11,45 +11,8 @@ public partial class GameListPage : PageBase<GameListPageViewModel>
{
InitializeComponent();
DataContext ??= new GameListPageViewModel();
//GameLibrarySettings.GameLibraryLayoutType.Subscribe(x =>
//{
// GameListRepeater.Layout = GetGameLayout(x);
//});
}
//static VirtualizingLayout GetGameLayout(GridLayoutType layoutType)
//{
// VirtualizingLayout layout = layoutType switch
// {
// GridLayoutType.List => new StackLayout()
// {
// Orientation = Orientation.Vertical,
// Spacing = 10,
// },
// GridLayoutType.CompactGrid => new UniformGridLayout()
// {
// MinItemWidth = 230,
// MinItemHeight = 65,
// MinColumnSpacing = 5,
// MinRowSpacing = 5,
// ItemsJustification = UniformGridLayoutItemsJustification.Start,
// ItemsStretch = UniformGridLayoutItemsStretch.Uniform,
// },
// _ => new UniformGridLayout()
// {
// MinItemWidth = 150,
// MinItemHeight = 310,
// MinColumnSpacing = 10,
// MinRowSpacing = 10,
// ItemsJustification = UniformGridLayoutItemsJustification.Start,
// ItemsStretch = UniformGridLayoutItemsStretch.Uniform,
// },
// };
// return layout;
//}
private void AppOpenLink_MenuItem_Click(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
{
if (sender is MenuFlyoutItem item && item.DataContext is SteamApp app)
@@ -260,7 +260,7 @@
Command="{Binding $parent[spp:PageBase].((spp:IdleAppsPageViewModel)DataContext).RunStopBtnCommand}"
CommandParameter="{Binding}"
Cursor="Hand"
IsVisible="{Binding !Process, Converter={StaticResource IsNullConverter}}"
IsVisible="{Binding Process, Converter={StaticResource IsNullConverter}, ConverterParameter=invert}"
ToolTip.Tip="{Binding Path=Res.GameList_StopItemBtn, Mode=OneWay, Source={x:Static s:ResourceService.Current}}">
<Viewbox Width="60" Height="60">
<ui:SymbolIcon Symbol="Pause" />
@@ -113,7 +113,7 @@ public sealed partial class IdleCardPageViewModel : ViewModelBase
{
if (SteamLoginState.Success && SteamLoginState.SteamId != (ulong?)SteamConnectService.Current.CurrentSteamUser?.SteamId64)
{
Toast.Show(ToastIcon.Error, Strings.SteamIdle_LoginSteamUserError);
Toast.Show(ToastIcon.Warning, Strings.SteamIdle_LoginSteamUserError);
//RunState = false;
//RunLoaingState = false;
//return;
@@ -228,10 +228,9 @@ public sealed partial class IdleCardPageViewModel : ViewModelBase
LoginViewModel.Close += async _ =>
{
IsLogin = SteamLoginState.Success;
ViewState = 1;
await LoadBadges();
SteamAppsSort();
ViewState = 1;
};
ViewState = 0;
//var vm = new IdleSteamLoginPageViewModel(ref SteamLoginState);
@@ -429,7 +428,7 @@ public sealed partial class IdleCardPageViewModel : ViewModelBase
{
var multi = IdleGameList.Where(z => z.Badge.HoursPlayed >= SteamIdleSettings.MinRunTime.Value).ToList();
if (multi.Count > 1)
if (multi.Count > 1 || (multi.Count == 1 && IdleGameList.Count == 1))
{
idleApp = VerifyIsNext(multi, isNext);
PauseAutoNext(false);
@@ -529,17 +529,20 @@
IsVisible="{Binding !IdleGameList.Count}"
Text="未获取到挂卡游戏数据" />
</StackPanel>
<ItemsRepeater DockPanel.Dock="Bottom" ItemsSource="{Binding IdleGameList}">
<ItemsRepeater.Layout>
<UniformGridLayout
<ui:ItemsRepeater
DockPanel.Dock="Bottom"
ItemsSource="{Binding IdleGameList}"
VerticalCacheLength="50">
<ui:ItemsRepeater.Layout>
<ui:UniformGridLayout
ItemsJustification="Start"
ItemsStretch="Uniform"
MinColumnSpacing="5"
MinItemHeight="160"
MinItemWidth="280"
MinRowSpacing="5" />
</ItemsRepeater.Layout>
<ItemsRepeater.ItemTemplate>
</ui:ItemsRepeater.Layout>
<ui:ItemsRepeater.ItemTemplate>
<DataTemplate DataType="spp:IdleApp">
<spp:AppItem
Title="{Binding App.DisplayName}"
@@ -698,8 +701,8 @@
</spp:AppItem.Image>
</spp:AppItem>
</DataTemplate>
</ItemsRepeater.ItemTemplate>
</ItemsRepeater>
</ui:ItemsRepeater.ItemTemplate>
</ui:ItemsRepeater>
</Panel>
</spp:OptionsDisplayItem.Content>
</spp:OptionsDisplayItem>
+2
View File
@@ -152,4 +152,6 @@ public partial interface IApplication
System.Drawing.Size? GetScreenSize() => null;
bool? IsAnyWindowNotMinimized() => null;
async void OpenBrowserCommandCore(object? url) => await Browser2.OpenAsync(url?.ToString());
}
@@ -160,15 +160,6 @@ public static class ThirdPartyLoginHelper
static IDisposable? serverDisposable;
/// <summary>
/// 释放 WebSocket Server 占用资源
/// </summary>
public static void DisposeServer()
{
serverDisposable?.Dispose();
serverDisposable = null;
}
static void StartServer(IApplication app)
{
if (ws != null) return;
@@ -196,6 +187,15 @@ public static class ThirdPartyLoginHelper
});
}
/// <summary>
/// 释放 WebSocket Server 占用资源
/// </summary>
public static void DisposeServer()
{
serverDisposable?.Dispose();
serverDisposable = null;
}
static Aes? tempAes;
static bool isBind;
static WindowViewModel? vm;
@@ -220,7 +220,7 @@ public static class ThirdPartyLoginHelper
public static async Task StartAsync(WindowViewModel vm, ExternalLoginChannel channel, bool isBind)
{
var app = IApplication.Instance;
if (!OperatingSystem2.IsAndroid() && !OperatingSystem2.IsIOS())
if (!OperatingSystem2.IsAndroid() && !OperatingSystem2.IsIOS() && !OperatingSystem2.IsMacOS())
{
// Android/iOS 使用 URL Scheme 回调
StartServer(app);
@@ -273,8 +273,10 @@ public static class ThirdPartyLoginHelper
qs.Add("dg", DeviceIdHelper.DeviceIdG.ToStringN());
qs.Add("dr", DeviceIdHelper.DeviceIdR);
qs.Add("dn", DeviceIdHelper.DeviceIdN);
if (OperatingSystem.IsMacOS())
if (OperatingSystem2.IsMacOS())
{
qs.Add("isUS", "true");
}
var ub = new UriBuilder(apiBaseUrl)
{
Path = $"/identity/v1/externallogin/{(int)channel}",
+118 -1
View File
@@ -477,7 +477,7 @@ namespace BD.WTTS.Client.Resources {
}
/// <summary>
/// 查找类似 ASF 挂卡 的本地化字符串。
/// 查找类似 ASF 的本地化字符串。
/// </summary>
public static string ArchiSteamFarmPlus {
get {
@@ -4195,6 +4195,123 @@ namespace BD.WTTS.Client.Resources {
}
}
/// <summary>
/// 查找类似 共存令牌 的本地化字符串。
/// </summary>
public static string LocalAuth_JoinSteamAuthenticator {
get {
return ResourceManager.GetString("LocalAuth_JoinSteamAuthenticator", resourceCulture);
}
}
/// <summary>
/// 查找类似 确认 Steam App 令牌验证码 的本地化字符串。
/// </summary>
public static string LocalAuth_JoinSteamAuthenticator_ConfirmSteamAppAuthenticatorCode {
get {
return ResourceManager.GetString("LocalAuth_JoinSteamAuthenticator_ConfirmSteamAppAuthenticatorCode", resourceCulture);
}
}
/// <summary>
/// 查找类似 初始化本地令牌错误 的本地化字符串。
/// </summary>
public static string LocalAuth_JoinSteamAuthenticator_InitLocalAuthenticatorError {
get {
return ResourceManager.GetString("LocalAuth_JoinSteamAuthenticator_InitLocalAuthenticatorError", resourceCulture);
}
}
/// <summary>
/// 查找类似 请输入 Steam App 中显示的令牌验证码 的本地化字符串。
/// </summary>
public static string LocalAuth_JoinSteamAuthenticator_InputSteamAppAuthenticatorCode {
get {
return ResourceManager.GetString("LocalAuth_JoinSteamAuthenticator_InputSteamAppAuthenticatorCode", resourceCulture);
}
}
/// <summary>
/// 查找类似 打开 Steam App 绑定令牌后在此页面输入验证 的本地化字符串。
/// </summary>
public static string LocalAuth_JoinSteamAuthenticator_InputSteamAppAuthenticatorCodeTips {
get {
return ResourceManager.GetString("LocalAuth_JoinSteamAuthenticator_InputSteamAppAuthenticatorCodeTips", resourceCulture);
}
}
/// <summary>
/// 查找类似 登录请求错误 的本地化字符串。
/// </summary>
public static string LocalAuth_JoinSteamAuthenticator_LoginRequestError {
get {
return ResourceManager.GetString("LocalAuth_JoinSteamAuthenticator_LoginRequestError", resourceCulture);
}
}
/// <summary>
/// 查找类似 解析用户 Steam 令牌信息失败 的本地化字符串。
/// </summary>
public static string LocalAuth_JoinSteamAuthenticator_ParseUser2FAInfoError {
get {
return ResourceManager.GetString("LocalAuth_JoinSteamAuthenticator_ParseUser2FAInfoError", resourceCulture);
}
}
/// <summary>
/// 查找类似 获取用户 Steam 令牌信息失败 的本地化字符串。
/// </summary>
public static string LocalAuth_JoinSteamAuthenticator_RequestUser2FAInfoError {
get {
return ResourceManager.GetString("LocalAuth_JoinSteamAuthenticator_RequestUser2FAInfoError", resourceCulture);
}
}
/// <summary>
/// 查找类似 保存令牌失败 的本地化字符串。
/// </summary>
public static string LocalAuth_JoinSteamAuthenticator_SaveLocalAuthenticatorError {
get {
return ResourceManager.GetString("LocalAuth_JoinSteamAuthenticator_SaveLocalAuthenticatorError", resourceCulture);
}
}
/// <summary>
/// 查找类似 Steam App 令牌验证码 的本地化字符串。
/// </summary>
public static string LocalAuth_JoinSteamAuthenticator_SteamAppAuthenticatorCode {
get {
return ResourceManager.GetString("LocalAuth_JoinSteamAuthenticator_SteamAppAuthenticatorCode", resourceCulture);
}
}
/// <summary>
/// 查找类似 请输入已在 Steam App 中绑定的令牌当前的令牌验证码 的本地化字符串。
/// </summary>
public static string LocalAuth_JoinSteamAuthenticator_SteamGuardCodeEmptyError {
get {
return ResourceManager.GetString("LocalAuth_JoinSteamAuthenticator_SteamGuardCodeEmptyError", resourceCulture);
}
}
/// <summary>
/// 查找类似 验证令牌错误 的本地化字符串。
/// </summary>
public static string LocalAuth_JoinSteamAuthenticator_VerifySteamGuardCodeError {
get {
return ResourceManager.GetString("LocalAuth_JoinSteamAuthenticator_VerifySteamGuardCodeError", resourceCulture);
}
}
/// <summary>
/// 查找类似 在 Watt Toolkit 中与官方 Steam App 中使用相同的令牌信息 的本地化字符串。
/// </summary>
public static string LocalAuth_JoinSteamAuthenticatorDesc {
get {
return ResourceManager.GetString("LocalAuth_JoinSteamAuthenticatorDesc", resourceCulture);
}
}
/// <summary>
/// 查找类似 确定要注销当前令牌登录的账号信息吗? 的本地化字符串。
/// </summary>
File diff suppressed because it is too large Load Diff
@@ -95,10 +95,11 @@ public sealed class AdvertiseService : ReactiveObject
}
}
private static async void ClickAdvertisement(AdvertisementDTO dto)
static async void ClickAdvertisement(AdvertisementDTO? dto)
{
if (dto != null)
{
//IApplication.Instance.OpenBrowserCommandCore(dto.Url);
await Browser2.OpenAsync(dto.Url);
}
}
@@ -224,6 +224,12 @@ public sealed class UserService : ReactiveObject
/// <returns></returns>
public async Task OpenAuthUrl(string url)
{
if (url.StartsWith(Constants.Urls.WattGame, StringComparison.OrdinalIgnoreCase))
{
OpenAuthUrl(url, FastLoginWebChannel.WattGame);
return;
}
var token = await userManager.GetAuthTokenAsync();
if (token == null)
{
@@ -524,7 +524,7 @@ public sealed class SteamConnectService
#region 加载备注信息和 JumpList
var accountRemarks = Ioc.Get<IPartialGameAccountSettings>()?.AccountRemarks;
var accountRemarks = Ioc.Get_Nullable<IPartialGameAccountSettings>()?.AccountRemarks;
#if WINDOWS
List<(string title, string applicationPath, string iconResourcePath, string arguments, string description, string customCategory)>? jumplistData = new();
@@ -318,7 +318,7 @@ partial class Startup // 自定义控制台命令参数
var users = steamService.GetRememberUserList();
var accountRemarks =
Ioc.Get<IPartialGameAccountSettings>()?.AccountRemarks;
Ioc.Get_Nullable<IPartialGameAccountSettings>()?.AccountRemarks;
var sUsers = users.Select(s =>
{
@@ -10,6 +10,13 @@ public sealed class PluginStorePageViewModel : TabItemViewModel
public override string IconKey => "avares://BD.WTTS.Client.Avalonia/UI/Assets/Icons/home.ico";
public ICommand NavgationToMenuPageCommand { get; }
public PluginStorePageViewModel()
{
NavgationToMenuPageCommand = ReactiveCommand.Create<TabItemViewModel>(NavgationToMenuPage);
}
public void NavgationToMenuPage(TabItemViewModel tabItem)
{
INavigationService.Instance.Navigate(tabItem.PageType, NavigationTransitionEffect.FromBottom);