mirror of
https://github.com/BeyondDimension/SteamTools.git
synced 2026-10-26 12:09:32 +08:00
Compare commits
37
Commits
3.0.0-rc.2
...
gen4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
42464db1bc | ||
|
|
9e4c4836c0 | ||
|
|
d34a5d3347 | ||
|
|
fd119ae0e1 | ||
|
|
3d59c24dec | ||
|
|
ea315a9b44 | ||
|
|
d5592b4bc2 | ||
|
|
2df32c67d0 | ||
|
|
fdaf795202 | ||
|
|
a7572ecd50 | ||
|
|
d433d60d29 | ||
|
|
3fe8f931a2 | ||
|
|
a69d97fcdb | ||
|
|
aa63e3ab9f | ||
|
|
a56fc36380 | ||
|
|
4c5428be5f | ||
|
|
e6953e50b8 | ||
|
|
a961f68242 | ||
|
|
72f301d526 | ||
|
|
2b18e03098 | ||
|
|
9fffe8458a | ||
|
|
ea7282f290 | ||
|
|
3714710dd8 | ||
|
|
00c228abd8 | ||
|
|
54fc1e3593 | ||
|
|
d2d04a37cf | ||
|
|
0600a5ca9f | ||
|
|
01dc528e21 | ||
|
|
9014198aeb | ||
|
|
bfd6b82a95 | ||
|
|
a6a45e5324 | ||
|
|
0ed0416f69 | ||
|
|
ce6fd9a4d6 | ||
|
|
7f06198bb6 | ||
|
|
8202df3a65 | ||
|
|
5033261a64 | ||
|
|
191c957a23 |
@@ -216,6 +216,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Steam++", "src\BD.WTTS.Clie
|
||||
EndProject
|
||||
Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "BD.WTTS.Client.AppHost.Bridge.Package", "src\BD.WTTS.Client.AppHost.Bridge.Package\BD.WTTS.Client.AppHost.Bridge.Package.wapproj", "{27795C79-2994-4514-8656-BA34FCEE8901}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ArchiSteamFarm", "ref\ArchiSteamFarm\ArchiSteamFarm\ArchiSteamFarm.csproj", "{8C34FCD5-8C7F-4B10-A970-7DEA8A61F56B}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -1260,6 +1262,26 @@ Global
|
||||
{27795C79-2994-4514-8656-BA34FCEE8901}.Release|x86.ActiveCfg = Release|x86
|
||||
{27795C79-2994-4514-8656-BA34FCEE8901}.Release|x86.Build.0 = Release|x86
|
||||
{27795C79-2994-4514-8656-BA34FCEE8901}.Release|x86.Deploy.0 = Release|x86
|
||||
{8C34FCD5-8C7F-4B10-A970-7DEA8A61F56B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8C34FCD5-8C7F-4B10-A970-7DEA8A61F56B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8C34FCD5-8C7F-4B10-A970-7DEA8A61F56B}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{8C34FCD5-8C7F-4B10-A970-7DEA8A61F56B}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{8C34FCD5-8C7F-4B10-A970-7DEA8A61F56B}.Debug|ARM64.ActiveCfg = Debug|Any CPU
|
||||
{8C34FCD5-8C7F-4B10-A970-7DEA8A61F56B}.Debug|ARM64.Build.0 = Debug|Any CPU
|
||||
{8C34FCD5-8C7F-4B10-A970-7DEA8A61F56B}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{8C34FCD5-8C7F-4B10-A970-7DEA8A61F56B}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{8C34FCD5-8C7F-4B10-A970-7DEA8A61F56B}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{8C34FCD5-8C7F-4B10-A970-7DEA8A61F56B}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{8C34FCD5-8C7F-4B10-A970-7DEA8A61F56B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8C34FCD5-8C7F-4B10-A970-7DEA8A61F56B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8C34FCD5-8C7F-4B10-A970-7DEA8A61F56B}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{8C34FCD5-8C7F-4B10-A970-7DEA8A61F56B}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{8C34FCD5-8C7F-4B10-A970-7DEA8A61F56B}.Release|ARM64.ActiveCfg = Release|Any CPU
|
||||
{8C34FCD5-8C7F-4B10-A970-7DEA8A61F56B}.Release|ARM64.Build.0 = Release|Any CPU
|
||||
{8C34FCD5-8C7F-4B10-A970-7DEA8A61F56B}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{8C34FCD5-8C7F-4B10-A970-7DEA8A61F56B}.Release|x64.Build.0 = Release|Any CPU
|
||||
{8C34FCD5-8C7F-4B10-A970-7DEA8A61F56B}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{8C34FCD5-8C7F-4B10-A970-7DEA8A61F56B}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -1326,6 +1348,7 @@ Global
|
||||
{35676E23-8E54-4785-A75B-98EB0650596B} = {99D97BD4-3F51-48BC-8BD2-647F6D268BB0}
|
||||
{26D8AA24-2ACE-4167-BC2B-117B9BB76AA4} = {5541B406-4A9A-4AC8-AA77-CE14E133DB80}
|
||||
{27795C79-2994-4514-8656-BA34FCEE8901} = {5541B406-4A9A-4AC8-AA77-CE14E133DB80}
|
||||
{8C34FCD5-8C7F-4B10-A970-7DEA8A61F56B} = {99D97BD4-3F51-48BC-8BD2-647F6D268BB0}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {567F588F-E95C-4286-8B30-DB3B2200221C}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
#添加桌面文件
|
||||
run_path=$(dirname "$0")
|
||||
base_path="$(dirname "$run_path")"
|
||||
exec_name="Steam++"
|
||||
rm -rf "$HOME/Desktop/Watt Toolkit.desktop" 2>/dev/null
|
||||
echo "#!/usr/bin/env xdg-open
|
||||
[Desktop Entry]
|
||||
Name=Watt Toolkit
|
||||
Exec=$base_path/$exec_name.sh
|
||||
Icon=$base_path/Icons/Watt-Toolkit.png
|
||||
Terminal=false
|
||||
Type=Application
|
||||
StartupNotify=false" >"$HOME/Desktop/Watt Toolkit.desktop"
|
||||
chmod +x "$HOME/Desktop/Watt Toolkit.desktop"
|
||||
exit 0
|
||||
@@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env xdg-open
|
||||
[Desktop Entry]
|
||||
Name=°²×° Watt Toolkit
|
||||
Exec=curl https://steampp.net/pkg/latest/steamdeck/install.sh | bash -s --
|
||||
Icon=steamdeck-gaming-return
|
||||
Terminal=true
|
||||
Type=Application
|
||||
StartupNotify=false
|
||||
+1
-1
Submodule ref/Avalonia.Image2 updated: 3d8eb52230...88c36e288e
+1
-1
Submodule ref/DirectoryPackages updated: 02663c0b1c...f785a0bae8
+1
-1
Submodule ref/SteamClient updated: 866d8ac88d...d9bfcfca09
Submodule ref/WTTS.MicroServices.ClientSDK updated: 0f04842586...d38c205b17
+1
-1
Submodule ref/WinAuth updated: 06269f56a1...a20460165f
@@ -21,7 +21,7 @@ public static partial class AssemblyInfo
|
||||
/// <summary>
|
||||
/// RC 版本号,范围 0~9,只增不减
|
||||
/// </summary>
|
||||
const string ver_for_rc = "2";
|
||||
const string ver_for_rc = "3";
|
||||
|
||||
public const string FileVersion = $"{Version2}.{ver_for_rc}0{ver_for_preview}.0";
|
||||
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BD.WTTS.Converters;
|
||||
|
||||
public sealed class StringOmitConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
string s = value.ToString();
|
||||
int leng;
|
||||
if (int.TryParse(parameter.ToString(), out leng))
|
||||
{
|
||||
if (s.Length <= leng)
|
||||
return s;
|
||||
else
|
||||
return s[..leng] + "...";
|
||||
}
|
||||
else
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@
|
||||
<spp:StringEqualsConverter x:Key="StringEqualsConverter" />
|
||||
<spp:EnumLocalizationNameConverter x:Key="EnumLocalizationNameConverter" />
|
||||
<spp:VisbleStringConverter x:Key="VisbleStringConverter" />
|
||||
<spp:StringOmitConverter x:Key="StringOmitConverter" />
|
||||
</Application.Resources>
|
||||
<Application.Styles>
|
||||
<sty:FluentAvaloniaTheme PreferSystemTheme="False" PreferUserAccentColor="True" />
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<Styles
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:spp="https://steampp.net/ui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:ms="https://steampp.net/settings"
|
||||
xmlns:sys="using:System"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<Styles
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:spp="https://steampp.net/ui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:s="https://steampp.net/services"
|
||||
x:CompileBindings="True">
|
||||
@@ -16,7 +17,7 @@
|
||||
|
||||
<!-- AutoCompleteBox -->
|
||||
<Style Selector="AutoCompleteBox.Search /template/ TextBox#PART_TextBox">
|
||||
<Setter Property="Watermark" Value="{ReflectionBinding Path=Res.Search, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
<Setter Property="Watermark" Value="{ReflectionBinding Path=Res.Search, Mode=OneWay, Source={x:Static spp:Strings.Search}}" />
|
||||
<Setter Property="InnerRightContent">
|
||||
<Template>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<Styles
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:spp="https://steampp.net/ui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
x:CompileBindings="True">
|
||||
<Design.PreviewWith>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<Styles
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:spp="https://steampp.net/ui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:ui="using:FluentAvalonia.UI.Controls"
|
||||
x:CompileBindings="True">
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<Styles
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:spp="https://steampp.net/ui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
x:CompileBindings="True">
|
||||
<Design.PreviewWith>
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
Stretch="UniformToFill" />
|
||||
<TextBlock
|
||||
HorizontalAlignment="Center"
|
||||
Text="{Binding Path=Res.GameList_IsLoading, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
Text="{Binding Path=Res.GameList_IsLoading, Mode=OneWay, Source={x:Static spp:Strings.GameList_IsLoading}}"
|
||||
Theme="{StaticResource SubtitleTextBlockStyle}" />
|
||||
<TextBlock
|
||||
HorizontalAlignment="Center"
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
Foreground="{DynamicResource TextFillColorPrimaryBrush}"
|
||||
Text="{ReflectionBinding Path=Res.CustomFilePicker_Tip,
|
||||
Mode=OneWay,
|
||||
Source={x:Static s:ResourceService.Current}}"
|
||||
Source={x:Static spp:Strings.CustomFilePicker_Tip}}"
|
||||
TextAlignment="Center"
|
||||
Theme="{StaticResource BodyStrongTextBlockStyle}" />
|
||||
</StackPanel>
|
||||
@@ -76,4 +76,4 @@
|
||||
<Style Selector="spp|CustomFilePicker:pointerover /template/ Panel#FilePickerTipBorder">
|
||||
<Setter Property="IsVisible" Value="True" />
|
||||
</Style>
|
||||
</Styles>
|
||||
</Styles>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<Styles
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:spp="https://steampp.net/ui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
x:CompileBindings="True">
|
||||
<Design.PreviewWith>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<Styles
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:spp="https://steampp.net/ui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:ui="using:FluentAvalonia.UI.Controls"
|
||||
x:CompileBindings="True">
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<Styles
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:spp="https://steampp.net/ui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
x:CompileBindings="True">
|
||||
<Design.PreviewWith>
|
||||
|
||||
@@ -17,10 +17,7 @@
|
||||
Classes="Circle"
|
||||
Value="60" />
|
||||
<ProgressBar Width="150" IsIndeterminate="True" />
|
||||
<ProgressBar
|
||||
Width="150"
|
||||
Classes="notransitions"
|
||||
Value="50" />
|
||||
<ProgressBar Width="150" Value="50" />
|
||||
|
||||
<TextBlock Text="Material Progress" />
|
||||
<ProgressBar
|
||||
@@ -31,7 +28,6 @@
|
||||
<ProgressBar
|
||||
Width="150"
|
||||
Height="5"
|
||||
Classes="Material notransitions"
|
||||
Value="50" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
@@ -58,7 +54,7 @@
|
||||
<Setter Property="Width" Value="{DynamicResource ProgressBarMinHeight}" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="ProgressBar:not(.notransitions) /template/ Border#PART_Indicator">
|
||||
<Style Selector="ProgressBar[IsIndeterminate=False] /template/ Border#PART_Indicator">
|
||||
<Setter Property="Transitions">
|
||||
<Transitions>
|
||||
<DoubleTransition
|
||||
|
||||
@@ -86,4 +86,4 @@
|
||||
</Transitions>
|
||||
</Setter>
|
||||
</Style>
|
||||
</Styles>
|
||||
</Styles>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<Styles
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:spp="https://steampp.net/ui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
x:CompileBindings="True">
|
||||
<Design.PreviewWith>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<ResourceDictionary
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:spp="https://steampp.net/ui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:ui="using:FluentAvalonia.UI.Controls"
|
||||
x:CompileBindings="True">
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<Styles
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:spp="https://steampp.net/ui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
x:CompileBindings="True">
|
||||
<Design.PreviewWith>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<Styles
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:spp="https://steampp.net/ui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:ui="using:FluentAvalonia.UI.Controls"
|
||||
xmlns:uip="using:FluentAvalonia.UI.Controls.Primitives"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<ResourceDictionary
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:spp="https://steampp.net/ui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:ms="https://steampp.net/settings"
|
||||
x:CompileBindings="True">
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<Styles
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:spp="https://steampp.net/ui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:s="https://steampp.net/services"
|
||||
xmlns:ui="using:FluentAvalonia.UI.Controls"
|
||||
@@ -27,26 +28,26 @@
|
||||
<MenuItem
|
||||
x:Name="TextBoxContextMenuCutItem"
|
||||
Command="{Binding $parent[TextBox].Cut}"
|
||||
Header="{Binding Path=Res.Cut, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
Header="{Binding Path=Res.Cut, Mode=OneWay, Source={x:Static spp:Strings.Cut}}"
|
||||
InputGesture="{x:Static TextBox.CutGesture}"
|
||||
IsEnabled="{Binding $parent[TextBox].CanCut}" />
|
||||
<MenuItem
|
||||
x:Name="TextBoxContextMenuCopyItem"
|
||||
Command="{Binding $parent[TextBox].Copy}"
|
||||
Header="{Binding Path=Res.Copy, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
Header="{Binding Path=Res.Copy, Mode=OneWay, Source={x:Static spp:Strings.Copy}}"
|
||||
InputGesture="{x:Static TextBox.CopyGesture}"
|
||||
IsEnabled="{Binding $parent[TextBox].CanCopy}" />
|
||||
<MenuItem
|
||||
x:Name="TextBoxContextMenuPasteItem"
|
||||
Command="{Binding $parent[TextBox].Paste}"
|
||||
Header="{Binding Path=Res.Paste, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
Header="{Binding Path=Res.Paste, Mode=OneWay, Source={x:Static spp:Strings.Paste}}"
|
||||
InputGesture="{x:Static TextBox.PasteGesture}"
|
||||
IsEnabled="{Binding $parent[TextBox].CanPaste}" />
|
||||
<MenuItem Header="-" />
|
||||
<MenuItem
|
||||
x:Name="TextBoxContextMenuSelectAllItem"
|
||||
Command="{Binding $parent[TextBox].SelectAll}"
|
||||
Header="{Binding Path=Res.SelectAll, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
Header="{Binding Path=Res.SelectAll, Mode=OneWay, Source={x:Static spp:Strings.SelectAll}}"
|
||||
InputGesture="Ctrl + A"
|
||||
IsEnabled="{Binding $parent[TextBox].Text, Converter={StaticResource IsNullConverter}, ConverterParameter=invert}" />
|
||||
</MenuFlyout>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<Styles
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:spp="https://steampp.net/ui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:s="https://steampp.net/services"
|
||||
xmlns:ui="using:FluentAvalonia.UI.Controls"
|
||||
@@ -296,8 +297,8 @@
|
||||
</Styles.Resources>
|
||||
|
||||
<Style Selector="ToggleSwitch">
|
||||
<Setter Property="OffContent" Value="{ReflectionBinding Path=Res.Off, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
<Setter Property="OnContent" Value="{ReflectionBinding Path=Res.On, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
<Setter Property="OffContent" Value="{ReflectionBinding Path=Res.Off, Mode=OneWay, Source={x:Static spp:Strings.Off}}" />
|
||||
<Setter Property="OnContent" Value="{ReflectionBinding Path=Res.On, Mode=OneWay, Source={x:Static spp:Strings.On}}" />
|
||||
<Setter Property="MinWidth" Value="0" />
|
||||
</Style>
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<Styles
|
||||
x:Class="BD.WTTS.UI.Styling.CustomTheme"
|
||||
xmlns:spp="https://steampp.net/ui"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
x:CompileBindings="True">
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<ResourceDictionary
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:spp="https://steampp.net/ui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:sys="using:System"
|
||||
xmlns:ui="https://steampp.net/ui"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<ResourceDictionary
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:spp="https://steampp.net/ui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:ui="using:FluentAvalonia.UI.Controls"
|
||||
x:CompileBindings="True">
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<Styles
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:spp="https://steampp.net/ui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:sys="using:System"
|
||||
xmlns:ui="using:FluentAvalonia.UI.Controls"
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<ResourceDictionary xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<ResourceDictionary xmlns="https://github.com/avaloniaui"
|
||||
xmlns:spp="https://steampp.net/ui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<!-- Add Resources Here -->
|
||||
<LinearGradientBrush x:Key="HeaderOpacityMaskBrush" StartPoint="0,0" EndPoint="0%,100%">
|
||||
<GradientStop Offset="0" Color="#FF000000" />
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<ResourceDictionary xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<ResourceDictionary xmlns="https://github.com/avaloniaui"
|
||||
xmlns:spp="https://steampp.net/ui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<!-- Add Resources Here -->
|
||||
<LinearGradientBrush x:Key="HeaderOpacityMaskBrush" StartPoint="0,0" EndPoint="0%,100%">
|
||||
<GradientStop Color="#00000000" />
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<ResourceDictionary xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<ResourceDictionary xmlns="https://github.com/avaloniaui"
|
||||
xmlns:spp="https://steampp.net/ui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<!-- Add Resources Here -->
|
||||
<LinearGradientBrush x:Key="HeaderOpacityMaskBrush" StartPoint="0,0" EndPoint="0%,100%">
|
||||
<GradientStop Offset="0" Color="#FF000000" />
|
||||
|
||||
@@ -97,27 +97,27 @@
|
||||
Content=""
|
||||
Theme="{StaticResource FA_SystemCaptionButton}"
|
||||
ToolTip.Placement="Bottom"
|
||||
ToolTip.Tip="{Binding Path=Res.Minimize, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
ToolTip.Tip="{Binding Path=Res.Minimize, Mode=OneWay, Source={x:Static spp:Strings.Minimize}}" />
|
||||
<Button
|
||||
Name="MaxRestoreButton"
|
||||
Content=""
|
||||
Theme="{StaticResource FA_SystemCaptionButton}"
|
||||
ToolTip.Placement="Bottom"
|
||||
ToolTip.Tip="{Binding Path=Res.Maximize, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
ToolTip.Tip="{Binding Path=Res.Maximize, Mode=OneWay, Source={x:Static spp:Strings.Maximize}}" />
|
||||
<Button
|
||||
Name="CloseButton"
|
||||
Classes="Close"
|
||||
Content="{StaticResource Close}"
|
||||
Theme="{StaticResource FA_SystemCaptionButton}"
|
||||
ToolTip.Placement="Bottom"
|
||||
ToolTip.Tip="{Binding Path=Res.Close, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
ToolTip.Tip="{Binding Path=Res.Close, Mode=OneWay, Source={x:Static spp:Strings.Close}}" />
|
||||
</StackPanel>
|
||||
</ControlTemplate>
|
||||
</Setter>
|
||||
|
||||
<Style Selector="^:maximized /template/ Button#MaxRestoreButton">
|
||||
<Setter Property="Content" Value="" />
|
||||
<Setter Property="ToolTip.Tip" Value="{Binding Path=Res.Restore, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
<Setter Property="ToolTip.Tip" Value="{Binding Path=Res.Restore, Mode=OneWay, Source={x:Static spp:Strings.Restore}}" />
|
||||
</Style>
|
||||
</ControlTheme>
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
Foreground="White"
|
||||
Text="{ReflectionBinding Path=Res.Advertisement,
|
||||
Mode=OneWay,
|
||||
Source={x:Static s:ResourceService.Current}}" />
|
||||
Source={x:Static spp:Strings.Advertisement}}" />
|
||||
<Button
|
||||
Name="CloseAdBtn"
|
||||
HorizontalAlignment="Right"
|
||||
@@ -49,7 +49,7 @@
|
||||
Background="Transparent"
|
||||
Content="{ReflectionBinding Path=Res.Advertisement_Close,
|
||||
Mode=OneWay,
|
||||
Source={x:Static s:ResourceService.Current}}"
|
||||
Source={x:Static spp:Strings.Advertisement_Close}}"
|
||||
Cursor="Hand"
|
||||
Foreground="White" />
|
||||
</Panel>
|
||||
|
||||
@@ -8,8 +8,8 @@ public class OptionsDisplayItem : TemplatedControl
|
||||
public static readonly StyledProperty<string> DescriptionProperty =
|
||||
AvaloniaProperty.Register<OptionsDisplayItem, string>(nameof(Description));
|
||||
|
||||
public static readonly StyledProperty<FAIconElement> IconProperty =
|
||||
AvaloniaProperty.Register<OptionsDisplayItem, FAIconElement>(nameof(Icon));
|
||||
public static readonly StyledProperty<object?> IconProperty =
|
||||
AvaloniaProperty.Register<OptionsDisplayItem, object?>(nameof(Icon));
|
||||
|
||||
public static readonly StyledProperty<bool> NavigatesProperty =
|
||||
AvaloniaProperty.Register<OptionsDisplayItem, bool>(nameof(Navigates));
|
||||
@@ -41,7 +41,7 @@ public class OptionsDisplayItem : TemplatedControl
|
||||
set => SetValue(DescriptionProperty, value);
|
||||
}
|
||||
|
||||
public FAIconElement Icon
|
||||
public object? Icon
|
||||
{
|
||||
get => GetValue(IconProperty);
|
||||
set => SetValue(IconProperty, value);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<UserControl
|
||||
x:Class="BD.WTTS.UI.Views.Controls.SplashScreen"
|
||||
xmlns:spp="https://steampp.net/ui"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
|
||||
@@ -15,9 +15,7 @@
|
||||
<StackPanel Spacing="{StaticResource SettingsSpacing}">
|
||||
<TextBlock
|
||||
Margin="0,0,0,5"
|
||||
Text="{ReflectionBinding Path=Res.About,
|
||||
Mode=OneWay,
|
||||
Source={x:Static s:ResourceService.Current}}"
|
||||
Text="{Binding Path=Res.About, Mode=OneWay, Source={x:Static spp:Strings.About}}"
|
||||
Theme="{StaticResource SubtitleTextBlockStyle}" />
|
||||
|
||||
<spp:OptionsDisplayItem
|
||||
@@ -140,9 +138,7 @@
|
||||
Margin="12,4,0,0"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{DynamicResource TextFillColorPrimaryBrush}"
|
||||
Text="{ReflectionBinding Path=Res.Link,
|
||||
Mode=OneWay,
|
||||
Source={x:Static s:ResourceService.Current}}" />
|
||||
Text="{Binding Path=Res.Link, Mode=OneWay, Source={x:Static spp:Strings.Link}}" />
|
||||
<ItemsRepeater Margin="0,0,6,6" ItemsSource="{Binding Hyperlinks, Mode=OneTime}">
|
||||
<ItemsRepeater.Layout>
|
||||
<UniformGridLayout MinItemWidth="166" />
|
||||
@@ -165,9 +161,7 @@
|
||||
Margin="12,4,0,0"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{DynamicResource TextFillColorPrimaryBrush}"
|
||||
Text="{ReflectionBinding Path=Res.OpenSourceLibrary,
|
||||
Mode=OneWay,
|
||||
Source={x:Static s:ResourceService.Current}}" />
|
||||
Text="{Binding Path=Res.OpenSourceLibrary, Mode=OneWay, Source={x:Static spp:Strings.OpenSourceLibrary}}" />
|
||||
<ItemsRepeater Margin="0,0,6,6" ItemsSource="{Binding OSL, Mode=OneTime}">
|
||||
<ItemsRepeater.Layout>
|
||||
<UniformGridLayout MinItemWidth="290" />
|
||||
|
||||
@@ -122,7 +122,7 @@
|
||||
<TextBox
|
||||
Name="CommandTextBox"
|
||||
Grid.Row="1"
|
||||
Watermark="{Binding Path=Res.Debug_InstructionPlaceholder, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
Watermark="{Binding Path=Res.Debug_InstructionPlaceholder, Mode=OneWay, Source={x:Static spp:Strings.Debug_InstructionPlaceholder}}" />
|
||||
</Grid>
|
||||
</Border>
|
||||
</spp:PageBase>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<UserControl
|
||||
x:Class="BD.WTTS.UI.Views.Pages.ErrorPage"
|
||||
xmlns:spp="https://steampp.net/ui"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
@@ -15,12 +16,12 @@
|
||||
VerticalAlignment="Center"
|
||||
FontSize="16"
|
||||
Foreground="White"
|
||||
Text="{Binding Path=Res.Error_PageFault, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />-->
|
||||
Text="{Binding Path=Res.Error_PageFault, Mode=OneWay, Source={x:Static spp:Strings.Error_PageFault}}" />-->
|
||||
<TextBlock
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="16"
|
||||
Foreground="White"
|
||||
Text="{Binding Path=Res.NewFeatureDevelopment, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
Text="{Binding Path=Res.NewFeatureDevelopment, Mode=OneWay, Source={x:Static spp:Strings.NewFeatureDevelopment}}" />
|
||||
</Panel>
|
||||
</UserControl>
|
||||
</UserControl>
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
MaxWidth="1080"
|
||||
Spacing="20">
|
||||
<spp:Snackbar
|
||||
Title="{Binding Path=Res.Notice_Tray_Title, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
Title="{Binding Path=Res.Notice_Tray_Title, Mode=OneWay, Source={x:Static spp:Strings.Notice_Tray_Title}}"
|
||||
VerticalAlignment="Top"
|
||||
IsClosable="False"
|
||||
IsOpen="True"
|
||||
@@ -81,7 +81,7 @@
|
||||
Message="当前使用的程序版本为测试版本,可能会有各种各样不可言明的 Bug,遇到问题请理性反馈,谢谢。"
|
||||
Severity="Warning" />
|
||||
<spp:Snackbar
|
||||
Title="{Binding Path=Res.Notice_Tray_Title, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
Title="{Binding Path=Res.Notice_Tray_Title, Mode=OneWay, Source={x:Static spp:Strings.Notice_Tray_Title}}"
|
||||
VerticalAlignment="Top"
|
||||
IsClosable="False"
|
||||
IsOpen="True"
|
||||
@@ -119,7 +119,7 @@
|
||||
Theme="{StaticResource SubtitleTextBlockStyle}" />
|
||||
</WrapPanel>
|
||||
<TextBlock VerticalAlignment="Center" Theme="{StaticResource SubtitleTextBlockStyle}">
|
||||
<Run Text="{Binding Path=Res.Welcome_User_, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
<Run Text="{Binding Path=Res.Welcome_User_, Mode=OneWay, Source={x:Static spp:Strings.Welcome_User_}}" />
|
||||
</TextBlock>
|
||||
</WrapPanel>
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ public partial class HomePage : ReactiveUserControl<HomePageViewModel>
|
||||
public HomePage()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.SetViewModel<HomePageViewModel>(false);
|
||||
this.SetViewModel<HomePageViewModel>(true);
|
||||
|
||||
//ShopsScrollViewer.PointerWheelChanged += ShopsScrollViewer_PointerWheelChanged;
|
||||
}
|
||||
|
||||
@@ -212,13 +212,13 @@
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
IsVisible="{Binding Path=User, Mode=OneWay, Source={x:Static s:UserService.Current}, Converter={StaticResource IsNullConverter}}"
|
||||
Text="{Binding Path=Res.User_UnLogin, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
Text="{Binding Path=Res.User_UnLogin, Mode=OneWay, Source={x:Static spp:Strings.User_UnLogin}}" />
|
||||
|
||||
<StackPanel VerticalAlignment="Center" IsVisible="{Binding Path=User, Mode=OneWay, Source={x:Static s:UserService.Current}, Converter={StaticResource IsNullConverter}, ConverterParameter=invert}">
|
||||
<TextBlock Text="{Binding Path=User.NickName, Mode=OneWay, Source={x:Static s:UserService.Current}}" />
|
||||
|
||||
<Border VerticalAlignment="Center" IsVisible="{Binding Path=User.UserType, Mode=OneWay, Source={x:Static s:UserService.Current}, Converter={StaticResource EnumEqualValueConverter}, ConverterParameter={x:Static enum:UserType.Sponsor}}">
|
||||
<TextBlock FontSize="10" Text="{Binding Path=Res.User_Sponsor, Mode=OneWay, Source={x:Static s:ResourceService.Current}, StringFormat={}❤️{0}}" />
|
||||
<TextBlock FontSize="10" Text="{Binding Path=Res.User_Sponsor, Mode=OneWay, Source={x:Static spp:Strings.User_Sponsor}, StringFormat={}❤️{0}}" />
|
||||
</Border>
|
||||
|
||||
</StackPanel>
|
||||
@@ -243,14 +243,14 @@
|
||||
<Button
|
||||
Margin="5,0"
|
||||
Command="{Binding Path=SignInAsync, Mode=OneWay, Source={x:Static s:UserService.Current}}"
|
||||
Content="{Binding Path=Res.Sign, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
Content="{Binding Path=Res.Sign, Mode=OneWay, Source={x:Static spp:Strings.Sign}}"
|
||||
FontSize="10"
|
||||
IsVisible="{Binding Path=!User.IsSignIn, Mode=OneWay, Source={x:Static s:UserService.Current}}" />
|
||||
<Button
|
||||
Margin="5,0"
|
||||
FontSize="10"
|
||||
IsVisible="{Binding Path=User.IsSignIn, Mode=OneWay, Source={x:Static s:UserService.Current}}"
|
||||
ToolTip.Tip="{Binding Path=Res.Signed, Mode=OneWay, Source={x:Static s:ResourceService.Current}}">
|
||||
ToolTip.Tip="{Binding Path=Res.Signed, Mode=OneWay, Source={x:Static spp:Strings.Signed}}">
|
||||
<Button.Content>
|
||||
<MultiBinding StringFormat="{}{0} : {1}">
|
||||
<CompiledBinding Path="Res.User_EngineOil" Source="{x:Static s:ResourceService.Current}" />
|
||||
@@ -266,24 +266,24 @@
|
||||
<MenuItem
|
||||
Command="{Binding OpenBrowserCommand, Source={x:Static spp:App.Instance}}"
|
||||
CommandParameter="https://steampp.net/account/center/info"
|
||||
Header="{Binding Path=Res.PersonalCenter, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
Header="{Binding Path=Res.PersonalCenter, Mode=OneWay, Source={x:Static spp:Strings.PersonalCenter}}"
|
||||
IsVisible="{Binding Path=User, Mode=OneWay, Source={x:Static s:UserService.Current}, Converter={StaticResource IsNullConverter}, ConverterParameter=invert}" />
|
||||
<!--<MenuItem Header="{Binding Path=Res.MyOrder, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" IsVisible="{Binding Path=User, Mode=OneWay, Source={x:Static s:UserService.Current}, Converter={StaticResource IsNullConverter}, ConverterParameter=invert}" />-->
|
||||
<!--<MenuItem Header="{Binding Path=Res.MyOrder, Mode=OneWay, Source={x:Static spp:Strings.MyOrder}}" IsVisible="{Binding Path=User, Mode=OneWay, Source={x:Static s:UserService.Current}, Converter={StaticResource IsNullConverter}, ConverterParameter=invert}" />-->
|
||||
<MenuItem
|
||||
Command="{Binding OpenBrowserCommand, Source={x:Static spp:App.Instance}}"
|
||||
CommandParameter="https://steampp.net/account/center/bind"
|
||||
Header="{Binding Path=Res.BindThirdPartyAccount, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
Header="{Binding Path=Res.BindThirdPartyAccount, Mode=OneWay, Source={x:Static spp:Strings.BindThirdPartyAccount}}"
|
||||
IsVisible="{Binding Path=User, Mode=OneWay, Source={x:Static s:UserService.Current}, Converter={StaticResource IsNullConverter}, ConverterParameter=invert}" />
|
||||
<MenuItem
|
||||
Command="{Binding OpenBrowserCommand, Source={x:Static spp:App.Instance}}"
|
||||
CommandParameter="https://steampp.net/account/center/safe"
|
||||
Header="{Binding Path=Res.PersonalSafe, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
Header="{Binding Path=Res.PersonalSafe, Mode=OneWay, Source={x:Static spp:Strings.PersonalSafe}}"
|
||||
IsVisible="{Binding Path=User, Mode=OneWay, Source={x:Static s:UserService.Current}, Converter={StaticResource IsNullConverter}, ConverterParameter=invert}" />
|
||||
<MenuItem Header="-" IsVisible="{Binding Path=User, Mode=OneWay, Source={x:Static s:UserService.Current}, Converter={StaticResource IsNullConverter}, ConverterParameter=invert}" />
|
||||
<MenuItem
|
||||
Command="{Binding Path=SignOut, Mode=OneWay, Source={x:Static s:UserService.Current}}"
|
||||
Foreground="{DynamicResource SystemFillColorCriticalBrush}"
|
||||
Header="{Binding Path=Res.SignOut, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
Header="{Binding Path=Res.SignOut, Mode=OneWay, Source={x:Static spp:Strings.SignOut}}"
|
||||
IsVisible="{Binding Path=User, Mode=OneWay, Source={x:Static s:UserService.Current}, Converter={StaticResource IsNullConverter}, ConverterParameter=invert}" />
|
||||
<!--<MenuItem
|
||||
Command="{Binding Path=ShowWindow,
|
||||
@@ -330,7 +330,7 @@
|
||||
</Style>
|
||||
<Style Selector="Grid#PaneToggleButtonGrid">
|
||||
<Setter Property="Margin" Value="5 5 0 0" />
|
||||
<Setter Property="ToolTip.Tip" Value="{Binding Path=Res.Back, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
<Setter Property="ToolTip.Tip" Value="{Binding Path=Res.Back, Mode=OneWay, Source={x:Static spp:Strings.Back}}" />
|
||||
<Setter Property="ToolTip.Placement" Value="Bottom" />
|
||||
</Style>
|
||||
</ui:NavigationView.Styles>
|
||||
|
||||
@@ -26,11 +26,11 @@
|
||||
CornerRadius="{StaticResource ControlCornerRadius}"
|
||||
ItemContainerTheme="{StaticResource TabItemStyle}"
|
||||
Theme="{StaticResource TabStripStyle}">
|
||||
<TabStripItem Content="{Binding Path=Res.Settings_General, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" Tag="Settings_General" />
|
||||
<TabStripItem Content="{Binding Path=Res.Settings_UI, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" Tag="Settings_UI" />
|
||||
<TabStripItem Content="{Binding Path=Res.Settings_Plugin, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" Tag="Settings_Plugin" />
|
||||
<TabStripItem Content="{Binding Path=Res.Settings_Steam, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" Tag="Settings_Steam" />
|
||||
<TabStripItem Content="{Binding Path=Res.About, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" Tag="AboutPage" />
|
||||
<TabStripItem Content="{Binding Path=Res.Settings_General, Mode=OneWay, Source={x:Static spp:Strings.Settings_General}}" Tag="Settings_General" />
|
||||
<TabStripItem Content="{Binding Path=Res.Settings_UI, Mode=OneWay, Source={x:Static spp:Strings.Settings_UI}}" Tag="Settings_UI" />
|
||||
<TabStripItem Content="{Binding Path=Res.Settings_Plugin, Mode=OneWay, Source={x:Static spp:Strings.Settings_Plugin}}" Tag="Settings_Plugin" />
|
||||
<TabStripItem Content="{Binding Path=Res.Settings_Steam, Mode=OneWay, Source={x:Static spp:Strings.Settings_Steam}}" Tag="Settings_Steam" />
|
||||
<TabStripItem Content="{Binding Path=Res.About, Mode=OneWay, Source={x:Static spp:Strings.About}}" Tag="AboutPage" />
|
||||
</TabStrip>
|
||||
</spp:PageBase.TabContent>
|
||||
<!--<spp:PageBase.ActionContent>
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
<StackPanel Spacing="{StaticResource SettingsSpacing}">
|
||||
<TextBlock
|
||||
Margin="0,0,0,10"
|
||||
Text="{Binding Path=Res.Settings_General, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
Text="{Binding Path=Res.Settings_General, Mode=OneWay, Source={x:Static spp:Strings.Settings_General}}"
|
||||
Theme="{StaticResource SubtitleTextBlockStyle}" />
|
||||
<spp:OptionsDisplayItem Description="{Binding Path=Res.Settings_StartupAutoRun, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" Header="{Binding Path=Res.Settings_General_StartAutoRun, Mode=OneWay, Source={x:Static s:ResourceService.Current}}">
|
||||
<spp:OptionsDisplayItem Description="{Binding Path=Res.Settings_StartupAutoRun, Mode=OneWay, Source={x:Static spp:Strings.Settings_StartupAutoRun}}" Header="{Binding Path=Res.Settings_General_StartAutoRun, Mode=OneWay, Source={x:Static spp:Strings.Settings_StartupAutoRun}}">
|
||||
<spp:OptionsDisplayItem.Icon>
|
||||
<ui:FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="" />
|
||||
</spp:OptionsDisplayItem.Icon>
|
||||
@@ -28,7 +28,7 @@
|
||||
</spp:OptionsDisplayItem.ActionButton>
|
||||
</spp:OptionsDisplayItem>
|
||||
|
||||
<spp:OptionsDisplayItem Description="{Binding Path=Res.Settings_StartupNoShowMainWindow, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" Header="{Binding Path=Res.Settings_General_RuningMinimize, Mode=OneWay, Source={x:Static s:ResourceService.Current}}">
|
||||
<spp:OptionsDisplayItem Description="{Binding Path=Res.Settings_StartupNoShowMainWindow, Mode=OneWay, Source={x:Static spp:Strings.Settings_StartupNoShowMainWindow}}" Header="{Binding Path=Res.Settings_General_RuningMinimize, Mode=OneWay, Source={x:Static spp:Strings.Settings_StartupNoShowMainWindow}}">
|
||||
<spp:OptionsDisplayItem.Icon>
|
||||
<ui:FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="" />
|
||||
</spp:OptionsDisplayItem.Icon>
|
||||
@@ -37,7 +37,7 @@
|
||||
</spp:OptionsDisplayItem.ActionButton>
|
||||
</spp:OptionsDisplayItem>
|
||||
|
||||
<spp:OptionsDisplayItem Description="{Binding Path=Res.Settings_General_EnableTrayIcon_Tip, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" Header="{Binding Path=Res.Settings_General_EnableTrayIcon, Mode=OneWay, Source={x:Static s:ResourceService.Current}}">
|
||||
<spp:OptionsDisplayItem Description="{Binding Path=Res.Settings_General_EnableTrayIcon_Tip, Mode=OneWay, Source={x:Static spp:Strings.Settings_General_EnableTrayIcon_Tip}}" Header="{Binding Path=Res.Settings_General_EnableTrayIcon, Mode=OneWay, Source={x:Static spp:Strings.Settings_General_EnableTrayIcon_Tip}}">
|
||||
<spp:OptionsDisplayItem.Icon>
|
||||
<ui:FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="" />
|
||||
</spp:OptionsDisplayItem.Icon>
|
||||
@@ -46,7 +46,7 @@
|
||||
</spp:OptionsDisplayItem.ActionButton>
|
||||
</spp:OptionsDisplayItem>
|
||||
|
||||
<spp:OptionsDisplayItem Header="{Binding Path=Res.Settings_General_AutoCheckUpdate, Mode=OneWay, Source={x:Static s:ResourceService.Current}}">
|
||||
<spp:OptionsDisplayItem Header="{Binding Path=Res.Settings_General_AutoCheckUpdate, Mode=OneWay, Source={x:Static spp:Strings.Settings_General_AutoCheckUpdate}}">
|
||||
<spp:OptionsDisplayItem.Icon>
|
||||
<ui:FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="" />
|
||||
</spp:OptionsDisplayItem.Icon>
|
||||
@@ -55,7 +55,7 @@
|
||||
</spp:OptionsDisplayItem.ActionButton>
|
||||
</spp:OptionsDisplayItem>
|
||||
|
||||
<spp:OptionsDisplayItem Header="{Binding Path=Res.Settings_General_UpdateChannel, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" IsVisible="{spp:OnPlatform OfficialRelease}">
|
||||
<spp:OptionsDisplayItem Header="{Binding Path=Res.Settings_General_UpdateChannel, Mode=OneWay, Source={x:Static spp:Strings.Settings_General_UpdateChannel}}" IsVisible="{spp:OnPlatform OfficialRelease}">
|
||||
<spp:OptionsDisplayItem.Icon>
|
||||
<ui:FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="" />
|
||||
</spp:OptionsDisplayItem.Icon>
|
||||
@@ -75,7 +75,7 @@
|
||||
</spp:OptionsDisplayItem.ActionButton>
|
||||
</spp:OptionsDisplayItem>
|
||||
|
||||
<spp:OptionsDisplayItem Description="{Binding Path=Res.Settings_RestartEffective, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" Header="{Binding Path=Res.Settings_General_UseGPURendering, Mode=OneWay, Source={x:Static s:ResourceService.Current}}">
|
||||
<spp:OptionsDisplayItem Description="{Binding Path=Res.Settings_RestartEffective, Mode=OneWay, Source={x:Static spp:Strings.Settings_RestartEffective}}" Header="{Binding Path=Res.Settings_General_UseGPURendering, Mode=OneWay, Source={x:Static spp:Strings.Settings_RestartEffective}}">
|
||||
<spp:OptionsDisplayItem.Icon>
|
||||
<ui:FontIcon FontFamily="Segoe Fluent Icons" Glyph="" />
|
||||
</spp:OptionsDisplayItem.Icon>
|
||||
@@ -94,7 +94,7 @@
|
||||
</spp:OptionsDisplayItem>
|
||||
|
||||
<ui:SettingsExpander
|
||||
Header="{Binding Path=Res.Settings_General_StorageSpace, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
Header="{Binding Path=Res.Settings_General_StorageSpace, Mode=OneWay, Source={x:Static spp:Strings.Settings_General_StorageSpace}}"
|
||||
IconSource="Globe"
|
||||
IsClickEnabled="False"
|
||||
IsExpanded="True">
|
||||
@@ -105,23 +105,23 @@
|
||||
<Button
|
||||
Command="{Binding OpenFolder_Click}"
|
||||
CommandParameter="{x:Null}"
|
||||
Content="{Binding Path=Res.Settings_General_BrowseCustomFolder, Mode=OneWay, Source={x:Static s:ResourceService.Current}, Converter={StaticResource StringFormatConverter}, ConverterParameter=App}" />
|
||||
Content="{Binding Path=Res.Settings_General_BrowseCustomFolder, Mode=OneWay, Source={x:Static spp:Strings.Settings_General_BrowseCustomFolder}, Converter={StaticResource StringFormatConverter}, ConverterParameter=App}" />
|
||||
</ui:SettingsExpander.Footer>
|
||||
|
||||
<ui:SettingsExpanderItem
|
||||
ActionIconSource="Open"
|
||||
Command="{Binding OpenFolder_Click}"
|
||||
CommandParameter="AppData"
|
||||
Content="{Binding Path=Res.Settings_General_AppData, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
Content="{Binding Path=Res.Settings_General_AppData, Mode=OneWay, Source={x:Static spp:Strings.Settings_General_AppData}}"
|
||||
IsClickEnabled="True"
|
||||
ToolTip.Tip="{Binding Path=Res.Settings_General_BrowseCustomFolder, Mode=OneWay, Source={x:Static s:ResourceService.Current}, Converter={StaticResource StringFormatConverter}, ConverterParameter=AppData}" />
|
||||
ToolTip.Tip="{Binding Path=Res.Settings_General_BrowseCustomFolder, Mode=OneWay, Source={x:Static spp:Strings.Settings_General_BrowseCustomFolder}, Converter={StaticResource StringFormatConverter}, ConverterParameter=AppData}" />
|
||||
<ui:SettingsExpanderItem
|
||||
ActionIconSource="Open"
|
||||
Command="{Binding OpenFolder_Click}"
|
||||
CommandParameter="Cache"
|
||||
Content="{Binding Path=Res.Settings_General_CacheData, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
Content="{Binding Path=Res.Settings_General_CacheData, Mode=OneWay, Source={x:Static spp:Strings.Settings_General_CacheData}}"
|
||||
IsClickEnabled="True"
|
||||
ToolTip.Tip="{Binding Path=Res.Settings_General_BrowseCustomFolder, Mode=OneWay, Source={x:Static s:ResourceService.Current}, Converter={StaticResource StringFormatConverter}, ConverterParameter=Cache}">
|
||||
ToolTip.Tip="{Binding Path=Res.Settings_General_BrowseCustomFolder, Mode=OneWay, Source={x:Static spp:Strings.Settings_General_BrowseCustomFolder}, Converter={StaticResource StringFormatConverter}, ConverterParameter=Cache}">
|
||||
<ui:SettingsExpanderItem.Footer>
|
||||
<TextBlock
|
||||
Name="CacheSize"
|
||||
@@ -134,9 +134,9 @@
|
||||
ActionIconSource="Open"
|
||||
Command="{Binding OpenFolder_Click}"
|
||||
CommandParameter="Logs"
|
||||
Content="{Binding Path=Res.Settings_General_LogsData, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
Content="{Binding Path=Res.Settings_General_LogsData, Mode=OneWay, Source={x:Static spp:Strings.Settings_General_LogsData}}"
|
||||
IsClickEnabled="True"
|
||||
ToolTip.Tip="{Binding Path=Res.Settings_General_BrowseCustomFolder, Mode=OneWay, Source={x:Static s:ResourceService.Current}, Converter={StaticResource StringFormatConverter}, ConverterParameter=Logs}">
|
||||
ToolTip.Tip="{Binding Path=Res.Settings_General_BrowseCustomFolder, Mode=OneWay, Source={x:Static spp:Strings.Settings_General_BrowseCustomFolder}, Converter={StaticResource StringFormatConverter}, ConverterParameter=Logs}">
|
||||
<ui:SettingsExpanderItem.Footer>
|
||||
<TextBlock
|
||||
Name="LogSize"
|
||||
|
||||
@@ -16,10 +16,10 @@
|
||||
<StackPanel Spacing="{StaticResource SettingsSpacing}">
|
||||
<TextBlock
|
||||
Margin="0,0,0,10"
|
||||
Text="{Binding Path=Res.Settings_Plugin, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
Text="{Binding Path=Res.Settings_Plugin, Mode=OneWay, Source={x:Static spp:Strings.Settings_Plugin}}"
|
||||
Theme="{StaticResource SubtitleTextBlockStyle}" />
|
||||
|
||||
<ui:SettingsExpander Description="{Binding Path=Res.Plugin_OnlyLoadOfficePlugins, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" Header="{Binding Path=Res.Plugin_SafeMode, Mode=OneWay, Source={x:Static s:ResourceService.Current}}">
|
||||
<ui:SettingsExpander Description="{Binding Path=Res.Plugin_OnlyLoadOfficePlugins, Mode=OneWay, Source={x:Static spp:Strings.Plugin_OnlyLoadOfficePlugins}}" Header="{Binding Path=Res.Plugin_SafeMode, Mode=OneWay, Source={x:Static spp:Strings.Plugin_OnlyLoadOfficePlugins}}">
|
||||
<ui:SettingsExpander.IconSource>
|
||||
<ui:FontIconSource FontFamily="Segoe Fluent Icons" Glyph="{StaticResource DefenderApp}" />
|
||||
</ui:SettingsExpander.IconSource>
|
||||
@@ -35,14 +35,14 @@
|
||||
<CompiledBinding
|
||||
Mode="OneWay"
|
||||
Path="Res.Plugin_InstalledPlugins"
|
||||
Source="{x:Static s:ResourceService.Current}" />
|
||||
Source="{x:Static spp:Strings.Plugin_InstalledPlugins}" />
|
||||
<CompiledBinding
|
||||
Mode="OneWay"
|
||||
Path="MainWindow2.PluginCount"
|
||||
Source="{x:Static s:IViewModelManager.Instance}" />
|
||||
Source="{x:Static spp:Strings.IViewModelManager.Instance}" />
|
||||
</MultiBinding>
|
||||
</TextBlock.Text>
|
||||
<!--<Run Text="{Binding Path=Res.Plugin_InstalledPlugins, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
<!--<Run Text="{Binding Path=Res.Plugin_InstalledPlugins, Mode=OneWay, Source={x:Static spp:Strings.Plugin_InstalledPlugins}}" />
|
||||
<Run Text="(" />
|
||||
<Run Text="{Binding MainWindow2.PluginCount, Mode=OneWay, Source={x:Static s:IViewModelManager.Instance}}" />
|
||||
<Run Text=")" />-->
|
||||
@@ -73,14 +73,14 @@
|
||||
<ui:SettingsExpanderItem
|
||||
ActionIconSource="Refresh"
|
||||
Command="{Binding $parent[spp:Settings_Plugin].((spp:SettingsPageViewModel)DataContext).CheckUpdate_Click}"
|
||||
Content="{Binding Path=Res.CheckUpdate, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
Content="{Binding Path=Res.CheckUpdate, Mode=OneWay, Source={x:Static spp:Strings.CheckUpdate}}"
|
||||
IsClickEnabled="True">
|
||||
<ui:SettingsExpanderItem.Description>
|
||||
<MultiBinding StringFormat="{}{0}{1}">
|
||||
<CompiledBinding
|
||||
Mode="OneWay"
|
||||
Path="Res.Plugin_Version"
|
||||
Source="{x:Static s:ResourceService.Current}" />
|
||||
Source="{x:Static spp:Strings.Plugin_Version}" />
|
||||
<CompiledBinding Mode="OneWay" Path="Data.Version" />
|
||||
</MultiBinding>
|
||||
</ui:SettingsExpanderItem.Description>
|
||||
@@ -89,19 +89,19 @@
|
||||
ActionIconSource="Open"
|
||||
Command="{Binding $parent[spp:Settings_Plugin].((spp:SettingsPageViewModel)DataContext).OpenPluginDirectory_Click}"
|
||||
CommandParameter="{Binding Data.AssemblyLocation}"
|
||||
Content="{Binding Path=Res.Plugin_OpenFolder, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
Content="{Binding Path=Res.Plugin_OpenFolder, Mode=OneWay, Source={x:Static spp:Strings.Plugin_OpenFolder}}"
|
||||
IsClickEnabled="True" />
|
||||
<ui:SettingsExpanderItem
|
||||
ActionIconSource="Open"
|
||||
Command="{Binding $parent[spp:Settings_Plugin].((spp:SettingsPageViewModel)DataContext).OpenPluginCacheDirectory_Click}"
|
||||
CommandParameter="{Binding Data.CacheDirectory}"
|
||||
Content="{Binding Path=Res.Plugin_OpenCacheFolder, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
Content="{Binding Path=Res.Plugin_OpenCacheFolder, Mode=OneWay, Source={x:Static spp:Strings.Plugin_OpenCacheFolder}}"
|
||||
IsClickEnabled="True" />
|
||||
<ui:SettingsExpanderItem
|
||||
ActionIconSource="Delete"
|
||||
Command="{Binding $parent[spp:Settings_Plugin].((spp:SettingsPageViewModel)DataContext).DeletePlugin_Click}"
|
||||
CommandParameter="{Binding Data}"
|
||||
Content="{Binding Path=Res.Plugin_Delete, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
Content="{Binding Path=Res.Plugin_Delete, Mode=OneWay, Source={x:Static spp:Strings.Plugin_Delete}}"
|
||||
IsClickEnabled="True" />
|
||||
</ui:SettingsExpander>
|
||||
</DataTemplate>
|
||||
@@ -111,17 +111,17 @@
|
||||
<!--<ui:SettingsExpander
|
||||
Description="{Binding Path=Res.Plugin_ManageAllInstalledPlugins,
|
||||
Mode=OneWay,
|
||||
Source={x:Static s:ResourceService.Current}}"
|
||||
Source={x:Static spp:Strings.Plugin_ManageAllInstalledPlugins}}"
|
||||
Header="{Binding Path=Res.Plugin_InstalledPlugins,
|
||||
Mode=OneWay,
|
||||
Source={x:Static s:ResourceService.Current}}"
|
||||
Source={x:Static spp:Strings.Plugin_InstalledPlugins}}"
|
||||
IsExpanded="True"
|
||||
ItemsSource="{Binding Plugins}">
|
||||
<ui:SettingsExpander.IconSource>
|
||||
<ui:SymbolIconSource Symbol="Calculator" />
|
||||
</ui:SettingsExpander.IconSource>
|
||||
<ui:SettingsExpander.Footer>
|
||||
<Button Content="{Binding Path=Res.Plugin_OpenFolder, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
<Button Content="{Binding Path=Res.Plugin_OpenFolder, Mode=OneWay, Source={x:Static spp:Strings.Plugin_OpenFolder}}" />
|
||||
</ui:SettingsExpander.Footer>
|
||||
<ui:SettingsExpander.ItemTemplate>
|
||||
<DataTemplate>
|
||||
@@ -148,21 +148,21 @@
|
||||
Theme="{StaticResource TransparentButton}">
|
||||
<DropDownButton.Flyout>
|
||||
<MenuFlyout>
|
||||
<MenuItem Command="{Binding Path=DataContext.CheckUpdate_Click, RelativeSource={RelativeSource AncestorType=spp:Settings_Plugin}}" Header="{Binding Path=Res.CheckUpdate, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
<MenuItem Command="{Binding Path=DataContext.CheckUpdate_Click, RelativeSource={RelativeSource AncestorType=spp:Settings_Plugin}}" Header="{Binding Path=Res.CheckUpdate, Mode=OneWay, Source={x:Static spp:Strings.CheckUpdate}}" />
|
||||
<MenuItem
|
||||
Command="{Binding Path=DataContext.OpenPluginDirectory_Click,
|
||||
RelativeSource={RelativeSource AncestorType=spp:Settings_Plugin}}"
|
||||
CommandParameter="{Binding Data.AssemblyLocation}"
|
||||
Header="{Binding Path=Res.Plugin_OpenFolder,
|
||||
Mode=OneWay,
|
||||
Source={x:Static s:ResourceService.Current}}" />
|
||||
Source={x:Static spp:Strings.Plugin_OpenFolder}}" />
|
||||
<MenuItem
|
||||
Command="{Binding Path=DataContext.OpenPluginCacheDirectory_Click,
|
||||
RelativeSource={RelativeSource AncestorType=spp:Settings_Plugin}}"
|
||||
CommandParameter="{Binding Data.CacheDirectory}"
|
||||
Header="{Binding Path=Res.Plugin_OpenCacheFolder,
|
||||
Mode=OneWay,
|
||||
Source={x:Static s:ResourceService.Current}}" />
|
||||
Source={x:Static spp:Strings.Plugin_OpenCacheFolder}}" />
|
||||
<MenuItem Header="-" />
|
||||
<MenuItem
|
||||
Command="{Binding Path=DataContext.DeletePlugin_Click,
|
||||
@@ -170,7 +170,7 @@
|
||||
CommandParameter="{Binding Data}"
|
||||
Header="{Binding Path=Res.Plugin_Delete,
|
||||
Mode=OneWay,
|
||||
Source={x:Static s:ResourceService.Current}}" />
|
||||
Source={x:Static spp:Strings.Plugin_Delete}}" />
|
||||
</MenuFlyout>
|
||||
</DropDownButton.Flyout>
|
||||
</DropDownButton>
|
||||
|
||||
@@ -16,18 +16,19 @@
|
||||
<StackPanel Spacing="{StaticResource SettingsSpacing}">
|
||||
<TextBlock
|
||||
Margin="0,0,0,10"
|
||||
Text="{Binding Path=Res.Settings_Steam, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
Text="{Binding Path=Res.Settings_Steam, Mode=OneWay, Source={x:Static spp:Strings.Settings_Steam}}"
|
||||
Theme="{StaticResource SubtitleTextBlockStyle}" />
|
||||
<spp:OptionsDisplayItem Description="{Binding Source={x:Static ms:SteamSettings.SteamProgramPath}, Path=Value, Mode=OneWay}" Header="{Binding Path=Res.Settings_Steam_Path, Mode=OneWay, Source={x:Static s:ResourceService.Current}}">
|
||||
<spp:OptionsDisplayItem Description="{Binding Source={x:Static ms:SteamSettings.SteamProgramPath}, Path=Value, Mode=OneWay}"
|
||||
Header="{Binding Path=Res.Settings_Steam_Path, Mode=OneWay, Source={x:Static spp:Strings.Settings_Steam_Path}}">
|
||||
<spp:OptionsDisplayItem.Icon>
|
||||
<ui:FontIcon FontFamily="Segoe Fluent Icons" Glyph="" />
|
||||
</spp:OptionsDisplayItem.Icon>
|
||||
<spp:OptionsDisplayItem.ActionButton>
|
||||
<Button Command="{Binding SelectSteamProgramLocation}" Content="{Binding Path=Res.LocalAuth_ExportAuth_SelectPath, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
<Button Command="{Binding SelectSteamProgramLocation}" Content="{Binding Path=Res.LocalAuth_ExportAuth_SelectPath, Mode=OneWay, Source={x:Static spp:Strings.LocalAuth_ExportAuth_SelectPath}}" />
|
||||
</spp:OptionsDisplayItem.ActionButton>
|
||||
</spp:OptionsDisplayItem>
|
||||
|
||||
<spp:OptionsDisplayItem Header="{Binding Path=Res.Settings_Steam_AutoRunSteam, Mode=OneWay, Source={x:Static s:ResourceService.Current}}">
|
||||
<spp:OptionsDisplayItem Header="{Binding Path=Res.Settings_Steam_AutoRunSteam, Mode=OneWay, Source={x:Static spp:Strings.Settings_Steam_AutoRunSteam}}">
|
||||
<spp:OptionsDisplayItem.Icon>
|
||||
<ui:FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="" />
|
||||
</spp:OptionsDisplayItem.Icon>
|
||||
@@ -37,8 +38,8 @@
|
||||
</spp:OptionsDisplayItem>
|
||||
|
||||
<spp:OptionsDisplayItem
|
||||
Description="{Binding Path=Res.Settings_Steam_AdminRunPrompt, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
Header="{Binding Path=Res.Settings_Steam_RuningAdmin, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
Description="{Binding Path=Res.Settings_Steam_AdminRunPrompt, Mode=OneWay, Source={x:Static spp:Strings.Settings_Steam_AdminRunPrompt}}"
|
||||
Header="{Binding Path=Res.Settings_Steam_RuningAdmin, Mode=OneWay, Source={x:Static spp:Strings.Settings_Steam_RuningAdmin}}"
|
||||
IsVisible="{spp:OnPlatform Windows}">
|
||||
<spp:OptionsDisplayItem.Icon>
|
||||
<ui:FontIcon FontFamily="Segoe Fluent Icons" Glyph="" />
|
||||
@@ -48,7 +49,7 @@
|
||||
</spp:OptionsDisplayItem.ActionButton>
|
||||
</spp:OptionsDisplayItem>
|
||||
|
||||
<spp:OptionsDisplayItem Header="{Binding Path=Res.Settings_Steam_RuningMinimize, Mode=OneWay, Source={x:Static s:ResourceService.Current}}">
|
||||
<spp:OptionsDisplayItem Header="{Binding Path=Res.Settings_Steam_RuningMinimize, Mode=OneWay, Source={x:Static spp:Strings.Settings_Steam_RuningMinimize}}">
|
||||
<spp:OptionsDisplayItem.Icon>
|
||||
<ui:FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="" />
|
||||
</spp:OptionsDisplayItem.Icon>
|
||||
@@ -57,7 +58,8 @@
|
||||
</spp:OptionsDisplayItem.ActionButton>
|
||||
</spp:OptionsDisplayItem>
|
||||
|
||||
<spp:OptionsDisplayItem Description="{Binding Path=Res.Settings_Steam_NoAutoUpdate, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" Header="{Binding Path=Res.Settings_Steam_NotCheckUpdate, Mode=OneWay, Source={x:Static s:ResourceService.Current}}">
|
||||
<spp:OptionsDisplayItem Description="{Binding Path=Res.Settings_Steam_NoAutoUpdate, Mode=OneWay, Source={x:Static spp:Strings.Settings_Steam_NoAutoUpdate}}"
|
||||
Header="{Binding Path=Res.Settings_Steam_NotCheckUpdate, Mode=OneWay, Source={x:Static spp:Strings.Settings_Steam_NotCheckUpdate}}">
|
||||
<spp:OptionsDisplayItem.Icon>
|
||||
<ui:FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="" />
|
||||
</spp:OptionsDisplayItem.Icon>
|
||||
@@ -66,7 +68,7 @@
|
||||
</spp:OptionsDisplayItem.ActionButton>
|
||||
</spp:OptionsDisplayItem>
|
||||
|
||||
<spp:OptionsDisplayItem Header="{Binding Path=Res.Settings_Steam_RunSteamChina, Mode=OneWay, Source={x:Static s:ResourceService.Current}}">
|
||||
<spp:OptionsDisplayItem Header="{Binding Path=Res.Settings_Steam_RunSteamChina, Mode=OneWay, Source={x:Static spp:Strings.Settings_Steam_RunSteamChina}}">
|
||||
<spp:OptionsDisplayItem.Icon>
|
||||
<ui:FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="" />
|
||||
</spp:OptionsDisplayItem.Icon>
|
||||
@@ -75,7 +77,8 @@
|
||||
</spp:OptionsDisplayItem.ActionButton>
|
||||
</spp:OptionsDisplayItem>
|
||||
|
||||
<spp:OptionsDisplayItem Description="{Binding Path=Res.Settings_Steam_AutoPopupMessage, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" Header="{Binding Path=Res.Settings_Steam_CheckSteamRuningNotification, Mode=OneWay, Source={x:Static s:ResourceService.Current}}">
|
||||
<spp:OptionsDisplayItem Description="{Binding Path=Res.Settings_Steam_AutoPopupMessage, Mode=OneWay, Source={x:Static spp:Strings.Settings_Steam_AutoPopupMessage}}"
|
||||
Header="{Binding Path=Res.Settings_Steam_CheckSteamRuningNotification, Mode=OneWay, Source={x:Static spp:Strings.Settings_Steam_CheckSteamRuningNotification}}">
|
||||
<spp:OptionsDisplayItem.Icon>
|
||||
<ui:FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="" />
|
||||
</spp:OptionsDisplayItem.Icon>
|
||||
@@ -84,12 +87,13 @@
|
||||
</spp:OptionsDisplayItem.ActionButton>
|
||||
</spp:OptionsDisplayItem>
|
||||
|
||||
<spp:OptionsDisplayItem Description="{Binding Source={x:Static ms:SteamSettings.SteamStratParameter}, Path=Value, Mode=OneWay}" Header="{Binding Path=Res.Settings_Steam_SteamStratParameter, Mode=OneWay, Source={x:Static s:ResourceService.Current}}">
|
||||
<spp:OptionsDisplayItem Description="{Binding Source={x:Static ms:SteamSettings.SteamStratParameter}, Path=Value, Mode=OneWay}"
|
||||
Header="{Binding Path=Res.Settings_Steam_SteamStratParameter, Mode=OneWay, Source={x:Static spp:Strings.Settings_Steam_SteamStratParameter}}">
|
||||
<spp:OptionsDisplayItem.Icon>
|
||||
<ui:FontIcon FontFamily="Segoe Fluent Icons" Glyph="" />
|
||||
</spp:OptionsDisplayItem.Icon>
|
||||
<spp:OptionsDisplayItem.ActionButton>
|
||||
<Button Command="{Binding EditSteamParameter}" Content="{Binding Path=Res.Edit, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
<Button Command="{Binding EditSteamParameter}" Content="{Binding Path=Res.Edit, Mode=OneWay, Source={x:Static spp:Strings.Edit}}" />
|
||||
</spp:OptionsDisplayItem.ActionButton>
|
||||
<!--<spp:OptionsDisplayItem.Content>
|
||||
<TextBox Classes="clearButton"
|
||||
|
||||
@@ -19,13 +19,13 @@
|
||||
<StackPanel Spacing="{StaticResource SettingsSpacing}">
|
||||
<TextBlock
|
||||
Margin="0,0,0,10"
|
||||
Text="{Binding Path=Res.Settings_UI, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
Text="{Binding Path=Res.Settings_UI, Mode=OneWay, Source={x:Static spp:Strings.Settings_UI}}"
|
||||
Theme="{StaticResource SubtitleTextBlockStyle}" />
|
||||
|
||||
<Border IsEnabled="{Binding Path=User, Mode=OneWay, Source={x:Static s:UserService.Current}, Converter={StaticResource IsNullConverter}, ConverterParameter=invert}">
|
||||
<ui:SettingsExpander
|
||||
Description="{Binding Path=Res.Advertisement_NoShow_Tip, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
Header="{Binding Path=Res.Advertisement_NoShow, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
Description="{Binding Path=Res.Advertisement_NoShow_Tip, Mode=OneWay, Source={x:Static spp:Strings.Advertisement_NoShow_Tip}}"
|
||||
Header="{Binding Path=Res.Advertisement_NoShow, Mode=OneWay, Source={x:Static spp:Strings.Advertisement_NoShow}}"
|
||||
IsEnabled="{Binding Path=User.UserType, Mode=OneWay, Source={x:Static s:UserService.Current}, Converter={StaticResource EnumEqualValueConverter}, ConverterParameter={x:Static enum:UserType.Sponsor}}">
|
||||
<ui:SettingsExpander.IconSource>
|
||||
<ui:FontIconSource FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="{StaticResource HeartBroken}" />
|
||||
@@ -37,8 +37,8 @@
|
||||
</Border>
|
||||
|
||||
<spp:OptionsDisplayItem
|
||||
Description="{Binding Path=Res.Settings_UI_ThemeStyle, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
Header="{Binding Path=Res.Settings_Theme, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
Description="{Binding Path=Res.Settings_UI_ThemeStyle, Mode=OneWay, Source={x:Static spp:Strings.Settings_UI_ThemeStyle}}"
|
||||
Header="{Binding Path=Res.Settings_Theme, Mode=OneWay, Source={x:Static spp:Strings.Settings_Theme}}"
|
||||
Icon="DarkTheme">
|
||||
<spp:OptionsDisplayItem.ActionButton>
|
||||
<ComboBox SelectedItem="{Binding Source={x:Static ms:UISettings.Theme}, Path=Value, Mode=TwoWay, Converter={StaticResource EnumConverter}, ConverterParameter={x:Type spp:AppTheme}}">
|
||||
@@ -56,17 +56,17 @@
|
||||
</spp:OptionsDisplayItem.ActionButton>
|
||||
</spp:OptionsDisplayItem>
|
||||
<spp:OptionsDisplayItem
|
||||
Description="{Binding Path=Res.Settings_UI_AccentColor, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
Description="{Binding Path=Res.Settings_UI_AccentColor, Mode=OneWay, Source={x:Static spp:Strings.Settings_UI_AccentColor}}"
|
||||
Expands="True"
|
||||
Header="{Binding Path=Res.Settings_ThemeAccent, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
Header="{Binding Path=Res.Settings_ThemeAccent, Mode=OneWay, Source={x:Static spp:Strings.Settings_ThemeAccent}}"
|
||||
Icon="ColorLine"
|
||||
IsExpanded="{Binding Path=IsChecked, ElementName=AccentCustom, Mode=OneWay}">
|
||||
<spp:OptionsDisplayItem.ActionButton>
|
||||
<StackPanel Orientation="Horizontal" Spacing="10">
|
||||
<RadioButton Content="{Binding Path=Res.Settings_UI_SystemDefault, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" IsChecked="{Binding Source={x:Static ms:UISettings.UseSystemThemeAccent}, Path=Value, Mode=TwoWay}" />
|
||||
<RadioButton Content="{Binding Path=Res.Settings_UI_SystemDefault, Mode=OneWay, Source={x:Static spp:Strings.Settings_UI_SystemDefault}}" IsChecked="{Binding Source={x:Static ms:UISettings.UseSystemThemeAccent}, Path=Value, Mode=TwoWay}" />
|
||||
<RadioButton
|
||||
x:Name="AccentCustom"
|
||||
Content="{Binding Path=Res.Settings_UI_Custom, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
Content="{Binding Path=Res.Settings_UI_Custom, Mode=OneWay, Source={x:Static spp:Strings.Settings_UI_Custom}}"
|
||||
IsChecked="{Binding Source={x:Static ms:UISettings.UseSystemThemeAccent}, Path=!Value, Mode=OneWay}" />
|
||||
</StackPanel>
|
||||
</spp:OptionsDisplayItem.ActionButton>
|
||||
@@ -76,7 +76,7 @@
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
DockPanel.Dock="Left"
|
||||
Text="{Binding Path=Res.Settings_UI_PreviewColor, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
Text="{Binding Path=Res.Settings_UI_PreviewColor, Mode=OneWay, Source={x:Static spp:Strings.Settings_UI_PreviewColor}}" />
|
||||
|
||||
<Grid
|
||||
HorizontalAlignment="Left"
|
||||
@@ -252,7 +252,7 @@
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
DockPanel.Dock="Left"
|
||||
Text="{Binding Path=Res.Settings_UI_CustomColor, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
Text="{Binding Path=Res.Settings_UI_CustomColor, Mode=OneWay, Source={x:Static spp:Strings.Settings_UI_CustomColor}}" />
|
||||
|
||||
<ui:ColorPickerButton
|
||||
DockPanel.Dock="Right"
|
||||
@@ -270,8 +270,8 @@
|
||||
</spp:OptionsDisplayItem>
|
||||
|
||||
<spp:OptionsDisplayItem
|
||||
Description="{Binding Path=Res.Settings_UI_DefaultLanguage, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
Header="{Binding Path=Res.Settings_Language, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
Description="{Binding Path=Res.Settings_UI_DefaultLanguage, Mode=OneWay, Source={x:Static spp:Strings.Settings_UI_DefaultLanguage}}"
|
||||
Header="{Binding Path=Res.Settings_Language, Mode=OneWay, Source={x:Static spp:Strings.Settings_Language}}"
|
||||
Navigates="False">
|
||||
<spp:OptionsDisplayItem.Icon>
|
||||
<ui:FontIcon FontFamily="Segoe Fluent Icons" Glyph="" />
|
||||
@@ -291,8 +291,8 @@
|
||||
</spp:OptionsDisplayItem>
|
||||
|
||||
<spp:OptionsDisplayItem
|
||||
Description="{Binding Path=Res.Settings_UI_DefaultFonts, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
Header="{Binding Path=Res.Settings_Fonts, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
Description="{Binding Path=Res.Settings_UI_DefaultFonts, Mode=OneWay, Source={x:Static spp:Strings.Settings_UI_DefaultFonts}}"
|
||||
Header="{Binding Path=Res.Settings_Fonts, Mode=OneWay, Source={x:Static spp:Strings.Settings_Fonts}}"
|
||||
Icon="Font"
|
||||
Navigates="False">
|
||||
<spp:OptionsDisplayItem.ActionButton>
|
||||
@@ -314,8 +314,8 @@
|
||||
</spp:OptionsDisplayItem>
|
||||
|
||||
<spp:OptionsDisplayItem
|
||||
Description="{Binding Path=Res.Settings_UI_WindowBackgroundStyle, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
Header="{Binding Path=Res.Settings_UI_WindowTransparencyMaterial, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
Description="{Binding Path=Res.Settings_UI_WindowBackgroundStyle, Mode=OneWay, Source={x:Static spp:Strings.Settings_UI_WindowBackgroundStyle}}"
|
||||
Header="{Binding Path=Res.Settings_UI_WindowTransparencyMaterial, Mode=OneWay, Source={x:Static spp:Strings.Settings_UI_WindowTransparencyMaterial}}"
|
||||
Navigates="False">
|
||||
<spp:OptionsDisplayItem.Icon>
|
||||
<ui:FontIcon FontFamily="Segoe Fluent Icons" Glyph="" />
|
||||
@@ -336,7 +336,7 @@
|
||||
</spp:OptionsDisplayItem.ActionButton>
|
||||
</spp:OptionsDisplayItem>
|
||||
|
||||
<spp:OptionsDisplayItem Header="{Binding Path=Res.Settings_UI_BackgroundOpacity, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" Navigates="False">
|
||||
<spp:OptionsDisplayItem Header="{Binding Path=Res.Settings_UI_BackgroundOpacity, Mode=OneWay, Source={x:Static spp:Strings.Settings_UI_BackgroundOpacity}}" Navigates="False">
|
||||
<spp:OptionsDisplayItem.Icon>
|
||||
<ui:FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="" />
|
||||
</spp:OptionsDisplayItem.Icon>
|
||||
@@ -351,7 +351,7 @@
|
||||
|
||||
<spp:OptionsDisplayItem
|
||||
Expands="True"
|
||||
Header="{Binding Path=Res.Settings_UI_CustomBackgroundImage, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
Header="{Binding Path=Res.Settings_UI_CustomBackgroundImage, Mode=OneWay, Source={x:Static spp:Strings.Settings_UI_CustomBackgroundImage}}"
|
||||
IsExpanded="{Binding Source={x:Static ms:UISettings.WindowBackgroundCustomImage}, Path=Value, Mode=OneWay}"
|
||||
Navigates="False">
|
||||
<spp:OptionsDisplayItem.Icon>
|
||||
@@ -367,7 +367,7 @@
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
DockPanel.Dock="Left"
|
||||
Text="{Binding Path=Res.PreviewPictures, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
Text="{Binding Path=Res.PreviewPictures, Mode=OneWay, Source={x:Static spp:Strings.PreviewPictures}}" />
|
||||
|
||||
<Image
|
||||
Width="250"
|
||||
@@ -389,7 +389,7 @@
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
DockPanel.Dock="Left"
|
||||
Text="{Binding Path=Res.Settings_UI_BackgroundImageOpacity, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
Text="{Binding Path=Res.Settings_UI_BackgroundImageOpacity, Mode=OneWay, Source={x:Static spp:Strings.Settings_UI_BackgroundImageOpacity}}" />
|
||||
<Slider
|
||||
MinWidth="250"
|
||||
DockPanel.Dock="Right"
|
||||
@@ -408,11 +408,11 @@
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
DockPanel.Dock="Left"
|
||||
Text="{Binding Path=Res.SelectPicture, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
Text="{Binding Path=Res.SelectPicture, Mode=OneWay, Source={x:Static spp:Strings.SelectPicture}}" />
|
||||
<Button
|
||||
MinWidth="150"
|
||||
Command="{Binding SelectImage_Click}"
|
||||
Content="{Binding Path=Res.Settings_UI_SelectImage, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
Content="{Binding Path=Res.Settings_UI_SelectImage, Mode=OneWay, Source={x:Static spp:Strings.Settings_UI_SelectImage}}"
|
||||
DockPanel.Dock="Right" />
|
||||
</DockPanel>
|
||||
|
||||
@@ -425,7 +425,7 @@
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
DockPanel.Dock="Left"
|
||||
Text="{Binding Path=Res.PictureZoom, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
Text="{Binding Path=Res.PictureZoom, Mode=OneWay, Source={x:Static spp:Strings.PictureZoom}}" />
|
||||
<ComboBox
|
||||
MinWidth="150"
|
||||
DockPanel.Dock="Right"
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
<StackPanel Classes="Mid">
|
||||
<TextBlock
|
||||
HorizontalAlignment="Left"
|
||||
Text="{Binding Path=Res.User_FastLoginTip, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
Text="{Binding Path=Res.User_FastLoginTip, Mode=OneWay, Source={x:Static spp:Strings.User_FastLoginTip}}"
|
||||
Theme="{StaticResource CaptionTextBlockStyle}" />
|
||||
<ItemsControl Background="Transparent" ItemsSource="{Binding ExternalLoginChannels}">
|
||||
<ItemsControl.Styles>
|
||||
@@ -107,7 +107,7 @@
|
||||
MaxLength="{x:Static com:PhoneNumberHelper.ChineseMainlandPhoneNumberLength}"
|
||||
Text="{Binding PhoneNumber}"
|
||||
TextAlignment="Left"
|
||||
Watermark="{Binding Path=Res.User_Phone, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
Watermark="{Binding Path=Res.User_Phone, Mode=OneWay, Source={x:Static spp:Strings.User_Phone}}" />
|
||||
<Border HorizontalAlignment="Left" Cursor="Hand">
|
||||
<DropDownButton
|
||||
Margin="0"
|
||||
@@ -139,7 +139,7 @@
|
||||
VerticalContentAlignment="Center"
|
||||
MaxLength="{x:Static columns:MaxLengths.SMS_CAPTCHA}"
|
||||
Text="{Binding SmsCode}"
|
||||
Watermark="{Binding Path=Res.User_SMSCode, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
Watermark="{Binding Path=Res.User_SMSCode, Mode=OneWay, Source={x:Static spp:Strings.User_SMSCode}}" />
|
||||
<Border
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Stretch"
|
||||
@@ -162,22 +162,22 @@
|
||||
HorizontalContentAlignment="Center"
|
||||
Classes="accent"
|
||||
Command="{Binding Submit}"
|
||||
Content="{Binding Path=Res.LoginAndRegister, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
Content="{Binding Path=Res.LoginAndRegister, Mode=OneWay, Source={x:Static spp:Strings.LoginAndRegister}}" />
|
||||
|
||||
</StackPanel>
|
||||
|
||||
<!-- 2 加载中状态 -->
|
||||
<StackPanel Classes="Mid">
|
||||
<TextBlock Text="{Binding Path=Res.User_WaitFastLoginTip, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" TextWrapping="Wrap" />
|
||||
<TextBlock Text="{Binding Path=Res.User_WaitFastLoginTip, Mode=OneWay, Source={x:Static spp:Strings.User_WaitFastLoginTip}}" TextWrapping="Wrap" />
|
||||
|
||||
<WrapPanel Margin="0,20" HorizontalAlignment="Center">
|
||||
<TextBlock Text="{Binding Path=Res.User_LoginUnexpectedPrompt, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" Theme="{StaticResource CaptionTextBlockStyle}" />
|
||||
<TextBlock Text="{Binding Path=Res.User_LoginUnexpectedPrompt, Mode=OneWay, Source={x:Static spp:Strings.User_LoginUnexpectedPrompt}}" Theme="{StaticResource CaptionTextBlockStyle}" />
|
||||
<ui:HyperlinkButton
|
||||
Margin="5,0"
|
||||
Padding="0"
|
||||
HorizontalContentAlignment="Center"
|
||||
Command="{Binding ManualLogin}">
|
||||
<TextBlock Text="{Binding Path=Res.Login_ManualLogin, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" Theme="{StaticResource CaptionTextBlockStyle}" />
|
||||
<TextBlock Text="{Binding Path=Res.Login_ManualLogin, Mode=OneWay, Source={x:Static spp:Strings.Login_ManualLogin}}" Theme="{StaticResource CaptionTextBlockStyle}" />
|
||||
</ui:HyperlinkButton>
|
||||
</WrapPanel>
|
||||
|
||||
@@ -197,7 +197,7 @@
|
||||
<Button
|
||||
HorizontalContentAlignment="Center"
|
||||
Command="{Binding ChangeState}"
|
||||
Content="{Binding Path=Res.Cancel, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
Content="{Binding Path=Res.Cancel, Mode=OneWay, Source={x:Static spp:Strings.Cancel}}"
|
||||
Theme="{StaticResource TransparentButton}">
|
||||
<Button.CommandParameter>
|
||||
<x:Int16>0</x:Int16>
|
||||
@@ -207,7 +207,7 @@
|
||||
HorizontalContentAlignment="Center"
|
||||
Command="{Binding ChooseChannel}"
|
||||
CommandParameter="{Binding CurrentSelectChannel}"
|
||||
Content="{Binding Path=Res.Retry, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
Content="{Binding Path=Res.Retry, Mode=OneWay, Source={x:Static spp:Strings.Retry}}"
|
||||
Theme="{StaticResource TransparentButton}" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
@@ -220,7 +220,7 @@
|
||||
HorizontalAlignment="Center">
|
||||
<TextBlock
|
||||
FontSize="12"
|
||||
Text="{Binding Path=Res.User_RegisterAgreed, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
Text="{Binding Path=Res.User_RegisterAgreed, Mode=OneWay, Source={x:Static spp:Strings.User_RegisterAgreed}}"
|
||||
Theme="{StaticResource CaptionTextBlockStyle}" />
|
||||
<ui:HyperlinkButton
|
||||
Margin="5,0"
|
||||
@@ -228,16 +228,16 @@
|
||||
Command="{Binding OpenHyperlink}"
|
||||
CommandParameter="Agreement"
|
||||
Cursor="Hand">
|
||||
<TextBlock Text="{Binding Path=Res.User_Agreement, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" Theme="{StaticResource CaptionTextBlockStyle}" />
|
||||
<TextBlock Text="{Binding Path=Res.User_Agreement, Mode=OneWay, Source={x:Static spp:Strings.User_Agreement}}" Theme="{StaticResource CaptionTextBlockStyle}" />
|
||||
</ui:HyperlinkButton>
|
||||
<TextBlock Text="{Binding Path=Res.And, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" Theme="{StaticResource CaptionTextBlockStyle}" />
|
||||
<TextBlock Text="{Binding Path=Res.And, Mode=OneWay, Source={x:Static spp:Strings.And}}" Theme="{StaticResource CaptionTextBlockStyle}" />
|
||||
<ui:HyperlinkButton
|
||||
Margin="5,0"
|
||||
Padding="0"
|
||||
Command="{Binding OpenHyperlink}"
|
||||
CommandParameter="Privacy"
|
||||
Cursor="Hand">
|
||||
<TextBlock Text="{Binding Path=Res.User_Privacy, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" Theme="{StaticResource CaptionTextBlockStyle}" />
|
||||
<TextBlock Text="{Binding Path=Res.User_Privacy, Mode=OneWay, Source={x:Static spp:Strings.User_Privacy}}" Theme="{StaticResource CaptionTextBlockStyle}" />
|
||||
</ui:HyperlinkButton>
|
||||
</WrapPanel>
|
||||
|
||||
@@ -255,7 +255,7 @@
|
||||
<Button.CommandParameter>
|
||||
<x:Int16>0</x:Int16>
|
||||
</Button.CommandParameter>
|
||||
<TextBlock Text="{Binding Path=Res.User_FastLogin, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
<TextBlock Text="{Binding Path=Res.User_FastLogin, Mode=OneWay, Source={x:Static spp:Strings.User_FastLogin}}" />
|
||||
</Button>
|
||||
<Separator
|
||||
Height="18"
|
||||
@@ -272,7 +272,7 @@
|
||||
<Button.CommandParameter>
|
||||
<x:Int16>1</x:Int16>
|
||||
</Button.CommandParameter>
|
||||
<TextBlock Text="{Binding Path=Res.User_PhoneLogin, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
<TextBlock Text="{Binding Path=Res.User_PhoneLogin, Mode=OneWay, Source={x:Static spp:Strings.User_PhoneLogin}}" />
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
@@ -45,6 +45,18 @@ public partial class LoginOrRegisterPage : ReactiveUserControl<LoginOrRegisterWi
|
||||
this.ViewModel.Close();
|
||||
}
|
||||
}
|
||||
Application.Current!.UrlsOpened += Current_UrlsOpened;
|
||||
}
|
||||
|
||||
private async void Current_UrlsOpened(object? sender, UrlOpenedEventArgs e)
|
||||
{
|
||||
var loginUrl = e.Urls.Where(x => x.StartsWith(Constants.UrlSchemes.Login)).FirstOrDefault();
|
||||
if (loginUrl != null)
|
||||
{
|
||||
//var token = loginUrl.TrimStart(Constants.UrlSchemes.Login);
|
||||
var token = loginUrl.Substring(Constants.UrlSchemes.Login.Length, loginUrl.Length - Constants.UrlSchemes.Login.Length);
|
||||
await ThirdPartyLoginHelper.OnMessageAsync(token);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnDataContextChanged(EventArgs e)
|
||||
@@ -59,6 +71,7 @@ public partial class LoginOrRegisterPage : ReactiveUserControl<LoginOrRegisterWi
|
||||
|
||||
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
|
||||
{
|
||||
Application.Current!.UrlsOpened -= Current_UrlsOpened;
|
||||
base.OnDetachedFromVisualTree(e);
|
||||
if (DataContext is LoginOrRegisterWindowViewModel vm)
|
||||
{
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
<DockPanel>
|
||||
<!--<Button
|
||||
Margin="0,0,0,5"
|
||||
Content="{Binding Path=Res.Notice_AllMarkHasRead,Mode=OneWay,Source={x:Static s:ResourceService.Current}}"
|
||||
Content="{Binding Path=Res.Notice_AllMarkHasRead,Mode=OneWay,Source={x:Static spp:Strings.Notice_AllMarkHasRead}}"
|
||||
Cursor="Hand"
|
||||
DockPanel.Dock="Top"
|
||||
Theme="{StaticResource HyperlinkButton}" />-->
|
||||
|
||||
@@ -52,6 +52,7 @@ public sealed partial class MainWindow : ReactiveAppWindow<MainWindowViewModel>
|
||||
}
|
||||
Task2.InBackground(async () =>
|
||||
{
|
||||
IViewModelManager.Instance.Get<HomePageViewModel>().GetServerContent();
|
||||
await AdvertiseService.Current.RefrshAdvertiseAsync();
|
||||
NoticeService.Current.GetNewsAsync();
|
||||
});
|
||||
|
||||
+3
-3
@@ -32,9 +32,9 @@ sealed class ReverseProxyHttpClientHandler : DelegatingHandler
|
||||
var tlsSniValue = domainConfig.GetTlsSniPattern().WithDomain(uri.Host).WithRandom();
|
||||
request.SetRequestContext(new RequestContext(isHttps, tlsSniValue));
|
||||
|
||||
//// 设置请求头 host,修改协议为 http
|
||||
//request.Headers.Host = uri.Host;
|
||||
//request.RequestUri = new UriBuilder(uri) { Scheme = Uri.UriSchemeHttp }.Uri;
|
||||
// 设置请求头 host,修改协议为 http
|
||||
request.Headers.Host = uri.Host;
|
||||
request.RequestUri = new UriBuilder(uri) { Scheme = Uri.UriSchemeHttp }.Uri;
|
||||
|
||||
if (domainConfig.Timeout != null)
|
||||
{
|
||||
|
||||
+1
-1
@@ -89,7 +89,7 @@ sealed partial class HttpReverseProxyMiddleware
|
||||
|
||||
var forwarderRequestConfig = new ForwarderRequestConfig()
|
||||
{
|
||||
Version = context.Request.Protocol.StartsWith("HTTP/2.0") ? System.Net.HttpVersion.Version20 : System.Net.HttpVersion.Version11,
|
||||
Version = context.Request.Protocol.StartsWith("HTTP/2") ? System.Net.HttpVersion.Version20 : System.Net.HttpVersion.Version11,
|
||||
};
|
||||
|
||||
var error = await httpForwarder.SendAsync(context, destinationPrefix, httpClient, forwarderRequestConfig, HttpTransformer.Empty);
|
||||
|
||||
@@ -47,17 +47,8 @@ internal sealed class ScriptRepository : Repository<Script, int>, IScriptReposit
|
||||
const string sql_ =
|
||||
$"{SQLStrings.Update}[{Script.TableName}] " +
|
||||
$"set [{Script.ColumnName_CachePath}] = '{{0}}' " +
|
||||
$"where [{Script.ColumnName_CachePath}] = {{1}}";
|
||||
$"where [{Script.ColumnName_Id}] = {{1}}";
|
||||
var sql = string.Format(sql_, item.CachePath, item.LocalId);
|
||||
//var sql =
|
||||
// SQLStrings.Update +
|
||||
// "[" + Script.TableName + "]" +
|
||||
// " set " +
|
||||
// "[" + Script.ColumnName_Enable + "]" +
|
||||
// $" = {item.Enable}" +
|
||||
// " where " +
|
||||
// "[" + Script.ColumnName_Id + "]" +
|
||||
// $" = {item.LocalId}";
|
||||
var r = await dbConnection.ExecuteAsync(sql);
|
||||
return r;
|
||||
}, cancellationToken: cancellationToken).ConfigureAwait(false);
|
||||
|
||||
@@ -366,15 +366,28 @@ public sealed class ScriptManager : GeneralHttpClientFactory, IScriptManager
|
||||
static IApiRsp OK_Script_DeleteSuccess() => ApiRspHelper.Ok(AppResources.Script_DeleteSuccess);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 版本升级 检查数据库 数据 是否正确 不正确删除重新打包缓存文件
|
||||
/// </summary>
|
||||
/// <param name="list"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<IEnumerable<ScriptDTO>> CheckFiles(IEnumerable<ScriptDTO> list)
|
||||
{
|
||||
var scripts = list.ToList();
|
||||
foreach (var item in list)
|
||||
{
|
||||
//检查缓存文件夹如果不是 IScriptManager.DirName_Build 替换成 IScriptManager.DirName_Build 开头
|
||||
if (!item.CachePath.StartsWith($"{IScriptManager.DirName_Build}/"))
|
||||
if (!item.CachePath.StartsWith($"{IScriptManager.DirName_Build}{Path.DirectorySeparatorChar}"))
|
||||
{
|
||||
item.CachePath = Path.Combine(IScriptManager.DirName_Build, item.FileName!);
|
||||
var cachePath = Path.Combine(Plugin.Instance.CacheDirectory, item.CachePath);
|
||||
if (File.Exists(cachePath))
|
||||
{
|
||||
File.Delete(cachePath);
|
||||
}
|
||||
await TryReadFileAsync(item, true);
|
||||
//清理 脚本内容 后续 IPC 传递 插件进程读取。
|
||||
item.Content = string.Empty;
|
||||
await scriptRepository.SaveScriptCachePathAsync(item, default);
|
||||
}
|
||||
if (!CheckFile(item))
|
||||
@@ -405,8 +418,9 @@ public sealed class ScriptManager : GeneralHttpClientFactory, IScriptManager
|
||||
/// 修改为仅尝试判断文件是否存在
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
/// <param name="isReadContent"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<ScriptDTO> TryReadFileAsync(ScriptDTO item)
|
||||
public async Task<ScriptDTO> TryReadFileAsync(ScriptDTO item, bool isReadContent = false)
|
||||
{
|
||||
var cachePath = Path.Combine(Plugin.Instance.CacheDirectory, item.CachePath);
|
||||
if (File.Exists(cachePath))
|
||||
@@ -419,7 +433,10 @@ public sealed class ScriptManager : GeneralHttpClientFactory, IScriptManager
|
||||
var infoPath = Path.Combine(Plugin.Instance.AppDataDirectory, item.FilePath);
|
||||
if (File.Exists(infoPath))
|
||||
{
|
||||
//item.Content = File.ReadAllText(infoPath);
|
||||
if (isReadContent)
|
||||
{
|
||||
item.Content = File.ReadAllText(infoPath);
|
||||
}
|
||||
if (!await BuildScriptAsync(item, fileInfo, item.IsCompile))
|
||||
{
|
||||
toast.Show(ToastIcon.Error, AppResources.Script_ReadFileError_.Format(item.Name));
|
||||
|
||||
@@ -11,7 +11,21 @@ partial class ProxyService
|
||||
/// 启动代理服务
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
async Task<OperateProxyServiceResult> StartProxyServiceAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await StartProxyServiceCoreAsync();
|
||||
return result;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ex;
|
||||
}
|
||||
}
|
||||
|
||||
async Task<OperateProxyServiceResult> StartProxyServiceCoreAsync()
|
||||
{
|
||||
IReadOnlyCollection<AccelerateProjectDTO>? proxyDomains = EnableProxyDomains;
|
||||
|
||||
@@ -262,7 +276,21 @@ partial class ProxyService
|
||||
/// <summary>
|
||||
/// 停止代理服务
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
async Task<OperateProxyServiceResult> StopProxyServiceAsync(bool isExit = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await StopProxyServiceCoreAsync(isExit);
|
||||
return result;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ex;
|
||||
}
|
||||
}
|
||||
|
||||
async Task<OperateProxyServiceResult> StopProxyServiceCoreAsync(bool isExit)
|
||||
{
|
||||
bool callSet = true;
|
||||
#if WINDOWS
|
||||
@@ -322,10 +350,12 @@ partial class ProxyService
|
||||
/// 操作代理服务返回结果
|
||||
/// </summary>
|
||||
/// <param name="Error"></param>
|
||||
readonly record struct OperateProxyServiceResult(string? Error)
|
||||
readonly record struct OperateProxyServiceResult(string? Error, Exception? Exception = null)
|
||||
{
|
||||
public static implicit operator OperateProxyServiceResult(string error) => new(error);
|
||||
|
||||
public static implicit operator OperateProxyServiceResult(Exception exception) => new(null, exception);
|
||||
|
||||
/// <summary>
|
||||
/// 将返回结果使用 Toast 显示并且返回当前应设置的代理状态
|
||||
/// </summary>
|
||||
@@ -339,6 +369,11 @@ partial class ProxyService
|
||||
Toast.Show(ToastIcon.Success, Strings.CommunityFix_StartProxySuccess);
|
||||
proxyStatus = true;
|
||||
}
|
||||
else if (Exception != null)
|
||||
{
|
||||
Exception.LogAndShowT(nameof(ProxyService));
|
||||
proxyStatus = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Toast.Show(ToastIcon.Error, Error);
|
||||
@@ -356,6 +391,11 @@ partial class ProxyService
|
||||
Toast.Show(ToastIcon.Error, Error);
|
||||
proxyStatus = true;
|
||||
}
|
||||
else if (Exception != null)
|
||||
{
|
||||
Exception.LogAndShowT(nameof(ProxyService));
|
||||
proxyStatus = true;
|
||||
}
|
||||
return proxyStatus;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -330,23 +330,24 @@ public sealed partial class ProxyService
|
||||
#endif
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
if (ProxySettings.SupportProxyServicesStatus.Value.Any_Nullable() && result.Content.Any_Nullable())
|
||||
{
|
||||
var items = result.Content!.SelectMany(s => s.Items!);
|
||||
foreach (var item in items)
|
||||
{
|
||||
if (ProxySettings.SupportProxyServicesStatus.Value.Contains(item.Id.ToString()))
|
||||
{
|
||||
item.ThreeStateEnable = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ProxyDomains.AddOrUpdate(result.Content!);
|
||||
}
|
||||
|
||||
LoadOrSaveLocalAccelerate();
|
||||
|
||||
if (ProxySettings.SupportProxyServicesStatus.Value.Any_Nullable() && ProxyDomains.Items.Any_Nullable())
|
||||
{
|
||||
var items = ProxyDomains.Items!.SelectMany(s => s.Items!);
|
||||
var enableItems = ProxySettings.SupportProxyServicesStatus.Value;
|
||||
foreach (var item in items)
|
||||
{
|
||||
if (enableItems.Contains(item.Id.ToString()))
|
||||
{
|
||||
item.ThreeStateEnable = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//if (IsLoadImage && ProxyDomains.Items.Any_Nullable())
|
||||
//{
|
||||
// foreach (var item in ProxyDomains.Items)
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
Margin="0,5"
|
||||
HorizontalAlignment="Center"
|
||||
Foreground="DodgerBlue"
|
||||
Text="{Binding Path=Res.UploadFlow, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
Text="{Binding Path=Res.UploadFlow, Mode=OneWay, Source={x:Static spp:Strings.UploadFlow}}"
|
||||
Theme="{StaticResource BodyStrongTextBlockStyle}" />
|
||||
<TextBlock
|
||||
x:Name="textBlockRead"
|
||||
@@ -37,7 +37,7 @@
|
||||
Margin="0,5"
|
||||
HorizontalAlignment="Center"
|
||||
Foreground="IndianRed"
|
||||
Text="{Binding Path=Res.DownloadFlow, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
Text="{Binding Path=Res.DownloadFlow, Mode=OneWay, Source={x:Static spp:Strings.DownloadFlow}}"
|
||||
Theme="{StaticResource BodyStrongTextBlockStyle}" />
|
||||
<TextBlock
|
||||
x:Name="textBlockWrite"
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
Margin="28,4,0,4"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding Path=Res.CommunityFix_StartProxy, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
Text="{Binding Path=Res.CommunityFix_StartProxy, Mode=OneWay, Source={x:Static spp:Strings.CommunityFix_StartProxy}}" />
|
||||
</Panel>
|
||||
</Button>
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
Margin="28,4,0,4"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center">
|
||||
<!--<Run Text="{Binding Path=Res.CommunityFix_StopProxy,Source={x:Static s:ResourceService.Current}},Mode=OneWay}" />
|
||||
<!--<Run Text="{Binding Path=Res.CommunityFix_StopProxy,Source={x:Static spp:Strings.CommunityFix_StopProxy}},Mode=OneWay}" />
|
||||
<Run Text=" " />
|
||||
<Run Text="{Binding Path=AccelerateTime,Source={x:Static s:ProxyService.Current}},Mode=OneWay,Converter={StaticResource StringFormatConverter}}" />-->
|
||||
<TextBlock.Text>
|
||||
@@ -85,7 +85,7 @@
|
||||
<CompiledBinding
|
||||
Mode="OneWay"
|
||||
Path="Res.CommunityFix_StopProxy"
|
||||
Source="{x:Static s:ResourceService.Current}}" />
|
||||
Source="{x:Static spp:Strings.CommunityFix_StopProxy}}" />
|
||||
<CompiledBinding
|
||||
Converter="{StaticResource StringFormatConverter}"
|
||||
Mode="OneWay"
|
||||
@@ -123,7 +123,7 @@
|
||||
Margin="28,4,0,4"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding Path=Res.Refresh, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
Text="{Binding Path=Res.Refresh, Mode=OneWay, Source={x:Static spp:Strings.Refresh}}" />
|
||||
</Panel>
|
||||
</Button>
|
||||
|
||||
@@ -143,7 +143,7 @@
|
||||
Margin="28,4,0,4"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding Path=Res.CommunityFix_MenuName, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
Text="{Binding Path=Res.CommunityFix_MenuName, Mode=OneWay, Source={x:Static spp:Strings.CommunityFix_MenuName}}" />
|
||||
</Panel>
|
||||
</ToggleButton>
|
||||
|
||||
@@ -164,7 +164,7 @@
|
||||
</DataTemplate>
|
||||
</ui:MenuFlyoutSubItem.ItemTemplate>
|
||||
</ui:MenuFlyoutSubItem>-->
|
||||
<!--<ui:MenuFlyoutItem Text="{Binding Path=Res.Settings_Plugin, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />-->
|
||||
<!--<ui:MenuFlyoutItem Text="{Binding Path=Res.Settings_Plugin, Mode=OneWay, Source={x:Static spp:Strings.Settings_Plugin}}" />-->
|
||||
<!--<ui:MenuFlyoutSeparator />-->
|
||||
<!--<ui:MenuFlyoutItem Text="安装证书" />
|
||||
<ui:MenuFlyoutItem Text="移除证书" />
|
||||
@@ -180,7 +180,7 @@
|
||||
<CompiledBinding
|
||||
Mode="OneWay"
|
||||
Path="Res.Plugin_Version"
|
||||
Source="{x:Static s:ResourceService.Current}" />
|
||||
Source="{x:Static spp:Strings.Plugin_Version}" />
|
||||
<CompiledBinding
|
||||
Mode="OneWay"
|
||||
Path="Version"
|
||||
@@ -188,9 +188,9 @@
|
||||
</MultiBinding>
|
||||
</ui:MenuFlyoutItem.Text>
|
||||
</ui:MenuFlyoutItem>
|
||||
<!--<ui:MenuFlyoutItem Text="{Binding Path=Res.ViewInStore, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
<ui:MenuFlyoutItem Text="{Binding Path=Res.UseHelp, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
<ui:MenuFlyoutItem Text="{Binding Path=Res.AboutThisPlugin, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />-->
|
||||
<!--<ui:MenuFlyoutItem Text="{Binding Path=Res.ViewInStore, Mode=OneWay, Source={x:Static spp:Strings.ViewInStore}}" />
|
||||
<ui:MenuFlyoutItem Text="{Binding Path=Res.UseHelp, Mode=OneWay, Source={x:Static spp:Strings.UseHelp}}" />
|
||||
<ui:MenuFlyoutItem Text="{Binding Path=Res.AboutThisPlugin, Mode=OneWay, Source={x:Static spp:Strings.AboutThisPlugin}}" />-->
|
||||
</ui:FAMenuFlyout>
|
||||
</DropDownButton.Flyout>
|
||||
</DropDownButton>
|
||||
@@ -198,7 +198,7 @@
|
||||
</spp:PageBase.ActionContent>
|
||||
<spp:PageBase.PaneContent>
|
||||
<StackPanel Margin="15,20" Spacing="10">
|
||||
<TextBlock Text="{Binding Path=Res.CommunityFix_ProxyMode, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" Theme="{StaticResource BodyStrongTextBlockStyle}" />
|
||||
<TextBlock Text="{Binding Path=Res.CommunityFix_ProxyMode, Mode=OneWay, Source={x:Static spp:Strings.CommunityFix_ProxyMode}}" Theme="{StaticResource BodyStrongTextBlockStyle}" />
|
||||
|
||||
<TabStrip
|
||||
Background="{DynamicResource ControlOnImageFillColorDefaultBrush}"
|
||||
@@ -215,14 +215,14 @@
|
||||
</TabStrip.ItemTemplate>
|
||||
</TabStrip>
|
||||
|
||||
<TextBlock Text="{Binding Path=Res.CommunityFix_MenuName, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" Theme="{StaticResource BodyStrongTextBlockStyle}" />
|
||||
<TextBlock Text="{Binding Path=Res.CommunityFix_MenuName, Mode=OneWay, Source={x:Static spp:Strings.CommunityFix_MenuName}}" Theme="{StaticResource BodyStrongTextBlockStyle}" />
|
||||
<DockPanel>
|
||||
<ToggleSwitch
|
||||
VerticalAlignment="Center"
|
||||
Classes="NoContent"
|
||||
IsChecked="{Binding Source={x:Static s:ProxyService.Current}, Path=IsEnableScript, Mode=TwoWay}"
|
||||
OffContent="{Binding Path=Res.CommunityFix_EnableScriptService, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
OnContent="{Binding Path=Res.CommunityFix_EnableScriptService, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
OffContent="{Binding Path=Res.CommunityFix_EnableScriptService, Mode=OneWay, Source={x:Static spp:Strings.CommunityFix_EnableScriptService}}"
|
||||
OnContent="{Binding Path=Res.CommunityFix_EnableScriptService, Mode=OneWay, Source={x:Static spp:Strings.CommunityFix_EnableScriptService}}" />
|
||||
|
||||
<!--<WrapPanel>-->
|
||||
<TextBlock
|
||||
@@ -247,7 +247,7 @@
|
||||
VerticalAlignment="Center"
|
||||
Command="{Binding Source={x:Static s:ProxyService.Current}, Path=RefreshIpv6Support, Mode=OneWay}"
|
||||
Theme="{StaticResource TransparentButton}"
|
||||
ToolTip.Tip="{Binding Path=Res.Refresh, Mode=OneWay, Source={x:Static s:ResourceService.Current}}">
|
||||
ToolTip.Tip="{Binding Path=Res.Refresh, Mode=OneWay, Source={x:Static spp:Strings.Refresh}}">
|
||||
<ui:SymbolIcon Symbol="Refresh" />
|
||||
</Button>
|
||||
</WrapPanel>-->
|
||||
@@ -256,8 +256,8 @@
|
||||
VerticalAlignment="Center"
|
||||
Classes="NoContent"
|
||||
IsChecked="{Binding Source={x:Static ms:ProxySettings.ProgramStartupRunProxy}, Path=Value, Mode=TwoWay}"
|
||||
OffContent="{Binding Path=Res.CommunityFix_AutoRunProxy, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
OnContent="{Binding Path=Res.CommunityFix_AutoRunProxy, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
OffContent="{Binding Path=Res.CommunityFix_AutoRunProxy, Mode=OneWay, Source={x:Static spp:Strings.CommunityFix_AutoRunProxy}}"
|
||||
OnContent="{Binding Path=Res.CommunityFix_AutoRunProxy, Mode=OneWay, Source={x:Static spp:Strings.CommunityFix_AutoRunProxy}}" />
|
||||
|
||||
<!--<StackPanel Orientation="Horizontal" Spacing="4">
|
||||
<ToggleButton
|
||||
@@ -265,7 +265,7 @@
|
||||
Theme="{StaticResource TransparentToggleButton}"
|
||||
ToolTip.Tip="{Binding Path=Res.GameList_OnlyInstalled,
|
||||
Mode=OneWay,
|
||||
Source={x:Static s:ResourceService.Current}}">
|
||||
Source={x:Static spp:Strings.GameList_OnlyInstalled}}">
|
||||
<Viewbox Width="20" Height="20">
|
||||
<ui:SymbolIcon Symbol="Play" />
|
||||
</Viewbox>
|
||||
@@ -276,7 +276,7 @@
|
||||
Theme="{StaticResource TransparentToggleButton}"
|
||||
ToolTip.Tip="{Binding Path=Res.GameList_OnlyCloudArchive,
|
||||
Mode=OneWay,
|
||||
Source={x:Static s:ResourceService.Current}}">
|
||||
Source={x:Static spp:Strings.GameList_OnlyCloudArchive}}">
|
||||
<Viewbox Width="20" Height="20">
|
||||
<ui:SymbolIcon Symbol="CloudSyncComplete" />
|
||||
</Viewbox>
|
||||
@@ -286,37 +286,37 @@
|
||||
<Button
|
||||
HorizontalAlignment="Stretch"
|
||||
Command="{Binding ProxySettingsCommand}"
|
||||
Content="{Binding Path=Res.CommunityFix_ProxySettings, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
Content="{Binding Path=Res.CommunityFix_ProxySettings, Mode=OneWay, Source={x:Static spp:Strings.CommunityFix_ProxySettings}}" />
|
||||
|
||||
<Separator Margin="0,8" Classes="Horizontal" />
|
||||
|
||||
<Button
|
||||
HorizontalAlignment="Stretch"
|
||||
Command="{Binding SetupCertificateCommand}"
|
||||
Content="{Binding Path=Res.CommunityFix_SetupCertificate, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
Content="{Binding Path=Res.CommunityFix_SetupCertificate, Mode=OneWay, Source={x:Static spp:Strings.CommunityFix_SetupCertificate}}" />
|
||||
<Button
|
||||
HorizontalAlignment="Stretch"
|
||||
Command="{Binding DeleteCertificateCommand}"
|
||||
Content="{Binding Path=Res.CommunityFix_DeleteCertificate, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
Content="{Binding Path=Res.CommunityFix_DeleteCertificate, Mode=OneWay, Source={x:Static spp:Strings.CommunityFix_DeleteCertificate}}" />
|
||||
<Button
|
||||
HorizontalAlignment="Stretch"
|
||||
Command="{Binding OpenCertificateDirCommand}"
|
||||
Content="{Binding Path=Res.CommunityFix_OpenCertificateDir, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
Content="{Binding Path=Res.CommunityFix_OpenCertificateDir, Mode=OneWay, Source={x:Static spp:Strings.CommunityFix_OpenCertificateDir}}" />
|
||||
|
||||
<Separator Margin="0,8" Classes="Horizontal" />
|
||||
|
||||
<Button
|
||||
HorizontalAlignment="Stretch"
|
||||
Command="{Binding EditHostsFileCommand}"
|
||||
Content="{Binding Path=Res.CommunityFix_EditHostsFile, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
Content="{Binding Path=Res.CommunityFix_EditHostsFile, Mode=OneWay, Source={x:Static spp:Strings.CommunityFix_EditHostsFile}}" />
|
||||
<Button
|
||||
HorizontalAlignment="Stretch"
|
||||
Command="{Binding ResetHostsFileCommand}"
|
||||
Content="{Binding Path=Res.CommunityFix_ResetHostsFile, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
Content="{Binding Path=Res.CommunityFix_ResetHostsFile, Mode=OneWay, Source={x:Static spp:Strings.CommunityFix_ResetHostsFile}}" />
|
||||
<Button
|
||||
HorizontalAlignment="Stretch"
|
||||
Command="{Binding OpenHostsDirCommand}"
|
||||
Content="{Binding Path=Res.CommunityFix_OpenHostsDir, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
Content="{Binding Path=Res.CommunityFix_OpenHostsDir, Mode=OneWay, Source={x:Static spp:Strings.CommunityFix_OpenHostsDir}}" />
|
||||
|
||||
<!--<ui:FAComboBox ItemsSource="{Binding Source={x:Static ms:ProxySettings.ProxyModes}, Path=., Mode=OneWay}" SelectedItem="{Binding Source={x:Static ms:ProxySettings.ProxyMode}, Path=Value, Mode=TwoWay}">
|
||||
<ui:FAComboBox.ItemTemplate>
|
||||
@@ -358,7 +358,8 @@
|
||||
</ia:DataTriggerBehavior>
|
||||
</i:Interaction.Behaviors>-->
|
||||
|
||||
<spp:ContentLoader IsLoading="{Binding Source={x:Static s:ProxyService.Current}, Path=!!!ProxyDomainsList.Count, Mode=OneWay}" NoResultMessage="{Binding Path=Res.CommunityFix_ItemsEmpty, Mode=OneWay, Source={x:Static s:ResourceService.Current}}">
|
||||
<spp:ContentLoader IsLoading="{Binding Source={x:Static s:ProxyService.Current}, Path=!!!ProxyDomainsList.Count, Mode=OneWay}"
|
||||
NoResultMessage="{Binding Path=Res.CommunityFix_ItemsEmpty, Mode=OneWay, Source={x:Static spp:Strings.CommunityFix_ItemsEmpty}}">
|
||||
<Grid ColumnDefinitions="*,Auto">
|
||||
<ItemsControl ItemsSource="{Binding Source={x:Static s:ProxyService.Current}, Path=ProxyDomainsList, Mode=OneWay}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
@@ -435,8 +436,8 @@
|
||||
x:Name="Tabs"
|
||||
ItemContainerTheme="{StaticResource TabItemStyle}"
|
||||
Theme="{StaticResource TabStripStyle}">
|
||||
<TabStripItem Content="{Binding Path=Res.CommunityFix_FlowStatistics, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
<TabStripItem Content="{Binding Path=Res.CommunityFix_Services, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
<TabStripItem Content="{Binding Path=Res.CommunityFix_FlowStatistics, Mode=OneWay, Source={x:Static spp:Strings.CommunityFix_FlowStatistics}}" />
|
||||
<TabStripItem Content="{Binding Path=Res.CommunityFix_Services, Mode=OneWay, Source={x:Static spp:Strings.CommunityFix_Services}}" />
|
||||
</TabStrip>
|
||||
<StackPanel
|
||||
Grid.Row="0"
|
||||
@@ -450,7 +451,7 @@
|
||||
</Style>
|
||||
</StackPanel.Styles>
|
||||
<!--<StackPanel HorizontalAlignment="Center" Orientation="Horizontal">
|
||||
<TextBlock FontSize="26" Text="{Binding Path=Res.CommunityFix_AlreadyProxy, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
<TextBlock FontSize="26" Text="{Binding Path=Res.CommunityFix_AlreadyProxy, Mode=OneWay, Source={x:Static spp:Strings.CommunityFix_AlreadyProxy}}" />
|
||||
<TextBlock
|
||||
Margin="5,0,0,0"
|
||||
FontSize="26"
|
||||
@@ -459,12 +460,12 @@
|
||||
StringFormat={}{0:hh\\:mm\\:ss}}" />
|
||||
</StackPanel>-->
|
||||
<TextBlock>
|
||||
<Run Text="{Binding Path=Res.CommunityFix_ProxyMode, StringFormat={}{0}:, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
<Run Text="{Binding Path=Res.CommunityFix_ProxyMode, StringFormat={}{0}:, Mode=OneWay, Source={x:Static spp:Strings.CommunityFix_ProxyMode, StringFormat={}{0}:}}" />
|
||||
<Run Text="{Binding Source={x:Static ms:ProxySettings.ProxyMode}, Path=Value, Mode=OneWay, Converter={StaticResource EnumLocalizationNameConverter}}" />
|
||||
|
||||
<Run Text=" " />
|
||||
|
||||
<Run Text="{Binding Path=Res.CommunityFix_EnableScriptService, StringFormat={}{0}:, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
<Run Text="{Binding Path=Res.CommunityFix_EnableScriptService, StringFormat={}{0}:, Mode=OneWay, Source={x:Static spp:Strings.CommunityFix_EnableScriptService, StringFormat={}{0}:}}" />
|
||||
<Run Text="{Binding Source={x:Static s:ProxyService.Current}, Path=IsEnableScript, Converter={StaticResource StringFormatConverter}}" />
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
@@ -487,7 +488,7 @@
|
||||
Margin="0,0,0,10"
|
||||
DockPanel.Dock="Top"
|
||||
FontSize="16"
|
||||
Text="{Binding Path=Res.CommunityFix_AccelerationsEnable, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
Text="{Binding Path=Res.CommunityFix_AccelerationsEnable, Mode=OneWay, Source={x:Static spp:Strings.CommunityFix_AccelerationsEnable}}" />
|
||||
<ScrollViewer>
|
||||
<ItemsControl ItemsSource="{Binding EnableProxyDomains, Source={x:Static s:ProxyService.Current}}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
@@ -514,7 +515,7 @@
|
||||
Margin="0,0,0,10"
|
||||
DockPanel.Dock="Top"
|
||||
FontSize="16"
|
||||
Text="{Binding Path=Res.CommunityFix_ScriptsEnable, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
Text="{Binding Path=Res.CommunityFix_ScriptsEnable, Mode=OneWay, Source={x:Static spp:Strings.CommunityFix_ScriptsEnable}}" />
|
||||
<ScrollViewer>
|
||||
<ItemsControl ItemsSource="{Binding EnableProxyScripts^, Source={x:Static s:ProxyService.Current}}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
|
||||
@@ -30,12 +30,12 @@
|
||||
</On>
|
||||
</OnFormFactor>
|
||||
</TabStrip.ItemsPanel>
|
||||
<TabStripItem Content="{Binding Path=Res.CommunityFix, Mode=OneWay, Source={x:Static s:ResourceService.Current}}">
|
||||
<TabStripItem Content="{Binding Path=Res.CommunityFix, Mode=OneWay, Source={x:Static spp:Strings.CommunityFix}}">
|
||||
<TabStripItem.Tag>
|
||||
<x:Type TypeName="spp:AcceleratorPage" />
|
||||
</TabStripItem.Tag>
|
||||
</TabStripItem>
|
||||
<TabStripItem Content="{Binding Path=Res.ScriptConfig, Mode=OneWay, Source={x:Static s:ResourceService.Current}}">
|
||||
<TabStripItem Content="{Binding Path=Res.ScriptConfig, Mode=OneWay, Source={x:Static spp:Strings.ScriptConfig}}">
|
||||
<TabStripItem.Tag>
|
||||
<x:Type TypeName="spp:ScriptPage" />
|
||||
</TabStripItem.Tag>
|
||||
|
||||
@@ -14,10 +14,10 @@
|
||||
x:DataType="spp:ProxySettingsWindowViewModel"
|
||||
mc:Ignorable="d">
|
||||
<StackPanel Margin="{StaticResource PageMargin}" Spacing="{StaticResource SettingsSpacing}">
|
||||
<ui:SettingsExpander Header="{Binding Path=Res.CommunityFix_ProxySettings, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" IsExpanded="True">
|
||||
<ui:SettingsExpander Header="{Binding Path=Res.CommunityFix_ProxySettings, Mode=OneWay, Source={x:Static spp:Strings.CommunityFix_ProxySettings}}" IsExpanded="True">
|
||||
|
||||
<ui:SettingsExpanderItem>
|
||||
<TextBlock Text="{Binding Path=Res.Settings_Proxy_SystemProxyIp, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
<TextBlock Text="{Binding Path=Res.Settings_Proxy_SystemProxyIp, Mode=OneWay, Source={x:Static spp:Strings.Settings_Proxy_SystemProxyIp}}" />
|
||||
<ui:SettingsExpanderItem.Footer>
|
||||
<ui:FAComboBox
|
||||
IsEditable="True"
|
||||
@@ -27,7 +27,7 @@
|
||||
</ui:SettingsExpanderItem>
|
||||
|
||||
<ui:SettingsExpanderItem>
|
||||
<TextBlock Text="{Binding Path=Res.Settings_Proxy_CustomDNS, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
<TextBlock Text="{Binding Path=Res.Settings_Proxy_CustomDNS, Mode=OneWay, Source={x:Static spp:Strings.Settings_Proxy_CustomDNS}}" />
|
||||
<ui:SettingsExpanderItem.Footer>
|
||||
<ui:FAComboBox
|
||||
IsEditable="True"
|
||||
@@ -48,35 +48,35 @@
|
||||
<Button Content="{Binding Path=Res.Refresh,Mode=OneWay,Source={x:Static resx:R.Current}}"></Button>
|
||||
</DockPanel>-->
|
||||
<ui:SettingsExpanderItem>
|
||||
<TextBlock Text="{Binding Path=Res.CommunityFix_AutoRunProxy, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
<TextBlock Text="{Binding Path=Res.CommunityFix_AutoRunProxy, Mode=OneWay, Source={x:Static spp:Strings.CommunityFix_AutoRunProxy}}" />
|
||||
<ui:SettingsExpanderItem.Footer>
|
||||
<ToggleSwitch Classes="LeftContent" IsChecked="{Binding Source={x:Static ms:ProxySettings.ProgramStartupRunProxy}, Path=Value, Mode=TwoWay}" />
|
||||
</ui:SettingsExpanderItem.Footer>
|
||||
</ui:SettingsExpanderItem>
|
||||
|
||||
<ui:SettingsExpanderItem>
|
||||
<TextBlock Text="{Binding Path=Res.CommunityFix_ProxyOnlyOnScript, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
<TextBlock Text="{Binding Path=Res.CommunityFix_ProxyOnlyOnScript, Mode=OneWay, Source={x:Static spp:Strings.CommunityFix_ProxyOnlyOnScript}}" />
|
||||
<ui:SettingsExpanderItem.Footer>
|
||||
<ToggleSwitch Classes="LeftContent" IsChecked="{Binding Source={x:Static ms:ProxySettings.OnlyEnableProxyScript}, Path=Value, Mode=TwoWay}" />
|
||||
</ui:SettingsExpanderItem.Footer>
|
||||
</ui:SettingsExpanderItem>
|
||||
|
||||
<ui:SettingsExpanderItem>
|
||||
<TextBlock Text="{Binding Path=Res.CommunityFix_EnableHttpProxyToHttps, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
<TextBlock Text="{Binding Path=Res.CommunityFix_EnableHttpProxyToHttps, Mode=OneWay, Source={x:Static spp:Strings.CommunityFix_EnableHttpProxyToHttps}}" />
|
||||
<ui:SettingsExpanderItem.Footer>
|
||||
<ToggleSwitch Classes="LeftContent" IsChecked="{Binding Source={x:Static ms:ProxySettings.EnableHttpProxyToHttps}, Path=Value, Mode=TwoWay}" />
|
||||
</ui:SettingsExpanderItem.Footer>
|
||||
</ui:SettingsExpanderItem>
|
||||
|
||||
<ui:SettingsExpanderItem>
|
||||
<TextBlock Text="{Binding Path=Res.CommunityFix_EnableUseDoh, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
<TextBlock Text="{Binding Path=Res.CommunityFix_EnableUseDoh, Mode=OneWay, Source={x:Static spp:Strings.CommunityFix_EnableUseDoh}}" />
|
||||
<ui:SettingsExpanderItem.Footer>
|
||||
<ToggleSwitch Classes="LeftContent" IsChecked="{Binding Source={x:Static ms:ProxySettings.UseDoh}, Path=Value, Mode=TwoWay}" />
|
||||
</ui:SettingsExpanderItem.Footer>
|
||||
</ui:SettingsExpanderItem>
|
||||
|
||||
<ui:SettingsExpanderItem>
|
||||
<TextBlock Text="{Binding Path=Res.CommunityFix_CustomDohAddres, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
<TextBlock Text="{Binding Path=Res.CommunityFix_CustomDohAddres, Mode=OneWay, Source={x:Static spp:Strings.CommunityFix_CustomDohAddres}}" />
|
||||
<ui:SettingsExpanderItem.Footer>
|
||||
<ui:FAComboBox
|
||||
IsEditable="True"
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
xmlns:s="https://steampp.net/services"
|
||||
xmlns:spp="https://steampp.net/ui"
|
||||
xmlns:ui="using:FluentAvalonia.UI.Controls"
|
||||
Title="{Binding Path=Res.ScriptConfig, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
Title="{Binding Path=Res.ScriptConfig, Mode=OneWay, Source={x:Static spp:Strings.ScriptConfig}}"
|
||||
d:DesignHeight="450"
|
||||
d:DesignWidth="800"
|
||||
x:CompileBindings="True"
|
||||
@@ -37,7 +37,7 @@
|
||||
Margin="28,4,0,4"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding Path=Res.ScriptStore, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
Text="{Binding Path=Res.ScriptStore, Mode=OneWay, Source={x:Static spp:Strings.ScriptStore}}" />
|
||||
</Panel>
|
||||
</Button>
|
||||
<Separator
|
||||
@@ -64,7 +64,7 @@
|
||||
Margin="28,4,0,4"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding Path=Res.Import, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
Text="{Binding Path=Res.Import, Mode=OneWay, Source={x:Static spp:Strings.Import}}" />
|
||||
</Panel>
|
||||
</Button>
|
||||
<Button
|
||||
@@ -83,7 +83,7 @@
|
||||
Margin="28,4,0,4"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding Path=Res.Refresh, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
Text="{Binding Path=Res.Refresh, Mode=OneWay, Source={x:Static spp:Strings.Refresh}}" />
|
||||
</Panel>
|
||||
</Button>
|
||||
<DropDownButton
|
||||
@@ -96,10 +96,10 @@
|
||||
Theme="{StaticResource TransparentButton}">
|
||||
<DropDownButton.Flyout>
|
||||
<ui:FAMenuFlyout Placement="BottomEdgeAlignedRight">
|
||||
<!--<ui:MenuFlyoutItem Text="{Binding Path=Res.Script_Settings, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />-->
|
||||
<!--<ui:MenuFlyoutItem Text="{Binding Path=Res.Script_Settings, Mode=OneWay, Source={x:Static spp:Strings.Script_Settings}}" />-->
|
||||
<!--<ui:MenuFlyoutSeparator />-->
|
||||
<ui:ToggleMenuFlyoutItem IsChecked="{Binding Source={x:Static ms:ProxySettings.IsAutoCheckScriptUpdate}, Path=Value, Mode=TwoWay}" Text="{Binding Path=Res.Script_AutoUpdate, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
<ui:ToggleMenuFlyoutItem IsChecked="{Binding Source={x:Static ms:ProxySettings.IsOnlyWorkSteamBrowser}, Path=Value, Mode=TwoWay}" Text="{Binding Path=Res.CommunityFix_OnlySteamBrowser, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
<ui:ToggleMenuFlyoutItem IsChecked="{Binding Source={x:Static ms:ProxySettings.IsAutoCheckScriptUpdate}, Path=Value, Mode=TwoWay}" Text="{Binding Path=Res.Script_AutoUpdate, Mode=OneWay, Source={x:Static spp:Strings.Script_AutoUpdate}}" />
|
||||
<ui:ToggleMenuFlyoutItem IsChecked="{Binding Source={x:Static ms:ProxySettings.IsOnlyWorkSteamBrowser}, Path=Value, Mode=TwoWay}" Text="{Binding Path=Res.CommunityFix_OnlySteamBrowser, Mode=OneWay, Source={x:Static spp:Strings.CommunityFix_OnlySteamBrowser}}" />
|
||||
<ui:MenuFlyoutSeparator />
|
||||
<ui:MenuFlyoutItem IsEnabled="False">
|
||||
<ui:MenuFlyoutItem.Text>
|
||||
@@ -107,7 +107,7 @@
|
||||
<CompiledBinding
|
||||
Mode="OneWay"
|
||||
Path="Res.Plugin_Version"
|
||||
Source="{x:Static s:ResourceService.Current}" />
|
||||
Source="{x:Static spp:Strings.Plugin_Version}" />
|
||||
<CompiledBinding
|
||||
Mode="OneWay"
|
||||
Path="Version"
|
||||
@@ -115,9 +115,9 @@
|
||||
</MultiBinding>
|
||||
</ui:MenuFlyoutItem.Text>
|
||||
</ui:MenuFlyoutItem>
|
||||
<!--<ui:MenuFlyoutItem Text="{Binding Path=Res.ViewInStore, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
<ui:MenuFlyoutItem Text="{Binding Path=Res.UseHelp, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
<ui:MenuFlyoutItem Text="{Binding Path=Res.AboutThisPlugin, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />-->
|
||||
<!--<ui:MenuFlyoutItem Text="{Binding Path=Res.ViewInStore, Mode=OneWay, Source={x:Static spp:Strings.ViewInStore}}" />
|
||||
<ui:MenuFlyoutItem Text="{Binding Path=Res.UseHelp, Mode=OneWay, Source={x:Static spp:Strings.UseHelp}}" />
|
||||
<ui:MenuFlyoutItem Text="{Binding Path=Res.AboutThisPlugin, Mode=OneWay, Source={x:Static spp:Strings.AboutThisPlugin}}" />-->
|
||||
</ui:FAMenuFlyout>
|
||||
</DropDownButton.Flyout>
|
||||
</DropDownButton>
|
||||
@@ -160,7 +160,7 @@
|
||||
Command="{Binding $parent[spp:PageBase].((spp:ScriptPageViewModel)DataContext).EditScriptItemCommand}"
|
||||
CommandParameter="{Binding}"
|
||||
Theme="{DynamicResource TransparentButton}"
|
||||
ToolTip.Tip="{Binding Path=Res.Script_Edit, Mode=OneWay, Source={x:Static s:ResourceService.Current}}">
|
||||
ToolTip.Tip="{Binding Path=Res.Script_Edit, Mode=OneWay, Source={x:Static spp:Strings.Script_Edit}}">
|
||||
<Viewbox Width="20" Height="20">
|
||||
<ui:SymbolIcon Symbol="CodeHTML" />
|
||||
</Viewbox>
|
||||
@@ -169,7 +169,7 @@
|
||||
Command="{Binding $parent[spp:PageBase].((spp:ScriptPageViewModel)DataContext).RefreshScriptItemCommand}"
|
||||
CommandParameter="{Binding}"
|
||||
Theme="{DynamicResource TransparentButton}"
|
||||
ToolTip.Tip="{Binding Path=Res.Script_Refresh, Mode=OneWay, Source={x:Static s:ResourceService.Current}}">
|
||||
ToolTip.Tip="{Binding Path=Res.Script_Refresh, Mode=OneWay, Source={x:Static spp:Strings.Script_Refresh}}">
|
||||
<Viewbox Width="20" Height="20">
|
||||
<ui:SymbolIcon Symbol="Refresh" />
|
||||
</Viewbox>
|
||||
@@ -183,17 +183,17 @@
|
||||
CommandParameter="{Binding}"
|
||||
Text="{Binding Path=Res.Script_Edit,
|
||||
Mode=OneWay,
|
||||
Source={x:Static s:ResourceService.Current}}" />
|
||||
Source={x:Static spp:Strings.Script_Edit}}" />
|
||||
<ui:MenuFlyoutItem
|
||||
Command="{Binding $parent[spp:PageBase].((spp:ScriptPageViewModel)DataContext).RefreshScriptItemButton}"
|
||||
CommandParameter="{Binding}"
|
||||
Text="{Binding Path=Res.Script_Refresh,
|
||||
Mode=OneWay,
|
||||
Source={x:Static s:ResourceService.Current}}" />-->
|
||||
Source={x:Static spp:Strings.Script_Refresh}}" />-->
|
||||
<ui:MenuFlyoutItem
|
||||
Command="{Binding OpenBrowserCommand, Source={x:Static spp:App.Instance}}"
|
||||
CommandParameter="{Binding SourceLink}"
|
||||
Text="{Binding Path=Res.Script_Home, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
Text="{Binding Path=Res.Script_Home, Mode=OneWay, Source={x:Static spp:Strings.Script_Home}}" />
|
||||
<ui:MenuFlyoutItem
|
||||
Command="{Binding $parent[spp:PageBase].((spp:ScriptPageViewModel)DataContext).DownloadScriptItemCommand}"
|
||||
CommandParameter="{Binding}"
|
||||
@@ -203,7 +203,7 @@
|
||||
<CompiledBinding
|
||||
Mode="OneWay"
|
||||
Path="Res.Script_Update"
|
||||
Source="{x:Static s:ResourceService.Current}" />
|
||||
Source="{x:Static spp:Strings.Script_Update}" />
|
||||
<CompiledBinding Mode="OneWay" Path="NewVersion" />
|
||||
</MultiBinding>
|
||||
</ui:MenuFlyoutItem.Text>
|
||||
@@ -213,7 +213,7 @@
|
||||
Command="{Binding $parent[spp:PageBase].((spp:ScriptPageViewModel)DataContext).DeleteScriptItemCommand}"
|
||||
CommandParameter="{Binding}"
|
||||
Foreground="{DynamicResource SystemFillColorCriticalBrush}"
|
||||
Text="{Binding Path=Res.Delete, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
Text="{Binding Path=Res.Delete, Mode=OneWay, Source={x:Static spp:Strings.Delete}}" />
|
||||
</ui:FAMenuFlyout>
|
||||
</spp:AppItem.MoreFlyout>
|
||||
<spp:AppItem.Image>
|
||||
@@ -230,7 +230,7 @@
|
||||
Classes="Circle"
|
||||
IsIndeterminate="True"
|
||||
IsVisible="{Binding IsLoading}"
|
||||
ToolTip.Tip="{Binding Path=Res.Script_ImportLoading, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
ToolTip.Tip="{Binding Path=Res.Script_ImportLoading, Mode=OneWay, Source={x:Static spp:Strings.Script_ImportLoading}}" />
|
||||
</Panel>
|
||||
</spp:AppItem.Image>
|
||||
</spp:AppItem>
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
<spp:AppItem.Status>
|
||||
<Panel>
|
||||
<Border Classes="Status" IsVisible="{Binding IsExist}">
|
||||
<TextBlock Text="{Binding Path=Res.Installed, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
<TextBlock Text="{Binding Path=Res.Installed, Mode=OneWay, Source={x:Static spp:Strings.Installed}}" />
|
||||
</Border>
|
||||
<Button
|
||||
Classes="accent"
|
||||
@@ -69,7 +69,7 @@
|
||||
<ui:MenuFlyoutItem
|
||||
Command="{Binding OpenBrowserCommand, Source={x:Static spp:App.Instance}}"
|
||||
CommandParameter="{Binding SourceLink}"
|
||||
Text="{Binding Path=Res.Script_Home, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
Text="{Binding Path=Res.Script_Home, Mode=OneWay, Source={x:Static spp:Strings.Script_Home}}" />
|
||||
</ui:FAMenuFlyout>
|
||||
</spp:AppItem.MoreFlyout>
|
||||
<spp:AppItem.Image>
|
||||
@@ -86,4 +86,4 @@
|
||||
</ItemsRepeater>
|
||||
</spp:ContentLoader>
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
</UserControl>
|
||||
|
||||
+15
-3
@@ -72,9 +72,10 @@
|
||||
|
||||
<ItemGroup>
|
||||
<!-- ArchiSteamFarm WebAPI Models -->
|
||||
<Compile Include="..\..\ref\ArchiSteamFarm\ArchiSteamFarm\IPC\Requests\*.cs">
|
||||
<LinkBase>_\ArchiSteamFarm\IPC\Requests</LinkBase>
|
||||
</Compile>
|
||||
<EmbeddedResource Update="Properties\Resources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="_\ArchiSteamFarm\Localization\Strings.resx">
|
||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Strings.Designer.cs</LastGenOutput>
|
||||
@@ -100,6 +101,9 @@
|
||||
<Compile Include="..\..\ref\ArchiSteamFarm\ArchiSteamFarm\Steam\Data\Confirmation.cs">
|
||||
<LinkBase>_\ArchiSteamFarm\Steam\Data</LinkBase>
|
||||
</Compile>
|
||||
<Compile Include="..\..\ref\ArchiSteamFarm\ArchiSteamFarm\Steam\Cards\Game.cs">
|
||||
<LinkBase>_\ArchiSteamFarm\Steam\Cards</LinkBase>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -125,6 +129,14 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Properties\Resources.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="UI\Views\Pages\ArchiSteamFarmPage.axaml.cs">
|
||||
<DependentUpon>ArchiSteamFarmPage.axaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="_\ArchiSteamFarm\Localization\Strings.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace BD.WTTS.Enums;
|
||||
|
||||
public enum ActionItem
|
||||
{
|
||||
StartOrStop = 1,
|
||||
AddBot,
|
||||
Refresh,
|
||||
OpenWebConsole,
|
||||
Wiki,
|
||||
Repo,
|
||||
ConfigGenerator,
|
||||
WebAddBot,
|
||||
WebConfig,
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
namespace BD.WTTS.Enums;
|
||||
|
||||
public enum EPathFolder : byte
|
||||
{
|
||||
/// <inheritdoc cref="SharedInfo.HomeDirectory"/>
|
||||
ASF,
|
||||
|
||||
/// <inheritdoc cref="SharedInfo.ConfigDirectory"/>
|
||||
Config,
|
||||
|
||||
/// <inheritdoc cref="SharedInfo.PluginsDirectory"/>
|
||||
Plugin,
|
||||
|
||||
/// <inheritdoc cref="SharedInfo.WebsiteDirectory"/>
|
||||
WWW,
|
||||
|
||||
/// <inheritdoc cref="SharedInfo.LogFileDirectory"/>
|
||||
Logs,
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
namespace BD.WTTS;
|
||||
|
||||
public static class EPathFolderExtensions
|
||||
{
|
||||
public static string GetFolderPath(this EPathFolder folderASFPath)
|
||||
{
|
||||
string folderASFPathValue = folderASFPath switch
|
||||
{
|
||||
EPathFolder.Config => SharedInfo.DirCreateByNotExists(Path.Combine(SharedInfo.HomeDirectory, SharedInfo.ConfigDirectory)),
|
||||
EPathFolder.Plugin => SharedInfo.DirCreateByNotExists(Path.Combine(SharedInfo.HomeDirectory, SharedInfo.PluginsDirectory)),
|
||||
EPathFolder.WWW => Path.Combine(SharedInfo.HomeDirectory, SharedInfo.WebsiteDirectory),
|
||||
EPathFolder.Logs => Path.Combine(SharedInfo.HomeDirectory, SharedInfo.ArchivalLogsDirectory),
|
||||
EPathFolder.ASF or _ => SharedInfo.HomeDirectory,
|
||||
};
|
||||
return folderASFPathValue;
|
||||
}
|
||||
}
|
||||
+3
-2
@@ -14,9 +14,10 @@ public static partial class ServiceCollectionExtensions
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static IServiceCollection AddArchiSteamFarmService(this IServiceCollection services)
|
||||
{
|
||||
//services.AddSingleton<IArchiSteamFarmService, ArchiSteamFarmServiceImpl>();
|
||||
//services.AddSingleton<IArchiSteamFarmHelperService>(s => s.GetRequiredService<IArchiSteamFarmService>());
|
||||
services.AddSingleton<IArchiSteamFarmWebApiService, ArchiSteamFarmWebApiServiceImpl>();
|
||||
services.AddSingleton<IArchiSteamFarmService, ArchiSteamFarmServiceImpl>();
|
||||
//services.AddSingleton<IArchiSteamFarmHelperService>(s => s.GetRequiredService<IArchiSteamFarmService>());
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
using BD.WTTS.Properties;
|
||||
using BD.WTTS.UI.Views.Pages;
|
||||
using CreateHttpHandlerArgs = System.ValueTuple<
|
||||
bool,
|
||||
System.Net.DecompressionMethods,
|
||||
@@ -18,13 +20,16 @@ public sealed class Plugin : PluginBase<Plugin>, IPlugin
|
||||
|
||||
public override string Name => moduleName;
|
||||
|
||||
public sealed override object? Icon => Resources.asf;
|
||||
|
||||
public override IEnumerable<MenuTabItemViewModel>? GetMenuTabItems()
|
||||
{
|
||||
yield return new MenuTabItemViewModel(this, "ArchiSteamFarmPlus")
|
||||
{
|
||||
PageType = null,
|
||||
PageType = typeof(ArchiSteamFarmPage),
|
||||
IsResourceGet = true,
|
||||
IconKey = "GameConsole",
|
||||
//IconKey = "GameConsole",
|
||||
IconKey = Icon
|
||||
};
|
||||
}
|
||||
|
||||
@@ -97,4 +102,9 @@ public sealed class Plugin : PluginBase<Plugin>, IPlugin
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override IEnumerable<(Action<IServiceCollection>? @delegate, bool isInvalid, string name)>? GetConfiguration(bool directoryExists)
|
||||
{
|
||||
yield return GetConfiguration<ASFSettings_>(directoryExists);
|
||||
}
|
||||
}
|
||||
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// 此代码由工具生成。
|
||||
// 运行时版本:4.0.30319.42000
|
||||
//
|
||||
// 对此文件的更改可能会导致不正确的行为,并且如果
|
||||
// 重新生成代码,这些更改将会丢失。
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace BD.WTTS.Properties {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 一个强类型的资源类,用于查找本地化的字符串等。
|
||||
/// </summary>
|
||||
// 此类是由 StronglyTypedResourceBuilder
|
||||
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
|
||||
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
|
||||
// (以 /str 作为命令选项),或重新生成 VS 项目。
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resources() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 返回此类使用的缓存的 ResourceManager 实例。
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("BD.WTTS.Properties.Resources", typeof(Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重写当前线程的 CurrentUICulture 属性,对
|
||||
/// 使用此强类型资源类的所有资源查找执行重写。
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找 System.Byte[] 类型的本地化资源。
|
||||
/// </summary>
|
||||
internal static byte[] asf {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("asf", resourceCulture);
|
||||
return ((byte[])(obj));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 1.3
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">1.3</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1">this is my long string</data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
[base64 mime encoded serialized .NET Framework object]
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
[base64 mime encoded string representing a byte array form of the .NET Framework object]
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>1.3</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="asf" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\UI\Assets\asf.ico;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
</root>
|
||||
+505
-288
@@ -1,336 +1,553 @@
|
||||
//#if (WINDOWS || MACCATALYST || MACOS || LINUX) && !(IOS || ANDROID)
|
||||
//using ASFStrings = ArchiSteamFarm.Localization.Strings;
|
||||
//using AppResources = BD.WTTS.Client.Resources.Strings;
|
||||
//using ASFNLogManager = ArchiSteamFarm.LogManager;
|
||||
#if (WINDOWS || MACCATALYST || MACOS || LINUX) && !(IOS || ANDROID)
|
||||
using ASFStrings = ArchiSteamFarm.Localization.Strings;
|
||||
using AppResources = BD.WTTS.Client.Resources.Strings;
|
||||
using ArchiSteamFarm.Core;
|
||||
using ArchiSteamFarm.Storage;
|
||||
using ArchiSteamFarm.Steam;
|
||||
using ArchiSteamFarm.Steam.Storage;
|
||||
using ArchiSteamFarm.IPC;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
//// ReSharper disable once CheckNamespace
|
||||
//namespace BD.WTTS.Services.Implementation;
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BD.WTTS.Services.Implementation;
|
||||
|
||||
//public partial class ArchiSteamFarmServiceImpl : ReactiveObject, IArchiSteamFarmService, IIoc
|
||||
//{
|
||||
// const string TAG = "ArchiSteamFarmS";
|
||||
public partial class ArchiSteamFarmServiceImpl : ReactiveObject, IArchiSteamFarmService
|
||||
{
|
||||
const string TAG = "ArchiSteamFarmS";
|
||||
|
||||
// public ArchiSteamFarmServiceImpl()
|
||||
// {
|
||||
// ArchiSteamFarmLibrary.Init(this, IOPath.AppDataDirectory, IApplication.LogDirPathASF);
|
||||
// }
|
||||
private readonly AsyncLock @lock = new AsyncLock();
|
||||
|
||||
// public event Action<string>? OnConsoleWirteLine;
|
||||
private bool isFirstStart = true;
|
||||
|
||||
// public TaskCompletionSource<string>? ReadLineTask { get; set; }
|
||||
private bool _IsReadPasswordLine;
|
||||
|
||||
// private readonly AsyncLock @lock = new AsyncLock();
|
||||
private HttpClient _httpClient = new();
|
||||
|
||||
// bool _IsReadPasswordLine;
|
||||
protected readonly IArchiSteamFarmWebApiService webApiService = IArchiSteamFarmWebApiService.Instance;
|
||||
|
||||
// public bool IsReadPasswordLine
|
||||
// {
|
||||
// get => _IsReadPasswordLine;
|
||||
// set => this.RaiseAndSetIfChanged(ref _IsReadPasswordLine, value);
|
||||
// }
|
||||
public ArchiSteamFarmServiceImpl()
|
||||
{
|
||||
}
|
||||
|
||||
// public DateTimeOffset? StartTime { get; set; }
|
||||
public Process? ASFProcess { get; set; }
|
||||
|
||||
// public Version CurrentVersion => SharedInfo.Version;
|
||||
public event Action<string>? OnConsoleWirteLine;
|
||||
|
||||
// private bool isFirstStart = true;
|
||||
public TaskCompletionSource<string>? ReadLineTask { get; set; }
|
||||
|
||||
// T IIoc.GetRequiredService<T>() where T : class => Ioc.Get<T>();
|
||||
public bool IsReadPasswordLine
|
||||
{
|
||||
get => _IsReadPasswordLine;
|
||||
set => this.RaiseAndSetIfChanged(ref _IsReadPasswordLine, value);
|
||||
}
|
||||
|
||||
// T? IIoc.GetService<T>() where T : class => Ioc.Get_Nullable<T>();
|
||||
public DateTimeOffset? StartTime { get; set; }
|
||||
|
||||
// static void InitCoreLoggers()
|
||||
// {
|
||||
// IApplication.LogDirPathASF = ASFPathHelper.GetLogDirectory(IApplication.LogDirPathASF);
|
||||
// if (ASFNLogManager.Configuration != null) return;
|
||||
// LoggingConfiguration config = new();
|
||||
// FileTarget fileTarget = new("File")
|
||||
// {
|
||||
// ArchiveFileName = ASFPathHelper.GetNLogArchiveFileName(IApplication.LogDirPathASF),
|
||||
// ArchiveNumbering = ArchiveNumberingMode.Rolling,
|
||||
// ArchiveOldFileOnStartup = true,
|
||||
// CleanupFileName = false,
|
||||
// ConcurrentWrites = false,
|
||||
// DeleteOldFileOnStartup = true,
|
||||
// FileName = ASFPathHelper.GetNLogFileName(IApplication.LogDirPathASF),
|
||||
// Layout = ASFPathHelper.NLogGeneralLayout,
|
||||
// ArchiveAboveSize = 10485760,
|
||||
// MaxArchiveFiles = 10,
|
||||
// MaxArchiveDays = 7,
|
||||
// };
|
||||
// //IApplication.InitializeTarget(config, fileTarget, NLogLevel.Debug);
|
||||
// var historyTarget = new HistoryTarget("History")
|
||||
// {
|
||||
// Layout = ASFPathHelper.NLogGeneralLayout,
|
||||
// MaxCount = 20,
|
||||
// };
|
||||
// //IApplication.InitializeTarget(config, historyTarget, NLogLevel.Debug);
|
||||
// ASFNLogManager.Configuration = config;
|
||||
// }
|
||||
public Version CurrentVersion => SharedInfo.Version;
|
||||
|
||||
// public async Task<bool> StartAsync(string[]? args = null)
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// StartTime = DateTimeOffset.Now;
|
||||
public void ShellMessageInput(string data)
|
||||
{
|
||||
using (var sw = ASFProcess.StandardInput)
|
||||
{
|
||||
sw.WriteLine(data);
|
||||
sw.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
// if (isFirstStart)
|
||||
// {
|
||||
// InitCoreLoggers();
|
||||
public async Task<bool> StartAsync(string[]? args = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var isOk = false;
|
||||
StartTime = DateTimeOffset.Now;
|
||||
if (isFirstStart)
|
||||
{
|
||||
await ReadEncryptionKeyAsync();
|
||||
isFirstStart = false;
|
||||
}
|
||||
|
||||
// InitHistoryLogger();
|
||||
if (!await StartProcess() && !isFirstStart)
|
||||
{
|
||||
await StopAsync().ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
isOk = true;
|
||||
ASF.IsReady = true;
|
||||
}
|
||||
return isOk;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.LogAndShowT(TAG, msg: "ASF Start Fail.");
|
||||
await StopAsync().ConfigureAwait(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// ArchiSteamFarm.NLog.Logging.GetUserInputFunc = async (bool isPassword) =>
|
||||
// {
|
||||
// using (await @lock.LockAsync())
|
||||
// {
|
||||
// ReadLineTask = new(TaskCreationOptions.AttachedToParent);
|
||||
// IsReadPasswordLine = isPassword;
|
||||
//#if NET6_0_OR_GREATER
|
||||
// var result = await ReadLineTask.Task.WaitAsync(TimeSpan.FromSeconds(60));
|
||||
//#else
|
||||
// var result = await ReadLineTask.Task;
|
||||
//#endif
|
||||
// if (IsReadPasswordLine)
|
||||
// IsReadPasswordLine = false;
|
||||
// ReadLineTask = null;
|
||||
// return result;
|
||||
// }
|
||||
// };
|
||||
#region StartProcess
|
||||
|
||||
// await ReadEncryptionKeyAsync();
|
||||
private async Task<bool> StartProcess()
|
||||
{
|
||||
var isStartSuccess = false;
|
||||
try
|
||||
{
|
||||
if (ASFProcess != null || string.IsNullOrEmpty(SharedInfo.ASFExecuteFilePath))
|
||||
{
|
||||
Toast.Show(ToastIcon.Error, BDStrings.ASF_SelectASFExePath);
|
||||
return isStartSuccess;
|
||||
}
|
||||
|
||||
// await Program.Init(args).ConfigureAwait(false);
|
||||
// isFirstStart = false;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// if (!await Program.InitASF().ConfigureAwait(false))
|
||||
// {
|
||||
// await StopAsync().ConfigureAwait(false);
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
// return true;
|
||||
// }
|
||||
// catch (Exception e)
|
||||
// {
|
||||
// e.LogAndShowT(TAG, msg: "ASF Start Fail.");
|
||||
// await StopAsync().ConfigureAwait(false);
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
if (ASFSettings.CheckArchiSteamFarmExe && !await CheckFileConsistence()) // 检查文件是否被篡改
|
||||
{
|
||||
Toast.Show(ToastIcon.Error, BDStrings.ASF_ExecuteFileUnsafe);
|
||||
return isStartSuccess;
|
||||
}
|
||||
|
||||
// public async Task StopAsync()
|
||||
// {
|
||||
// StartTime = null;
|
||||
// ReadLineTask?.TrySetResult("");
|
||||
// await Program.InitShutdownSequence();
|
||||
// }
|
||||
webApiService.SetIPCUrl(GetIPCUrl()); // 设置 IPC 接口地址
|
||||
|
||||
// async Task IArchiSteamFarmHelperService.Restart()
|
||||
// {
|
||||
// Toast.Show(AppResources.ASF_Restarting, ToastLength.Short);
|
||||
KillASFProcess(); // 杀死未关闭的 ASF 进程
|
||||
|
||||
// var s = ASFService.Current;
|
||||
// if (s.IsASFRuning)
|
||||
// {
|
||||
// await s.StopASFCoreAsync(false);
|
||||
// }
|
||||
// await s.InitASFCoreAsync(false);
|
||||
var options = new ProcessStartInfo(SharedInfo.ASFExecuteFilePath);
|
||||
options.CreateNoWindow = true;
|
||||
options.UseShellExecute = false;
|
||||
options.RedirectStandardOutput = true;
|
||||
options.RedirectStandardInput = true;
|
||||
options.RedirectStandardError = true;
|
||||
if (!string.IsNullOrEmpty(EncryptionKey))
|
||||
{
|
||||
options.ArgumentList.Add("--CRYPTKEY");
|
||||
options.ArgumentList.Add(EncryptionKey);
|
||||
}
|
||||
ASFProcess = Process.Start(options);
|
||||
|
||||
// Toast.Show(AppResources.ASF_Restarted, ToastLength.Short);
|
||||
// }
|
||||
ASFService.Current.ConsoleLogText = string.Empty;
|
||||
ThreadPool.QueueUserWorkItem(ReadOutPutData);
|
||||
AppDomain.CurrentDomain.ProcessExit += ExitHandler;
|
||||
AppDomain.CurrentDomain.UnhandledException += ExitHandler;
|
||||
|
||||
// LogLevel IArchiSteamFarmHelperService.MinimumLevel => IApplication.LoggerMinLevel;
|
||||
ASFProcess!.ErrorDataReceived += new DataReceivedEventHandler(ExitHandler);
|
||||
ASFProcess.BeginErrorReadLine();
|
||||
while (!SocketHelper.IsUsePort(CurrentIPCPortValue))
|
||||
{
|
||||
Thread.Sleep(1000);
|
||||
continue;
|
||||
}
|
||||
isStartSuccess = true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
return isStartSuccess;
|
||||
}
|
||||
|
||||
// private void InitHistoryLogger()
|
||||
// {
|
||||
// ArchiSteamFarm.NLog.Logging.InitHistoryLogger();
|
||||
private void KillASFProcess()
|
||||
{
|
||||
var processName = Path.GetFileNameWithoutExtension(SharedInfo.ASFExecuteFilePath);
|
||||
var process_list = Process.GetProcessesByName(processName);
|
||||
if (process_list.Any())
|
||||
process_list.ForEach(x =>
|
||||
{
|
||||
if (Path.GetFullPath(x.MainModule?.FileName ?? string.Empty) == Path.GetFullPath(SharedInfo.ASFExecuteFilePath))
|
||||
{
|
||||
x.Kill(); x.Dispose();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// HistoryTarget? historyTarget = ArchiSteamFarm.LogManager.Configuration.AllTargets.OfType<HistoryTarget>().FirstOrDefault();
|
||||
private async Task<bool> CheckFileConsistence()
|
||||
{
|
||||
var isConsistence = false;
|
||||
if (File.Exists(SharedInfo.ASFExecuteFilePath))
|
||||
{
|
||||
try
|
||||
{
|
||||
var versionInfo = FileVersionInfo.GetVersionInfo(SharedInfo.ASFExecuteFilePath);
|
||||
|
||||
// if (historyTarget != null)
|
||||
// historyTarget.NewHistoryEntry += (object? sender, HistoryTarget.NewHistoryEntryArgs newHistoryEntryArgs) =>
|
||||
// {
|
||||
// OnConsoleWirteLine?.Invoke(newHistoryEntryArgs.Message);
|
||||
// };
|
||||
// }
|
||||
var fileName = "ASF-win-x64.zip";
|
||||
var downloadUrl = $"https://github.com/JustArchiNET/ArchiSteamFarm/releases/download/{versionInfo.FileVersion}/{fileName}";
|
||||
var savePath = Path.Combine(Plugin.Instance.AppDataDirectory, $"ASF-{versionInfo.FileVersion}", fileName);
|
||||
var destDir = Path.GetDirectoryName(savePath)!;
|
||||
|
||||
// public async Task<string?> ExecuteCommandAsync(string command)
|
||||
// {
|
||||
// Bot? targetBot = Bot.Bots?.OrderBy(bot => bot.Key, Bot.BotsComparer).Select(bot => bot.Value).FirstOrDefault();
|
||||
var online_asfPath = Path.Combine(destDir, Path.GetFileName(SharedInfo.ASFExecuteFilePath));
|
||||
|
||||
// ASF.ArchiLogger.LogGenericInfo(command);
|
||||
if (!File.Exists(online_asfPath))
|
||||
{
|
||||
Directory.CreateDirectory(destDir);
|
||||
if (await DownloadASFRelease(downloadUrl, savePath))
|
||||
ZipFile.ExtractToDirectory(savePath, destDir);
|
||||
}
|
||||
if (File.Exists(online_asfPath) && CalculateFileHash(SharedInfo.ASFExecuteFilePath) == CalculateFileHash(online_asfPath))
|
||||
isConsistence = true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
|
||||
// if (targetBot == null)
|
||||
// {
|
||||
// ASF.ArchiLogger.LogGenericWarning(ASFStrings.ErrorNoBotsDefined);
|
||||
// return null;
|
||||
// }
|
||||
}
|
||||
return isConsistence;
|
||||
|
||||
// ASF.ArchiLogger.LogGenericInfo(ASFStrings.Executing);
|
||||
string CalculateFileHash(string filePath)
|
||||
{
|
||||
using (var hasher = SHA256.Create())
|
||||
using (var stream = new BufferedStream(File.OpenRead(filePath), 1200000))
|
||||
{
|
||||
byte[] hashBytes = hasher.ComputeHash(stream);
|
||||
return BitConverter.ToString(hashBytes).Replace("-", "");
|
||||
}
|
||||
}
|
||||
|
||||
// ulong steamOwnerID = ASF.GlobalConfig?.SteamOwnerID ?? GlobalConfig.DefaultSteamOwnerID;
|
||||
async Task<bool> DownloadASFRelease(string downloadUrl, string savePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
HttpResponseMessage response = await _httpClient.GetAsync(downloadUrl);
|
||||
|
||||
// var access = targetBot.GetAccess(steamOwnerID);
|
||||
// string? response = await targetBot.Commands.Response(access, command, steamOwnerID);
|
||||
// Ensure a successful response before proceeding
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
// if (!string.IsNullOrEmpty(response))
|
||||
// ASF.ArchiLogger.LogGenericInfo(response);
|
||||
// return response;
|
||||
// }
|
||||
using (var fileStream = new FileStream(savePath, FileMode.Create, FileAccess.Write, FileShare.None))
|
||||
{
|
||||
await response.Content.CopyToAsync(fileStream);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// public IReadOnlyDictionary<string, Bot>? GetReadOnlyAllBots()
|
||||
// {
|
||||
// var bots = Bot.Bots;
|
||||
// //if (bots is not null)
|
||||
// // foreach (var bot in bots.Values)
|
||||
// // {
|
||||
// // bot.AvatarUrl = GetAvatarUrl(bot);
|
||||
// // }
|
||||
// return bots;
|
||||
// }
|
||||
private void ExitHandler(object? sender, EventArgs eventArgs)
|
||||
{
|
||||
ASFService.Current.StopASFAsync().GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
// public async void SaveBot(Bot bot)
|
||||
// {
|
||||
// //var bot = Bot.GetBot(botName);
|
||||
// string filePath = Bot.GetFilePath(bot.BotName, Bot.EFileType.Config);
|
||||
// bool result = await BotConfig.Write(filePath, bot.BotConfig).ConfigureAwait(false);
|
||||
// }
|
||||
private async void ReadOutPutData(object? obj)
|
||||
{
|
||||
using (StreamReader sr = ASFProcess.StandardOutput)
|
||||
{
|
||||
int readResult;
|
||||
char ch;
|
||||
StringBuilder sb = new();
|
||||
var len = string.Empty;
|
||||
|
||||
// public GlobalConfig? GetGlobalConfig()
|
||||
// {
|
||||
// return ASF.GlobalConfig;
|
||||
// }
|
||||
while (true)
|
||||
{
|
||||
var readAsync = Task.Run(sr.Read);
|
||||
|
||||
// public async void SaveGlobalConfig(GlobalConfig config)
|
||||
// {
|
||||
// string filePath = ASF.GetFilePath(ASF.EFileType.Config);
|
||||
// bool result = await GlobalConfig.Write(filePath, config).ConfigureAwait(false);
|
||||
// if (result)
|
||||
// {
|
||||
// Toast.Show("SaveGlobalConfig " + result);
|
||||
// }
|
||||
// }
|
||||
await Task.WhenAny(readAsync, Task.Delay(TimeSpan.FromSeconds(3)));
|
||||
|
||||
// string IPCRootUrl
|
||||
// {
|
||||
// get
|
||||
// {
|
||||
// string? value = null;
|
||||
// var a = ArchiSteamFarm.IPC.ArchiKestrel.ServerAddresses;
|
||||
// var loopback = IPAddress.Loopback.ToString();
|
||||
// if (a != null)
|
||||
// {
|
||||
// value = a.FirstOrDefault(x => x.Contains(loopback) && x.StartsWith(String2.Prefix_HTTP))
|
||||
// ?? a.FirstOrDefault(x => x.Contains(loopback))
|
||||
// ?? a.FirstOrDefault();
|
||||
// }
|
||||
// if (string.IsNullOrWhiteSpace(value))
|
||||
// {
|
||||
// value = $"http://{loopback}:{CurrentIPCPortValue}";
|
||||
// }
|
||||
// return value;
|
||||
// }
|
||||
// }
|
||||
if (!readAsync.IsCompleted)
|
||||
{
|
||||
if (sb.Length > 0)
|
||||
{
|
||||
len = sb.ToString();
|
||||
OnConsoleWirteLine?.Invoke(len);
|
||||
sb.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
// public string GetIPCUrl()
|
||||
// {
|
||||
// var defaultUrl = IPCRootUrl;
|
||||
// string absoluteConfigDirectory = Path.Combine(ASFPathHelper.AppDataDirectory, SharedInfo.ConfigDirectory);
|
||||
// string customConfigPath = Path.Combine(absoluteConfigDirectory, SharedInfo.IPCConfigFile);
|
||||
// if (File.Exists(customConfigPath))
|
||||
// {
|
||||
// var configRoot = new ConfigurationBuilder().SetBasePath(absoluteConfigDirectory).AddJsonFile(SharedInfo.IPCConfigFile, false, true).Build();
|
||||
// var urlSection = configRoot.GetSection("Url").Value;
|
||||
// try
|
||||
// {
|
||||
// var url = new Uri(urlSection!);
|
||||
// if (IPAddress.Any.ToString() == url.Host)
|
||||
// {
|
||||
// return defaultUrl;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// return url.AbsolutePath;
|
||||
// }
|
||||
// }
|
||||
// catch
|
||||
// {
|
||||
// return defaultUrl;
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// return defaultUrl;
|
||||
// }
|
||||
// }
|
||||
if ((readResult = await readAsync) != -1)
|
||||
{
|
||||
ch = (char)readResult;
|
||||
sb.Append(ch);
|
||||
|
||||
// public int CurrentIPCPortValue { get; set; }
|
||||
// Note the following common line feed chars:
|
||||
// \n - UNIX \r\n - DOS \r - Mac
|
||||
if (ch == '\r' || ch == '\n')
|
||||
{
|
||||
readResult = sr.Read();
|
||||
if (readResult != -1)
|
||||
{
|
||||
ch = (char)readResult;
|
||||
if (ch == '\n')
|
||||
{
|
||||
sb.Append(ch);
|
||||
len = sb.ToString();
|
||||
OnConsoleWirteLine?.Invoke(len);
|
||||
sb.Clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
len = sb.ToString();
|
||||
OnConsoleWirteLine?.Invoke(len);
|
||||
sb.Clear();
|
||||
sb.Append(ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
// //public static IEnumerable<HttpMessageHandler> GetAllHandlers()
|
||||
// //{
|
||||
// // // 动态更改运行中的代理设置,遍历 ASF 中的 HttpClientHandler 设置新的 Proxy
|
||||
// // var asf_handler = ASF.WebBrowser?.HttpClientHandler;
|
||||
// // if (asf_handler != null) yield return asf_handler;
|
||||
// // var bots = Bot.BotsReadOnly?.Values;
|
||||
// // if (bots != null)
|
||||
// // {
|
||||
// // foreach (var bot in bots)
|
||||
// // {
|
||||
// // var bot_handler = bot.ArchiWebHandler.WebBrowser.HttpClientHandler;
|
||||
// // if (bot_handler != null) yield return bot_handler;
|
||||
// // }
|
||||
// // }
|
||||
// //}
|
||||
public async Task StopAsync()
|
||||
{
|
||||
StartTime = null;
|
||||
ASF.IsReady &= false;
|
||||
ReadLineTask?.TrySetResult("");
|
||||
if (ASFProcess != null)
|
||||
{
|
||||
await Task.WhenAny(webApiService.ASF.Exit(), Task.Delay(TimeSpan.FromSeconds(3)));
|
||||
ASFProcess.Kill();
|
||||
ASFProcess.Dispose();
|
||||
ASFProcess = null;
|
||||
}
|
||||
}
|
||||
|
||||
// string EncryptionKey
|
||||
// {
|
||||
// set => ArchiCryptoHelper.SetEncryptionKey(value);
|
||||
// }
|
||||
public async Task Restart()
|
||||
{
|
||||
Toast.Show(ToastIcon.Info, AppResources.ASF_Restarting, ToastLength.Short);
|
||||
|
||||
// const string ASF_CRYPTKEY = "ASF_CRYPTKEY";
|
||||
// const string ASF_CRYPTKEY_DEF_VALUE = nameof(ArchiSteamFarm);
|
||||
var s = ASFService.Current;
|
||||
if (s.IsASFRuning)
|
||||
{
|
||||
await s.StopASFCoreAsync(false);
|
||||
}
|
||||
await s.InitASFCoreAsync(false);
|
||||
|
||||
// public async Task SetEncryptionKeyAsync()
|
||||
// {
|
||||
// var result = await TextBoxWindowViewModel.ShowDialogAsync(new TextBoxWindowViewModel
|
||||
// {
|
||||
// Title = AppResources.ASF_SetCryptKey,
|
||||
// Placeholder = ASF_CRYPTKEY,
|
||||
// InputType = TextBoxWindowViewModel.TextBoxInputType.Password,
|
||||
// });
|
||||
// var isUseDefaultCryptKey = string.IsNullOrEmpty(result) || result == ASF_CRYPTKEY_DEF_VALUE;
|
||||
// if (!isUseDefaultCryptKey)
|
||||
// {
|
||||
// await ISecureStorage.Instance.SetAsync(ASF_CRYPTKEY, result);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// await ISecureStorage.Instance.RemoveAsync(ASF_CRYPTKEY);
|
||||
// result = ASF_CRYPTKEY_DEF_VALUE;
|
||||
// }
|
||||
// ArchiCryptoHelper.SetEncryptionKey(result!);
|
||||
// }
|
||||
Toast.Show(ToastIcon.Success, AppResources.ASF_Restarted, ToastLength.Short);
|
||||
}
|
||||
|
||||
// /// <summary>
|
||||
// /// 尝试读取已保存的自定义密钥并应用
|
||||
// /// </summary>
|
||||
// /// <returns></returns>
|
||||
// static async Task ReadEncryptionKeyAsync()
|
||||
// {
|
||||
// if (!ArchiCryptoHelper.HasDefaultCryptKey)
|
||||
// {
|
||||
// // 当前运行中已设置了自定义密钥,则跳过
|
||||
// return;
|
||||
// }
|
||||
// var result = await ISecureStorage.Instance.GetAsync(ASF_CRYPTKEY);
|
||||
// if (!string.IsNullOrEmpty(result))
|
||||
// {
|
||||
// ArchiCryptoHelper.SetEncryptionKey(result);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
LogLevel MinimumLevel => IApplication.LoggerMinLevel;
|
||||
|
||||
//#endif
|
||||
public async Task<string?> ExecuteCommandAsync(string command)
|
||||
{
|
||||
(var isSuccess, _) = VerifyApiReady<GenericResponse>();
|
||||
if (!isSuccess) return string.Empty;
|
||||
|
||||
var request = new CommandRequest(command);
|
||||
var r = await webApiService.Command.CommandPost(request);
|
||||
return r.IsSuccess ? r.Content : null;
|
||||
}
|
||||
|
||||
public async Task<IReadOnlyDictionary<string, Bot>?> GetReadOnlyAllBots()
|
||||
{
|
||||
(var isSuccess, var rsp) = VerifyApiReady<IReadOnlyDictionary<string, Bot>?>();
|
||||
if (!isSuccess) return rsp.Content;
|
||||
|
||||
var r = await webApiService.Bot.BotGet("asf");
|
||||
var bots = r.Content;
|
||||
//if (bots is not null)
|
||||
// foreach (var bot in bots.Values)
|
||||
// {
|
||||
// bot.AvatarUrl = GetAvatarUrl(bot);
|
||||
// }
|
||||
return bots;
|
||||
}
|
||||
|
||||
public async Task<bool> SaveBot(string botName, BotConfig botConfig)
|
||||
{
|
||||
(var isSuccess, _) = VerifyApiReady<GenericResponse>();
|
||||
if (!isSuccess) return isSuccess;
|
||||
|
||||
var request = new BotRequest() { BotConfig = botConfig };
|
||||
var r = await webApiService.Bot.BotPost(botName, request);
|
||||
return r.IsSuccess;
|
||||
}
|
||||
|
||||
public async Task<GlobalConfig?> GetGlobalConfig()
|
||||
{
|
||||
(var isSuccess, _) = VerifyApiReady<GenericResponse>();
|
||||
if (!isSuccess) return null;
|
||||
|
||||
var r = await webApiService.ASF.Get();
|
||||
return r.IsSuccess ? r.Content.GlobalConfig : null;
|
||||
}
|
||||
|
||||
public async Task<bool> SaveGlobalConfig(GlobalConfig config)
|
||||
{
|
||||
(var isSuccess, _) = VerifyApiReady<GenericResponse>();
|
||||
if (!isSuccess) return isSuccess;
|
||||
|
||||
var request = new ASFRequest() { GlobalConfig = config };
|
||||
var r = await webApiService.ASF.Post(request);
|
||||
if (r.IsSuccess)
|
||||
Toast.Show(ToastIcon.Info, "SaveGlobalConfig " + r.IsSuccess);
|
||||
return r.IsSuccess;
|
||||
}
|
||||
|
||||
string IPCRootUrl { get => $"http://{IPAddress.Loopback}:{CurrentIPCPortValue}"; }
|
||||
|
||||
public string GetIPCUrl()
|
||||
{
|
||||
var ipcUrl = new Uri(IPCRootUrl);
|
||||
string absoluteConfigDirectory = Path.Combine(SharedInfo.HomeDirectory, SharedInfo.ConfigDirectory);
|
||||
string customConfigPath = Path.Combine(absoluteConfigDirectory, SharedInfo.IPCConfigFile);
|
||||
if (File.Exists(customConfigPath))
|
||||
{
|
||||
var jsonObj = JObject.Parse(File.ReadAllText(customConfigPath));
|
||||
var urlSection = jsonObj.SelectToken("Kestrel.Endpoints.Http.Url")?.Value<string>();
|
||||
try
|
||||
{
|
||||
var url = new Uri(urlSection!);
|
||||
if (url.AbsoluteUri != ipcUrl.AbsoluteUri)
|
||||
{
|
||||
jsonObj["Kestrel"]!["Endpoints"]!["Http"]!["Url"] = ipcUrl.OriginalString;
|
||||
File.WriteAllText(customConfigPath, jsonObj.ToString());
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var iPCConfig = new IPCConfig(ipcUrl);
|
||||
File.WriteAllText(customConfigPath, System.Text.Json.JsonSerializer.Serialize(iPCConfig));
|
||||
}
|
||||
CurrentIPCPortValue = ipcUrl.Port;
|
||||
return ipcUrl.OriginalString;
|
||||
}
|
||||
|
||||
private int _currentIpcPortValue;
|
||||
|
||||
public int CurrentIPCPortValue
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_currentIpcPortValue == default)
|
||||
{
|
||||
_currentIpcPortValue = ASFSettings.IPCPortId.Value;
|
||||
|
||||
if (ASFSettings.IPCPortOccupiedRandom.Value)
|
||||
{
|
||||
if (SocketHelper.IsUsePort(_currentIpcPortValue))
|
||||
{
|
||||
_currentIpcPortValue = SocketHelper.GetRandomUnusedPort(IPAddress.Loopback);
|
||||
return _currentIpcPortValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
return _currentIpcPortValue;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
_currentIpcPortValue = value;
|
||||
}
|
||||
}
|
||||
|
||||
const string ASF_CRYPTKEY = "ASF_CRYPTKEY";
|
||||
const string ASF_CRYPTKEY_DEF_VALUE = nameof(ArchiSteamFarm);
|
||||
|
||||
public string? EncryptionKey { get; set; }
|
||||
|
||||
public async Task SetEncryptionKeyAsync()
|
||||
{
|
||||
var result = await TextBoxWindowViewModel.ShowDialogAsync(new TextBoxWindowViewModel
|
||||
{
|
||||
Title = AppResources.ASF_SetCryptKey,
|
||||
Placeholder = ASF_CRYPTKEY,
|
||||
InputType = TextBoxWindowViewModel.TextBoxInputType.Password,
|
||||
});
|
||||
var isUseDefaultCryptKey = string.IsNullOrEmpty(result) || result == ASF_CRYPTKEY_DEF_VALUE;
|
||||
if (!isUseDefaultCryptKey)
|
||||
{
|
||||
await ISecureStorage.Instance.SetAsync(ASF_CRYPTKEY, result);
|
||||
}
|
||||
else
|
||||
{
|
||||
await ISecureStorage.Instance.RemoveAsync(ASF_CRYPTKEY);
|
||||
result = ASF_CRYPTKEY_DEF_VALUE;
|
||||
}
|
||||
EncryptionKey = result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 尝试读取已保存的自定义密钥并应用
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private async Task ReadEncryptionKeyAsync()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(EncryptionKey))
|
||||
{
|
||||
// 当前运行中已设置了自定义密钥,则跳过
|
||||
return;
|
||||
}
|
||||
var result = await ISecureStorage.Instance.GetAsync(ASF_CRYPTKEY);
|
||||
if (!string.IsNullOrEmpty(result))
|
||||
EncryptionKey = result;
|
||||
}
|
||||
|
||||
public async Task<IApiRsp> BotResumeAsync(string botNames, CancellationToken cancellationToken = default)
|
||||
{
|
||||
(var isSuccess, var rsp) = VerifyApiReady<GenericResponse>();
|
||||
if (!isSuccess) return rsp;
|
||||
return await webApiService.Bot.ResumePost(botNames, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<IApiRsp> BotPauseAsync(string botNames, BotPauseRequest request, CancellationToken cancellationToken = default)
|
||||
{
|
||||
(var isSuccess, var rsp) = VerifyApiReady<GenericResponse>();
|
||||
if (!isSuccess) return rsp;
|
||||
return await webApiService.Bot.PausePost(botNames, request, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<IApiRsp> BotStopAsync(string botNames, CancellationToken cancellationToken = default)
|
||||
{
|
||||
(var isSuccess, var rsp) = VerifyApiReady<GenericResponse>();
|
||||
if (!isSuccess) return rsp;
|
||||
return await webApiService.Bot.StopPost(botNames, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<IApiRsp> BotStartAsync(string botNames, CancellationToken cancellationToken = default)
|
||||
{
|
||||
(var isSuccess, var rsp) = VerifyApiReady<GenericResponse>();
|
||||
if (!isSuccess) return rsp;
|
||||
return await webApiService.Bot.StartPost(botNames, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<IApiRsp<IReadOnlyDictionary<string, GamesToRedeemInBackgroundResponse>>> BotGetUsedAndUnusedKeysAsync(string botNames, CancellationToken cancellationToken = default)
|
||||
{
|
||||
(var isSuccess, var rsp) = VerifyApiReady<IReadOnlyDictionary<string, GamesToRedeemInBackgroundResponse>>();
|
||||
if (!isSuccess) return rsp;
|
||||
return await webApiService.Bot.GamesToRedeemInBackgroundGet(botNames, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<IApiRsp> BotRedeemKeyAsync(string botNames, BotGamesToRedeemInBackgroundRequest request, CancellationToken cancellationToken = default)
|
||||
{
|
||||
(var isSuccess, var rsp) = VerifyApiReady<GenericResponse>();
|
||||
if (!isSuccess) return rsp;
|
||||
return await webApiService.Bot.GamesToRedeemInBackgroundPost(botNames, request, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<IApiRsp> BotResetRedeemedKeysRecordAsync(string botNames, CancellationToken cancellationToken = default)
|
||||
{
|
||||
(var isSuccess, var rsp) = VerifyApiReady<GenericResponse>();
|
||||
if (!isSuccess) return rsp;
|
||||
return await webApiService.Bot.GamesToRedeemInBackgroundDelete(botNames, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<IApiRsp> BotDeleteAsync(string botNames, CancellationToken cancellationToken = default)
|
||||
{
|
||||
(var isSuccess, var rsp) = VerifyApiReady<GenericResponse>();
|
||||
if (!isSuccess) return rsp;
|
||||
return await webApiService.Bot.BotDelete(botNames, cancellationToken);
|
||||
}
|
||||
|
||||
private (bool isSuccess, IApiRsp<TResponseBody?>? apiRsp) VerifyApiReady<TResponseBody>()
|
||||
{
|
||||
string? ipc_error = null;
|
||||
if (!ASFService.Current.IsASFRuning)
|
||||
{
|
||||
ipc_error = BDStrings.ASF_RequirRunASF;
|
||||
}
|
||||
else if (!ASF.IsReady)
|
||||
{
|
||||
// IPC 未启动前无法获取正确的端口号,会导致拼接的 URL 值不正确
|
||||
ipc_error = BDStrings.ASF_IPCIsReadyFalse;
|
||||
}
|
||||
if (ipc_error != null)
|
||||
{
|
||||
Toast.Show(ToastIcon.Error, ipc_error);
|
||||
return (false, ApiRspHelper.Fail<TResponseBody>(ipc_error));
|
||||
}
|
||||
return (true, null);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
+179
-5
@@ -1,3 +1,4 @@
|
||||
using ArchiSteamFarm.Steam;
|
||||
using static BD.WTTS.Services.IArchiSteamFarmWebApiService;
|
||||
|
||||
namespace BD.WTTS.Services.Implementation;
|
||||
@@ -32,11 +33,11 @@ partial class ArchiSteamFarmWebApiServiceImpl // ApiControllers
|
||||
return result!;
|
||||
}
|
||||
|
||||
public async Task<IApiRsp> Hash(
|
||||
public async Task<IApiRsp<string>> Hash(
|
||||
ASFHashRequest request,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var result = await SendAsync<ASFHashRequest, Void>(
|
||||
var result = await SendAsync<ASFHashRequest, string>(
|
||||
"Api/ASF/Hash",
|
||||
HttpMethod.Post,
|
||||
reqBody: request,
|
||||
@@ -79,13 +80,12 @@ partial class ArchiSteamFarmWebApiServiceImpl // ApiControllers
|
||||
}
|
||||
|
||||
public async Task<IApiRsp<string?>> Update(
|
||||
UpdateRequest request,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var result = await SendAsync<UpdateRequest, string>(
|
||||
var result = await SendAsync<Void, string>(
|
||||
"Api/ASF/Update",
|
||||
HttpMethod.Post,
|
||||
reqBody: request,
|
||||
reqBody: default,
|
||||
cancellationToken: cancellationToken);
|
||||
return result!;
|
||||
}
|
||||
@@ -96,11 +96,185 @@ partial class ArchiSteamFarmWebApiServiceImpl // ApiControllers
|
||||
|
||||
#region BotController
|
||||
|
||||
public async Task<IApiRsp> BotDelete(
|
||||
string botNames,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var result = await SendAsync<Void, Void>(
|
||||
$"Api/Bot/{botNames}",
|
||||
HttpMethod.Delete,
|
||||
reqBody: default,
|
||||
cancellationToken: cancellationToken);
|
||||
return result!;
|
||||
}
|
||||
|
||||
public async Task<IApiRsp<IReadOnlyDictionary<string, Bot>>> BotGet(
|
||||
string botNames,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var result = await SendAsync<Void, IReadOnlyDictionary<string, Bot>>(
|
||||
$"Api/Bot/{botNames}",
|
||||
HttpMethod.Get,
|
||||
reqBody: default,
|
||||
cancellationToken: cancellationToken);
|
||||
return result!;
|
||||
}
|
||||
|
||||
public async Task<IApiRsp> BotPost(
|
||||
string botNames,
|
||||
BotRequest request,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var result = await SendAsync<BotRequest, Void>(
|
||||
$"Api/Bot/{botNames}",
|
||||
HttpMethod.Post,
|
||||
reqBody: request,
|
||||
cancellationToken: cancellationToken);
|
||||
return result!;
|
||||
}
|
||||
|
||||
public async Task<IApiRsp> GamesToRedeemInBackgroundDelete(
|
||||
string botNames,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var result = await SendAsync<Void, Void>(
|
||||
$"Api/Bot/{botNames}/GamesToRedeemInBackground",
|
||||
HttpMethod.Delete,
|
||||
reqBody: default,
|
||||
cancellationToken: cancellationToken);
|
||||
return result!;
|
||||
}
|
||||
|
||||
public async Task<IApiRsp<IReadOnlyDictionary<string, GamesToRedeemInBackgroundResponse>>> GamesToRedeemInBackgroundGet(
|
||||
string botNames,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var result = await SendAsync<Void, IReadOnlyDictionary<string, GamesToRedeemInBackgroundResponse>>(
|
||||
$"Api/Bot/{botNames}/GamesToRedeemInBackground",
|
||||
HttpMethod.Get,
|
||||
reqBody: default,
|
||||
cancellationToken: cancellationToken);
|
||||
return result!;
|
||||
}
|
||||
|
||||
public async Task<IApiRsp> GamesToRedeemInBackgroundPost(
|
||||
string botNames,
|
||||
BotGamesToRedeemInBackgroundRequest request,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var result = await SendAsync<BotGamesToRedeemInBackgroundRequest, Void>(
|
||||
$"Api/Bot/{botNames}/GamesToRedeemInBackground",
|
||||
HttpMethod.Post,
|
||||
reqBody: request,
|
||||
cancellationToken: cancellationToken);
|
||||
return result!;
|
||||
}
|
||||
|
||||
public async Task<IApiRsp> InputPost(
|
||||
string botNames,
|
||||
BotInputRequest request,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var result = await SendAsync<BotInputRequest, Void>(
|
||||
$"Api/Bot/{botNames}/Input",
|
||||
HttpMethod.Post,
|
||||
reqBody: request,
|
||||
cancellationToken: cancellationToken);
|
||||
return result!;
|
||||
}
|
||||
|
||||
public async Task<IApiRsp> PausePost(
|
||||
string botNames,
|
||||
BotPauseRequest request,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var result = await SendAsync<BotPauseRequest, Void>(
|
||||
$"Api/Bot/{botNames}/Pause",
|
||||
HttpMethod.Post,
|
||||
reqBody: request,
|
||||
cancellationToken: cancellationToken);
|
||||
return result!;
|
||||
}
|
||||
|
||||
public async Task<IApiRsp> RedeemPost(
|
||||
string botNames,
|
||||
BotRedeemRequest request,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var result = await SendAsync<BotRedeemRequest, Void>(
|
||||
$"Api/Bot/{botNames}/Redeem",
|
||||
HttpMethod.Post,
|
||||
reqBody: request,
|
||||
cancellationToken: cancellationToken);
|
||||
return result!;
|
||||
}
|
||||
|
||||
public async Task<IApiRsp> RenamePost(
|
||||
string botNames,
|
||||
BotRenameRequest request,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var result = await SendAsync<BotRenameRequest, Void>(
|
||||
$"Api/Bot/{botNames}/Rename",
|
||||
HttpMethod.Post,
|
||||
reqBody: request,
|
||||
cancellationToken: cancellationToken);
|
||||
return result!;
|
||||
}
|
||||
|
||||
public async Task<IApiRsp> ResumePost(
|
||||
string botNames,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var result = await SendAsync<Void, Void>(
|
||||
$"Api/Bot/{botNames}/Resume",
|
||||
HttpMethod.Post,
|
||||
reqBody: default,
|
||||
cancellationToken: cancellationToken);
|
||||
return result!;
|
||||
}
|
||||
|
||||
public async Task<IApiRsp> StartPost(
|
||||
string botNames,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var result = await SendAsync<Void, Void>(
|
||||
$"Api/Bot/{botNames}/Start",
|
||||
HttpMethod.Post,
|
||||
reqBody: default,
|
||||
cancellationToken: cancellationToken);
|
||||
return result!;
|
||||
}
|
||||
|
||||
public async Task<IApiRsp> StopPost(
|
||||
string botNames,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var result = await SendAsync<Void, Void>(
|
||||
$"Api/Bot/{botNames}/Stop",
|
||||
HttpMethod.Post,
|
||||
reqBody: default,
|
||||
cancellationToken: cancellationToken);
|
||||
return result!;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public ICommandClient Command => this;
|
||||
|
||||
#region CommandController
|
||||
|
||||
public async Task<IApiRsp<string>> CommandPost(
|
||||
CommandRequest request,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var result = await SendAsync<CommandRequest, string>(
|
||||
$"Api/Command",
|
||||
HttpMethod.Post,
|
||||
reqBody: request,
|
||||
cancellationToken: cancellationToken);
|
||||
return result!;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
+5
-6
@@ -1,4 +1,3 @@
|
||||
using Microsoft.AspNetCore.Mvc.NewtonsoftJson;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace BD.WTTS.Services.Implementation;
|
||||
@@ -12,7 +11,7 @@ partial class ArchiSteamFarmWebApiServiceImpl // JsonSerializer(Newtonsoft.Json)
|
||||
// https://github.com/BeyondDimension/ArchiSteamFarm/blob/v5.4.9.3/ArchiSteamFarm/IPC/Startup.cs#L350-L364
|
||||
// https://github.com/dotnet/aspnetcore/blob/v7.0.11/src/Mvc/Mvc.NewtonsoftJson/src/JsonSerializerSettingsProvider.cs
|
||||
|
||||
var settings = JsonSerializerSettingsProvider.CreateSerializerSettings();
|
||||
var settings = new JsonSerializerSettings();
|
||||
// Fix default contract resolver to use original names and not a camel case
|
||||
settings.ContractResolver = new DefaultContractResolver();
|
||||
|
||||
@@ -23,13 +22,13 @@ partial class ArchiSteamFarmWebApiServiceImpl // JsonSerializer(Newtonsoft.Json)
|
||||
HttpContent Serialize(object? value, Type? objectType = null)
|
||||
{
|
||||
var stream = new MemoryStream();
|
||||
using var streamWriter = new StreamWriter(stream, Encoding.UTF8, leaveOpen: true);
|
||||
using var streamWriter = new StreamWriter(stream, new UTF8Encoding(false), leaveOpen: true);
|
||||
using var jsonWriter = new JsonTextWriter(streamWriter);
|
||||
serializer.Serialize(jsonWriter, value, objectType);
|
||||
jsonWriter.Flush();
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
var content = new StreamContent(stream);
|
||||
content.Headers.TryAddWithoutValidation(
|
||||
"Content-Type",
|
||||
"application/json;charset=utf-8");
|
||||
content.Headers.TryAddWithoutValidation("Content-Type", "application/json;charset=utf-8");
|
||||
return content;
|
||||
}
|
||||
|
||||
|
||||
+9
-11
@@ -3,11 +3,11 @@ namespace BD.WTTS.Services.Implementation;
|
||||
partial class ArchiSteamFarmWebApiServiceImpl // SendAsync(HttpClient)
|
||||
: GeneralHttpClientFactory
|
||||
{
|
||||
[Obsolete("TODO: 更改为设置项的默认值")]
|
||||
const string DefaultBaseAddress = "http://localhost:1242";
|
||||
|
||||
[Obsolete("TODO: 更改为从设置项中读取")]
|
||||
string BaseAddress => "";
|
||||
string BaseAddress = string.Empty;
|
||||
|
||||
public void SetIPCUrl(string ipcUrl) => BaseAddress = ipcUrl;
|
||||
|
||||
HttpClient CreateClient()
|
||||
{
|
||||
@@ -24,7 +24,8 @@ partial class ArchiSteamFarmWebApiServiceImpl // SendAsync(HttpClient)
|
||||
}
|
||||
|
||||
var client = CreateClient($"{TAG}_{baseAddressStr}", HttpHandlerCategory.Default);
|
||||
client.BaseAddress = baseAddress;
|
||||
if (client.BaseAddress == null || !client.BaseAddress.Equals(baseAddress))
|
||||
client.BaseAddress = baseAddress;
|
||||
return client;
|
||||
}
|
||||
|
||||
@@ -35,11 +36,11 @@ partial class ArchiSteamFarmWebApiServiceImpl // SendAsync(HttpClient)
|
||||
bool isShowResponseErrorMessage = true,
|
||||
string? errorAppendText = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
where TRequestBody : notnull
|
||||
where TResponseBody : notnull
|
||||
where TRequestBody : class
|
||||
where TResponseBody : class
|
||||
{
|
||||
var result = await SendCoreAsync();
|
||||
if (isShowResponseErrorMessage)
|
||||
if (!result.IsSuccess && isShowResponseErrorMessage)
|
||||
{
|
||||
conn_helper.ShowResponseErrorMessage(requestUrl, result, errorAppendText);
|
||||
}
|
||||
@@ -57,9 +58,6 @@ partial class ArchiSteamFarmWebApiServiceImpl // SendAsync(HttpClient)
|
||||
try
|
||||
{
|
||||
var reqContent = Serialize(reqBody, typeRequestBody);
|
||||
#if DEBUG
|
||||
var reqContentJsonStr = await reqContent.ReadAsStringAsync(cancellationToken);
|
||||
#endif
|
||||
req.Content = reqContent;
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -106,7 +104,7 @@ partial class ArchiSteamFarmWebApiServiceImpl // SendAsync(HttpClient)
|
||||
}
|
||||
}
|
||||
|
||||
struct Void
|
||||
class Void
|
||||
{
|
||||
// https://github.com/dotnet/runtime/blob/v7.0.11/src/libraries/System.Private.CoreLib/src/System/Void.cs
|
||||
}
|
||||
|
||||
@@ -1,98 +1,122 @@
|
||||
//#if (WINDOWS || MACCATALYST || MACOS || LINUX) && !(IOS || ANDROID)
|
||||
#if (WINDOWS || MACCATALYST || MACOS || LINUX) && !(IOS || ANDROID)
|
||||
|
||||
//// ReSharper disable once CheckNamespace
|
||||
// ReSharper disable once CheckNamespace
|
||||
using ArchiSteamFarm.Steam;
|
||||
using ArchiSteamFarm.Steam.Storage;
|
||||
using ArchiSteamFarm.Storage;
|
||||
|
||||
//namespace BD.WTTS.Services;
|
||||
namespace BD.WTTS.Services;
|
||||
|
||||
///// <summary>
|
||||
///// ArchiSteamFarm 服务
|
||||
///// </summary>
|
||||
//public partial interface IArchiSteamFarmService : IArchiSteamFarmHelperService
|
||||
//{
|
||||
// static new IArchiSteamFarmService Instance => Ioc.Get<IArchiSteamFarmService>();
|
||||
/// <summary>
|
||||
/// ArchiSteamFarm 服务
|
||||
/// </summary>
|
||||
public partial interface IArchiSteamFarmService
|
||||
{
|
||||
static IArchiSteamFarmService Instance => Ioc.Get<IArchiSteamFarmService>();
|
||||
|
||||
// event Action<string>? OnConsoleWirteLine;
|
||||
event Action<string>? OnConsoleWirteLine;
|
||||
|
||||
// TaskCompletionSource<string>? ReadLineTask { get; }
|
||||
TaskCompletionSource<string>? ReadLineTask { get; }
|
||||
|
||||
// bool IsReadPasswordLine { get; }
|
||||
bool IsReadPasswordLine { get; }
|
||||
|
||||
// DateTimeOffset? StartTime { get; }
|
||||
Process? ASFProcess { get; }
|
||||
|
||||
// Version CurrentVersion { get; }
|
||||
DateTimeOffset? StartTime { get; }
|
||||
|
||||
// /// <summary>
|
||||
// /// 启动 ArchiSteamFarm
|
||||
// /// </summary>
|
||||
// /// <param name="args"></param>
|
||||
// Task<bool> StartAsync(string[]? args = null);
|
||||
Version CurrentVersion { get; }
|
||||
|
||||
// Task StopAsync();
|
||||
/// <summary>
|
||||
/// 控制台输入
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
void ShellMessageInput(string data);
|
||||
|
||||
// /// <summary>
|
||||
// /// 执行 ArchiSteamFarm 指令
|
||||
// /// </summary>
|
||||
// /// <param name="command"></param>
|
||||
// Task<string?> ExecuteCommandAsync(string command);
|
||||
/// <summary>
|
||||
/// 启动 ArchiSteamFarm
|
||||
/// </summary>
|
||||
/// <param name="args"></param>
|
||||
Task<bool> StartAsync(string[]? args = null);
|
||||
|
||||
// /// <summary>
|
||||
// /// 获取 IPC 地址
|
||||
// /// </summary>
|
||||
// /// <returns></returns>
|
||||
// string GetIPCUrl();
|
||||
Task StopAsync();
|
||||
|
||||
// /// <summary>
|
||||
// /// 获取 Bot 只读集合
|
||||
// /// </summary>
|
||||
// /// <returns></returns>
|
||||
// IReadOnlyDictionary<string, Bot>? GetReadOnlyAllBots();
|
||||
/// <summary>
|
||||
/// 执行 ArchiSteamFarm 指令
|
||||
/// </summary>
|
||||
/// <param name="command"></param>
|
||||
Task<string?> ExecuteCommandAsync(string command);
|
||||
|
||||
// GlobalConfig? GetGlobalConfig();
|
||||
/// <summary>
|
||||
/// 获取 IPC 地址
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
string GetIPCUrl();
|
||||
|
||||
// async void CommandSubmit(string? command)
|
||||
// {
|
||||
// if (string.IsNullOrEmpty(command))
|
||||
// return;
|
||||
/// <summary>
|
||||
/// 获取 Bot 只读集合
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<IReadOnlyDictionary<string, Bot>?> GetReadOnlyAllBots();
|
||||
|
||||
// if (ReadLineTask is null)
|
||||
// {
|
||||
// if (command[0] == '!')
|
||||
// {
|
||||
// command = command.Remove(0, 1);
|
||||
// }
|
||||
// await ExecuteCommandAsync(command);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// ReadLineTask.TrySetResult(command);
|
||||
// }
|
||||
// }
|
||||
Task<GlobalConfig?> GetGlobalConfig();
|
||||
|
||||
// int CurrentIPCPortValue { get; protected set; }
|
||||
Task<bool> SaveBot(string botName, BotConfig botConfig);
|
||||
|
||||
// int IArchiSteamFarmHelperService.IPCPortValue
|
||||
// {
|
||||
// get
|
||||
// {
|
||||
// CurrentIPCPortValue = ASFSettings.IPCPortId.Value;
|
||||
// if (CurrentIPCPortValue == default) CurrentIPCPortValue = ASFSettings.DefaultIPCPortIdValue;
|
||||
// if (ASFSettings.IPCPortOccupiedRandom.Value)
|
||||
// {
|
||||
// if (SocketHelper.IsUsePort(CurrentIPCPortValue))
|
||||
// {
|
||||
// CurrentIPCPortValue = SocketHelper.GetRandomUnusedPort(IPAddress.Loopback);
|
||||
// return CurrentIPCPortValue;
|
||||
// }
|
||||
// }
|
||||
// return CurrentIPCPortValue;
|
||||
// }
|
||||
// }
|
||||
Task<bool> SaveGlobalConfig(GlobalConfig config);
|
||||
|
||||
// /// <summary>
|
||||
// /// 使用弹窗密码框输入自定义密钥并设置与保存
|
||||
// /// </summary>
|
||||
// /// <returns></returns>
|
||||
// Task SetEncryptionKeyAsync();
|
||||
//}
|
||||
async void CommandSubmit(string? command)
|
||||
{
|
||||
if (string.IsNullOrEmpty(command))
|
||||
return;
|
||||
|
||||
//#endif
|
||||
if (ReadLineTask is null)
|
||||
{
|
||||
if (command[0] == '!')
|
||||
{
|
||||
command = command.Remove(0, 1);
|
||||
}
|
||||
await ExecuteCommandAsync(command);
|
||||
}
|
||||
else
|
||||
{
|
||||
ReadLineTask.TrySetResult(command);
|
||||
}
|
||||
}
|
||||
|
||||
int CurrentIPCPortValue { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 使用弹窗密码框输入自定义密钥并设置与保存
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task SetEncryptionKeyAsync();
|
||||
|
||||
Task<IApiRsp> BotResumeAsync(string botNames,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
Task<IApiRsp> BotPauseAsync(string botNames,
|
||||
BotPauseRequest request,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
Task<IApiRsp> BotStopAsync(string botNames,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
Task<IApiRsp> BotStartAsync(string botNames,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
Task<IApiRsp<IReadOnlyDictionary<string, GamesToRedeemInBackgroundResponse>>> BotGetUsedAndUnusedKeysAsync(string botNames,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
Task<IApiRsp> BotRedeemKeyAsync(string botNames,
|
||||
BotGamesToRedeemInBackgroundRequest request,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
Task<IApiRsp> BotResetRedeemedKeysRecordAsync(string botNames,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
Task<IApiRsp> BotDeleteAsync(
|
||||
string botNames,
|
||||
CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
#endif
|
||||
+114
-3
@@ -1,3 +1,5 @@
|
||||
using ArchiSteamFarm.Steam;
|
||||
|
||||
namespace BD.WTTS.Services;
|
||||
|
||||
public interface IArchiSteamFarmWebApiService
|
||||
@@ -9,6 +11,8 @@ public interface IArchiSteamFarmWebApiService
|
||||
// IApiRsp<T> = GenericResponse<T>
|
||||
// T maybe null !!!
|
||||
|
||||
void SetIPCUrl(string ipcUrl);
|
||||
|
||||
IASFClient ASF { get; }
|
||||
|
||||
interface IASFClient
|
||||
@@ -37,7 +41,7 @@ public interface IArchiSteamFarmWebApiService
|
||||
/// <param name="request"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
Task<IApiRsp> Hash(
|
||||
Task<IApiRsp<string>> Hash(
|
||||
ASFHashRequest request,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
@@ -74,7 +78,6 @@ public interface IArchiSteamFarmWebApiService
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
Task<IApiRsp<string?>> Update(
|
||||
UpdateRequest request,
|
||||
CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
@@ -82,13 +85,121 @@ public interface IArchiSteamFarmWebApiService
|
||||
|
||||
interface IBotClient
|
||||
{
|
||||
/// <summary>
|
||||
/// Deletes all files related to given bots.
|
||||
/// </summary>
|
||||
Task<IApiRsp> BotDelete(
|
||||
string botNames,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Fetches common info related to given bots.
|
||||
/// </summary>
|
||||
Task<IApiRsp<IReadOnlyDictionary<string, Bot>>> BotGet(
|
||||
string botNames,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Updates bot config of given bot.
|
||||
/// </summary>
|
||||
Task<IApiRsp> BotPost(
|
||||
string botNames,
|
||||
BotRequest request,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Removes BGR output files of given bots.
|
||||
/// </summary>
|
||||
Task<IApiRsp> GamesToRedeemInBackgroundDelete(
|
||||
string botNames,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Fetches BGR output files of given bots.
|
||||
/// </summary>
|
||||
Task<IApiRsp<IReadOnlyDictionary<string, GamesToRedeemInBackgroundResponse>>> GamesToRedeemInBackgroundGet(
|
||||
string botNames,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Adds keys to redeem using BGR to given bot.
|
||||
/// </summary>
|
||||
Task<IApiRsp> GamesToRedeemInBackgroundPost(
|
||||
string botNames,
|
||||
BotGamesToRedeemInBackgroundRequest request,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Provides input value to given bot for next usage.
|
||||
/// </summary>
|
||||
Task<IApiRsp> InputPost(
|
||||
string botNames,
|
||||
BotInputRequest request,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Pauses given bots.
|
||||
/// </summary>
|
||||
Task<IApiRsp> PausePost(
|
||||
string botNames,
|
||||
BotPauseRequest request,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Redeems cd-keys on given bot.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Response contains a map that maps each provided cd-key to its redeem result.
|
||||
/// Redeem result can be a null value, this means that ASF didn't even attempt to send a request (e.g. because of bot not being connected to Steam network).
|
||||
/// </remarks>
|
||||
Task<IApiRsp> RedeemPost(
|
||||
string botNames,
|
||||
BotRedeemRequest request,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Renames given bot along with all its related files.
|
||||
/// </summary>
|
||||
Task<IApiRsp> RenamePost(
|
||||
string botNames,
|
||||
BotRenameRequest request,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Resumes given bots.
|
||||
/// </summary>
|
||||
Task<IApiRsp> ResumePost(
|
||||
string botNames,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Starts given bots.
|
||||
/// </summary>
|
||||
Task<IApiRsp> StartPost(
|
||||
string botNames,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Stops given bots.
|
||||
/// </summary>
|
||||
Task<IApiRsp> StopPost(
|
||||
string botNames,
|
||||
CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
ICommandClient Command { get; }
|
||||
|
||||
interface ICommandClient
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Executes a command.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This API endpoint is supposed to be entirely replaced by ASF actions available under /Api/ASF/{action} and /Api/Bot/{bot}/{action}.
|
||||
/// You should use "given bot" commands when executing this endpoint, omitting targets of the command will cause the command to be executed on first defined bot
|
||||
/// </remarks>
|
||||
Task<IApiRsp<string>> CommandPost(
|
||||
CommandRequest request,
|
||||
CancellationToken cancellationToken = default);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,199 +1,253 @@
|
||||
//#if (WINDOWS || MACCATALYST || MACOS || LINUX) && !(IOS || ANDROID)
|
||||
//using AppResources = BD.WTTS.Client.Resources.Strings;
|
||||
#if (WINDOWS || MACCATALYST || MACOS || LINUX) && !(IOS || ANDROID)
|
||||
using ArchiSteamFarm.Core;
|
||||
using ArchiSteamFarm.Steam;
|
||||
using ArchiSteamFarm.Steam.Storage;
|
||||
using ArchiSteamFarm.Storage;
|
||||
using Newtonsoft.Json;
|
||||
using AppResources = BD.WTTS.Client.Resources.Strings;
|
||||
|
||||
//// ReSharper disable once CheckNamespace
|
||||
//namespace BD.WTTS.Services;
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BD.WTTS.Services;
|
||||
|
||||
//public sealed class ASFService : ReactiveObject
|
||||
//{
|
||||
// static ASFService? mCurrent;
|
||||
public sealed class ASFService : ReactiveObject
|
||||
{
|
||||
static ASFService? mCurrent;
|
||||
|
||||
// public static ASFService Current => mCurrent ?? new();
|
||||
public static ASFService Current => mCurrent ?? new();
|
||||
|
||||
// readonly IArchiSteamFarmService archiSteamFarmService = IArchiSteamFarmService.Instance;
|
||||
readonly IArchiSteamFarmService archiSteamFarmService = IArchiSteamFarmService.Instance;
|
||||
|
||||
// string? _IPCUrl;
|
||||
string? _IPCUrl;
|
||||
|
||||
// public string? IPCUrl
|
||||
// {
|
||||
// get => _IPCUrl;
|
||||
// set => this.RaiseAndSetIfChanged(ref _IPCUrl, value);
|
||||
// }
|
||||
public string? IPCUrl
|
||||
{
|
||||
get => _IPCUrl;
|
||||
set => this.RaiseAndSetIfChanged(ref _IPCUrl, value);
|
||||
}
|
||||
|
||||
// string? _ConsoleLogText;
|
||||
string? _ConsoleLogText;
|
||||
|
||||
// public string? ConsoleLogText
|
||||
// {
|
||||
// get => _ConsoleLogText;
|
||||
// set => this.RaiseAndSetIfChanged(ref _ConsoleLogText, value);
|
||||
// }
|
||||
public string? ConsoleLogText
|
||||
{
|
||||
get => _ConsoleLogText;
|
||||
set => this.RaiseAndSetIfChanged(ref _ConsoleLogText, value);
|
||||
}
|
||||
|
||||
// public IConsoleBuilder ConsoleLogBuilder { get; } = new ConsoleBuilder();
|
||||
string? _ConsoleLogInput;
|
||||
|
||||
// public SourceCache<Bot, string> SteamBotsSourceList;
|
||||
public string? ConsoleLogInput
|
||||
{
|
||||
get => _ConsoleLogInput;
|
||||
set => this.RaiseAndSetIfChanged(ref _ConsoleLogInput, value);
|
||||
}
|
||||
|
||||
// public bool IsASFRuning => archiSteamFarmService.StartTime != null;
|
||||
public IConsoleBuilder ConsoleLogBuilder { get; } = new ConsoleBuilder();
|
||||
|
||||
// GlobalConfig? _GlobalConfig;
|
||||
public SourceCache<Bot, string> SteamBotsSourceList;
|
||||
|
||||
// public GlobalConfig? GlobalConfig
|
||||
// {
|
||||
// get => _GlobalConfig;
|
||||
// set => this.RaiseAndSetIfChanged(ref _GlobalConfig, value);
|
||||
// }
|
||||
public bool IsASFRuning => archiSteamFarmService.StartTime != null;
|
||||
|
||||
// private ASFService()
|
||||
// {
|
||||
// mCurrent = this;
|
||||
GlobalConfig? _GlobalConfig;
|
||||
|
||||
// SteamBotsSourceList = new SourceCache<Bot, string>(t => t.BotName);
|
||||
public GlobalConfig? GlobalConfig
|
||||
{
|
||||
get => _GlobalConfig;
|
||||
set => this.RaiseAndSetIfChanged(ref _GlobalConfig, value);
|
||||
}
|
||||
|
||||
// archiSteamFarmService.OnConsoleWirteLine += OnConsoleWirteLine;
|
||||
private ASFService()
|
||||
{
|
||||
mCurrent = this;
|
||||
|
||||
// ASFSettings.ConsoleMaxLine.Subscribe(x =>
|
||||
// {
|
||||
// var line = x;
|
||||
// if (x < ASFSettings.MinRangeConsoleMaxLine) line = ASFSettings.MinRangeConsoleMaxLine;
|
||||
// if (x > ASFSettings.MaxRangeConsoleMaxLine) line = ASFSettings.MaxRangeConsoleMaxLine;
|
||||
// ConsoleLogBuilder.MaxLine = line;
|
||||
// });
|
||||
// }
|
||||
SteamBotsSourceList = new SourceCache<Bot, string>(t => t.BotName);
|
||||
|
||||
// void OnConsoleWirteLine(string message)
|
||||
// {
|
||||
// MainThread2.InvokeOnMainThreadAsync(() =>
|
||||
// {
|
||||
// ConsoleLogBuilder.AppendLine(message);
|
||||
// var text = ConsoleLogBuilder.ToString();
|
||||
// ConsoleLogText = text;
|
||||
// });
|
||||
// }
|
||||
archiSteamFarmService.OnConsoleWirteLine += OnConsoleWirteLine;
|
||||
|
||||
// /// <summary>
|
||||
// /// 是否正在启动或停止中
|
||||
// /// </summary>
|
||||
// public bool IsASFRunOrStoping { get; private set; }
|
||||
ASFSettings.ConsoleMaxLine.Subscribe(x =>
|
||||
{
|
||||
var line = x;
|
||||
if (x < ASFSettings.MinRangeConsoleMaxLine) line = ASFSettings.MinRangeConsoleMaxLine;
|
||||
if (x > ASFSettings.MaxRangeConsoleMaxLine) line = ASFSettings.MaxRangeConsoleMaxLine;
|
||||
ConsoleLogBuilder.MaxLine = line;
|
||||
});
|
||||
}
|
||||
|
||||
// public Task InitASFAsync() => InitASFCoreAsync(true);
|
||||
void OnConsoleWirteLine(string message)
|
||||
{
|
||||
MainThread2.InvokeOnMainThreadAsync(() =>
|
||||
{
|
||||
ConsoleLogBuilder.AppendLine(message);
|
||||
var text = ConsoleLogBuilder.ToString();
|
||||
ConsoleLogText = text;
|
||||
});
|
||||
}
|
||||
|
||||
// public async Task InitASFCoreAsync(bool showToast)
|
||||
// {
|
||||
// if (IsASFRunOrStoping) return;
|
||||
public void ShellMessageInput()
|
||||
{
|
||||
if (string.IsNullOrEmpty(ConsoleLogInput))
|
||||
{
|
||||
return;
|
||||
}
|
||||
archiSteamFarmService.ShellMessageInput(ConsoleLogInput);
|
||||
}
|
||||
|
||||
// if (showToast) Toast.Show(AppResources.ASF_Starting, ToastLength.Short);
|
||||
/// <summary>
|
||||
/// 是否正在启动或停止中
|
||||
/// </summary>
|
||||
public bool IsASFRunOrStoping { get; private set; }
|
||||
|
||||
// IsASFRunOrStoping = true;
|
||||
public Task InitASFAsync() => InitASFCoreAsync(true);
|
||||
|
||||
// //if (ASF.GlobalConfig?.SteamOwnerID is null or 0)
|
||||
// //{
|
||||
// // Toast.Show(AppResources.ASF_Starting, ToastLength.Long);
|
||||
// // return;
|
||||
// //}
|
||||
public async Task InitASFCoreAsync(bool showToast)
|
||||
{
|
||||
if (IsASFRunOrStoping) return;
|
||||
|
||||
// var isOk = await archiSteamFarmService.StartAsync();
|
||||
// if (!isOk)
|
||||
// {
|
||||
// if (showToast) Toast.Show(AppResources.ASF_Stoped, ToastLength.Short);
|
||||
// return;
|
||||
// }
|
||||
if (showToast) Toast.Show(ToastIcon.Info, AppResources.ASF_Starting, ToastLength.Short);
|
||||
|
||||
// RefreshBots();
|
||||
IsASFRunOrStoping = true;
|
||||
|
||||
// IPCUrl = archiSteamFarmService.GetIPCUrl();
|
||||
var isOk = await archiSteamFarmService.StartAsync();
|
||||
if (!isOk)
|
||||
{
|
||||
if (showToast) Toast.Show(ToastIcon.Error, AppResources.ASF_Stoped, ToastLength.Short);
|
||||
IsASFRunOrStoping = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// MainThread2.BeginInvokeOnMainThread(() =>
|
||||
// {
|
||||
// this.RaisePropertyChanged(nameof(IsASFRuning));
|
||||
// });
|
||||
RefreshBots();
|
||||
|
||||
// IsASFRunOrStoping = false;
|
||||
IPCUrl = archiSteamFarmService.GetIPCUrl();
|
||||
|
||||
// if (showToast) Toast.Show(AppResources.ASF_Started, ToastLength.Short);
|
||||
// }
|
||||
MainThread2.BeginInvokeOnMainThread(() =>
|
||||
{
|
||||
this.RaisePropertyChanged(nameof(IsASFRuning));
|
||||
});
|
||||
|
||||
// public Task StopASFAsync() => StopASFCoreAsync(true);
|
||||
IsASFRunOrStoping = false;
|
||||
|
||||
// public async Task StopASFCoreAsync(bool showToast)
|
||||
// {
|
||||
// if (IsASFRunOrStoping) return;
|
||||
if (showToast) Toast.Show(ToastIcon.Success, AppResources.ASF_Started, ToastLength.Short);
|
||||
}
|
||||
|
||||
// if (showToast) Toast.Show(AppResources.ASF_Stoping, ToastLength.Short);
|
||||
public Task StopASFAsync() => StopASFCoreAsync(true);
|
||||
|
||||
// IsASFRunOrStoping = true;
|
||||
public async Task StopASFCoreAsync(bool showToast)
|
||||
{
|
||||
if (IsASFRunOrStoping) return;
|
||||
|
||||
// await archiSteamFarmService.StopAsync();
|
||||
if (showToast) Toast.Show(ToastIcon.Info, AppResources.ASF_Stoping, ToastLength.Short);
|
||||
|
||||
// MainThread2.BeginInvokeOnMainThread(() =>
|
||||
// {
|
||||
// this.RaisePropertyChanged(nameof(IsASFRuning));
|
||||
// });
|
||||
IsASFRunOrStoping = true;
|
||||
|
||||
// IsASFRunOrStoping = false;
|
||||
await archiSteamFarmService.StopAsync();
|
||||
|
||||
// if (showToast) Toast.Show(AppResources.ASF_Stoped, ToastLength.Short);
|
||||
// }
|
||||
MainThread2.BeginInvokeOnMainThread(() =>
|
||||
{
|
||||
this.RaisePropertyChanged(nameof(IsASFRuning));
|
||||
});
|
||||
|
||||
// public void RefreshBots()
|
||||
// {
|
||||
// var bots = archiSteamFarmService.GetReadOnlyAllBots();
|
||||
// if (bots.Any_Nullable())
|
||||
// {
|
||||
// SteamBotsSourceList.AddOrUpdate(bots!.Values);
|
||||
// }
|
||||
// }
|
||||
IsASFRunOrStoping = false;
|
||||
|
||||
// public void RefreshConfig()
|
||||
// {
|
||||
// GlobalConfig = archiSteamFarmService.GetGlobalConfig();
|
||||
// }
|
||||
if (showToast) Toast.Show(ToastIcon.Info, AppResources.ASF_Stoped, ToastLength.Short);
|
||||
}
|
||||
|
||||
// public async void ImportBotFiles(IEnumerable<string>? files) => await ImportJsonFileAsync(files, allowBot: true, allowGlobal: false);
|
||||
public async void RefreshBots()
|
||||
{
|
||||
var bots = await archiSteamFarmService.GetReadOnlyAllBots();
|
||||
if (bots.Any_Nullable())
|
||||
{
|
||||
SteamBotsSourceList.AddOrUpdate(bots!.Values);
|
||||
}
|
||||
}
|
||||
|
||||
// public async void ImportGlobalFiles(string? file) => await ImportJsonFileAsync(new[] { file }, allowBot: false, allowGlobal: true);
|
||||
public async void RefreshConfig()
|
||||
{
|
||||
GlobalConfig = await archiSteamFarmService.GetGlobalConfig();
|
||||
}
|
||||
|
||||
// async Task ImportJsonFileAsync(IEnumerable<string?>? files, bool allowBot, bool allowGlobal)
|
||||
// {
|
||||
// if (files == null) return;
|
||||
// var num = 0;
|
||||
// foreach (var filename in files)
|
||||
// {
|
||||
// if (string.IsNullOrWhiteSpace(filename)) continue;
|
||||
// var file = new FileInfo(filename);
|
||||
// if (file.Exists && string.Equals(file.Extension, SharedInfo.JsonConfigExtension, StringComparison.OrdinalIgnoreCase))
|
||||
// {
|
||||
// object? config;
|
||||
// if (file.Name != SharedInfo.GlobalConfigFileName)
|
||||
// {
|
||||
// if (!allowBot) continue;
|
||||
// var bot = await BotConfig.Load(file.FullName).ConfigureAwait(false);
|
||||
// config = bot.BotConfig;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// if (!allowGlobal) continue;
|
||||
// var g = await GlobalConfig.Load(file.FullName).ConfigureAwait(false);
|
||||
// config = g.GlobalConfig;
|
||||
// }
|
||||
// if (config != null)
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// file.CopyTo(Path.Combine(SharedInfo.ConfigDirectory, file.Name), true);
|
||||
// num++;
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// Log.Error(nameof(ASFService), ex, nameof(ImportBotFiles));
|
||||
// continue;
|
||||
// }
|
||||
// if (allowGlobal && config is GlobalConfig g)
|
||||
// {
|
||||
// GlobalConfig = ASF.GlobalConfig = g;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// Toast.Show(string.Format(AppResources.LocalAuth_ImportSuccessTip_, num));
|
||||
// }
|
||||
//}
|
||||
//#endif
|
||||
public async void ImportBotFiles(IEnumerable<string>? files) => await ImportJsonFileAsync(files, allowBot: true, allowGlobal: false);
|
||||
|
||||
public async void ImportGlobalFiles(string? file) => await ImportJsonFileAsync(new[] { file }, allowBot: false, allowGlobal: true);
|
||||
|
||||
async Task ImportJsonFileAsync(IEnumerable<string?>? files, bool allowBot, bool allowGlobal)
|
||||
{
|
||||
if (files == null) return;
|
||||
var num = 0;
|
||||
foreach (var filename in files)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(filename)) continue;
|
||||
var file = new FileInfo(filename);
|
||||
if (file.Exists && string.Equals(file.Extension, SharedInfo.JsonConfigExtension, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
object? config;
|
||||
string json;
|
||||
try
|
||||
{
|
||||
json = await File.ReadAllTextAsync(file.FullName).ConfigureAwait(false);
|
||||
if (string.IsNullOrEmpty(json))
|
||||
{
|
||||
ASF.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsEmpty, nameof(json)));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (file.Name != SharedInfo.GlobalConfigFileName)
|
||||
{
|
||||
if (!allowBot) continue;
|
||||
var botConfig = JsonConvert.DeserializeObject<BotConfig>(json);
|
||||
if (botConfig == null)
|
||||
{
|
||||
ASF.ArchiLogger.LogNullError(botConfig);
|
||||
return;
|
||||
}
|
||||
|
||||
if (await archiSteamFarmService.SaveBot(Path.GetFileNameWithoutExtension(file.FullName), botConfig))
|
||||
config = botConfig;
|
||||
else
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!allowGlobal) continue;
|
||||
var globalConfig = JsonConvert.DeserializeObject<GlobalConfig>(json);
|
||||
if (globalConfig == null)
|
||||
{
|
||||
ASF.ArchiLogger.LogNullError(globalConfig);
|
||||
return;
|
||||
}
|
||||
|
||||
if (await archiSteamFarmService.SaveGlobalConfig(globalConfig))
|
||||
config = globalConfig;
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ASF.ArchiLogger.LogGenericException(e);
|
||||
|
||||
return;
|
||||
}
|
||||
if (config != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
file.CopyTo(Path.Combine(SharedInfo.HomeDirectory, SharedInfo.ConfigDirectory, file.Name), true);
|
||||
num++;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(nameof(ASFService), ex, nameof(ImportBotFiles));
|
||||
continue;
|
||||
}
|
||||
if (allowGlobal && config is GlobalConfig g)
|
||||
{
|
||||
GlobalConfig = g;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Toast.Show(ToastIcon.Success, string.Format(AppResources.LocalAuth_ImportSuccessTip_, num));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,19 +1,73 @@
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BD.WTTS.Settings;
|
||||
|
||||
public sealed partial class ASFSettings : SettingsHost2<ASFSettings>
|
||||
[JsonSourceGenerationOptions(WriteIndented = true, IgnoreReadOnlyProperties = true)]
|
||||
[JsonSerializable(typeof(ASFSettings_))]
|
||||
internal partial class ASFSettingsContext : JsonSerializerContext
|
||||
{
|
||||
static ASFSettingsContext? instance;
|
||||
|
||||
public static ASFSettingsContext Instance
|
||||
=> instance ??= new ASFSettingsContext(ISettings.GetDefaultOptions());
|
||||
}
|
||||
|
||||
[MPObj, MP2Obj(SerializeLayout.Explicit)]
|
||||
public sealed partial class ASFSettings_ : IASFSettings, ISettings, ISettings<ASFSettings_>
|
||||
{
|
||||
public const string Name = nameof(ASFSettings);
|
||||
|
||||
static string ISettings.Name => Name;
|
||||
|
||||
static JsonSerializerContext ISettings.JsonSerializerContext
|
||||
=> ASFSettingsContext.Instance;
|
||||
|
||||
static JsonTypeInfo ISettings.JsonTypeInfo
|
||||
=> ASFSettingsContext.Instance.ASFSettings_;
|
||||
|
||||
static JsonTypeInfo<ASFSettings_> ISettings<ASFSettings_>.JsonTypeInfo
|
||||
=> ASFSettingsContext.Instance.ASFSettings_;
|
||||
|
||||
[MPKey(0), MP2Key(0), JsonPropertyOrder(0)]
|
||||
public string ArchiSteamFarmExePath { get; set; } = string.Empty;
|
||||
|
||||
[MPKey(1), MP2Key(1), JsonPropertyOrder(1)]
|
||||
public bool AutoRunArchiSteamFarm { get; set; }
|
||||
|
||||
[MPKey(2), MP2Key(2), JsonPropertyOrder(2)]
|
||||
public int ConsoleMaxLine { get; set; } = IASFSettings.DefaultConsoleMaxLine;
|
||||
|
||||
[MPKey(3), MP2Key(3), JsonPropertyOrder(3)]
|
||||
public int ConsoleFontSize { get; set; } = IASFSettings.DefaultConsoleFontSize;
|
||||
|
||||
[MPKey(4), MP2Key(4), JsonPropertyOrder(4)]
|
||||
public int IPCPortId { get; set; } = IASFSettings.DefaultIPCPortIdValue;
|
||||
|
||||
[MPKey(5), MP2Key(5), JsonPropertyOrder(5)]
|
||||
public bool IPCPortOccupiedRandom { get; set; } = true;
|
||||
|
||||
[MPKey(6), MP2Key(6), JsonPropertyOrder(6)]
|
||||
public bool CheckArchiSteamFarmExe { get; set; }
|
||||
}
|
||||
|
||||
public sealed partial class ASFSettings
|
||||
{
|
||||
/// <summary>
|
||||
/// ASF路径
|
||||
/// </summary>
|
||||
public static SerializableProperty<string> ArchiSteamFarmExePath { get; }
|
||||
= GetProperty(defaultValue: string.Empty);
|
||||
public static SettingsProperty<string, ASFSettings_> ArchiSteamFarmExePath { get; }
|
||||
= new(string.Empty);
|
||||
|
||||
/// <summary>
|
||||
/// 程序启动时自动运行ASF
|
||||
/// </summary>
|
||||
public static SerializableProperty<bool> AutoRunArchiSteamFarm { get; }
|
||||
= GetProperty(defaultValue: false);
|
||||
public static SettingsStructProperty<bool, ASFSettings_> AutoRunArchiSteamFarm { get; }
|
||||
= new(false);
|
||||
|
||||
/// <summary>
|
||||
/// 检查文件安全性
|
||||
/// </summary>
|
||||
public static SettingsStructProperty<bool, ASFSettings_> CheckArchiSteamFarmExe { get; }
|
||||
= new(false);
|
||||
|
||||
#region ConsoleMaxLine
|
||||
|
||||
@@ -32,8 +86,8 @@ public sealed partial class ASFSettings : SettingsHost2<ASFSettings>
|
||||
/// </summary>
|
||||
public const int MaxRangeConsoleMaxLine = 5000;
|
||||
|
||||
public static SerializableProperty<int> ConsoleMaxLine { get; }
|
||||
= GetProperty(defaultValue: DefaultConsoleMaxLine);
|
||||
public static SettingsStructProperty<int, ASFSettings_> ConsoleMaxLine { get; }
|
||||
= new(DefaultConsoleMaxLine);
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -44,20 +98,20 @@ public sealed partial class ASFSettings : SettingsHost2<ASFSettings>
|
||||
/// <summary>
|
||||
/// 控制台字体大小,默认值 14,Android 上单位为 sp
|
||||
/// </summary>
|
||||
public static SerializableProperty<int> ConsoleFontSize { get; }
|
||||
= GetProperty(defaultValue: DefaultConsoleFontSize);
|
||||
public static SettingsStructProperty<int, ASFSettings_> ConsoleFontSize { get; }
|
||||
= new(DefaultConsoleFontSize);
|
||||
|
||||
public const int DefaultIPCPortIdValue = 6242;
|
||||
|
||||
/// <summary>
|
||||
/// IPC 端口号,默认值为 <see cref="DefaultIPCPortIdValue"/>
|
||||
/// </summary>
|
||||
public static SerializableProperty<int> IPCPortId { get; }
|
||||
= GetProperty(defaultValue: DefaultIPCPortIdValue);
|
||||
public static SettingsStructProperty<int, ASFSettings_> IPCPortId { get; }
|
||||
= new(DefaultIPCPortIdValue);
|
||||
|
||||
/// <summary>
|
||||
/// IPC 端口号被占用时是否随机一个未使用的端口号,默认值 <see langword="true"/>
|
||||
/// </summary>
|
||||
public static SerializableProperty<bool> IPCPortOccupiedRandom { get; }
|
||||
= GetProperty(defaultValue: true);
|
||||
public static SettingsStructProperty<bool, ASFSettings_> IPCPortOccupiedRandom { get; }
|
||||
= new(true);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BD.WTTS.Settings.Abstractions;
|
||||
|
||||
public partial interface IASFSettings
|
||||
{
|
||||
static IASFSettings? Instance
|
||||
=> Ioc.Get_Nullable<IOptionsMonitor<IASFSettings>>()?.CurrentValue;
|
||||
|
||||
string ArchiSteamFarmExePath { get; set; }
|
||||
|
||||
bool AutoRunArchiSteamFarm { get; set; }
|
||||
|
||||
bool CheckArchiSteamFarmExe { get; set; }
|
||||
|
||||
#region ConsoleMaxLine
|
||||
|
||||
/// <summary>
|
||||
/// 控制台默认最大行数
|
||||
/// </summary>
|
||||
const int DefaultConsoleMaxLine = 200;
|
||||
|
||||
/// <summary>
|
||||
/// 控制台默认最大行数范围最小值
|
||||
/// </summary>
|
||||
const int MinRangeConsoleMaxLine = DefaultConsoleMaxLine;
|
||||
|
||||
/// <summary>
|
||||
/// 控制台默认最大行数范围最大值
|
||||
/// </summary>
|
||||
const int MaxRangeConsoleMaxLine = 5000;
|
||||
|
||||
int ConsoleMaxLine { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
const int DefaultConsoleFontSize = 14;
|
||||
const int MinRangeConsoleFontSize = 8;
|
||||
const int MaxRangeConsoleFontSize = 24;
|
||||
|
||||
int ConsoleFontSize { get; set; }
|
||||
|
||||
const int DefaultIPCPortIdValue = 6242;
|
||||
|
||||
int IPCPortId { get; set; }
|
||||
|
||||
bool IPCPortOccupiedRandom { get; set; }
|
||||
}
|
||||
+293
@@ -0,0 +1,293 @@
|
||||
#if !EXCLUDE_ASF
|
||||
using ArchiSteamFarm.Steam;
|
||||
using System.Collections.Specialized;
|
||||
using Avalonia.Automation;
|
||||
using BD.SteamClient.Models;
|
||||
using BD.SteamClient.Models.Idle;
|
||||
using BD.SteamClient.Services;
|
||||
using BD.WTTS.UI.Views.Pages;
|
||||
using System.Linq;
|
||||
using ArchiSteamFarm.Core;
|
||||
|
||||
namespace BD.WTTS.UI.ViewModels;
|
||||
|
||||
public sealed partial class ArchiSteamFarmPlusPageViewModel : ViewModelBase
|
||||
{
|
||||
private readonly IArchiSteamFarmService asfService = IArchiSteamFarmService.Instance;
|
||||
|
||||
public ArchiSteamFarmPlusPageViewModel()
|
||||
{
|
||||
SelectBotFiles = ReactiveCommand.CreateFromTask(SelectBotFiles_Click);
|
||||
|
||||
SelectGlobalFiles = ReactiveCommand.CreateFromTask(SelectGlobalFiles_Click);
|
||||
|
||||
SelectASFExePath = ReactiveCommand.CreateFromTask(SelectASFProgramLocation);
|
||||
|
||||
OpenWebUIConsole = ReactiveCommand.Create(() =>
|
||||
{
|
||||
OpenBrowser(null);
|
||||
});
|
||||
|
||||
OpenASFBrowser = ReactiveCommand.Create<string>(OpenBrowser);
|
||||
|
||||
ShellMessageInput = ReactiveCommand.Create(ShellMessageInput_Click);
|
||||
|
||||
RunOrStop = ReactiveCommand.Create(RunOrStopASF);
|
||||
|
||||
AddBot = ReactiveCommand.Create(ShowAddBotWindow);
|
||||
|
||||
RefreshBots = ReactiveCommand.Create(ASFService.Current.RefreshBots);
|
||||
|
||||
OpenASFFolder = ReactiveCommand.Create<string>(OpenFolder);
|
||||
|
||||
SetEncryptionKey = ReactiveCommand.Create(SetEncryptionKey_Click);
|
||||
|
||||
ASFService.Current.WhenValueChanged(x => x.IsASFRuning)
|
||||
.Subscribe(x =>
|
||||
{
|
||||
RunOrStopText = x ? BDStrings.ASF_Stop : BDStrings.ASF_Start;
|
||||
});
|
||||
|
||||
ASFService.Current.SteamBotsSourceList
|
||||
.Connect()
|
||||
.ObserveOn(RxApp.MainThreadScheduler)
|
||||
.Sort(SortExpressionComparer<Bot>.Descending(x => x.BotName))
|
||||
.Bind(out _SteamBots)
|
||||
.Subscribe();
|
||||
|
||||
//if (IApplication.IsDesktopPlatform)
|
||||
//{
|
||||
// ConsoleSelectFont = R.Fonts.FirstOrDefault(x => x.Value == ASFSettings.ConsoleFontName.Value);
|
||||
// this.WhenValueChanged(x => x.ConsoleSelectFont, false)
|
||||
// .Subscribe(x => ASFSettings.ConsoleFontName.Value = x.Value);
|
||||
//}
|
||||
}
|
||||
|
||||
public override void Activation()
|
||||
{
|
||||
base.Activation();
|
||||
|
||||
if (ASFSettings.AutoRunArchiSteamFarm.Value && !string.IsNullOrEmpty(ASFSettings.ArchiSteamFarmExePath.Value))
|
||||
StartOrStopASF_Click();
|
||||
}
|
||||
|
||||
public async Task SelectBotFiles_Click()
|
||||
{
|
||||
FilePickerFileType? fileTypes;
|
||||
if (IApplication.IsDesktop())
|
||||
{
|
||||
fileTypes = new ValueTuple<string, string[]>[]
|
||||
{
|
||||
("Json Files", new[] { FileEx.JSON, }),
|
||||
//("All Files", new[] { "*", }),
|
||||
};
|
||||
}
|
||||
else if (OperatingSystem2.IsAndroid())
|
||||
{
|
||||
fileTypes = new[] { MediaTypeNames.JSON };
|
||||
}
|
||||
else
|
||||
{
|
||||
fileTypes = null;
|
||||
}
|
||||
await FilePicker2.PickMultipleAsync(ASFService.Current.ImportBotFiles, fileTypes);
|
||||
}
|
||||
|
||||
public async Task SelectGlobalFiles_Click()
|
||||
{
|
||||
FilePickerFileType? fileTypes;
|
||||
if (IApplication.IsDesktop())
|
||||
{
|
||||
fileTypes = new ValueTuple<string, string[]>[]
|
||||
{
|
||||
("Json Files", new[] { FileEx.JSON, }),
|
||||
//("All Files", new[] { "*", }),
|
||||
};
|
||||
}
|
||||
else if (OperatingSystem2.IsAndroid())
|
||||
{
|
||||
fileTypes = new[] { MediaTypeNames.JSON };
|
||||
}
|
||||
else
|
||||
{
|
||||
fileTypes = null;
|
||||
}
|
||||
await FilePicker2.PickAsync(ASFService.Current.ImportGlobalFiles, fileTypes);
|
||||
}
|
||||
|
||||
public async Task SelectASFProgramLocation()
|
||||
{
|
||||
AvaloniaFilePickerFileTypeFilter fileTypes = new AvaloniaFilePickerFileTypeFilter.Item[] {
|
||||
new("ArchiSteamFarm") {
|
||||
Patterns = new[] { "ArchiSteamFarm.exe", },
|
||||
//MimeTypes =
|
||||
//AppleUniformTypeIdentifiers =
|
||||
},
|
||||
};
|
||||
await FilePicker2.PickAsync((path) =>
|
||||
{
|
||||
if (!string.IsNullOrEmpty(path))
|
||||
ASFSettings.ArchiSteamFarmExePath.Value = path;
|
||||
}, fileTypes);
|
||||
}
|
||||
|
||||
public static void StartOrStopASF_Click(bool? startOrStop = null) => Task.Run(async () =>
|
||||
{
|
||||
var s = ASFService.Current;
|
||||
if (!s.IsASFRuning)
|
||||
{
|
||||
if (!startOrStop.HasValue || startOrStop.Value)
|
||||
await s.InitASFAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!startOrStop.HasValue || !startOrStop.Value)
|
||||
await s.StopASFAsync();
|
||||
}
|
||||
});
|
||||
|
||||
public void RunOrStopASF() => StartOrStopASF_Click();
|
||||
|
||||
public async void ShowAddBotWindow()
|
||||
{
|
||||
await IWindowManager.Instance.ShowAsync(AppEndPoint.ASF_AddBot, resizeMode: ResizeMode.CanResize);
|
||||
}
|
||||
|
||||
public async void PauseOrResumeBotFarming(Bot bot)
|
||||
{
|
||||
(bool success, string message) result;
|
||||
IApiRsp apiRsp = null;
|
||||
if (bot.CardsFarmer.Paused)
|
||||
{
|
||||
apiRsp = await asfService.BotResumeAsync(bot.BotName);
|
||||
}
|
||||
else
|
||||
{
|
||||
var request = new BotPauseRequest() { Permanent = true };
|
||||
apiRsp = await asfService.BotPauseAsync(bot.BotName, request);
|
||||
}
|
||||
result = (apiRsp.IsSuccess, apiRsp.Message);
|
||||
|
||||
ASFService.Current.SteamBotsSourceList.AddOrUpdate(bot);
|
||||
|
||||
if (result.success)
|
||||
Toast.Show(ToastIcon.Success, result.message);
|
||||
else
|
||||
Toast.Show(ToastIcon.Error, string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, result.message));
|
||||
}
|
||||
|
||||
public async void EnableOrDisableBot(Bot bot)
|
||||
{
|
||||
(bool success, string message) result;
|
||||
IApiRsp apiRsp = null;
|
||||
if (bot.KeepRunning)
|
||||
apiRsp = await asfService.BotStopAsync(bot.BotName);
|
||||
else
|
||||
apiRsp = await asfService.BotStartAsync(bot.BotName);
|
||||
result = (apiRsp.IsSuccess, apiRsp.Message);
|
||||
|
||||
if (!result.success)
|
||||
Toast.Show(ToastIcon.Error, string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, result.message));
|
||||
|
||||
ASFService.Current.SteamBotsSourceList.AddOrUpdate(bot);
|
||||
}
|
||||
|
||||
public async Task<(IReadOnlyDictionary<string, string>? UnusedKeys, IReadOnlyDictionary<string, string>? UsedKeys)> GetUsedAndUnusedKeys(Bot bot)
|
||||
{
|
||||
var r = await asfService.BotGetUsedAndUnusedKeysAsync(bot.BotName);
|
||||
if (r.IsSuccess && r.Content.TryGetValue(bot.BotName, out var response))
|
||||
return (response.UnusedKeys, response.UsedKeys);
|
||||
return default;
|
||||
}
|
||||
|
||||
public async void RedeemKeyBot(Bot bot, IOrderedDictionary keys)
|
||||
{
|
||||
var request = new BotGamesToRedeemInBackgroundRequest() { GamesToRedeemInBackground = (OrderedDictionary)keys };
|
||||
await asfService.BotRedeemKeyAsync(bot.BotName, request);
|
||||
}
|
||||
|
||||
public async Task<bool> ResetBotRedeemedKeysRecord(Bot bot)
|
||||
{
|
||||
var r = await asfService.BotResetRedeemedKeysRecordAsync(bot.BotName);
|
||||
return r.IsSuccess;
|
||||
}
|
||||
|
||||
public async void GoToBotSettings(Bot bot)
|
||||
{
|
||||
await Browser2.OpenAsync(IPCUrl + "/bot/" + bot.BotName + "/config", BrowserLaunchMode.External);
|
||||
}
|
||||
|
||||
public void EditBotFile(Bot bot)
|
||||
{
|
||||
var filePath = Path.Combine(SharedInfo.HomeDirectory, SharedInfo.ConfigDirectory, $"{bot.BotName}{SharedInfo.JsonConfigExtension}");
|
||||
IPlatformService.Instance.OpenFileByTextReader(filePath);
|
||||
}
|
||||
|
||||
public async void DeleteBot(Bot bot)
|
||||
{
|
||||
var s = await MessageBox.ShowAsync(BDStrings.ASF_DeleteBotTip, button: MessageBox.Button.OKCancel);
|
||||
if (s == MessageBox.Result.OK)
|
||||
{
|
||||
var result = await asfService.BotDeleteAsync(bot.BotName);
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
ASFService.Current.SteamBotsSourceList.Remove(bot);
|
||||
Toast.Show(ToastIcon.Success, BDStrings.ASF_DeleteBotSuccess);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OpenFolder(string tag)
|
||||
{
|
||||
if (!Enum.TryParse<EPathFolder>(tag, true, out var folderASFPath)) return;
|
||||
var folderASFPathValue = folderASFPath.GetFolderPath();
|
||||
IPlatformService.Instance.OpenFolder(folderASFPathValue);
|
||||
}
|
||||
|
||||
async void OpenBrowserCore(ActionItem tag)
|
||||
{
|
||||
var url = tag switch
|
||||
{
|
||||
ActionItem.Repo => "https://github.com/JustArchiNET/ArchiSteamFarm",
|
||||
ActionItem.Wiki => "https://github.com/JustArchiNET/ArchiSteamFarm/wiki/Home-zh-CN",
|
||||
ActionItem.ConfigGenerator => "https://justarchinet.github.io/ASF-WebConfigGenerator",
|
||||
ActionItem.WebConfig => IPCUrl + "/asf-config",
|
||||
ActionItem.WebAddBot => IPCUrl + "/bot/new",
|
||||
_ => IPCUrl,
|
||||
};
|
||||
|
||||
if (url.StartsWith(IPCUrl))
|
||||
{
|
||||
string? ipc_error = null;
|
||||
if (!ASFService.Current.IsASFRuning)
|
||||
{
|
||||
ipc_error = BDStrings.ASF_RequirRunASF;
|
||||
}
|
||||
else if (!ASF.IsReady)
|
||||
{
|
||||
// IPC 未启动前无法获取正确的端口号,会导致拼接的 URL 值不正确
|
||||
ipc_error = BDStrings.ASF_IPCIsReadyFalse;
|
||||
}
|
||||
if (ipc_error != null)
|
||||
{
|
||||
Toast.Show(ToastIcon.Error, ipc_error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
await Browser2.OpenAsync(url, BrowserLaunchMode.External);
|
||||
}
|
||||
|
||||
public void OpenBrowser(string? tag)
|
||||
{
|
||||
var tag_ = Enum.TryParse<ActionItem>(tag, out var @enum) ? @enum : default;
|
||||
OpenBrowserCore(tag_);
|
||||
}
|
||||
|
||||
public async void SetEncryptionKey_Click() => await asfService.SetEncryptionKeyAsync();
|
||||
|
||||
public void ShellMessageInput_Click() => ASFService.Current.ShellMessageInput();
|
||||
|
||||
public string IPCUrl => asfService.GetIPCUrl();
|
||||
}
|
||||
#endif
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
using ArchiSteamFarm.Steam;
|
||||
|
||||
namespace BD.WTTS.UI.ViewModels;
|
||||
|
||||
public sealed partial class ArchiSteamFarmPlusPageViewModel
|
||||
{
|
||||
/// <summary>
|
||||
/// 启动或停止 ASF 文本展示
|
||||
/// </summary>
|
||||
[Reactive]
|
||||
public string? RunOrStopText { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// ASF bots
|
||||
/// </summary>
|
||||
private readonly ReadOnlyObservableCollection<Bot> _SteamBots;
|
||||
|
||||
/// <summary>
|
||||
/// ASF bots
|
||||
/// </summary>
|
||||
public ReadOnlyObservableCollection<Bot> SteamBots => _SteamBots;
|
||||
|
||||
/// <summary>
|
||||
/// 通过配置文件导入 ASF Bot
|
||||
/// </summary>
|
||||
public ICommand SelectBotFiles { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 通过配置文件导入 ASF 全局配置
|
||||
/// </summary>
|
||||
public ICommand SelectGlobalFiles { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 选择 ASF 可执行文件路径
|
||||
/// </summary>
|
||||
public ICommand SelectASFExePath { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 启动或停止
|
||||
/// </summary>
|
||||
public ICommand RunOrStop { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 添加 ASF Bot
|
||||
/// </summary>
|
||||
public ICommand AddBot { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 刷新 ASF Bots
|
||||
/// </summary>
|
||||
public ICommand RefreshBots { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 打开 ASF WEBUI 控制台
|
||||
/// </summary>
|
||||
public ICommand OpenWebUIConsole { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 打开 ASF 文件夹
|
||||
/// </summary>
|
||||
public ICommand OpenASFFolder { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 设置 ASF 加密密钥
|
||||
/// </summary>
|
||||
public ICommand SetEncryptionKey { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 打开 ASF 相关网址
|
||||
/// </summary>
|
||||
public ICommand OpenASFBrowser { get; }
|
||||
|
||||
public ICommand ShellMessageInput { get; }
|
||||
|
||||
private bool _IsRedeemKeyDialogOpen;
|
||||
|
||||
public bool IsRedeemKeyDialogOpen
|
||||
{
|
||||
get => _IsRedeemKeyDialogOpen;
|
||||
set => this.RaiseAndSetIfChanged(ref _IsRedeemKeyDialogOpen, value);
|
||||
}
|
||||
}
|
||||
+295
@@ -0,0 +1,295 @@
|
||||
<spp:PageBase
|
||||
x:Class="BD.WTTS.UI.Views.Pages.ArchiSteamFarmPage"
|
||||
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:ms="https://steampp.net/settings"
|
||||
xmlns:s="https://steampp.net/services"
|
||||
xmlns:spp="https://steampp.net/ui"
|
||||
xmlns:ui="using:FluentAvalonia.UI.Controls"
|
||||
Title="{Binding Name, Source={x:Static s:Plugin.Instance}, Mode=OneWay}"
|
||||
d:DesignHeight="450"
|
||||
d:DesignWidth="800"
|
||||
x:CompileBindings="True"
|
||||
x:DataType="spp:ArchiSteamFarmPlusPageViewModel"
|
||||
Description="{Binding Description, Source={x:Static s:Plugin.Instance}, Mode=OneWay}"
|
||||
Subtitle="{Binding Author, Source={x:Static s:Plugin.Instance}, Mode=OneWay, Converter={StaticResource StringFormatConverter}, ConverterParameter=Plugin_Author}"
|
||||
mc:Ignorable="d">
|
||||
<spp:PageBase.PreviewImage>
|
||||
<ui:ImageIconSource Source="{Binding Icon, Source={x:Static s:Plugin.Instance}, Mode=OneWay, Converter={StaticResource BitmapAssetValueConverter}}" />
|
||||
</spp:PageBase.PreviewImage>
|
||||
<spp:PageBase.ActionContent>
|
||||
<StackPanel Orientation="Horizontal" Spacing="2">
|
||||
<Button
|
||||
Padding="8,4"
|
||||
Command="{Binding RunOrStop}"
|
||||
DockPanel.Dock="Right"
|
||||
Theme="{StaticResource TransparentButton}">
|
||||
<Panel>
|
||||
<Viewbox
|
||||
Width="16"
|
||||
Height="16"
|
||||
HorizontalAlignment="Left"
|
||||
IsVisible="{ReflectionBinding Source={x:Static s:ASFService.Current},
|
||||
Path=!IsASFRuning}">
|
||||
<ui:SymbolIcon Symbol="Play" />
|
||||
</Viewbox>
|
||||
<Viewbox
|
||||
Width="16"
|
||||
Height="16"
|
||||
HorizontalAlignment="Left"
|
||||
IsVisible="{ReflectionBinding Source={x:Static s:ASFService.Current},
|
||||
Path=IsASFRuning}">
|
||||
<ui:SymbolIcon Symbol="Pause" />
|
||||
</Viewbox>
|
||||
<TextBlock
|
||||
Margin="28,4,0,4"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
IsVisible="{ReflectionBinding Source={x:Static s:ASFService.Current},
|
||||
Path=!IsASFRuning}"
|
||||
Text="{Binding Path=Res.ASF_Start, Mode=OneWay, Source={x:Static spp:Strings.ASF_Start}}" />
|
||||
|
||||
<TextBlock
|
||||
Margin="28,4,0,4"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
IsVisible="{ReflectionBinding Source={x:Static s:ASFService.Current},
|
||||
Path=IsASFRuning}"
|
||||
Text="{Binding Path=Res.ASF_Stop, Mode=OneWay, Source={x:Static spp:Strings.ASF_Stop}}" />
|
||||
</Panel>
|
||||
</Button>
|
||||
<Button
|
||||
Padding="8,4"
|
||||
Command="{Binding OpenASFBrowser}"
|
||||
CommandParameter="WebAddBot"
|
||||
DockPanel.Dock="Right"
|
||||
Theme="{StaticResource TransparentButton}">
|
||||
<Panel>
|
||||
<Viewbox
|
||||
Width="16"
|
||||
Height="16"
|
||||
HorizontalAlignment="Left">
|
||||
<ui:SymbolIcon Symbol="Add" />
|
||||
</Viewbox>
|
||||
<TextBlock
|
||||
Margin="28,4,0,4"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Text="新增 Bot" />
|
||||
</Panel>
|
||||
</Button>
|
||||
<Button
|
||||
Padding="8,4"
|
||||
Command="{Binding RefreshBots}"
|
||||
DockPanel.Dock="Right"
|
||||
Theme="{StaticResource TransparentButton}">
|
||||
<Panel>
|
||||
<Viewbox
|
||||
Width="16"
|
||||
Height="16"
|
||||
HorizontalAlignment="Left">
|
||||
<ui:SymbolIcon Symbol="Refresh" />
|
||||
</Viewbox>
|
||||
<TextBlock
|
||||
Margin="28,4,0,4"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Text="刷新 Bot" />
|
||||
</Panel>
|
||||
</Button>
|
||||
<ToggleButton
|
||||
Padding="8,4"
|
||||
DockPanel.Dock="Right"
|
||||
IsChecked="{Binding $parent[spp:PageBase].IsPaneOpen, Mode=TwoWay}"
|
||||
Theme="{StaticResource TransparentToggleButton}">
|
||||
<Panel>
|
||||
<Viewbox
|
||||
Width="16"
|
||||
Height="16"
|
||||
HorizontalAlignment="Left">
|
||||
<ui:SymbolIcon Symbol="Settings" />
|
||||
</Viewbox>
|
||||
<TextBlock
|
||||
Margin="28,4,0,4"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Text="设置" />
|
||||
</Panel>
|
||||
</ToggleButton>
|
||||
<DropDownButton
|
||||
Padding="8"
|
||||
HorizontalContentAlignment="Center"
|
||||
VerticalContentAlignment="Center"
|
||||
Content="{StaticResource More}"
|
||||
FontFamily="{StaticResource SymbolThemeFontFamily}"
|
||||
FontSize="20"
|
||||
Theme="{StaticResource TransparentButton}">
|
||||
<DropDownButton.Flyout>
|
||||
<ui:FAMenuFlyout Placement="BottomEdgeAlignedRight">
|
||||
<ui:MenuFlyoutItem
|
||||
Command="{Binding OpenASFBrowser}"
|
||||
CommandParameter="Repo"
|
||||
Text="Repo" />
|
||||
<ui:MenuFlyoutSeparator />
|
||||
<ui:MenuFlyoutItem
|
||||
Command="{Binding OpenASFBrowser}"
|
||||
CommandParameter="Wiki"
|
||||
Text="Wiki" />
|
||||
<ui:MenuFlyoutSeparator />
|
||||
<ui:MenuFlyoutItem
|
||||
Command="{Binding OpenASFBrowser}"
|
||||
CommandParameter="ConfigGenerator"
|
||||
Text="ConfigGenerator" />
|
||||
</ui:FAMenuFlyout>
|
||||
</DropDownButton.Flyout>
|
||||
</DropDownButton>
|
||||
</StackPanel>
|
||||
</spp:PageBase.ActionContent>
|
||||
|
||||
<spp:PageBase.PaneContent>
|
||||
<StackPanel Margin="15,20" Spacing="20">
|
||||
<spp:OptionsDisplayItem Description="{Binding Source={x:Static ms:ASFSettings.ArchiSteamFarmExePath}, Path=Value, Mode=OneWay, Converter={StaticResource StringOmitConverter}, ConverterParameter=15}" Header="ASF 文件路径">
|
||||
<spp:OptionsDisplayItem.Icon>
|
||||
<ui:FontIcon FontFamily="Segoe Fluent Icons" Glyph="" />
|
||||
</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="" />
|
||||
</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="" />
|
||||
</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="" />
|
||||
</spp:OptionsDisplayItem.Icon>
|
||||
<spp:OptionsDisplayItem.ActionButton>
|
||||
<ui:FAComboBox IsEditable="True" Text="{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="" />
|
||||
</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="" />
|
||||
</spp:OptionsDisplayItem.Icon>
|
||||
<spp:OptionsDisplayItem.ActionButton>
|
||||
<ui:FAComboBox IsEditable="True" Text="{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="" />
|
||||
</spp:OptionsDisplayItem.Icon>
|
||||
<spp:OptionsDisplayItem.ActionButton>
|
||||
<ui:FAComboBox IsEditable="True" Text="{Binding Source={x:Static ms:ASFSettings.ConsoleFontSize}, Path=Value, Mode=TwoWay}" />
|
||||
</spp:OptionsDisplayItem.ActionButton>
|
||||
</spp:OptionsDisplayItem>
|
||||
|
||||
|
||||
|
||||
</StackPanel>
|
||||
</spp:PageBase.PaneContent>
|
||||
<spp:ContentLoader IsLoading="False">
|
||||
<StackPanel Orientation="Vertical" Spacing="2">
|
||||
<StackPanel Orientation="Horizontal" Spacing="2">
|
||||
<Button
|
||||
Width="180"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Command="{Binding SelectBotFiles}"
|
||||
Content="选择 Bot 配置文件导入" />
|
||||
<Button
|
||||
Width="180"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Command="{Binding SelectGlobalFiles}"
|
||||
Content="选择全局配置文件导入" />
|
||||
<Button
|
||||
Width="180"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Command="{Binding OpenWebUIConsole}"
|
||||
Content="打开 WebUI 控制台" />
|
||||
<Button
|
||||
Width="180"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Command="{Binding SetEncryptionKey}"
|
||||
Content="SetEncryptionKey" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Orientation="Horizontal" Spacing="2">
|
||||
<Button
|
||||
Width="180"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Command="{Binding OpenASFFolder}"
|
||||
CommandParameter="config"
|
||||
Content="配置文件文件夹" />
|
||||
<Button
|
||||
Width="180"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Command="{Binding OpenASFFolder}"
|
||||
CommandParameter="plugin"
|
||||
Content="插件文件夹" />
|
||||
<Button
|
||||
Width="180"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Command="{Binding OpenASFFolder}"
|
||||
CommandParameter="Logs"
|
||||
Content="日志文件夹" />
|
||||
<Button
|
||||
Width="180"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Command="{Binding OpenASFFolder}"
|
||||
CommandParameter="www"
|
||||
Content="WEBUI 文件夹" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Spacing="2">
|
||||
<Label
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Content="控制台输入" />
|
||||
<TextBox Width="200" Text="{Binding Source={x:Static s:ASFService.Current}, Path=ConsoleLogInput, Mode=TwoWay}" />
|
||||
<Button
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Command="{Binding ShellMessageInput}"
|
||||
Content="发送" />
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock Text="{Binding Source={x:Static s:ASFService.Current}, Path=ConsoleLogText, Mode=TwoWay}" />
|
||||
</StackPanel>
|
||||
</spp:ContentLoader>
|
||||
</spp:PageBase>
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.ReactiveUI;
|
||||
|
||||
namespace BD.WTTS.UI.Views.Pages;
|
||||
|
||||
public partial class ArchiSteamFarmPage : PageBase<ArchiSteamFarmPlusPageViewModel>
|
||||
{
|
||||
public ArchiSteamFarmPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContext ??= new ArchiSteamFarmPlusPageViewModel();
|
||||
}
|
||||
|
||||
protected override void OnLoaded(RoutedEventArgs e)
|
||||
{
|
||||
base.OnLoaded(e);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,8 @@ public static class ASF
|
||||
[PublicAPI]
|
||||
public static readonly ArchiLogger ArchiLogger = new(SharedInfo.ASF);
|
||||
|
||||
public static bool IsReady { get; set; }
|
||||
|
||||
public enum EUserInputType : byte
|
||||
{
|
||||
None,
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ArchiSteamFarm.IPC;
|
||||
|
||||
public class IPCConfig
|
||||
{
|
||||
public IPCConfig(Uri uri) { Kestrel = new(uri); }
|
||||
|
||||
public Kestrel Kestrel { get; private set; }
|
||||
}
|
||||
|
||||
public class Kestrel
|
||||
{
|
||||
public Kestrel(Uri uri) { Endpoints = new(uri); }
|
||||
|
||||
public Endpoints Endpoints { get; private set; }
|
||||
}
|
||||
|
||||
public class Endpoints
|
||||
{
|
||||
public Endpoints(Uri uri) { Http = new(uri); }
|
||||
|
||||
public Http Http { get; private set; }
|
||||
}
|
||||
|
||||
public class Http
|
||||
{
|
||||
public Http(Uri uri) { Url = uri; }
|
||||
|
||||
public Uri Url { get; private set; }
|
||||
}
|
||||
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// |
|
||||
// Copyright 2015-2023 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
// |
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// |
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// |
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using ArchiSteamFarm.Helpers;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ArchiSteamFarm.IPC.Requests;
|
||||
|
||||
[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
|
||||
public sealed class ASFEncryptRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Encryption method used for encrypting this string.
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
[Required]
|
||||
public ArchiCryptoHelper.ECryptoMethod CryptoMethod { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// String to encrypt with provided <see cref="CryptoMethod" />.
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
[Required]
|
||||
public string StringToEncrypt { get; set; } = "";
|
||||
|
||||
[JsonConstructor]
|
||||
public ASFEncryptRequest() { }
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// |
|
||||
// Copyright 2015-2023 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
// |
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// |
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// |
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using ArchiSteamFarm.Helpers;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ArchiSteamFarm.IPC.Requests;
|
||||
|
||||
[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
|
||||
public sealed class ASFHashRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Hashing method used for hashing this string.
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
[Required]
|
||||
public ArchiCryptoHelper.EHashingMethod HashingMethod { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// String to hash with provided <see cref="HashingMethod" />.
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
[Required]
|
||||
public string StringToHash { get; set; } = "";
|
||||
|
||||
[JsonConstructor]
|
||||
public ASFHashRequest() { }
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// |
|
||||
// Copyright 2015-2023 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
// |
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// |
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// |
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using ArchiSteamFarm.Storage;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ArchiSteamFarm.IPC.Requests;
|
||||
|
||||
[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
|
||||
public sealed class ASFRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// ASF's global config structure.
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
[Required]
|
||||
public GlobalConfig GlobalConfig { get; set; } = new();
|
||||
|
||||
[JsonConstructor]
|
||||
public ASFRequest() { }
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// |
|
||||
// Copyright 2015-2023 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
// |
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// |
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// |
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using System.Collections.Specialized;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ArchiSteamFarm.IPC.Requests;
|
||||
|
||||
[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
|
||||
public sealed class BotGamesToRedeemInBackgroundRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// A string-string map that maps cd-key to redeem (key) to its name (value).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Key in the map must be a valid and unique Steam cd-key.
|
||||
/// Value in the map must be a non-null and non-empty name of the key (e.g. game's name, but can be anything).
|
||||
/// </remarks>
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
[Required]
|
||||
public OrderedDictionary GamesToRedeemInBackground { get; set; } = new();
|
||||
|
||||
[JsonConstructor]
|
||||
public BotGamesToRedeemInBackgroundRequest() { }
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// |
|
||||
// Copyright 2015-2023 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
// |
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// |
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// |
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using ArchiSteamFarm.Core;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ArchiSteamFarm.IPC.Requests;
|
||||
|
||||
[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
|
||||
public sealed class BotInputRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies the type of the input.
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
public ASF.EUserInputType Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the value for given input type (declared in <see cref="Type" />)
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
public string Value { get; private set; } = "";
|
||||
|
||||
[JsonConstructor]
|
||||
public BotInputRequest() { }
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// |
|
||||
// Copyright 2015-2023 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
// |
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// |
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// |
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ArchiSteamFarm.IPC.Requests;
|
||||
|
||||
[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
|
||||
public sealed class BotPauseRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies if pause is permanent or temporary (default).
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
public bool Permanent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Specifies automatic resume action in given seconds. Default value of 0 disables automatic resume.
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
public ushort ResumeInSeconds { get; private set; } = 0;
|
||||
|
||||
[JsonConstructor]
|
||||
public BotPauseRequest() { }
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// |
|
||||
// Copyright 2015-2023 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
// |
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// |
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// |
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using System.Collections.Immutable;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ArchiSteamFarm.IPC.Requests;
|
||||
|
||||
[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
|
||||
public sealed class BotRedeemRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// A collection (set) of keys to redeem.
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
[Required]
|
||||
public ImmutableHashSet<string> KeysToRedeem { get; set; } = ImmutableHashSet<string>.Empty;
|
||||
|
||||
[JsonConstructor]
|
||||
public BotRedeemRequest() { }
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// |
|
||||
// Copyright 2015-2023 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
// |
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// |
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// |
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ArchiSteamFarm.IPC.Requests;
|
||||
|
||||
[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
|
||||
public sealed class BotRenameRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies the new name for the bot. The new name can't be "ASF", neither the one used by any existing bot.
|
||||
/// </summary>
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
[Required]
|
||||
public string NewName { get; set; } = "";
|
||||
|
||||
[JsonConstructor]
|
||||
public BotRenameRequest() { }
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user