From 3142e554710cda46f6f5e6c794c1902e44c3da2a Mon Sep 17 00:00:00 2001 From: Aigio Liu Date: Wed, 10 Nov 2021 14:54:03 +0800 Subject: [PATCH] UserAccountBindFragment --- src/AboutAppInfoPopup.cs | 5 + .../UI/Fragments/UserAccountBindFragment.cs | 101 +++- .../ST.Client.Windows.csproj | 1 + .../ServiceCollectionExtensions.cs | 6 +- .../Services/Implementation/SevenZipHelper.cs | 49 ++ .../fragment_account_binding_content.xml | 472 +++++++++--------- src/ST.Client/ST.Client.csproj | 1 - src/ST.Client/Services/ISevenZipHelper.cs | 24 + .../ApplicationUpdateServiceBaseImpl.cs | 64 ++- src/ST.Client/SevenZipHelper.cs | 54 -- src/ST.Client/UI/ResIcon.cs | 20 + src/ST.Client/UI/Resx/R.cs | 8 +- .../UI/ViewModels/ThirdPartyLoginHelper.cs | 8 + .../Windows/LoginOrRegisterWindowViewModel.cs | 18 +- src/ST/FastLoginChannel.cs | 27 + 15 files changed, 513 insertions(+), 345 deletions(-) create mode 100644 src/ST.Client.Desktop.Windows/Services/Implementation/SevenZipHelper.cs create mode 100644 src/ST.Client/Services/ISevenZipHelper.cs delete mode 100644 src/ST.Client/SevenZipHelper.cs diff --git a/src/AboutAppInfoPopup.cs b/src/AboutAppInfoPopup.cs index 2ffdd6b7b..1f62ec928 100644 --- a/src/AboutAppInfoPopup.cs +++ b/src/AboutAppInfoPopup.cs @@ -17,6 +17,7 @@ using System.Application.Services; using System.Reflection; using Microsoft.Extensions.DependencyInjection; using System.Collections.Generic; +using System.Application.Services.Implementation; // ReSharper disable once CheckNamespace namespace System.Application.UI @@ -136,6 +137,10 @@ namespace System.Application.UI b.AppendLine(); #endif + b.Append("[app.updcha] "); + b.Append(ApplicationUpdateServiceBaseImpl.UpdateChannelType); + b.AppendLine(); + b.Append("[clr.ver] "); string? clrVersion; try diff --git a/src/ST.Client.Android/UI/Fragments/UserAccountBindFragment.cs b/src/ST.Client.Android/UI/Fragments/UserAccountBindFragment.cs index 8f2f3482b..628e52204 100644 --- a/src/ST.Client.Android/UI/Fragments/UserAccountBindFragment.cs +++ b/src/ST.Client.Android/UI/Fragments/UserAccountBindFragment.cs @@ -1,4 +1,5 @@ using Android.Views; +using Android.Widget; using Binding; using ReactiveUI; using System.Application.Services; @@ -13,43 +14,76 @@ namespace System.Application.UI.Fragments { protected override int? LayoutResource => Resource.Layout.fragment_account_binding; - static readonly Dictionary btnAccountBindDict = new() - { - { Resource.Id.btnAccountBindSteam, FastLoginChannel.Steam }, - { Resource.Id.btnAccountBindMicrosoft, FastLoginChannel.Microsoft }, - { Resource.Id.btnAccountBindApple, FastLoginChannel.Apple }, - { Resource.Id.btnAccountBindQQ, FastLoginChannel.QQ }, - }; - static readonly Dictionary tbAccountBindDict = new() - { - { Resource.Id.tbAccountBindSteam, FastLoginChannel.Steam }, - { Resource.Id.tbAccountBindMicrosoft, FastLoginChannel.Microsoft }, - { Resource.Id.tbAccountBindApple, FastLoginChannel.Apple }, - { Resource.Id.tbAccountBindQQ, FastLoginChannel.QQ }, - }; + Button[]? btnAccountBinds; + EditText[]? tbAccountBinds; + ImageView[]? ivIconAccountBinds; public override void OnCreateView(View view) { base.OnCreateView(view); - var btnAccountBinds = new[] { binding!.btnAccountBindSteam, binding.btnAccountBindMicrosoft, binding.btnAccountBindApple, binding.btnAccountBindQQ, }; - var tbAccountBinds = new[] { binding.tbAccountBindSteam, binding.tbAccountBindMicrosoft, binding.tbAccountBindApple, binding.tbAccountBindQQ, }; + btnAccountBinds = new[] { + binding!.btnAccountBind0, + binding.btnAccountBind1, + binding.btnAccountBind2, + binding.btnAccountBind3, + }; + tbAccountBinds = new[] { + binding.tbAccountBind0, + binding.tbAccountBind1, + binding.tbAccountBind2, + binding.tbAccountBind3, + }; + ivIconAccountBinds = new[] + { + binding.ivIconAccountBind0, + binding.ivIconAccountBind1, + binding.ivIconAccountBind2, + binding.ivIconAccountBind3, + }; + + for (int i = 0; i < ivIconAccountBinds.Length; i++) + { + var iconResId = ThirdPartyLoginHelper.FastLoginChannels[i] + .ToIcon().ToImageResource(); + if (iconResId.HasValue) + { + ivIconAccountBinds[i].SetImageResource(iconResId.Value); + } + } UserService.Current.WhenAnyValue(x => x.HasPhoneNumber).SubscribeInMainThread(value => { if (binding == null) return; - foreach (var item in btnAccountBinds) + for (int i = 0; i < btnAccountBinds.Length; i++) { - item.Enabled = value; + var item = btnAccountBinds[i]; + var cha = ThirdPartyLoginHelper.FastLoginChannels[i]; + if (cha.IsSupported()) + { + if (item.Enabled != value) + { + item.Enabled = value; + } + } + else if (item.Enabled) + { + item.Enabled = false; + } } }).AddTo(this); UserService.Current.WhenAnyValue(x => x.User).SubscribeInMainThread(value => { if (binding == null) return; - foreach (var item in tbAccountBinds) + for (int i = 0; i < tbAccountBinds.Length; i++) { - item.Text = GetIsBindOrUnbundleTbText(tbAccountBindDict[item.Id]) ?? string.Empty; + var item = tbAccountBinds[i]; + var cha = ThirdPartyLoginHelper.FastLoginChannels[i]; + if (cha.IsSupported()) + { + item.Text = GetIsBindOrUnbundleTbText(cha) ?? string.Empty; + } } }).AddTo(this); @@ -63,9 +97,18 @@ namespace System.Application.UI.Fragments binding.tvAccountBindTip.Text = AppResources.User_AccountBindTip; - foreach (var item in btnAccountBinds) + for (int i = 0; i < btnAccountBinds.Length; i++) { - item.Text = GetIsBindOrUnbundleBtnText(btnAccountBindDict[item.Id]); + var item = btnAccountBinds[i]; + var cha = ThirdPartyLoginHelper.FastLoginChannels[i]; + if (cha.IsSupported()) + { + item.Text = GetIsBindOrUnbundleBtnText(cha); + } + else + { + item.Text = AppResources.UnderConstruction; + } } }).AddTo(this); @@ -74,10 +117,18 @@ namespace System.Application.UI.Fragments protected override bool OnClick(View view) { - if (btnAccountBindDict.ContainsKey(view.Id)) + for (int i = 0; i < btnAccountBinds!.Length; i++) { - ViewModel!.OnBindOrUnbundleFastLoginClick(btnAccountBindDict[view.Id]); - return true; + var item = btnAccountBinds[i]; + if (item.Id == view.Id) + { + var cha = ThirdPartyLoginHelper.FastLoginChannels[i]; + if (cha.IsSupported()) + { + ViewModel!.OnBindOrUnbundleFastLoginClick(cha); + return true; + } + } } return base.OnClick(view); } diff --git a/src/ST.Client.Desktop.Windows/ST.Client.Windows.csproj b/src/ST.Client.Desktop.Windows/ST.Client.Windows.csproj index cdf9fd545..4a0db0c4b 100644 --- a/src/ST.Client.Desktop.Windows/ST.Client.Windows.csproj +++ b/src/ST.Client.Desktop.Windows/ST.Client.Windows.csproj @@ -41,6 +41,7 @@ + diff --git a/src/ST.Client.Desktop.Windows/ServiceCollectionExtensions.cs b/src/ST.Client.Desktop.Windows/ServiceCollectionExtensions.cs index a1c5c0d7d..5b7e1ceaa 100644 --- a/src/ST.Client.Desktop.Windows/ServiceCollectionExtensions.cs +++ b/src/ST.Client.Desktop.Windows/ServiceCollectionExtensions.cs @@ -36,8 +36,12 @@ namespace Microsoft.Extensions.DependencyInjection } services.AddSingleton(); services.AddSingleton(); - if (options.HasMainProcessRequired) services.AddNotifyIcon(); + if (options.HasMainProcessRequired) + { + services.AddNotifyIcon(); + } //services.AddSingleton(); + services.AddSingleton(); } else { diff --git a/src/ST.Client.Desktop.Windows/Services/Implementation/SevenZipHelper.cs b/src/ST.Client.Desktop.Windows/Services/Implementation/SevenZipHelper.cs new file mode 100644 index 000000000..ec4648099 --- /dev/null +++ b/src/ST.Client.Desktop.Windows/Services/Implementation/SevenZipHelper.cs @@ -0,0 +1,49 @@ +using SevenZip; +using System.IO; +using CC = System.Common.Constants; + +namespace System.Application.Services.Implementation +{ + internal sealed class SevenZipHelper : ISevenZipHelper + { + public static bool IsInitialized { get; private set; } + + static void Initialize() + { + if (IsInitialized) return; + // ✅ AppContext.BaseDirectory + var sevenZipLibraryPath = Path.Combine(AppContext.BaseDirectory, "7z.dll"); + SevenZipBase.SetLibraryPath(sevenZipLibraryPath); + IsInitialized = true; + } + + public bool Unpack(string filePath, string dirPath, + IProgress? progress = null, + float maxProgress = CC.MaxProgress) + { + Initialize(); + + if (!File.Exists(filePath)) return false; + if (Directory.Exists(dirPath)) return false; + + using var fs = File.OpenRead(filePath); + float length = fs.Length; + Directory.CreateDirectory(dirPath); + using var archive = new SevenZipExtractor(fs); + var hasProgress = progress != null; + if (hasProgress) + { + archive.Extracting += (_, e) => + { + progress!.Report(e.PercentDone); + }; + } + archive.ExtractArchive(dirPath); + if (hasProgress) + { + progress!.Report(maxProgress); + } + return true; + } + } +} diff --git a/src/ST.Client.Mobile.Droid.Design/ui/src/main/res/layout/fragment_account_binding_content.xml b/src/ST.Client.Mobile.Droid.Design/ui/src/main/res/layout/fragment_account_binding_content.xml index 0f615bf85..3680909d9 100644 --- a/src/ST.Client.Mobile.Droid.Design/ui/src/main/res/layout/fragment_account_binding_content.xml +++ b/src/ST.Client.Mobile.Droid.Design/ui/src/main/res/layout/fragment_account_binding_content.xml @@ -1,264 +1,264 @@ + + + android:orientation="vertical" + app:layout_constraintGuide_begin="@dimen/activity_horizontal_margin" + xamarin:managedType="AndroidX.ConstraintLayout.Widget.Guideline" /> - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - + diff --git a/src/ST.Client/ST.Client.csproj b/src/ST.Client/ST.Client.csproj index 2eab308b1..2ebafd617 100644 --- a/src/ST.Client/ST.Client.csproj +++ b/src/ST.Client/ST.Client.csproj @@ -29,7 +29,6 @@ - diff --git a/src/ST.Client/Services/ISevenZipHelper.cs b/src/ST.Client/Services/ISevenZipHelper.cs new file mode 100644 index 000000000..0d9790f21 --- /dev/null +++ b/src/ST.Client/Services/ISevenZipHelper.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Text; +using CC = System.Common.Constants; + +namespace System.Application.Services +{ + public interface ISevenZipHelper + { + static ISevenZipHelper Instance => DI.Get_Nullable() ?? throw new PlatformNotSupportedException(); + + /// + /// 解压压缩包文件 + /// + /// 要解压的压缩包文件路径 + /// 要解压的文件夹路径,文件夹必须不存在 + /// 进度值监听 + /// + /// + bool Unpack(string filePath, string dirPath, + IProgress? progress = null, + float maxProgress = CC.MaxProgress); + } +} diff --git a/src/ST.Client/Services/Implementation/ApplicationUpdateServiceBaseImpl.cs b/src/ST.Client/Services/Implementation/ApplicationUpdateServiceBaseImpl.cs index 118ef3751..d6ca52dfb 100644 --- a/src/ST.Client/Services/Implementation/ApplicationUpdateServiceBaseImpl.cs +++ b/src/ST.Client/Services/Implementation/ApplicationUpdateServiceBaseImpl.cs @@ -24,6 +24,7 @@ namespace System.Application.Services.Implementation /// public abstract class ApplicationUpdateServiceBaseImpl : ReactiveObject, IApplicationUpdateService { + protected const string TAG = "AppUpdateS"; protected readonly ICloudServiceClient client; protected readonly AppSettings settings; protected readonly IToast toast; @@ -572,17 +573,28 @@ namespace System.Application.Services.Implementation Directory.Delete(dirPath, true); } - var isOK = await Task.Run(() => downloadType switch + var isOK = await Task.Run(() => { - AppDownloadType.Compressed_GZip - => TarGZipHelper.Unpack(value, dirPath, - progress: new Progress(OnReportDecompressing), - maxProgress: CC.MaxProgress), - AppDownloadType.Compressed_7z - => SevenZipHelper.Unpack(value, dirPath, - progress: new Progress(OnReportDecompressing), - maxProgress: CC.MaxProgress), - _ => false, + try + { + return downloadType switch + { + AppDownloadType.Compressed_GZip + => TarGZipHelper.Unpack(value, dirPath, + progress: new Progress(OnReportDecompressing), + maxProgress: CC.MaxProgress), + AppDownloadType.Compressed_7z + => ISevenZipHelper.Instance.Unpack(value, dirPath, + progress: new Progress(OnReportDecompressing), + maxProgress: CC.MaxProgress), + _ => false, + }; + } + catch (Exception ex) + { + Log.Error(TAG, ex, "Compressed unpack catch."); + return false; + } }); if (isOK) { @@ -655,18 +667,30 @@ namespace System.Application.Services.Implementation } } + /// + /// 当前应用设置的更新渠道 + /// + public static UpdateChannelType UpdateChannelType + { + get + { + var channel = GeneralSettings.UpdateChannel.Value; + switch (channel) + { + case UpdateChannelType.GitHub: + case UpdateChannelType.Gitee: + break; + default: + channel = R.IsChineseSimplified ? UpdateChannelType.Gitee : UpdateChannelType.GitHub; + break; + } + return channel; + } + } + protected virtual AppVersionDTO.Download? GetByDownloadChannelSettings(IEnumerable downloads) { - var channel = GeneralSettings.UpdateChannel.Value; - switch (channel) - { - case UpdateChannelType.GitHub: - case UpdateChannelType.Gitee: - break; - default: - channel = R.Language.StartsWith("zh") ? UpdateChannelType.Gitee : UpdateChannelType.GitHub; - break; - } + var channel = UpdateChannelType; return downloads.FirstOrDefault(x => x.DownloadChannelType == channel) ?? downloads.FirstOrDefault(); } diff --git a/src/ST.Client/SevenZipHelper.cs b/src/ST.Client/SevenZipHelper.cs deleted file mode 100644 index e5fac9655..000000000 --- a/src/ST.Client/SevenZipHelper.cs +++ /dev/null @@ -1,54 +0,0 @@ -using SevenZip; -using System.IO; -using CC = System.Common.Constants; - -namespace System.Application -{ - public static class SevenZipHelper - { - static SevenZipHelper() - { - if (OperatingSystem2.IsWindows) - { - // ✅ AppContext.BaseDirectory - var sevenZipLibraryPath = Path.Combine(AppContext.BaseDirectory, "7z.dll"); - SevenZipBase.SetLibraryPath(sevenZipLibraryPath); - } - } - - /// - /// 解压压缩包文件 - /// - /// 要解压的压缩包文件路径 - /// 要解压的文件夹路径,文件夹必须不存在 - /// 进度值监听 - /// - /// - public static bool Unpack(string filePath, string dirPath, - IProgress? progress = null, - float maxProgress = CC.MaxProgress) - { - if (!File.Exists(filePath)) return false; - if (Directory.Exists(dirPath)) return false; - - using var fs = File.OpenRead(filePath); - float length = fs.Length; - Directory.CreateDirectory(dirPath); - using var archive = new SevenZipExtractor(fs); - var hasProgress = progress != null; - if (hasProgress) - { - archive.Extracting += (_, e) => - { - progress!.Report(e.PercentDone); - }; - } - archive.ExtractArchive(dirPath); - if (hasProgress) - { - progress!.Report(maxProgress); - } - return true; - } - } -} \ No newline at end of file diff --git a/src/ST.Client/UI/ResIcon.cs b/src/ST.Client/UI/ResIcon.cs index 8536108ae..42a326fad 100644 --- a/src/ST.Client/UI/ResIcon.cs +++ b/src/ST.Client/UI/ResIcon.cs @@ -1,3 +1,6 @@ +using System.Application; +using System.Application.UI; + namespace System.Application.UI { /// @@ -23,4 +26,21 @@ namespace System.Application.UI /// PlatformPhone, } +} + +// ReSharper disable once CheckNamespace +namespace System +{ + public static class ResIconEnumExtensions + { + public static ResIcon ToIcon(this FastLoginChannel fastLoginChannel) + => fastLoginChannel switch + { + FastLoginChannel.Steam => ResIcon.Steam, + FastLoginChannel.Microsoft => ResIcon.Xbox, + FastLoginChannel.QQ => ResIcon.QQ, + FastLoginChannel.Apple => ResIcon.Apple, + _ => throw new ArgumentOutOfRangeException(nameof(fastLoginChannel), fastLoginChannel, null), + }; + } } \ No newline at end of file diff --git a/src/ST.Client/UI/Resx/R.cs b/src/ST.Client/UI/Resx/R.cs index c2ddb86ef..95327d3e1 100644 --- a/src/ST.Client/UI/Resx/R.cs +++ b/src/ST.Client/UI/Resx/R.cs @@ -28,13 +28,17 @@ namespace System.Application.UI.Resx public static CultureInfo DefaultCurrentUICulture { get; private set; } + public static bool IsChineseSimplified => IsMatch(Culture, zh_Hans); + + const string zh_Hans = "zh-Hans"; + static R() { DefaultCurrentUICulture = CultureInfo.CurrentUICulture; var languagesDict = new Dictionary(StringComparer.OrdinalIgnoreCase) { { "", "Auto" }, - { "zh-Hans", "Chinese (Simplified)" }, + { zh_Hans, "Chinese (Simplified)" }, { "zh-Hant", "Chinese (Traditional)" }, { "en", "English" }, { "ko", "Korean" }, @@ -47,7 +51,7 @@ namespace System.Application.UI.Resx SteamLanguages = new Dictionary(StringComparer.OrdinalIgnoreCase) { { "zh-CN", "schinese" }, - { "zh-Hans", "schinese" }, + { zh_Hans, "schinese" }, { "zh-Hant", "tchinese" }, { "en","english"}, { "ko", "koreana" }, diff --git a/src/ST.Client/UI/ViewModels/ThirdPartyLoginHelper.cs b/src/ST.Client/UI/ViewModels/ThirdPartyLoginHelper.cs index 8d7005251..400ff4101 100644 --- a/src/ST.Client/UI/ViewModels/ThirdPartyLoginHelper.cs +++ b/src/ST.Client/UI/ViewModels/ThirdPartyLoginHelper.cs @@ -239,6 +239,14 @@ namespace System.Application.UI.ViewModels public string Msg { get; set; } = string.Empty; } + + public static FastLoginChannel[] FastLoginChannels = new[] // 更改此数组可控制UI列表的顺序 + { + FastLoginChannel.QQ, + FastLoginChannel.Steam, + FastLoginChannel.Microsoft, + FastLoginChannel.Apple, + }; } partial class UserProfileWindowViewModel : IBindWindowViewModel diff --git a/src/ST.Client/UI/ViewModels/Windows/LoginOrRegisterWindowViewModel.cs b/src/ST.Client/UI/ViewModels/Windows/LoginOrRegisterWindowViewModel.cs index 3196365c7..e8e663e2d 100644 --- a/src/ST.Client/UI/ViewModels/Windows/LoginOrRegisterWindowViewModel.cs +++ b/src/ST.Client/UI/ViewModels/Windows/LoginOrRegisterWindowViewModel.cs @@ -55,12 +55,18 @@ namespace System.Application.UI.ViewModels IEnumerable GetFastLoginChannels() { - yield return FastLoginChannelViewModel.Create(nameof(FastLoginChannel.QQ), this); - yield return FastLoginChannelViewModel.Create(nameof(FastLoginChannel.Steam), this); - yield return FastLoginChannelViewModel.Create(nameof(FastLoginChannel.Xbox), this); -#if DEBUG - yield return FastLoginChannelViewModel.Create(nameof(FastLoginChannel.Apple), this); -#endif + foreach (var item in ThirdPartyLoginHelper.FastLoginChannels) + { + if (item.IsSupported()) + { + yield return FastLoginChannelViewModel.Create(item switch + { + FastLoginChannel.Microsoft => nameof(FastLoginChannel.Xbox), + _ => item.ToString(), + }, this); + } + } + if (IsMobileLayout) { yield return FastLoginChannelViewModel.Create(FastLoginChannelViewModel.PhoneNumber, this); diff --git a/src/ST/FastLoginChannel.cs b/src/ST/FastLoginChannel.cs index ce4b16a3c..ee36794af 100644 --- a/src/ST/FastLoginChannel.cs +++ b/src/ST/FastLoginChannel.cs @@ -1,3 +1,5 @@ +using System.Application; + namespace System.Application { /// @@ -52,4 +54,29 @@ namespace System.Application Xbox = Microsoft, } +} + +// ReSharper disable once CheckNamespace +namespace System +{ + public static class FastLoginChannelEnumExtensions + { + /// + /// 当前快速登录渠道是否已支持 + /// + /// + /// + public static bool IsSupported(this FastLoginChannel fastLoginChannel) +#if DEBUG + => true; +#else + => fastLoginChannel switch + { + FastLoginChannel.Steam or + FastLoginChannel.Microsoft or + FastLoginChannel.QQ => true, + _ => false, + }; +#endif + } } \ No newline at end of file