using System; using Syncfusion.XForms.PopupLayout; using Xamarin.Forms; namespace InABox.Mobile { public interface IPopupManager { bool Initialise(); } public class PopupManagerConfiguration { public static double? DefaultHeight => 700; public static double? DefaultWidth => 350; public static double? AutoSize => null; public static RelativePosition? CenterOnScreen => null; public double? RequestedHeight { get; set; } = DefaultHeight; public double? RequestedWidth { get; set; } = DefaultWidth; public AutoSizeMode SizeMode { get => (Equals(RequestedHeight,AutoSize) && Equals(RequestedWidth,AutoSize)) ? AutoSizeMode.Both : Equals(RequestedHeight,AutoSize) ? AutoSizeMode.Height : Equals(RequestedWidth,AutoSize) ? AutoSizeMode.Width : AutoSizeMode.None; set { RequestedHeight = value is AutoSizeMode.Both or AutoSizeMode.Height ? AutoSize : DefaultHeight; RequestedWidth = value is AutoSizeMode.Both or AutoSizeMode.Width ? AutoSize : DefaultWidth; } } public bool ShowHeader { get; set; } = false; public bool ShowFooter { get; set; } = false; public int Padding { get; set; } = 10; public int CornerRadius { get; set; } = 5; public bool Modal { get; set; } = false; public RelativePosition? Position { get; set; } = CenterOnScreen; } public static class PopupManager { private static SfPopupLayout _popup = null; private static ContentPage FindParentPage(Element view) { if (view is ContentPage page) return page; return FindParentPage(view.Parent); } public static void DisplayError(Element view, string message) { MobileLogging.Log("Unable to create Popup Layout!"); var page = FindParentPage(view); Device.BeginInvokeOnMainThread(() => { page.DisplayAlert("Error", message, "OK"); }); } public static bool Initialise() { var service = DependencyService.Get(); return service?.Initialise() == true; } public static void ShowPopup(VisualElement parent, Func view, PopupManagerConfiguration config = null) { if (_popup == null && Initialise()) _popup = new SfPopupLayout(); if (_popup == null) { DisplayError(parent, "Unable to create Popup!\nPlease try again or restart the application."); return; } var cfg = config ?? new PopupManagerConfiguration(); _popup.PopupView.AutoSizeMode = cfg.SizeMode; if (Equals(cfg.RequestedHeight, PopupManagerConfiguration.AutoSize)) _popup.PopupView.ClearValue(VisualElement.HeightRequestProperty); else _popup.PopupView.HeightRequest = cfg.RequestedHeight!.Value; if (Equals(cfg.RequestedWidth, PopupManagerConfiguration.AutoSize)) _popup.PopupView.ClearValue(VisualElement.WidthRequestProperty); else _popup.PopupView.WidthRequest = cfg.RequestedWidth!.Value; _popup.PopupView.ShowHeader = cfg.ShowHeader; _popup.PopupView.ShowFooter = cfg.ShowFooter; _popup.PopupView.PopupStyle.CornerRadius = cfg.CornerRadius; _popup.StaysOpen = cfg.Modal; _popup.PopupView.ContentTemplate = new DataTemplate(() => { Grid grid = new Grid() { Padding = cfg.Padding }; grid.Children.Add(view()); return grid; }); if (parent is View pView && cfg.Position != PopupManagerConfiguration.CenterOnScreen) { var offset = GetOffset(parent, cfg.Position!.Value); _popup.ShowRelativeToView(pView, cfg.Position!.Value, offset.X, offset.Y); } else _popup.Show(); } /// /// Calculates the offest of the Menu to position it at the center of the Button /// Let's not presume that all the calculations are correct - its only been tested /// against AlignToLeftOf (for top-right-hand side menu options /// /// /// private static Point GetOffset(VisualElement parent, RelativePosition Position) { return Position switch { // Displays the popup at the top of the given view. RelativePosition.AlignTop => new Point(parent.Width / 2F, parent.Height / 2F), // Displays the popup to the left of the given view. RelativePosition.AlignToLeftOf => new Point(parent.Width / 2F, parent.Height / 2F), // Displays the popup to the right of the given view. RelativePosition.AlignToRightOf => new Point(0F - (parent.Width / 2F), parent.Height / 2F), // Displays the popup at the bottom of the given view. RelativePosition.AlignBottom => new Point(parent.Width / 2F, 0F - (parent.Height / 2F)), // Displays the popup at the top left position of the given view. RelativePosition.AlignTopLeft => new Point(parent.Width / 2F, parent.Height / 2F), // Displays the popup at the top right position of the given view. RelativePosition.AlignTopRight => new Point(0F - (parent.Width / 2F), parent.Height / 2F), // Displays the popup at the bottom left position of the given view. RelativePosition.AlignBottomLeft => new Point(0F - (parent.Width / 2F), parent.Height / 2F), // Displays the popup at the bottom right position of the given view. RelativePosition.AlignBottomRight => new Point(0F - (parent.Width / 2F), 0F - (parent.Height / 2F)), _ => new Point() }; } public static void DismissPopup() { if (_popup != null) _popup.Dismiss(); } } }