Limited
2
0

feat(ci): add supporter verification and auto-hide functionality
Some checks failed
Release / Verify Apple Build (push) Successful in 14s
Release / Build & Pack (push) Successful in 8h59m34s
Release / Publish (push) Failing after 16s

Implement BmcSupporterService to verify supporters via BMC API with configurable caching. Add SupporterEmail and HideIfSupporter properties to all controls to automatically hide donation prompts for existing supporters. Replace PNG logo with SVG for crisp rendering at all scales. Add BmcOptions and BmcConfiguration for library-wide settings. Bump version to 1.1.0.
This commit is contained in:
2026-03-04 00:35:05 -05:00
parent 7ec645b9a6
commit 66c8ec8ecf
12 changed files with 436 additions and 329 deletions

433
README.md
View File

@@ -3,7 +3,7 @@
[![.NET MAUI](https://img.shields.io/badge/.NET%20MAUI-10.0-512BD4?logo=dotnet)](https://dotnet.microsoft.com/apps/maui)
[![Platform](https://img.shields.io/badge/platform-Android%20%7C%20iOS%20%7C%20macOS%20%7C%20Windows-blue)](https://dotnet.microsoft.com/apps/maui)
[![License](https://img.shields.io/badge/license-MIT-green)](LICENSE)
[![NuGet](https://img.shields.io/badge/nuget-coming%20soon-orange)](https://www.nuget.org)
[![NuGet](https://img.shields.io/badge/nuget-v1.1.0-blue)](https://git.marketally.com/misc/bmc.maui/packages)
A comprehensive .NET MAUI library for integrating Buy Me a Coffee support into your cross-platform applications. Provides branded buttons, QR codes, and interactive widgets with official BMC styling and theming.
@@ -16,6 +16,7 @@ A comprehensive .NET MAUI library for integrating Buy Me a Coffee support into y
- [BuyMeACoffeeButton](#buymeacoffeebutton)
- [BuyMeACoffeeQrCode](#buymeacoffeeqrcode)
- [BuyMeACoffeeWidget](#buymeacoffeewidget)
- [Supporter Verification](#supporter-verification)
- [Theming](#theming)
- [API Reference](#api-reference)
- [Platform Support](#platform-support)
@@ -26,14 +27,15 @@ A comprehensive .NET MAUI library for integrating Buy Me a Coffee support into y
## Features
**BuyMeACoffeeButton** - Branded button with official coffee cup logo and 8 color themes
**BuyMeACoffeeQrCode** - QR code generator with embedded BMC logo overlay
**BuyMeACoffeeWidget** - Full-featured support widget with amount selection, name/message fields, and monthly toggle
**Official Branding** - Uses authentic Buy Me a Coffee colors, logos, and styling
**Cross-Platform** - Supports Android, iOS, macOS, and Windows
**Customizable** - Extensive theming and styling options
**Touch Optimized** - Smooth animations and hover effects
**QR Code Generation** - High-quality QR codes with error correction level H
- **BuyMeACoffeeButton** - Branded button with official coffee cup logo and 8 color themes
- **BuyMeACoffeeQrCode** - QR code generator with embedded BMC logo overlay
- **BuyMeACoffeeWidget** - Full-featured support widget with amount selection, name/message fields, and monthly toggle
- **Official Branding** - Crisp SVG-based logos via MAUI asset pipeline, authentic Buy Me a Coffee colors and styling
- **Supporter Verification** - Auto-hide controls for users who have already supported you via the BMC API
- **Cross-Platform** - Supports Android, iOS, macOS, and Windows
- **Customizable** - Extensive theming and styling options
- **Touch Optimized** - Smooth animations and hover effects
- **QR Code Generation** - High-quality QR codes with error correction level H
## Installation
@@ -41,19 +43,33 @@ A comprehensive .NET MAUI library for integrating Buy Me a Coffee support into y
- .NET 10.0 SDK or later
- .NET MAUI workload installed
- Visual Studio 2022 17.8+ or Visual Studio Code with .NET MAUI extension
### Add to Your Project
### NuGet Package
1. **Add the project reference** to your .NET MAUI application:
Add the MarketAlly NuGet source to your `NuGet.config`:
```xml
<ItemGroup>
<ProjectReference Include="..\BuyMeCofee.Maui\BuyMeCofee.Maui.csproj" />
</ItemGroup>
<configuration>
<packageSources>
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
<add key="MarketAlly" value="https://git.marketally.com/api/packages/misc/nuget/index.json" />
</packageSources>
</configuration>
```
2. **Register the library** in your `MauiProgram.cs`:
Then add the package reference:
```xml
<PackageReference Include="BuyMeCofee.Maui" Version="1.1.0" />
```
Or via CLI:
```bash
dotnet add package BuyMeCofee.Maui --version 1.1.0
```
### Register in MauiProgram.cs
```csharp
using BuyMeCofee.Maui;
@@ -66,7 +82,7 @@ public static class MauiProgram
builder
.UseMauiApp<App>()
.UseBuyMeACoffee(); // Add this line
return builder.Build();
}
}
@@ -85,7 +101,7 @@ xmlns:bmc="clr-namespace:BuyMeCofee.Maui.Controls;assembly=BuyMeCofee.Maui"
Add a button to your page:
```xml
<bmc:BuyMeACoffeeButton
<bmc:BuyMeACoffeeButton
Username="yourname"
ButtonText="Buy me a coffee"
Theme="Yellow" />
@@ -100,7 +116,7 @@ A branded button that opens your Buy Me a Coffee page in the default browser.
#### Basic Usage
```xml
<bmc:BuyMeACoffeeButton
<bmc:BuyMeACoffeeButton
Username="yourname"
Theme="Yellow" />
```
@@ -108,7 +124,7 @@ A branded button that opens your Buy Me a Coffee page in the default browser.
#### With Custom Styling
```xml
<bmc:BuyMeACoffeeButton
<bmc:BuyMeACoffeeButton
Username="yourname"
ButtonText="Support My Work"
Theme="Violet"
@@ -121,7 +137,7 @@ A branded button that opens your Buy Me a Coffee page in the default browser.
#### Custom Theme
```xml
<bmc:BuyMeACoffeeButton
<bmc:BuyMeACoffeeButton
Username="yourname"
Theme="Custom"
CustomBackgroundColor="#FF6B6B"
@@ -129,37 +145,20 @@ A branded button that opens your Buy Me a Coffee page in the default browser.
ButtonText="Donate" />
```
#### Code-Behind Example
```csharp
using BuyMeCofee.Maui.Controls;
using BuyMeCofee.Maui.Enums;
var button = new BuyMeACoffeeButton
{
Username = "yourname",
ButtonText = "Buy me a coffee",
Theme = BmcButtonTheme.Blue,
CornerRadius = 10,
FontSize = 16,
CupSize = 28
};
layout.Children.Add(button);
```
#### Properties
| Property | Type | Default | Description |
|----------|------|---------|-------------|
| `Username` | `string` | `""` | Your Buy Me a Coffee username/slug |
| `ButtonText` | `string` | `"Buy me a coffee"` | Button label text |
| `Theme` | `BmcButtonTheme` | `Yellow` | Color theme preset (Yellow, Black, White, Blue, Violet, Orange, Red, Green, Custom) |
| `Theme` | `BmcButtonTheme` | `Yellow` | Color theme preset |
| `CustomBackgroundColor` | `Color?` | `null` | Background color (Custom theme only) |
| `CustomTextColor` | `Color?` | `null` | Text color (Custom theme only) |
| `CornerRadius` | `double` | `8.0` | Border corner radius |
| `FontSize` | `double` | `16.0` | Button text font size |
| `CupSize` | `double` | `28.0` | Coffee cup logo height |
| `SupporterEmail` | `string?` | `null` | Email to check against supporters list |
| `HideIfSupporter` | `bool` | `false` | Auto-hide if email is a verified supporter |
### BuyMeACoffeeQrCode
@@ -168,7 +167,7 @@ Generates a QR code linking to your BMC profile with the coffee cup logo overlai
#### Basic Usage
```xml
<bmc:BuyMeACoffeeQrCode
<bmc:BuyMeACoffeeQrCode
Username="yourname"
Size="250" />
```
@@ -176,7 +175,7 @@ Generates a QR code linking to your BMC profile with the coffee cup logo overlai
#### With Custom Colors
```xml
<bmc:BuyMeACoffeeQrCode
<bmc:BuyMeACoffeeQrCode
Username="yourname"
Size="300"
ForegroundColor="DarkBlue"
@@ -184,23 +183,6 @@ Generates a QR code linking to your BMC profile with the coffee cup logo overlai
LogoSizeFraction="0.3" />
```
#### Code-Behind Example
```csharp
using BuyMeCofee.Maui.Controls;
var qrCode = new BuyMeACoffeeQrCode
{
Username = "yourname",
Size = 250,
ForegroundColor = Colors.Black,
BackgroundColor = Colors.White,
LogoSizeFraction = 0.25
};
layout.Children.Add(qrCode);
```
#### Properties
| Property | Type | Default | Description |
@@ -210,6 +192,8 @@ layout.Children.Add(qrCode);
| `ForegroundColor` | `Color` | `Black` | QR code module color |
| `BackgroundColor` | `Color` | `White` | QR code background color |
| `LogoSizeFraction` | `double` | `0.25` | Logo size as fraction of QR code (0.0-0.35) |
| `SupporterEmail` | `string?` | `null` | Email to check against supporters list |
| `HideIfSupporter` | `bool` | `false` | Auto-hide if email is a verified supporter |
### BuyMeACoffeeWidget
@@ -218,7 +202,7 @@ A full-featured support widget with amount entry, preset chips, name/message fie
#### Basic Usage
```xml
<bmc:BuyMeACoffeeWidget
<bmc:BuyMeACoffeeWidget
Username="yourname"
DisplayName="John Doe" />
```
@@ -226,7 +210,7 @@ A full-featured support widget with amount entry, preset chips, name/message fie
#### With Custom Configuration
```xml
<bmc:BuyMeACoffeeWidget
<bmc:BuyMeACoffeeWidget
Username="yourname"
DisplayName="John Doe"
DefaultAmount="10"
@@ -239,14 +223,6 @@ A full-featured support widget with amount entry, preset chips, name/message fie
#### Handling Support Events
```xml
<bmc:BuyMeACoffeeWidget
x:Name="supportWidget"
Username="yourname"
DisplayName="John Doe"
SupportRequested="OnSupportRequested" />
```
```csharp
private void OnSupportRequested(object sender, SupportRequestedEventArgs e)
{
@@ -254,37 +230,9 @@ private void OnSupportRequested(object sender, SupportRequestedEventArgs e)
Console.WriteLine($"Amount: ${e.Amount}");
Console.WriteLine($"Message: {e.Message ?? "No message"}");
Console.WriteLine($"Monthly: {e.IsMonthly}");
// Log analytics, show confirmation, etc.
}
```
#### Code-Behind Example
```csharp
using BuyMeCofee.Maui.Controls;
using BuyMeCofee.Maui.Models;
var widget = new BuyMeACoffeeWidget
{
Username = "yourname",
DisplayName = "John Doe",
DefaultAmount = 5,
SuggestedAmounts = new[] { 25, 50, 100 },
AccentColor = Color.FromArgb("#6C5CE7"),
ShowMonthlyOption = true,
SupportButtonText = "Support"
};
widget.SupportRequested += (sender, e) =>
{
// Handle support request
Debug.WriteLine($"Amount: ${e.Amount}, Monthly: {e.IsMonthly}");
};
layout.Children.Add(widget);
```
#### Properties
| Property | Type | Default | Description |
@@ -296,6 +244,8 @@ layout.Children.Add(widget);
| `AccentColor` | `Color` | `#6C5CE7` | Support button background color |
| `ShowMonthlyOption` | `bool` | `true` | Show "Make this monthly" checkbox |
| `SupportButtonText` | `string` | `"Support"` | Support button label text |
| `SupporterEmail` | `string?` | `null` | Email to check against supporters list |
| `HideIfSupporter` | `bool` | `false` | Auto-hide if email is a verified supporter |
#### Events
@@ -308,19 +258,53 @@ layout.Children.Add(widget);
```csharp
public class SupportRequestedEventArgs : EventArgs
{
public string Username { get; init; } // BMC username
public int Amount { get; init; } // Support amount
public string? Name { get; init; } // Supporter name (optional)
public string? Message { get; init; } // Support message (optional)
public bool IsMonthly { get; init; } // Monthly subscription toggle
public string Username { get; init; }
public int Amount { get; init; }
public string? Name { get; init; }
public string? Message { get; init; }
public bool IsMonthly { get; init; }
}
```
## Supporter Verification
The library can automatically check if a user has already supported you via the Buy Me a Coffee API. When verified, controls can auto-hide themselves — useful for removing donation prompts for existing supporters.
### Setup
Get your API access token from [Buy Me a Coffee Developer Dashboard](https://developers.buymeacoffee.com/).
Configure the token in `MauiProgram.cs`:
```csharp
builder.UseBuyMeACoffee(options =>
{
options.AccessToken = "your_bmc_api_token";
options.CacheDuration = TimeSpan.FromHours(1); // default
});
```
### Usage
Add `SupporterEmail` and `HideIfSupporter` to any control:
```xml
<bmc:BuyMeACoffeeButton
Username="yourname"
Theme="Yellow"
SupporterEmail="{Binding CurrentUserEmail}"
HideIfSupporter="True" />
```
When `HideIfSupporter` is `true` and the email matches a one-time supporter or active member, the control sets `IsVisible = false`.
The service queries both `/api/v1/supporters` (one-time) and `/api/v1/subscriptions` (members) endpoints, caches results in memory, and fails silently if the API is unreachable.
## Theming
### Button Themes
The library includes 8 official Buy Me a Coffee color themes:
The library includes 8 official Buy Me a Coffee color themes plus a custom option:
```csharp
public enum BmcButtonTheme
@@ -337,38 +321,15 @@ public enum BmcButtonTheme
}
```
### Theme Examples
```xml
<!-- Official Yellow Theme -->
<bmc:BuyMeACoffeeButton Username="yourname" Theme="Yellow" />
<!-- Dark Theme -->
<bmc:BuyMeACoffeeButton Username="yourname" Theme="Black" />
<!-- Light Theme with Border -->
<bmc:BuyMeACoffeeButton Username="yourname" Theme="White" />
<!-- Violet Theme -->
<bmc:BuyMeACoffeeButton Username="yourname" Theme="Violet" />
<!-- Custom Theme -->
<bmc:BuyMeACoffeeButton
Username="yourname"
Theme="Custom"
CustomBackgroundColor="#FF1744"
CustomTextColor="White" />
```
### Brand Colors Reference
```csharp
public static class BmcColors
{
public const string CupYellow = "#FFDD00"; // Official cup color
public const string BrandDark = "#0D0C22"; // Brand dark
public const string WidgetPurple = "#6C5CE7"; // Widget accent
public const string WhiteStroke = "#E0E0E0"; // Border color
public const string CupYellow = "#FFDD00";
public const string BrandDark = "#0D0C22";
public const string WidgetPurple = "#6C5CE7";
public const string WhiteStroke = "#E0E0E0";
}
```
@@ -377,40 +338,20 @@ public static class BmcColors
### Extension Methods
```csharp
public static class BuyMeACoffeeExtensions
{
/// <summary>
/// Registers Buy Me a Coffee controls and their dependencies (SkiaSharp).
/// Call this in your MauiProgram.cs CreateMauiApp() builder.
/// </summary>
public static MauiAppBuilder UseBuyMeACoffee(this MauiAppBuilder builder);
}
// Basic registration (no API features)
public static MauiAppBuilder UseBuyMeACoffee(this MauiAppBuilder builder);
// With API configuration (enables supporter verification)
public static MauiAppBuilder UseBuyMeACoffee(this MauiAppBuilder builder, Action<BmcOptions> configure);
```
### Helper Classes
#### BmcThemeResolver
### BmcOptions
```csharp
public static class BmcThemeResolver
public class BmcOptions
{
/// <summary>
/// Resolves a BmcButtonTheme enum to theme colors.
/// </summary>
/// <exception cref="InvalidOperationException">Thrown for Custom theme</exception>
public static BmcThemeInfo Resolve(BmcButtonTheme theme);
}
public record BmcThemeInfo(Color Background, Color TextColor, Color StrokeColor);
```
#### BmcBrandAssets
```csharp
internal static class BmcBrandAssets
{
internal static ImageSource GetCupLogo();
internal static Stream GetCupLogoStream();
public string? AccessToken { get; set; }
public TimeSpan CacheDuration { get; set; } = TimeSpan.FromHours(1);
}
```
@@ -432,189 +373,33 @@ public static class BmcConstants
| Platform | Minimum Version | Status |
|----------|----------------|--------|
| **Android** | API 21 (Android 5.0) | Supported |
| **iOS** | 15.0+ | Supported |
| **macOS** (Catalyst) | 15.0+ | Supported |
| **Windows** | 10.0.17763.0+ | Supported |
**Note:** On Linux, only Android targets are built by default. iOS and macOS Catalyst require macOS build environment.
| **Android** | API 21 (Android 5.0) | Supported |
| **iOS** | 15.0+ | Supported |
| **macOS** (Catalyst) | 15.0+ | Supported |
| **Windows** | 10.0.17763.0+ | Supported |
## Dependencies
The library requires the following NuGet packages:
```xml
<PackageReference Include="Microsoft.Maui.Controls" Version="$(MauiVersion)" />
<PackageReference Include="QRCoder" Version="1.6.0" />
<PackageReference Include="SkiaSharp.Views.Maui.Controls" Version="3.116.1" />
```
These are automatically installed when you reference the project.
## Support This Project
## Examples
If this library saved you time, consider buying me a coffee:
### Complete Page Example
```xml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:bmc="clr-namespace:BuyMeCofee.Maui.Controls;assembly=BuyMeCofee.Maui"
x:Class="MyApp.SupportPage"
Title="Support">
<ScrollView>
<VerticalStackLayout Spacing="20" Padding="20">
<!-- Button Examples -->
<Label Text="Button Themes" FontSize="20" FontAttributes="Bold" />
<bmc:BuyMeACoffeeButton
Username="yourname"
Theme="Yellow"
HorizontalOptions="Center" />
<bmc:BuyMeACoffeeButton
Username="yourname"
Theme="Violet"
ButtonText="Support My Work"
HorizontalOptions="Center" />
<!-- QR Code -->
<Label Text="QR Code" FontSize="20" FontAttributes="Bold" Margin="0,20,0,0" />
<bmc:BuyMeACoffeeQrCode
Username="yourname"
Size="250"
HorizontalOptions="Center" />
<!-- Widget -->
<Label Text="Support Widget" FontSize="20" FontAttributes="Bold" Margin="0,20,0,0" />
<bmc:BuyMeACoffeeWidget
Username="yourname"
DisplayName="John Doe"
DefaultAmount="10"
SuggestedAmounts="10,25,50"
SupportRequested="OnSupportRequested"
HorizontalOptions="Center" />
</VerticalStackLayout>
</ScrollView>
</ContentPage>
```
### Dynamic Theme Switching
```csharp
using BuyMeCofee.Maui.Controls;
using BuyMeCofee.Maui.Enums;
public partial class ThemePage : ContentPage
{
private BuyMeACoffeeButton _button;
private readonly BmcButtonTheme[] _themes =
{
BmcButtonTheme.Yellow,
BmcButtonTheme.Black,
BmcButtonTheme.Blue,
BmcButtonTheme.Violet,
BmcButtonTheme.Orange,
BmcButtonTheme.Red,
BmcButtonTheme.Green
};
private int _currentThemeIndex = 0;
public ThemePage()
{
InitializeComponent();
_button = new BuyMeACoffeeButton
{
Username = "yourname",
Theme = _themes[0]
};
var switchButton = new Button { Text = "Change Theme" };
switchButton.Clicked += OnSwitchTheme;
var layout = new VerticalStackLayout
{
Spacing = 20,
Padding = 20,
Children = { _button, switchButton }
};
Content = layout;
}
private void OnSwitchTheme(object sender, EventArgs e)
{
_currentThemeIndex = (_currentThemeIndex + 1) % _themes.Length;
_button.Theme = _themes[_currentThemeIndex];
}
}
```
### Analytics Integration
```csharp
using BuyMeCofee.Maui.Controls;
using BuyMeCofee.Maui.Models;
public partial class AnalyticsPage : ContentPage
{
public AnalyticsPage()
{
InitializeComponent();
var widget = new BuyMeACoffeeWidget
{
Username = "yourname",
DisplayName = "John Doe"
};
widget.SupportRequested += OnSupportRequested;
Content = widget;
}
private void OnSupportRequested(object sender, SupportRequestedEventArgs e)
{
// Log to analytics service
AnalyticsService.TrackEvent("SupportRequested", new Dictionary<string, string>
{
{ "username", e.Username },
{ "amount", e.Amount.ToString() },
{ "is_monthly", e.IsMonthly.ToString() },
{ "has_name", (!string.IsNullOrEmpty(e.Name)).ToString() },
{ "has_message", (!string.IsNullOrEmpty(e.Message)).ToString() }
});
// Show confirmation
DisplayAlert("Thank You!",
$"You're about to support with ${e.Amount}. Redirecting to Buy Me a Coffee...",
"OK");
}
}
```
[![Buy Me a Coffee](https://img.shields.io/badge/Buy%20Me%20a%20Coffee-FFDD00?style=for-the-badge&logo=buy-me-a-coffee&logoColor=black)](https://buymeacoffee.com/logikonline)
## Contributing
Contributions are welcome! Please feel free to submit issues, feature requests, or pull requests.
### Development Setup
1. Clone the repository
2. Open in Visual Studio 2022 or VS Code
3. Ensure .NET MAUI workload is installed
4. Build and run the sample project
## License
This project is licensed under the MIT License. See the LICENSE file for details.
---
**Not affiliated with Buy Me a Coffee.** This is an unofficial community library. Buy Me a Coffee and its branding are trademarks of Buy Me a Coffee LLC.
**Not affiliated with Buy Me a Coffee.** This is an unofficial community library. Buy Me a Coffee and its branding are trademarks of Buy Me a Coffee LLC.