Giter Club home page Giter Club logo

mopups's Introduction


Mopups

Customisable Popups for MAUI

Table of Contents

NuGet Downloads nuget

About The Project

Mopups is a replacement for the "Rg.Plugins.Popups" plugin for Xamarin. Mopups intends to provide a similar experience to this plugin, however also clean up the code base and provide forward looking enhancements. Developers familar with the original plugin should find it a smooth transition, but we do recommend reading the wiki and reaching out with any issues.

The "PreBaked" is a neat blend of Mopups and AsyncAwaitBestPractices plugins to bring you a quick way to add popups into your MAUIs App using familiar concepts

Platforms Supported (Current)

  • Android
  • iOS
  • Windows
  • MacOS (Mac Catalyst) (This is a bit iffy..)

Below is a video by @jfversluis introducing Mopups Watch the video

Getting Started

First, you must follow the initialisation

Installation

You can install the nuget by looking up 'Mopups' in your nuget package manager, or by getting it here

Usage

here is an example of what this plugin makes easy (Looks slow due to giphy)

Gif Example

New Example

To Use the plugin for its inbuilt popup pages in a basic setting (Dual/Single Response, Login, TextInput EntryInput,and loader.) All you need are these one liners

SingleResponse Popup Page

return await SingleResponseViewModel.AutoGenerateBasicPopup(Color.HotPink, Color.Black, "I Accept", Color.Gray, "Good Job, enjoy this single response example", "thumbsup.png");

DualResponse Popup Page

return await DualResponseViewModel.AutoGenerateBasicPopup(Color.WhiteSmoke, Color.Red, "Okay", Color.WhiteSmoke, Color.Green, "Looks Good!", Color.DimGray, "This is an example of a dual response popup page", "thumbsup.png");

Loader Popup Page

  await PreBakedMopupService.GetInstance().WrapTaskInLoader(Task.Delay(10000), Color.Blue, Color.White, LoadingReasons(), Color.Black);

Text Input PopupPage

await TextInputViewModel.AutoGenerateBasicPopup(Color.WhiteSmoke, Color.Red, "Cancel", Color.WhiteSmoke, Color.Green, "Submit", Color.DimGray, "Text input Example", string.Empty);

Entry Input PopupPage

await EntryInputViewModel.AutoGenerateBasicPopup(Color.WhiteSmoke, Color.Red, "Cancel", Color.WhiteSmoke, Color.Green, "Submit", Color.DimGray, "Text input Example", string.Empty);

LoginPage PopupPage

var (username, password) = await LoginViewModel.AutoGenerateBasicPopup(Color.WhiteSmoke, Color.Red, "Cancel", Color.WhiteSmoke, Color.Green, "Submit", Color.DimGray, string.Empty, "Username Here", string.Empty, "Password here", "thumbsup.png", 0, 0);

or, to return from the loader a value

await PreBakedMopupService.GetInstance().WrapReturnableTaskInLoader<bool, LoaderPopupPage>(IndepthCheckAgainstDatabase(), Color.Blue, Color.White, LoadingReasons(), Color.Black);

you can also add in synchronous functions, however they are wrapped in a task

private bool LongRunningFunction(int millisecondDelay)
{
    Thread.Sleep(millisecondDelay);
    return true;
}
await PreBakedMopupService.GetInstance().WrapReturnableFuncInLoader(LongRunningFunction, 6000, Color.Blue, Color.White, LoadingReasons(), Color.Black);

That's it! for advanced usage read on

In Version 1.2.0, Mopups has added some pre created pages that can provide users the ability to return data from popups. I have also added the ability to overload the look of these pages and create your own.

I do wish it were simpler, however, with the limited time i have to work on this, it'll have to do.

This set of API's will be used for when the basic API wont cut it, without relying on me making another overload for every situation under the sun.

This API introduces

GeneratePopup<TPopupPage> Which allows you to supply your own popuppage xaml which will then be attached to whatever VM you called it from.

GeneratePopup(Dictionary<string, object> propertyDictionary) Which allows you have a dictionary of values that a popup uses, pass and automatically attach to the appropriate properties on the VM side

These are both non-static. and require you to have an instance of the ViewModel to work with. Hence

<ViewModelClassNameHere>.GenerateVM() Which provides you with a new instance of that VM

<ViewModelClassNameHere>.PullViewModelProperties() Which collects all the properties of a VM, and provides them to you in a dictionary, so you can reuse and also while debugging, check what exists/whats been changed Returns this Dictionary<string, (object property, Type propertyType)>

However, for initialisation, i internally (and you can use) the following function <ViewModelClassNameHere>.InitialiseOptionalProperties(Dictionary<string, object> optionalProperties) Which will attempt to set each of the viewmodel properties with the corrosponding value in the dictionary

So, to fix that, i provide <ViewModelClassNameHere>.FinalisePreparedProperties(Dictionary<string, (object property, Type propertyType)> viewModelProperties) Which takes in the Dictionary<string, (object property, Type propertyType)> and creates Dictionary<string, object> optionalProperties

If you want to make your own Popup Page

This is the real power of this Plugin . If you look at the source for DualResponsePopupPage, or the SingleResponse version you'll notice that they are just simple Xaml Pages. Nothing fancy.

You can create the full thing yourself

  1. Create Xaml Page with codebehind
  2. Create your ViewModel that is associated with the popup, lets call ours InformationPopupPage
  3. Ensure your ViewModel inherits from PopupViewModel<TReturnable> where TReturnable is what you want the popuppage to return to its caller
  4. Ensure that your xaml page codebehind inherits from PopupPage (requirement to use rg plugins popup) and IGenericViewModel<TViewModel> where TViewModel is your Viewmodel, in our case it will be IGenericViewModel<InformationPopupPage>
  5. You're ready to start using it the same as DualResponsePopupPage

or you can provide your own Xaml Page, with a codebehind that inherits from PopupPage and IGenericViewModel<TViewModel> where TViewModel is the plugin provided VM you wish to use.

to use this version, just call TViewModel.GeneratePopup<YourXamlPopupPage>()

License

This project uses the MIT License

Contact

My Github,

mopups's People

Contributors

aswinpg avatar bakerhillpins avatar busec0 avatar eichbaum avatar ieuanwalker avatar luckyducko avatar maxkoshevoi avatar mlxyz avatar paulmdemers avatar preussenkaiser avatar prok155 avatar pureween avatar romerotg avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mopups's Issues

Android back button crashes

After i installed the NuGet i've noticed the android device back button is crashing the app.

Navigation bar back button and Navigation.PopAsync are fine, its just the device back button -

2022-07-01.17-55-58.1.mp4

Downloaded your source code to try and recreate it using your sample app. Duplicated the main page (setting the background black) and replicated the same issue.

PanGestureRecognizer jitters

Not sure if this is a use case you'd support, but I'm trying to implement a drag to dismiss.
Logic is all working but the popup jitters when being dragged -

2022-07-01.14-33-56.mp4
public partial class SearchPopup :  PopupPage
{
	double _closeYPosition, _y = 0;
	readonly Color _backgroundColour;
	public SearchPopup()
	{
		InitializeComponent();
		_backgroundColour = BackgroundColor;
	}

	protected override async void OnSizeAllocated(double width, double height)
	{
		base.OnSizeAllocated(width, height);

		if (height < 0)
		{
			return;
		}

		//! IMPORTANT - Delay needed as height isn't set properly when the device is rotated 
		await Task.Delay(100);		

        // Set pop up to 80% of the screen height
		PopupContent.HeightRequest = 0.8 * height;

		// Set close Y position to 20% of the height of the pop up
		_closeYPosition = 0.2 * PopupContent.HeightRequest;
	}

	async void TapGestureRecognizer_Tapped(object sender, EventArgs e)
	{
		await MopupService.Instance.PopAsync();
	}

	async void PanGestureRecognizer_PanUpdated(object sender, PanUpdatedEventArgs e)
	{
		switch (e.StatusType)
		{
			case GestureStatus.Running:
				draggingBar.SetDynamicResource(BackgroundColorProperty, "BlueDarkColour");

				// Don't allow dragging up
				if (e.TotalY < 0)
				{
					break;
				}

				// Calculate percentage pop up has been dragged down
				double percentage = ((PopupContent.HeightRequest - (PopupContent.HeightRequest - e.TotalY)) / PopupContent.HeightRequest) * 100;

				// Animate background colour opacity
				this.CancelAnimation();
				await this.ColorTo(this.BackgroundColor, _backgroundColour.WithAlpha(Convert.ToSingle(_backgroundColour.Alpha * ((100 - percentage) / 100))), c => BackgroundColor = c, 100);

				// Move pop up to y pan position
				PopupContent.TranslationY = e.TotalY;
				_y = e.TotalY;
				break;

			case GestureStatus.Completed:
				draggingBar.SetDynamicResource(BackgroundColorProperty, "BackgroundColourSecondary");

				if (_y > _closeYPosition)
				{
					await MopupService.Instance.PopAsync();
				}
				else
				{
					await PopupContent.TranslateTo(0, 0);
					await this.ColorTo(this.BackgroundColor, _backgroundColour, c => BackgroundColor = c);
				}

				break;
		}
	}
}

public static class ViewExtensions
{
	public static Task<bool> ColorTo(this VisualElement self, Color fromColor, Color toColor, Action<Color> callback, uint length = 250, Easing? easing = null)
	{
		Func<double, Color> transform = (t) => Color.FromRgba(
			fromColor.Red + t * (toColor.Red - fromColor.Red),
			fromColor.Green + t * (toColor.Green - fromColor.Green),
			fromColor.Blue + t * (toColor.Blue - fromColor.Blue),
			fromColor.Alpha + t * (toColor.Alpha - fromColor.Alpha));
		
		return ColorAnimation(self, "ColorTo", transform, callback, length, easing);
	}

	public static void CancelAnimation(this VisualElement self)
	{
		self.AbortAnimation("ColorTo");
	}

	static Task<bool> ColorAnimation(VisualElement element, string name, Func<double, Color> transform, Action<Color> callback, uint length, Easing? easing)
	{
		easing = easing ?? Easing.Linear;
		var taskCompletionSource = new TaskCompletionSource<bool>();

		element.Animate<Color>(name, transform, callback, 16, length, easing, (v, c) => taskCompletionSource.SetResult(c));
		return taskCompletionSource.Task;
	}
}
<?xml version="1.0" encoding="utf-8" ?>
<Mopups:PopupPage x:Class="FitNote.Popups.SearchPopup"
                  xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
                  xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                  xmlns:Animations="clr-namespace:Mopups.Animations;assembly=Mopups"
                  xmlns:Mopups="clr-namespace:Mopups.Pages;assembly=Mopups"
                  Title="Aswin"
                  BackgroundColor="#99404040"
                  BackgroundInputTransparent="False"
                  CloseWhenBackgroundIsClicked="True">
    <Mopups:PopupPage.Animation>
        <Animations:MoveAnimation DurationIn="400"
                                  DurationOut="300"
                                  EasingIn="SinOut"
                                  EasingOut="SinIn"
                                  HasBackgroundAnimation="True"
                                  PositionIn="Bottom"
                                  PositionOut="Bottom" />
    </Mopups:PopupPage.Animation>

    <Border x:Name="PopupContent"
            Margin="-2"
            Padding="0"
            BackgroundColor="{DynamicResource BackgroundColourPrimary}"
            HorizontalOptions="FillAndExpand"
            VerticalOptions="End">
        <Border.StrokeShape>
            <RoundRectangle CornerRadius="20,20,0,0" />
        </Border.StrokeShape>
        <Grid RowDefinitions="auto,auto,auto">
            <BoxView x:Name="draggingBar"
                     Grid.Row="0"
                     Margin="0,10,0,0"
                     BackgroundColor="{DynamicResource BackgroundColourSecondary}"
                     CornerRadius="5"
                     HeightRequest="10"
                     WidthRequest="100">
                <BoxView.GestureRecognizers>
                    <PanGestureRecognizer PanUpdated="PanGestureRecognizer_PanUpdated" />
                </BoxView.GestureRecognizers>
            </BoxView>
            <Label Grid.Row="1"
                   Margin="20"
                   Text="CANCEL">
                <Label.GestureRecognizers>
                    <TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped" />
                </Label.GestureRecognizers>
            </Label>

            <Label Grid.Row="2"
                   Margin="20"
                   Text="{Binding Source={RelativeSource AncestorType={x:Type Border}}, Path=HeightRequest}" />
        </Grid>
    </Border>
</Mopups:PopupPage>

Purpose of lock in PopupNavigation

When looking at the old RG implementation it seems the locking of the popupStack serves a broader purpose. It is used to check the list of popups and prevent concurrency problems when equality conditions are met for a popup instance. In Mopups the lock is only used to check the stack if a popup has indeed been added before it is removed:

lock (_locker)
{
if (!_popupStack.Contains(page))
{
return;
}
}

I would argue the same equality conditions should be met when adding/pushing a popup, by also using a Contains check on the stack. It would then also make sense to check the same lock when pushing popups to the stack (and other relevant operations on the list). It would also make the whole thing thread safe.

The bigger purpose here would be to provide a way of implementing equality overrides for popup instances. This way you can create a mechanism that prevents opening the same popup twice, sort of a modal popup if you like, if you would for example check equality on the popups name only. This really is my main goal when looking at the current implementation, which used to be possible with the old RG implementation.

Add nullable annotation

Add <Nullable>enable</Nullable> to the project file.
This will provide better development and usage experience.

I can help annotate the code.

Can we make the PopupNavigation PopupStack property static?

I would like to be able to check the count of the PopupStack by doing something like:

Mopups.Services.PopupNavigation.PopupStack.Count

I want to do this to add a protective check before trying to pop something of an empty stack. The PopupStack property would need to be made static.

Thoughts?

Issues with Demo Project

First off, it's unclear if I should be loading the Sample Solution in the sample dir or the Mopups Solution in the root? I opted for the Sample solution.

Tried to run the demo project SampleMopups.sln and had had several errors:

  1. NuGet downgrade error.
    Severity Code Description Project File Line Suppression State Error NU1605 Warning As Error: Detected package downgrade: Microsoft.WindowsAppSDK from 1.2.221209.1 to 1.2.221116.1. Reference the package directly from the project to select a different version. SampleMopups -> Microsoft.Maui.Graphics.Win2D.WinUI.Desktop 7.0.81 -> Microsoft.WindowsAppSDK (>= 1.2.221209.1) SampleMopups -> Microsoft.WindowsAppSDK (>= 1.2.221116.1) SampleMopups D:\Repos\Dumpster\Mopups\SampleMaui\SampleMopups.csproj 1
  2. Sample Solution doesn't include Mopups.csproj so build fails on clone. (Hence confusion)
  3. Pickers don't have Selected index set.
  4. Selected index cases for AnimationType switch start at 1, not 0, and thus the 3rd choice ScaleAnimation throws exception.

If page background is gradient then mopup isn't transparent.

Setting mopup background color to transparent doesn't work if I have set the background of the page with gradient brush.

This is for MainPage.xaml:
`ContentPage.Background>

    <LinearGradientBrush EndPoint="0,1">
        <GradientStop Color="{AppThemeBinding Light={StaticResource PageBackgroundLight}, Dark={StaticResource PageBackgroundDark}}"
                      Offset="0.5" />
        <GradientStop Color="#E3FFFC"
                      Offset="1.0" />
    </LinearGradientBrush>

</ContentPage.Background>`

and this is for mopup page.
<?xml version="1.0" encoding="utf-8" ?> <mopups:PopupPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:mopups="clr-namespace:Mopups.Pages;assembly=Mopups" x:Class="Tafseer_e_Namoona.Popups.ContentsPage" Title="ContentsPage" BackgroundColor="#80000000" >

Please check and let me know how can I resolve this issue.

Thanks.

Version 1.1.1 Throws WinUI error

After upgrading to today's version 1.1.1, Win UI throws a runtime type initializer error whose inner exception is "Operation not supported on this platform." I am using latest Visual Studio Enterprise stable on up-to-date Windows 11, original release. I have tried both clean/rebuild and then deletion in the affected project of its bin folder and everything in its obj folder except project.assets.json. No change. Reversion to previous Mopups version cures issue. Tried all this twice with identical results.

David Pressman

Properly implement handler pattern

Currently, Mopups does things that I am sure is extremely bad practice (Especially my hack? for getting the MauiContext just off the first window)

I believe the codebase code be further cleaned up by moving to a proper handler infrastructure, with mappers and whatnot, instead of just piggybacking off of PageHandler.

System.PlatformNotSupportedException is thrown when showing the popup in iOS

I tried to show the popup in my iPad 16.1 Simulator and the app crashes with the following message

System.PlatformNotSupportedException: Operation is not supported on this platform.
   at Mopups.Services.PopupNavigation.<GeneratePopupPlatform>g__PullPlatformImplementation|18_0()
   at Mopups.Services.PopupNavigation.GeneratePopupPlatform()
2023-03-23 13:55:35.521484+0530 Temp[13237:201425]    at Mopups.Services.PopupNavigation.<>c.<.cctor>b__25_0()
   at System.Lazy`1[[Mopups.Interfaces.IPopupPlatform, Mopups, Version=1.1.1.0, Culture=neutral, PublicKeyToken=null]].PublicationOnlyViaFactory(LazyHelper initializer)
2023-03-23 13:55:35.521674+0530 Temp[13237:201425]    at System.Lazy`1[[Mopups.Interfaces.IPopupPlatform, Mopups, Version=1.1.1.0, Culture=neutral, PublicKeyToken=null]].CreateValue()
   at System.Lazy`1[[Mopups.Interfaces.IPopupPlatform, Mopups, Version=1.1.1.0, Culture=neutral, PublicKeyToken=null]].get_Value()
2023-03-23 13:55:35.521776+0530 Temp[13237:201425]    at Mopups.Services.PopupNavigation..ctor()
   at Mopups.Services.MopupService.CreatePopupNavigation()
   at Mopups.Services.MopupService.<>c.<.cctor>b__10_0()
2023-03-23 13:55:35.521892+0530 Temp[13237:201425]    at System.Lazy`1[[Mopups.Interfaces.IPopupNavigation, Mopups, Version=1.1.1.0, Culture=neutral, PublicKeyToken=null]].PublicationOnlyViaFactory(LazyHelper initializer)
   at System.Lazy`1[[Mopups.Interfaces.IPopupNavigation, Mopups, Version=1.1.1.0, Culture=neutral, PublicKeyToken=null]].CreateValue()
2023-03-23 13:55:35.521999+0530 Temp[13237:201425]    at System.Lazy`1[[Mopups.Interfaces.IPopupNavigation, Mopups, Version=1.1.1.0, Culture=neutral, PublicKeyToken=null]].get_Value()
   at Mopups.Services.MopupService.get_Instance()
   at Temp.MainPage.OnCounterClicked(Object sender, EventArgs e) in /Users/rthanga1/Official/Samples/temp/Temp/Temp/MainPage.xaml.cs:line 22

Activity Indicator does not work on Android

Really enjoying the package thanks.
Have just come across the 1 issue with the Activity Indicator not showing in a PopupPage.
Seen this on Android and have not checked this on iOS.

[HouseKeeping] Clean up solution

The Mopups Solution has alot of...junk in it.

That's my bad.

I will remerge the two mini project together In the next release, once it passes PR.

Windows PlatformNotSupported v1.1.1

Something isn't quite right with the 1.1.1 NuGet package - if I reference that from the default template and call anything on MopupService (even IsSupported) then it all falls over with PlatformNotSupportedException. If I revert to 1.1.0 then it all seems to work fine.

Environment:

  • VS2022 17.6.4
  • .NET 7 (7.0.304)
  • Target: net7.0-windows10.0.19041.0

MAC Build warning about possible runtime failures

upon a Rebuild, i get the following warning:

There was a mismatch between the processor architecture of the project being built "MSIL" and the processor architecture of the reference "C:\Users\Win10.nuget\packages\mopups\1.1.0\lib\net7.0-maccatalyst15.4\Mopups.dll", "AMD64". This mismatch may cause runtime failures. Please consider changing the targeted processor architecture of your project through the Configuration Manager so as to align the processor architectures between your project and references, or take a dependency on references with a processor architecture that matches the targeted processor architecture of your project.

The used version is 1.1.0. I could not yet try if this does really create runtime problems, but this warning does not pass our internal reviews.

[iOS] The popup overlap DisplayActionSheet

When the popup is showing, We open the DisplayActionSheet.
=> The popup overlap DisplayActionSheet => Cannot tap to DisplayActionSheet

Configuration
iOS 14.6
Mopups: 1.1.0
VS: 17.5.2

How do you pass data when you close a popup?

Hi
I am probably missing the obvious here,
I have a popup and and input some data I.E Person object - Name- Surname than I close the popup and I need to pass the parameters to the page that called the popup. I noticed that there is a popped event but is not exposed.

Is there any example on how you can pass data from a pop up to a page when you close the popup?

The only way I can see is using weakreferencemanager from mvvm toolkit but I want to avoid using that to pass data

many thanks for this control!!

DisplayAlert Displaying Beneath PopupPage on iOS

On iOS, using DisplayAlert from a PopupPage causes the alert to be displayed under the PopupPage. My app is running on an iPhone 14 with iOS 16.4. The alert displays as expected on the Android version.

MyPopup.xaml.cs

public partial class MyPopup : Mopups.Pages.PopupPage
{
    public MyPopup()
    {
        InitializeComponent();
    }

    private async void Close_Popup(object sender, EventArgs e)
    {
        if (!await DisplayAlert("Confirm", "Are you sure you want to cancel?", "Yes", "No"))
            return;

        await Mopups.Services.MopupService.Instance.PopAsync();
    }
}

App crashes when closing a popup that contains an indicator view (iOS only)

As described in the title, when closing a popup that contains an indicator view, the app is crashing in iOS. I have included a sample project and stacktrace to display the issue. Can you take a look at it please? Thank you.

For reference, I am using Visual Studio 17.4.4 with .NET SDK 7.0.102.

CarouselPopupSample.zip

**System.InvalidOperationException:** 'PlatformView cannot be null here'

2023-01-12 11:13:41.450630-0700 CarouselPopupSample[2799:1687340] 
Unhandled Exception:
System.InvalidOperationException: PlatformView cannot be null here
   at Microsoft.Maui.Handlers.ViewHandler`2[[Microsoft.Maui.IIndicatorView, Microsoft.Maui, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[Microsoft.Maui.Platform.MauiPageControl, Microsoft.Maui, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].get_PlatformView()
   at Microsoft.Maui.Handlers.IndicatorViewHandler.DisconnectHandler(MauiPageControl platformView)
   at Microsoft.Maui.Handlers.ViewHandler`2[[Microsoft.Maui.IIndicatorView, Microsoft.Maui, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[Microsoft.Maui.Platform.MauiPageControl, Microsoft.Maui, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].OnDisconnectHandler(UIView platformView)
   at Microsoft.Maui.Handlers.ViewHandler.OnDisconnectHandler(Object platformView)
   at Microsoft.Maui.Handlers.ElementHandler.DisconnectHandler(Object platformView)
   at Microsoft.Maui.
Handlers.ElementHandler.Microsoft.Maui.IElementHandler.DisconnectHandler()
   at Mopups.iOS.Implementation.iOSMopups.DisposeModelAndChildrenHandlers(VisualElement view)
   at Mopups.iOS.Implementation.iOSMopups.RemoveAsync(PopupPage page)
   at Mopups.Services.PopupNavigation.<>c__DisplayClass23_0.<<RemovePageAsync>g__RemovePage|0>d.MoveNext()
--- End of stack trace from previous location ---
   at CarouselPopupSample.Popup.<>c.<<CloseButtonClicked>b__1_0>d.MoveNext() in C:\Users\aaoki\source\repos\CarouselPopupSample\Popup.xaml.cs:line 16
--- End of stack trace from previous location ---
   at ObjCRuntime.Runtime.ThrowException(IntPtr gchandle)
   at UIKit.UIApplication.UIApplicationMain(Int32 argc, String[] argv, IntPtr principalClassName, IntPtr delegateClassName)
   at UIKit.UIApplication.Main(String[] args, Type principalClass, Type delegateClass)
   at CarouselPopupSample.Program.Main(String[] args) in C:\Users\aaoki\source\repos\CarouselPopupSample\Platforms\iOS\Program.cs:line 13
2023-01-12 11:13:41.454885-0700 CarouselPopupSample[2799:1687340] Unhandled managed exception: PlatformView cannot be null here (System.InvalidOperationException)
   at Microsoft.Maui.Handlers.ViewHandler`2[[Microsoft.Maui.IIndicatorView, Microsoft.Maui, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[Microsoft.Maui.Platform.MauiPageControl, Microsoft.Maui, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].get_PlatformView()
   at Microsoft.Maui.Handlers.IndicatorViewHandler.DisconnectHandler(MauiPageControl platformView)
   at Microsoft.Maui.Handlers.ViewHandler`2[[Microsoft.Maui.IIndicatorView, Microsoft.Maui, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[Microsoft.Maui.Platform.MauiPageControl, Microsoft.Maui, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].OnDisconnectHandler(UIView platformView)
   at Microsoft.Maui.Handlers.ViewHandler.OnDisconnectHandler(Object platformView)
   at Microsoft.Maui.Handlers.ElementHandler.DisconnectHandler(Object platformView)
   at Microso
ft.Maui.Handlers.ElementHandler.Microsoft.Maui.IElementHandler.DisconnectHandler()
   at Mopups.iOS.Implementation.iOSMopups.DisposeModelAndChildrenHandlers(VisualElement view)
   at Mopups.iOS.Implementation.iOSMopups.RemoveAsync(PopupPage page)
   at Mopups.Services.PopupNavigation.<>c__DisplayClass23_0.<<RemovePageAsync>g__RemovePage|0>d.MoveNext()
--- End of stack trace from previous location ---
   at CarouselPopupSample.Popup.<>c.<<CloseButtonClicked>b__1_0>d.MoveNext() in C:\Users\aaoki\source\repos\CarouselPopupSample\Popup.xaml.cs:line 16
--- End of stack trace from previous location ---
   at ObjCRuntime.Runtime.ThrowException(IntPtr gchandle)
   at UIKit.UIApplication.UIApplicationMain(Int32 argc, String[] argv, IntPtr principalClassName, IntPtr delegateClassName)
   at UIKit.UIApplication.Main(String[] args, Type principalClass, Type delegateClass)
   at CarouselPopupSample.Program.Main(String[] args) in C:\Users\aaoki\source\repos\CarouselPopupSample\Platforms\iOS\Program.cs:line 13

Referenced assembly Mopups targets a different processor.

CSC : warning CS8012: Referenced assembly 'Mopups, Version=1.1.0.0, Culture=neutral, PublicKeyToken=null' targets a different processor. [Sample.csproj::TargetFramework=net7.0-maccatalyst]

Sample.csproj contains

  <PropertyGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)'))=='android'">
    <RuntimeIdentifiers>android-arm;android-arm64;android-x86;android-x64</RuntimeIdentifiers>
  </PropertyGroup>

  <PropertyGroup Condition="$([MSBuild]::IsOSPlatform('windows'))=='false' and $([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)'))=='maccatalyst' and $(Configuration) == 'Debug'">
    <RuntimeIdentifiers>maccatalyst-arm64;maccatalyst-x64</RuntimeIdentifiers>
  </PropertyGroup>

HasSystemPadding doesn't work

Hi,
thanks for the MAUI port of Rg.Plugins.Popup
It looks like the HasSystemPadding property from Rg.Plugins.Popup isn't working well.

You can check this by setting HasSystemPadding to true in the LoginPage in the sample project.
It doesn't respect the navigationbar and status bar on Android.
I haven't tested on iOS yet.

CloseWhenBackgroundIsClicked=True does not work on iOS

CloseWhenBackgroundIsClicked=True does not work on iOS.
Unless you also set BackgroundInputTransparent=True, but then the click is passed to the element that is visible, which is probably not what you want to do.

On the sample project:

  • the loginPage is ok : CloseWhenBackgroundIsClicked=True and BackgroundInputTransparent=True (no background visible element).
  • the AswinPage is broken : CloseWhenBackgroundIsClicked=True and BackgroundInputTransparent=False (visible elements in background).

No issue on Android.

Could you please take a look?
Thanks

iOS Architecture error

Hi,
Thanks for this great plugin!
When building my iOS MAUI app, I get the following warning:
There was a mismatch between the processor architecture of the project being built "" and the processor architecture of the reference "/Users/runner/.nuget/packages/mopups/1.0.3/lib/net6.0-ios15.4/Mopups.dll", "AMD64".
Should iOS not have the ARM64 architecture? It looks like this is not the case for Mopups.

Kind regards!

Accessibility

Screenreader

In RG.Popups a workaround was added to prevent the screenreader from working on the background page.

 static void HandleAccessibilityWorkaround(PopupPage page)
            {
                if (page.AndroidTalkbackAccessibilityWorkaround)
                {
                    var navCount = XApplication.Current.MainPage.Navigation.NavigationStack.Count;
                    var modalCount = XApplication.Current.MainPage.Navigation.ModalStack.Count;
                    XApplication.Current.MainPage.GetOrCreateRenderer().View.ImportantForAccessibility = ImportantForAccessibility.NoHideDescendants;

                    if (navCount > 0)
                    {
                        XApplication.Current.MainPage.Navigation.NavigationStack[navCount - 1].GetOrCreateRenderer().View.ImportantForAccessibility = ImportantForAccessibility.NoHideDescendants;
                    }
                    if (modalCount > 0)
                    {
                        XApplication.Current.MainPage.Navigation.ModalStack[modalCount - 1].GetOrCreateRenderer().View.ImportantForAccessibility = ImportantForAccessibility.NoHideDescendants;
                    }

                    DisableFocusableInTouchMode(XApplication.Current.MainPage.GetOrCreateRenderer().View.Parent);
                }
            }

            static void DisableFocusableInTouchMode(IViewParent? parent)
            {
                var view = parent;
                string className = $"{view?.GetType().Name}";

                while (!className.Contains("PlatformRenderer") && view != null)
                {
                    view = view.Parent;
                    className = $"{view?.GetType().Name}";
                }

                if (view is Android.Views.View androidView)
                {
                    androidView.Focusable = false;
                    androidView.FocusableInTouchMode = false;
                }
            }

The property AndroidTalkbackAccessibilityWorkaround was added, but personally don't think it's needed and the popup should just be accessible by default.

Keyboard navigation

This was never fixed but would be nice to make the control fully accessible.
rotorgames/Rg.Plugins.Popup#728

This may help - https://stackoverflow.com/a/64632343/4353708

Android - OnAppering, OnDisappearing not working

This functions and event not working. When a pop-ups appear or disappear They are don't be triggered.

 `	public MyPopup()
{
	InitializeComponent();
	this.Appearing += LoaderState_Appearing;
	this.Disappearing += LoaderState_Disappearing;
}

private void LoaderState_Disappearing(object sender, EventArgs e)
{
	
}

private void LoaderState_Appearing(object sender, EventArgs e)
{
	
}

protected override void OnAppearing()
{
	base.OnAppearing();
}

protected override void OnDisappearing()
{
	base.OnDisappearing();
}`

Workaround

 `	public MyPopup()
{
	InitializeComponent();
	MopupService.Instance.Popping += Instance_Popping;
	MopupService.Instance.Pushing += Instance_Pushing;

}

private void Instance_Pushing(object sender, Mopups.Events.PopupNavigationEventArgs e)
{
	if (e.Page is MyPopup)
	{
                    //appering 
            } 
}

private void Instance_Popping(object sender, Mopups.Events.PopupNavigationEventArgs e)
{
    if (e.Page is MyPopup)
    {
                   disappering
    }
}`

Closing popup causes crash in IOS

Using the await MopupService.Instance.PopAsync() causes the app to crash specifically on IOS. On Android, all works well. You can see the error message and stack trace in the image attached.

301517862_606932141043297_6605776098673599441_n

If I wrap the await MopupService.Instance.PopAsync() in a try catch, the exception is swallowed however the app still crashes once the screen is touched. Error message and stack trace attached below:

301416691_491425982986049_6614557745973874674_n

Things to note:

The ConfigureMopups() line is added in MauiProgram.cs.
For navigation, I am using Shell.

Steps to reproduce (Screenshot 1):

  1. Open popup using await MopupService.Instance.PushAsync(<Popup>)
  2. Close popup using await MopupService.Instance.PopAsync()
  3. App crashes

Steps to reproduce with try-catch (screenshot 2):

  1. Open popup using await MopupService.Instance.PushAsync(<Popup>)
  2. Close popup using await MopupService.Instance.PopAsync() (exception doesn't cause crash)
  3. Tap on the app
  4. Exception is thrown in Program.cs

IOS Issues

Having either no popup shown or a null exception when trying to push a page inside the view model for iOS.

When I inject the MopupService as a singleton into the constructor and use the service like this await this.popupNavigation.PushAsync(new MyPage()); inside of a MainThread.BeginInvokeOnMainThread I get the error below. I get the same error when using await MopupService.Instance.PushAsync(new MyPage());

at Mopups.Platforms.iOS.PopupPageHandler..ctor()
at System.Reflection.ConstructorInvoker.InterpretedInvoke(Object obj, Span`1 args, BindingFlags invokeAttr)

When I either don't put it inside of a MainThread.BeginInvokeOnMainThread or the old Device.BeginInvokeOnMainThread then no exception but the popup never appears (Running in Viewmodel).

If I use either PushAsync() method in the view itself it only works if it is placed inside of a clicked event. But if it's placed inside of an event listener method that was invoked inside the ViewModel then we see the same error.

I am able to use PushAsync inside the ViewModel for Android.

I am a bit confused. I am using .ConfigureMopups() inside of the mauiProgram and am also using app shell to carry out my other navigation elements.

Trimming support

When trying to publish an application with <PublishTrimmed>true</PublishTrimmed>, this library produces the following:

  Mopups.dll: [IL2104] Assembly 'Mopups' produced trim warnings. For more information see https://aka.ms/dotnet-illink/libraries

I guess it doesn't support net6.0/net7.0 trimming - https://aka.ms/dotnet-illink/libraries

[BUG] iOS doesn't blur background of previois page

Setting the background to transparent just pops the page popup on top of the previois page without blurring the background, it would be cool if there is a property or way to blur the previous page background so it appears as a true popup not just a page on top. Happens on iOS 16.

Repetitive clic on windows throws "No installed components were detected."

I have a multiplatform project that uses Mopups, our first target for now is WINDOWS and let me say "MOPUPS" is greate tool.

But I'm having this issue, I use a MOPUP as a awaiting messsage it locks

image

This popup is started (PushAsync) before I start an API interaction, and is stoped (PopAsync) when that interaction finishes. My problem is when the user hits clic on one button several times while a popup is opening.

Here is the stack trace

at WinRT.DelegateExtensions.DynamicInvokeAbi(Delegate del, Object[] invoke_params)
at ABI.System.Collections.Generic.IVectorMethods1.Append(IObjectReference obj, T value) at Microsoft.Maui.Handlers.ContentViewHandler.UpdateContent(IContentViewHandler handler) at Microsoft.Maui.Handlers.ContentViewHandler.MapContent(IContentViewHandler handler, IContentView page) at Microsoft.Maui.PropertyMapper.UpdateProperties(IElementHandler viewHandler, IElement virtualView) at Microsoft.Maui.Handlers.ContentViewHandler.SetVirtualView(IView view) at Microsoft.Maui.Controls.Element.SetHandler(IElementHandler newHandler) at Microsoft.Maui.Platform.ElementExtensions.ToHandler(IElement view, IMauiContext context) at Microsoft.Maui.Platform.ElementExtensions.ToPlatform(IElement view, IMauiContext context) at Mopups.Windows.Implementation.PopupPlatformWindows.<RemoveAsync>d__6.MoveNext() at Mopups.Services.PopupNavigation.<>c__DisplayClass23_0.<<RemovePageAsync>g__RemovePage|0>d.MoveNext() at AsyncAwaitBestPractices.SafeFireAndForgetExtensions.<HandleSafeFireAndForget>d__161.MoveNext()
at System.Threading.Tasks.Task.<>c.b__128_0(Object state)
at Microsoft.UI.Dispatching.DispatcherQueueSynchronizationContext.<>c__DisplayClass2_0.b__0()

Thaks for this great tool.

BackgroundClickedCommand gets executed twice

Hi,
I was testing the BackgroundClickedCommand, and i noticed that it gets executed twice once a popup is closed. below is my xaml code:

<pages:PopupPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:animations="clr-namespace:Mopups.Animations;assembly=Mopups" xmlns:pages="clr-namespace:Mopups.Pages;assembly=Mopups" xmlns:converters="clr-namespace:MarketLeader.Mobile.Application.Converters" xmlns:controls="clr-namespace:MarketLeader.Mobile.Application.Controls" x:Class="MarketLeader.Mobile.Application.Views.ContactTabs.StatusFilterPopup" Title="{Binding Title}" HasSystemPadding="True" CloseWhenBackgroundIsClicked="True" BackgroundClickedCommand="{Binding CloseCommand}" x:Name="statusPopup">
...

could this be a bug?

tested on iOS simulator. im using MVVM, so using the IPopupNavigation with dependency injection

Sample crashes when opening Popup

When pressing button to open popup, sample app cashes with:

Java.Lang.IllegalArgumentException: 
'The style on this component requires your app theme to be Theme.MaterialComponents (or a descendant).'

Exit code 0x80070005 on windows platform

Hi,
It's working perflectly on Android emulator but crash on Windows platform exit code 0x80070005.
image
If you won't I can upload my test project on Github.

Merry christmas.

iOS rendering issue

iOS doesn't render the popups correctly -

  • The popup is cut off at the bottom
  • Looks like the background is rendered twice with one having a margin added, so there is a darker inner background

image

Support for MAUI Embedding

SUMMARY
Hi! Thank you very much for your work in porting this library to .NET MAUI, it is greatly appreciated!

We have an app that utilizes MAUI Embedding to use MAUI pages in ".NET for Android" and ".NET for iOS" apps (previously Xamarin.Android and Xamarin.iOS). I was hoping to use your library in this app, but it seems that the Mopups registration doesn't seem to take effect when using this approach. Do you know if this is possible at all with this approach, or if this is something that's possible to implement? When I try to open a popup page from the iOS project, I get this error at runtime:

System.NullReferenceException: Object reference not set to an instance of an object. at Mopups.iOS.Implementation.iOSMopups.AddAsync(PopupPage page) at Mopups.Services.PopupNavigation.<>c__DisplayClass20_0.<<PushAsync>g__PushPage|0>d.MoveNext()

On Android I just get a NullReferenceException at runtime.

DETAILS
The use-case involves having one class library for the iOS/Android app and one class library where the MAUI pages are located. I use the embedding technique (as described in the previous link) and I use the host builder to add the .ConfigureMopups() in my AppDelegate.cs / MainActivity.cs. I've attached a repro of a project that uses MAUI embedding and that tries to use this package.

I understand that this embedding technique might not be all that used, but it would be great if there is a way to make this package work with this setup.

PLATFORMS

  • Android
  • iOS

MAUIEmbedding.zip

Operation is not Supported on this Platform error - iOS Release configuration only

I'm seeing this exception while using v1.1.1 on iOS, but only in the Release configuration. I have built a very simple test app that is modeled from Gerald Versluis' demo. The button opens a PopupPage that hosts a picker control. Everything works fine when compiled as Debug and deployed to an iPad. This is done using Visual Studio 2022 attached to a MacBook Pro where the iPad is connected. Fairly straightforward textbook setup.

MicrosoftTeams-image (20)

Now when it is time to create a Release build for testing the app fails, returning a PlatformNotSupportedException.

MicrosoftTeams-image (19)

The release build is an Azure DevOps pipeline. The file is attached for clarity on how it is configured.
azure-pipelines.yml.txt

An interesting thing to note - I have also created an Adhoc provisioning profile so I can build a Release version from VS 2022 on Windows and deploy it directly to the iPad (via the MacBook Pro of course). Under this scenario the release version works.

A second interesting thing to note - I have downloaded a zip copy of the Mopups code and referenced it as a project within this test app rather than a nuget package. Running it through the DevOps release pipeline generates a build that works.

I see that there are a few issues surrounding PlatformNotSupportedException. I have come across one earlier with Windows and resolved it with #47 (comment)

Has anyone seen the issue I am describing here, or have any idea on what might be occurring?

Thanks,
Brian Loehr

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.