From 9e2e8d7d59de652a516c008e8928254eebb1df3e Mon Sep 17 00:00:00 2001 From: Aigio Liu Date: Tue, 22 Jun 2021 21:21:32 +0800 Subject: [PATCH] ShowWindowServiceImpl for Android --- ...llectionExtensions.AddShowWindowService.cs | 20 +++ .../ServiceCollectionExtensions.cs | 14 +- .../Windows/WpfCompatExtensions.cs | 2 +- .../LinuxDesktopPlatformServiceImpl.cs | 3 +- .../MacDesktopPlatformServiceImpl.cs | 5 +- ...atformServiceImpl.WindowTopRightButtons.cs | 7 +- src/ST.Client.Desktop/CustomWindow.cs | 6 + .../MessageBox/MessageBoxCompat.cs | 12 +- .../MessageBox/ResizeModeCompat.cs | 10 +- .../Services/IDesktopPlatformService.cs | 9 +- .../Services/IShowWindowService.cs | 5 + .../ViewModels/Base/DialogWindowViewModel.cs | 5 +- .../Pages/About/AboutPageViewModel.shared.cs | 4 - .../LocalAuthPage/PasswordWindowViewModel.cs | 25 +++- .../Windows/MessageBoxWindowViewModel.cs | 2 +- .../main/res/layout/activity_textblock.xml | 28 ++++ .../src/main/res/layout/textbox_password.xml | 31 ++++ .../GoToPlatformPages.cs | 81 +++++++++++ .../ST.Client.Mobile.Droid.csproj | 9 ++ .../ServiceCollectionExtensions.cs | 2 +- .../Implementation/ShowWindowServiceImpl.cs | 136 ++++++++++++++++++ .../UI/Activities/AboutActivity.cs | 6 +- .../UI/Activities/TextBlockActivity.cs | 47 ++++++ .../UI/Fragments/CommunityFixFragment.cs | 7 +- .../UI/Fragments/GameListFragment.cs | 6 +- .../UI/ViewModels/TextBlockViewModel.cs | 24 ++++ src/ST.Client.Mobile/ST.Client.Mobile.csproj | 31 +++- src/Startup2.cs | 3 +- 28 files changed, 477 insertions(+), 63 deletions(-) create mode 100644 src/ST.Client.Desktop.Avalonia/ServiceCollectionExtensions.AddShowWindowService.cs create mode 100644 src/ST.Client.Mobile.Droid.Design/ui/src/main/res/layout/activity_textblock.xml create mode 100644 src/ST.Client.Mobile.Droid.Design/ui/src/main/res/layout/textbox_password.xml create mode 100644 src/ST.Client.Mobile.Droid/Services/Implementation/ShowWindowServiceImpl.cs create mode 100644 src/ST.Client.Mobile.Droid/UI/Activities/TextBlockActivity.cs create mode 100644 src/ST.Client.Mobile.Droid/UI/ViewModels/TextBlockViewModel.cs diff --git a/src/ST.Client.Desktop.Avalonia/ServiceCollectionExtensions.AddShowWindowService.cs b/src/ST.Client.Desktop.Avalonia/ServiceCollectionExtensions.AddShowWindowService.cs new file mode 100644 index 000000000..c690e43a3 --- /dev/null +++ b/src/ST.Client.Desktop.Avalonia/ServiceCollectionExtensions.AddShowWindowService.cs @@ -0,0 +1,20 @@ +using System.Application.Services; +using System.Application.Services.Implementation; + +// ReSharper disable once CheckNamespace +namespace Microsoft.Extensions.DependencyInjection +{ + public static partial class ServiceCollectionExtensions + { + /// + /// 添加显示窗口服务 + /// + /// + /// + public static IServiceCollection AddShowWindowService(this IServiceCollection services) + { + services.AddSingleton(); + return services; + } + } +} \ No newline at end of file diff --git a/src/ST.Client.Desktop.Avalonia/ServiceCollectionExtensions.cs b/src/ST.Client.Desktop.Avalonia/ServiceCollectionExtensions.cs index 7edf49c52..702509002 100644 --- a/src/ST.Client.Desktop.Avalonia/ServiceCollectionExtensions.cs +++ b/src/ST.Client.Desktop.Avalonia/ServiceCollectionExtensions.cs @@ -1,5 +1,4 @@ using Avalonia.Controls; -using System; using System.Application.Services; using System.Application.Services.Implementation; using System.Application.UI; @@ -7,7 +6,7 @@ using System.Application.UI; // ReSharper disable once CheckNamespace namespace Microsoft.Extensions.DependencyInjection { - public static class ServiceCollectionExtensions + public static partial class ServiceCollectionExtensions { /// /// 添加主线程助手类(MainThreadDesktop)服务 @@ -20,17 +19,6 @@ namespace Microsoft.Extensions.DependencyInjection return services; } - /// - /// 添加显示窗口服务 - /// - /// - /// - public static IServiceCollection AddShowWindowService(this IServiceCollection services) - { - services.AddSingleton(); - return services; - } - /// /// 添加应用程序更新服务 /// diff --git a/src/ST.Client.Desktop.Avalonia/Windows/WpfCompatExtensions.cs b/src/ST.Client.Desktop.Avalonia/Windows/WpfCompatExtensions.cs index 56632b5b4..60967575a 100644 --- a/src/ST.Client.Desktop.Avalonia/Windows/WpfCompatExtensions.cs +++ b/src/ST.Client.Desktop.Avalonia/Windows/WpfCompatExtensions.cs @@ -31,7 +31,7 @@ namespace System.Windows window.CanResize = true; break; } - p.SetResizeMode(window.PlatformImpl.Handle.Handle, (int)value); + p.SetResizeMode(window.PlatformImpl.Handle.Handle, value); } static readonly bool IsWin32NT = Environment.OSVersion.Platform == PlatformID.Win32NT; diff --git a/src/ST.Client.Desktop.Linux/Services/Implementation/LinuxDesktopPlatformServiceImpl.cs b/src/ST.Client.Desktop.Linux/Services/Implementation/LinuxDesktopPlatformServiceImpl.cs index 4321b7aab..a313e8900 100644 --- a/src/ST.Client.Desktop.Linux/Services/Implementation/LinuxDesktopPlatformServiceImpl.cs +++ b/src/ST.Client.Desktop.Linux/Services/Implementation/LinuxDesktopPlatformServiceImpl.cs @@ -1,12 +1,13 @@ using System.Application.Models; using System.Diagnostics; using System.IO; +using System.Windows; namespace System.Application.Services.Implementation { internal sealed partial class LinuxDesktopPlatformServiceImpl : IDesktopPlatformService { - public void SetResizeMode(IntPtr hWnd, int value) + public void SetResizeMode(IntPtr hWnd, ResizeModeCompat value) { } diff --git a/src/ST.Client.Desktop.Mac/Services/Implementation/MacDesktopPlatformServiceImpl.cs b/src/ST.Client.Desktop.Mac/Services/Implementation/MacDesktopPlatformServiceImpl.cs index b50b6d16d..b5801a410 100644 --- a/src/ST.Client.Desktop.Mac/Services/Implementation/MacDesktopPlatformServiceImpl.cs +++ b/src/ST.Client.Desktop.Mac/Services/Implementation/MacDesktopPlatformServiceImpl.cs @@ -7,12 +7,13 @@ using System.Application.Models; using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; +using System.Windows; namespace System.Application.Services.Implementation { internal sealed partial class MacDesktopPlatformServiceImpl : IDesktopPlatformService { - public void SetResizeMode(IntPtr hWnd, int value) + public void SetResizeMode(IntPtr hWnd, ResizeModeCompat value) { } @@ -29,7 +30,7 @@ namespace System.Application.Services.Implementation Arguments = $"-a \"{name}\" \"{filePath}\"", }; pInfo.UseShellExecute = true; - var p = Process.Start(pInfo); + var p = Process.Start(pInfo); if (p == null) throw new FileNotFoundException(name); p.Close(); } diff --git a/src/ST.Client.Desktop.Windows/Services/Implementation/WindowsDesktopPlatformServiceImpl.WindowTopRightButtons.cs b/src/ST.Client.Desktop.Windows/Services/Implementation/WindowsDesktopPlatformServiceImpl.WindowTopRightButtons.cs index 1c288c3cd..472f97c1f 100644 --- a/src/ST.Client.Desktop.Windows/Services/Implementation/WindowsDesktopPlatformServiceImpl.WindowTopRightButtons.cs +++ b/src/ST.Client.Desktop.Windows/Services/Implementation/WindowsDesktopPlatformServiceImpl.WindowTopRightButtons.cs @@ -1,4 +1,5 @@ using System.Runtime.InteropServices; +using System.Windows; namespace System.Application.Services.Implementation { @@ -85,16 +86,16 @@ namespace System.Application.Services.Implementation _ = SetWindowLong(hWnd, GWL_STYLE, GetWindowLong(hWnd, GWL_STYLE) & ~WS_MAXIMIZEBOX); } - public void SetResizeMode(IntPtr hWnd, int value) + public void SetResizeMode(IntPtr hWnd, ResizeModeCompat value) { switch (value) { - case IDesktopPlatformService.ResizeMode_NoResize: + case ResizeModeCompat.NoResize: _ = DeleteMenu(GetSystemMenu(hWnd, false), SC_MAXIMIZE, MF_BYCOMMAND); _ = DeleteMenu(GetSystemMenu(hWnd, false), SC_MINIMIZE, MF_BYCOMMAND); HideMinimizeAndMaximizeButtons(hWnd); break; - case IDesktopPlatformService.ResizeMode_CanMinimize: + case ResizeModeCompat.CanMinimize: _ = DeleteMenu(GetSystemMenu(hWnd, false), SC_MAXIMIZE, MF_BYCOMMAND); DisableMaximizeButton(hWnd); break; diff --git a/src/ST.Client.Desktop/CustomWindow.cs b/src/ST.Client.Desktop/CustomWindow.cs index 8bc1b1541..deac5e106 100644 --- a/src/ST.Client.Desktop/CustomWindow.cs +++ b/src/ST.Client.Desktop/CustomWindow.cs @@ -5,13 +5,18 @@ namespace System.Application /// public enum CustomWindow { +#if !__MOBILE__ LoginOrRegister, +#endif MessageBox, +#if !__MOBILE__ AddAuth, ShowAuth, AuthTrade, EncryptionAuth, +#endif Password, +#if !__MOBILE__ TaskBar, ExportAuth, ScriptStore, @@ -23,5 +28,6 @@ namespace System.Application NewVersion, WebView3, BindPhoneNumber, +#endif } } \ No newline at end of file diff --git a/src/ST.Client.Desktop/MessageBox/MessageBoxCompat.cs b/src/ST.Client.Desktop/MessageBox/MessageBoxCompat.cs index 238ee9c56..cf7595554 100644 --- a/src/ST.Client.Desktop/MessageBox/MessageBoxCompat.cs +++ b/src/ST.Client.Desktop/MessageBox/MessageBoxCompat.cs @@ -1,4 +1,4 @@ -using System.Application; +using System.Application; using System.Application.Services; using System.Application.UI.ViewModels; using System.Properties; @@ -10,20 +10,20 @@ namespace System.Windows /// /// 显示消息框。 /// - public static class MessageBoxCompat + public static partial class MessageBoxCompat { const string default_caption = ThisAssembly.AssemblyTrademark; const MessageBoxButtonCompat default_button = MessageBoxButtonCompat.OK; + static readonly Lazy mbcs = + new(DI.Get_Nullable); /// public static async Task ShowAsync( string messageBoxText, string caption, MessageBoxButtonCompat button, MessageBoxImageCompat? icon = null) { - var f = DI.Get_Nullable(); - - if (f != null) + if (mbcs.Value != null) { - return await f.ShowAsync(messageBoxText, caption, button, icon); + return await mbcs.Value.ShowAsync(messageBoxText, caption, button, icon); } var viewModel = new MessageBoxWindowViewModel diff --git a/src/ST.Client.Desktop/MessageBox/ResizeModeCompat.cs b/src/ST.Client.Desktop/MessageBox/ResizeModeCompat.cs index 53f3efd68..3cc5cddab 100644 --- a/src/ST.Client.Desktop/MessageBox/ResizeModeCompat.cs +++ b/src/ST.Client.Desktop/MessageBox/ResizeModeCompat.cs @@ -1,5 +1,3 @@ -using System.Application.Services; - // ReSharper disable once CheckNamespace namespace System.Windows { @@ -11,22 +9,22 @@ namespace System.Windows /// /// 用户无法调整窗口的大小。 不显示 "最大化" 和 "最小化" 框。 /// - NoResize = IDesktopPlatformService.ResizeMode_NoResize, + NoResize, /// /// 用户只能最小化窗口并从任务栏还原。 同时显示 "最小化" 和 "最大化" 框,但只启用 "最小化" 框。 /// - CanMinimize = IDesktopPlatformService.ResizeMode_CanMinimize, + CanMinimize, /// /// 用户可以通过使用 "最小化" 和 "最大化" 框以及围绕窗口的可拖动轮廓来完全调整窗口的大小。 显示和启用 "最小化" 和 "最大化" 框。 (默认) 。 /// - CanResize = IDesktopPlatformService.ResizeMode_CanResize, + CanResize, /// /// 此选项具有与相同的功能 ,但会将 "调整手柄" 添加到窗口的右下角。 /// [Obsolete("not implemented")] - CanResizeWithGrip = IDesktopPlatformService.ResizeMode_CanResizeWithGrip, + CanResizeWithGrip, } } \ No newline at end of file diff --git a/src/ST.Client.Desktop/Services/IDesktopPlatformService.cs b/src/ST.Client.Desktop/Services/IDesktopPlatformService.cs index 3c7573694..73c2de457 100644 --- a/src/ST.Client.Desktop/Services/IDesktopPlatformService.cs +++ b/src/ST.Client.Desktop/Services/IDesktopPlatformService.cs @@ -4,7 +4,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Runtime.Versioning; using System.Security.Cryptography; -using ResizeMode = System.Int32; +using System.Windows; namespace System.Application.Services { @@ -14,7 +14,7 @@ namespace System.Application.Services public static IDesktopPlatformService Instance => DI.Get(); - void SetResizeMode(IntPtr hWnd, ResizeMode value); + void SetResizeMode(IntPtr hWnd, ResizeModeCompat value); /// /// 获取一个正在运行的进程的命令行参数。 @@ -153,11 +153,6 @@ namespace System.Application.Services #endregion - public const ResizeMode ResizeMode_NoResize = 0; - public const ResizeMode ResizeMode_CanMinimize = 1; - public const ResizeMode ResizeMode_CanResize = 2; - public const ResizeMode ResizeMode_CanResizeWithGrip = 3; - #region MachineUniqueIdentifier private static (byte[] key, byte[] iv) GetMachineSecretKey(string? value) diff --git a/src/ST.Client.Desktop/Services/IShowWindowService.cs b/src/ST.Client.Desktop/Services/IShowWindowService.cs index 7edc2050f..77275dbba 100644 --- a/src/ST.Client.Desktop/Services/IShowWindowService.cs +++ b/src/ST.Client.Desktop/Services/IShowWindowService.cs @@ -1,6 +1,9 @@ using System.Application.UI.ViewModels; using System.Threading.Tasks; using System.Windows; +#if __MOBILE__ +using WindowViewModel = System.Application.UI.ViewModels.PageViewModel; +#endif namespace System.Application.Services { @@ -67,8 +70,10 @@ namespace System.Application.Services bool isDialog = true); +#if !__MOBILE__ void CloseWindow(WindowViewModel vm); void HideWindow(WindowViewModel vm); void ShowWindow(WindowViewModel vm); +#endif } } \ No newline at end of file diff --git a/src/ST.Client.Desktop/UI/ViewModels/Base/DialogWindowViewModel.cs b/src/ST.Client.Desktop/UI/ViewModels/Base/DialogWindowViewModel.cs index db448d59c..8c914890a 100644 --- a/src/ST.Client.Desktop/UI/ViewModels/Base/DialogWindowViewModel.cs +++ b/src/ST.Client.Desktop/UI/ViewModels/Base/DialogWindowViewModel.cs @@ -1,4 +1,7 @@ -using System.Windows.Input; +using System.Windows.Input; +#if __MOBILE__ +using WindowViewModel = System.Application.UI.ViewModels.PageViewModel; +#endif namespace System.Application.UI.ViewModels { diff --git a/src/ST.Client.Desktop/UI/ViewModels/Pages/About/AboutPageViewModel.shared.cs b/src/ST.Client.Desktop/UI/ViewModels/Pages/About/AboutPageViewModel.shared.cs index 63081a4e7..780fc2b8a 100644 --- a/src/ST.Client.Desktop/UI/ViewModels/Pages/About/AboutPageViewModel.shared.cs +++ b/src/ST.Client.Desktop/UI/ViewModels/Pages/About/AboutPageViewModel.shared.cs @@ -42,15 +42,11 @@ namespace System.Application.UI.ViewModels DelAccountCommand = ReactiveCommand.CreateFromTask(async () => { if (!UserService.Current.IsAuthenticated) return; -#if !__MOBILE__ var r = await MessageBoxCompat.ShowAsync(AppResources.DelAccountTips, ThisAssembly.AssemblyTrademark, MessageBoxButtonCompat.OKCancel); if (r == MessageBoxResultCompat.OK) { await UserService.Current.DelAccountAsync(); } -#else - throw new NotImplementedException(); -#endif }); #if __MOBILE__ diff --git a/src/ST.Client.Desktop/UI/ViewModels/Windows/LocalAuthPage/PasswordWindowViewModel.cs b/src/ST.Client.Desktop/UI/ViewModels/Windows/LocalAuthPage/PasswordWindowViewModel.cs index 5f565d19d..a0028a606 100644 --- a/src/ST.Client.Desktop/UI/ViewModels/Windows/LocalAuthPage/PasswordWindowViewModel.cs +++ b/src/ST.Client.Desktop/UI/ViewModels/Windows/LocalAuthPage/PasswordWindowViewModel.cs @@ -1,11 +1,11 @@ -using Newtonsoft.Json.Linq; using ReactiveUI; -using System.Application.Models; using System.Application.Services; using System.Application.UI.Resx; -using System.Properties; using System.Threading.Tasks; using System.Windows; +#if __MOBILE__ +using WindowViewModel = System.Application.UI.ViewModels.PageViewModel; +#endif namespace System.Application.UI.ViewModels { @@ -23,7 +23,6 @@ namespace System.Application.UI.ViewModels set => this.RaiseAndSetIfChanged(ref _Password, value); } - public static async Task ShowPasswordDialog() { var vm = new PasswordWindowViewModel(); @@ -31,12 +30,25 @@ namespace System.Application.UI.ViewModels return vm.Password; } - - public void Ok() + /// + /// 输入内容验证 + /// + /// + public bool InputValidator() { if (string.IsNullOrWhiteSpace(Password)) { Toast.Show(AppResources.LocalAuth_ProtectionAuth_PasswordErrorTip); + return false; + } + return true; + } + +#if !__MOBILE__ + public void Ok() + { + if (!InputValidator()) + { return; } this.Close(); @@ -47,5 +59,6 @@ namespace System.Application.UI.ViewModels Password = string.Empty; this.Close(); } +#endif } } \ No newline at end of file diff --git a/src/ST.Client.Desktop/UI/ViewModels/Windows/MessageBoxWindowViewModel.cs b/src/ST.Client.Desktop/UI/ViewModels/Windows/MessageBoxWindowViewModel.cs index ebb69b326..774e24023 100644 --- a/src/ST.Client.Desktop/UI/ViewModels/Windows/MessageBoxWindowViewModel.cs +++ b/src/ST.Client.Desktop/UI/ViewModels/Windows/MessageBoxWindowViewModel.cs @@ -1,4 +1,4 @@ -using ReactiveUI; +using ReactiveUI; namespace System.Application.UI.ViewModels { diff --git a/src/ST.Client.Mobile.Droid.Design/ui/src/main/res/layout/activity_textblock.xml b/src/ST.Client.Mobile.Droid.Design/ui/src/main/res/layout/activity_textblock.xml new file mode 100644 index 000000000..a04f09da6 --- /dev/null +++ b/src/ST.Client.Mobile.Droid.Design/ui/src/main/res/layout/activity_textblock.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + diff --git a/src/ST.Client.Mobile.Droid.Design/ui/src/main/res/layout/textbox_password.xml b/src/ST.Client.Mobile.Droid.Design/ui/src/main/res/layout/textbox_password.xml new file mode 100644 index 000000000..9a22d0451 --- /dev/null +++ b/src/ST.Client.Mobile.Droid.Design/ui/src/main/res/layout/textbox_password.xml @@ -0,0 +1,31 @@ + + + + + + + + + diff --git a/src/ST.Client.Mobile.Droid/GoToPlatformPages.cs b/src/ST.Client.Mobile.Droid/GoToPlatformPages.cs index e66c415c3..5097abda4 100644 --- a/src/ST.Client.Mobile.Droid/GoToPlatformPages.cs +++ b/src/ST.Client.Mobile.Droid/GoToPlatformPages.cs @@ -45,5 +45,86 @@ namespace System.Application public static void StartActivity(this Fragment fragment) where TActivity : Activity => StartActivity(fragment, typeof(TActivity)); + + const string KEY_ViewModel = "ByteArrayViewModel"; + static void StartActivity(this Activity activity, Type activityType, byte[] viewModel) + { + var intent = new Intent(activity, activityType); + intent.PutExtra(KEY_ViewModel, viewModel); + activity.StartActivity(intent); + } + + public static TViewModel? GetViewModel(this Activity activity) + { + var intent = activity.Intent; + if (intent != null) + { + var byteArray = intent.GetByteArrayExtra(KEY_ViewModel); + if (byteArray != null) + { + try + { + var value = Serializable.DMP(byteArray); + return value; + } + catch + { + + } + } + } + return default; + } + + public static void StartActivity(Activity activity, Type activityType, object viewModel, Type? viewModelType = null) + { + viewModelType ??= viewModel.GetType(); + var viewModel_ = Serializable.SMP(viewModelType, viewModel); + StartActivity(activity, activityType, viewModel_); + } + + public static void StartActivity(Fragment fragment, Type activityType, object viewModel, Type? viewModelType = null) + { + var activity = fragment.Activity; + if (activity == null) return; + StartActivity(activity, activityType, viewModel, viewModelType); + } + + public static void StartActivity(Activity activity, object viewModel, Type? viewModelType = null) + { + StartActivity(activity, typeof(TActivity), viewModel, viewModelType); + } + + public static void StartActivity(Fragment fragment, object viewModel, Type? viewModelType = null) + { + var activity = fragment.Activity; + if (activity == null) return; + StartActivity(activity, viewModel, viewModelType); + } + + public static void StartActivity(Activity activity, Type activityType, TViewModel viewModel) + { + var viewModel_ = Serializable.SMP(viewModel); + StartActivity(activity, activityType, viewModel_); + } + + public static void StartActivity(Fragment fragment, Type activityType, TViewModel viewModel) + { + var activity = fragment.Activity; + if (activity == null) return; + StartActivity(activity, activityType, viewModel); + } + + public static void StartActivity(Activity activity, TViewModel viewModel) + { + StartActivity(activity, typeof(TActivity), viewModel); + } + + public static void StartActivity(Fragment fragment, TViewModel viewModel) + { + var activity = fragment.Activity; + if (activity == null) return; + StartActivity(activity, viewModel); + } } } \ 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 d65514d9f..931ac551a 100644 --- a/src/ST.Client.Mobile.Droid/ST.Client.Mobile.Droid.csproj +++ b/src/ST.Client.Mobile.Droid/ST.Client.Mobile.Droid.csproj @@ -83,6 +83,7 @@ + @@ -347,6 +348,9 @@ Resources\layout\activity_main.xml + + Resources\layout\activity_textblock.xml + Resources\layout\fragment_community_fix.xml @@ -386,6 +390,9 @@ Resources\layout\shared_toolbar.xml + + Resources\layout\textbox_password.xml + Resources\menu\bottom_nav_menu.xml @@ -482,3 +489,5 @@ + + diff --git a/src/ST.Client.Mobile.Droid/ServiceCollectionExtensions.cs b/src/ST.Client.Mobile.Droid/ServiceCollectionExtensions.cs index 1ad73706d..6d4ec9927 100644 --- a/src/ST.Client.Mobile.Droid/ServiceCollectionExtensions.cs +++ b/src/ST.Client.Mobile.Droid/ServiceCollectionExtensions.cs @@ -1,4 +1,4 @@ -using Microsoft.Extensions.Http; +using Microsoft.Extensions.Http; using System.Application.Services; using System.Application.Services.Implementation; using System.Net.Http; diff --git a/src/ST.Client.Mobile.Droid/Services/Implementation/ShowWindowServiceImpl.cs b/src/ST.Client.Mobile.Droid/Services/Implementation/ShowWindowServiceImpl.cs new file mode 100644 index 000000000..cabec51a4 --- /dev/null +++ b/src/ST.Client.Mobile.Droid/Services/Implementation/ShowWindowServiceImpl.cs @@ -0,0 +1,136 @@ +using Android.Content; +using Android.Views; +using Binding; +using Google.Android.Material.Dialog; +using System.Application.UI.Resx; +using System.Application.UI.ViewModels; +using System.Threading.Tasks; +using System.Windows; +using AlertDialog = AndroidX.AppCompat.App.AlertDialog; +using XEPlatform = Xamarin.Essentials.Platform; + +namespace System.Application.Services.Implementation +{ + internal sealed class ShowWindowServiceImpl : IShowWindowService + { + static string PositiveButtonText => AppResources.Confirm; + static string NegativeButtonText => AppResources.Cancel; + + Task PlatformShowWindow(CustomWindow customWindow, PageViewModel? viewModel = null, string title = "") + { + TaskCompletionSource tcs = new(); + try + { + AlertDialog? dialog = null; + + void SetConfirmButton(MaterialAlertDialogBuilder b) + { + b.SetPositiveButton(PositiveButtonText, (_, e) => + { + tcs.TrySetResult(true); + }); + } + void SetCancelButton(MaterialAlertDialogBuilder b) + { + b.SetNegativeButton(NegativeButtonText, (_, e) => + { + tcs.TrySetResult(false); + }); + } + + Action? CreateMessageBoxDialogWindow(MaterialAlertDialogBuilder b) + { + SetConfirmButton(b); + SetCancelButton(b); + if (viewModel is MessageBoxWindowViewModel viewModel_mb) + { + b.SetMessage(viewModel_mb.Content); + } + return null; + } + Action? CreatePasswordDialogWindow(MaterialAlertDialogBuilder b) + { + // https://material.io/components/text-fields/android + // https://material.io/components/dialogs#specs + IDialogInterfaceOnClickListener? listener = null; + b.SetPositiveButton(PositiveButtonText, listener); + SetCancelButton(b); + var view = LayoutInflater.From(b.Context)!.Inflate(Resource.Layout.textbox_password, null, false)!; + var binding = new textbox_password(view); + binding.layoutPassword.Hint = AppResources.LocalAuth_PasswordRequired1; + b.SetView(view); + return d => + { + d.GetButton((int)DialogButtonType.Positive).Click += (_, _) => + { + if (viewModel is PasswordWindowViewModel viewModel_p) + { + viewModel_p.Password = binding.tbPassword.Text; + if (viewModel_p.InputValidator()) + { + d.Dismiss(); + tcs.TrySetResult(true); + } + } + }; + }; + } + + Func?> @delegate = customWindow switch + { + CustomWindow.MessageBox => CreateMessageBoxDialogWindow, + CustomWindow.Password => CreatePasswordDialogWindow, + _ => throw new NotImplementedException(), + }; + if (!string.IsNullOrEmpty(title) && viewModel != null) + { + viewModel.Title = title; + } + var builder = new MaterialAlertDialogBuilder(XEPlatform.CurrentActivity); + if (!string.IsNullOrWhiteSpace(viewModel?.Title)) + { + builder.SetTitle(viewModel!.Title); + } + var dialog_delegate = @delegate(builder); + dialog = builder.Create(); + dialog.CancelEvent += (_, _) => + { + tcs.TrySetResult(false); + }; + if (dialog_delegate != null) + { + dialog.ShowEvent += (_, _) => + { + dialog_delegate?.Invoke(dialog); + }; + } + dialog.Show(); + } + catch (Exception e) + { + tcs.TrySetException(e); + } + return tcs.Task; + } + + public async Task Show(CustomWindow customWindow, TWindowViewModel? viewModel = null, string title = "", ResizeModeCompat resizeMode = default, bool isDialog = false, bool isParent = true) where TWindowViewModel : PageViewModel, new() + { + await PlatformShowWindow(customWindow, viewModel, title); + } + + public async Task Show(Type typeWindowViewModel, CustomWindow customWindow, PageViewModel? viewModel = null, string title = "", ResizeModeCompat resizeMode = default, bool isDialog = false, bool isParent = true) + { + await PlatformShowWindow(customWindow, viewModel, title); + } + + public async Task ShowDialog(CustomWindow customWindow, TWindowViewModel? viewModel = null, string title = "", ResizeModeCompat resizeMode = default, bool isDialog = true) where TWindowViewModel : PageViewModel, new() + { + return await PlatformShowWindow(customWindow, viewModel, title); + } + + public async Task ShowDialog(Type typeWindowViewModel, CustomWindow customWindow, PageViewModel? viewModel = null, string title = "", ResizeModeCompat resizeMode = default, bool isDialog = true) + { + await PlatformShowWindow(customWindow, viewModel, title); + } + } +} \ No newline at end of file diff --git a/src/ST.Client.Mobile.Droid/UI/Activities/AboutActivity.cs b/src/ST.Client.Mobile.Droid/UI/Activities/AboutActivity.cs index 57134495b..dda278ae9 100644 --- a/src/ST.Client.Mobile.Droid/UI/Activities/AboutActivity.cs +++ b/src/ST.Client.Mobile.Droid/UI/Activities/AboutActivity.cs @@ -86,7 +86,11 @@ namespace System.Application.UI.Activities R.Language)); break; case PreferenceButton.开放源代码许可: - throw new NotImplementedException(); + TextBlockActivity.StartActivity(this, new TextBlockViewModel + { + Title = AppResources.About_OpenSource, + ContentSource = TextBlockViewModel.ContentSourceEnum.OpenSourceLibrary, + }); break; case PreferenceButton.源码仓库: new MaterialAlertDialogBuilder(this).SetItems(SourceRepositories, (_, e) => BrowserOpenByDialogClick(e, value => value switch diff --git a/src/ST.Client.Mobile.Droid/UI/Activities/TextBlockActivity.cs b/src/ST.Client.Mobile.Droid/UI/Activities/TextBlockActivity.cs new file mode 100644 index 000000000..eb15fbec2 --- /dev/null +++ b/src/ST.Client.Mobile.Droid/UI/Activities/TextBlockActivity.cs @@ -0,0 +1,47 @@ +using Android.App; +using Android.Content.PM; +using Android.OS; +using Android.Runtime; +using Binding; +using System.Application.Models; +using System.Application.UI.ViewModels; + +namespace System.Application.UI.Activities +{ + [Register(JavaPackageConstants.Activities + nameof(TextBlockActivity))] + [Activity(Theme = ManifestConstants.MainTheme_NoActionBar, + LaunchMode = LaunchMode.SingleTask, + ConfigurationChanges = ManifestConstants.ConfigurationChanges)] + internal sealed class TextBlockActivity : BaseActivity + { + protected override int? LayoutResource => Resource.Layout.activity_textblock; + + protected override void OnCreate(Bundle? savedInstanceState) + { + base.OnCreate(savedInstanceState); + + var vm = this.GetViewModel(); + if (vm == null) + { + Finish(); + return; + } + + this.SetSupportActionBarWithNavigationClick(binding!.toolbar); + SupportActionBar.SetDisplayHomeAsUpEnabled(true); + if (!string.IsNullOrWhiteSpace(vm.Title)) Title = vm.Title; + + if (!string.IsNullOrWhiteSpace(vm.Content)) binding!.tvContent.Text = vm.Content; + else if (vm.ContentSource != default) binding!.tvContent.Text = vm.ContentSource switch + { + TextBlockViewModel.ContentSourceEnum.OpenSourceLibrary => OpenSourceLibrary.StringValues, + _ => string.Empty, + }; + } + + public static void StartActivity(Activity activity, TextBlockViewModel viewModel) + { + GoToPlatformPages.StartActivity(activity, viewModel); + } + } +} \ No newline at end of file diff --git a/src/ST.Client.Mobile.Droid/UI/Fragments/CommunityFixFragment.cs b/src/ST.Client.Mobile.Droid/UI/Fragments/CommunityFixFragment.cs index 2d416fe9f..491f888d4 100644 --- a/src/ST.Client.Mobile.Droid/UI/Fragments/CommunityFixFragment.cs +++ b/src/ST.Client.Mobile.Droid/UI/Fragments/CommunityFixFragment.cs @@ -2,6 +2,8 @@ using Android.Runtime; using Android.Views; using Binding; using System.Application.UI.Resx; +using System.Properties; +using System.Windows; namespace System.Application.UI.Fragments { @@ -10,11 +12,14 @@ namespace System.Application.UI.Fragments { protected override int? LayoutResource => Resource.Layout.fragment_community_fix; - public override void OnCreateView(View view) + public override async void OnCreateView(View view) { base.OnCreateView(view); binding!.textView.Text = GetType().Name.TrimEnd("Fragment") + Environment.NewLine + AppResources.UnderConstruction; binding!.textView.Gravity = GravityFlags.Center; + + var r = await MessageBoxCompat.ShowAsync(AppResources.DelAccountTips, ThisAssembly.AssemblyTrademark, MessageBoxButtonCompat.OKCancel); + Toast.Show(r.ToString()); } } } \ No newline at end of file diff --git a/src/ST.Client.Mobile.Droid/UI/Fragments/GameListFragment.cs b/src/ST.Client.Mobile.Droid/UI/Fragments/GameListFragment.cs index e2a05c595..df17f252f 100644 --- a/src/ST.Client.Mobile.Droid/UI/Fragments/GameListFragment.cs +++ b/src/ST.Client.Mobile.Droid/UI/Fragments/GameListFragment.cs @@ -2,6 +2,7 @@ using Android.Runtime; using Android.Views; using Binding; using System.Application.UI.Resx; +using System.Application.UI.ViewModels; namespace System.Application.UI.Fragments { @@ -10,11 +11,14 @@ namespace System.Application.UI.Fragments { protected override int? LayoutResource => Resource.Layout.fragment_game_list; - public override void OnCreateView(View view) + public override async void OnCreateView(View view) { base.OnCreateView(view); binding!.textView.Text = GetType().Name.TrimEnd("Fragment") + Environment.NewLine + AppResources.UnderConstruction; binding!.textView.Gravity = GravityFlags.Center; + + var text = await PasswordWindowViewModel.ShowPasswordDialog(); + Toast.Show(string.IsNullOrWhiteSpace(text) ? "IsNullOrWhiteSpace" : text!); } } } diff --git a/src/ST.Client.Mobile.Droid/UI/ViewModels/TextBlockViewModel.cs b/src/ST.Client.Mobile.Droid/UI/ViewModels/TextBlockViewModel.cs new file mode 100644 index 000000000..1d321e583 --- /dev/null +++ b/src/ST.Client.Mobile.Droid/UI/ViewModels/TextBlockViewModel.cs @@ -0,0 +1,24 @@ +using MPKey = MessagePack.KeyAttribute; +using MPObj = MessagePack.MessagePackObjectAttribute; + +namespace System.Application.UI.ViewModels +{ + [MPObj] + public class TextBlockViewModel + { + [MPKey(0)] + public string? Title { get; set; } + + [MPKey(1)] + public string? Content { get; set; } + + [MPKey(2)] + public ContentSourceEnum ContentSource { get; set; } + + public enum ContentSourceEnum + { + None, + OpenSourceLibrary, + } + } +} \ No newline at end of file diff --git a/src/ST.Client.Mobile/ST.Client.Mobile.csproj b/src/ST.Client.Mobile/ST.Client.Mobile.csproj index 74e511d9e..1554e8c9d 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,22 +63,41 @@ Services\Implementation - + UI\ViewModels\AboutPageViewModel.shared.cs Models\Enum + + MessageBox + + + Services + + + Services + + + + UI\ViewModels + + + UI\ViewModels\Base + + + UI\ViewModels + - + - - + + \ No newline at end of file diff --git a/src/Startup2.cs b/src/Startup2.cs index 3c508b3c4..f9a98a62f 100644 --- a/src/Startup2.cs +++ b/src/Startup2.cs @@ -175,7 +175,7 @@ namespace System.Application // 添加主线程助手(MainThreadDesktop) services.AddMainThreadPlatformService(); - +#endif #region MessageBox /* System.Windows.MessageBox 在 WPF 库中,仅支持 Win 平台 @@ -203,7 +203,6 @@ namespace System.Application #endif #endregion -#endif #if StartupTrace StartupTrace.Restart("DI.ConfigureDemandServices.GUI"); #endif