Compare commits

...

11 Commits

Author SHA1 Message Date
wangyingpan bc19a02f4f 🐛 修复替换令牌时恢复代码不显示的问题
调整添加令牌时的提示信息
2024-04-29 18:07:05 +08:00
Aigio Liu d59d63d57e 🎨 vipEndTimeString 2024-04-29 16:13:40 +08:00
yingpanwang 9ad6e8fa8d Fix/authenticator verifycode UI (#3313)
* 🐛 修复添加令牌邮箱/短信验证ui显示

* 🎨 删除绑定手机号步骤
🐛 修复替换令牌逻辑验证码信息展示错误的问题

* 🐛 修复添加令牌邮箱/短信验证ui显示

* 🎨 删除绑定手机号步骤
🐛 修复替换令牌逻辑验证码信息展示错误的问题

* ✨ 替换令牌中添加绑定手机号窜哦做
2024-04-29 15:27:28 +08:00
Aigio Liu 45ef15b220 🎨 VipEndTimeString 2024-04-29 15:04:47 +08:00
Aigio Liu 25dfd1f888 🐛 VipEndTimeString 2024-04-29 15:01:57 +08:00
Aigio Liu 0495cd3079 💚 CI 2024-04-29 13:14:45 +08:00
Aigio Liu ea9c45d78b 🎨 VipEndTimeString 2024-04-29 13:11:51 +08:00
Aigio Liu 4427fd1a5f 🐛 VipEndTimeString 2024-04-29 12:18:03 +08:00
RMBGAME edf3c3a72c ⬆️ SteamClient 2024-04-29 12:10:10 +08:00
Aigio Liu 55490d2351 🐛 VipEndTimeString 2024-04-29 11:59:22 +08:00
Aigio Liu 17ae6655b4 🐛 VipEndTimeString 2024-04-29 11:55:34 +08:00
13 changed files with 630 additions and 262 deletions
+5 -5
View File
@@ -68,19 +68,19 @@ jobs:
run: dotnet --info run: dotnet --info
- name: Build BD.WTTS.Client.AppHost - name: Build BD.WTTS.Client.AppHost
run: dotnet build -c Release src\BD.WTTS.Client.AppHost\BD.WTTS.Client.AppHost.csproj --nologo -v q /property:WarningLevel=1 run: dotnet build -c Release src\BD.WTTS.Client.AppHost\BD.WTTS.Client.AppHost.csproj --nologo -v q --property:WarningLevel=1;DebugType=pdbonly
- name: Build BD.WTTS.Client.Plugins.Accelerator.ReverseProxy - name: Build BD.WTTS.Client.Plugins.Accelerator.ReverseProxy
run: dotnet build -c Release src\BD.WTTS.Client.Plugins.Accelerator.ReverseProxy\BD.WTTS.Client.Plugins.Accelerator.ReverseProxy.csproj --nologo -v q /property:WarningLevel=1 run: dotnet build -c Release src\BD.WTTS.Client.Plugins.Accelerator.ReverseProxy\BD.WTTS.Client.Plugins.Accelerator.ReverseProxy.csproj --nologo -v q --property:WarningLevel=1;DebugType=pdbonly
- name: Build BD.WTTS.Client.Avalonia.App - name: Build BD.WTTS.Client.Avalonia.App
run: dotnet build -c Release src\BD.WTTS.Client.Avalonia.App\BD.WTTS.Client.Avalonia.App.csproj --nologo -v q /property:WarningLevel=1 run: dotnet build -c Release src\BD.WTTS.Client.Avalonia.App\BD.WTTS.Client.Avalonia.App.csproj --nologo -v q --property:WarningLevel=1;DebugType=pdbonly
- name: Build BD.WTTS.Client.Avalonia.Designer.HostApp - name: Build BD.WTTS.Client.Avalonia.Designer.HostApp
run: dotnet build -c Release src\BD.WTTS.Client.Avalonia.Designer.HostApp\BD.WTTS.Client.Avalonia.Designer.HostApp.csproj --nologo -v q /property:WarningLevel=1 run: dotnet build -c Release src\BD.WTTS.Client.Avalonia.Designer.HostApp\BD.WTTS.Client.Avalonia.Designer.HostApp.csproj --nologo -v q --property:WarningLevel=1;DebugType=pdbonly
- name: Test - name: Test
run: dotnet test src/BD.WTTS.UnitTest/BD.WTTS.UnitTest.csproj -c Release -p:GeneratePackageOnBuild=false --nologo -v q /property:WarningLevel=1 run: dotnet test src/BD.WTTS.UnitTest/BD.WTTS.UnitTest.csproj -c Release -p:GeneratePackageOnBuild=false --nologo -v q --property:WarningLevel=1;DebugType=pdbonly
# release: # release:
# name: Release # name: Release
@@ -52,8 +52,10 @@ public sealed partial class GameAcceleratorService
[Reactive] [Reactive]
public DateTime? VipEndTime { get; set; } public DateTime? VipEndTime { get; set; }
const string VipEndTimeStringDef = "新用户免费试用 2 天";
[Reactive] [Reactive]
public string? VipEndTimeString { get; set; } public string? VipEndTimeString { get; set; } = VipEndTimeStringDef;
GameAcceleratorService() GameAcceleratorService()
{ {
@@ -177,54 +179,51 @@ public sealed partial class GameAcceleratorService
.ObserveOn(RxApp.MainThreadScheduler) .ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(async x => .Subscribe(async x =>
{ {
if (string.IsNullOrWhiteSpace(x?.WattOpenId)) string vipEndTimeString = VipEndTimeStringDef;
return; try
var vipEndTimeResult = await IMicroServiceClient.Instance.Manage.GetXunYouVipEndTime();
if (vipEndTimeResult == null)
{ {
Log.Error(nameof(GameAcceleratorService), if (string.IsNullOrWhiteSpace(x?.WattOpenId))
"XunYouSDK.GetVipEndTime is null.");
return;
}
if (!vipEndTimeResult.IsSuccess || vipEndTimeResult.Content == null)
{
Toast.Show(ToastIcon.Error, "获取会员时间失败");
return;
}
if (vipEndTimeResult.Content.Code == XunYouBaseResponseCode.成功)
{
var etime = vipEndTimeResult.Content.Data?.ExpireTime;
if (etime.HasValue)
{ {
VipEndTime = etime.Value.ToDateTime(UnixTimestampType.Seconds); return;
//var acc_order = (await IMicroServiceClient.Instance.Ordering.GetUserOrderCount([OrderStatus.Paid, OrderStatus.Completed], OrderBusinessType.XunYouOrder)).Content; }
//if (acc_order <= 0)
//{
// if (VipEndTime.Value.AddDays(365).Date == DateTimeOffset.Now.Date)
// VipEndTimeString = "试用时长到期";
// else
// VipEndTimeString = "新用户试用2天";
//}
//else
//{
// VipEndTimeString = $"游戏加速会员有效期 {VipEndTime.Value:yyyy-MM-dd}";
//}
if (VipEndTime.Value.AddDays(365).Date == DateTimeOffset.Now.Date) var vipEndTimeResult = await IMicroServiceClient.Instance.Manage.GetXunYouVipEndTime();
VipEndTimeString = "新用户试用2天"; if (vipEndTimeResult == null)
else {
VipEndTimeString = $"游戏加速会员有效期 {VipEndTime.Value:yyyy-MM-dd}"; Log.Error(nameof(GameAcceleratorService),
"XunYouSDK.GetVipEndTime is null.");
return;
}
if (!vipEndTimeResult.IsSuccess || vipEndTimeResult.Content == null)
{
Toast.Show(ToastIcon.Error, "获取会员时间失败");
return;
}
if (vipEndTimeResult.Content.Code == XunYouBaseResponseCode.成功)
{
var etime = vipEndTimeResult.Content.Data?.ExpireTime;
if (etime.HasValue)
{
VipEndTime = etime.Value.ToDateTime(UnixTimestampType.Seconds);
if (VipEndTime.Value > DateTime.Now)
{
vipEndTimeString = $"游戏加速会员有效期 {VipEndTime.Value:yyyy-MM-dd}";
}
}
}
else
{
Log.Error(nameof(GameAcceleratorService),
"XunYouSDK.GetVipEndTime is fail, message: {message}, code: {code}.",
vipEndTimeResult.Content.Message,
vipEndTimeResult.Content.Code);
} }
} }
else finally
{ {
Log.Error(nameof(GameAcceleratorService), VipEndTimeString = vipEndTimeString;
"XunYouSDK.GetVipEndTime is fail, message: {message}, code: {code}.",
vipEndTimeResult.Content.Message,
vipEndTimeResult.Content.Code);
} }
}); });
@@ -0,0 +1,162 @@
using WinAuth;
using AppResources = BD.WTTS.Client.Resources.Strings;
namespace BD.WTTS.UI.ViewModels;
/// <summary>
/// 添加 Steam 账号手机号页面 VM
/// </summary>
public class AddSteamAccountPhoneNumberPageViewModel : WindowViewModel
{
#region 步骤 Index 定义
const int TAB_INDEX_BINDING = 0;
const int TAB_INDEX_CONFIRMATION_Email = 1;
const int TAB_INDEX_CONFIRMATION_SMS = 2;
#endregion 步骤 Index 定义
/// <summary>
/// 手机号文本
/// </summary>
[Reactive]
public string? PhoneNumberText { get; set; }
/// <summary>
/// 验证码文本
/// </summary>
[Reactive]
public string? CodeText { get; set; }
/// <summary>
/// 步骤 Index
/// </summary>
[Reactive]
public int SelectIndex { get; set; }
/// <summary>
/// 是否显示加载中
/// </summary>
[Reactive]
public bool IsLoading { get; set; }
private readonly SteamAuthenticator.EnrollState _enrollState;
private readonly SteamAuthenticator _steamAuthenticator;
public AddSteamAccountPhoneNumberPageViewModel(
SteamAuthenticator.EnrollState enrollState,
SteamAuthenticator steamAuthenticator
)
{
SelectIndex = TAB_INDEX_BINDING;
_steamAuthenticator = steamAuthenticator;
_enrollState = enrollState;
}
/// <summary>
/// 开始绑定手机号
/// </summary>
/// <returns></returns>
public async Task StartBindingAsync()
{
if (IsLoading)
{
Toast.Show(ToastIcon.Warning, AppResources.Warning_DoNotOperateFrequently);
return;
}
if (string.IsNullOrEmpty(PhoneNumberText))
{
Toast.Show(ToastIcon.Warning, AppResources.Warning_PleaseEnterTel);
return;
}
IsLoading = true;
try
{
string? msg = await _steamAuthenticator.AddPhoneNumberAsync(_enrollState, PhoneNumberText);
Toast.Show(ToastIcon.Info, msg ?? string.Empty);
if (_enrollState.RequiresEmailConfirmPhone)
{
SelectIndex = TAB_INDEX_CONFIRMATION_Email;
}
else
{
SelectIndex = TAB_INDEX_CONFIRMATION_SMS;
}
}
finally
{
IsLoading = false;
}
}
/// <summary>
/// 确认邮箱链接
/// </summary>
/// <returns></returns>
public async Task ConfirmBindingEmailAsync()
{
if (IsLoading)
{
Toast.Show(ToastIcon.Warning, AppResources.Warning_DoNotOperateFrequently);
return;
}
if (string.IsNullOrEmpty(PhoneNumberText))
{
Toast.Show(ToastIcon.Warning, AppResources.Warning_PleaseEnterTel);
return;
}
IsLoading = true;
try
{
var reslut = await _steamAuthenticator.AddPhoneNumberAsync(_enrollState, PhoneNumberText!);
if (_enrollState.RequiresEmailConfirmPhone == false && reslut == null)
{
SelectIndex = TAB_INDEX_CONFIRMATION_SMS;
}
}
finally
{
IsLoading = false;
}
}
/// <summary>
/// 验收短信验证码
/// </summary>
/// <returns></returns>
public async Task VerifyAccountPhoneWithCodeAsync()
{
if (string.IsNullOrEmpty(PhoneNumberText))
{
Toast.Show(ToastIcon.Warning, AppResources.Warning_PleaseEnterTel);
return;
}
if (string.IsNullOrEmpty(CodeText))
{
Toast.Show(ToastIcon.Warning, AppResources.Error_PleaseEnterTelCode);
return;
}
var verified = await _steamAuthenticator
.VerifyPhoneNumberAsync(PhoneNumberText!, CodeText!, _enrollState.AccessToken!);
if (verified)
{
Close?.Invoke(verified);
}
}
}
@@ -1,16 +1,22 @@
using AppResources = BD.WTTS.Client.Resources.Strings;
using BD.SteamClient.Models; using BD.SteamClient.Models;
using BD.SteamClient.Services; using BD.SteamClient.Services;
using BD.WTTS.UI.Views.Controls;
using WinAuth; using WinAuth;
using AppResources = BD.WTTS.Client.Resources.Strings;
#if !ANDROID #if !ANDROID
using ToastLength = BD.Common.Enums.ToastLength;
#endif #endif
namespace BD.WTTS.UI.ViewModels; namespace BD.WTTS.UI.ViewModels;
public sealed partial class SteamLoginImportPageViewModel : ViewModelBase public sealed partial class SteamLoginImportPageViewModel : ViewModelBase
{ {
const int TAB_INDEX_LOGIN = 0;
const int TAB_INDEX_LOGINCONFIRM = 1;
const int TAB_INDEX_VERIFYCODE = 2;
const int TAB_INDEX_DONE = 3;
public static string Name => AppResources.Auth_SteamLoginImport; public static string Name => AppResources.Auth_SteamLoginImport;
readonly ISteamAccountService _steamAccountService = Ioc.Get<ISteamAccountService>(); readonly ISteamAccountService _steamAccountService = Ioc.Get<ISteamAccountService>();
@@ -94,7 +100,7 @@ public sealed partial class SteamLoginImportPageViewModel : ViewModelBase
{ {
if (string.IsNullOrEmpty(PhoneCodeText)) if (string.IsNullOrEmpty(PhoneCodeText))
{ {
Toast.Show(ToastIcon.Error, AppResources.Error_PleaseEnterTelCode); Toast.Show(ToastIcon.Error, AppResources.Error_PleaseEnterCode);
return false; return false;
} }
else else
@@ -115,7 +121,7 @@ public sealed partial class SteamLoginImportPageViewModel : ViewModelBase
Created = DateTimeOffset.Now, Created = DateTimeOffset.Now,
}; };
await AuthenticatorHelper.SaveAuthenticator(iADTO); await AuthenticatorHelper.SaveAuthenticator(iADTO);
SelectIndex = 4; SelectIndex = TAB_INDEX_DONE;
} }
/// <summary> /// <summary>
@@ -136,15 +142,23 @@ public sealed partial class SteamLoginImportPageViewModel : ViewModelBase
if (_enrollState.NoPhoneNumber == true) if (_enrollState.NoPhoneNumber == true)
{ {
_enrollState.Error = null; _enrollState.Error = null;
SelectIndex = 2; //SelectIndex = 2;
// 正常情况下不会走到这里,因为已经不需要绑定手机的步骤了
return;
} }
//导入最后一步,需要账号绑定的手机验证码确认 // 导入最后一步,需要账号绑定的手机验证码确认
// 2024-04-23 Steam绑定令牌不强制手机绑定 可以输入 邮箱者手机验证码
if (_enrollState.RequiresActivation == true) if (_enrollState.RequiresActivation == true)
{ {
// 查询账号手机号绑定状态
// IsVerifyAccountPhone = await _steamAccountService.CheckAccountPhoneStatus(_enrollState.AccessToken!) ?? false;
await CheckAccountPhoneStatus();
_enrollState.Error = null; _enrollState.Error = null;
RevocationCodeText = _enrollState.RevocationCode; RevocationCodeText = _enrollState.RevocationCode;
SelectIndex = 3; SelectIndex = TAB_INDEX_VERIFYCODE;
} }
} }
@@ -161,7 +175,7 @@ public sealed partial class SteamLoginImportPageViewModel : ViewModelBase
//Toast.Show(ToastIcon.Error, Strings.LocalAuth_SteamUser_Requires2FA); //Toast.Show(ToastIcon.Error, Strings.LocalAuth_SteamUser_Requires2FA);
//Reset(); //Reset();
Requires2FA = _steamLoginState.Requires2FA; Requires2FA = _steamLoginState.Requires2FA;
SelectIndex = 1; SelectIndex = TAB_INDEX_LOGINCONFIRM;
return false; return false;
} }
//需要邮箱验证码 //需要邮箱验证码
@@ -170,7 +184,7 @@ public sealed partial class SteamLoginImportPageViewModel : ViewModelBase
EmailDomainText = string.IsNullOrEmpty(_steamLoginState.EmailDomain) == false EmailDomainText = string.IsNullOrEmpty(_steamLoginState.EmailDomain) == false
? $"******@{_steamLoginState.EmailDomain}" ? $"******@{_steamLoginState.EmailDomain}"
: string.Empty; : string.Empty;
SelectIndex = 1; SelectIndex = TAB_INDEX_LOGINCONFIRM;
return false; return false;
} }
else if (!string.IsNullOrEmpty(_steamLoginState.Message)) else if (!string.IsNullOrEmpty(_steamLoginState.Message))
@@ -189,6 +203,12 @@ public sealed partial class SteamLoginImportPageViewModel : ViewModelBase
return !string.IsNullOrEmpty(_steamLoginState.AccessToken); return !string.IsNullOrEmpty(_steamLoginState.AccessToken);
} }
async ValueTask CheckAccountPhoneStatus()
{
// 查询账号手机号绑定状态
IsVerifyAccountPhone = await _steamAccountService.CheckAccountPhoneStatus(_enrollState.AccessToken!) ?? false;
}
public async Task LoginSteamImport() public async Task LoginSteamImport()
{ {
if (IsLoading) if (IsLoading)
@@ -200,7 +220,7 @@ public sealed partial class SteamLoginImportPageViewModel : ViewModelBase
try try
{ {
if (SelectIndex == 0) if (SelectIndex == TAB_INDEX_LOGIN)
{ {
await LoginSteamFirstAsync(); await LoginSteamFirstAsync();
} }
@@ -224,22 +244,63 @@ public sealed partial class SteamLoginImportPageViewModel : ViewModelBase
//已有令牌情况下执行替换令牌逻辑 //已有令牌情况下执行替换令牌逻辑
if (_enrollState.ReplaceAuth) if (_enrollState.ReplaceAuth)
{ {
if (SelectIndex == 1 && await steamAuthenticator.RemoveAuthenticatorViaChallengeStartSync(_enrollState.AccessToken!)) if (SelectIndex == TAB_INDEX_LOGINCONFIRM && await steamAuthenticator.RemoveAuthenticatorViaChallengeStartSync(_enrollState.AccessToken!))
{ {
SelectIndex = 3; await CheckAccountPhoneStatus();
SelectIndex = TAB_INDEX_VERIFYCODE;
if (!IsVerifyAccountPhone)
{
Toast.Show(ToastIcon.Warning, "只绑定邮箱的情况下无法直接替换令牌");
// 弹出绑定手机号流程
var added = await IWindowManager.Instance.ShowTaskDialogAsync(
viewModel: new AddSteamAccountPhoneNumberPageViewModel(_enrollState, steamAuthenticator),
pageContent: new AddSteamAccountPhoneNumberPage(),
isCancelButton: false,
isOkButton: false,
isRetryButton: false
);
// 查询账号手机号绑定状态
await CheckAccountPhoneStatus();
// 如果通过弹出的绑定手机号绑定成功 开始执行替换令牌
if (added && IsVerifyAccountPhone)
{
/*
* 绑定手机号会发送验证码
* 执行开始替换令牌操作也会发送验证码
* 如果两个操作间隔太短会导致 Steam 不发送验证码
*/
await Task.Delay(TimeSpan.FromSeconds(30));
await steamAuthenticator.RemoveAuthenticatorViaChallengeStartSync(_enrollState.AccessToken!);
}
// 取消了绑定手机号流程 无法执行替换令牌操作
else
{
SelectIndex = TAB_INDEX_LOGIN;
}
return;
}
return; return;
} }
else if (SelectIndex == 3) else if (SelectIndex == TAB_INDEX_VERIFYCODE)
{ {
if (string.IsNullOrEmpty(PhoneCodeText)) if (string.IsNullOrEmpty(PhoneCodeText))
{ {
Toast.Show(ToastIcon.Error, Strings.Error_PleaseEnterTelCode); Toast.Show(ToastIcon.Error, Strings.Error_PleaseEnterCode);
return; return;
} }
if (await steamAuthenticator.RemoveAuthenticatorViaChallengeContinueSync(PhoneCodeText, _enrollState.AccessToken!)) if (await steamAuthenticator.RemoveAuthenticatorViaChallengeContinueSync(PhoneCodeText, _enrollState.AccessToken!))
{ {
await SaveAuthenticatorAsync(); await SaveAuthenticatorAsync();
RevocationCodeText = steamAuthenticator.RecoveryCode;
return; return;
} }
} }
@@ -319,4 +380,4 @@ public sealed partial class SteamLoginImportPageViewModel : ViewModelBase
IsLoading = false; IsLoading = false;
} }
} }
} }
@@ -1,9 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BD.WTTS.UI.ViewModels; namespace BD.WTTS.UI.ViewModels;
public sealed partial class SteamLoginImportPageViewModel public sealed partial class SteamLoginImportPageViewModel
@@ -67,4 +61,10 @@ public sealed partial class SteamLoginImportPageViewModel
[Reactive] [Reactive]
public string? PhoneNumberText { get; set; } public string? PhoneNumberText { get; set; }
}
/// <summary>
/// 是否已验证账号的手机号
/// </summary>
[Reactive]
public bool IsVerifyAccountPhone { get; set; }
}
@@ -0,0 +1,93 @@
<UserControl
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:spp="https://steampp.net/ui"
xmlns:s="https://steampp.net/services"
d:DesignWidth="400"
d:DesignHeight="250"
x:DataType="spp:AddSteamAccountPhoneNumberPageViewModel"
x:CompileBindings="True"
x:Class="BD.WTTS.UI.Views.Controls.AddSteamAccountPhoneNumberPage"
mc:Ignorable="d">
<Grid RowDefinitions="Auto,*">
<spp:Stepper SelectedIndex="{Binding SelectIndex}">
<spp:StepperItem Content="{Binding Path=Res.Steam_BindTel, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
<spp:StepperItem Content="{Binding Path=Res.Steam_ConfirmEmailLink, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
<spp:StepperItem Content="{Binding Path=Res.TelCode, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
</spp:Stepper>
<spp:ContentLoader
Grid.Row="1"
MinWidth="400"
MinHeight="250"
IsLoading="{Binding IsLoading}"
IsShowNoResultText="False">
<Carousel IsVisible="{Binding !IsLoading}" SelectedIndex="{Binding SelectIndex}">
<StackPanel
HorizontalAlignment="Center"
VerticalAlignment="Center"
Spacing="10">
<DockPanel>
<TextBlock
Margin="0,0,0,6"
DockPanel.Dock="Top"
Text="{Binding Path=Res.User_Phone, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
<TextBox
Name="PhoneNumberText"
MaxWidth="300"
Text="{Binding PhoneNumberText}"
Watermark="+8601234567890" />
</DockPanel>
<Button
MinWidth="280"
HorizontalAlignment="Center"
HorizontalContentAlignment="Center"
Command="{Binding StartBindingAsync}"
Content="{Binding Path=Res.Continue, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
</StackPanel>
<StackPanel
HorizontalAlignment="Center"
VerticalAlignment="Center"
Spacing="10">
<Button
MinWidth="280"
HorizontalAlignment="Center"
HorizontalContentAlignment="Center"
Command="{Binding ConfirmBindingEmailAsync}"
Content="{Binding Path=Res.Continue, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
</StackPanel>
<StackPanel
HorizontalAlignment="Center"
VerticalAlignment="Center"
Spacing="10">
<DockPanel>
<TextBlock
Margin="0,0,0,6"
DockPanel.Dock="Top"
Text="{Binding Path=Res.Error_PleaseEnterTelCode, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
<TextBox
Name="CodeText"
MaxWidth="300"
Text="{Binding CodeText}" />
</DockPanel>
<Button
MinWidth="280"
HorizontalAlignment="Center"
HorizontalContentAlignment="Center"
Command="{Binding VerifyAccountPhoneWithCodeAsync}"
Content="{Binding Path=Res.Continue, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
</StackPanel>
</Carousel>
</spp:ContentLoader>
</Grid>
</UserControl>
@@ -0,0 +1,11 @@
using Avalonia.Controls;
namespace BD.WTTS.UI.Views.Controls;
public partial class AddSteamAccountPhoneNumberPage : UserControl
{
public AddSteamAccountPhoneNumberPage()
{
InitializeComponent();
}
}
@@ -11,85 +11,86 @@
x:CompileBindings="True" x:CompileBindings="True"
x:DataType="spp:SteamLoginImportPageViewModel" x:DataType="spp:SteamLoginImportPageViewModel"
mc:Ignorable="d"> mc:Ignorable="d">
<Grid RowDefinitions="Auto,*"> <Grid RowDefinitions="Auto,*">
<spp:Stepper SelectedIndex="{Binding SelectIndex}"> <spp:Stepper SelectedIndex="{Binding SelectIndex}">
<spp:StepperItem Content="{Binding Path=Res.Steam_Login, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" /> <spp:StepperItem Content="{Binding Path=Res.Steam_Login, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
<spp:StepperItem Content="{Binding Path=Res.LoginVerify, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" /> <spp:StepperItem Content="{Binding Path=Res.LoginVerify, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
<spp:StepperItem Content="{Binding Path=Res.Steam_BindTel, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" /> <!--隐藏绑定手机号步骤-->
<spp:StepperItem Content="{Binding Path=Res.TelCode, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" /> <!--<spp:StepperItem IsVisible="false" Content="{Binding Path=Res.Steam_BindTel, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />-->
<spp:StepperItem Content="{Binding Path=Res.Btn_Text_Complete, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" /> <spp:StepperItem Content="{Binding Path=Res.LocalAuth_VerifyCode, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
</spp:Stepper> <spp:StepperItem Content="{Binding Path=Res.Btn_Text_Complete, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
</spp:Stepper>
<spp:ContentLoader <spp:ContentLoader
Grid.Row="1" Grid.Row="1"
MinWidth="600" MinWidth="600"
MinHeight="400" MinHeight="400"
IsLoading="{Binding IsLoading}" IsLoading="{Binding IsLoading}"
IsShowNoResultText="False"> IsShowNoResultText="False">
<Carousel IsVisible="{Binding !IsLoading}" SelectedIndex="{Binding SelectIndex}"> <Carousel IsVisible="{Binding !IsLoading}" SelectedIndex="{Binding SelectIndex}">
<!-- 登录 --> <!-- 登录 -->
<StackPanel <StackPanel
HorizontalAlignment="Center" HorizontalAlignment="Center"
VerticalAlignment="Center" VerticalAlignment="Center"
Spacing="10"> Spacing="10">
<PathIcon <PathIcon
Width="88" Width="88"
Height="88" Height="88"
Data="{StaticResource Steam}" /> Data="{StaticResource Steam}" />
<TextBox <TextBox
MaxWidth="280" MaxWidth="280"
Text="{Binding UserNameText}" Text="{Binding UserNameText}"
Watermark="{Binding Path=Res.Steam_User, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" /> Watermark="{Binding Path=Res.Steam_User, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
<TextBox <TextBox
Name="PasswordText" Name="PasswordText"
MaxWidth="280" MaxWidth="280"
Classes="revealPasswordButton" Classes="revealPasswordButton"
PasswordChar="{StaticResource PasswordChar}" PasswordChar="{StaticResource PasswordChar}"
Text="{Binding PasswordText}" Text="{Binding PasswordText}"
Watermark="{Binding Path=Res.Steam_Password, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" /> Watermark="{Binding Path=Res.Steam_Password, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
<Button <Button
MinWidth="280" MinWidth="280"
HorizontalAlignment="Center" HorizontalAlignment="Center"
VerticalAlignment="Bottom" VerticalAlignment="Bottom"
HorizontalContentAlignment="Center" HorizontalContentAlignment="Center"
Command="{Binding LoginSteamImport}" Command="{Binding LoginSteamImport}"
Content="{Binding Path=Res.Login, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" /> Content="{Binding Path=Res.Login, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
</StackPanel> </StackPanel>
<!-- 邮箱验证 --> <!-- 邮箱验证 -->
<Panel> <Panel>
<spp:Snackbar <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 s:ResourceService.Current}}"
VerticalAlignment="Top" VerticalAlignment="Top"
IsClosable="False" IsClosable="False"
IsOpen="True" IsOpen="True"
IsVisible="{Binding !Requires2FA}" IsVisible="{Binding !Requires2FA}"
Message="{Binding Path=Res.LocalAuth_EmailCodeTip, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" Message="{Binding Path=Res.LocalAuth_EmailCodeTip, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
Severity="Warning" /> Severity="Warning" />
<spp:Snackbar <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 s:ResourceService.Current}}"
VerticalAlignment="Top" VerticalAlignment="Top"
IsClosable="False" IsClosable="False"
IsOpen="True" IsOpen="True"
IsVisible="{Binding Requires2FA}" IsVisible="{Binding Requires2FA}"
Message="{Binding Path=Res.LocalAuth_Steam2FACodeTip, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" Message="{Binding Path=Res.LocalAuth_Steam2FACodeTip, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
Severity="Warning" /> Severity="Warning" />
<StackPanel <StackPanel
HorizontalAlignment="Center" HorizontalAlignment="Center"
VerticalAlignment="Center" VerticalAlignment="Center"
Spacing="10"> Spacing="10">
<TextBlock IsVisible="{Binding !Requires2FA}" Text="{Binding Path=Res.EmailCode, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" /> <TextBlock IsVisible="{Binding !Requires2FA}" Text="{Binding Path=Res.EmailCode, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
<TextBlock IsVisible="{Binding Requires2FA}" Text="{Binding Path=Res.Steam2FACode, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" /> <TextBlock IsVisible="{Binding Requires2FA}" Text="{Binding Path=Res.Steam2FACode, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
<TextBox <TextBox
Name="EmailAuthText" Name="EmailAuthText"
MinWidth="300" MinWidth="300"
FontSize="24" FontSize="24"
Text="{Binding EmailAuthText}" /> Text="{Binding EmailAuthText}" />
<!--<TextBlock <!--<TextBlock
Margin="10,0" Margin="10,0"
HorizontalAlignment="Center" HorizontalAlignment="Center"
Text="{Binding EmailDomainText}" />--> Text="{Binding EmailDomainText}" />-->
<!--<TextBlock <!--<TextBlock
Margin="10,0" Margin="10,0"
HorizontalAlignment="Center" HorizontalAlignment="Center"
Text="{Binding Path=Res.LocalAuth_EmailCodeTip, Text="{Binding Path=Res.LocalAuth_EmailCodeTip,
@@ -97,121 +98,138 @@
Source={x:Static s:ResourceService.Current}}" Source={x:Static s:ResourceService.Current}}"
TextAlignment="Center" TextAlignment="Center"
TextWrapping="WrapWithOverflow" />--> TextWrapping="WrapWithOverflow" />-->
<Button <Button
MinWidth="280" MinWidth="280"
HorizontalAlignment="Center" HorizontalAlignment="Center"
HorizontalContentAlignment="Center" HorizontalContentAlignment="Center"
Command="{Binding LoginSteamImport}" Command="{Binding LoginSteamImport}"
Content="{Binding Path=Res.Continue, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" /> Content="{Binding Path=Res.Continue, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
</StackPanel> </StackPanel>
</Panel> </Panel>
<!-- 绑定手机 --> <!-- 绑定手机 -->
<Panel> <!--
<spp:Snackbar <Panel>
Title="{Binding Path=Res.Notice_Tray_Title, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" <spp:Snackbar
VerticalAlignment="Top" Title="{Binding Path=Res.Notice_Tray_Title, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
IsClosable="False" VerticalAlignment="Top"
IsOpen="True" IsClosable="False"
Message="{Binding Path=Res.Warning_SteamAuthPhoneBind, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" IsOpen="True"
Severity="Warning" /> Message="{Binding Path=Res.Warning_SteamAuthPhoneBind, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
<StackPanel Severity="Warning" />
HorizontalAlignment="Center" <StackPanel
VerticalAlignment="Center" HorizontalAlignment="Center"
Spacing="10"> VerticalAlignment="Center"
Spacing="10">
<DockPanel> <DockPanel>
<TextBlock <TextBlock
Margin="0,0,0,6" Margin="0,0,0,6"
DockPanel.Dock="Top" DockPanel.Dock="Top"
Text="{Binding Path=Res.User_Phone, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" /> Text="{Binding Path=Res.User_Phone, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
<TextBox <TextBox
Name="PhoneNumberText" Name="PhoneNumberText"
MaxWidth="300" MaxWidth="300"
Text="{Binding PhoneNumberText}" Text="{Binding PhoneNumberText}"
Watermark="+8601234567890" /> Watermark="+8601234567890" />
</DockPanel> </DockPanel>
<Button <Button
MinWidth="280" MinWidth="280"
HorizontalAlignment="Center" HorizontalAlignment="Center"
HorizontalContentAlignment="Center" HorizontalContentAlignment="Center"
Command="{Binding LoginSteamImport}" Command="{Binding LoginSteamImport}"
Content="{Binding Path=Res.Continue, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" /> Content="{Binding Path=Res.Continue, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
</StackPanel> </StackPanel>
</Panel> </Panel>-->
<!-- 验证手机 --> <!-- 验证手机 或 邮箱 -->
<Panel> <!-- 2024-04-23 Steam绑定令牌不强制手机绑定 可以输入 邮箱者手机验证码 -->
<spp:Snackbar <Panel>
Title="{Binding Path=Res.Notice_Tray_Title, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" <spp:Snackbar
VerticalAlignment="Top" Title="{Binding Path=Res.Notice_Tray_Title, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
IsClosable="False" VerticalAlignment="Top"
IsOpen="True" IsClosable="False"
Message="{Binding Path=Res.LocalAuth_SMSCodeTip, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" IsVisible="{Binding IsVerifyAccountPhone}"
Severity="Warning" /> IsOpen="True"
<StackPanel Message="{Binding Path=Res.LocalAuth_SMSCodeTip, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
HorizontalAlignment="Center" Severity="Warning" />
VerticalAlignment="Center" <spp:Snackbar
Spacing="10"> Title="{Binding Path=Res.Notice_Tray_Title, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
<DockPanel IsVisible="{Binding RevocationCodeText, Mode=OneWay, Converter={StaticResource IsNullConverter}, ConverterParameter=invert}"> VerticalAlignment="Top"
<TextBlock IsClosable="False"
Margin="0,0,0,6" IsVisible="{Binding !IsVerifyAccountPhone}"
DockPanel.Dock="Top" IsOpen="True"
Text="{Binding Path=Res.RecoveryCode, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" /> Message="{Binding Path=Res.LocalAuth_EmailCodeTip, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
<TextBox Severity="Warning" />
MaxWidth="300" <StackPanel
IsReadOnly="True" HorizontalAlignment="Center"
Text="{Binding RevocationCodeText, Mode=OneWay}" /> VerticalAlignment="Center"
</DockPanel> Spacing="10">
<!--<CheckBox Content="{Binding Path=Res.RecoveryCode_Remember, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />--> <DockPanel IsVisible="{Binding RevocationCodeText, Mode=OneWay, Converter={StaticResource IsNullConverter}, ConverterParameter=invert}">
<DockPanel> <TextBlock
<TextBlock Margin="0,0,0,6"
Margin="0,0,0,6" DockPanel.Dock="Top"
DockPanel.Dock="Top" Text="{Binding Path=Res.RecoveryCode, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
Text="{Binding Path=Res.SMSCode, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" /> <TextBox
<TextBox MaxWidth="300"
Name="PhoneCodeText" IsReadOnly="True"
MaxWidth="300" Text="{Binding RevocationCodeText, Mode=OneWay}" />
Text="{Binding PhoneCodeText}" /> </DockPanel>
</DockPanel> <!--<CheckBox Content="{Binding Path=Res.RecoveryCode_Remember, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />-->
<Button <DockPanel>
MinWidth="280" <TextBlock
HorizontalAlignment="Center" Margin="0,0,0,6"
HorizontalContentAlignment="Center" DockPanel.Dock="Top"
Command="{Binding LoginSteamImport}" IsVisible="{Binding IsVerifyAccountPhone}"
Content="{Binding Path=Res.Continue, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" /> Text="{Binding Path=Res.SMSCode, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
</StackPanel> <TextBlock
</Panel> Margin="0,0,0,6"
DockPanel.Dock="Top"
IsVisible="{Binding !IsVerifyAccountPhone}"
Text="{Binding Path=Res.EmailCode, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
<TextBox
Name="PhoneCodeText"
MaxWidth="300"
Text="{Binding PhoneCodeText}" />
</DockPanel>
<Button
MinWidth="280"
HorizontalAlignment="Center"
HorizontalContentAlignment="Center"
Command="{Binding LoginSteamImport}"
Content="{Binding Path=Res.Continue, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
</StackPanel>
</Panel>
<!-- 完成 --> <!-- 完成 -->
<Panel> <Panel>
<spp:Snackbar <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 s:ResourceService.Current}}"
VerticalAlignment="Top" VerticalAlignment="Top"
IsClosable="False" IsClosable="False"
IsOpen="True" IsOpen="True"
Message="{Binding Path=Res.RecoveryCode_RememberTip, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" Message="{Binding Path=Res.RecoveryCode_RememberTip, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
Severity="Success" /> Severity="Success" />
<StackPanel VerticalAlignment="Center" Spacing="10"> <StackPanel VerticalAlignment="Center" Spacing="10">
<DockPanel IsVisible="{Binding RevocationCodeText, Mode=OneWay, Converter={StaticResource IsNullConverter}, ConverterParameter=invert}"> <DockPanel IsVisible="{Binding RevocationCodeText, Mode=OneWay, Converter={StaticResource IsNullConverter}, ConverterParameter=invert}">
<TextBlock <TextBlock
Margin="0,0,0,6" Margin="0,0,0,6"
DockPanel.Dock="Top" DockPanel.Dock="Top"
Text="{Binding Path=Res.RecoveryCode, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" /> Text="{Binding Path=Res.RecoveryCode, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
<TextBox <TextBox
MaxWidth="300" MaxWidth="300"
IsReadOnly="True" IsReadOnly="True"
Text="{Binding RevocationCodeText, Mode=OneWay}" /> Text="{Binding RevocationCodeText, Mode=OneWay}" />
</DockPanel> </DockPanel>
<Button <Button
MinWidth="280" MinWidth="280"
HorizontalAlignment="Center" HorizontalAlignment="Center"
Command="{Binding Reset}" Command="{Binding Reset}"
Content="{Binding Path=Res.Confirm, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" /> Content="{Binding Path=Res.Confirm, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
</StackPanel> </StackPanel>
</Panel> </Panel>
</Carousel> </Carousel>
</spp:ContentLoader> </spp:ContentLoader>
</Grid> </Grid>
</UserControl> </UserControl>
@@ -14,7 +14,7 @@ public partial class SteamLoginImportPage : ReactiveUserControl<SteamLoginImport
DataContext ??= new SteamLoginImportPageViewModel(); DataContext ??= new SteamLoginImportPageViewModel();
PasswordText.KeyUp += PasswordTextOnKeyUp; PasswordText.KeyUp += PasswordTextOnKeyUp;
EmailAuthText.KeyUp += PasswordTextOnKeyUp; EmailAuthText.KeyUp += PasswordTextOnKeyUp;
PhoneNumberText.KeyUp += PasswordTextOnKeyUp; //PhoneNumberText.KeyUp += PasswordTextOnKeyUp;
PhoneCodeText.KeyUp += PasswordTextOnKeyUp; PhoneCodeText.KeyUp += PasswordTextOnKeyUp;
EmailAuthText.TextInput += EmailAuthText_TextInput; EmailAuthText.TextInput += EmailAuthText_TextInput;
PhoneCodeText.TextInput += EmailAuthText_TextInput; PhoneCodeText.TextInput += EmailAuthText_TextInput;
@@ -34,4 +34,4 @@ public partial class SteamLoginImportPage : ReactiveUserControl<SteamLoginImport
e.Handled = true; e.Handled = true;
} }
} }
} }
+18
View File
@@ -4484,6 +4484,15 @@ namespace BD.WTTS.Client.Resources {
} }
} }
/// <summary>
/// 查找类似 验证码 的本地化字符串。
/// </summary>
public static string LocalAuth_VerifyCode {
get {
return ResourceManager.GetString("LocalAuth_VerifyCode", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 使用 Steam++ V1 版本工具箱导出的文件导入令牌 的本地化字符串。 /// 查找类似 使用 Steam++ V1 版本工具箱导出的文件导入令牌 的本地化字符串。
/// </summary> /// </summary>
@@ -6702,6 +6711,15 @@ namespace BD.WTTS.Client.Resources {
} }
} }
/// <summary>
/// 查找类似 确认邮箱链接 的本地化字符串。
/// </summary>
public static string Steam_ConfirmEmailLink {
get {
return ResourceManager.GetString("Steam_ConfirmEmailLink", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Steam 客户端登录区域: 的本地化字符串。 /// 查找类似 Steam 客户端登录区域: 的本地化字符串。
/// </summary> /// </summary>
@@ -2945,6 +2945,12 @@
</data> </data>
<data name="Idle_PIN_NotBeNull" xml:space="preserve"> <data name="Idle_PIN_NotBeNull" xml:space="preserve">
<value>PIN CODE 不能为空</value> <value>PIN CODE 不能为空</value>
</data>
<data name="LocalAuth_VerifyCode" xml:space="preserve">
<value>验证码</value>
</data>
<data name="Steam_ConfirmEmailLink" xml:space="preserve">
<value>确认邮箱链接</value>
</data> </data>
<data name="CommunityFix_Starting" xml:space="preserve"> <data name="CommunityFix_Starting" xml:space="preserve">
<value>正在启动加速...</value> <value>正在启动加速...</value>