From 27f2dbbb5a6b6cd75e442965e6b3c96974b7796c Mon Sep 17 00:00:00 2001 From: Satoshi Nakamura Date: Mon, 29 Jul 2019 14:47:48 +0900 Subject: [PATCH 1/3] Fix Loading on Android --- .../AiForms.Dialogs.Android.csproj | 2 +- AiForms.Dialogs.Android/DefaultLoading.cs | 10 ++++++---- AiForms.Dialogs.Android/LoadingBase.cs | 2 ++ AiForms.Dialogs.Android/LoadingDialogPayload.cs | 8 ++++++-- AiForms.Dialogs.Android/LoadingPlatformDialog.cs | 11 ++++++++++- AiForms.Dialogs.Android/ReusableLoading.cs | 7 ++++--- Sample/Sample/ViewModels/MainPageViewModel.cs | 14 +++++++------- 7 files changed, 36 insertions(+), 18 deletions(-) diff --git a/AiForms.Dialogs.Android/AiForms.Dialogs.Android.csproj b/AiForms.Dialogs.Android/AiForms.Dialogs.Android.csproj index b6f96e4..a9caea1 100644 --- a/AiForms.Dialogs.Android/AiForms.Dialogs.Android.csproj +++ b/AiForms.Dialogs.Android/AiForms.Dialogs.Android.csproj @@ -161,7 +161,7 @@ - {7FAEA2AA-1832-4CAF-B0BA-4501F377269D} + {0BDF7090-FE73-49E6-B554-B2DA240768BB} AiForms.Dialogs.Abstractions diff --git a/AiForms.Dialogs.Android/DefaultLoading.cs b/AiForms.Dialogs.Android/DefaultLoading.cs index 5c0cf7c..a1087c6 100644 --- a/AiForms.Dialogs.Android/DefaultLoading.cs +++ b/AiForms.Dialogs.Android/DefaultLoading.cs @@ -41,9 +41,10 @@ public async Task StartAsync(Func, Task> action, string messag public void Show(string message = null, bool isCurrentScope = false) { + IsDialogShownTcs = new TaskCompletionSource(); OnceInitializeAction?.Invoke(); - var payload = new LoadingDialogPayload(ContentView); + var payload = new LoadingDialogPayload(ContentView,IsDialogShownTcs); var bundle = new Bundle(); bundle.PutSerializable(LoadingDialogPayload.PayloadKey, payload); @@ -56,7 +57,8 @@ public void Show(string message = null, bool isCurrentScope = false) } public void Hide() - { + { + if (Progress != null) { Progress.ProgressChanged -= ProgressAction; @@ -70,9 +72,9 @@ public void Hide() Task.Run(async () => { - // Wait a bit for ensuring that the dialog is created. + // Wait for ensuring that the dialog is created. // Because it sometimes crashes or freezes when executing a very short process. - await Task.Delay(50); + await IsDialogShownTcs.Task; var dialog = FragmentManager.FindFragmentByTag(LoadingImplementation.LoadingDialogTag); dialog?.Dismiss(); ContentView.RemoveFromParent(); diff --git a/AiForms.Dialogs.Android/LoadingBase.cs b/AiForms.Dialogs.Android/LoadingBase.cs index ca83fb4..2d94553 100644 --- a/AiForms.Dialogs.Android/LoadingBase.cs +++ b/AiForms.Dialogs.Android/LoadingBase.cs @@ -16,6 +16,8 @@ public class LoadingBase:IDisposable protected ViewGroup ContentView; + protected TaskCompletionSource IsDialogShownTcs; + public LoadingBase(LoadingPlatformDialog loadingDialog) { PlatformDialog = loadingDialog; diff --git a/AiForms.Dialogs.Android/LoadingDialogPayload.cs b/AiForms.Dialogs.Android/LoadingDialogPayload.cs index 49ca53b..436dd80 100644 --- a/AiForms.Dialogs.Android/LoadingDialogPayload.cs +++ b/AiForms.Dialogs.Android/LoadingDialogPayload.cs @@ -1,4 +1,5 @@ -using AiForms.Dialogs.Abstractions; +using System.Threading.Tasks; +using AiForms.Dialogs.Abstractions; using Android.Views; using Java.IO; @@ -10,11 +11,13 @@ public class LoadingDialogPayload : Java.Lang.Object, ISerializable public static readonly string PayloadKey = "loadingDialogPayload"; public LoadingView LoadingView { get; set; } public ViewGroup ContentView { get; set; } + public TaskCompletionSource IsShownTcs { get; set; } - public LoadingDialogPayload(ViewGroup contentView, LoadingView loadingView = null) + public LoadingDialogPayload(ViewGroup contentView, TaskCompletionSource tcs, LoadingView loadingView = null) { LoadingView = loadingView; ContentView = contentView; + IsShownTcs = tcs; } protected override void Dispose(bool disposing) @@ -23,6 +26,7 @@ protected override void Dispose(bool disposing) { LoadingView = null; ContentView = null; + IsShownTcs = null; } base.Dispose(disposing); } diff --git a/AiForms.Dialogs.Android/LoadingPlatformDialog.cs b/AiForms.Dialogs.Android/LoadingPlatformDialog.cs index ed5a9ed..ac36237 100644 --- a/AiForms.Dialogs.Android/LoadingPlatformDialog.cs +++ b/AiForms.Dialogs.Android/LoadingPlatformDialog.cs @@ -25,6 +25,7 @@ public override Android.App.Dialog OnCreateDialog(Bundle savedInstanceState) _loadingView = payload.LoadingView; _contentView = payload.ContentView; + var isShowTcs = payload.IsShownTcs; payload.Dispose(); @@ -36,7 +37,15 @@ public override Android.App.Dialog OnCreateDialog(Bundle savedInstanceState) DestroyTcs = new TaskCompletionSource(); - return dialog; + try + { + + return dialog; + } + finally + { + isShowTcs.SetResult(true); + } } public override void OnStart() diff --git a/AiForms.Dialogs.Android/ReusableLoading.cs b/AiForms.Dialogs.Android/ReusableLoading.cs index b6a9f19..342b4b2 100644 --- a/AiForms.Dialogs.Android/ReusableLoading.cs +++ b/AiForms.Dialogs.Android/ReusableLoading.cs @@ -66,9 +66,10 @@ public async Task StartAsync(Func, Task> action, bool isCurren void ShowInner() { + IsDialogShownTcs = new TaskCompletionSource(); OnceInitializeAction?.Invoke(); - var payload = new LoadingDialogPayload(ContentView, _loadingView); + var payload = new LoadingDialogPayload(ContentView,IsDialogShownTcs, _loadingView); var bundle = new Bundle(); bundle.PutSerializable(LoadingDialogPayload.PayloadKey, payload); @@ -95,9 +96,9 @@ public void Hide() Task.Run(async () => { - // Wait a bit for ensuring that the dialog is created. + // Wait for ensuring that the dialog is created. // Because it sometimes crashes or freezes when executing a very short process. - await Task.Delay(50); + await IsDialogShownTcs.Task; var dialog = FragmentManager.FindFragmentByTag(LoadingImplementation.LoadingDialogTag); dialog?.Dismiss(); ContentView.RemoveFromParent(); diff --git a/Sample/Sample/ViewModels/MainPageViewModel.cs b/Sample/Sample/ViewModels/MainPageViewModel.cs index 55ec679..b46a7a4 100644 --- a/Sample/Sample/ViewModels/MainPageViewModel.cs +++ b/Sample/Sample/ViewModels/MainPageViewModel.cs @@ -83,13 +83,13 @@ public MainPageViewModel(MyIndicatorView myIndicatorView) }); await customLoading.StartAsync(async p => { - //await Task.Delay(1); - p.Report(0d); - for (var i = 0; i < 100; i++) - { - await Task.Delay(50); - p.Report((i + 1) * 0.01d); - } + await Task.Delay(1); + //p.Report(0d); + //for (var i = 0; i < 100; i++) + //{ + // await Task.Delay(50); + // p.Report((i + 1) * 0.01d); + //} }); }); From df0fb37d8154cbf248b9d91848b4664557262806 Mon Sep 17 00:00:00 2001 From: Satoshi Nakamura Date: Thu, 15 Aug 2019 21:28:42 +0900 Subject: [PATCH 2/3] Fix Sample --- Sample/Sample.iOS/Info.plist | 6 +-- Sample/Sample/ViewModels/MainPageViewModel.cs | 46 +++++++++---------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/Sample/Sample.iOS/Info.plist b/Sample/Sample.iOS/Info.plist index d2c8b2a..0213a9e 100644 --- a/Sample/Sample.iOS/Info.plist +++ b/Sample/Sample.iOS/Info.plist @@ -3,7 +3,7 @@ CFBundleDisplayName - Sample + Dialogs CFBundleShortVersionString 1.0 CFBundleVersion @@ -39,8 +39,8 @@ XSAppIconAssets Resources/Images.xcassets/AppIcons.appiconset CFBundleName - Sample + Dialogs CFBundleIdentifier - jp.kamusoft.sample + jp.kamusoft.dialogs diff --git a/Sample/Sample/ViewModels/MainPageViewModel.cs b/Sample/Sample/ViewModels/MainPageViewModel.cs index b46a7a4..237a586 100644 --- a/Sample/Sample/ViewModels/MainPageViewModel.cs +++ b/Sample/Sample/ViewModels/MainPageViewModel.cs @@ -49,23 +49,23 @@ public MainPageViewModel(MyIndicatorView myIndicatorView) var loadingFlg = false; LoadingCommand.Subscribe(async _ => { - Loading.Instance.Show(); - await Task.Delay(1); - Loading.Instance.Hide(); - - //await Loading.Instance.StartAsync(async progress => { - // //await Task.Delay(1); - // progress.Report(0d); - // for (var i = 0; i < 100; i++) - // { - // if (i == 50) - // { - // Loading.Instance.SetMessage("Soon..."); - // } - // await Task.Delay(50); - // progress.Report((i + 1) * 0.01d); - // } - //},null,loadingFlg).ConfigureAwait(false); + //Loading.Instance.Show(); + //await Task.Delay(1); + //Loading.Instance.Hide(); + + await Loading.Instance.StartAsync(async progress => { + //await Task.Delay(1); + progress.Report(0d); + for (var i = 0; i < 100; i++) + { + if (i == 50) + { + Loading.Instance.SetMessage("Soon..."); + } + await Task.Delay(25); + progress.Report((i + 1) * 0.01d); + } + },null,loadingFlg).ConfigureAwait(false); loadingFlg = !loadingFlg; }); @@ -84,12 +84,12 @@ public MainPageViewModel(MyIndicatorView myIndicatorView) await customLoading.StartAsync(async p => { await Task.Delay(1); - //p.Report(0d); - //for (var i = 0; i < 100; i++) - //{ - // await Task.Delay(50); - // p.Report((i + 1) * 0.01d); - //} + p.Report(0d); + for (var i = 0; i < 100; i++) + { + await Task.Delay(25); + p.Report((i + 1) * 0.01d); + } }); }); From 6c0996af0970d9f807dcfe52ed5163518b6046a5 Mon Sep 17 00:00:00 2001 From: Satoshi Nakamura Date: Thu, 4 Jun 2020 11:43:03 +0900 Subject: [PATCH 3/3] Nested dialogs #8 --- .gitignore | 1 + .../DialogImplementation.cs | 16 --------- .../ExtraPlatformDialog.cs | 5 +++ AiForms.Dialogs.Android/ReusableDialog.cs | 25 +++++++------- .../Sample/ViewModels/DialogTestViewModel.cs | 2 +- .../Sample/ViewModels/SurveyPageViewModel.cs | 26 +++++++++++++++ Sample/Sample/Views/Dialogs/TestDialog.xaml | 10 ++++++ .../Sample/Views/Dialogs/TestDialog.xaml.cs | 33 +++++++++++++++++++ Sample/Sample/Views/IndexPage.xaml | 1 + Sample/Sample/Views/SurveyPage.xaml | 7 ++++ Sample/Sample/Views/SurveyPage.xaml.cs | 15 +++++++++ nuget/AzurePipelines.nuspec | 4 ++- 12 files changed, 116 insertions(+), 29 deletions(-) create mode 100644 Sample/Sample/ViewModels/SurveyPageViewModel.cs create mode 100644 Sample/Sample/Views/Dialogs/TestDialog.xaml create mode 100644 Sample/Sample/Views/Dialogs/TestDialog.xaml.cs create mode 100644 Sample/Sample/Views/SurveyPage.xaml create mode 100644 Sample/Sample/Views/SurveyPage.xaml.cs diff --git a/.gitignore b/.gitignore index 10f16da..b0eb4b4 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ ## files generated by popular Visual Studio add-ons. .vs/ +mono_crash.* # User-specific files *.suo diff --git a/AiForms.Dialogs.Android/DialogImplementation.cs b/AiForms.Dialogs.Android/DialogImplementation.cs index 1e2e71a..ef4a187 100644 --- a/AiForms.Dialogs.Android/DialogImplementation.cs +++ b/AiForms.Dialogs.Android/DialogImplementation.cs @@ -7,13 +7,8 @@ namespace AiForms.Dialogs [Android.Runtime.Preserve(AllMembers = true)] public class DialogImplementation : IDialog { - public static readonly string ExtraDialogTag = "ExtraDialog"; - internal ExtraPlatformDialog ExtraDialog; - FragmentManager FragmentManager => Dialogs.FragmentManager; - public DialogImplementation() { - ExtraDialog = new ExtraPlatformDialog(); } public IReusableDialog Create(object viewModel = null) where TView : DialogView @@ -30,8 +25,6 @@ public IReusableDialog Create(DialogView view, object viewModel = null) public async Task ShowAsync(object viewModel = null) where TView : DialogView { - if (IsRunning()) return false; - using (var dlg = Create(viewModel)) { return await dlg.ShowAsync(); @@ -40,19 +33,10 @@ public async Task ShowAsync(object viewModel = null) where TView : public async Task ShowAsync(DialogView view, object viewModel = null) { - if (IsRunning()) return false; - using (var dlg = Create(view, viewModel)) { return await dlg.ShowAsync(); } } - - bool IsRunning() - { - var dialog = Dialogs.FragmentManager.FindFragmentByTag(DialogImplementation.ExtraDialogTag); - return dialog != null; - } - } } diff --git a/AiForms.Dialogs.Android/ExtraPlatformDialog.cs b/AiForms.Dialogs.Android/ExtraPlatformDialog.cs index 0d3278f..29ffc5e 100644 --- a/AiForms.Dialogs.Android/ExtraPlatformDialog.cs +++ b/AiForms.Dialogs.Android/ExtraPlatformDialog.cs @@ -17,6 +17,11 @@ public class ExtraPlatformDialog : Android.App.DialogFragment DialogView _dialogView; ViewGroup _contentView; + public ExtraPlatformDialog() { } + + // System Required! + public ExtraPlatformDialog(IntPtr handle, JniHandleOwnership transfer) :base(handle,transfer) { } + public override Android.App.Dialog OnCreateDialog(Bundle savedInstanceState) { base.OnCreateDialog(savedInstanceState); diff --git a/AiForms.Dialogs.Android/ReusableDialog.cs b/AiForms.Dialogs.Android/ReusableDialog.cs index 5eb38a6..069a243 100644 --- a/AiForms.Dialogs.Android/ReusableDialog.cs +++ b/AiForms.Dialogs.Android/ReusableDialog.cs @@ -1,4 +1,5 @@ using System; +using System.Threading; using System.Threading.Tasks; using AiForms.Dialogs.Abstractions; using Android.App; @@ -16,18 +17,18 @@ namespace AiForms.Dialogs [Android.Runtime.Preserve(AllMembers = true)] public class ReusableDialog:Java.Lang.Object, IReusableDialog, View.IOnKeyListener { - DialogImplementation _extraDialog; - ExtraPlatformDialog _platformDialog => _extraDialog.ExtraDialog; + ExtraPlatformDialog _platformDialog; FragmentManager FragmentManager => Dialogs.FragmentManager; DialogView _dlgView; IVisualElementRenderer _renderer; ViewGroup _contentView; Action OnceInitializeAction; + Guid _guid; public ReusableDialog(DialogView view) { - _dlgView = view; - _extraDialog = Dialog.Instance as DialogImplementation; + _dlgView = view; + _guid = Guid.NewGuid(); // Because the process can't be executed until application completely loads, // set the action here to execute later on. @@ -125,7 +126,7 @@ void Initialize() public async Task ShowAsync() { - var dialog = FragmentManager.FindFragmentByTag(DialogImplementation.ExtraDialogTag); + var dialog = FragmentManager.FindFragmentByTag(_guid.ToString()); if (dialog != null) { return false; @@ -148,7 +149,7 @@ async void complete(object sender, EventArgs e) _dlgView.RunDismissalAnimation(); await Dismiss(); tcs.SetResult(true); - }; + } _dlgView.DialogNotifierInternal.Canceled += cancel; _dlgView.DialogNotifierInternal.Completed += complete; @@ -157,8 +158,9 @@ async void complete(object sender, EventArgs e) var payload = new ExtraDialogPayload(_dlgView,_contentView); var bundle = new Bundle(); bundle.PutSerializable("extraDialogPayload", payload); + _platformDialog = new ExtraPlatformDialog(); _platformDialog.Arguments = bundle; - _platformDialog.Show(FragmentManager, DialogImplementation.ExtraDialogTag); + _platformDialog.Show(FragmentManager, _guid.ToString()); try { @@ -171,6 +173,7 @@ async void complete(object sender, EventArgs e) _dlgView.TearDown(); payload.Dispose(); bundle.Dispose(); + } } @@ -190,7 +193,7 @@ protected override void Dispose(bool disposing) if (!_renderer.View.IsDisposed()) { _renderer.View.Dispose(); - } + } _contentView.Dispose(); _contentView = null; @@ -198,8 +201,6 @@ protected override void Dispose(bool disposing) _renderer.Dispose(); _renderer = null; - _extraDialog = null; - OnceInitializeAction = null; } base.Dispose(disposing); @@ -256,9 +257,11 @@ void handler(object sender, Animation.AnimationEndEventArgs e) await tcs.Task; anim.AnimationEnd -= handler; - var dialog = FragmentManager.FindFragmentByTag(DialogImplementation.ExtraDialogTag); + var dialog = FragmentManager.FindFragmentByTag(_guid.ToString()); dialog.Dismiss(); _contentView.RemoveFromParent(); + _platformDialog.Dispose(); + _platformDialog = null; await Task.Delay(250); // wait for a bit time until the dialog is completely released. } diff --git a/Sample/Sample/ViewModels/DialogTestViewModel.cs b/Sample/Sample/ViewModels/DialogTestViewModel.cs index 1759a2d..0ba259a 100644 --- a/Sample/Sample/ViewModels/DialogTestViewModel.cs +++ b/Sample/Sample/ViewModels/DialogTestViewModel.cs @@ -76,7 +76,7 @@ string GetHAlignString() string GetVAlignString() { - switch (HorizontalLayoutAlignment) + switch (VerticalLayoutAlignment) { case LayoutAlignment.Start: return "Top"; diff --git a/Sample/Sample/ViewModels/SurveyPageViewModel.cs b/Sample/Sample/ViewModels/SurveyPageViewModel.cs new file mode 100644 index 0000000..bef1f56 --- /dev/null +++ b/Sample/Sample/ViewModels/SurveyPageViewModel.cs @@ -0,0 +1,26 @@ +using System; +using AiForms.Dialogs.Abstractions; +using Prism.Mvvm; +using Reactive.Bindings; +using Sample.Views; +using Sample.Views.Dialogs; + +namespace Sample.ViewModels +{ + public class SurveyPageViewModel:BindableBase + { + public ReactiveCommand ShowDialogCommand { get; } = new ReactiveCommand(); + public SurveyPageViewModel() + { + var dialog = AiForms.Dialogs.Dialog.Instance; + ShowDialogCommand.Subscribe(async _ => + { + var ret = await dialog.ShowAsync(); + if (ret) + { + //await dialog.ShowAsync(); + } + }); + } + } +} diff --git a/Sample/Sample/Views/Dialogs/TestDialog.xaml b/Sample/Sample/Views/Dialogs/TestDialog.xaml new file mode 100644 index 0000000..b79fe1d --- /dev/null +++ b/Sample/Sample/Views/Dialogs/TestDialog.xaml @@ -0,0 +1,10 @@ + + + +