From 81de2e83d9ebd3dcd0e929c46cb8609b01b92d8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Su=C3=A1rez?= Date: Tue, 15 Jun 2021 18:25:32 +0200 Subject: [PATCH 01/17] Implement Alerts in Maui Core --- .../Core/src/WinUI/FormsFlyout.xaml.cs | 14 +- ...Direction.cs => FlowDirectionConverter.cs} | 8 - src/Controls/src/Core/Page.cs | 20 +- .../src/Core/TypeConverterAttribute.cs | 1 + .../src/Platform/Android/HandlerExtensions.cs | 2 +- .../Platform/Android/MauiAppCompatActivity.cs | 18 +- src/Core/src/Platform/Android/PopupManager.cs | 540 ++++++++++++++++++ .../src/Platform}/MessagingCenter.cs | 3 +- .../src/Platform/Windows/ActionSheetDialog.cs | 7 + src/Core/src/Platform/Windows/AlertDialog.cs | 7 + .../Platform/Windows/MauiWinUIApplication.cs | 17 +- src/Core/src/Platform/Windows/PopupManager.cs | 131 +++++ src/Core/src/Platform/Windows/PromptDialog.cs | 7 + .../Platform/iOS/MauiUIApplicationDelegate.cs | 5 + src/Core/src/Platform/iOS/PopupManager.cs | 196 +++++++ .../src/Primitives}/ActionSheetArguments.cs | 3 +- src/Core/src/Primitives/Alert.cs | 10 + .../src/Primitives}/AlertArguments.cs | 4 +- src/Core/src/Primitives/FlowDirection.cs | 5 +- .../src/Primitives}/PromptArguments.cs | 3 +- 20 files changed, 956 insertions(+), 45 deletions(-) rename src/Controls/src/Core/{FlowDirection.cs => FlowDirectionConverter.cs} (87%) create mode 100644 src/Core/src/Platform/Android/PopupManager.cs rename src/{Controls/src/Core => Core/src/Platform}/MessagingCenter.cs (99%) create mode 100644 src/Core/src/Platform/Windows/ActionSheetDialog.cs create mode 100644 src/Core/src/Platform/Windows/AlertDialog.cs create mode 100644 src/Core/src/Platform/Windows/PopupManager.cs create mode 100644 src/Core/src/Platform/Windows/PromptDialog.cs create mode 100644 src/Core/src/Platform/iOS/PopupManager.cs rename src/{Controls/src/Core => Core/src/Primitives}/ActionSheetArguments.cs (96%) create mode 100644 src/Core/src/Primitives/Alert.cs rename src/{Controls/src/Core => Core/src/Primitives}/AlertArguments.cs (93%) rename src/{Controls/src/Core => Core/src/Primitives}/PromptArguments.cs (95%) diff --git a/src/Compatibility/Core/src/WinUI/FormsFlyout.xaml.cs b/src/Compatibility/Core/src/WinUI/FormsFlyout.xaml.cs index 351c8178a263..b258d4139cc8 100644 --- a/src/Compatibility/Core/src/WinUI/FormsFlyout.xaml.cs +++ b/src/Compatibility/Core/src/WinUI/FormsFlyout.xaml.cs @@ -21,18 +21,18 @@ public FormsFlyout(ActionSheetArguments sheetOptions) TitleBlock.Text = options.Title ?? string.Empty; OptionsList.ItemsSource = options.Buttons.ToList(); - if (options.FlowDirection == Microsoft.Maui.Controls.FlowDirection.RightToLeft) + if (options.FlowDirection == Maui.FlowDirection.RightToLeft) { - TitleBlock.FlowDirection = Microsoft.UI.Xaml.FlowDirection.RightToLeft; - OptionsList.FlowDirection = Microsoft.UI.Xaml.FlowDirection.RightToLeft; + TitleBlock.FlowDirection = UI.Xaml.FlowDirection.RightToLeft; + OptionsList.FlowDirection = UI.Xaml.FlowDirection.RightToLeft; } - else if (options.FlowDirection == Microsoft.Maui.Controls.FlowDirection.LeftToRight) + else if (options.FlowDirection == Maui.FlowDirection.LeftToRight) { - TitleBlock.FlowDirection = Microsoft.UI.Xaml.FlowDirection.LeftToRight; - OptionsList.FlowDirection = Microsoft.UI.Xaml.FlowDirection.LeftToRight; + TitleBlock.FlowDirection = UI.Xaml.FlowDirection.LeftToRight; + OptionsList.FlowDirection = UI.Xaml.FlowDirection.LeftToRight; } - if (options.FlowDirection == Microsoft.Maui.Controls.FlowDirection.RightToLeft) + if (options.FlowDirection == Maui.FlowDirection.RightToLeft) { if (options.Cancel != null) { diff --git a/src/Controls/src/Core/FlowDirection.cs b/src/Controls/src/Core/FlowDirectionConverter.cs similarity index 87% rename from src/Controls/src/Core/FlowDirection.cs rename to src/Controls/src/Core/FlowDirectionConverter.cs index 39386da0203b..4c40512da179 100644 --- a/src/Controls/src/Core/FlowDirection.cs +++ b/src/Controls/src/Core/FlowDirectionConverter.cs @@ -2,14 +2,6 @@ namespace Microsoft.Maui.Controls { - [TypeConverter(typeof(FlowDirectionConverter))] - public enum FlowDirection - { - MatchParent = 0, - LeftToRight = 1, - RightToLeft = 2, - } - [Xaml.TypeConversion(typeof(FlowDirection))] public class FlowDirectionConverter : TypeConverter { diff --git a/src/Controls/src/Core/Page.cs b/src/Controls/src/Core/Page.cs index 1ad1c96de046..97b7da31b393 100644 --- a/src/Controls/src/Core/Page.cs +++ b/src/Controls/src/Core/Page.cs @@ -13,13 +13,13 @@ namespace Microsoft.Maui.Controls { public partial class Page : VisualElement, ILayout, IPageController, IElementConfiguration, IPaddingElement { - public const string BusySetSignalName = "Microsoft.Maui.Controls.BusySet"; + public const string BusySetSignalName = AlertConstants.BusySetSignalName; - public const string AlertSignalName = "Microsoft.Maui.Controls.SendAlert"; + public const string AlertSignalName = AlertConstants.AlertSignalName; - public const string PromptSignalName = "Microsoft.Maui.Controls.SendPrompt"; + public const string PromptSignalName = AlertConstants.PromptSignalName; - public const string ActionSheetSignalName = "Microsoft.Maui.Controls.ShowActionSheet"; + public const string ActionSheetSignalName = AlertConstants.ActionSheetSignalName; internal static readonly BindableProperty IgnoresContainerAreaProperty = BindableProperty.Create("IgnoresContainerArea", typeof(bool), typeof(Page), false); @@ -165,9 +165,9 @@ public Task DisplayActionSheet(string title, string cancel, string destr args.FlowDirection = flowDirection; if (IsPlatformEnabled) - MessagingCenter.Send(this, ActionSheetSignalName, args); + MessagingCenter.Send((IPage)this, ActionSheetSignalName, args); else - _pendingActions.Add(() => MessagingCenter.Send(this, ActionSheetSignalName, args)); + _pendingActions.Add(() => MessagingCenter.Send((IPage)this, ActionSheetSignalName, args)); return args.Result.Task; } @@ -196,9 +196,9 @@ public Task DisplayAlert(string title, string message, string accept, stri args.FlowDirection = flowDirection; if (IsPlatformEnabled) - MessagingCenter.Send(this, AlertSignalName, args); + MessagingCenter.Send((IPage)this, AlertSignalName, args); else - _pendingActions.Add(() => MessagingCenter.Send(this, AlertSignalName, args)); + _pendingActions.Add(() => MessagingCenter.Send((IPage)this, AlertSignalName, args)); return args.Result.Task; } @@ -208,9 +208,9 @@ public Task DisplayAlert(string title, string message, string accept, stri var args = new PromptArguments(title, message, accept, cancel, placeholder, maxLength, keyboard, initialValue); if (IsPlatformEnabled) - MessagingCenter.Send(this, PromptSignalName, args); + MessagingCenter.Send((IPage)this, PromptSignalName, args); else - _pendingActions.Add(() => MessagingCenter.Send(this, PromptSignalName, args)); + _pendingActions.Add(() => MessagingCenter.Send((IPage)this, PromptSignalName, args)); return args.Result.Task; } diff --git a/src/Controls/src/Core/TypeConverterAttribute.cs b/src/Controls/src/Core/TypeConverterAttribute.cs index 31056e369a77..5e4e4d635ac4 100644 --- a/src/Controls/src/Core/TypeConverterAttribute.cs +++ b/src/Controls/src/Core/TypeConverterAttribute.cs @@ -50,6 +50,7 @@ public sealed class TypeConverterAttribute : Attribute { typeof(CornerRadius), typeof(CornerRadiusTypeConverter) }, { typeof(Color), typeof(ColorTypeConverter) }, { typeof(Font), typeof(FontTypeConverter) }, + { typeof(FlowDirection), typeof(FlowDirectionConverter) }, { typeof(Keyboard), typeof(KeyboardTypeConverter) }, { typeof(Rectangle), typeof(RectangleTypeConverter) }, { typeof(Size), typeof(SizeTypeConverter) }, diff --git a/src/Core/src/Platform/Android/HandlerExtensions.cs b/src/Core/src/Platform/Android/HandlerExtensions.cs index 1ecdee79372b..fd9d15020dea 100644 --- a/src/Core/src/Platform/Android/HandlerExtensions.cs +++ b/src/Core/src/Platform/Android/HandlerExtensions.cs @@ -1,5 +1,4 @@ using System; -using Microsoft.Maui.Hosting; using AView = Android.Views.View; namespace Microsoft.Maui @@ -7,6 +6,7 @@ namespace Microsoft.Maui public static class HandlerExtensions { public static AView ToContainerView(this IView view, IMauiContext context) => new ContainerView(context) { CurrentView = view }; + public static AView ToNative(this IView view, IMauiContext context) { _ = view ?? throw new ArgumentNullException(nameof(view)); diff --git a/src/Core/src/Platform/Android/MauiAppCompatActivity.cs b/src/Core/src/Platform/Android/MauiAppCompatActivity.cs index 595d8b9321bb..c3052f1da494 100644 --- a/src/Core/src/Platform/Android/MauiAppCompatActivity.cs +++ b/src/Core/src/Platform/Android/MauiAppCompatActivity.cs @@ -1,11 +1,7 @@ using System; using Android.OS; -using Android.Views; using AndroidX.AppCompat.App; using AndroidX.AppCompat.Widget; -using AndroidX.CoordinatorLayout.Widget; -using AndroidX.Navigation.UI; -using Google.Android.Material.AppBar; namespace Microsoft.Maui { @@ -57,12 +53,13 @@ protected override void OnCreate(Bundle? savedInstanceState) window = mauiApp.CreateWindow(state); } + PopupManager.Subscribe(this, mauiContext); + SetContentView(window.View.ToNative(mauiContext)); //TODO MAUI // Allow users to customize the toolbarid? - bool? windowActionBar; - if (Theme.TryResolveAttribute(Resource.Attribute.windowActionBar, out windowActionBar) && + if (Theme.TryResolveAttribute(Resource.Attribute.windowActionBar, out var windowActionBar) && windowActionBar == false) { var toolbar = FindViewById(Resource.Id.maui_toolbar); @@ -70,5 +67,12 @@ protected override void OnCreate(Bundle? savedInstanceState) SetSupportActionBar(toolbar); } } + + protected override void OnDestroy() + { + base.OnDestroy(); + + PopupManager.Unsubscribe(this); + } } -} +} \ No newline at end of file diff --git a/src/Core/src/Platform/Android/PopupManager.cs b/src/Core/src/Platform/Android/PopupManager.cs new file mode 100644 index 000000000000..b001a96f7c56 --- /dev/null +++ b/src/Core/src/Platform/Android/PopupManager.cs @@ -0,0 +1,540 @@ +#nullable disable +using System; +using System.Collections.Generic; +using System.Linq; +using Android.App; +using Android.Content; +using Android.Text; +using Android.Views; +using Android.Widget; +using AppCompatActivity = AndroidX.AppCompat.App.AppCompatActivity; +using AppCompatAlertDialog = AndroidX.AppCompat.App.AlertDialog; +using AWindow = Android.Views.Window; + +namespace Microsoft.Maui +{ + internal static class PopupManager + { + static readonly List Subscriptions = new List(); + + internal static void Subscribe(Activity context, MauiContext mauiContext) + { + if (Subscriptions.Any(s => s.Activity == context)) + { + return; + } + + Subscriptions.Add(new PopupRequestHelper(context, mauiContext)); + } + + internal static void Unsubscribe(Activity context) + { + var toRemove = Subscriptions.Where(s => s.Activity == context).ToList(); + + foreach (PopupRequestHelper popupRequestHelper in toRemove) + { + popupRequestHelper.Dispose(); + Subscriptions.Remove(popupRequestHelper); + } + } + + internal static void ResetBusyCount(Activity context) + { + Subscriptions.FirstOrDefault(s => s.Activity == context)?.ResetBusyCount(); + } + + internal sealed class PopupRequestHelper : IDisposable + { + int _busyCount; + bool? _supportsProgress; + + internal PopupRequestHelper(Activity context, MauiContext mauiContext) + { + Activity = context; + MauiContext = mauiContext; + + MessagingCenter.Subscribe(Activity, AlertConstants.BusySetSignalName, OnPageBusy); + MessagingCenter.Subscribe(Activity, AlertConstants.AlertSignalName, OnAlertRequested); + MessagingCenter.Subscribe(Activity, AlertConstants.PromptSignalName, OnPromptRequested); + MessagingCenter.Subscribe(Activity, AlertConstants.ActionSheetSignalName, OnActionSheetRequested); + } + + public Activity Activity { get; } + public MauiContext MauiContext { get; } + + public void Dispose() + { + MessagingCenter.Unsubscribe(Activity, AlertConstants.BusySetSignalName); + MessagingCenter.Unsubscribe(Activity, AlertConstants.AlertSignalName); + MessagingCenter.Unsubscribe(Activity, AlertConstants.PromptSignalName); + MessagingCenter.Unsubscribe(Activity, AlertConstants.ActionSheetSignalName); + } + + public void ResetBusyCount() + { + _busyCount = 0; + } + + void OnPageBusy(IPage sender, bool enabled) + { + // Verify that the page making the request is part of this activity + if (!PageIsInThisContext(sender)) + { + return; + } + + _busyCount = Math.Max(0, enabled ? _busyCount + 1 : _busyCount - 1); + + UpdateProgressBarVisibility(_busyCount > 0); + } + + void OnActionSheetRequested(IPage sender, ActionSheetArguments arguments) + { + // Verify that the page making the request is part of this activity + if (!PageIsInThisContext(sender)) + { + return; + } + + var builder = new DialogBuilder(Activity); + + builder.SetTitle(arguments.Title); + string[] items = arguments.Buttons.ToArray(); + builder.SetItems(items, (o, args) => arguments.Result.TrySetResult(items[args.Which])); + + if (arguments.Cancel != null) + builder.SetPositiveButton(arguments.Cancel, (o, args) => arguments.Result.TrySetResult(arguments.Cancel)); + + if (arguments.Destruction != null) + builder.SetNegativeButton(arguments.Destruction, (o, args) => arguments.Result.TrySetResult(arguments.Destruction)); + + var dialog = builder.Create(); + builder.Dispose(); + + if (dialog == null) + return; + + // To match current functionality of handler we set cancelable on outside + // and return null + if (dialog.Window != null) + { + if (arguments.FlowDirection == FlowDirection.MatchParent && sender is IView view) + { + // TODO: Update FlowDirection + } + else if (arguments.FlowDirection == FlowDirection.LeftToRight) + dialog.Window.DecorView.LayoutDirection = LayoutDirection.Ltr; + else if (arguments.FlowDirection == FlowDirection.RightToLeft) + dialog.Window.DecorView.LayoutDirection = LayoutDirection.Rtl; + } + + dialog.SetCanceledOnTouchOutside(true); + dialog.SetCancelEvent((o, e) => arguments.SetResult(null)); + dialog.Show(); + + var listView = dialog.GetListView(); + + if (listView != null) + { + listView.TextDirection = GetTextDirection(sender, arguments.FlowDirection); + LayoutDirection layoutDirection = GetLayoutDirection(sender, arguments.FlowDirection); + + if (dialog.GetButton((int)DialogButtonType.Negative)?.Parent is View parentView) + { + if (arguments.Cancel != null) + parentView.LayoutDirection = layoutDirection; + if (arguments.Destruction != null) + parentView.LayoutDirection = layoutDirection; + } + } + } + + void OnAlertRequested(IPage sender, AlertArguments arguments) + { + // Verify that the page making the request is part of this activity + if (!PageIsInThisContext(sender)) + { + return; + } + + int messageID = 16908299; + var alert = new DialogBuilder(Activity).Create(); + + if (alert == null) + return; + + if (alert.Window != null) + { + if (arguments.FlowDirection == FlowDirection.MatchParent && sender is IView view) + { + // TODO: Update FlowDirection + } + else if (arguments.FlowDirection == FlowDirection.LeftToRight) + alert.Window.DecorView.LayoutDirection = LayoutDirection.Ltr; + else if (arguments.FlowDirection == FlowDirection.RightToLeft) + alert.Window.DecorView.LayoutDirection = LayoutDirection.Rtl; + } + + alert.SetTitle(arguments.Title); + alert.SetMessage(arguments.Message); + if (arguments.Accept != null) + alert.SetButton((int)DialogButtonType.Positive, arguments.Accept, (o, args) => arguments.SetResult(true)); + alert.SetButton((int)DialogButtonType.Negative, arguments.Cancel, (o, args) => arguments.SetResult(false)); + alert.SetCancelEvent((o, args) => { arguments.SetResult(false); }); + alert.Show(); + + TextView textView = (TextView)alert.findViewByID(messageID); + textView.TextDirection = GetTextDirection(sender, arguments.FlowDirection); + + + if (alert.GetButton((int)DialogButtonType.Negative).Parent is View parentView) + parentView.LayoutDirection = GetLayoutDirection(sender, arguments.FlowDirection); + } + + LayoutDirection GetLayoutDirection(IPage sender, FlowDirection flowDirection) + { + if (flowDirection == FlowDirection.LeftToRight) + return LayoutDirection.Ltr; + else if (flowDirection == FlowDirection.RightToLeft) + return LayoutDirection.Rtl; + + // TODO: Check EffectiveFlowDirection + + return LayoutDirection.Ltr; + } + + TextDirection GetTextDirection(IPage sender, FlowDirection flowDirection) + { + if (flowDirection == FlowDirection.LeftToRight) + return TextDirection.Ltr; + else if (flowDirection == FlowDirection.RightToLeft) + return TextDirection.Rtl; + + // TODO: Check EffectiveFlowDirection + + return TextDirection.Ltr; + } + + void OnPromptRequested(IPage sender, PromptArguments arguments) + { + // Verify that the page making the request is part of this activity + if (!PageIsInThisContext(sender)) + { + return; + } + + var alertDialog = new DialogBuilder(Activity).Create(); + + if (alertDialog == null) + return; + + alertDialog.SetTitle(arguments.Title); + alertDialog.SetMessage(arguments.Message); + + var frameLayout = new FrameLayout(Activity); + var editText = new EditText(Activity) { Hint = arguments.Placeholder, Text = arguments.InitialValue }; + var layoutParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.WrapContent) + { + LeftMargin = (int)(22 * Activity.Resources.DisplayMetrics.Density), + RightMargin = (int)(22 * Activity.Resources.DisplayMetrics.Density) + }; + + editText.LayoutParameters = layoutParams; + editText.InputType = arguments.Keyboard.ToInputType(); + if (arguments.Keyboard == Keyboard.Numeric) + editText.KeyListener = LocalizedDigitsKeyListener.Create(editText.InputType); + + if (arguments.MaxLength > -1) + editText.SetFilters(new IInputFilter[] { new InputFilterLengthFilter(arguments.MaxLength) }); + + frameLayout.AddView(editText); + alertDialog.SetView(frameLayout); + + alertDialog.SetButton((int)DialogButtonType.Positive, arguments.Accept, (o, args) => arguments.SetResult(editText.Text)); + alertDialog.SetButton((int)DialogButtonType.Negative, arguments.Cancel, (o, args) => arguments.SetResult(null)); + alertDialog.SetCancelEvent((o, args) => { arguments.SetResult(null); }); + + alertDialog.Window.SetSoftInputMode(SoftInput.StateVisible); + alertDialog.Show(); + editText.RequestFocus(); + } + + void UpdateProgressBarVisibility(bool isBusy) + { + if (!SupportsProgress) + return; +#pragma warning disable 612, 618 + + Activity.SetProgressBarIndeterminate(true); + Activity.SetProgressBarIndeterminateVisibility(isBusy); +#pragma warning restore 612, 618 + } + + internal bool SupportsProgress + { + get + { + if (_supportsProgress.HasValue) + return _supportsProgress.Value; + + int progressCircularId = Activity.Resources.GetIdentifier("progress_circular", "id", "android"); + + if (progressCircularId > 0) + _supportsProgress = Activity.FindViewById(progressCircularId) != null; + else + _supportsProgress = true; + + return _supportsProgress.Value; + } + } + + bool PageIsInThisContext(IPage page) + { + var nativeView = page.ToNative(MauiContext); + + if (nativeView.Context == null) + { + return false; + } + + return nativeView.Context.Equals(Activity); + } + + // This is a proxy dialog builder class to support both pre-appcompat and appcompat dialogs for Alert, + // ActionSheet, Prompt, etc. + internal sealed class DialogBuilder + { + AppCompatAlertDialog.Builder _appcompatBuilder; + AlertDialog.Builder _legacyBuilder; + + bool _useAppCompat; + + public DialogBuilder(Activity activity) + { + if (activity is AppCompatActivity) + { + _appcompatBuilder = new AppCompatAlertDialog.Builder(activity); + _useAppCompat = true; + } + else + { + _legacyBuilder = new AlertDialog.Builder(activity); + } + } + + public void SetTitle(string title) + { + if (_useAppCompat) + { + _appcompatBuilder?.SetTitle(title); + } + else + { + _legacyBuilder?.SetTitle(title); + } + } + + public void SetItems(string[] items, EventHandler handler) + { + if (_useAppCompat) + { + _appcompatBuilder?.SetItems(items, handler); + } + else + { + _legacyBuilder?.SetItems(items, handler); + } + } + + public void SetPositiveButton(string text, EventHandler handler) + { + if (_useAppCompat) + { + _appcompatBuilder?.SetPositiveButton(text, handler); + } + else + { + _legacyBuilder?.SetPositiveButton(text, handler); + } + } + + public void SetNegativeButton(string text, EventHandler handler) + { + if (_useAppCompat) + { + _appcompatBuilder?.SetNegativeButton(text, handler); + } + else + { + _legacyBuilder?.SetNegativeButton(text, handler); + } + } + + public FlexibleAlertDialog Create() + { + if (_useAppCompat && _appcompatBuilder != null) + { + return new FlexibleAlertDialog(_appcompatBuilder.Create()); + } + + if (_legacyBuilder != null) + return new FlexibleAlertDialog(_legacyBuilder.Create()); + + return null; + } + + public void Dispose() + { + if (_useAppCompat) + { + _appcompatBuilder?.Dispose(); + } + else + { + _legacyBuilder?.Dispose(); + } + } + } + + internal sealed class FlexibleAlertDialog + { + readonly AppCompatAlertDialog _appcompatAlertDialog; + readonly AlertDialog _legacyAlertDialog; + bool _useAppCompat; + + public FlexibleAlertDialog(AlertDialog alertDialog) + { + _legacyAlertDialog = alertDialog; + } + + public FlexibleAlertDialog(AppCompatAlertDialog alertDialog) + { + _appcompatAlertDialog = alertDialog; + _useAppCompat = true; + } + + public void SetTitle(string title) + { + if (_useAppCompat) + { + _appcompatAlertDialog.SetTitle(title); + } + else + { + _legacyAlertDialog.SetTitle(title); + } + } + + public void SetMessage(string message) + { + if (_useAppCompat) + { + _appcompatAlertDialog.SetMessage(message); + } + else + { + _legacyAlertDialog.SetMessage(message); + } + } + + public void SetButton(int whichButton, string text, EventHandler handler) + { + if (_useAppCompat) + { + _appcompatAlertDialog.SetButton(whichButton, text, handler); + } + else + { + _legacyAlertDialog.SetButton(whichButton, text, handler); + } + } + + public Button GetButton(int whichButton) + { + if (_useAppCompat) + { + return _appcompatAlertDialog.GetButton(whichButton); + } + else + { + return _legacyAlertDialog.GetButton(whichButton); + } + } + + public View GetListView() + { + if (_useAppCompat) + { + return _appcompatAlertDialog.ListView; + } + else + { + return _legacyAlertDialog.ListView; + } + } + + public void SetCancelEvent(EventHandler cancel) + { + if (_useAppCompat) + { + _appcompatAlertDialog.CancelEvent += cancel; + } + else + { + _legacyAlertDialog.CancelEvent += cancel; + } + } + + public void SetCanceledOnTouchOutside(bool canceledOnTouchOutSide) + { + if (_useAppCompat) + { + _appcompatAlertDialog.SetCanceledOnTouchOutside(canceledOnTouchOutSide); + } + else + { + _legacyAlertDialog.SetCanceledOnTouchOutside(canceledOnTouchOutSide); + } + } + + public void SetView(View view) + { + if (_useAppCompat) + { + _appcompatAlertDialog.SetView(view); + } + else + { + _legacyAlertDialog.SetView(view); + } + } + + public View findViewByID(int id) + { + if (_useAppCompat) + { + return _appcompatAlertDialog.FindViewById(id); + } + else + { + return _legacyAlertDialog.FindViewById(id); + } + } + + public AWindow Window => _useAppCompat ? _appcompatAlertDialog?.Window : _legacyAlertDialog?.Window; + + public void Show() + { + if (_useAppCompat) + { + _appcompatAlertDialog.Show(); + } + else + { + _legacyAlertDialog.Show(); + } + } + } + } + } +} \ No newline at end of file diff --git a/src/Controls/src/Core/MessagingCenter.cs b/src/Core/src/Platform/MessagingCenter.cs similarity index 99% rename from src/Controls/src/Core/MessagingCenter.cs rename to src/Core/src/Platform/MessagingCenter.cs index 20e0bec7890c..61a000195e9f 100644 --- a/src/Controls/src/Core/MessagingCenter.cs +++ b/src/Core/src/Platform/MessagingCenter.cs @@ -1,9 +1,10 @@ +#nullable disable using System; using System.Collections.Generic; using System.Linq; using System.Reflection; -namespace Microsoft.Maui.Controls +namespace Microsoft.Maui { public interface IMessagingCenter { diff --git a/src/Core/src/Platform/Windows/ActionSheetDialog.cs b/src/Core/src/Platform/Windows/ActionSheetDialog.cs new file mode 100644 index 000000000000..fe5732546477 --- /dev/null +++ b/src/Core/src/Platform/Windows/ActionSheetDialog.cs @@ -0,0 +1,7 @@ +namespace Microsoft.Maui +{ + class ActionSheetDialog + { + + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Windows/AlertDialog.cs b/src/Core/src/Platform/Windows/AlertDialog.cs new file mode 100644 index 000000000000..e318c673cb6a --- /dev/null +++ b/src/Core/src/Platform/Windows/AlertDialog.cs @@ -0,0 +1,7 @@ +namespace Microsoft.Maui +{ + class AlertDialog + { + + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Windows/MauiWinUIApplication.cs b/src/Core/src/Platform/Windows/MauiWinUIApplication.cs index 1d5fe4f264c9..fc92427ca50b 100644 --- a/src/Core/src/Platform/Windows/MauiWinUIApplication.cs +++ b/src/Core/src/Platform/Windows/MauiWinUIApplication.cs @@ -3,10 +3,8 @@ using Microsoft.Extensions.Hosting; using Microsoft.Maui.Hosting; using Microsoft.Maui.LifecycleEvents; -using Microsoft.UI; using Microsoft.UI.Xaml.Controls; -using Microsoft.UI.Xaml.Data; -using Microsoft.UI.Xaml.Media; +using Windows.UI.Core.Preview; namespace Microsoft.Maui { @@ -37,7 +35,7 @@ protected override void OnLaunched(UI.Xaml.LaunchActivatedEventArgs args) var activationState = new ActivationState(mauiContext, args); var window = Application.CreateWindow(activationState); - var content = (window.View as IView); + var content = window.View; var canvas = CreateRootContainer(); @@ -47,6 +45,8 @@ protected override void OnLaunched(UI.Xaml.LaunchActivatedEventArgs args) MainWindow.Content = canvas; + PopupManager.Subscribe(this, mauiContext); + Current.Services?.InvokeLifecycleEvents(del => del(this, args)); MainWindow.SizeChanged += (sender, sizeChangedArgs) => @@ -66,9 +66,16 @@ protected override void OnLaunched(UI.Xaml.LaunchActivatedEventArgs args) nativeContent.Height = canvas.ActualHeight; }; + //SystemNavigationManagerPreview.GetForCurrentView().CloseRequested += OnCloseRequested; + MainWindow.Activate(); } + void OnCloseRequested(object? sender, SystemNavigationCloseRequestedPreviewEventArgs e) + { + PopupManager.Unsubscribe(this); + } + Canvas CreateRootContainer() { // TODO WINUI should this be some other known constant or via some mechanism? Or done differently? @@ -101,4 +108,4 @@ protected MauiWinUIApplication() public IApplication Application { get; protected set; } = null!; } -} +} \ No newline at end of file diff --git a/src/Core/src/Platform/Windows/PopupManager.cs b/src/Core/src/Platform/Windows/PopupManager.cs new file mode 100644 index 000000000000..4a80ad0bbecd --- /dev/null +++ b/src/Core/src/Platform/Windows/PopupManager.cs @@ -0,0 +1,131 @@ +#nullable disable +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; + +namespace Microsoft.Maui +{ + internal static class PopupManager + { + static readonly List Subscriptions = new List(); + + internal static void Subscribe(Application application, MauiContext mauiContext) + { + if (Subscriptions.Any(s => s.Application == application)) + { + return; + } + + Subscriptions.Add(new PopupRequestHelper(application, mauiContext)); + } + + internal static void Unsubscribe(Application application) + { + var toRemove = Subscriptions.Where(s => s.Application == application).ToList(); + + foreach (PopupRequestHelper popupRequestHelper in toRemove) + { + popupRequestHelper.Dispose(); + Subscriptions.Remove(popupRequestHelper); + } + } + + internal sealed class PopupRequestHelper : IDisposable + { + static Task CurrentAlert; + + internal PopupRequestHelper(Application application, MauiContext mauiContext) + { + Application = application; + MauiContext = mauiContext; + + MessagingCenter.Subscribe(Application, AlertConstants.BusySetSignalName, OnPageBusy); + MessagingCenter.Subscribe(Application, AlertConstants.AlertSignalName, OnAlertRequested); + MessagingCenter.Subscribe(Application, AlertConstants.PromptSignalName, OnPromptRequested); + MessagingCenter.Subscribe(Application, AlertConstants.ActionSheetSignalName, OnActionSheetRequested); + } + + public Application Application { get; } + public MauiContext MauiContext { get; } + + public void Dispose() + { + MessagingCenter.Unsubscribe(Application, AlertConstants.BusySetSignalName); + MessagingCenter.Unsubscribe(Application, AlertConstants.AlertSignalName); + MessagingCenter.Unsubscribe(Application, AlertConstants.PromptSignalName); + MessagingCenter.Unsubscribe(Application, AlertConstants.ActionSheetSignalName); + } + + void OnPageBusy(IPage sender, bool enabled) + { + + } + + async void OnAlertRequested(IPage sender, AlertArguments arguments) + { + string content = arguments.Message ?? string.Empty; + string title = arguments.Title ?? string.Empty; + + var alertDialog = new ContentDialog + { + Content = content, + Title = title + }; + + if (arguments.FlowDirection == FlowDirection.RightToLeft) + { + alertDialog.FlowDirection = UI.Xaml.FlowDirection.RightToLeft; + } + else if (arguments.FlowDirection == FlowDirection.LeftToRight) + { + alertDialog.FlowDirection = UI.Xaml.FlowDirection.LeftToRight; + } + + // TODO: Check EffectiveFlowDirection + + if (arguments.Cancel != null) + alertDialog.SecondaryButtonText = arguments.Cancel; + + if (arguments.Accept != null) + alertDialog.PrimaryButtonText = arguments.Accept; + + // This is a temporary workaround + var nativePage = sender.ToNative(MauiContext); + alertDialog.XamlRoot = nativePage.XamlRoot; + + var currentAlert = CurrentAlert; + + while (currentAlert != null) + { + await currentAlert; + currentAlert = CurrentAlert; + } + + CurrentAlert = ShowAlert(alertDialog); + arguments.SetResult(await CurrentAlert.ConfigureAwait(false)); + CurrentAlert = null; + } + + void OnPromptRequested(IPage sender, PromptArguments arguments) + { + + + } + + void OnActionSheetRequested(IPage sender, ActionSheetArguments arguments) + { + + } + + static async Task ShowAlert(ContentDialog alert) + { + ContentDialogResult result = await alert.ShowAsync(); + + return result == ContentDialogResult.Primary; + } + } + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Windows/PromptDialog.cs b/src/Core/src/Platform/Windows/PromptDialog.cs new file mode 100644 index 000000000000..36356e1ba082 --- /dev/null +++ b/src/Core/src/Platform/Windows/PromptDialog.cs @@ -0,0 +1,7 @@ +namespace Microsoft.Maui +{ + class PromptDialog + { + + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/iOS/MauiUIApplicationDelegate.cs b/src/Core/src/Platform/iOS/MauiUIApplicationDelegate.cs index e083af2801bc..2df863544f05 100644 --- a/src/Core/src/Platform/iOS/MauiUIApplicationDelegate.cs +++ b/src/Core/src/Platform/iOS/MauiUIApplicationDelegate.cs @@ -25,6 +25,7 @@ public override bool WillFinishLaunching(UIApplication application, NSDictionary Services = host.Services; Current.Services?.InvokeLifecycleEvents(del => del(application, launchOptions)); + return true; } @@ -32,6 +33,8 @@ public override bool FinishedLaunching(UIApplication application, NSDictionary l { Application = Services.GetRequiredService(); + PopupManager.Subscribe(application); + var mauiContext = new MauiContext(Services); var activationState = new ActivationState(mauiContext); @@ -92,6 +95,8 @@ public override void OnResignActivation(UIApplication application) public override void WillTerminate(UIApplication application) { + PopupManager.Unsubscribe(application); + Current.Services?.InvokeLifecycleEvents(del => del(application)); } diff --git a/src/Core/src/Platform/iOS/PopupManager.cs b/src/Core/src/Platform/iOS/PopupManager.cs new file mode 100644 index 000000000000..1b6bda71d3fd --- /dev/null +++ b/src/Core/src/Platform/iOS/PopupManager.cs @@ -0,0 +1,196 @@ +#nullable disable +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Foundation; +using Microsoft.Maui.Graphics; +using UIKit; + +namespace Microsoft.Maui +{ + internal static class PopupManager + { + static readonly List Subscriptions = new List(); + + internal static void Subscribe(UIApplication application) + { + if (Subscriptions.Any(s => s.Application == application)) + { + return; + } + + Subscriptions.Add(new PopupRequestHelper(application)); + } + + internal static void Unsubscribe(UIApplication context) + { + var toRemove = Subscriptions.Where(s => s.Application == context).ToList(); + + foreach (PopupRequestHelper popupRequestHelper in toRemove) + { + popupRequestHelper.Dispose(); + Subscriptions.Remove(popupRequestHelper); + } + } + internal sealed class PopupRequestHelper : IDisposable + { + const float AlertPadding = 10.0f; + + int _busyCount; + + internal PopupRequestHelper(UIApplication application) + { + Application = application; + + MessagingCenter.Subscribe(Application, AlertConstants.BusySetSignalName, OnPageBusy); + MessagingCenter.Subscribe(Application, AlertConstants.AlertSignalName, OnAlertRequested); + MessagingCenter.Subscribe(Application, AlertConstants.PromptSignalName, OnPromptRequested); + MessagingCenter.Subscribe(Application, AlertConstants.ActionSheetSignalName, OnActionSheetRequested); + } + + public UIApplication Application { get; } + + public void Dispose() + { + MessagingCenter.Unsubscribe(Application, AlertConstants.BusySetSignalName); + MessagingCenter.Unsubscribe(Application, AlertConstants.AlertSignalName); + MessagingCenter.Unsubscribe(Application, AlertConstants.PromptSignalName); + MessagingCenter.Unsubscribe(Application, AlertConstants.ActionSheetSignalName); + } + + void OnPageBusy(IPage sender, bool enabled) + { + _busyCount = Math.Max(0, enabled ? _busyCount + 1 : _busyCount - 1); + UIApplication.SharedApplication.NetworkActivityIndicatorVisible = _busyCount > 0; + } + + void OnAlertRequested(IPage sender, AlertArguments arguments) + { + PresentAlert(arguments); + } + + void OnPromptRequested(IPage sender, PromptArguments arguments) + { + PresentPrompt(arguments); + } + + void OnActionSheetRequested(IPage sender, ActionSheetArguments arguments) + { + PresentActionSheet(arguments); + } + + void PresentAlert(AlertArguments arguments) + { + var window = new UIWindow { BackgroundColor = Colors.Transparent.ToNative() }; + + var alert = UIAlertController.Create(arguments.Title, arguments.Message, UIAlertControllerStyle.Alert); + var oldFrame = alert.View.Frame; + alert.View.Frame = new RectangleF((float)oldFrame.X, (float)oldFrame.Y, (float)oldFrame.Width, (float)oldFrame.Height - AlertPadding * 2); + + if (arguments.Cancel != null) + { + alert.AddAction(CreateActionWithWindowHide(arguments.Cancel, UIAlertActionStyle.Cancel, + () => arguments.SetResult(false), window)); + } + + if (arguments.Accept != null) + { + alert.AddAction(CreateActionWithWindowHide(arguments.Accept, UIAlertActionStyle.Default, + () => arguments.SetResult(true), window)); + } + + PresentPopUp(window, alert); + } + + void PresentPrompt(PromptArguments arguments) + { + var window = new UIWindow { BackgroundColor = Colors.Transparent.ToNative() }; + + var alert = UIAlertController.Create(arguments.Title, arguments.Message, UIAlertControllerStyle.Alert); + alert.AddTextField(uiTextField => + { + uiTextField.Placeholder = arguments.Placeholder; + uiTextField.Text = arguments.InitialValue; + uiTextField.ShouldChangeCharacters = (field, range, replacementString) => arguments.MaxLength <= -1 || field.Text.Length + replacementString.Length - range.Length <= arguments.MaxLength; + uiTextField.ApplyKeyboard(arguments.Keyboard); + }); + + var oldFrame = alert.View.Frame; + alert.View.Frame = new RectangleF((float)oldFrame.X, (float)oldFrame.Y, (float)oldFrame.Width, (float)oldFrame.Height - AlertPadding * 2); + + alert.AddAction(CreateActionWithWindowHide(arguments.Cancel, UIAlertActionStyle.Cancel, () => arguments.SetResult(null), window)); + alert.AddAction(CreateActionWithWindowHide(arguments.Accept, UIAlertActionStyle.Default, () => arguments.SetResult(alert.TextFields[0].Text), window)); + + PresentPopUp(window, alert); + } + + + void PresentActionSheet(ActionSheetArguments arguments) + { + var alert = UIAlertController.Create(arguments.Title, null, UIAlertControllerStyle.ActionSheet); + var window = new UIWindow { BackgroundColor = Colors.Transparent.ToNative() }; + + // Clicking outside of an ActionSheet is an implicit cancel on iPads. If we don't handle it, it freezes the app. + if (arguments.Cancel != null || UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Pad) + { + alert.AddAction(CreateActionWithWindowHide(arguments.Cancel ?? "", UIAlertActionStyle.Cancel, () => arguments.SetResult(arguments.Cancel), window)); + } + + if (arguments.Destruction != null) + { + alert.AddAction(CreateActionWithWindowHide(arguments.Destruction, UIAlertActionStyle.Destructive, () => arguments.SetResult(arguments.Destruction), window)); + } + + foreach (var label in arguments.Buttons) + { + if (label == null) + continue; + + var blabel = label; + + alert.AddAction(CreateActionWithWindowHide(blabel, UIAlertActionStyle.Default, () => arguments.SetResult(blabel), window)); + } + + PresentPopUp(window, alert, arguments); + } + static void PresentPopUp(UIWindow window, UIAlertController alert, ActionSheetArguments arguments = null) + { + window.RootViewController = new UIViewController(); + window.RootViewController.View.BackgroundColor = Colors.Transparent.ToNative(); + window.WindowLevel = UIWindowLevel.Alert + 1; + window.MakeKeyAndVisible(); + + if (UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Pad && arguments != null) + { + UIDevice.CurrentDevice.BeginGeneratingDeviceOrientationNotifications(); + var observer = NSNotificationCenter.DefaultCenter.AddObserver(UIDevice.OrientationDidChangeNotification, + n => { alert.PopoverPresentationController.SourceRect = window.RootViewController.View.Bounds; }); + + arguments.Result.Task.ContinueWith(t => + { + NSNotificationCenter.DefaultCenter.RemoveObserver(observer); + UIDevice.CurrentDevice.EndGeneratingDeviceOrientationNotifications(); + }, TaskScheduler.FromCurrentSynchronizationContext()); + + alert.PopoverPresentationController.SourceView = window.RootViewController.View; + alert.PopoverPresentationController.SourceRect = window.RootViewController.View.Bounds; + alert.PopoverPresentationController.PermittedArrowDirections = 0; // No arrow + } + + window.RootViewController.PresentViewController(alert, true, null); + } + + // Creates a UIAlertAction which includes a call to hide the presenting UIWindow at the end + UIAlertAction CreateActionWithWindowHide(string text, UIAlertActionStyle style, Action setResult, UIWindow window) + { + return UIAlertAction.Create(text, style, + action => + { + window.Hidden = true; + setResult(); + }); + } + } + } +} \ No newline at end of file diff --git a/src/Controls/src/Core/ActionSheetArguments.cs b/src/Core/src/Primitives/ActionSheetArguments.cs similarity index 96% rename from src/Controls/src/Core/ActionSheetArguments.cs rename to src/Core/src/Primitives/ActionSheetArguments.cs index 16112e3e205f..6a4ef40dc9e1 100644 --- a/src/Controls/src/Core/ActionSheetArguments.cs +++ b/src/Core/src/Primitives/ActionSheetArguments.cs @@ -1,9 +1,10 @@ +#nullable disable using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Threading.Tasks; -namespace Microsoft.Maui.Controls.Internals +namespace Microsoft.Maui { [EditorBrowsable(EditorBrowsableState.Never)] public class ActionSheetArguments diff --git a/src/Core/src/Primitives/Alert.cs b/src/Core/src/Primitives/Alert.cs new file mode 100644 index 000000000000..56d0f26f924b --- /dev/null +++ b/src/Core/src/Primitives/Alert.cs @@ -0,0 +1,10 @@ +namespace Microsoft.Maui +{ + public class AlertConstants + { + public const string BusySetSignalName = "Microsoft.Maui.Controls.BusySet"; + public const string AlertSignalName = "Microsoft.Maui.Controls.SendAlert"; + public const string PromptSignalName = "Microsoft.Maui.Controls.SendPrompt"; + public const string ActionSheetSignalName = "Microsoft.Maui.Controls.ShowActionSheet"; + } +} diff --git a/src/Controls/src/Core/AlertArguments.cs b/src/Core/src/Primitives/AlertArguments.cs similarity index 93% rename from src/Controls/src/Core/AlertArguments.cs rename to src/Core/src/Primitives/AlertArguments.cs index 5c14bd0765db..ec7495ad0287 100644 --- a/src/Controls/src/Core/AlertArguments.cs +++ b/src/Core/src/Primitives/AlertArguments.cs @@ -1,7 +1,7 @@ -using System.ComponentModel; +using System.ComponentModel; using System.Threading.Tasks; -namespace Microsoft.Maui.Controls.Internals +namespace Microsoft.Maui { [EditorBrowsable(EditorBrowsableState.Never)] public class AlertArguments diff --git a/src/Core/src/Primitives/FlowDirection.cs b/src/Core/src/Primitives/FlowDirection.cs index 98aa3be61013..49dfe08c9b55 100644 --- a/src/Core/src/Primitives/FlowDirection.cs +++ b/src/Core/src/Primitives/FlowDirection.cs @@ -2,7 +2,8 @@ { public enum FlowDirection { - LeftToRight = 0, - RightToLeft = 1 + MatchParent = 0, + LeftToRight = 1, + RightToLeft = 2 } } \ No newline at end of file diff --git a/src/Controls/src/Core/PromptArguments.cs b/src/Core/src/Primitives/PromptArguments.cs similarity index 95% rename from src/Controls/src/Core/PromptArguments.cs rename to src/Core/src/Primitives/PromptArguments.cs index 6e4c8589f525..7434f88fdefa 100644 --- a/src/Controls/src/Core/PromptArguments.cs +++ b/src/Core/src/Primitives/PromptArguments.cs @@ -1,7 +1,8 @@ +#nullable disable using System.ComponentModel; using System.Threading.Tasks; -namespace Microsoft.Maui.Controls.Internals +namespace Microsoft.Maui { [EditorBrowsable(EditorBrowsableState.Never)] public class PromptArguments From 1b2cb168115b1260036be2059ffcc1e8923d8d0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Su=C3=A1rez?= Date: Wed, 16 Jun 2021 11:24:12 +0200 Subject: [PATCH 02/17] Updated Windows implementation --- .../samples/Controls.Sample/Pages/MainPage.cs | 499 ++++++++++-------- .../{PopupManager.cs => AlertManager.cs} | 16 +- .../Platform/Android/MauiAppCompatActivity.cs | 4 +- .../src/Platform/Windows/ActionSheetDialog.cs | 143 ++++- src/Core/src/Platform/Windows/AlertDialog.cs | 18 +- .../{PopupManager.cs => AlertManager.cs} | 103 +++- .../Platform/Windows/MauiWinUIApplication.cs | 10 +- src/Core/src/Platform/Windows/PromptDialog.cs | 61 ++- .../iOS/{PopupManager.cs => AlertManager.cs} | 17 +- .../Platform/iOS/MauiUIApplicationDelegate.cs | 4 +- .../{Alert.cs => AlertConstants.cs} | 0 11 files changed, 605 insertions(+), 270 deletions(-) rename src/Core/src/Platform/Android/{PopupManager.cs => AlertManager.cs} (96%) rename src/Core/src/Platform/Windows/{PopupManager.cs => AlertManager.cs} (52%) rename src/Core/src/Platform/iOS/{PopupManager.cs => AlertManager.cs} (94%) rename src/Core/src/Primitives/{Alert.cs => AlertConstants.cs} (100%) diff --git a/src/Controls/samples/Controls.Sample/Pages/MainPage.cs b/src/Controls/samples/Controls.Sample/Pages/MainPage.cs index 6ccda256ff3d..722725f3f6fd 100644 --- a/src/Controls/samples/Controls.Sample/Pages/MainPage.cs +++ b/src/Controls/samples/Controls.Sample/Pages/MainPage.cs @@ -72,231 +72,232 @@ Visibility IFrameworkElement.Visibility void SetupMauiLayout() { var verticalStack = new VerticalStackLayout() { Spacing = 5, BackgroundColor = Colors.AntiqueWhite }; - var horizontalStack = new HorizontalStackLayout() { Spacing = 2, BackgroundColor = Colors.CornflowerBlue }; + //var horizontalStack = new HorizontalStackLayout() { Spacing = 2, BackgroundColor = Colors.CornflowerBlue }; //verticalStack.Add(CreateSampleGrid()); - verticalStack.Add(CreateResizingButton()); - - AddTextResizeDemo(verticalStack); - verticalStack.Add(CreateTransformations()); - verticalStack.Add(CreateAnimations()); - verticalStack.Add(CreateShapes()); - - verticalStack.Add(new Label { Text = " ", Padding = new Thickness(10) }); - var label = new Label { Text = "End-aligned text", BackgroundColor = Colors.Fuchsia, HorizontalTextAlignment = TextAlignment.End }; - label.Margin = new Thickness(15, 10, 20, 15); - - SemanticProperties.SetHint(label, "Hint Text"); - SemanticProperties.SetDescription(label, "Description Text"); - - verticalStack.Add(label); - verticalStack.Add(new Label { Text = "This should be BIG text!", FontSize = 24, HorizontalOptions = LayoutOptions.End }); - - SemanticProperties.SetHeadingLevel((BindableObject)verticalStack.Children.Last(), SemanticHeadingLevel.Level1); - verticalStack.Add(new Label { Text = "This should be BOLD text!", FontAttributes = FontAttributes.Bold, HorizontalOptions = LayoutOptions.Center }); - verticalStack.Add(new Label { Text = "This should have character spacing!", CharacterSpacing = 3 }); - verticalStack.Add(new Label { Text = "This should be a CUSTOM font!", FontFamily = "Dokdo" }); - verticalStack.Add( - new Button - { - Text = "Push a Page", - Rotation = 15, - Scale = 1.5, - Command = new Command(async () => - { - await Navigation.PushAsync(new SemanticsPage()); - }) - } - ); - - verticalStack.Add(new Label { Text = "This should have padding", Padding = new Thickness(40), BackgroundColor = Colors.LightBlue }); - verticalStack.Add(new Label { Text = LoremIpsum }); - verticalStack.Add(new Label { Text = LoremIpsum, MaxLines = 2 }); - verticalStack.Add(new Label { Text = LoremIpsum, LineBreakMode = LineBreakMode.TailTruncation }); - verticalStack.Add(new Label { Text = LoremIpsum, MaxLines = 2, LineBreakMode = LineBreakMode.TailTruncation }); - verticalStack.Add(new Label { Text = "This should have five times the line height! " + LoremIpsum, LineHeight = 5, MaxLines = 2 }); - verticalStack.Add(new Label - { - FontSize = 24, - Text = "LinearGradient Text", - Background = new LinearGradientBrush( - new GradientStopCollection - { - new GradientStop(Colors.Green, 0), - new GradientStop(Colors.Blue, 1) - }, - new Point(0, 0), - new Point(1, 0)) - }); - verticalStack.Add(new Label - { - Text = "RadialGradient", - Padding = new Thickness(30), - Background = new RadialGradientBrush( - new GradientStopCollection - { - new GradientStop(Colors.DarkBlue, 0), - new GradientStop(Colors.Yellow, 0.6f), - new GradientStop(Colors.LightPink, 1) - }, - new Point(0.5, 0.5), - 0.3f) - }); - - SemanticProperties.SetHeadingLevel((BindableObject)verticalStack.Children.Last(), SemanticHeadingLevel.Level2); - - var visibleClearButtonEntry = new Entry() { ClearButtonVisibility = ClearButtonVisibility.WhileEditing, Placeholder = "This Entry will show clear button if has input." }; - var hiddenClearButtonEntry = new Entry() { ClearButtonVisibility = ClearButtonVisibility.Never, Placeholder = "This Entry will not..." }; - - verticalStack.Add(visibleClearButtonEntry); - verticalStack.Add(hiddenClearButtonEntry); - - verticalStack.Add(new Editor { Text = "Editor TextColor", TextColor = Colors.Olive }); - verticalStack.Add(new Editor { Text = "Editor using CharacterSpacing", CharacterSpacing = 10 }); - verticalStack.Add(new Editor { Placeholder = "This is an editor placeholder." }); - verticalStack.Add(new Editor { Placeholder = "Editor PlaceholderColor", PlaceholderColor = Colors.Green }); - - var paddingButton = new Button - { - Padding = new Thickness(40), - Text = "This button has a padding!!", - BackgroundColor = Colors.Purple, - }; - - verticalStack.Add(paddingButton); - - var underlineLabel = new Label { Text = "underline", TextDecorations = TextDecorations.Underline }; - verticalStack.Add(underlineLabel); - - verticalStack.Add(new ActivityIndicator()); - verticalStack.Add(new ActivityIndicator { Color = Colors.Red, IsRunning = true }); - - var button = new Button() { Text = _viewModel.Text, WidthRequest = 200 }; - button.Clicked += async (sender, e) => - { - var events = _services.GetRequiredService(); - events.InvokeEvents>("CustomEventName", action => action("VALUE")); - - var location = await Geolocation.GetLocationAsync(new GeolocationRequest(GeolocationAccuracy.Lowest)); - Debug.WriteLine($"I tracked you down to {location.Latitude}, {location.Longitude}! You can't hide!"); - }; - - var button2 = new Button() - { - TextColor = Colors.Green, - Text = "Hello I'm a button", - // BackgroundColor = Color.Purple, - Margin = new Thickness(12) - }; - - horizontalStack.Add(button); - horizontalStack.Add(button2); - - horizontalStack.Add(new Label { Text = "And these buttons are in a HorizontalStackLayout", VerticalOptions = LayoutOptions.Center }); - - verticalStack.Add(horizontalStack); - - verticalStack.Add(new Button { Text = "CharacterSpacing" }); - verticalStack.Add(new Button { CharacterSpacing = 8, Text = "CharacterSpacing" }); - - verticalStack.Add(new RedButton { Text = "Dynamically Registered" }); - verticalStack.Add(new CustomButton { Text = "Button Registered to Compat Renderer" }); - - var checkbox = new CheckBox(); - checkbox.CheckedChanged += (sender, e) => - { - Debug.WriteLine($"Checked Changed to '{e.Value}'"); - }; - verticalStack.Add(checkbox); - verticalStack.Add(new CheckBox { BackgroundColor = Colors.LightPink }); - verticalStack.Add(new CheckBox { IsChecked = true, Color = Colors.Aquamarine }); - - var editor = new Editor(); - editor.Completed += (sender, args) => - { - Debug.WriteLine($"Editor Completed"); - }; - - verticalStack.Add(editor); - verticalStack.Add(new Editor { Text = "Editor" }); - verticalStack.Add(new Editor { Text = "Lorem ipsum dolor sit amet", MaxLength = 10 }); - verticalStack.Add(new Editor { Text = "Predictive Text Off", IsTextPredictionEnabled = false }); - verticalStack.Add(new Editor { Text = "Lorem ipsum dolor sit amet", FontSize = 10, FontFamily = "Dokdo" }); - verticalStack.Add(new Editor { Text = "ReadOnly Editor", IsReadOnly = true }); - - var entry = new Entry(); - entry.TextChanged += (sender, e) => - { - Debug.WriteLine($"Text Changed from '{e.OldTextValue}' to '{e.NewTextValue}'"); - }; - - var entryMargin = new Thickness(10, 0); - - verticalStack.Add(entry); - verticalStack.Add(new Entry { Text = "Entry with custom Font", TextColor = Colors.DarkRed, FontFamily = "Dokdo", MaxLength = -1, Margin = entryMargin }); - verticalStack.Add(new Entry { IsPassword = true, TextColor = Colors.Black, Placeholder = "Pasword Entry", Margin = entryMargin }); - verticalStack.Add(new Entry { IsTextPredictionEnabled = false }); - verticalStack.Add(new Entry { Placeholder = "This should be placeholder text", Margin = entryMargin }); - verticalStack.Add(new Entry { Text = "This should be read only property", IsReadOnly = true, Margin = entryMargin }); - verticalStack.Add(new Entry { MaxLength = 5, Placeholder = "MaxLength text", Margin = entryMargin }); - verticalStack.Add(new Entry { Text = "This should be text with character spacing", CharacterSpacing = 10 }); - verticalStack.Add(new Entry { Keyboard = Keyboard.Numeric, Placeholder = "Numeric Entry" }); - verticalStack.Add(new Entry { Keyboard = Keyboard.Email, Placeholder = "Email Entry" }); - verticalStack.Add(new Entry { Placeholder = "This is a blue text box", BackgroundColor = Colors.CornflowerBlue }); - - verticalStack.Add(CreateSampleCursorSelection()); - - verticalStack.Add(new GraphicsView { Drawable = new TestDrawable(), HeightRequest = 50, WidthRequest = 200 }); - - verticalStack.Add(new ProgressBar { Progress = 0.5 }); - verticalStack.Add(new ProgressBar { Progress = 0.5, BackgroundColor = Colors.LightCoral }); - verticalStack.Add(new ProgressBar { Progress = 0.5, ProgressColor = Colors.Purple }); - - verticalStack.Add(new SearchBar { CharacterSpacing = 4, Text = "A search query", TextColor = Colors.Orange }); - verticalStack.Add(new SearchBar { Placeholder = "Placeholder" }); - verticalStack.Add(new SearchBar { HorizontalTextAlignment = TextAlignment.End, Text = "SearchBar HorizontalTextAlignment" }); - verticalStack.Add(new SearchBar { Text = "SearchBar MaxLength", MaxLength = 50 }); - verticalStack.Add(new SearchBar { Text = "SearchBar CancelButtonColor", CancelButtonColor = Colors.IndianRed }); - - var monkeyList = new List - { - "Baboon", - "Capuchin Monkey", - "Blue Monkey", - "Squirrel Monkey", - "Golden Lion Tamarin", - "Howler Monkey", - "Japanese Macaque" - }; - - var picker = new Picker { Title = "Select a monkey", TitleColor = Colors.Red, FontFamily = "Dokdo", HorizontalTextAlignment = TextAlignment.Center }; - - picker.ItemsSource = monkeyList; - verticalStack.Add(picker); - - verticalStack.Add(new Slider()); - verticalStack.Add(new Slider { ThumbImageSource = "dotnet_bot.png" }); - - verticalStack.Add(new Stepper()); - verticalStack.Add(new Stepper { BackgroundColor = Colors.IndianRed }); - verticalStack.Add(new Stepper { Minimum = 0, Maximum = 10, Value = 5 }); - - verticalStack.Add(new Switch()); - verticalStack.Add(new Switch() { OnColor = Colors.Green }); - verticalStack.Add(new Switch() { ThumbColor = Colors.Yellow }); - verticalStack.Add(new Switch() { OnColor = Colors.Green, ThumbColor = Colors.Yellow }); - - verticalStack.Add(new DatePicker()); - verticalStack.Add(new DatePicker { TextColor = Colors.OrangeRed }); - verticalStack.Add(new DatePicker { CharacterSpacing = 6 }); - verticalStack.Add(new DatePicker { FontSize = 24 }); - - verticalStack.Add(new TimePicker()); - verticalStack.Add(new TimePicker { TextColor = Colors.LightGreen }); - verticalStack.Add(new TimePicker { Time = TimeSpan.FromHours(8), CharacterSpacing = 6 }); - - verticalStack.Add(new Label { Text = "IMAGES (static | animated):" }); - verticalStack.Add(CreateImagesGrid()); + //verticalStack.Add(CreateResizingButton()); + + //AddTextResizeDemo(verticalStack); + //verticalStack.Add(CreateTransformations()); + //verticalStack.Add(CreateAnimations()); + //verticalStack.Add(CreateShapes()); + verticalStack.Add(CreateAlerts()); + + //verticalStack.Add(new Label { Text = " ", Padding = new Thickness(10) }); + //var label = new Label { Text = "End-aligned text", BackgroundColor = Colors.Fuchsia, HorizontalTextAlignment = TextAlignment.End }; + //label.Margin = new Thickness(15, 10, 20, 15); + + //SemanticProperties.SetHint(label, "Hint Text"); + //SemanticProperties.SetDescription(label, "Description Text"); + + //verticalStack.Add(label); + //verticalStack.Add(new Label { Text = "This should be BIG text!", FontSize = 24, HorizontalOptions = LayoutOptions.End }); + + //SemanticProperties.SetHeadingLevel((BindableObject)verticalStack.Children.Last(), SemanticHeadingLevel.Level1); + //verticalStack.Add(new Label { Text = "This should be BOLD text!", FontAttributes = FontAttributes.Bold, HorizontalOptions = LayoutOptions.Center }); + //verticalStack.Add(new Label { Text = "This should have character spacing!", CharacterSpacing = 3 }); + //verticalStack.Add(new Label { Text = "This should be a CUSTOM font!", FontFamily = "Dokdo" }); + //verticalStack.Add( + // new Button + // { + // Text = "Push a Page", + // Rotation = 15, + // Scale = 1.5, + // Command = new Command(async () => + // { + // await Navigation.PushAsync(new SemanticsPage()); + // }) + // } + //); + + //verticalStack.Add(new Label { Text = "This should have padding", Padding = new Thickness(40), BackgroundColor = Colors.LightBlue }); + //verticalStack.Add(new Label { Text = LoremIpsum }); + //verticalStack.Add(new Label { Text = LoremIpsum, MaxLines = 2 }); + //verticalStack.Add(new Label { Text = LoremIpsum, LineBreakMode = LineBreakMode.TailTruncation }); + //verticalStack.Add(new Label { Text = LoremIpsum, MaxLines = 2, LineBreakMode = LineBreakMode.TailTruncation }); + //verticalStack.Add(new Label { Text = "This should have five times the line height! " + LoremIpsum, LineHeight = 5, MaxLines = 2 }); + //verticalStack.Add(new Label + //{ + // FontSize = 24, + // Text = "LinearGradient Text", + // Background = new LinearGradientBrush( + // new GradientStopCollection + // { + // new GradientStop(Colors.Green, 0), + // new GradientStop(Colors.Blue, 1) + // }, + // new Point(0, 0), + // new Point(1, 0)) + //}); + //verticalStack.Add(new Label + //{ + // Text = "RadialGradient", + // Padding = new Thickness(30), + // Background = new RadialGradientBrush( + // new GradientStopCollection + // { + // new GradientStop(Colors.DarkBlue, 0), + // new GradientStop(Colors.Yellow, 0.6f), + // new GradientStop(Colors.LightPink, 1) + // }, + // new Point(0.5, 0.5), + // 0.3f) + //}); + + //SemanticProperties.SetHeadingLevel((BindableObject)verticalStack.Children.Last(), SemanticHeadingLevel.Level2); + + //var visibleClearButtonEntry = new Entry() { ClearButtonVisibility = ClearButtonVisibility.WhileEditing, Placeholder = "This Entry will show clear button if has input." }; + //var hiddenClearButtonEntry = new Entry() { ClearButtonVisibility = ClearButtonVisibility.Never, Placeholder = "This Entry will not..." }; + + //verticalStack.Add(visibleClearButtonEntry); + //verticalStack.Add(hiddenClearButtonEntry); + + //verticalStack.Add(new Editor { Text = "Editor TextColor", TextColor = Colors.Olive }); + //verticalStack.Add(new Editor { Text = "Editor using CharacterSpacing", CharacterSpacing = 10 }); + //verticalStack.Add(new Editor { Placeholder = "This is an editor placeholder." }); + //verticalStack.Add(new Editor { Placeholder = "Editor PlaceholderColor", PlaceholderColor = Colors.Green }); + + //var paddingButton = new Button + //{ + // Padding = new Thickness(40), + // Text = "This button has a padding!!", + // BackgroundColor = Colors.Purple, + //}; + + //verticalStack.Add(paddingButton); + + //var underlineLabel = new Label { Text = "underline", TextDecorations = TextDecorations.Underline }; + //verticalStack.Add(underlineLabel); + + //verticalStack.Add(new ActivityIndicator()); + //verticalStack.Add(new ActivityIndicator { Color = Colors.Red, IsRunning = true }); + + //var button = new Button() { Text = _viewModel.Text, WidthRequest = 200 }; + //button.Clicked += async (sender, e) => + //{ + // var events = _services.GetRequiredService(); + // events.InvokeEvents>("CustomEventName", action => action("VALUE")); + + // var location = await Geolocation.GetLocationAsync(new GeolocationRequest(GeolocationAccuracy.Lowest)); + // Debug.WriteLine($"I tracked you down to {location.Latitude}, {location.Longitude}! You can't hide!"); + //}; + + //var button2 = new Button() + //{ + // TextColor = Colors.Green, + // Text = "Hello I'm a button", + // BackgroundColor = Color.Purple, + // Margin = new Thickness(12) + //}; + + //horizontalStack.Add(button); + //horizontalStack.Add(button2); + + //horizontalStack.Add(new Label { Text = "And these buttons are in a HorizontalStackLayout", VerticalOptions = LayoutOptions.Center }); + + //verticalStack.Add(horizontalStack); + + //verticalStack.Add(new Button { Text = "CharacterSpacing" }); + //verticalStack.Add(new Button { CharacterSpacing = 8, Text = "CharacterSpacing" }); + + //verticalStack.Add(new RedButton { Text = "Dynamically Registered" }); + //verticalStack.Add(new CustomButton { Text = "Button Registered to Compat Renderer" }); + + //var checkbox = new CheckBox(); + //checkbox.CheckedChanged += (sender, e) => + //{ + // Debug.WriteLine($"Checked Changed to '{e.Value}'"); + //}; + //verticalStack.Add(checkbox); + //verticalStack.Add(new CheckBox { BackgroundColor = Colors.LightPink }); + //verticalStack.Add(new CheckBox { IsChecked = true, Color = Colors.Aquamarine }); + + //var editor = new Editor(); + //editor.Completed += (sender, args) => + //{ + // Debug.WriteLine($"Editor Completed"); + //}; + + //verticalStack.Add(editor); + //verticalStack.Add(new Editor { Text = "Editor" }); + //verticalStack.Add(new Editor { Text = "Lorem ipsum dolor sit amet", MaxLength = 10 }); + //verticalStack.Add(new Editor { Text = "Predictive Text Off", IsTextPredictionEnabled = false }); + //verticalStack.Add(new Editor { Text = "Lorem ipsum dolor sit amet", FontSize = 10, FontFamily = "Dokdo" }); + //verticalStack.Add(new Editor { Text = "ReadOnly Editor", IsReadOnly = true }); + + //var entry = new Entry(); + //entry.TextChanged += (sender, e) => + //{ + // Debug.WriteLine($"Text Changed from '{e.OldTextValue}' to '{e.NewTextValue}'"); + //}; + + //var entryMargin = new Thickness(10, 0); + + //verticalStack.Add(entry); + //verticalStack.Add(new Entry { Text = "Entry with custom Font", TextColor = Colors.DarkRed, FontFamily = "Dokdo", MaxLength = -1, Margin = entryMargin }); + //verticalStack.Add(new Entry { IsPassword = true, TextColor = Colors.Black, Placeholder = "Pasword Entry", Margin = entryMargin }); + //verticalStack.Add(new Entry { IsTextPredictionEnabled = false }); + //verticalStack.Add(new Entry { Placeholder = "This should be placeholder text", Margin = entryMargin }); + //verticalStack.Add(new Entry { Text = "This should be read only property", IsReadOnly = true, Margin = entryMargin }); + //verticalStack.Add(new Entry { MaxLength = 5, Placeholder = "MaxLength text", Margin = entryMargin }); + //verticalStack.Add(new Entry { Text = "This should be text with character spacing", CharacterSpacing = 10 }); + //verticalStack.Add(new Entry { Keyboard = Keyboard.Numeric, Placeholder = "Numeric Entry" }); + //verticalStack.Add(new Entry { Keyboard = Keyboard.Email, Placeholder = "Email Entry" }); + //verticalStack.Add(new Entry { Placeholder = "This is a blue text box", BackgroundColor = Colors.CornflowerBlue }); + + //verticalStack.Add(CreateSampleCursorSelection()); + + //verticalStack.Add(new GraphicsView { Drawable = new TestDrawable(), HeightRequest = 50, WidthRequest = 200 }); + + //verticalStack.Add(new ProgressBar { Progress = 0.5 }); + //verticalStack.Add(new ProgressBar { Progress = 0.5, BackgroundColor = Colors.LightCoral }); + //verticalStack.Add(new ProgressBar { Progress = 0.5, ProgressColor = Colors.Purple }); + + //verticalStack.Add(new SearchBar { CharacterSpacing = 4, Text = "A search query", TextColor = Colors.Orange }); + //verticalStack.Add(new SearchBar { Placeholder = "Placeholder" }); + //verticalStack.Add(new SearchBar { HorizontalTextAlignment = TextAlignment.End, Text = "SearchBar HorizontalTextAlignment" }); + //verticalStack.Add(new SearchBar { Text = "SearchBar MaxLength", MaxLength = 50 }); + //verticalStack.Add(new SearchBar { Text = "SearchBar CancelButtonColor", CancelButtonColor = Colors.IndianRed }); + + //var monkeyList = new List + //{ + // "Baboon", + // "Capuchin Monkey", + // "Blue Monkey", + // "Squirrel Monkey", + // "Golden Lion Tamarin", + // "Howler Monkey", + // "Japanese Macaque" + //}; + + //var picker = new Picker { Title = "Select a monkey", TitleColor = Colors.Red, FontFamily = "Dokdo", HorizontalTextAlignment = TextAlignment.Center }; + + //picker.ItemsSource = monkeyList; + //verticalStack.Add(picker); + + //verticalStack.Add(new Slider()); + //verticalStack.Add(new Slider { ThumbImageSource = "dotnet_bot.png" }); + + //verticalStack.Add(new Stepper()); + //verticalStack.Add(new Stepper { BackgroundColor = Colors.IndianRed }); + //verticalStack.Add(new Stepper { Minimum = 0, Maximum = 10, Value = 5 }); + + //verticalStack.Add(new Switch()); + //verticalStack.Add(new Switch() { OnColor = Colors.Green }); + //verticalStack.Add(new Switch() { ThumbColor = Colors.Yellow }); + //verticalStack.Add(new Switch() { OnColor = Colors.Green, ThumbColor = Colors.Yellow }); + + //verticalStack.Add(new DatePicker()); + //verticalStack.Add(new DatePicker { TextColor = Colors.OrangeRed }); + //verticalStack.Add(new DatePicker { CharacterSpacing = 6 }); + //verticalStack.Add(new DatePicker { FontSize = 24 }); + + //verticalStack.Add(new TimePicker()); + //verticalStack.Add(new TimePicker { TextColor = Colors.LightGreen }); + //verticalStack.Add(new TimePicker { Time = TimeSpan.FromHours(8), CharacterSpacing = 6 }); + + //verticalStack.Add(new Label { Text = "IMAGES (static | animated):" }); + //verticalStack.Add(CreateImagesGrid()); Content = new ScrollView { @@ -601,6 +602,58 @@ IView CreateShapes() return verticalStack; } + IView CreateAlerts() + { + var simpleAlertButton = new Button { Text ="Simple Alert"}; + + simpleAlertButton.Clicked += async (sender, args) => + { + await DisplayAlert("Alert", "You have been alerted", "OK"); + }; + + var yesNoAlertButton = new Button { Text = "Yes/No Alert" }; + + yesNoAlertButton.Clicked += async (sender, args) => + { + bool answer = await DisplayAlert("Question?", "Would you like to play a game", "Yes", "No"); + Debug.WriteLine("Answer: " + answer); + }; + + var simpleActionSheetButton = new Button { Text = "Simple ActionSheet" }; + + simpleActionSheetButton.Clicked += async (sender, args) => + { + string action = await DisplayActionSheet("ActionSheet: Send to?", "Cancel", null, "Email", "Twitter", "Facebook"); + Debug.WriteLine("Action: " + action); + }; + + var cancelDeleteActionSheetButton = new Button { Text = "Cancel/Delete ActionSheet" }; + + cancelDeleteActionSheetButton.Clicked += async (sender, args) => + { + string action = await DisplayActionSheet("ActionSheet: SavePhoto?", "Cancel", "Delete", "Photo Roll", "Email"); + Debug.WriteLine("Action: " + action); + }; + + var simplePromptButton = new Button { Text = "Simple Prompt" }; + + simplePromptButton.Clicked += async (sender, args) => + { + await DisplayPromptAsync("Question 1", "What's your name?"); + }; + + var verticalStack = new VerticalStackLayout + { + simpleAlertButton, + yesNoAlertButton, + simpleActionSheetButton, + cancelDeleteActionSheetButton, + simplePromptButton + }; + + return verticalStack; + } + void AddTextResizeDemo(Microsoft.Maui.ILayout layout) { var resizeTestButton = new Button { Text = "Resize Test" }; diff --git a/src/Core/src/Platform/Android/PopupManager.cs b/src/Core/src/Platform/Android/AlertManager.cs similarity index 96% rename from src/Core/src/Platform/Android/PopupManager.cs rename to src/Core/src/Platform/Android/AlertManager.cs index b001a96f7c56..b78d867274be 100644 --- a/src/Core/src/Platform/Android/PopupManager.cs +++ b/src/Core/src/Platform/Android/AlertManager.cs @@ -13,9 +13,9 @@ namespace Microsoft.Maui { - internal static class PopupManager + internal static class AlertManager { - static readonly List Subscriptions = new List(); + static readonly List Subscriptions = new List(); internal static void Subscribe(Activity context, MauiContext mauiContext) { @@ -24,17 +24,17 @@ internal static void Subscribe(Activity context, MauiContext mauiContext) return; } - Subscriptions.Add(new PopupRequestHelper(context, mauiContext)); + Subscriptions.Add(new AlertRequestHelper(context, mauiContext)); } internal static void Unsubscribe(Activity context) { var toRemove = Subscriptions.Where(s => s.Activity == context).ToList(); - foreach (PopupRequestHelper popupRequestHelper in toRemove) + foreach (AlertRequestHelper alertRequestHelper in toRemove) { - popupRequestHelper.Dispose(); - Subscriptions.Remove(popupRequestHelper); + alertRequestHelper.Dispose(); + Subscriptions.Remove(alertRequestHelper); } } @@ -43,12 +43,12 @@ internal static void ResetBusyCount(Activity context) Subscriptions.FirstOrDefault(s => s.Activity == context)?.ResetBusyCount(); } - internal sealed class PopupRequestHelper : IDisposable + internal sealed class AlertRequestHelper : IDisposable { int _busyCount; bool? _supportsProgress; - internal PopupRequestHelper(Activity context, MauiContext mauiContext) + internal AlertRequestHelper(Activity context, MauiContext mauiContext) { Activity = context; MauiContext = mauiContext; diff --git a/src/Core/src/Platform/Android/MauiAppCompatActivity.cs b/src/Core/src/Platform/Android/MauiAppCompatActivity.cs index c3052f1da494..d5ecd9a387a4 100644 --- a/src/Core/src/Platform/Android/MauiAppCompatActivity.cs +++ b/src/Core/src/Platform/Android/MauiAppCompatActivity.cs @@ -53,7 +53,7 @@ protected override void OnCreate(Bundle? savedInstanceState) window = mauiApp.CreateWindow(state); } - PopupManager.Subscribe(this, mauiContext); + AlertManager.Subscribe(this, mauiContext); SetContentView(window.View.ToNative(mauiContext)); @@ -72,7 +72,7 @@ protected override void OnDestroy() { base.OnDestroy(); - PopupManager.Unsubscribe(this); + AlertManager.Unsubscribe(this); } } } \ No newline at end of file diff --git a/src/Core/src/Platform/Windows/ActionSheetDialog.cs b/src/Core/src/Platform/Windows/ActionSheetDialog.cs index fe5732546477..714c87d9c305 100644 --- a/src/Core/src/Platform/Windows/ActionSheetDialog.cs +++ b/src/Core/src/Platform/Windows/ActionSheetDialog.cs @@ -1,7 +1,146 @@ -namespace Microsoft.Maui +#nullable disable +using System; +using System.Linq; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; + +namespace Microsoft.Maui { - class ActionSheetDialog + public sealed class ActionSheetContent : UserControl { + ActionSheetArguments _options; + + public event EventHandler OptionSelected; + + public ActionSheetContent(ActionSheetArguments sheetOptions) + { + Initialize(); + + _options = sheetOptions; + + TitleBlock.Text = _options.Title ?? string.Empty; + OptionsList.ItemsSource = _options.Buttons.ToList(); + + if (_options.FlowDirection == Maui.FlowDirection.RightToLeft) + { + TitleBlock.FlowDirection = UI.Xaml.FlowDirection.RightToLeft; + OptionsList.FlowDirection = UI.Xaml.FlowDirection.RightToLeft; + } + else if (_options.FlowDirection == Maui.FlowDirection.LeftToRight) + { + TitleBlock.FlowDirection = UI.Xaml.FlowDirection.LeftToRight; + OptionsList.FlowDirection = UI.Xaml.FlowDirection.LeftToRight; + } + + if (_options.FlowDirection == Maui.FlowDirection.RightToLeft) + { + if (_options.Cancel != null) + { + LeftBtn.Content = _options.Cancel; + if (_options.Destruction != null) + RightBtn.Content = _options.Destruction; + } + else if (_options.Destruction != null) + LeftBtn.Content = _options.Destruction; + } + else + { + if (_options.Cancel != null) + { + RightBtn.Content = _options.Cancel; + if (_options.Destruction != null) + LeftBtn.Content = _options.Destruction; + } + else if (_options.Destruction != null) + RightBtn.Content = _options.Destruction; + } + + LeftBtn.Visibility = LeftBtn.Content == null ? UI.Xaml.Visibility.Collapsed : UI.Xaml.Visibility.Visible; + RightBtn.Visibility = RightBtn.Content == null ? UI.Xaml.Visibility.Collapsed : UI.Xaml.Visibility.Visible; + } + + internal TextBlock TitleBlock { get; private set; } + + internal ListView OptionsList { get; private set; } + + internal Button LeftBtn { get; private set; } + + internal Button RightBtn { get; private set; } + + void Initialize() + { + var mainLayout = new Grid + { + Padding = new UI.Xaml.Thickness(10), + RowDefinitions = + { + new RowDefinition { Height = new UI.Xaml.GridLength(0, UI.Xaml.GridUnitType.Star) }, + new RowDefinition { Height = new UI.Xaml.GridLength(0, UI.Xaml.GridUnitType.Auto) } + } + }; + + var firstLayout = new Grid + { + RowDefinitions = + { + new RowDefinition { Height = new UI.Xaml.GridLength(0, UI.Xaml.GridUnitType.Auto) }, + new RowDefinition { Height = new UI.Xaml.GridLength(0, UI.Xaml.GridUnitType.Star) } + } + }; + + TitleBlock = new TextBlock { FontSize = 18, MaxLines = 2 }; + firstLayout.Children.Add(TitleBlock); + Grid.SetRow(TitleBlock, 0); + + OptionsList = new ListView { IsItemClickEnabled = true, Margin = new UI.Xaml.Thickness(0, 10, 0, 10), SelectionMode = ListViewSelectionMode.None }; + OptionsList.ItemClick += ListItemSelected; + firstLayout.Children.Add(OptionsList); + Grid.SetRow(OptionsList, 1); + + var secondLayout = new Grid + { + ColumnDefinitions = + { + new ColumnDefinition { Width = new UI.Xaml.GridLength(0, UI.Xaml.GridUnitType.Star) }, + new ColumnDefinition { Width = new UI.Xaml.GridLength(0, UI.Xaml.GridUnitType.Star) } + }, + VerticalAlignment = VerticalAlignment.Bottom + }; + + LeftBtn = new Button { Height = 32, HorizontalAlignment = HorizontalAlignment.Stretch, Margin = new UI.Xaml.Thickness(0, 0, 5, 0) }; + LeftBtn.Click += ActionButtonClicked; + secondLayout.Children.Add(LeftBtn); + Grid.SetColumn(LeftBtn, 0); + + RightBtn = new Button { Height = 32, HorizontalAlignment = HorizontalAlignment.Stretch, Margin = new UI.Xaml.Thickness(5, 0, 0, 0) }; + RightBtn.Click += ActionButtonClicked; + secondLayout.Children.Add(RightBtn); + Grid.SetColumn(RightBtn, 1); + + mainLayout.Children.Add(firstLayout); + Grid.SetRow(firstLayout, 0); + + mainLayout.Children.Add(secondLayout); + Grid.SetRow(secondLayout, 1); + + Content = mainLayout; + } + + void ListItemSelected(object sender, ItemClickEventArgs e) + { + var selection = (string)e.ClickedItem; + _options.SetResult(selection); + + OptionSelected?.Invoke(this, null); + } + + void ActionButtonClicked(object sender, RoutedEventArgs e) + { + var button = (Button)sender; + var selection = (string)button.Content; + _options.SetResult(selection); + OptionSelected?.Invoke(this, null); + } } } \ No newline at end of file diff --git a/src/Core/src/Platform/Windows/AlertDialog.cs b/src/Core/src/Platform/Windows/AlertDialog.cs index e318c673cb6a..f3552ee1c2fc 100644 --- a/src/Core/src/Platform/Windows/AlertDialog.cs +++ b/src/Core/src/Platform/Windows/AlertDialog.cs @@ -1,7 +1,21 @@ -namespace Microsoft.Maui +using Microsoft.UI.Xaml.Controls; + +namespace Microsoft.Maui { - class AlertDialog + public sealed class AlertDialog : ContentDialog { + public ScrollBarVisibility VerticalScrollBarVisibility { get; set; } + + protected override void OnApplyTemplate() + { + base.OnApplyTemplate(); + + // The child template name is derived from the default style + // https://msdn.microsoft.com/en-us/library/windows/apps/mt299120.aspx + var scrollName = "ContentScrollViewer"; + if (GetTemplateChild(scrollName) is ScrollViewer contentScrollViewer) + contentScrollViewer.VerticalScrollBarVisibility = VerticalScrollBarVisibility; + } } } \ No newline at end of file diff --git a/src/Core/src/Platform/Windows/PopupManager.cs b/src/Core/src/Platform/Windows/AlertManager.cs similarity index 52% rename from src/Core/src/Platform/Windows/PopupManager.cs rename to src/Core/src/Platform/Windows/AlertManager.cs index 4a80ad0bbecd..321513a92d5e 100644 --- a/src/Core/src/Platform/Windows/PopupManager.cs +++ b/src/Core/src/Platform/Windows/AlertManager.cs @@ -8,9 +8,9 @@ namespace Microsoft.Maui { - internal static class PopupManager + internal static class AlertManager { - static readonly List Subscriptions = new List(); + static readonly List Subscriptions = new List(); internal static void Subscribe(Application application, MauiContext mauiContext) { @@ -19,25 +19,26 @@ internal static void Subscribe(Application application, MauiContext mauiContext) return; } - Subscriptions.Add(new PopupRequestHelper(application, mauiContext)); + Subscriptions.Add(new AlertRequestHelper(application, mauiContext)); } internal static void Unsubscribe(Application application) { var toRemove = Subscriptions.Where(s => s.Application == application).ToList(); - foreach (PopupRequestHelper popupRequestHelper in toRemove) + foreach (AlertRequestHelper alertRequestHelper in toRemove) { - popupRequestHelper.Dispose(); - Subscriptions.Remove(popupRequestHelper); + alertRequestHelper.Dispose(); + Subscriptions.Remove(alertRequestHelper); } } - internal sealed class PopupRequestHelper : IDisposable + internal sealed class AlertRequestHelper : IDisposable { static Task CurrentAlert; + static Task CurrentPrompt; - internal PopupRequestHelper(Application application, MauiContext mauiContext) + internal AlertRequestHelper(Application application, MauiContext mauiContext) { Application = application; MauiContext = mauiContext; @@ -61,7 +62,7 @@ public void Dispose() void OnPageBusy(IPage sender, bool enabled) { - + // TODO: Wrap the pages in a Canvas, and dynamically add a ProgressBar } async void OnAlertRequested(IPage sender, AlertArguments arguments) @@ -69,10 +70,11 @@ async void OnAlertRequested(IPage sender, AlertArguments arguments) string content = arguments.Message ?? string.Empty; string title = arguments.Title ?? string.Empty; - var alertDialog = new ContentDialog + var alertDialog = new AlertDialog { Content = content, - Title = title + Title = title, + VerticalScrollBarVisibility = ScrollBarVisibility.Auto }; if (arguments.FlowDirection == FlowDirection.RightToLeft) @@ -109,15 +111,82 @@ async void OnAlertRequested(IPage sender, AlertArguments arguments) CurrentAlert = null; } - void OnPromptRequested(IPage sender, PromptArguments arguments) + async void OnPromptRequested(IPage sender, PromptArguments arguments) { + var promptDialog = new PromptDialog + { + Title = arguments.Title ?? string.Empty, + Message = arguments.Message ?? string.Empty, + Input = arguments.InitialValue ?? string.Empty, + Placeholder = arguments.Placeholder ?? string.Empty, + MaxLength = arguments.MaxLength >= 0 ? arguments.MaxLength : 0, + // TODO: Implement InputScope property after port the keyboardExtensions + }; + + if (arguments.Cancel != null) + promptDialog.SecondaryButtonText = arguments.Cancel; + if (arguments.Accept != null) + promptDialog.PrimaryButtonText = arguments.Accept; + + var currentAlert = CurrentPrompt; + while (currentAlert != null) + { + await currentAlert; + currentAlert = CurrentPrompt; + } + + // This is a temporary workaround + var nativePage = sender.ToNative(MauiContext); + promptDialog.XamlRoot = nativePage.XamlRoot; + + CurrentPrompt = ShowPrompt(promptDialog); + arguments.SetResult(await CurrentPrompt.ConfigureAwait(false)); + CurrentPrompt = null; } void OnActionSheetRequested(IPage sender, ActionSheetArguments arguments) { + bool userDidSelect = false; + if (arguments.FlowDirection == FlowDirection.MatchParent) + { + // TODO: Check EffectiveFlowDirection + } + + var actionSheetContent = new ActionSheetContent(arguments); + + var actionSheet = new Flyout + { + Placement = UI.Xaml.Controls.Primitives.FlyoutPlacementMode.Full, + Content = actionSheetContent + }; + + actionSheetContent.OptionSelected += (s, e) => + { + userDidSelect = true; + actionSheet.Hide(); + }; + + actionSheet.Closed += (s, e) => + { + if (!userDidSelect) + arguments.SetResult(null); + }; + + try + { + var pageParent = sender.ToNative(MauiContext).Parent as FrameworkElement; + + if (pageParent != null) + actionSheet.ShowAt(pageParent); + } + catch (ArgumentException) // If the page is not in the visual tree + { + if (Window.Current.Content is FrameworkElement mainPage) + actionSheet.ShowAt(mainPage); + } } static async Task ShowAlert(ContentDialog alert) @@ -126,6 +195,16 @@ static async Task ShowAlert(ContentDialog alert) return result == ContentDialogResult.Primary; } + + static async Task ShowPrompt(PromptDialog prompt) + { + ContentDialogResult result = await prompt.ShowAsync(); + + if (result == ContentDialogResult.Primary) + return prompt.Input; + + return null; + } } } } \ No newline at end of file diff --git a/src/Core/src/Platform/Windows/MauiWinUIApplication.cs b/src/Core/src/Platform/Windows/MauiWinUIApplication.cs index fc92427ca50b..4fa7d10bfe8f 100644 --- a/src/Core/src/Platform/Windows/MauiWinUIApplication.cs +++ b/src/Core/src/Platform/Windows/MauiWinUIApplication.cs @@ -4,7 +4,6 @@ using Microsoft.Maui.Hosting; using Microsoft.Maui.LifecycleEvents; using Microsoft.UI.Xaml.Controls; -using Windows.UI.Core.Preview; namespace Microsoft.Maui { @@ -45,7 +44,7 @@ protected override void OnLaunched(UI.Xaml.LaunchActivatedEventArgs args) MainWindow.Content = canvas; - PopupManager.Subscribe(this, mauiContext); + AlertManager.Subscribe(this, mauiContext); Current.Services?.InvokeLifecycleEvents(del => del(this, args)); @@ -66,16 +65,9 @@ protected override void OnLaunched(UI.Xaml.LaunchActivatedEventArgs args) nativeContent.Height = canvas.ActualHeight; }; - //SystemNavigationManagerPreview.GetForCurrentView().CloseRequested += OnCloseRequested; - MainWindow.Activate(); } - void OnCloseRequested(object? sender, SystemNavigationCloseRequestedPreviewEventArgs e) - { - PopupManager.Unsubscribe(this); - } - Canvas CreateRootContainer() { // TODO WINUI should this be some other known constant or via some mechanism? Or done differently? diff --git a/src/Core/src/Platform/Windows/PromptDialog.cs b/src/Core/src/Platform/Windows/PromptDialog.cs index 36356e1ba082..d221fe1be5e6 100644 --- a/src/Core/src/Platform/Windows/PromptDialog.cs +++ b/src/Core/src/Platform/Windows/PromptDialog.cs @@ -1,7 +1,64 @@ -namespace Microsoft.Maui +#nullable disable +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Input; + +namespace Microsoft.Maui { - class PromptDialog + public sealed class PromptDialog : ContentDialog { + public PromptDialog() + { + Title = "TITLE"; + PrimaryButtonText = "Ok"; + SecondaryButtonText = "Cancel"; + + Initialize(); + } + + internal TextBlock TextBlockMessage { get; private set; } + internal TextBox TextBoxInput { get; private set; } + + public string Message + { + get => TextBlockMessage.Text; + set => TextBlockMessage.Text = value; + } + + public string Input + { + get => TextBoxInput.Text; + set => TextBoxInput.Text = value; + } + + public string Placeholder + { + get => TextBoxInput.PlaceholderText; + set => TextBoxInput.PlaceholderText = value; + } + + public int MaxLength + { + get => TextBoxInput.MaxLength; + set => TextBoxInput.MaxLength = value; + } + + public InputScope InputScope + { + get => TextBoxInput.InputScope; + set => TextBoxInput.InputScope = value; + } + + void Initialize() + { + var layout = new StackPanel(); + + TextBlockMessage = new TextBlock { Text = "Message", TextWrapping = UI.Xaml.TextWrapping.Wrap }; + TextBoxInput = new TextBox(); + + layout.Children.Add(TextBlockMessage); + layout.Children.Add(TextBoxInput); + Content = layout; + } } } \ No newline at end of file diff --git a/src/Core/src/Platform/iOS/PopupManager.cs b/src/Core/src/Platform/iOS/AlertManager.cs similarity index 94% rename from src/Core/src/Platform/iOS/PopupManager.cs rename to src/Core/src/Platform/iOS/AlertManager.cs index 1b6bda71d3fd..b5c75136b5fb 100644 --- a/src/Core/src/Platform/iOS/PopupManager.cs +++ b/src/Core/src/Platform/iOS/AlertManager.cs @@ -9,9 +9,9 @@ namespace Microsoft.Maui { - internal static class PopupManager + internal static class AlertManager { - static readonly List Subscriptions = new List(); + static readonly List Subscriptions = new List(); internal static void Subscribe(UIApplication application) { @@ -20,26 +20,27 @@ internal static void Subscribe(UIApplication application) return; } - Subscriptions.Add(new PopupRequestHelper(application)); + Subscriptions.Add(new AlertRequestHelper(application)); } internal static void Unsubscribe(UIApplication context) { var toRemove = Subscriptions.Where(s => s.Application == context).ToList(); - foreach (PopupRequestHelper popupRequestHelper in toRemove) + foreach (AlertRequestHelper alertRequestHelper in toRemove) { - popupRequestHelper.Dispose(); - Subscriptions.Remove(popupRequestHelper); + alertRequestHelper.Dispose(); + Subscriptions.Remove(alertRequestHelper); } } - internal sealed class PopupRequestHelper : IDisposable + + internal sealed class AlertRequestHelper : IDisposable { const float AlertPadding = 10.0f; int _busyCount; - internal PopupRequestHelper(UIApplication application) + internal AlertRequestHelper(UIApplication application) { Application = application; diff --git a/src/Core/src/Platform/iOS/MauiUIApplicationDelegate.cs b/src/Core/src/Platform/iOS/MauiUIApplicationDelegate.cs index 2df863544f05..d23c625d81f6 100644 --- a/src/Core/src/Platform/iOS/MauiUIApplicationDelegate.cs +++ b/src/Core/src/Platform/iOS/MauiUIApplicationDelegate.cs @@ -33,7 +33,7 @@ public override bool FinishedLaunching(UIApplication application, NSDictionary l { Application = Services.GetRequiredService(); - PopupManager.Subscribe(application); + AlertManager.Subscribe(application); var mauiContext = new MauiContext(Services); @@ -95,7 +95,7 @@ public override void OnResignActivation(UIApplication application) public override void WillTerminate(UIApplication application) { - PopupManager.Unsubscribe(application); + AlertManager.Unsubscribe(application); Current.Services?.InvokeLifecycleEvents(del => del(application)); } diff --git a/src/Core/src/Primitives/Alert.cs b/src/Core/src/Primitives/AlertConstants.cs similarity index 100% rename from src/Core/src/Primitives/Alert.cs rename to src/Core/src/Primitives/AlertConstants.cs From 35e419b98ad19d39d787fefede062452abf3b9c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Su=C3=A1rez?= Date: Wed, 16 Jun 2021 11:28:37 +0200 Subject: [PATCH 03/17] Updated sample --- src/Controls/samples/Controls.Sample/Pages/MainPage.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Controls/samples/Controls.Sample/Pages/MainPage.cs b/src/Controls/samples/Controls.Sample/Pages/MainPage.cs index 722725f3f6fd..26e28f0b1478 100644 --- a/src/Controls/samples/Controls.Sample/Pages/MainPage.cs +++ b/src/Controls/samples/Controls.Sample/Pages/MainPage.cs @@ -639,7 +639,8 @@ IView CreateAlerts() simplePromptButton.Clicked += async (sender, args) => { - await DisplayPromptAsync("Question 1", "What's your name?"); + string action = await DisplayPromptAsync("Question 1", "What's your name?"); + Debug.WriteLine("Action: " + action); }; var verticalStack = new VerticalStackLayout From de1c912fa3d7a30f3cc813f967d73038c54c3ab5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Su=C3=A1rez?= Date: Wed, 16 Jun 2021 11:42:47 +0200 Subject: [PATCH 04/17] Updated sample --- .../samples/Controls.Sample/Pages/MainPage.cs | 449 +++++++++--------- 1 file changed, 225 insertions(+), 224 deletions(-) diff --git a/src/Controls/samples/Controls.Sample/Pages/MainPage.cs b/src/Controls/samples/Controls.Sample/Pages/MainPage.cs index 26e28f0b1478..f6e5d0718ce8 100644 --- a/src/Controls/samples/Controls.Sample/Pages/MainPage.cs +++ b/src/Controls/samples/Controls.Sample/Pages/MainPage.cs @@ -72,232 +72,233 @@ Visibility IFrameworkElement.Visibility void SetupMauiLayout() { var verticalStack = new VerticalStackLayout() { Spacing = 5, BackgroundColor = Colors.AntiqueWhite }; - //var horizontalStack = new HorizontalStackLayout() { Spacing = 2, BackgroundColor = Colors.CornflowerBlue }; + var horizontalStack = new HorizontalStackLayout() { Spacing = 2, BackgroundColor = Colors.CornflowerBlue }; //verticalStack.Add(CreateSampleGrid()); - //verticalStack.Add(CreateResizingButton()); + verticalStack.Add(CreateResizingButton()); - //AddTextResizeDemo(verticalStack); - //verticalStack.Add(CreateTransformations()); - //verticalStack.Add(CreateAnimations()); - //verticalStack.Add(CreateShapes()); + AddTextResizeDemo(verticalStack); + verticalStack.Add(CreateTransformations()); + verticalStack.Add(CreateAnimations()); + verticalStack.Add(CreateShapes()); verticalStack.Add(CreateAlerts()); - //verticalStack.Add(new Label { Text = " ", Padding = new Thickness(10) }); - //var label = new Label { Text = "End-aligned text", BackgroundColor = Colors.Fuchsia, HorizontalTextAlignment = TextAlignment.End }; - //label.Margin = new Thickness(15, 10, 20, 15); - - //SemanticProperties.SetHint(label, "Hint Text"); - //SemanticProperties.SetDescription(label, "Description Text"); - - //verticalStack.Add(label); - //verticalStack.Add(new Label { Text = "This should be BIG text!", FontSize = 24, HorizontalOptions = LayoutOptions.End }); - - //SemanticProperties.SetHeadingLevel((BindableObject)verticalStack.Children.Last(), SemanticHeadingLevel.Level1); - //verticalStack.Add(new Label { Text = "This should be BOLD text!", FontAttributes = FontAttributes.Bold, HorizontalOptions = LayoutOptions.Center }); - //verticalStack.Add(new Label { Text = "This should have character spacing!", CharacterSpacing = 3 }); - //verticalStack.Add(new Label { Text = "This should be a CUSTOM font!", FontFamily = "Dokdo" }); - //verticalStack.Add( - // new Button - // { - // Text = "Push a Page", - // Rotation = 15, - // Scale = 1.5, - // Command = new Command(async () => - // { - // await Navigation.PushAsync(new SemanticsPage()); - // }) - // } - //); - - //verticalStack.Add(new Label { Text = "This should have padding", Padding = new Thickness(40), BackgroundColor = Colors.LightBlue }); - //verticalStack.Add(new Label { Text = LoremIpsum }); - //verticalStack.Add(new Label { Text = LoremIpsum, MaxLines = 2 }); - //verticalStack.Add(new Label { Text = LoremIpsum, LineBreakMode = LineBreakMode.TailTruncation }); - //verticalStack.Add(new Label { Text = LoremIpsum, MaxLines = 2, LineBreakMode = LineBreakMode.TailTruncation }); - //verticalStack.Add(new Label { Text = "This should have five times the line height! " + LoremIpsum, LineHeight = 5, MaxLines = 2 }); - //verticalStack.Add(new Label - //{ - // FontSize = 24, - // Text = "LinearGradient Text", - // Background = new LinearGradientBrush( - // new GradientStopCollection - // { - // new GradientStop(Colors.Green, 0), - // new GradientStop(Colors.Blue, 1) - // }, - // new Point(0, 0), - // new Point(1, 0)) - //}); - //verticalStack.Add(new Label - //{ - // Text = "RadialGradient", - // Padding = new Thickness(30), - // Background = new RadialGradientBrush( - // new GradientStopCollection - // { - // new GradientStop(Colors.DarkBlue, 0), - // new GradientStop(Colors.Yellow, 0.6f), - // new GradientStop(Colors.LightPink, 1) - // }, - // new Point(0.5, 0.5), - // 0.3f) - //}); - - //SemanticProperties.SetHeadingLevel((BindableObject)verticalStack.Children.Last(), SemanticHeadingLevel.Level2); - - //var visibleClearButtonEntry = new Entry() { ClearButtonVisibility = ClearButtonVisibility.WhileEditing, Placeholder = "This Entry will show clear button if has input." }; - //var hiddenClearButtonEntry = new Entry() { ClearButtonVisibility = ClearButtonVisibility.Never, Placeholder = "This Entry will not..." }; - - //verticalStack.Add(visibleClearButtonEntry); - //verticalStack.Add(hiddenClearButtonEntry); - - //verticalStack.Add(new Editor { Text = "Editor TextColor", TextColor = Colors.Olive }); - //verticalStack.Add(new Editor { Text = "Editor using CharacterSpacing", CharacterSpacing = 10 }); - //verticalStack.Add(new Editor { Placeholder = "This is an editor placeholder." }); - //verticalStack.Add(new Editor { Placeholder = "Editor PlaceholderColor", PlaceholderColor = Colors.Green }); - - //var paddingButton = new Button - //{ - // Padding = new Thickness(40), - // Text = "This button has a padding!!", - // BackgroundColor = Colors.Purple, - //}; - - //verticalStack.Add(paddingButton); - - //var underlineLabel = new Label { Text = "underline", TextDecorations = TextDecorations.Underline }; - //verticalStack.Add(underlineLabel); - - //verticalStack.Add(new ActivityIndicator()); - //verticalStack.Add(new ActivityIndicator { Color = Colors.Red, IsRunning = true }); - - //var button = new Button() { Text = _viewModel.Text, WidthRequest = 200 }; - //button.Clicked += async (sender, e) => - //{ - // var events = _services.GetRequiredService(); - // events.InvokeEvents>("CustomEventName", action => action("VALUE")); - - // var location = await Geolocation.GetLocationAsync(new GeolocationRequest(GeolocationAccuracy.Lowest)); - // Debug.WriteLine($"I tracked you down to {location.Latitude}, {location.Longitude}! You can't hide!"); - //}; - - //var button2 = new Button() - //{ - // TextColor = Colors.Green, - // Text = "Hello I'm a button", - // BackgroundColor = Color.Purple, - // Margin = new Thickness(12) - //}; - - //horizontalStack.Add(button); - //horizontalStack.Add(button2); - - //horizontalStack.Add(new Label { Text = "And these buttons are in a HorizontalStackLayout", VerticalOptions = LayoutOptions.Center }); - - //verticalStack.Add(horizontalStack); - - //verticalStack.Add(new Button { Text = "CharacterSpacing" }); - //verticalStack.Add(new Button { CharacterSpacing = 8, Text = "CharacterSpacing" }); - - //verticalStack.Add(new RedButton { Text = "Dynamically Registered" }); - //verticalStack.Add(new CustomButton { Text = "Button Registered to Compat Renderer" }); - - //var checkbox = new CheckBox(); - //checkbox.CheckedChanged += (sender, e) => - //{ - // Debug.WriteLine($"Checked Changed to '{e.Value}'"); - //}; - //verticalStack.Add(checkbox); - //verticalStack.Add(new CheckBox { BackgroundColor = Colors.LightPink }); - //verticalStack.Add(new CheckBox { IsChecked = true, Color = Colors.Aquamarine }); - - //var editor = new Editor(); - //editor.Completed += (sender, args) => - //{ - // Debug.WriteLine($"Editor Completed"); - //}; - - //verticalStack.Add(editor); - //verticalStack.Add(new Editor { Text = "Editor" }); - //verticalStack.Add(new Editor { Text = "Lorem ipsum dolor sit amet", MaxLength = 10 }); - //verticalStack.Add(new Editor { Text = "Predictive Text Off", IsTextPredictionEnabled = false }); - //verticalStack.Add(new Editor { Text = "Lorem ipsum dolor sit amet", FontSize = 10, FontFamily = "Dokdo" }); - //verticalStack.Add(new Editor { Text = "ReadOnly Editor", IsReadOnly = true }); - - //var entry = new Entry(); - //entry.TextChanged += (sender, e) => - //{ - // Debug.WriteLine($"Text Changed from '{e.OldTextValue}' to '{e.NewTextValue}'"); - //}; - - //var entryMargin = new Thickness(10, 0); - - //verticalStack.Add(entry); - //verticalStack.Add(new Entry { Text = "Entry with custom Font", TextColor = Colors.DarkRed, FontFamily = "Dokdo", MaxLength = -1, Margin = entryMargin }); - //verticalStack.Add(new Entry { IsPassword = true, TextColor = Colors.Black, Placeholder = "Pasword Entry", Margin = entryMargin }); - //verticalStack.Add(new Entry { IsTextPredictionEnabled = false }); - //verticalStack.Add(new Entry { Placeholder = "This should be placeholder text", Margin = entryMargin }); - //verticalStack.Add(new Entry { Text = "This should be read only property", IsReadOnly = true, Margin = entryMargin }); - //verticalStack.Add(new Entry { MaxLength = 5, Placeholder = "MaxLength text", Margin = entryMargin }); - //verticalStack.Add(new Entry { Text = "This should be text with character spacing", CharacterSpacing = 10 }); - //verticalStack.Add(new Entry { Keyboard = Keyboard.Numeric, Placeholder = "Numeric Entry" }); - //verticalStack.Add(new Entry { Keyboard = Keyboard.Email, Placeholder = "Email Entry" }); - //verticalStack.Add(new Entry { Placeholder = "This is a blue text box", BackgroundColor = Colors.CornflowerBlue }); - - //verticalStack.Add(CreateSampleCursorSelection()); - - //verticalStack.Add(new GraphicsView { Drawable = new TestDrawable(), HeightRequest = 50, WidthRequest = 200 }); - - //verticalStack.Add(new ProgressBar { Progress = 0.5 }); - //verticalStack.Add(new ProgressBar { Progress = 0.5, BackgroundColor = Colors.LightCoral }); - //verticalStack.Add(new ProgressBar { Progress = 0.5, ProgressColor = Colors.Purple }); - - //verticalStack.Add(new SearchBar { CharacterSpacing = 4, Text = "A search query", TextColor = Colors.Orange }); - //verticalStack.Add(new SearchBar { Placeholder = "Placeholder" }); - //verticalStack.Add(new SearchBar { HorizontalTextAlignment = TextAlignment.End, Text = "SearchBar HorizontalTextAlignment" }); - //verticalStack.Add(new SearchBar { Text = "SearchBar MaxLength", MaxLength = 50 }); - //verticalStack.Add(new SearchBar { Text = "SearchBar CancelButtonColor", CancelButtonColor = Colors.IndianRed }); - - //var monkeyList = new List - //{ - // "Baboon", - // "Capuchin Monkey", - // "Blue Monkey", - // "Squirrel Monkey", - // "Golden Lion Tamarin", - // "Howler Monkey", - // "Japanese Macaque" - //}; - - //var picker = new Picker { Title = "Select a monkey", TitleColor = Colors.Red, FontFamily = "Dokdo", HorizontalTextAlignment = TextAlignment.Center }; - - //picker.ItemsSource = monkeyList; - //verticalStack.Add(picker); - - //verticalStack.Add(new Slider()); - //verticalStack.Add(new Slider { ThumbImageSource = "dotnet_bot.png" }); - - //verticalStack.Add(new Stepper()); - //verticalStack.Add(new Stepper { BackgroundColor = Colors.IndianRed }); - //verticalStack.Add(new Stepper { Minimum = 0, Maximum = 10, Value = 5 }); - - //verticalStack.Add(new Switch()); - //verticalStack.Add(new Switch() { OnColor = Colors.Green }); - //verticalStack.Add(new Switch() { ThumbColor = Colors.Yellow }); - //verticalStack.Add(new Switch() { OnColor = Colors.Green, ThumbColor = Colors.Yellow }); - - //verticalStack.Add(new DatePicker()); - //verticalStack.Add(new DatePicker { TextColor = Colors.OrangeRed }); - //verticalStack.Add(new DatePicker { CharacterSpacing = 6 }); - //verticalStack.Add(new DatePicker { FontSize = 24 }); - - //verticalStack.Add(new TimePicker()); - //verticalStack.Add(new TimePicker { TextColor = Colors.LightGreen }); - //verticalStack.Add(new TimePicker { Time = TimeSpan.FromHours(8), CharacterSpacing = 6 }); - - //verticalStack.Add(new Label { Text = "IMAGES (static | animated):" }); - //verticalStack.Add(CreateImagesGrid()); + verticalStack.Add(new Label { Text = " ", Padding = new Thickness(10) }); + var label = new Label { Text = "End-aligned text", BackgroundColor = Colors.Fuchsia, HorizontalTextAlignment = TextAlignment.End }; + label.Margin = new Thickness(15, 10, 20, 15); + + SemanticProperties.SetHint(label, "Hint Text"); + SemanticProperties.SetDescription(label, "Description Text"); + + verticalStack.Add(label); + verticalStack.Add(new Label { Text = "This should be BIG text!", FontSize = 24, HorizontalOptions = LayoutOptions.End }); + + SemanticProperties.SetHeadingLevel((BindableObject)verticalStack.Children.Last(), SemanticHeadingLevel.Level1); + verticalStack.Add(new Label { Text = "This should be BOLD text!", FontAttributes = FontAttributes.Bold, HorizontalOptions = LayoutOptions.Center }); + verticalStack.Add(new Label { Text = "This should have character spacing!", CharacterSpacing = 3 }); + verticalStack.Add(new Label { Text = "This should be a CUSTOM font!", FontFamily = "Dokdo" }); + verticalStack.Add( + new Button + { + Text = "Push a Page", + Rotation = 15, + Scale = 1.5, + Command = new Command(async () => + { + await Navigation.PushAsync(new SemanticsPage()); + }) + } + ); + + verticalStack.Add(new Label { Text = "This should have padding", Padding = new Thickness(40), BackgroundColor = Colors.LightBlue }); + verticalStack.Add(new Label { Text = LoremIpsum }); + verticalStack.Add(new Label { Text = LoremIpsum, MaxLines = 2 }); + verticalStack.Add(new Label { Text = LoremIpsum, LineBreakMode = LineBreakMode.TailTruncation }); + verticalStack.Add(new Label { Text = LoremIpsum, MaxLines = 2, LineBreakMode = LineBreakMode.TailTruncation }); + verticalStack.Add(new Label { Text = "This should have five times the line height! " + LoremIpsum, LineHeight = 5, MaxLines = 2 }); + verticalStack.Add(new Label + { + FontSize = 24, + Text = "LinearGradient Text", + Background = new LinearGradientBrush( + new GradientStopCollection + { + new GradientStop(Colors.Green, 0), + new GradientStop(Colors.Blue, 1) + }, + new Point(0, 0), + new Point(1, 0)) + }); + verticalStack.Add(new Label + { + Text = "RadialGradient", + Padding = new Thickness(30), + Background = new RadialGradientBrush( + new GradientStopCollection + { + new GradientStop(Colors.DarkBlue, 0), + new GradientStop(Colors.Yellow, 0.6f), + new GradientStop(Colors.LightPink, 1) + }, + new Point(0.5, 0.5), + 0.3f) + }); + + SemanticProperties.SetHeadingLevel((BindableObject)verticalStack.Children.Last(), SemanticHeadingLevel.Level2); + + var visibleClearButtonEntry = new Entry() { ClearButtonVisibility = ClearButtonVisibility.WhileEditing, Placeholder = "This Entry will show clear button if has input." }; + var hiddenClearButtonEntry = new Entry() { ClearButtonVisibility = ClearButtonVisibility.Never, Placeholder = "This Entry will not..." }; + + verticalStack.Add(visibleClearButtonEntry); + verticalStack.Add(hiddenClearButtonEntry); + + verticalStack.Add(new Editor { Text = "Editor TextColor", TextColor = Colors.Olive }); + verticalStack.Add(new Editor { Text = "Editor using CharacterSpacing", CharacterSpacing = 10 }); + verticalStack.Add(new Editor { Placeholder = "This is an editor placeholder." }); + verticalStack.Add(new Editor { Placeholder = "Editor PlaceholderColor", PlaceholderColor = Colors.Green }); + + var paddingButton = new Button + { + Padding = new Thickness(40), + Text = "This button has a padding!!", + BackgroundColor = Colors.Purple, + }; + + verticalStack.Add(paddingButton); + + var underlineLabel = new Label { Text = "underline", TextDecorations = TextDecorations.Underline }; + verticalStack.Add(underlineLabel); + + verticalStack.Add(new ActivityIndicator()); + verticalStack.Add(new ActivityIndicator { Color = Colors.Red, IsRunning = true }); + + var button = new Button() { Text = _viewModel.Text, WidthRequest = 200 }; + button.Clicked += async (sender, e) => + { + var events = _services.GetRequiredService(); + events.InvokeEvents>("CustomEventName", action => action("VALUE")); + + var location = await Geolocation.GetLocationAsync(new GeolocationRequest(GeolocationAccuracy.Lowest)); + Debug.WriteLine($"I tracked you down to {location.Latitude}, {location.Longitude}! You can't hide!"); + }; + + var button2 = new Button() + { + TextColor = Colors.Green, + Text = "Hello I'm a button", + // BackgroundColor = Color.Purple, + Margin = new Thickness(12) + }; + + horizontalStack.Add(button); + horizontalStack.Add(button2); + + horizontalStack.Add(new Label { Text = "And these buttons are in a HorizontalStackLayout", VerticalOptions = LayoutOptions.Center }); + + verticalStack.Add(horizontalStack); + + verticalStack.Add(new Button { Text = "CharacterSpacing" }); + verticalStack.Add(new Button { CharacterSpacing = 8, Text = "CharacterSpacing" }); + + verticalStack.Add(new RedButton { Text = "Dynamically Registered" }); + verticalStack.Add(new CustomButton { Text = "Button Registered to Compat Renderer" }); + + var checkbox = new CheckBox(); + checkbox.CheckedChanged += (sender, e) => + { + Debug.WriteLine($"Checked Changed to '{e.Value}'"); + }; + verticalStack.Add(checkbox); + verticalStack.Add(new CheckBox { BackgroundColor = Colors.LightPink }); + verticalStack.Add(new CheckBox { IsChecked = true, Color = Colors.Aquamarine }); + + var editor = new Editor(); + editor.Completed += (sender, args) => + { + Debug.WriteLine($"Editor Completed"); + }; + + verticalStack.Add(editor); + verticalStack.Add(new Editor { Text = "Editor" }); + verticalStack.Add(new Editor { Text = "Lorem ipsum dolor sit amet", MaxLength = 10 }); + verticalStack.Add(new Editor { Text = "Predictive Text Off", IsTextPredictionEnabled = false }); + verticalStack.Add(new Editor { Text = "Lorem ipsum dolor sit amet", FontSize = 10, FontFamily = "Dokdo" }); + verticalStack.Add(new Editor { Text = "ReadOnly Editor", IsReadOnly = true }); + + var entry = new Entry(); + entry.TextChanged += (sender, e) => + { + Debug.WriteLine($"Text Changed from '{e.OldTextValue}' to '{e.NewTextValue}'"); + }; + + var entryMargin = new Thickness(10, 0); + + verticalStack.Add(entry); + verticalStack.Add(new Entry { Text = "Entry with custom Font", TextColor = Colors.DarkRed, FontFamily = "Dokdo", MaxLength = -1, Margin = entryMargin }); + verticalStack.Add(new Entry { IsPassword = true, TextColor = Colors.Black, Placeholder = "Pasword Entry", Margin = entryMargin }); + verticalStack.Add(new Entry { IsTextPredictionEnabled = false }); + verticalStack.Add(new Entry { Placeholder = "This should be placeholder text", Margin = entryMargin }); + verticalStack.Add(new Entry { Text = "This should be read only property", IsReadOnly = true, Margin = entryMargin }); + verticalStack.Add(new Entry { MaxLength = 5, Placeholder = "MaxLength text", Margin = entryMargin }); + verticalStack.Add(new Entry { Text = "This should be text with character spacing", CharacterSpacing = 10 }); + verticalStack.Add(new Entry { Keyboard = Keyboard.Numeric, Placeholder = "Numeric Entry" }); + verticalStack.Add(new Entry { Keyboard = Keyboard.Email, Placeholder = "Email Entry" }); + verticalStack.Add(new Entry { Placeholder = "This is a blue text box", BackgroundColor = Colors.CornflowerBlue }); + + verticalStack.Add(CreateSampleCursorSelection()); + + verticalStack.Add(new GraphicsView { Drawable = new TestDrawable(), HeightRequest = 50, WidthRequest = 200 }); + + verticalStack.Add(new ProgressBar { Progress = 0.5 }); + verticalStack.Add(new ProgressBar { Progress = 0.5, BackgroundColor = Colors.LightCoral }); + verticalStack.Add(new ProgressBar { Progress = 0.5, ProgressColor = Colors.Purple }); + + verticalStack.Add(new SearchBar { CharacterSpacing = 4, Text = "A search query", TextColor = Colors.Orange }); + verticalStack.Add(new SearchBar { Placeholder = "Placeholder" }); + verticalStack.Add(new SearchBar { HorizontalTextAlignment = TextAlignment.End, Text = "SearchBar HorizontalTextAlignment" }); + verticalStack.Add(new SearchBar { Text = "SearchBar MaxLength", MaxLength = 50 }); + verticalStack.Add(new SearchBar { Text = "SearchBar CancelButtonColor", CancelButtonColor = Colors.IndianRed }); + + var monkeyList = new List + { + "Baboon", + "Capuchin Monkey", + "Blue Monkey", + "Squirrel Monkey", + "Golden Lion Tamarin", + "Howler Monkey", + "Japanese Macaque" + }; + + var picker = new Picker { Title = "Select a monkey", TitleColor = Colors.Red, FontFamily = "Dokdo", HorizontalTextAlignment = TextAlignment.Center }; + + picker.ItemsSource = monkeyList; + verticalStack.Add(picker); + + verticalStack.Add(new Slider()); + verticalStack.Add(new Slider { MinimumTrackColor = Colors.Orange, MaximumTrackColor = Colors.Purple, ThumbColor = Colors.GreenYellow }); + verticalStack.Add(new Slider { ThumbImageSource = "dotnet_bot.png" }); + + verticalStack.Add(new Stepper()); + verticalStack.Add(new Stepper { BackgroundColor = Colors.IndianRed }); + verticalStack.Add(new Stepper { Minimum = 0, Maximum = 10, Value = 5 }); + + verticalStack.Add(new Switch()); + verticalStack.Add(new Switch() { OnColor = Colors.Green }); + verticalStack.Add(new Switch() { ThumbColor = Colors.Yellow }); + verticalStack.Add(new Switch() { OnColor = Colors.Green, ThumbColor = Colors.Yellow }); + + verticalStack.Add(new DatePicker()); + verticalStack.Add(new DatePicker { TextColor = Colors.OrangeRed }); + verticalStack.Add(new DatePicker { CharacterSpacing = 6 }); + verticalStack.Add(new DatePicker { FontSize = 24 }); + + verticalStack.Add(new TimePicker()); + verticalStack.Add(new TimePicker { TextColor = Colors.LightGreen }); + verticalStack.Add(new TimePicker { Time = TimeSpan.FromHours(8), CharacterSpacing = 6 }); + + verticalStack.Add(new Label { Text = "IMAGES (static | animated):" }); + verticalStack.Add(CreateImagesGrid()); Content = new ScrollView { @@ -604,7 +605,7 @@ IView CreateShapes() IView CreateAlerts() { - var simpleAlertButton = new Button { Text ="Simple Alert"}; + var simpleAlertButton = new Button { Text = "Simple Alert" }; simpleAlertButton.Clicked += async (sender, args) => { @@ -654,7 +655,7 @@ IView CreateAlerts() return verticalStack; } - + void AddTextResizeDemo(Microsoft.Maui.ILayout layout) { var resizeTestButton = new Button { Text = "Resize Test" }; @@ -741,4 +742,4 @@ public void Draw(ICanvas canvas, RectangleF dirtyRect) } } } -} +} \ No newline at end of file From 093028b23ac7c4eacc980a86a4a88c338c205c6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Su=C3=A1rez?= Date: Wed, 16 Jun 2021 11:45:27 +0200 Subject: [PATCH 05/17] Updated Page --- src/Controls/src/Core/Page.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Controls/src/Core/Page.cs b/src/Controls/src/Core/Page.cs index 97b7da31b393..96682def4476 100644 --- a/src/Controls/src/Core/Page.cs +++ b/src/Controls/src/Core/Page.cs @@ -413,9 +413,9 @@ public void SendAppearing() if (IsBusy) { if (IsPlatformEnabled) - MessagingCenter.Send(this, BusySetSignalName, true); + MessagingCenter.Send((IPage)this, BusySetSignalName, true); else - _pendingActions.Add(() => MessagingCenter.Send(this, BusySetSignalName, true)); + _pendingActions.Add(() => MessagingCenter.Send((IPage)this, BusySetSignalName, true)); } OnAppearing(); @@ -436,7 +436,7 @@ public void SendDisappearing() _hasAppeared = false; if (IsBusy) - MessagingCenter.Send(this, BusySetSignalName, false); + MessagingCenter.Send((IPage)this, BusySetSignalName, false); var pageContainer = this as IPageContainer; pageContainer?.CurrentPage?.SendDisappearing(); @@ -493,7 +493,7 @@ void OnPageBusyChanged() if (!_hasAppeared) return; - MessagingCenter.Send(this, BusySetSignalName, IsBusy); + MessagingCenter.Send((IPage)this, BusySetSignalName, IsBusy); } void OnToolbarItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs args) From de5c03b9494e4c55f10a9c8c43a74bb5ef6ee1cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Su=C3=A1rez?= Date: Thu, 17 Jun 2021 17:36:40 +0200 Subject: [PATCH 06/17] Fix broken unit tests --- src/Controls/tests/Core.UnitTests/PageTests.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Controls/tests/Core.UnitTests/PageTests.cs b/src/Controls/tests/Core.UnitTests/PageTests.cs index 7dc21940300a..5790f15d9a70 100644 --- a/src/Controls/tests/Core.UnitTests/PageTests.cs +++ b/src/Controls/tests/Core.UnitTests/PageTests.cs @@ -308,7 +308,7 @@ public void TestThrowOnInvalidAlignment() public void BusyNotSentWhenNotVisible() { var sent = false; - MessagingCenter.Subscribe(this, Page.BusySetSignalName, (p, b) => sent = true); + MessagingCenter.Subscribe(this, Page.BusySetSignalName, (p, b) => sent = true); new ContentPage { IsBusy = true }; @@ -319,7 +319,7 @@ public void BusyNotSentWhenNotVisible() public void BusySentWhenBusyPageAppears() { var sent = false; - MessagingCenter.Subscribe(this, Page.BusySetSignalName, (p, b) => + MessagingCenter.Subscribe(this, Page.BusySetSignalName, (p, b) => { Assert.That(b, Is.True); sent = true; @@ -341,7 +341,7 @@ public void BusySentWhenBusyPageDisappears() ((IPageController)page).SendAppearing(); var sent = false; - MessagingCenter.Subscribe(this, Page.BusySetSignalName, (p, b) => + MessagingCenter.Subscribe(this, Page.BusySetSignalName, (p, b) => { Assert.That(b, Is.False); sent = true; @@ -356,7 +356,7 @@ public void BusySentWhenBusyPageDisappears() public void BusySentWhenVisiblePageSetToBusy() { var sent = false; - MessagingCenter.Subscribe(this, Page.BusySetSignalName, (p, b) => sent = true); + MessagingCenter.Subscribe(this, Page.BusySetSignalName, (p, b) => sent = true); var page = new ContentPage(); ((IPageController)page).SendAppearing(); @@ -374,7 +374,7 @@ public void DisplayAlert() var page = new ContentPage() { IsPlatformEnabled = true }; AlertArguments args = null; - MessagingCenter.Subscribe(this, Page.AlertSignalName, (Page sender, AlertArguments e) => args = e); + MessagingCenter.Subscribe(this, Page.AlertSignalName, (IPage sender, AlertArguments e) => args = e); var task = page.DisplayAlert("Title", "Message", "Accept", "Cancel"); @@ -397,7 +397,7 @@ public void DisplayActionSheet() var page = new ContentPage() { IsPlatformEnabled = true }; ActionSheetArguments args = null; - MessagingCenter.Subscribe(this, Page.ActionSheetSignalName, (Page sender, ActionSheetArguments e) => args = e); + MessagingCenter.Subscribe(this, Page.ActionSheetSignalName, (IPage sender, ActionSheetArguments e) => args = e); var task = page.DisplayActionSheet("Title", "Cancel", "Destruction", "Other 1", "Other 2"); From cb41becf5e575f536ed989c6773d0de9cb06d64a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Su=C3=A1rez?= Date: Thu, 24 Jun 2021 14:28:23 +0200 Subject: [PATCH 07/17] Fixed build error --- src/Core/src/Platform/iOS/MauiUIApplicationDelegate.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Core/src/Platform/iOS/MauiUIApplicationDelegate.cs b/src/Core/src/Platform/iOS/MauiUIApplicationDelegate.cs index 3bf390428151..cde2f331fe09 100644 --- a/src/Core/src/Platform/iOS/MauiUIApplicationDelegate.cs +++ b/src/Core/src/Platform/iOS/MauiUIApplicationDelegate.cs @@ -31,12 +31,13 @@ public override bool WillFinishLaunching(UIApplication application, NSDictionary public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions) { - Application = Services.GetRequiredService(); + AlertManager.Subscribe(application); - UIWindow uIWindow = new UIWindow(); + Application = Services.GetRequiredService(); AlertManager.Subscribe(application); - var mauiContext = new MauiContext(Services); + UIWindow uIWindow = new UIWindow(); + var mauiContext = new MauiContext(Services, uIWindow); var activationState = new ActivationState(mauiContext); var window = Application.CreateWindow(activationState); @@ -130,4 +131,4 @@ protected MauiUIApplicationDelegate() public IApplication Application { get; protected set; } = null!; } -} +} \ No newline at end of file From 7a1577305dd083fd2c5a868726e7fa64a0366233 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Su=C3=A1rez?= Date: Thu, 24 Jun 2021 14:29:07 +0200 Subject: [PATCH 08/17] Fixed misaligned code issue --- .../samples/Controls.Sample/Pages/MainPage.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Controls/samples/Controls.Sample/Pages/MainPage.cs b/src/Controls/samples/Controls.Sample/Pages/MainPage.cs index 0d05d69caea1..d2e8cb14976f 100644 --- a/src/Controls/samples/Controls.Sample/Pages/MainPage.cs +++ b/src/Controls/samples/Controls.Sample/Pages/MainPage.cs @@ -83,7 +83,7 @@ void SetupMauiLayout() verticalStack.Add(CreateShapes()); verticalStack.Add(CreateAspectShapes()); verticalStack.Add(CreateAlerts()); - + verticalStack.Add(new Label { Text = " ", Padding = new Thickness(10) }); var label = new Label { Text = "End-aligned text", BackgroundColor = Colors.Fuchsia, HorizontalTextAlignment = TextAlignment.End }; label.Margin = new Thickness(15, 10, 20, 15); @@ -608,7 +608,7 @@ IView CreateShapes() return verticalStack; } - IView CreateAspectShapes() + IView CreateAspectShapes() { Geometry pathData = (Geometry)new PathGeometryConverter().ConvertFromInvariantString("M8.0886959,0L8.687694,0C12.279728,0.2989963 14.275696,2.2949993 15.971676,4.9890003 16.271724,4.5899982 16.470699,4.1909961 16.670711,3.8920001 18.765678,0.89799553 23.056684,-1.0980074 27.247655,0.79800445 28.544711,1.3970038 29.842683,2.2949993 30.740692,3.5919966 31.239652,4.3909931 31.837675,5.6880059 31.93765,6.8849973 32.336696,10.677006 30.740692,13.470998 29.442659,15.866003L26.648658,15.866003C26.149696,15.168005 26.050697,14.069998 25.351663,13.571004 24.453716,14.369009 24.353679,15.966009 23.75572,17.064001 23.156721,17.263006 22.457687,16.96401 21.759691,17.163 21.260667,17.761999 20.960681,19.359001 20.761707,20.257011 20.761707,19.458 20.561695,17.761999 20.462695,16.664007 20.262683,14.668997 20.162708,12.472997 19.963674,10.278004 19.863698,9.3800086 19.963674,8.1830015 19.164724,8.1830015 18.566703,8.1830015 18.466728,9.3800086 18.466728,9.9790077 18.266715,12.07401 17.867731,14.27001 17.468683,16.465002 16.969722,15.467001 16.670711,14.27001 16.171687,14.27001 15.57269,14.668997 15.27368,15.36701 14.973692,15.966009L13.975708,15.966009C13.876709,15.666998 13.576723,15.567007 13.277712,15.567007 12.878725,15.567007 12.47974,15.966009 12.47974,16.465002 12.47974,16.96401 12.878725,17.362997 13.277712,17.362997 13.476686,17.362997 13.776735,17.263006 13.876709,17.064001 14.375732,17.163 15.073729,17.064001 15.57269,17.064001 15.871701,16.664007 15.971676,16.265005 16.171687,15.966009 16.76971,16.763998 16.670711,18.161003 17.767694,18.660011 18.166679,18.361 18.266715,17.961998 18.366691,17.463003 18.566703,16.066 18.865714,14.569006 19.065725,13.071996 19.065725,12.873006 19.164724,11.675008 19.264699,11.375997 19.464712,14.069998 19.763723,17.761999 19.963674,20.556007 20.062671,21.354011 20.262683,21.554008 20.861682,21.953011 21.360704,21.554008 21.459703,21.454002 21.659715,20.855003 21.958665,20.157005 22.0587,19.359001 22.258712,18.560005 22.757675,18.461006 23.75572,18.760002 24.353679,18.461006 24.852703,17.662008 25.052713,16.364996 25.4517,15.567007 25.750711,16.066 25.950662,16.763998 26.249671,17.163L28.844699,17.163C28.445651,17.761999 27.846654,18.361 27.447667,18.760002 24.253703,22.352013 20.162708,25.545008 16.071712,27.641001 10.982733,24.84701 5.6937417,20.955009 2.4007186,15.567007 0.90371192,13.071996 -0.79226869,8.9810066 0.40475065,5.3889946 0.60476232,4.8900012 0.90371192,4.4899921 1.2037603,3.9909992 2.4007183,1.7959909 5.0947441,2.1702817E-07 8.0886959,0z"); @@ -635,7 +635,7 @@ IView CreateAspectShapes() return verticalStack; } - + IView CreateAlerts() { var simpleAlertButton = new Button { Text = "Simple Alert" }; @@ -684,11 +684,11 @@ IView CreateAlerts() simpleActionSheetButton, cancelDeleteActionSheetButton, simplePromptButton - }; - + }; + return verticalStack; - } - + } + void AddTextResizeDemo(Microsoft.Maui.ILayout layout) { var resizeTestButton = new Button { Text = "Resize Test" }; From 07808bedf81e200a4616c0701db156598446d771 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Su=C3=A1rez?= Date: Mon, 28 Jun 2021 16:31:15 +0200 Subject: [PATCH 09/17] Added Alerts sample --- .../Pages/Core/AlertsPage.xaml | 44 ++++++++++++++ .../Pages/Core/AlertsPage.xaml.cs | 58 +++++++++++++++++++ .../ViewModels/CoreViewModel.cs | 5 +- 3 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 src/Controls/samples/Controls.Sample/Pages/Core/AlertsPage.xaml create mode 100644 src/Controls/samples/Controls.Sample/Pages/Core/AlertsPage.xaml.cs diff --git a/src/Controls/samples/Controls.Sample/Pages/Core/AlertsPage.xaml b/src/Controls/samples/Controls.Sample/Pages/Core/AlertsPage.xaml new file mode 100644 index 000000000000..204eeb050e15 --- /dev/null +++ b/src/Controls/samples/Controls.Sample/Pages/Core/AlertsPage.xaml @@ -0,0 +1,44 @@ + + + + +