From 3799488d94048c25aa6e65fdb082c563eade120f Mon Sep 17 00:00:00 2001 From: Enis Necipoglu Date: Thu, 25 Jan 2024 20:49:08 +0300 Subject: [PATCH] Enhance default dialog popups --- src/UraniumUI/Dialogs/DefaultDialogService.cs | 406 +++++++++++++----- 1 file changed, 309 insertions(+), 97 deletions(-) diff --git a/src/UraniumUI/Dialogs/DefaultDialogService.cs b/src/UraniumUI/Dialogs/DefaultDialogService.cs index c7bcce46..3bf1e621 100644 --- a/src/UraniumUI/Dialogs/DefaultDialogService.cs +++ b/src/UraniumUI/Dialogs/DefaultDialogService.cs @@ -1,15 +1,51 @@ using InputKit.Shared.Controls; +using Microsoft.Extensions.Options; +using Plainer.Maui.Controls; +using UraniumUI.Resources; +using CheckBox = InputKit.Shared.Controls.CheckBox; namespace UraniumUI.Dialogs; public class DefaultDialogService : IDialogService { - public Task ConfirmAsync(string title, string message, string okText = "OK", string cancelText = "Cancel") + public async Task ConfirmAsync(string title, string message, string okText = "OK", string cancelText = "Cancel") { - return Application.Current.MainPage.DisplayAlert(title, message, okText, cancelText); + var tcs = new TaskCompletionSource(); + var currentPage = GetCurrentPage(); + + var popupPage = new ContentPage + { + BackgroundColor = GetBackdropColor(), + Content = GetFrame(currentPage.Width, new VerticalStackLayout + { + Children = + { + GetHeader(title), + new Label + { + Text = message, + Margin = 20, + }, + GetDivider(), + GetFooter(okText, new Command(() => + { + tcs.SetResult(true); + currentPage.Navigation.PopModalAsync(animated: false); + }), cancelText, new Command(() => + { + tcs.SetResult(false); + currentPage.Navigation.PopModalAsync(animated: false); + })) + } + }) + }; + + await currentPage.Navigation.PushModalAsync(ConfigurePopupPage(popupPage), animated: false); + + return await tcs.Task; } - public Task> DisplayCheckBoxPromptAsync( + public virtual Task> DisplayCheckBoxPromptAsync( string message, IEnumerable selectionSource, IEnumerable selectedItems = null, @@ -19,57 +55,62 @@ public Task> DisplayCheckBoxPromptAsync( { var tcs = new TaskCompletionSource>(); - var selectionView = new SelectionView + var prop = displayMember != null ? typeof(T).GetProperty(displayMember) : null; + + var checkBoxGroup = new VerticalStackLayout { - ColumnNumber = 1, - RowSpacing = 10, - SelectionType = InputKit.Shared.SelectionType.CheckBox, - ItemsSource = selectionSource.ToList(), + Margin = 20, + Spacing = 10, + VerticalOptions = LayoutOptions.Center, + HorizontalOptions = LayoutOptions.Start, }; - Application.Current.MainPage.Navigation.PushModalAsync(new ContentPage + foreach (var item in selectionSource) { - Content = new ScrollView + checkBoxGroup.Add(new CheckBox { - Content = new VerticalStackLayout - { - Padding = 20, - Spacing = 20, - HorizontalOptions = LayoutOptions.Center, - Children = { - new Label{ Text = message }, - selectionView, - new HorizontalStackLayout - { - Children = - { - new Button - { - Text = accept, - StyleClass = new []{ "FilledButton", "Dialog.Accept" }, - Command = new Command(() => - { - tcs.SetResult(selectionView.SelectedItems.Cast()); - Application.Current.MainPage.Navigation.PopModalAsync(); - }) - }, - new Button - { - Text = cancel, - - StyleClass = new []{ "OutlinedButton", "Dialog.Cancel" }, - Command = new Command(() => - { - tcs.SetResult(null); - Application.Current.MainPage.Navigation.PopModalAsync(); - }) - } - } - } - } - } - } - }); + Text = prop != null ? prop.GetValue(item)?.ToString() : item.ToString(), + CommandParameter = item, + IsChecked = selectedItems?.Contains(item) ?? false, + }); + } + + var currentPage = GetCurrentPage(); + + var rootGrid = new Grid + { + RowDefinitions = new RowDefinitionCollection + { + new RowDefinition(GridLength.Auto), + new RowDefinition(GridLength.Star), + new RowDefinition(GridLength.Auto), + new RowDefinition(GridLength.Auto), + } + }; + + rootGrid.Add(GetHeader(message)); + rootGrid.Add(new ScrollView { Content = checkBoxGroup, VerticalOptions = LayoutOptions.Start, MaximumHeightRequest = currentPage.Height * 0.6, }, row: 1); + rootGrid.Add(GetDivider(), row: 2); + rootGrid.Add(GetFooter( + accept, new Command(() => + { + tcs.TrySetResult(checkBoxGroup.Children.Where(x => x is CheckBox checkbox && checkbox.IsChecked).Select(s => (T)(s as CheckBox).CommandParameter)); + currentPage.Navigation.PopModalAsync(animated: false); + }), + cancel, new Command(() => + { + tcs.TrySetResult(null); + currentPage.Navigation.PopModalAsync(animated: false); + }) + ), row: 3); + + var popupPage = new ContentPage + { + BackgroundColor = GetBackdropColor(), + Content = GetFrame(currentPage.Width, rootGrid) + }; + + currentPage.Navigation.PushModalAsync(ConfigurePopupPage(popupPage), animated: false); return tcs.Task; } @@ -83,59 +124,60 @@ public Task DisplayRadioButtonPromptAsync(string message, { var tcs = new TaskCompletionSource(); - var selectionView = new SelectionView + var prop = displayMember != null ? typeof(T).GetProperty(displayMember) : null; + + var rbGroup = new RadioButtonGroupView() { - ColumnNumber = 1, - RowSpacing = 10, - SelectionType = InputKit.Shared.SelectionType.RadioButton, - ItemsSource = selectionSource.ToList(), + Margin = 20, + VerticalOptions = LayoutOptions.Center, + HorizontalOptions = LayoutOptions.Start }; - selectionView.SelectedItem = selected; + foreach (var item in selectionSource) + { + rbGroup.Add(new InputKit.Shared.Controls.RadioButton + { + Text = prop != null ? prop.GetValue(item)?.ToString() : item.ToString(), + Value = item, + }); + } + + rbGroup.SelectedItem = selected; - Application.Current.MainPage.Navigation.PushModalAsync(new ContentPage + var rootGrid = new Grid { - Content = new ScrollView + RowDefinitions = new RowDefinitionCollection + { + new RowDefinition(GridLength.Auto), + new RowDefinition(GridLength.Star), + new RowDefinition(GridLength.Auto), + new RowDefinition(GridLength.Auto), + } + }; + + var currentPage = GetCurrentPage(); + + rootGrid.Add(GetHeader(message)); + rootGrid.Add(new ScrollView { Content = rbGroup, VerticalOptions = LayoutOptions.Start, MaximumHeightRequest = currentPage.Height * 0.6, }, row: 1); + rootGrid.Add(GetDivider(), row: 2); + rootGrid.Add(GetFooter( + accept, new Command(() => { - Content = new VerticalStackLayout - { - Padding = 20, - Spacing = 20, - HorizontalOptions = LayoutOptions.Center, - Children = { - new Label{ Text = message }, - selectionView, - new HorizontalStackLayout - { - Spacing = 4, - Children = - { - new Button - { - Text = accept, - StyleClass = new []{ "FilledButton", "Dialog.Accept" }, - Command = new Command(() => - { - tcs.SetResult((T)(selectionView.SelectedItem ?? default(T))); - Application.Current.MainPage.Navigation.PopModalAsync(); - }) - }, - new Button - { - Text = cancel, - StyleClass = new []{ "OutlinedButton", "Dialog.Cancel" }, - Command = new Command(() => - { - tcs.SetResult(default(T)); - Application.Current.MainPage.Navigation.PopModalAsync(); - }) - } - } - } - } - } - } - }); + tcs.TrySetResult((T)rbGroup.SelectedItem); + currentPage.Navigation.PopModalAsync(animated: false); + }), + cancel, new Command(() => + { + tcs.TrySetResult(default); + currentPage.Navigation.PopModalAsync(animated: false); + }) + ), row: 3); + + currentPage.Navigation.PushModalAsync(ConfigurePopupPage(new ContentPage + { + BackgroundColor = GetBackdropColor(), + Content = GetFrame(currentPage.Width, rootGrid) + }), animated: false); return tcs.Task; } @@ -150,6 +192,176 @@ public Task DisplayTextPromptAsync( Keyboard keyboard = null, string initialValue = "") { - return Application.Current.MainPage.DisplayPromptAsync(title, message, accept, cancel, placeholder, maxLength, keyboard, initialValue); + var tcs = new TaskCompletionSource(); + + var entry = new EntryView + { + HorizontalOptions = LayoutOptions.Fill, + Placeholder = placeholder, + MaxLength = maxLength != -1 ? maxLength : int.MaxValue, + ClearButtonVisibility = ClearButtonVisibility.WhileEditing, + Keyboard = keyboard, + TextColor = ColorResource.GetColor("OnBackground", "OnBackgroundDark", Colors.WhiteSmoke), + PlaceholderColor = ColorResource.GetColor("Background", "BackgroundDark", Colors.Gray).WithAlpha(.5f), + BackgroundColor = Colors.Transparent, + Text = initialValue, + }; + + var entryholder = new Border + { + BackgroundColor = ColorResource.GetColor("OnSurface", "OnSurfaceDark", Colors.DarkGray).WithAlpha(.2f), + StyleClass = new[] { "SurfaceContainer", "Rounded" }, + Margin = new Thickness(20, 0, 20, 20), +#if IOS + Padding = new Thickness(5, 5), +#else + Padding = new Thickness(5, 0), +#endif + Content = entry + }; + + var currentPage = GetCurrentPage(); + + var popupPage = new ContentPage + { + BackgroundColor = GetBackdropColor(), + Content = GetFrame(currentPage.Width, new VerticalStackLayout + { + Children = + { + GetHeader(title), + new Label + { + Text = message, + Margin = 20 + }, + entryholder, + GetDivider(), + GetFooter( + accept, new Command(()=> + { + tcs.TrySetResult(entry.Text); + currentPage.Navigation.PopModalAsync(animated: false); + }), + cancel, new Command(()=> + { + tcs.TrySetResult(initialValue); + currentPage.Navigation.PopModalAsync(animated: false); + })) + } + }) + }; + + currentPage.Navigation.PushModalAsync(ConfigurePopupPage(popupPage), animated: false); + + return tcs.Task; + } + + protected virtual Page GetCurrentPage() + { + if (Application.Current.MainPage is Shell shell) + { + return shell.CurrentPage; + } + + if (Application.Current.MainPage is NavigationPage nav) + { + return nav.CurrentPage; + } + + if (Application.Current.MainPage is TabbedPage tabbed) + { + return tabbed.CurrentPage; + } + + return Application.Current.MainPage; + } + + protected virtual Color GetBackdropColor() + { + return Application.Current.RequestedTheme switch + { + AppTheme.Light => Color.FromArgb("#80000000"), + AppTheme.Dark => Color.FromArgb("#80ffffff"), + _ => Color.FromArgb("#80808080") + }; + } + + protected virtual Page ConfigurePopupPage(Page popupPage) + { +#if IOS + Microsoft.Maui.Controls.PlatformConfiguration.iOSSpecific.Page.SetModalPresentationStyle( + popupPage.On(), + Microsoft.Maui.Controls.PlatformConfiguration.iOSSpecific.UIModalPresentationStyle.OverFullScreen + ); +#endif + + return popupPage; + } + + protected virtual View GetFrame(double width, View content) + { + var options = UraniumServiceProvider.Current.GetRequiredService>()?.Value; + var desiredWidth = DeviceInfo.Idiom == DeviceIdiom.Desktop ? 400 : width * .8; + var frame = new Border + { + StyleClass = new[] { "SurfaceContainer", "Rounded" }, + HorizontalOptions = LayoutOptions.Center, + VerticalOptions = LayoutOptions.Center, + Padding = 0, + WidthRequest = desiredWidth, + Content = content + }; + + foreach (var effectFactory in options.Effects) + { + frame.Effects.Add(effectFactory()); + } + + return frame; + } + protected virtual BoxView GetDivider() + { + return new BoxView { StyleClass = new[] { "Divider" }, Margin = 0, HeightRequest = 1 }; + } + protected virtual View GetHeader(string title) + { + return new StackLayout + { + HorizontalOptions = LayoutOptions.Fill, + Children = + { + new Label + { + Text = title, + Margin = 20, + }, + GetDivider(), + } + }; + } + + protected virtual View GetFooter(string accept, Command acceptCommand, string cancel, Command cancelCommand) + { + return new FlexLayout + { + JustifyContent = Microsoft.Maui.Layouts.FlexJustify.End, + Margin = new Thickness(10), + Children = + { + new Button + { + Text = cancel, + StyleClass = new []{ "TextButton", "Dialog.Cancel" }, + Command = cancelCommand + }, + new Button + { + Text = accept, + StyleClass = new []{ "TextButton", "Dialog.Accept" }, + Command = acceptCommand + } + } + }; } }