LoginOrRegisterPage

This commit is contained in:
Aigio Liu
2021-06-19 21:31:50 +08:00
parent dc54aae844
commit 3ff117ecec
50 changed files with 615 additions and 170 deletions
@@ -60,6 +60,15 @@ namespace System.Application.Properties {
}
}
/// <summary>
/// 查找类似 此应用不支持在模拟器中运行 的本地化字符串。
/// </summary>
internal static string ExitCode_IsEmulator {
get {
return ResourceManager.GetString("ExitCode_IsEmulator", resourceCulture);
}
}
/// <summary>
/// 查找类似 此应用不支持在有ROOT权限的设备中运行 的本地化字符串。
/// </summary>
@@ -117,6 +117,9 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="ExitCode_IsEmulator" xml:space="preserve">
<value>此应用不支持在模拟器中运行</value>
</data>
<data name="ExitCode_IsRoot" xml:space="preserve">
<value>此应用不支持在有ROOT权限的设备中运行</value>
</data>
@@ -85,7 +85,8 @@ namespace System.Application.Security
ExitCode.IsVirtualApk => SR.ExitCode_IsVirtualApk,
ExitCode.IsRoot => SR.ExitCode_IsRoot,
ExitCode.IsXposedExists => SR.ExitCode_IsXposedExists,
_ => null,
ExitCode.IsCompatiblePC or ExitCode.IsEmulator => SR.ExitCode_IsEmulator,
_ => $"Incompatible device error {(int)code}",
};
if (str != null)
{
@@ -150,7 +151,7 @@ namespace System.Application.Security
static bool GetIsEmulator()
{
// 参考 https://github.com/gingo/android-emulator-detector/blob/master/EmulatorDetectorProject/EmulatorDetector/src/main/java/net/skoumal/emulatordetector/EmulatorDetector.java
return _() || DeviceInfo.DeviceType == DeviceType.Virtual;
return DeviceInfo.DeviceType == DeviceType.Virtual || _();
static bool contains(string l, string r)
{
return l.Contains(r, StringComparison.OrdinalIgnoreCase);
@@ -257,7 +258,8 @@ namespace System.Application.Security
{
#pragma warning disable CS8604 // 可能的 null 引用参数。
if (contains(opengl, "Bluestacks") ||
contains(opengl, "Translator")
contains(opengl, "Translator") ||
contains(opengl, "youwave")
)
#pragma warning restore CS8604 // 可能的 null 引用参数。
newRating += 10;
@@ -1,4 +1,4 @@
<Project Sdk="MSBuild.Sdk.Extras">
<Project Sdk="MSBuild.Sdk.Extras">
<PropertyGroup>
<TargetFramework>MonoAndroid11.0</TargetFramework>
@@ -42,8 +42,14 @@
</ItemGroup>
<ItemGroup>
<Compile Update="Properties\SR.Designer.cs">
<Compile Update="Application\Properties\SR.Designer.cs">
<DesignTime>True</DesignTime>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Application\Properties\SR.resx">
<LastGenOutput>SR.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
</Project>
@@ -1,11 +1,13 @@
using Android.App;
using Android.App;
using Android.OS;
using Android.Views.InputMethods;
using Android.Widget;
using AndroidX.AppCompat.App;
using AndroidX.Fragment.App;
using AndroidX.Navigation.Fragment;
using System.Diagnostics.CodeAnalysis;
using Fragment = AndroidX.Fragment.App.Fragment;
using Toolbar = AndroidX.AppCompat.Widget.Toolbar;
// ReSharper disable once CheckNamespace
namespace System
@@ -116,5 +118,11 @@ namespace System
public static bool IsAvailable(this Activity? activity) => activity.HasValue();
#endif
public static void SetSupportActionBarWithNavigationClick(this AppCompatActivity activity, Toolbar toolbar)
{
activity.SetSupportActionBar(toolbar);
toolbar.NavigationClick += (_, _) => activity.OnBackPressed();
}
}
}
@@ -0,0 +1,62 @@
using ReactiveUI;
namespace System.Application.UI.ViewModels
{
public abstract class IdTitleIconViewModel<TId, TIcon> : ReactiveObject
{
protected TId? id;
/// <summary>
/// 唯一键
/// </summary>
public TId? Id
{
get => id;
set
{
if (this.RaiseAndSetIfChanged2(ref id, value)) return;
Title = GetTitleById(value);
Icon = GetIconById(value);
OnIdChanged(value);
}
}
protected virtual void OnIdChanged(TId? value)
{
}
protected string title = string.Empty;
/// <summary>
/// 标题文本
/// </summary>
public virtual string Title
{
get => title;
set => this.RaiseAndSetIfChanged(ref title, value);
}
protected TIcon? icon;
/// <summary>
/// 图标
/// </summary>
public TIcon? Icon
{
get => icon;
set => this.RaiseAndSetIfChanged(ref icon, value);
}
/// <summary>
/// 根据键获取标题文本
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
protected abstract string GetTitleById(TId? id);
/// <summary>
/// 根据键获取图标
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
protected abstract TIcon GetIconById(TId? id);
}
}
@@ -6,7 +6,8 @@ using System.Drawing;
using System.IO;
using System.Text;
namespace System.Application
// ReSharper disable once CheckNamespace
namespace System
{
public static class HandleWindowExtensions
{
@@ -1,8 +1,8 @@
using System.Application.Services;
using System.Application.Services;
using System.Diagnostics;
// ReSharper disable once CheckNamespace
namespace System.Application
namespace System
{
/// <summary>
/// 为 <see cref="Process"/> 类型提供扩展方法
@@ -1,8 +1,8 @@
using StatefulModel.EventListeners;
using StatefulModel.EventListeners;
using System.ComponentModel;
// ReSharper disable once CheckNamespace
namespace System.Application
namespace System
{
public static class PropertyChangedExtensions
{
@@ -1,5 +1,5 @@
// ReSharper disable once CheckNamespace
namespace System.Application
// ReSharper disable once CheckNamespace
namespace System
{
public static class StartupArgsExtensions
{
@@ -5,6 +5,7 @@ using System.Drawing;
using System.IO;
using System.Text;
// ReSharper disable once CheckNamespace
namespace System.Application
{
public static class SteamAppPropertyExtensions
@@ -1,8 +1,9 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
namespace System.Application
// ReSharper disable once CheckNamespace
namespace System
{
public static class TaskExtensions
{
@@ -1,6 +1,7 @@
using System.Application.Mvvm;
namespace System.Application
// ReSharper disable once CheckNamespace
namespace System
{
public static class ViewModelExtensions
{
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
@@ -16,6 +16,12 @@
<Compile Include="..\ST\Properties\InternalsVisibleTo.cs">
<Link>Properties\InternalsVisibleTo.cs</Link>
</Compile>
<Compile Include="..\ST.Client.Mobile\UI\ViewModels\Base\RIdTitleIconViewModel.cs">
<LinkBase>UI\ViewModels\Base</LinkBase>
</Compile>
<Compile Include="..\ST.Client.Mobile\UI\ResIcon.cs">
<LinkBase>UI</LinkBase>
</Compile>
</ItemGroup>
<ItemGroup>
+10 -7
View File
@@ -1,8 +1,10 @@
using System.Application.UI.Resx;
using System.Collections.Generic;
#if !__MOBILE__
using System.Drawing;
using System.Drawing.Text;
using System.Linq;
#endif
namespace System.Application.Services
{
@@ -16,18 +18,19 @@ namespace System.Application.Services
protected static IReadOnlyCollection<KeyValuePair<string, string>> GetFontsByGdiPlus()
{
#if !__MOBILE__
// https://docs.microsoft.com/zh-cn/typography/font-list
var culture =
#if __MOBILE__
AppResources
#else
R
#endif
.Culture;
var culture = R.Culture;
InstalledFontCollection ifc = new();
var list = ifc.Families.Where(x => x.IsStyleAvailable(FontStyle.Regular)).Select(x => KeyValuePair.Create(x.GetName(culture.LCID), x.GetName(1033))).ToList();
list.Insert(0, IFontManager.Default);
return list;
#else
// Common7\IDE\ReferenceAssemblies\Microsoft\Framework\MonoAndroid\v1.0\Facades\System.Drawing.Common.dll
// System.Drawing.Text.InstalledFontCollection
// throw new PlatformNotSupportedException();
return Array.Empty<KeyValuePair<string, string>>();
#endif
}
}
}
@@ -11,6 +11,7 @@ using System.Threading.Tasks;
using System.Application.Mvvm;
using System.Collections.Generic;
// ReSharper disable once CheckNamespace
namespace System.Application.UI.ViewModels
{
public class ViewModelBase : ReactiveObject, IViewModelBase, IActivatableViewModel
@@ -6,6 +6,7 @@ using Xamarin.Essentials;
using MainThread = System.Application.MainThreadDesktop;
#endif
// ReSharper disable once CheckNamespace
namespace System.Application.UI.ViewModels
{
public partial class
@@ -1,12 +1,16 @@
using ReactiveUI;
using System.Application.Models;
using System.Application.Mvvm;
using System.Application.Services;
using System.Application.UI.Resx;
using System.Collections.ObjectModel;
using System.Drawing;
using System.Properties;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using Xamarin.Essentials;
using static System.Application.Services.CloudService.Constants;
namespace System.Application.UI.ViewModels
@@ -33,10 +37,12 @@ namespace System.Application.UI.ViewModels
#endif
AppResources.LoginAndRegister;
#if !__MOBILE__
FastLogin = ReactiveCommand.CreateFromTask<FastLoginChannel>(async channel =>
{
await FastLoginOrRegisterAsync(Close, channel);
});
#endif
ChooseChannel = ReactiveCommand.CreateFromTask<string>(async channel =>
{
if (Enum.TryParse<FastLoginChannel>(channel, out var channel_))
@@ -47,7 +53,7 @@ namespace System.Application.UI.ViewModels
{
switch (channel)
{
case nameof(PhoneNumber):
case FastLoginChannelViewModel.PhoneNumber:
await GoToLoginOrRegisterByPhoneNumberAsync();
break;
}
@@ -59,6 +65,17 @@ namespace System.Application.UI.ViewModels
//SteamConnectService.Current.WhenAnyValue(x => x.CurrentSteamUser)
// .Subscribe(_ => this.RaisePropertyChanged(nameof(SteamUser)));
fastLoginChannels = new()
{
FastLoginChannelViewModel.Create(nameof(FastLoginChannel.Steam), this),
FastLoginChannelViewModel.Create(nameof(FastLoginChannel.Xbox), this),
#if DEBUG
FastLoginChannelViewModel.Create(nameof(FastLoginChannel.Apple), this),
FastLoginChannelViewModel.Create(nameof(FastLoginChannel.QQ), this),
#endif
FastLoginChannelViewModel.Create(FastLoginChannelViewModel.PhoneNumber, this),
};
}
private string? _PhoneNumber;
@@ -223,17 +240,11 @@ namespace System.Application.UI.ViewModels
#endif
}
#if !__MOBILE__
[Obsolete("use ChooseChannel")]
public ICommand FastLogin { get; }
[Obsolete("use Channels")]
public FastLoginChannel[] FastLoginChannels { get; } = new[] {
FastLoginChannel.Steam,
FastLoginChannel.Xbox,
//FastLoginChannel.Apple,
//FastLoginChannel.QQ,
};
[Obsolete("use FastLoginChannels")]
public string[] Channels { get; } = new[]
{
nameof(FastLoginChannel.Steam),
@@ -242,9 +253,13 @@ namespace System.Application.UI.ViewModels
nameof(FastLoginChannel.Apple),
nameof(FastLoginChannel.QQ),
#endif
nameof(PhoneNumber),
FastLoginChannelViewModel.PhoneNumber,
};
#endif
/// <summary>
/// 选择快速登录渠道点击命令,参数类型为 <see cref="FastLoginChannelViewModel"/>.Id
/// </summary>
public ICommand ChooseChannel { get; }
protected override void Dispose(bool disposing)
@@ -255,5 +270,96 @@ namespace System.Application.UI.ViewModels
}
base.Dispose(disposing);
}
ObservableCollection<FastLoginChannelViewModel> fastLoginChannels;
/// <summary>
/// 快速登录渠道组
/// </summary>
public ObservableCollection<FastLoginChannelViewModel> FastLoginChannels
{
get => fastLoginChannels;
set => this.RaiseAndSetIfChanged(ref fastLoginChannels, value);
}
public sealed class FastLoginChannelViewModel : RIdTitleIconViewModel<string, ResIcon>
{
FastLoginChannelViewModel()
{
}
Color iconBgColor;
public Color IconBgColor
{
get => iconBgColor;
set => this.RaiseAndSetIfChanged(ref iconBgColor, value);
}
protected override void OnIdChanged(string? value)
{
IconBgColor = GetIconBgColorById(value);
}
public const string PhoneNumber = nameof(PhoneNumber);
protected override ResIcon GetIconById(string? id)
{
return id switch
{
nameof(FastLoginChannel.Steam) => ResIcon.Steam,
nameof(FastLoginChannel.Xbox) or
nameof(FastLoginChannel.Microsoft) => ResIcon.Xbox,
nameof(FastLoginChannel.Apple) => ResIcon.Apple,
nameof(FastLoginChannel.QQ) => ResIcon.QQ,
PhoneNumber => ResIcon.Phone,
_ => ResIcon.none,
};
}
protected override string GetTitleById(string? id)
{
if (id == PhoneNumber)
{
return AppResources.User_UsePhoneNumLoginChannel;
}
else if (!string.IsNullOrWhiteSpace(id))
{
if (id == nameof(FastLoginChannel.Xbox) ||
id == nameof(FastLoginChannel.Microsoft))
{
id = "Xbox Live";
}
return AppResources.User_UseFastLoginChannel_.Format(id);
}
return string.Empty;
}
static Color GetIconBgColorById(string? id)
{
var hexColor = id switch
{
nameof(FastLoginChannel.Steam) => "#145c8f",
nameof(FastLoginChannel.Xbox) or
nameof(FastLoginChannel.Microsoft) => "#027d00",
nameof(FastLoginChannel.Apple) => "#000000",
nameof(FastLoginChannel.QQ) => "#12B7F5",
PhoneNumber => "#2196F3",
_ => default,
};
return hexColor == default ? default : ColorConverters.FromHex(hexColor);
}
/// <summary>
/// 创建实例
/// </summary>
/// <param name="id"></param>
/// <param name="vm"></param>
/// <returns></returns>
public static FastLoginChannelViewModel Create(string id, IDisposableHolder vm)
{
FastLoginChannelViewModel r = new() { Id = id, };
r.OnBind(vm);
return r;
}
}
}
}
@@ -83,6 +83,11 @@
<ItemGroup>
<None Include="Properties\AndroidManifest.xml" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Xamarin.AndroidX.Migration" Version="1.0.8" />
<PackageReference Include="Xamarin.AndroidX.Legacy.Support.Core.UI" Version="1.0.0.8" />
<PackageReference Include="Xamarin.AndroidX.Lifecycle.LiveData" Version="2.3.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Common.CoreLib\Common.CoreLib.csproj">
<Project>{e7468fdd-75f7-4b08-ba47-b715bbcfcc11}</Project>
@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="1000"
android:viewportHeight="1000">
<path
android:fillColor="@android:color/white"
android:pathData="M905.714286 694.285714q-22.285714 71.428571-70.285714 142.857143-73.714286 112-146.857143 112-28 0-80-18.285714-49.142857-18.285714-86.285714-18.285714-34.857143 0-81.142857 18.857143-46.285714 19.428571-75.428571 19.428571-86.857143 0-172-148-84-149.142857-84-287.428571 0-130.285714 64.571429-213.714286 64-82.285714 162.285714-82.285714 41.142857 0 101.142857 17.142857 59.428571 17.142857 78.857143 17.142857 25.714286 0 81.714286-19.428571 58.285714-19.428571 98.857143-19.428571 68 0 121.714286 37.142857 29.714286 20.571429 59.428571 57.142857-45.142857 38.285714-65.142857 67.428571-37.142857 53.714286-37.142857 118.285714 0 70.857143 39.428571 127.428571t90.285714 72zm-214.857143-670.285714q0 34.857143-16.571429 77.714286-17.142857 42.857143-53.142857 78.857143-30.857143 30.857143-61.714286 41.142857-21.142857 6.285714-59.428571 9.714286 1.714286-85.142857 44.571429-146.857143 42.285714-61.142857 142.857143-84.571429 0.571429 1.714286 1.428571 6.285714t1.428571 6.285714q0 2.285714 2.857143 5.714286t2.857143 5.714286z" />
</vector>
@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M15.75 2C16.9926 2 18 3.00736 18 4.25V19.75C18 20.9926 16.9926 22 15.75 22H8.25C7.00736 22 6 20.9926 6 19.75V4.25C6 3.00736 7.00736 2 8.25 2H15.75ZM13.25 18H10.75C10.3358 18 10 18.3358 10 18.75C10 19.1642 10.3358 19.5 10.75 19.5H13.25C13.6642 19.5 14 19.1642 14 18.75C14 18.3358 13.6642 18 13.25 18Z" />
</vector>
@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="1000"
android:viewportHeight="1000">
<path
android:fillColor="@android:color/white"
android:pathData="M909.937778 664.803556c-18.432-110.876444-95.829333-183.523556-95.829333-183.523556 11.064889-100.664889-29.496889-118.528-29.496889-118.528C776.106667 51.313778 517.432889 56.775111 512 56.917333c-5.432889-0.142222-264.135111-5.603556-272.611556 305.863111 0 0-40.561778 17.863111-29.496889 118.528 0 0-77.397333 72.647111-95.829333 183.523556 0 0-9.841778 187.335111 88.462222 22.954667 0 0 22.129778 62.435556 62.663111 118.528 0 0-72.504889 25.486222-66.332444 91.761778 0 0-2.474667 73.898667 154.823111 68.835556 0 0 110.563556-8.903111 143.758222-57.344l29.240889 0c33.166222 48.440889 143.758222 57.344 143.758222 57.344 157.240889 5.091556 154.794667-68.835556 154.794667-68.835556 6.115556-66.247111-66.332444-91.761778-66.332444-91.761778 40.533333-56.092444 62.663111-118.528 62.663111-118.528C919.751111 852.167111 909.937778 664.803556 909.937778 664.803556L909.937778 664.803556zM909.937778 664.803556" />
</vector>
@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="496"
android:viewportHeight="512">
<path
android:fillColor="@android:color/white"
android:pathData="M496 256c0 137-111.2 248-248.4 248-113.8 0-209.6-76.3-239-180.4l95.2 39.3c6.4 32.1 34.9 56.4 68.9 56.4 39.2 0 71.9-32.4 70.2-73.5l84.5-60.2c52.1 1.3 95.8-40.9 95.8-93.5 0-51.6-42-93.5-93.7-93.5s-93.7 42-93.7 93.5v1.2L176.6 279c-15.5-0.9-30.7 3.4-43.5 12.1L0 236.1C10.2 108.4 117.1 8 247.6 8 384.8 8 496 119 496 256zM155.7 384.3l-30.5-12.6a52.79 52.79 0 0 0 27.2 25.8c26.9 11.2 57.8-1.6 69-28.4 5.4-13 5.5-27.3 0.1 -40.3-5.4-13-15.5-23.2-28.5-28.6-12.9-5.4-26.7-5.2-38.9-0.6l31.5 13c19.8 8.2 29.2 30.9 20.9 50.7-8.3 19.9-31 29.2-50.8 21zm173.8-129.9c-34.4 0-62.4-28-62.4-62.3s28-62.3 62.4-62.3 62.4 28 62.4 62.3-27.9 62.3-62.4 62.3zm0.1-15.6c25.9 0 46.9-21 46.9-46.8 0-25.9-21-46.8-46.9-46.8s-46.9 21-46.9 46.8c0.1 25.8 21.1 46.8 46.9 46.8z" />
</vector>
@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="512"
android:viewportHeight="512">
<path
android:fillColor="@android:color/white"
android:pathData="M369.9 318.2c44.3 54.3 64.7 98.8 54.4 118.7-7.9 15.1-56.7 44.6-92.6 55.9-29.6 9.3-68.4 13.3-100.4 10.2-38.2-3.7-76.9-17.4-110.1-39C93.3 445.8 87 438.3 87 423.4c0-29.9 32.9-82.3 89.2-142.1 32-33.9 76.5-73.7 81.4-72.6 9.4 2.1 84.3 75.1 112.3 109.5zM188.6 143.8c-29.7-26.9-58.1-53.9-86.4-63.4-15.2-5.1-16.3-4.8-28.7 8.1-29.2 30.4-53.5 79.7-60.3 122.4-5.4 34.2-6.1 43.8-4.2 60.5 5.6 50.5 17.3 85.4 40.5 120.9 9.5 14.6 12.1 17.3 9.3 9.9-4.2-11-0.3-37.5 9.5-64 14.3-39 53.9-112.9 120.3-194.4zm311.6 63.5C483.3 127.3 432.7 77 425.6 77c-7.3 0-24.2 6.5-36 13.9-23.3 14.5-41 31.4-64.3 52.8C367.7 197 427.5 283.1 448.2 346c6.8 20.7 9.7 41.1 7.4 52.3-1.7 8.5-1.7 8.5 1.4 4.6 6.1-7.7 19.9-31.3 25.4-43.5 7.4-16.2 15-40.2 18.6-58.7 4.3-22.5 3.9-70.8-0.8-93.4zM141.3 43C189 40.5 251 77.5 255.6 78.4c0.7 0.1 10.4-4.2 21.6-9.7 63.9-31.1 94-25.8 107.4-25.2-63.9-39.3-152.7-50-233.9-11.7-23.4 11.1-24 11.9-9.4 11.2z" />
</vector>
@@ -9,6 +9,13 @@
android:paddingTop="@dimen/fast_login_or_register_margin"
android:paddingBottom="@dimen/fast_login_or_register_margin">
<androidx.constraintlayout.widget.Group
android:id="@+id/content_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:constraint_referenced_ids="ivLogo,tbPhoneNumber,tbSmsCode,btnSendSms,btnSubmit,tvAgreementAndPrivacy"
xamarin:managedType="AndroidX.ConstraintLayout.Widget.Group" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/ivLogo"
android:layout_width="160dp"
@@ -1,17 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:xamarin="http://schemas.xamarin.com/android/xamarin/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/fast_login_or_register_margin"
android:layout_marginEnd="@dimen/fast_login_or_register_margin">
android:layout_marginEnd="@dimen/fast_login_or_register_margin"
android:clickable="true"
android:focusable="true"
android:foreground="?android:attr/selectableItemBackground"
app:cardUseCompatPadding="true">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:focusable="true"
android:orientation="horizontal">
<View
@@ -28,10 +31,11 @@
android:layout_alignEnd="@+id/bgIcon"
android:layout_centerVertical="true"
android:tint="@color/white"
tools:src="@drawable/mdi_rocket_black_24"
tools:src="@drawable/icon_steam_24"
xamarin:managedType="AndroidX.AppCompat.Widget.AppCompatImageView" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tvTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
@@ -3,6 +3,7 @@
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
<dimen name="fast_login_or_register_margin">22dp</dimen>
<dimen name="fast_login_or_register_margin_subtract_compat_padding">17dp</dimen>
<dimen name="user_profile_vertical_margin">24dp</dimen>
<dimen name="user_profile_avater_nickname_vertical_space">16dp</dimen>
<dimen name="avater_border_width">1px</dimen>
@@ -0,0 +1,37 @@
using Android.Graphics;
using Android.Views;
using System.Application.UI.Adapters;
using System.Application.UI.ViewModels;
// ReSharper disable once CheckNamespace
namespace AndroidX.RecyclerView.Widget
{
/// <summary>
/// 列表项的垂直间距
/// </summary>
public sealed class VerticalItemViewDecoration : RecyclerView.ItemDecoration
{
readonly int height;
public VerticalItemViewDecoration(int height)
{
this.height = height;
}
public override void GetItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state)
{
base.GetItemOffsets(outRect, view, parent, state);
var holder = parent.GetChildViewHolder(view);
var position = holder.BindingAdapterPosition;
if (parent.GetAdapter() is IReadOnlyViewModels<object> viewModels)
{
if (position < viewModels.ViewModels.Count - 1)
{
// 除了末尾项之外,底部添加相同的间距
outRect.Bottom = height;
}
}
}
}
}
@@ -4,10 +4,11 @@ using ReactiveUI;
using System.Application.UI.Adapters;
using System.Application.UI.ViewModels;
// ReSharper disable once CheckNamespace
namespace AndroidX.RecyclerView.Widget
{
/// <summary>
/// 列表项的垂直间距
/// 列表组项的垂直间距
/// </summary>
public sealed class VerticalItemViewGroupDecoration : RecyclerView.ItemDecoration
{
@@ -19,6 +19,11 @@ namespace System
ResIcon.baseline_settings_black_24 => Resource.Drawable.baseline_settings_black_24,
ResIcon.baseline_sports_esports_black_24 => Resource.Drawable.baseline_sports_esports_black_24,
ResIcon.baseline_verified_user_black_24 => Resource.Drawable.baseline_verified_user_black_24,
ResIcon.Steam => Resource.Drawable.icon_steam_24,
ResIcon.Xbox => Resource.Drawable.icon_xbox_24,
ResIcon.Apple => Resource.Drawable.icon_apple_24,
ResIcon.QQ => Resource.Drawable.icon_qq_24,
ResIcon.Phone => Resource.Drawable.icon_phone_24,
_ => (int?)null,
};
return resId;
@@ -37,4 +42,4 @@ namespace System
}
}
}
}
}
@@ -1,4 +1,4 @@
<Project Sdk="MSBuild.Sdk.Extras">
<Project Sdk="MSBuild.Sdk.Extras">
<PropertyGroup>
<TargetFramework>MonoAndroid11.0</TargetFramework>
@@ -57,6 +57,9 @@
<Compile Include="..\Common.ClientLib.Droid\Extensions\ContextExtensions.cs">
<LinkBase>Extensions</LinkBase>
</Compile>
<Compile Include="..\Common.ClientLib.Droid\Extensions\ActivityExtensions.cs">
<LinkBase>Extensions</LinkBase>
</Compile>
<Compile Include="..\Common.ClientLib.Droid\Extensions\ActivityManagerExtensions.cs">
<LinkBase>Extensions</LinkBase>
</Compile>
@@ -85,10 +88,15 @@
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="..\Common.ClientLib.Droid\Properties\SR.resx">
<EmbeddedResource Include="..\Common.ClientLib.Droid\Application\Properties\SR.resx">
<LinkBase>Properties</LinkBase>
<LastGenOutput>SR.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Include="..\Common.ClientLib.Droid\Application\Properties\SR.*.resx">
<LinkBase>Properties</LinkBase>
</EmbeddedResource>
<Compile Include="..\Common.ClientLib.Droid\Properties\SR.Designer.cs">
<Compile Include="..\Common.ClientLib.Droid\Application\Properties\SR.Designer.cs">
<DesignTime>True</DesignTime>
<LinkBase>Properties</LinkBase>
</Compile>
</ItemGroup>
@@ -100,6 +108,8 @@
<PackageReference Include="ReactiveUI.AndroidX" Version="13.3.2" />
<PackageReference Include="TencentOpenApiSDK.Android" Version="3.5.4.11" />
<PackageReference Include="Xamarin.AndroidX.Migration" Version="1.0.8" />
<PackageReference Include="Xamarin.AndroidX.Legacy.Support.Core.UI" Version="1.0.0.8" />
<PackageReference Include="Xamarin.AndroidX.Lifecycle.LiveData" Version="2.3.1" />
<!--dependencies implementation-->
<PackageReference Include="de.hdodenhof.circleimageview" Version="3.1.0" />
<PackageReference Include="Xamarin.AndroidX.AppCompat" Version="1.3.0" />
@@ -174,6 +184,21 @@
<AndroidResource Include="..\ST.Client.Mobile.Droid.Design\ui\src\main\res\drawable\bg_textbox.xml">
<Link>Resources\drawable\bg_textbox.xml</Link>
</AndroidResource>
<AndroidResource Include="..\ST.Client.Mobile.Droid.Design\ui\src\main\res\drawable\icon_apple_24.xml">
<Link>Resources\drawable\icon_apple_24.xml</Link>
</AndroidResource>
<AndroidResource Include="..\ST.Client.Mobile.Droid.Design\ui\src\main\res\drawable\icon_phone_24.xml">
<Link>Resources\drawable\icon_phone_24.xml</Link>
</AndroidResource>
<AndroidResource Include="..\ST.Client.Mobile.Droid.Design\ui\src\main\res\drawable\icon_qq_24.xml">
<Link>Resources\drawable\icon_qq_24.xml</Link>
</AndroidResource>
<AndroidResource Include="..\ST.Client.Mobile.Droid.Design\ui\src\main\res\drawable\icon_steam_24.xml">
<Link>Resources\drawable\icon_steam_24.xml</Link>
</AndroidResource>
<AndroidResource Include="..\ST.Client.Mobile.Droid.Design\ui\src\main\res\drawable\icon_xbox_24.xml">
<Link>Resources\drawable\icon_xbox_24.xml</Link>
</AndroidResource>
<AndroidResource Include="..\ST.Client.Mobile.Droid.Design\ui\src\main\res\drawable\mdi_rocket_black_24.xml">
<Link>Resources\drawable\mdi_rocket_black_24.xml</Link>
</AndroidResource>
@@ -444,3 +469,5 @@
@@ -41,9 +41,9 @@ namespace System.Application.UI.Activities
{
base.OnCreate(savedInstanceState);
SetSupportActionBar(binding!.toolbar);
this.SetSupportActionBarWithNavigationClick(binding!.toolbar);
ViewModel = new();
ViewModel = new() { Close = OnBackPressed };
ViewModel.AddTo(this);
var appBarConfiguration = new AppBarConfiguration.Builder(Resource.Id.navigation_login_or_register_fast).Build();
@@ -0,0 +1,57 @@
using Android.Views;
using Binding;
using ReactiveUI;
using System.Application.UI.ViewModels;
using Xamarin.Essentials;
using TViewHolder = System.Application.UI.Adapters.FastLoginChannelViewHolder;
using TViewModel = System.Application.UI.ViewModels.LoginOrRegisterPageViewModel.FastLoginChannelViewModel;
namespace System.Application.UI.Adapters
{
internal sealed class FastLoginChannelAdapter : BaseReactiveRecycleViewAdapter<TViewHolder, TViewModel>
{
public FastLoginChannelAdapter(LoginOrRegisterPageViewModel viewModel) : base(viewModel.FastLoginChannels)
{
}
public override int? GetLayoutResource(int viewType)
{
return Resource.Layout.layout_login_and_register_by_fast_channel;
}
}
internal sealed class FastLoginChannelViewHolder : BaseReactiveViewHolder<TViewModel>
{
readonly layout_login_and_register_by_fast_channel binding;
public FastLoginChannelViewHolder(View itemView) : base(itemView)
{
binding = new(itemView);
}
public override void OnBind()
{
base.OnBind();
ViewModel!.WhenAnyValue(x => x.Icon).Subscribe(value =>
{
binding.ivIcon.SetImageResourceIcon(value);
}).AddTo(this);
ViewModel!.WhenAnyValue(x => x.Title).Subscribe(value =>
{
binding.tvTitle.Text = value;
}).AddTo(this);
ViewModel!.WhenAnyValue(x => x.IconBgColor).Subscribe(value =>
{
if (value == default)
{
binding.bgIcon.Background = null;
}
else
{
binding.bgIcon.SetBackgroundColor(value.ToPlatformColor());
}
}).AddTo(this);
}
}
}
@@ -83,6 +83,15 @@ namespace System.Application.UI.Adapters
public virtual View? ItemLongClickView => null;
}
public static partial class RecycleViewAdapterHelper
{
public static View? GetView<TViewModel>(this ItemClickEventArgs<TViewModel> eventArgs)
{
if (eventArgs is PlatformItemClickEventArgs<TViewModel> eventArgs_) return eventArgs_.View;
return null;
}
}
}
// ReSharper disable once CheckNamespace
@@ -44,11 +44,7 @@ namespace System.Application.UI.Adapters
return base.GetItemViewType(position, viewModel);
}
}
}
// ReSharper disable once CheckNamespace
namespace System.Application.UI.Adapters.Internals
{
public static partial class RecycleViewAdapterHelper
{
public static bool IsImplItemViewType<TViewModel>()
@@ -50,11 +50,7 @@ namespace System.Application.UI.Adapters
return holder;
}
}
}
// ReSharper disable once CheckNamespace
namespace System.Application.UI.Adapters.Internals
{
public static partial class RecycleViewAdapterHelper
{
public static TViewHolder CreateViewHolder<TViewHolder>(View itemView)
@@ -1,14 +1,17 @@
using Android.Runtime;
using Android.Text.Method;
using Android.Views;
using AndroidX.RecyclerView.Widget;
using Binding;
using ReactiveUI;
using System.Application.Mvvm;
using System.Application.UI.Activities;
using System.Application.UI.Adapters;
using System.Application.UI.Resx;
using System.Application.UI.ViewModels;
using System.Collections.Generic;
using System.Reactive.Disposables;
using static System.Application.UI.ViewModels.LoginOrRegisterPageViewModel;
namespace System.Application.UI.Fragments
{
@@ -34,6 +37,24 @@ namespace System.Application.UI.Fragments
binding.tvAgreementAndPrivacy.TextFormatted = LoginOrRegisterActivity.CreateAgreementAndPrivacy(ViewModel!);
}
}).AddTo(this);
var adapter = new FastLoginChannelAdapter(ViewModel!);
adapter.ItemClick += (_, e) =>
{
switch (e.Current.Id)
{
case FastLoginChannelViewModel.PhoneNumber:
GoToUsePhoneNumberPage(e.GetView());
break;
default:
ViewModel!.ChooseChannel.Invoke(e.Current.Id);
break;
}
};
var layout = new LinearLayoutManager(Context, LinearLayoutManager.Vertical, false);
binding.rvFastLoginChannels.SetLayoutManager(layout);
binding.rvFastLoginChannels.AddItemDecoration(new VerticalItemViewDecoration(Context.Resources!.GetDimensionPixelSize(Resource.Dimension.fast_login_or_register_margin_subtract_compat_padding)));
binding.rvFastLoginChannels.SetAdapter(adapter);
}
void GoToUsePhoneNumberPage(View? view)
@@ -28,11 +28,40 @@ namespace System.Application.UI.Fragments
R.Current.WhenAnyValue(x => x.Res).Subscribe(_ =>
{
if (binding != null)
if (binding == null) return;
binding.tbPhoneNumber.Hint = AppResources.User_Phone;
binding.tbSmsCode.Hint = AppResources.SMSCode;
binding.btnSubmit.Text = AppResources.LoginAndRegister;
binding.tvAgreementAndPrivacy.TextFormatted = LoginOrRegisterActivity.CreateAgreementAndPrivacy(ViewModel!);
if (!ViewModel!.IsUnTimeLimit)
{
binding.tvAgreementAndPrivacy.TextFormatted = LoginOrRegisterActivity.CreateAgreementAndPrivacy(ViewModel!);
binding.btnSendSms.Text = AppResources.User_GetSMSCode;
}
}).AddTo(this);
ViewModel!.WhenAnyValue(x => x.IsLoading).Subscribe(value =>
{
if (binding == null) return;
binding.loading.Visibility = value ? ViewStates.Visible : ViewStates.Gone;
binding.content_group.Visibility = !value ? ViewStates.Visible : ViewStates.Gone;
}).AddTo(this);
SetOnClickListener(binding.btnSendSms, binding.btnSubmit);
}
protected override bool OnClick(View view)
{
if (view.Id == Resource.Id.btnSendSms)
{
ViewModel!.SendSms.Invoke();
return true;
}
else if (view.Id == Resource.Id.btnSubmit)
{
ViewModel!.Submit.Invoke();
return true;
}
return base.OnClick(view);
}
}
}
@@ -38,20 +38,16 @@ namespace System.Application.UI
return name == PackageName;
}
IsMainProcess = GetIsMainProcess();
var level = DILevel.Min;
if (IsMainProcess) level = DILevel.MainProcess;
Startup.Init(level);
if (IsMainProcess)
{
AllowStart = DeviceSecurityCheckUtil.IsSupported(
enableEmulator: _ThisAssembly.Debuggable,
allowXposed: true,
allowRoot: true);
}
var level = DILevel.Min;
if (IsMainProcess) level = DILevel.MainProcess;
Startup.Init(level);
if (IsMainProcess)
{
XEVersionTracking.Track();
}
+7 -9
View File
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
@@ -35,7 +35,7 @@
<Compile Include="..\ST.Client.Desktop\Mvvm\*.cs">
<LinkBase>Mvvm</LinkBase>
</Compile>
<Compile Remove="..\ST.Client.Desktop\Mvvm\CompositeDisposable.cs" />
<Compile Remove="..\ST.Client.Desktop\Mvvm\CompositeDisposable.cs"/>
<Compile Include="..\ST.Client.Desktop\UI\ViewModels\AreaUIHelper.cs">
<LinkBase>UI\ViewModels</LinkBase>
</Compile>
@@ -63,18 +63,16 @@
<Compile Include="..\ST.Client.Desktop\Services\Implementation\FontManagerImpl.cs">
<LinkBase>Services\Implementation</LinkBase>
</Compile>
<Compile Include="..\ST.Client.Desktop\ServiceCollectionExtensions.TryAddFontManager.cs" />
<Compile Include="..\ST.Client.Desktop\ServiceCollectionExtensions.TryAddFontManager.cs"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ST.Client\ST.Client.csproj" />
<ProjectReference Include="..\ST.Client\ST.Client.csproj"/>
</ItemGroup>
<ItemGroup>
<PackageReference Include="ReactiveUI" Version="13.3.2" />
<PackageReference Include="Microsoft.Identity.Client" Version="4.32.1" />
<PackageReference Include="ReactiveUI" Version="13.3.2"/>
<PackageReference Include="Microsoft.Identity.Client" Version="4.32.1"/>
<!--<PackageReference Include="StatefulModel.Standard" Version="0.1.0" />-->
<PackageReference Include="System.Drawing.Common" Version="5.0.2" />
</ItemGroup>
</Project>
</Project>
+9 -5
View File
@@ -1,7 +1,3 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace System.Application.UI
{
/// <summary>
@@ -11,6 +7,7 @@ namespace System.Application.UI
{
none,
avater_default,
#if __MOBILE__
baseline_account_box_black_24,
baseline_info_black_24,
baseline_person_black_24,
@@ -18,5 +15,12 @@ namespace System.Application.UI
baseline_settings_black_24,
baseline_sports_esports_black_24,
baseline_verified_user_black_24,
#endif
Steam,
Xbox,
Apple,
QQ,
Phone,
}
}
}
@@ -1,3 +1,4 @@
// ReSharper disable once CheckNamespace
namespace System.Application.UI.ViewModels
{
partial class PageViewModel
@@ -0,0 +1,64 @@
using ReactiveUI;
using System.Application.Mvvm;
using System.Application.UI.Resx;
// ReSharper disable once CheckNamespace
namespace System.Application.UI.ViewModels
{
public abstract class RIdTitleIconViewModel<TId, TIcon> : IdTitleIconViewModel<TId, TIcon>, IDisposable
{
IDisposable? disposable;
bool disposedValue;
/// <summary>
/// 绑定父视图模型
/// </summary>
/// <param name="vm"></param>
/// <returns></returns>
protected virtual void OnBind(IDisposableHolder vm)
{
disposable = R.Current.WhenAnyValue(x => x.Res).Subscribe(_ =>
{
Title = GetTitleById(id);
});
disposable.AddTo(vm);
}
/// <summary>
/// 解绑父视图模型
/// </summary>
/// <param name="vm"></param>
/// <returns></returns>
protected virtual void OnUnbind(IDisposableHolder vm)
{
if (disposable != null)
{
disposable.RemoveTo(vm);
}
}
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
// TODO: 释放托管状态(托管对象)
disposable?.Dispose();
}
// TODO: 释放未托管的资源(未托管的对象)并重写终结器
// TODO: 将大型字段设置为 null
disposable = null;
disposedValue = true;
}
}
public void Dispose()
{
// 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
}
}
@@ -1,4 +1,5 @@
using Microsoft.Identity.Client;
using ReactiveUI;
using System.Application.Services;
using System.Threading.Tasks;
using System.Windows.Input;
@@ -45,19 +45,19 @@ namespace System.Application.UI.ViewModels
nickNameNullValLangChangeSubscribe = null;
NickName = value.NickName;
var editProfile = preferenceButtons.FirstOrDefault(x => x.Id == PreferenceButton.EditProfile);
if (editProfile == null)
{
editProfile = PreferenceButtonViewModel.Create(PreferenceButton.EditProfile, this);
preferenceButtons.Insert(0, editProfile);
}
//var editProfile = preferenceButtons.FirstOrDefault(x => x.Id == PreferenceButton.EditProfile);
//if (editProfile == null)
//{
// editProfile = PreferenceButtonViewModel.Create(PreferenceButton.EditProfile, this);
// preferenceButtons.Insert(0, editProfile);
//}
var phoneNumber = preferenceButtons.FirstOrDefault(x => PreferenceButtonViewModel.IsPhoneNumber(x.Id));
if (phoneNumber == null)
{
phoneNumber = PreferenceButtonViewModel.Create(PreferenceButtonViewModel.GetPhoneNumberId(UserService.Current.HasPhoneNumber), this);
preferenceButtons.Insert(1, phoneNumber);
}
//var phoneNumber = preferenceButtons.FirstOrDefault(x => PreferenceButtonViewModel.IsPhoneNumber(x.Id));
//if (phoneNumber == null)
//{
// phoneNumber = PreferenceButtonViewModel.Create(PreferenceButtonViewModel.GetPhoneNumberId(UserService.Current.HasPhoneNumber), this);
// preferenceButtons.Insert(1, phoneNumber);
//}
}
}).AddTo(this);
@@ -108,7 +108,7 @@ namespace System.Application.UI.ViewModels
/// <summary>
/// 我的选项按钮视图模型
/// </summary>
public sealed class PreferenceButtonViewModel : ReactiveObject, IDisposable, IReadOnlyItemViewGroup
public sealed class PreferenceButtonViewModel : RIdTitleIconViewModel<PreferenceButton, ResIcon>, IReadOnlyItemViewGroup
{
PreferenceButtonViewModel()
{
@@ -116,12 +116,7 @@ namespace System.Application.UI.ViewModels
public int ItemViewGroup { get; set; }
/// <summary>
/// 根据键获取标题文本
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
static string GetTitleById(PreferenceButton id)
protected override string GetTitleById(PreferenceButton id)
{
var title = id switch
{
@@ -135,12 +130,7 @@ namespace System.Application.UI.ViewModels
return title;
}
/// <summary>
/// 根据键获取图标
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
static ResIcon GetIconById(PreferenceButton id)
protected override ResIcon GetIconById(PreferenceButton id)
{
var icon = id switch
{
@@ -161,11 +151,13 @@ namespace System.Application.UI.ViewModels
/// <returns></returns>
public static bool IsPhoneNumber(PreferenceButton id) => id == PreferenceButton.BindPhoneNumber || id == PreferenceButton.ChangePhoneNumber;
#if DEBUG
/// <summary>
/// 从选项按钮组中移除已登录才有的选项组
/// </summary>
/// <param name="collection"></param>
/// <param name="vm"></param>
[Obsolete("未登录时不隐藏选项,点击相关选项跳转登录", true)]
public static void RemoveAuthorized(ICollection<PreferenceButtonViewModel> collection, IDisposableHolder vm)
{
var removeArray = collection.Where(x => IsPhoneNumber(x.Id) || x.Id == PreferenceButton.EditProfile).ToArray();
@@ -175,6 +167,7 @@ namespace System.Application.UI.ViewModels
x.OnUnbind(vm);
});
}
#endif
/// <summary>
/// 根据是否有手机号码确定键为[绑定手机]还是[换绑手机]
@@ -186,72 +179,6 @@ namespace System.Application.UI.ViewModels
return hasPhoneNumber ? PreferenceButton.ChangePhoneNumber : PreferenceButton.BindPhoneNumber;
}
PreferenceButton id;
/// <summary>
/// 唯一键
/// </summary>
public PreferenceButton Id
{
get => id;
set
{
if (this.RaiseAndSetIfChanged2(ref id, value)) return;
Title = GetTitleById(value);
Icon = GetIconById(value);
}
}
string title = string.Empty;
/// <summary>
/// 标题文本
/// </summary>
public string Title
{
get => title;
set => this.RaiseAndSetIfChanged(ref title, value);
}
ResIcon icon;
/// <summary>
/// 图标
/// </summary>
public ResIcon Icon
{
get => icon;
set => this.RaiseAndSetIfChanged(ref icon, value);
}
IDisposable? disposable;
/// <summary>
/// 绑定父视图模型
/// </summary>
/// <param name="vm"></param>
/// <returns></returns>
PreferenceButtonViewModel OnBind(IDisposableHolder vm)
{
disposable = R.Current.WhenAnyValue(x => x.Res).Subscribe(_ =>
{
Title = GetTitleById(id);
});
disposable.AddTo(vm);
return this;
}
/// <summary>
/// 解绑父视图模型
/// </summary>
/// <param name="vm"></param>
/// <returns></returns>
PreferenceButtonViewModel OnUnbind(IDisposableHolder vm)
{
if (disposable != null)
{
disposable.RemoveTo(vm);
}
return this;
}
/// <summary>
/// 创建实例
/// </summary>
@@ -265,8 +192,6 @@ namespace System.Application.UI.ViewModels
return r;
}
public void Dispose() => disposable?.Dispose();
static bool GetAuthentication(PreferenceButton id)
{
var r = id switch