Add NuGet package assets and fix license

- Add icon.png for NuGet package
- Add PackageIcon and PackageReadmeFile to csproj
- Fix license from MIT to BSD-3-Clause (correct license per original)
- Add Copyright notice crediting original author

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-01 22:21:09 +00:00
parent c0e669fb30
commit d5b0054cb9
3 changed files with 249 additions and 126 deletions

View File

@@ -13,7 +13,10 @@
<Description>Popups for MAUI with multi-window support. Fork of Mopups by LuckyDucko.</Description>
<PackageProjectUrl>https://git.marketally.com/marketally/MarketAlly.Mopups</PackageProjectUrl>
<RepositoryUrl>https://git.marketally.com/marketally/MarketAlly.Mopups</RepositoryUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageLicenseExpression>BSD-3-Clause</PackageLicenseExpression>
<Copyright>Copyright (c) 2022, Tyson Elliot Hooker. All rights reserved.</Copyright>
<PackageIcon>icon.png</PackageIcon>
<PackageReadmeFile>README.md</PackageReadmeFile>
<DisableFastUpToDateCheck>true</DisableFastUpToDateCheck>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">21.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">11.0</SupportedOSPlatformVersion>
@@ -104,4 +107,9 @@
<PackageReference Include="Microsoft.Maui.Controls" Version="9.0.82" />
<PackageReference Include="Microsoft.Maui.Essentials" Version="9.0.82" />
</ItemGroup>
<ItemGroup>
<None Include="icon.png" Pack="true" PackagePath="\" />
<None Include="..\..\..\..\README.md" Pack="true" PackagePath="\" />
</ItemGroup>
</Project>

BIN
Mopups/Mopups.Maui/icon.png Normal file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

365
README.md
View File

@@ -1,175 +1,290 @@
# MarketAlly.Mopups
[![NuGet Version](https://img.shields.io/nuget/v/MarketAlly.Mopups.svg?style=flat)](https://www.nuget.org/packages/MarketAlly.Mopups/)
[![NuGet Downloads](https://img.shields.io/nuget/dt/MarketAlly.Mopups.svg)](https://www.nuget.org/packages/MarketAlly.Mopups/)
[![License: BSD-3-Clause](https://img.shields.io/badge/License-BSD--3--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause)
[![.NET](https://img.shields.io/badge/.NET-9.0-512BD4)](https://dotnet.microsoft.com/download)
[![Platform](https://img.shields.io/badge/Platform-iOS%20%7C%20Android%20%7C%20Windows%20%7C%20macOS-lightgray)](https://dotnet.microsoft.com/apps/maui)
<br />
<p align="center">
<h1 align="center">Mopups</h3>
<p align="center">
Customisable Popups for MAUI
<br />
</p>
</p>
<!-- TABLE OF CONTENTS -->
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
[![NuGet Downloads](https://img.shields.io/nuget/dt/Mopups.svg)](https://www.nuget.org/packages/Mopups/)
[![nuget](https://img.shields.io/nuget/v/Mopups.svg)](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 -->
## 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
[![Watch the video](https://img.youtube.com/vi/OGWhgASmSto/hqdefault.jpg)](https://youtu.be/OGWhgASmSto)
<!-- GETTING STARTED -->
## 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 EXAMPLES -->
## Usage
here is an example of what this plugin makes easy (Looks slow due to giphy)
![Gif Example](https://j.gifs.com/xn4mw9.gif)
### 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<bool, LoaderPopupPage>(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<App>()
.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<TPopupPage>`
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<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
// 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
`<ViewModelClassNameHere>.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:
`<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)> `
- Helper/tool windows
- Document windows
- Settings panels
- Floating utility windows
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
### API
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`
```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<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`
### Platform Implementation Details
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.
| 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<YourXamlPopupPage>()`
## 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 -->
## License
This project uses the MIT License
<!-- CONTACT -->
## 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.*