diff --git a/src/Common.ClientLib.Droid/Properties/SR.Designer.cs b/src/Common.ClientLib.Droid/Application/Properties/SR.Designer.cs similarity index 92% rename from src/Common.ClientLib.Droid/Properties/SR.Designer.cs rename to src/Common.ClientLib.Droid/Application/Properties/SR.Designer.cs index 62f4652e8..ae1e5f709 100644 --- a/src/Common.ClientLib.Droid/Properties/SR.Designer.cs +++ b/src/Common.ClientLib.Droid/Application/Properties/SR.Designer.cs @@ -60,6 +60,15 @@ namespace System.Application.Properties { } } + /// + /// 查找类似 此应用不支持在模拟器中运行 的本地化字符串。 + /// + internal static string ExitCode_IsEmulator { + get { + return ResourceManager.GetString("ExitCode_IsEmulator", resourceCulture); + } + } + /// /// 查找类似 此应用不支持在有ROOT权限的设备中运行 的本地化字符串。 /// diff --git a/src/Common.ClientLib.Droid/Properties/SR.en.resx b/src/Common.ClientLib.Droid/Application/Properties/SR.en.resx similarity index 100% rename from src/Common.ClientLib.Droid/Properties/SR.en.resx rename to src/Common.ClientLib.Droid/Application/Properties/SR.en.resx diff --git a/src/Common.ClientLib.Droid/Properties/SR.ja.resx b/src/Common.ClientLib.Droid/Application/Properties/SR.ja.resx similarity index 100% rename from src/Common.ClientLib.Droid/Properties/SR.ja.resx rename to src/Common.ClientLib.Droid/Application/Properties/SR.ja.resx diff --git a/src/Common.ClientLib.Droid/Properties/SR.ko.resx b/src/Common.ClientLib.Droid/Application/Properties/SR.ko.resx similarity index 100% rename from src/Common.ClientLib.Droid/Properties/SR.ko.resx rename to src/Common.ClientLib.Droid/Application/Properties/SR.ko.resx diff --git a/src/Common.ClientLib.Droid/Properties/SR.resx b/src/Common.ClientLib.Droid/Application/Properties/SR.resx similarity index 97% rename from src/Common.ClientLib.Droid/Properties/SR.resx rename to src/Common.ClientLib.Droid/Application/Properties/SR.resx index 24f5cc777..bbcaafb88 100644 --- a/src/Common.ClientLib.Droid/Properties/SR.resx +++ b/src/Common.ClientLib.Droid/Application/Properties/SR.resx @@ -117,6 +117,9 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + 此应用不支持在模拟器中运行 + 此应用不支持在有ROOT权限的设备中运行 diff --git a/src/Common.ClientLib.Droid/Properties/SR.ru.resx b/src/Common.ClientLib.Droid/Application/Properties/SR.ru.resx similarity index 100% rename from src/Common.ClientLib.Droid/Properties/SR.ru.resx rename to src/Common.ClientLib.Droid/Application/Properties/SR.ru.resx diff --git a/src/Common.ClientLib.Droid/Properties/SR.zh-Hant.resx b/src/Common.ClientLib.Droid/Application/Properties/SR.zh-Hant.resx similarity index 100% rename from src/Common.ClientLib.Droid/Properties/SR.zh-Hant.resx rename to src/Common.ClientLib.Droid/Application/Properties/SR.zh-Hant.resx diff --git a/src/Common.ClientLib.Droid/Application/Security/DeviceSecurityCheckUtil.cs b/src/Common.ClientLib.Droid/Application/Security/DeviceSecurityCheckUtil.cs index 3029b2637..9ef88ef1a 100644 --- a/src/Common.ClientLib.Droid/Application/Security/DeviceSecurityCheckUtil.cs +++ b/src/Common.ClientLib.Droid/Application/Security/DeviceSecurityCheckUtil.cs @@ -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; diff --git a/src/Common.ClientLib.Droid/Common.ClientLib.Droid.csproj b/src/Common.ClientLib.Droid/Common.ClientLib.Droid.csproj index 31b65273f..4e9cc8f5c 100644 --- a/src/Common.ClientLib.Droid/Common.ClientLib.Droid.csproj +++ b/src/Common.ClientLib.Droid/Common.ClientLib.Droid.csproj @@ -1,4 +1,4 @@ - + MonoAndroid11.0 @@ -42,8 +42,14 @@ - + True + + + + SR.Designer.cs + + \ No newline at end of file diff --git a/src/Common.ClientLib.Droid/Extensions/ActivityExtensions.cs b/src/Common.ClientLib.Droid/Extensions/ActivityExtensions.cs index 8b557e8d6..bc81c9028 100644 --- a/src/Common.ClientLib.Droid/Extensions/ActivityExtensions.cs +++ b/src/Common.ClientLib.Droid/Extensions/ActivityExtensions.cs @@ -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(); + } } } \ No newline at end of file diff --git a/src/Common.ClientLib/Application/UI/ViewModels/IdTitleIconViewModel.cs b/src/Common.ClientLib/Application/UI/ViewModels/IdTitleIconViewModel.cs new file mode 100644 index 000000000..12ab9b4b0 --- /dev/null +++ b/src/Common.ClientLib/Application/UI/ViewModels/IdTitleIconViewModel.cs @@ -0,0 +1,62 @@ +using ReactiveUI; + +namespace System.Application.UI.ViewModels +{ + public abstract class IdTitleIconViewModel : ReactiveObject + { + protected TId? id; + /// + /// 唯一键 + /// + 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; + /// + /// 标题文本 + /// + public virtual string Title + { + get => title; + set => this.RaiseAndSetIfChanged(ref title, value); + } + + protected TIcon? icon; + /// + /// 图标 + /// + public TIcon? Icon + { + get => icon; + set => this.RaiseAndSetIfChanged(ref icon, value); + } + + /// + /// 根据键获取标题文本 + /// + /// + /// + protected abstract string GetTitleById(TId? id); + + /// + /// 根据键获取图标 + /// + /// + /// + protected abstract TIcon GetIconById(TId? id); + } +} \ No newline at end of file diff --git a/src/ST.Client.Desktop/Extensions/HandleWindowExtensions.cs b/src/ST.Client.Desktop/Extensions/HandleWindowExtensions.cs index 59ab924de..4277986ae 100644 --- a/src/ST.Client.Desktop/Extensions/HandleWindowExtensions.cs +++ b/src/ST.Client.Desktop/Extensions/HandleWindowExtensions.cs @@ -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 { diff --git a/src/ST.Client.Desktop/Extensions/ProcessExtensions.cs b/src/ST.Client.Desktop/Extensions/ProcessExtensions.cs index 23830c4b5..4ec231ae3 100644 --- a/src/ST.Client.Desktop/Extensions/ProcessExtensions.cs +++ b/src/ST.Client.Desktop/Extensions/ProcessExtensions.cs @@ -1,8 +1,8 @@ -using System.Application.Services; +using System.Application.Services; using System.Diagnostics; // ReSharper disable once CheckNamespace -namespace System.Application +namespace System { /// /// 为 类型提供扩展方法 diff --git a/src/ST.Client.Desktop/Extensions/PropertyChangedExtensions.cs b/src/ST.Client.Desktop/Extensions/PropertyChangedExtensions.cs index 2913f3072..047a65a45 100644 --- a/src/ST.Client.Desktop/Extensions/PropertyChangedExtensions.cs +++ b/src/ST.Client.Desktop/Extensions/PropertyChangedExtensions.cs @@ -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 { diff --git a/src/ST.Client.Desktop/Extensions/StartupArgsExtensions.cs b/src/ST.Client.Desktop/Extensions/StartupArgsExtensions.cs index 5a8c3d288..483bda79d 100644 --- a/src/ST.Client.Desktop/Extensions/StartupArgsExtensions.cs +++ b/src/ST.Client.Desktop/Extensions/StartupArgsExtensions.cs @@ -1,5 +1,5 @@ -// ReSharper disable once CheckNamespace -namespace System.Application +// ReSharper disable once CheckNamespace +namespace System { public static class StartupArgsExtensions { diff --git a/src/ST.Client.Desktop/Extensions/SteamAppPropertyExtensions.cs b/src/ST.Client.Desktop/Extensions/SteamAppPropertyExtensions.cs index ba227c9f2..cd8ec1fed 100644 --- a/src/ST.Client.Desktop/Extensions/SteamAppPropertyExtensions.cs +++ b/src/ST.Client.Desktop/Extensions/SteamAppPropertyExtensions.cs @@ -5,6 +5,7 @@ using System.Drawing; using System.IO; using System.Text; +// ReSharper disable once CheckNamespace namespace System.Application { public static class SteamAppPropertyExtensions diff --git a/src/ST.Client.Desktop/Extensions/TaskExtensions.cs b/src/ST.Client.Desktop/Extensions/TaskExtensions.cs index 8d1e25183..782677600 100644 --- a/src/ST.Client.Desktop/Extensions/TaskExtensions.cs +++ b/src/ST.Client.Desktop/Extensions/TaskExtensions.cs @@ -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 { diff --git a/src/ST.Client.Desktop/Extensions/ViewModelExtensions.cs b/src/ST.Client.Desktop/Extensions/ViewModelExtensions.cs index 0dba25b71..f489a4631 100644 --- a/src/ST.Client.Desktop/Extensions/ViewModelExtensions.cs +++ b/src/ST.Client.Desktop/Extensions/ViewModelExtensions.cs @@ -1,6 +1,7 @@ using System.Application.Mvvm; -namespace System.Application +// ReSharper disable once CheckNamespace +namespace System { public static class ViewModelExtensions { diff --git a/src/ST.Client.Desktop/ST.Client.Desktop.csproj b/src/ST.Client.Desktop/ST.Client.Desktop.csproj index 73c92a987..7436ce83a 100644 --- a/src/ST.Client.Desktop/ST.Client.Desktop.csproj +++ b/src/ST.Client.Desktop/ST.Client.Desktop.csproj @@ -1,4 +1,4 @@ - + net6.0 @@ -16,6 +16,12 @@ Properties\InternalsVisibleTo.cs + + UI\ViewModels\Base + + + UI + diff --git a/src/ST.Client.Desktop/Services/IFontManager.cs b/src/ST.Client.Desktop/Services/IFontManager.cs index 7fbc6d067..96071c7b8 100644 --- a/src/ST.Client.Desktop/Services/IFontManager.cs +++ b/src/ST.Client.Desktop/Services/IFontManager.cs @@ -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> 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>(); +#endif } } } \ No newline at end of file diff --git a/src/ST.Client.Desktop/UI/ViewModels/Base/ViewModelBase.cs b/src/ST.Client.Desktop/UI/ViewModels/Base/ViewModelBase.cs index b118f6572..82eddf666 100644 --- a/src/ST.Client.Desktop/UI/ViewModels/Base/ViewModelBase.cs +++ b/src/ST.Client.Desktop/UI/ViewModels/Base/ViewModelBase.cs @@ -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 diff --git a/src/ST.Client.Desktop/UI/ViewModels/Base/WindowViewModel.shared.cs b/src/ST.Client.Desktop/UI/ViewModels/Base/WindowViewModel.shared.cs index 54285f77b..d3b8cd3ba 100644 --- a/src/ST.Client.Desktop/UI/ViewModels/Base/WindowViewModel.shared.cs +++ b/src/ST.Client.Desktop/UI/ViewModels/Base/WindowViewModel.shared.cs @@ -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 diff --git a/src/ST.Client.Desktop/UI/ViewModels/Windows/LoginOrRegisterWindowViewModel.shared.cs b/src/ST.Client.Desktop/UI/ViewModels/Windows/LoginOrRegisterWindowViewModel.shared.cs index 462138b2d..16cf3f8a3 100644 --- a/src/ST.Client.Desktop/UI/ViewModels/Windows/LoginOrRegisterWindowViewModel.shared.cs +++ b/src/ST.Client.Desktop/UI/ViewModels/Windows/LoginOrRegisterWindowViewModel.shared.cs @@ -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(async channel => { await FastLoginOrRegisterAsync(Close, channel); }); +#endif ChooseChannel = ReactiveCommand.CreateFromTask(async channel => { if (Enum.TryParse(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 + /// + /// 选择快速登录渠道点击命令,参数类型为 .Id + /// public ICommand ChooseChannel { get; } protected override void Dispose(bool disposing) @@ -255,5 +270,96 @@ namespace System.Application.UI.ViewModels } base.Dispose(disposing); } + + ObservableCollection fastLoginChannels; + /// + /// 快速登录渠道组 + /// + public ObservableCollection FastLoginChannels + { + get => fastLoginChannels; + set => this.RaiseAndSetIfChanged(ref fastLoginChannels, value); + } + + public sealed class FastLoginChannelViewModel : RIdTitleIconViewModel + { + 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); + } + + /// + /// 创建实例 + /// + /// + /// + /// + public static FastLoginChannelViewModel Create(string id, IDisposableHolder vm) + { + FastLoginChannelViewModel r = new() { Id = id, }; + r.OnBind(vm); + return r; + } + } } } \ No newline at end of file diff --git a/src/ST.Client.Mobile.Droid.App/ST.Client.Mobile.Droid.App.csproj b/src/ST.Client.Mobile.Droid.App/ST.Client.Mobile.Droid.App.csproj index 1e1ffe148..6c9110026 100644 --- a/src/ST.Client.Mobile.Droid.App/ST.Client.Mobile.Droid.App.csproj +++ b/src/ST.Client.Mobile.Droid.App/ST.Client.Mobile.Droid.App.csproj @@ -83,6 +83,11 @@ + + + + + {e7468fdd-75f7-4b08-ba47-b715bbcfcc11} diff --git a/src/ST.Client.Mobile.Droid.Design/ui/src/main/res/drawable/icon_apple_24.xml b/src/ST.Client.Mobile.Droid.Design/ui/src/main/res/drawable/icon_apple_24.xml new file mode 100644 index 000000000..0b044ef2d --- /dev/null +++ b/src/ST.Client.Mobile.Droid.Design/ui/src/main/res/drawable/icon_apple_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/src/ST.Client.Mobile.Droid.Design/ui/src/main/res/drawable/icon_phone_24.xml b/src/ST.Client.Mobile.Droid.Design/ui/src/main/res/drawable/icon_phone_24.xml new file mode 100644 index 000000000..fc1099281 --- /dev/null +++ b/src/ST.Client.Mobile.Droid.Design/ui/src/main/res/drawable/icon_phone_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/src/ST.Client.Mobile.Droid.Design/ui/src/main/res/drawable/icon_qq_24.xml b/src/ST.Client.Mobile.Droid.Design/ui/src/main/res/drawable/icon_qq_24.xml new file mode 100644 index 000000000..14409598b --- /dev/null +++ b/src/ST.Client.Mobile.Droid.Design/ui/src/main/res/drawable/icon_qq_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/src/ST.Client.Mobile.Droid.Design/ui/src/main/res/drawable/icon_steam_24.xml b/src/ST.Client.Mobile.Droid.Design/ui/src/main/res/drawable/icon_steam_24.xml new file mode 100644 index 000000000..bb7a1a545 --- /dev/null +++ b/src/ST.Client.Mobile.Droid.Design/ui/src/main/res/drawable/icon_steam_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/src/ST.Client.Mobile.Droid.Design/ui/src/main/res/drawable/icon_xbox_24.xml b/src/ST.Client.Mobile.Droid.Design/ui/src/main/res/drawable/icon_xbox_24.xml new file mode 100644 index 000000000..dae59088f --- /dev/null +++ b/src/ST.Client.Mobile.Droid.Design/ui/src/main/res/drawable/icon_xbox_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/src/ST.Client.Mobile.Droid.Design/ui/src/main/res/layout/fragment_login_and_register_by_phone_number_content.xml b/src/ST.Client.Mobile.Droid.Design/ui/src/main/res/layout/fragment_login_and_register_by_phone_number_content.xml index 2b95bab0b..2ba933203 100644 --- a/src/ST.Client.Mobile.Droid.Design/ui/src/main/res/layout/fragment_login_and_register_by_phone_number_content.xml +++ b/src/ST.Client.Mobile.Droid.Design/ui/src/main/res/layout/fragment_login_and_register_by_phone_number_content.xml @@ -9,6 +9,13 @@ android:paddingTop="@dimen/fast_login_or_register_margin" android:paddingBottom="@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"> 16dp 16dp 22dp + 17dp 24dp 16dp 1px diff --git a/src/ST.Client.Mobile.Droid/AndroidX.RecyclerView.Widget/VerticalItemViewDecoration.cs b/src/ST.Client.Mobile.Droid/AndroidX.RecyclerView.Widget/VerticalItemViewDecoration.cs new file mode 100644 index 000000000..527b0f8b8 --- /dev/null +++ b/src/ST.Client.Mobile.Droid/AndroidX.RecyclerView.Widget/VerticalItemViewDecoration.cs @@ -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 +{ + /// + /// 列表项的垂直间距 + /// + 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 viewModels) + { + if (position < viewModels.ViewModels.Count - 1) + { + // 除了末尾项之外,底部添加相同的间距 + outRect.Bottom = height; + } + } + } + } +} \ No newline at end of file diff --git a/src/ST.Client.Mobile.Droid/AndroidX.RecyclerView.Widget/VerticalItemViewGroupDecoration.cs b/src/ST.Client.Mobile.Droid/AndroidX.RecyclerView.Widget/VerticalItemViewGroupDecoration.cs index a1fe3632a..5480e3767 100644 --- a/src/ST.Client.Mobile.Droid/AndroidX.RecyclerView.Widget/VerticalItemViewGroupDecoration.cs +++ b/src/ST.Client.Mobile.Droid/AndroidX.RecyclerView.Widget/VerticalItemViewGroupDecoration.cs @@ -4,10 +4,11 @@ using ReactiveUI; using System.Application.UI.Adapters; using System.Application.UI.ViewModels; +// ReSharper disable once CheckNamespace namespace AndroidX.RecyclerView.Widget { /// - /// 列表项的垂直间距 + /// 列表组项的垂直间距 /// public sealed class VerticalItemViewGroupDecoration : RecyclerView.ItemDecoration { diff --git a/src/ST.Client.Mobile.Droid/Extensions/ResIconEnumExtensions.cs b/src/ST.Client.Mobile.Droid/Extensions/ResIconEnumExtensions.cs index 2a329e6e8..217afee0d 100644 --- a/src/ST.Client.Mobile.Droid/Extensions/ResIconEnumExtensions.cs +++ b/src/ST.Client.Mobile.Droid/Extensions/ResIconEnumExtensions.cs @@ -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 } } } -} \ No newline at end of file +} diff --git a/src/ST.Client.Mobile.Droid/ST.Client.Mobile.Droid.csproj b/src/ST.Client.Mobile.Droid/ST.Client.Mobile.Droid.csproj index 1407c2262..53f2246ed 100644 --- a/src/ST.Client.Mobile.Droid/ST.Client.Mobile.Droid.csproj +++ b/src/ST.Client.Mobile.Droid/ST.Client.Mobile.Droid.csproj @@ -1,4 +1,4 @@ - + MonoAndroid11.0 @@ -57,6 +57,9 @@ Extensions + + Extensions + Extensions @@ -85,10 +88,15 @@ - + + Properties + SR.Designer.cs + + Properties - + + True Properties @@ -100,6 +108,8 @@ + + @@ -174,6 +184,21 @@ Resources\drawable\bg_textbox.xml + + Resources\drawable\icon_apple_24.xml + + + Resources\drawable\icon_phone_24.xml + + + Resources\drawable\icon_qq_24.xml + + + Resources\drawable\icon_steam_24.xml + + + Resources\drawable\icon_xbox_24.xml + Resources\drawable\mdi_rocket_black_24.xml @@ -444,3 +469,5 @@ + + diff --git a/src/ST.Client.Mobile.Droid/UI/Activities/LoginOrRegisterActivity.cs b/src/ST.Client.Mobile.Droid/UI/Activities/LoginOrRegisterActivity.cs index ab4d05dc3..9d1fe7db4 100644 --- a/src/ST.Client.Mobile.Droid/UI/Activities/LoginOrRegisterActivity.cs +++ b/src/ST.Client.Mobile.Droid/UI/Activities/LoginOrRegisterActivity.cs @@ -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(); diff --git a/src/ST.Client.Mobile.Droid/UI/Adapters/FastLoginChannelAdapter.cs b/src/ST.Client.Mobile.Droid/UI/Adapters/FastLoginChannelAdapter.cs new file mode 100644 index 000000000..235ec82ab --- /dev/null +++ b/src/ST.Client.Mobile.Droid/UI/Adapters/FastLoginChannelAdapter.cs @@ -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 + { + 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 + { + 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); + } + } +} \ No newline at end of file diff --git a/src/ST.Client.Mobile.Droid/UI/Base/Features/ItemClick.cs b/src/ST.Client.Mobile.Droid/UI/Base/Features/ItemClick.cs index 5ec9759f4..dd3f802a1 100644 --- a/src/ST.Client.Mobile.Droid/UI/Base/Features/ItemClick.cs +++ b/src/ST.Client.Mobile.Droid/UI/Base/Features/ItemClick.cs @@ -83,6 +83,15 @@ namespace System.Application.UI.Adapters public virtual View? ItemLongClickView => null; } + + public static partial class RecycleViewAdapterHelper + { + public static View? GetView(this ItemClickEventArgs eventArgs) + { + if (eventArgs is PlatformItemClickEventArgs eventArgs_) return eventArgs_.View; + return null; + } + } } // ReSharper disable once CheckNamespace diff --git a/src/ST.Client.Mobile.Droid/UI/Base/Features/RecycleViewAdapter.GetItemViewType.cs b/src/ST.Client.Mobile.Droid/UI/Base/Features/RecycleViewAdapter.GetItemViewType.cs index 94db5dc36..a5a7af9e2 100644 --- a/src/ST.Client.Mobile.Droid/UI/Base/Features/RecycleViewAdapter.GetItemViewType.cs +++ b/src/ST.Client.Mobile.Droid/UI/Base/Features/RecycleViewAdapter.GetItemViewType.cs @@ -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() diff --git a/src/ST.Client.Mobile.Droid/UI/Base/Features/RecycleViewAdapter.OnCreateViewHolder.cs b/src/ST.Client.Mobile.Droid/UI/Base/Features/RecycleViewAdapter.OnCreateViewHolder.cs index f441f638f..d815df83a 100644 --- a/src/ST.Client.Mobile.Droid/UI/Base/Features/RecycleViewAdapter.OnCreateViewHolder.cs +++ b/src/ST.Client.Mobile.Droid/UI/Base/Features/RecycleViewAdapter.OnCreateViewHolder.cs @@ -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(View itemView) diff --git a/src/ST.Client.Mobile.Droid/UI/Fragments/FastLoginOrRegisterFragment.cs b/src/ST.Client.Mobile.Droid/UI/Fragments/FastLoginOrRegisterFragment.cs index dde5c798d..b22bc66ce 100644 --- a/src/ST.Client.Mobile.Droid/UI/Fragments/FastLoginOrRegisterFragment.cs +++ b/src/ST.Client.Mobile.Droid/UI/Fragments/FastLoginOrRegisterFragment.cs @@ -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) diff --git a/src/ST.Client.Mobile.Droid/UI/Fragments/PhoneNumberLoginOrRegisterFragment.cs b/src/ST.Client.Mobile.Droid/UI/Fragments/PhoneNumberLoginOrRegisterFragment.cs index 89adad848..a4662f02f 100644 --- a/src/ST.Client.Mobile.Droid/UI/Fragments/PhoneNumberLoginOrRegisterFragment.cs +++ b/src/ST.Client.Mobile.Droid/UI/Fragments/PhoneNumberLoginOrRegisterFragment.cs @@ -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); } } } \ No newline at end of file diff --git a/src/ST.Client.Mobile.Droid/UI/MainApplication.cs b/src/ST.Client.Mobile.Droid/UI/MainApplication.cs index 4a398331b..adf66cee6 100644 --- a/src/ST.Client.Mobile.Droid/UI/MainApplication.cs +++ b/src/ST.Client.Mobile.Droid/UI/MainApplication.cs @@ -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(); } diff --git a/src/ST.Client.Mobile/ST.Client.Mobile.csproj b/src/ST.Client.Mobile/ST.Client.Mobile.csproj index 33e93c3be..9f52d4044 100644 --- a/src/ST.Client.Mobile/ST.Client.Mobile.csproj +++ b/src/ST.Client.Mobile/ST.Client.Mobile.csproj @@ -1,4 +1,4 @@ - + netstandard2.1 @@ -35,7 +35,7 @@ Mvvm - + UI\ViewModels @@ -63,18 +63,16 @@ Services\Implementation - + - + - - + + - - - + \ No newline at end of file diff --git a/src/ST.Client.Mobile/UI/ResIcon.cs b/src/ST.Client.Mobile/UI/ResIcon.cs index ca2a27ac1..00ed3e930 100644 --- a/src/ST.Client.Mobile/UI/ResIcon.cs +++ b/src/ST.Client.Mobile/UI/ResIcon.cs @@ -1,7 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Text; - namespace System.Application.UI { /// @@ -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, } -} +} \ No newline at end of file diff --git a/src/ST.Client.Mobile/UI/ViewModels/Base/PageViewModel.cs b/src/ST.Client.Mobile/UI/ViewModels/Base/PageViewModel.cs index 132f25dbf..1495bffa2 100644 --- a/src/ST.Client.Mobile/UI/ViewModels/Base/PageViewModel.cs +++ b/src/ST.Client.Mobile/UI/ViewModels/Base/PageViewModel.cs @@ -1,3 +1,4 @@ +// ReSharper disable once CheckNamespace namespace System.Application.UI.ViewModels { partial class PageViewModel diff --git a/src/ST.Client.Mobile/UI/ViewModels/Base/RIdTitleIconViewModel.cs b/src/ST.Client.Mobile/UI/ViewModels/Base/RIdTitleIconViewModel.cs new file mode 100644 index 000000000..593693041 --- /dev/null +++ b/src/ST.Client.Mobile/UI/ViewModels/Base/RIdTitleIconViewModel.cs @@ -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 : IdTitleIconViewModel, IDisposable + { + IDisposable? disposable; + bool disposedValue; + + /// + /// 绑定父视图模型 + /// + /// + /// + protected virtual void OnBind(IDisposableHolder vm) + { + disposable = R.Current.WhenAnyValue(x => x.Res).Subscribe(_ => + { + Title = GetTitleById(id); + }); + disposable.AddTo(vm); + } + + /// + /// 解绑父视图模型 + /// + /// + /// + 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); + } + } +} \ No newline at end of file diff --git a/src/ST.Client.Mobile/UI/ViewModels/LoginOrRegisterPageViewModel.cs b/src/ST.Client.Mobile/UI/ViewModels/LoginOrRegisterPageViewModel.cs index 92c9f2531..ece06db1e 100644 --- a/src/ST.Client.Mobile/UI/ViewModels/LoginOrRegisterPageViewModel.cs +++ b/src/ST.Client.Mobile/UI/ViewModels/LoginOrRegisterPageViewModel.cs @@ -1,4 +1,5 @@ using Microsoft.Identity.Client; +using ReactiveUI; using System.Application.Services; using System.Threading.Tasks; using System.Windows.Input; diff --git a/src/ST.Client.Mobile/UI/ViewModels/MyPageViewModel.cs b/src/ST.Client.Mobile/UI/ViewModels/MyPageViewModel.cs index 16ae974c4..29a137e07 100644 --- a/src/ST.Client.Mobile/UI/ViewModels/MyPageViewModel.cs +++ b/src/ST.Client.Mobile/UI/ViewModels/MyPageViewModel.cs @@ -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 /// /// 我的选项按钮视图模型 /// - public sealed class PreferenceButtonViewModel : ReactiveObject, IDisposable, IReadOnlyItemViewGroup + public sealed class PreferenceButtonViewModel : RIdTitleIconViewModel, IReadOnlyItemViewGroup { PreferenceButtonViewModel() { @@ -116,12 +116,7 @@ namespace System.Application.UI.ViewModels public int ItemViewGroup { get; set; } - /// - /// 根据键获取标题文本 - /// - /// - /// - 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; } - /// - /// 根据键获取图标 - /// - /// - /// - static ResIcon GetIconById(PreferenceButton id) + protected override ResIcon GetIconById(PreferenceButton id) { var icon = id switch { @@ -161,11 +151,13 @@ namespace System.Application.UI.ViewModels /// public static bool IsPhoneNumber(PreferenceButton id) => id == PreferenceButton.BindPhoneNumber || id == PreferenceButton.ChangePhoneNumber; +#if DEBUG /// /// 从选项按钮组中移除已登录才有的选项组 /// /// /// + [Obsolete("未登录时不隐藏选项,点击相关选项跳转登录", true)] public static void RemoveAuthorized(ICollection 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 /// /// 根据是否有手机号码确定键为[绑定手机]还是[换绑手机] @@ -186,72 +179,6 @@ namespace System.Application.UI.ViewModels return hasPhoneNumber ? PreferenceButton.ChangePhoneNumber : PreferenceButton.BindPhoneNumber; } - PreferenceButton id; - /// - /// 唯一键 - /// - public PreferenceButton Id - { - get => id; - set - { - if (this.RaiseAndSetIfChanged2(ref id, value)) return; - Title = GetTitleById(value); - Icon = GetIconById(value); - } - } - - string title = string.Empty; - /// - /// 标题文本 - /// - public string Title - { - get => title; - set => this.RaiseAndSetIfChanged(ref title, value); - } - - ResIcon icon; - /// - /// 图标 - /// - public ResIcon Icon - { - get => icon; - set => this.RaiseAndSetIfChanged(ref icon, value); - } - - IDisposable? disposable; - - /// - /// 绑定父视图模型 - /// - /// - /// - PreferenceButtonViewModel OnBind(IDisposableHolder vm) - { - disposable = R.Current.WhenAnyValue(x => x.Res).Subscribe(_ => - { - Title = GetTitleById(id); - }); - disposable.AddTo(vm); - return this; - } - - /// - /// 解绑父视图模型 - /// - /// - /// - PreferenceButtonViewModel OnUnbind(IDisposableHolder vm) - { - if (disposable != null) - { - disposable.RemoveTo(vm); - } - return this; - } - /// /// 创建实例 /// @@ -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