diff --git a/Mopups/Mopups.Maui/Mopups.csproj b/Mopups/Mopups.Maui/Mopups.csproj
index ba5cb26..7aff78f 100644
--- a/Mopups/Mopups.Maui/Mopups.csproj
+++ b/Mopups/Mopups.Maui/Mopups.csproj
@@ -13,7 +13,10 @@
Popups for MAUI with multi-window support. Fork of Mopups by LuckyDucko.
https://git.marketally.com/marketally/MarketAlly.Mopups
https://git.marketally.com/marketally/MarketAlly.Mopups
- MIT
+ BSD-3-Clause
+ Copyright (c) 2022, Tyson Elliot Hooker. All rights reserved.
+ icon.png
+ README.md
true
21.0
11.0
@@ -104,4 +107,9 @@
+
+
+
+
+
diff --git a/Mopups/Mopups.Maui/icon.png b/Mopups/Mopups.Maui/icon.png
new file mode 100644
index 0000000..efdc7c3
Binary files /dev/null and b/Mopups/Mopups.Maui/icon.png differ
diff --git a/README.md b/README.md
index a5b34f0..e25c35d 100644
--- a/README.md
+++ b/README.md
@@ -1,175 +1,290 @@
+# MarketAlly.Mopups
+[](https://www.nuget.org/packages/MarketAlly.Mopups/)
+[](https://www.nuget.org/packages/MarketAlly.Mopups/)
+[](https://opensource.org/licenses/BSD-3-Clause)
+[](https://dotnet.microsoft.com/download)
+[](https://dotnet.microsoft.com/apps/maui)
-
-
-
-
Mopups
-
- Customisable Popups for MAUI
-
-
-
-
-
-
-
+Customizable popups for .NET MAUI with multi-window support. A fork of [Mopups](https://github.com/LuckyDucko/Mopups) by Tyson Hooker (LuckyDucko) with enhanced multi-window capabilities for all platforms.
## Table of Contents
-[](https://www.nuget.org/packages/Mopups/)
-[](https://www.nuget.org/packages/Mopups/)
-* [About the Project](#about-the-project)
-* [Getting Started](#getting-started)
- * [Installation](#installation)
-* [Usage](#usage)
-* [License](#license)
-* [Contact](#contact)
+- [Features](#features)
+- [Installation](#installation)
+- [Quick Start](#quick-start)
+- [Multi-Window Support](#multi-window-support)
+- [Usage](#usage)
+- [Platform Support](#platform-support)
+- [Requirements](#requirements)
+- [License](#license)
+- [Acknowledgments](#acknowledgments)
+## Features
+### Core Capabilities (from Mopups)
-
-## About The Project
+- **Customizable Popups**: Full control over popup appearance and behavior
+- **Async/Await Pattern**: Modern asynchronous popup handling
+- **Animation Support**: Built-in appearing and disappearing animations
+- **System Padding**: Automatic safe area handling
+- **Back Button Handling**: Customizable back button behavior
+- **Cross-Platform**: iOS, Android, Windows, and macOS (Mac Catalyst)
-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.
+### New in MarketAlly.Mopups v2.0.0
-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
+- **Multi-Window Support**: Display popups on specific windows instead of always on the main window
+ - Windows: Uses target window's `XamlRoot`
+ - iOS/iPadOS: Uses target window's `UIWindowScene`
+ - macOS Catalyst: Uses target window's `UIWindowScene`
+ - Android: Uses target window's Activity `DecorView`
-Platforms Supported (Current)
-- Android
-- iOS
-- Windows
-- MacOS (Mac Catalyst) (This is a bit iffy..)
+## Installation
+Install via NuGet Package Manager:
-Below is a video by @jfversluis introducing Mopups
-[](https://youtu.be/OGWhgASmSto)
-
-
-
-## Getting Started
-
-First, you must follow the [initialisation](https://github.com/LuckyDucko/Mopups/wiki/Setup)
-
-### Installation
-
-You can install the nuget by looking up 'Mopups' in your nuget package manager, or by getting it [here](https://www.nuget.org/packages/Mopups/)
-
-
-
-
-## Usage
-here is an example of what this plugin makes easy (Looks slow due to giphy)
-
-
-
-
-### 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`
-```csharp
-return await SingleResponseViewModel.AutoGenerateBasicPopup(Color.HotPink, Color.Black, "I Accept", Color.Gray, "Good Job, enjoy this single response example", "thumbsup.png");
+```bash
+dotnet add package MarketAlly.Mopups
```
-`DualResponse Popup Page`
-```csharp
-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");
+Or via Package Manager Console:
+
+```powershell
+Install-Package MarketAlly.Mopups
```
-`Loader Popup Page`
-```csharp
- await PreBakedMopupService.GetInstance().WrapTaskInLoader(Task.Delay(10000), Color.Blue, Color.White, LoadingReasons(), Color.Black);
-```
+## Quick Start
-`Text Input PopupPage`
-```csharp
-await TextInputViewModel.AutoGenerateBasicPopup(Color.WhiteSmoke, Color.Red, "Cancel", Color.WhiteSmoke, Color.Green, "Submit", Color.DimGray, "Text input Example", string.Empty);
-```
-`Entry Input PopupPage`
-```csharp
-await EntryInputViewModel.AutoGenerateBasicPopup(Color.WhiteSmoke, Color.Red, "Cancel", Color.WhiteSmoke, Color.Green, "Submit", Color.DimGray, "Text input Example", string.Empty);
-```
+### 1. Configure in MauiProgram.cs
-`LoginPage PopupPage`
```csharp
-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);
-```
+using Mopups.Hosting;
-or, to return from the loader a value
-```csharp
-await PreBakedMopupService.GetInstance().WrapReturnableTaskInLoader(IndepthCheckAgainstDatabase(), Color.Blue, Color.White, LoadingReasons(), Color.Black);
-```
-
-you can also add in synchronous functions, however they are wrapped in a task
-```csharp
-
-private bool LongRunningFunction(int millisecondDelay)
+public static MauiApp CreateMauiApp()
{
- Thread.Sleep(millisecondDelay);
- return true;
-}
-await PreBakedMopupService.GetInstance().WrapReturnableFuncInLoader(LongRunningFunction, 6000, Color.Blue, Color.White, LoadingReasons(), Color.Black);
+ var builder = MauiApp.CreateBuilder();
+ builder
+ .UseMauiApp()
+ .ConfigureMopups(); // Add this line
+ return builder.Build();
+}
```
-## That's it! for advanced usage read on
+### 2. Create a Popup Page
-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.
+```csharp
+using Mopups.Pages;
-I do wish it were simpler, however, with the limited time i have to work on this, it'll have to do.
+public class MyPopupPage : PopupPage
+{
+ public MyPopupPage()
+ {
+ Content = new StackLayout
+ {
+ Children =
+ {
+ new Label { Text = "Hello from popup!" },
+ new Button { Text = "Close", Command = new Command(async () =>
+ await MopupService.Instance.PopAsync()) }
+ }
+ };
+ }
+}
+```
-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.
+### 3. Show the Popup
-This API introduces
+```csharp
+using Mopups.Services;
- `GeneratePopup`
-Which allows you to supply your own popuppage xaml which will then be attached to whatever VM you called it from.
+// Show on main window (default behavior)
+await MopupService.Instance.PushAsync(new MyPopupPage());
-`GeneratePopup(Dictionary 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
+// Show on specific window (NEW in v2.0.0)
+await MopupService.Instance.PushAsync(new MyPopupPage(), targetWindow);
+```
-These are both non-static. and require you to have an instance of the ViewModel to work with. Hence
+## Multi-Window Support
-`.GenerateVM()`
-Which provides you with a new instance of that VM
+The key enhancement in MarketAlly.Mopups is the ability to display popups on specific windows. This is essential for applications with multiple windows, such as:
-`.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 `
+- Helper/tool windows
+- Document windows
+- Settings panels
+- Floating utility windows
-However, for initialisation, i internally (and you can use) the following function
-`.InitialiseOptionalProperties(Dictionary optionalProperties)`
-Which will attempt to set each of the viewmodel properties with the corrosponding value in the dictionary
+### API
-So, to fix that, i provide
-`.FinalisePreparedProperties(Dictionary viewModelProperties)`
-Which takes in the `Dictionary ` and creates `Dictionary optionalProperties`
+```csharp
+// Standard push (uses main window)
+Task PushAsync(PopupPage page, bool animate = true);
+// Window-aware push (NEW)
+Task PushAsync(PopupPage page, Window? window, bool animate = true);
+```
+### Example: Showing Dialog on Helper Window
-**If you want to make your own Popup Page**
+```csharp
+public class HelperWindow : Window
+{
+ public async Task ShowConfirmation()
+ {
+ var popup = new ConfirmationPopup();
-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.
+ // Pass 'this' to show popup on this window, not the main window
+ await MopupService.Instance.PushAsync(popup, this);
+ }
+}
+```
-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` 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` where `TViewModel` is your Viewmodel, in our case it will be `IGenericViewModel`
-5. You're ready to start using it the same as `DualResponsePopupPage`
+### Platform Implementation Details
-or you can provide your own Xaml Page, with a codebehind that inherits from `PopupPage` and `IGenericViewModel` where `TViewModel` is the plugin provided VM you wish to use.
+| Platform | How Window is Used |
+|----------|-------------------|
+| Windows | Gets `XamlRoot` from the target window's native `Microsoft.UI.Xaml.Window` |
+| iOS/iPadOS | Gets `UIWindowScene` from the target window's native `UIWindow` |
+| macOS Catalyst | Gets `UIWindowScene` from the target window's native `UIWindow` |
+| Android | Gets `DecorView` from the target window's `Activity` |
-to use this version, just call `TViewModel.GeneratePopup()`
+## Usage
+### Basic Popup Operations
+```csharp
+// Push a popup
+await MopupService.Instance.PushAsync(new MyPopupPage());
+
+// Push with animation control
+await MopupService.Instance.PushAsync(new MyPopupPage(), animate: false);
+
+// Pop the topmost popup
+await MopupService.Instance.PopAsync();
+
+// Pop all popups
+await MopupService.Instance.PopAllAsync();
+
+// Remove specific popup
+await MopupService.Instance.RemovePageAsync(specificPopup);
+
+// Check popup stack
+var popupStack = MopupService.Instance.PopupStack;
+```
+
+### Events
+
+```csharp
+MopupService.Instance.Pushing += (sender, args) =>
+ Console.WriteLine($"Pushing: {args.Page}");
+
+MopupService.Instance.Pushed += (sender, args) =>
+ Console.WriteLine($"Pushed: {args.Page}");
+
+MopupService.Instance.Popping += (sender, args) =>
+ Console.WriteLine($"Popping: {args.Page}");
+
+MopupService.Instance.Popped += (sender, args) =>
+ Console.WriteLine($"Popped: {args.Page}");
+```
+
+### PopupPage Properties
+
+```csharp
+public class MyPopupPage : PopupPage
+{
+ public MyPopupPage()
+ {
+ // Background click dismisses popup
+ CloseWhenBackgroundIsClicked = true;
+
+ // Handle safe areas
+ HasSystemPadding = true;
+
+ // Background color
+ BackgroundColor = Color.FromRgba("#80000000");
+ }
+
+ // Override for custom back button behavior
+ protected override bool OnBackButtonPressed()
+ {
+ // Return true to prevent dismissal
+ return false;
+ }
+}
+```
+
+## Platform Support
+
+| Platform | Minimum Version | Multi-Window Support |
+|----------|-----------------|---------------------|
+| iOS | 11.0 | Yes (iOS 13+ with UIScene) |
+| Android | API 21 (5.0) | Yes (Android 7.0+ multi-window) |
+| Windows | 10.0.17763.0 | Yes |
+| macOS | 13.1 (Catalyst) | Yes |
+
+## Requirements
+
+- .NET 9.0
+- Microsoft.Maui.Controls 9.0+
+- Microsoft.Maui.Essentials 9.0+
-
## License
-This project uses the MIT License
-
-## Contact
-My [Github](https://github.com/LuckyDucko),
+This project is licensed under the **BSD 3-Clause License**.
+```
+BSD 3-Clause License
+Copyright (c) 2022, Tyson Elliot Hooker
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+```
+
+## Acknowledgments
+
+This project is a fork of [Mopups](https://github.com/LuckyDucko/Mopups), originally created by **Tyson Hooker (LuckyDucko)**. We extend our gratitude to:
+
+- **Tyson Hooker** - Original author and maintainer of Mopups
+- **Maksym Koshovyi** - Contributor
+- **Aswin P G** - Contributor
+- **Kirill Lyubimov** - Contributor
+- **Martijn Van Dijk** - Contributor
+- **Shane Neuville** - Contributor
+
+Mopups itself was created as a replacement for the "Rg.Plugins.Popups" plugin for Xamarin, providing a modern popup solution for .NET MAUI.
+
+### Additional Resources
+
+- [Original Mopups Repository](https://github.com/LuckyDucko/Mopups)
+- [Mopups Introduction Video by Gerald Versluis](https://youtu.be/OGWhgASmSto)
+
+---
+
+**Built with precision by [MarketAlly](https://marketally.com)**
+
+*Multi-window popup support for .NET MAUI applications.*