ShowWindowServiceImpl for Android

This commit is contained in:
Aigio Liu
2021-06-22 21:22:04 +08:00
parent 63cb5c11d7
commit 9e2e8d7d59
28 changed files with 477 additions and 63 deletions
@@ -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
{
/// <summary>
/// 添加显示窗口服务
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
public static IServiceCollection AddShowWindowService(this IServiceCollection services)
{
services.AddSingleton<IShowWindowService, ShowWindowServiceImpl>();
return services;
}
}
}
@@ -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
{
/// <summary>
/// 添加主线程助手类(MainThreadDesktop)服务
@@ -20,17 +19,6 @@ namespace Microsoft.Extensions.DependencyInjection
return services;
}
/// <summary>
/// 添加显示窗口服务
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
public static IServiceCollection AddShowWindowService(this IServiceCollection services)
{
services.AddSingleton<IShowWindowService, ShowWindowServiceImpl>();
return services;
}
/// <summary>
/// 添加应用程序更新服务
/// </summary>
@@ -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;
@@ -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)
{
}
@@ -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();
}
@@ -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;
+6
View File
@@ -5,13 +5,18 @@ namespace System.Application
/// </summary>
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
}
}
@@ -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
/// <summary>
/// 显示消息框。
/// </summary>
public static class MessageBoxCompat
public static partial class MessageBoxCompat
{
const string default_caption = ThisAssembly.AssemblyTrademark;
const MessageBoxButtonCompat default_button = MessageBoxButtonCompat.OK;
static readonly Lazy<IMessageBoxCompatService?> mbcs =
new(DI.Get_Nullable<IMessageBoxCompatService>);
/// <inheritdoc cref="IMessageBoxCompatService.ShowAsync(string, string, MessageBoxButtonCompat, MessageBoxImageCompat?)"/>
public static async Task<MessageBoxResultCompat> ShowAsync(
string messageBoxText, string caption, MessageBoxButtonCompat button, MessageBoxImageCompat? icon = null)
{
var f = DI.Get_Nullable<IMessageBoxCompatService>();
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
@@ -1,5 +1,3 @@
using System.Application.Services;
// ReSharper disable once CheckNamespace
namespace System.Windows
{
@@ -11,22 +9,22 @@ namespace System.Windows
/// <summary>
/// 用户无法调整窗口的大小。 不显示 "最大化" 和 "最小化" 框。
/// </summary>
NoResize = IDesktopPlatformService.ResizeMode_NoResize,
NoResize,
/// <summary>
/// 用户只能最小化窗口并从任务栏还原。 同时显示 "最小化" 和 "最大化" 框,但只启用 "最小化" 框。
/// </summary>
CanMinimize = IDesktopPlatformService.ResizeMode_CanMinimize,
CanMinimize,
/// <summary>
/// 用户可以通过使用 "最小化" 和 "最大化" 框以及围绕窗口的可拖动轮廓来完全调整窗口的大小。 显示和启用 "最小化" 和 "最大化" 框。 (默认) 。
/// </summary>
CanResize = IDesktopPlatformService.ResizeMode_CanResize,
CanResize,
/// <summary>
/// 此选项具有与相同的功能 <see cref="CanResize"/> ,但会将 "调整手柄" 添加到窗口的右下角。
/// </summary>
[Obsolete("not implemented")]
CanResizeWithGrip = IDesktopPlatformService.ResizeMode_CanResizeWithGrip,
CanResizeWithGrip,
}
}
@@ -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<IDesktopPlatformService>();
void SetResizeMode(IntPtr hWnd, ResizeMode value);
void SetResizeMode(IntPtr hWnd, ResizeModeCompat value);
/// <summary>
/// 获取一个正在运行的进程的命令行参数。
@@ -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)
@@ -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
}
}
@@ -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
{
@@ -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__
@@ -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<string?> ShowPasswordDialog()
{
var vm = new PasswordWindowViewModel();
@@ -31,12 +30,25 @@ namespace System.Application.UI.ViewModels
return vm.Password;
}
public void Ok()
/// <summary>
/// 输入内容验证
/// </summary>
/// <returns></returns>
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
}
}
@@ -1,4 +1,4 @@
using ReactiveUI;
using ReactiveUI;
namespace System.Application.UI.ViewModels
{
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:xamarin="http://schemas.xamarin.com/android/xamarin/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/shared_toolbar" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tvContent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="12dp"
android:textColor="@color/text_primary"
android:textIsSelectable="true"
tools:text="Ahead-of-time compiler.\n\nSimilar to JIT, this compiler also translates IL to machine code. In contrast to JIT compilation, AOT compilation happens before the application is executed and is usually performed on a different machine. Because AOT tool chains don't compile at run time, they don't have to minimize time spent compiling. That means they can spend more time optimizing. Since the context of AOT is the entire application, the AOT compiler also performs cross-module linking and whole-program analysis, which means that all references are followed and a single executable is produced.\n\nSee CoreRT and .NET Native.\n\nASP.NET\n\nThe original ASP.NET implementation that ships with the .NET Framework, also known as ASP.NET 4.x.\n\nSometimes ASP.NET is an umbrella term that refers to both the original ASP.NET and ASP.NET Core. The meaning that the term carries in any given instance is determined by context. Refer to ASP.NET 4.x when you want to make it clear that you're not using ASP.NET to mean both implementations.\n\nSee ASP.NET documentation.\n\nASP.NET Core\n\nA cross-platform, high-performance, open-source implementation of ASP.NET.\n\nSee ASP.NET Core documentation.CLR\n\nCommon Language Runtime.\n\nThe exact meaning depends on the context. Common Language Runtime usually refers to the runtime of .NET Framework or the runtime of .NET 5 (and .NET Core) and later versions.\n\nA CLR handles memory allocation and management. A CLR is also a virtual machine that not only executes apps but also generates and compiles code on-the-fly using a JIT compiler.\n\nThe CLR implementation for .NET Framework is Windows only.\n\n
The CLR implementation for .NET 5 and later versions (also known as the Core CLR) is built from the same code base as the .NET Framework CLR. Originally, the Core CLR was the runtime of Silverlight and was designed to run on multiple platforms, specifically Windows and OS X. It's still a cross-platform runtime, now including support for many Linux distributions.\n\nSee also runtime.\n\nCore CLR\n\nThe Common Language Runtime for .NET 5 (and .NET Core) and later versions.\n\nSee CLR.\n\nCoreRT\n\n
In contrast to the CLR, CoreRT is not a virtual machine, which means it doesn't include the facilities to generate and run code on-the-fly because it doesn't include a JIT. It does, however, include the GC and the ability for run-time type identification (RTTI) and reflection. However, its type system is designed so that metadata for reflection isn't required. Not requiring metadata enables having an AOT tool chain that can link away superfluous metadata and (more importantly) identify code that the app doesn't use. CoreRT is in development.\n\nSee Intro to CoreRT and .NET Runtime Lab."
xamarin:managedType="AndroidX.AppCompat.Widget.AppCompatTextView" />
</ScrollView>
</LinearLayout>
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:xamarin="http://schemas.xamarin.com/android/xamarin/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="24dp"
android:paddingTop="8dp"
android:paddingEnd="24dp"
android:paddingBottom="8dp">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/layoutPassword"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:endIconMode="password_toggle"
tools:hint="Placeholder"
xamarin:managedType="Google.Android.Material.TextField.TextInputLayout">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/tbPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword"
tools:text="123"
xamarin:managedType="Google.Android.Material.TextField.TextInputEditText" />
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
@@ -45,5 +45,86 @@ namespace System.Application
public static void StartActivity<TActivity>(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<TViewModel>(this Activity activity)
{
var intent = activity.Intent;
if (intent != null)
{
var byteArray = intent.GetByteArrayExtra(KEY_ViewModel);
if (byteArray != null)
{
try
{
var value = Serializable.DMP<TViewModel>(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<TActivity>(Activity activity, object viewModel, Type? viewModelType = null)
{
StartActivity(activity, typeof(TActivity), viewModel, viewModelType);
}
public static void StartActivity<TActivity>(Fragment fragment, object viewModel, Type? viewModelType = null)
{
var activity = fragment.Activity;
if (activity == null) return;
StartActivity<TActivity>(activity, viewModel, viewModelType);
}
public static void StartActivity<TViewModel>(Activity activity, Type activityType, TViewModel viewModel)
{
var viewModel_ = Serializable.SMP(viewModel);
StartActivity(activity, activityType, viewModel_);
}
public static void StartActivity<TViewModel>(Fragment fragment, Type activityType, TViewModel viewModel)
{
var activity = fragment.Activity;
if (activity == null) return;
StartActivity(activity, activityType, viewModel);
}
public static void StartActivity<TActivity, TViewModel>(Activity activity, TViewModel viewModel)
{
StartActivity(activity, typeof(TActivity), viewModel);
}
public static void StartActivity<TActivity, TViewModel>(Fragment fragment, TViewModel viewModel)
{
var activity = fragment.Activity;
if (activity == null) return;
StartActivity<TActivity, TViewModel>(activity, viewModel);
}
}
}
@@ -83,6 +83,7 @@
<EmbeddedResource Remove="UI\Views.Controls\**" />
<None Remove="UI\Views.Controls\**" />
<Compile Include="..\Common.ClientLib.Droid\Application\DarkModeUtil.cs" />
<Compile Include="..\ST.Client.Desktop.Avalonia\ServiceCollectionExtensions.AddShowWindowService.cs" />
</ItemGroup>
<ItemGroup Condition="'$(Configuration)'=='Debug'">
@@ -347,6 +348,9 @@
<AndroidBoundLayout Include="..\ST.Client.Mobile.Droid.Design\ui\src\main\res\layout\activity_main.xml">
<Link>Resources\layout\activity_main.xml</Link>
</AndroidBoundLayout>
<AndroidBoundLayout Include="..\ST.Client.Mobile.Droid.Design\ui\src\main\res\layout\activity_textblock.xml">
<Link>Resources\layout\activity_textblock.xml</Link>
</AndroidBoundLayout>
<AndroidBoundLayout Include="..\ST.Client.Mobile.Droid.Design\ui\src\main\res\layout\fragment_community_fix.xml">
<Link>Resources\layout\fragment_community_fix.xml</Link>
</AndroidBoundLayout>
@@ -386,6 +390,9 @@
<AndroidBoundLayout Include="..\ST.Client.Mobile.Droid.Design\ui\src\main\res\layout\shared_toolbar.xml">
<Link>Resources\layout\shared_toolbar.xml</Link>
</AndroidBoundLayout>
<AndroidBoundLayout Include="..\ST.Client.Mobile.Droid.Design\ui\src\main\res\layout\textbox_password.xml">
<Link>Resources\layout\textbox_password.xml</Link>
</AndroidBoundLayout>
<AndroidResource Include="..\ST.Client.Mobile.Droid.Design\ui\src\main\res\menu\bottom_nav_menu.xml">
<Link>Resources\menu\bottom_nav_menu.xml</Link>
</AndroidResource>
@@ -482,3 +489,5 @@
@@ -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;
@@ -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<bool> PlatformShowWindow(CustomWindow customWindow, PageViewModel? viewModel = null, string title = "")
{
TaskCompletionSource<bool> 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<AlertDialog>? CreateMessageBoxDialogWindow(MaterialAlertDialogBuilder b)
{
SetConfirmButton(b);
SetCancelButton(b);
if (viewModel is MessageBoxWindowViewModel viewModel_mb)
{
b.SetMessage(viewModel_mb.Content);
}
return null;
}
Action<AlertDialog>? 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<MaterialAlertDialogBuilder, Action<AlertDialog>?> @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<TWindowViewModel>(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<bool> ShowDialog<TWindowViewModel>(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);
}
}
}
@@ -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
@@ -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<activity_textblock>
{
protected override int? LayoutResource => Resource.Layout.activity_textblock;
protected override void OnCreate(Bundle? savedInstanceState)
{
base.OnCreate(savedInstanceState);
var vm = this.GetViewModel<TextBlockViewModel>();
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<TextBlockActivity, TextBlockViewModel>(activity, viewModel);
}
}
}
@@ -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());
}
}
}
@@ -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!);
}
}
}
@@ -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,
}
}
}
+25 -6
View File
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
@@ -35,7 +35,7 @@
<Compile Include="..\ST.Client.Desktop\Mvvm\*.cs">
<LinkBase>Mvvm</LinkBase>
</Compile>
<Compile Remove="..\ST.Client.Desktop\Mvvm\CompositeDisposable.cs"/>
<Compile Remove="..\ST.Client.Desktop\Mvvm\CompositeDisposable.cs" />
<Compile Include="..\ST.Client.Desktop\UI\ViewModels\AreaUIHelper.cs">
<LinkBase>UI\ViewModels</LinkBase>
</Compile>
@@ -63,22 +63,41 @@
<Compile Include="..\ST.Client.Desktop\Services\Implementation\FontManagerImpl.cs">
<LinkBase>Services\Implementation</LinkBase>
</Compile>
<Compile Include="..\ST.Client.Desktop\ServiceCollectionExtensions.TryAddFontManager.cs"/>
<Compile Include="..\ST.Client.Desktop\ServiceCollectionExtensions.TryAddFontManager.cs" />
<Compile Include="..\ST.Client.Desktop\UI\ViewModels\Pages\About\AboutPageViewModel.shared.cs">
<Link>UI\ViewModels\AboutPageViewModel.shared.cs</Link>
</Compile>
<Compile Include="..\ST.Client.Desktop\Models\Enum\AppTheme.cs">
<LinkBase>Models\Enum</LinkBase>
</Compile>
<Compile Include="..\ST.Client.Desktop\MessageBox\*.cs">
<LinkBase>MessageBox</LinkBase>
</Compile>
<Compile Include="..\ST.Client.Desktop\Services\IMessageBoxCompatService.cs">
<LinkBase>Services</LinkBase>
</Compile>
<Compile Include="..\ST.Client.Desktop\Services\IShowWindowService.cs">
<LinkBase>Services</LinkBase>
</Compile>
<Compile Include="..\ST.Client.Desktop\CustomWindow.cs" />
<Compile Include="..\ST.Client.Desktop\UI\ViewModels\Windows\MessageBoxWindowViewModel.cs">
<LinkBase>UI\ViewModels</LinkBase>
</Compile>
<Compile Include="..\ST.Client.Desktop\UI\ViewModels\Base\DialogWindowViewModel.cs">
<LinkBase>UI\ViewModels\Base</LinkBase>
</Compile>
<Compile Include="..\ST.Client.Desktop\UI\ViewModels\Windows\LocalAuthPage\PasswordWindowViewModel.cs">
<LinkBase>UI\ViewModels</LinkBase>
</Compile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ST.Client\ST.Client.csproj"/>
<ProjectReference Include="..\ST.Client\ST.Client.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="ReactiveUI" Version="13.3.2"/>
<PackageReference Include="Microsoft.Identity.Client" Version="4.32.1"/>
<PackageReference Include="ReactiveUI" Version="13.3.2" />
<PackageReference Include="Microsoft.Identity.Client" Version="4.32.1" />
<!--<PackageReference Include="StatefulModel.Standard" Version="0.1.0" />-->
</ItemGroup>
</Project>
+1 -2
View File
@@ -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