feat(scenarios): add buy me a coffee maui library
Create a .NET MAUI library for Buy Me a Coffee integration with branded button, QR code, and widget controls. Includes 8 theme presets (yellow, black, white, blue, violet, orange, red, green), customizable styling, and SkiaSharp-based rendering. Supports opening BMC pages in browser and generating QR codes for donations.
2026-03-03 23:19:45 -05:00
|
|
|
using BuyMeCofee.Maui.Constants;
|
|
|
|
|
using BuyMeCofee.Maui.Helpers;
|
|
|
|
|
using BuyMeCofee.Maui.Models;
|
|
|
|
|
using Microsoft.Maui.Controls.Shapes;
|
|
|
|
|
|
|
|
|
|
namespace BuyMeCofee.Maui.Controls;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// A branded Buy Me a Coffee support widget with amount entry, preset chips,
|
|
|
|
|
/// name/message fields, and a monthly toggle. Opens the BMC page on support tap.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public class BuyMeACoffeeWidget : ContentView
|
|
|
|
|
{
|
|
|
|
|
#region Bindable Properties
|
|
|
|
|
|
|
|
|
|
public static readonly BindableProperty UsernameProperty =
|
|
|
|
|
BindableProperty.Create(nameof(Username), typeof(string), typeof(BuyMeACoffeeWidget),
|
|
|
|
|
string.Empty, propertyChanged: OnUsernameChanged);
|
|
|
|
|
|
|
|
|
|
public static readonly BindableProperty DisplayNameProperty =
|
|
|
|
|
BindableProperty.Create(nameof(DisplayName), typeof(string), typeof(BuyMeACoffeeWidget),
|
|
|
|
|
string.Empty, propertyChanged: OnDisplayNameChanged);
|
|
|
|
|
|
|
|
|
|
public static readonly BindableProperty SuggestedAmountsProperty =
|
|
|
|
|
BindableProperty.Create(nameof(SuggestedAmounts), typeof(int[]), typeof(BuyMeACoffeeWidget),
|
|
|
|
|
BmcConstants.DefaultSuggestedAmounts, propertyChanged: OnChipsChanged);
|
|
|
|
|
|
|
|
|
|
public static readonly BindableProperty DefaultAmountProperty =
|
|
|
|
|
BindableProperty.Create(nameof(DefaultAmount), typeof(int), typeof(BuyMeACoffeeWidget),
|
|
|
|
|
5, propertyChanged: OnDefaultAmountChanged);
|
|
|
|
|
|
|
|
|
|
public static readonly BindableProperty AccentColorProperty =
|
|
|
|
|
BindableProperty.Create(nameof(AccentColor), typeof(Color), typeof(BuyMeACoffeeWidget),
|
|
|
|
|
Color.FromArgb(BmcColors.WidgetPurple), propertyChanged: OnAccentChanged);
|
|
|
|
|
|
|
|
|
|
public static readonly BindableProperty ShowMonthlyOptionProperty =
|
|
|
|
|
BindableProperty.Create(nameof(ShowMonthlyOption), typeof(bool), typeof(BuyMeACoffeeWidget),
|
|
|
|
|
true, propertyChanged: OnShowMonthlyChanged);
|
|
|
|
|
|
|
|
|
|
public static readonly BindableProperty SupportButtonTextProperty =
|
|
|
|
|
BindableProperty.Create(nameof(SupportButtonText), typeof(string), typeof(BuyMeACoffeeWidget),
|
|
|
|
|
BmcConstants.DefaultSupportButtonText);
|
|
|
|
|
|
2026-03-04 00:35:05 -05:00
|
|
|
public static readonly BindableProperty SupporterEmailProperty =
|
|
|
|
|
BindableProperty.Create(nameof(SupporterEmail), typeof(string), typeof(BuyMeACoffeeWidget),
|
|
|
|
|
null, propertyChanged: OnSupporterPropertyChanged);
|
|
|
|
|
|
|
|
|
|
public static readonly BindableProperty HideIfSupporterProperty =
|
|
|
|
|
BindableProperty.Create(nameof(HideIfSupporter), typeof(bool), typeof(BuyMeACoffeeWidget),
|
|
|
|
|
false, propertyChanged: OnSupporterPropertyChanged);
|
|
|
|
|
|
feat(scenarios): add buy me a coffee maui library
Create a .NET MAUI library for Buy Me a Coffee integration with branded button, QR code, and widget controls. Includes 8 theme presets (yellow, black, white, blue, violet, orange, red, green), customizable styling, and SkiaSharp-based rendering. Supports opening BMC pages in browser and generating QR codes for donations.
2026-03-03 23:19:45 -05:00
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Properties
|
|
|
|
|
|
|
|
|
|
/// <summary>Your Buy Me a Coffee username/slug.</summary>
|
|
|
|
|
public string Username
|
|
|
|
|
{
|
|
|
|
|
get => (string)GetValue(UsernameProperty);
|
|
|
|
|
set => SetValue(UsernameProperty, value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>Name displayed in "Support {DisplayName}" header.</summary>
|
|
|
|
|
public string DisplayName
|
|
|
|
|
{
|
|
|
|
|
get => (string)GetValue(DisplayNameProperty);
|
|
|
|
|
set => SetValue(DisplayNameProperty, value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>Preset amount chips. Default: [25, 50, 100]</summary>
|
|
|
|
|
public int[] SuggestedAmounts
|
|
|
|
|
{
|
|
|
|
|
get => (int[])GetValue(SuggestedAmountsProperty);
|
|
|
|
|
set => SetValue(SuggestedAmountsProperty, value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>Initial amount in the entry field. Default: 5</summary>
|
|
|
|
|
public int DefaultAmount
|
|
|
|
|
{
|
|
|
|
|
get => (int)GetValue(DefaultAmountProperty);
|
|
|
|
|
set => SetValue(DefaultAmountProperty, value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>Accent color for the Support button. Default: BMC purple (#6C5CE7)</summary>
|
|
|
|
|
public Color AccentColor
|
|
|
|
|
{
|
|
|
|
|
get => (Color)GetValue(AccentColorProperty);
|
|
|
|
|
set => SetValue(AccentColorProperty, value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>Whether to show the "Make this monthly" checkbox. Default: true</summary>
|
|
|
|
|
public bool ShowMonthlyOption
|
|
|
|
|
{
|
|
|
|
|
get => (bool)GetValue(ShowMonthlyOptionProperty);
|
|
|
|
|
set => SetValue(ShowMonthlyOptionProperty, value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>Text on the support button. Default: "Support"</summary>
|
|
|
|
|
public string SupportButtonText
|
|
|
|
|
{
|
|
|
|
|
get => (string)GetValue(SupportButtonTextProperty);
|
|
|
|
|
set => SetValue(SupportButtonTextProperty, value);
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-04 00:35:05 -05:00
|
|
|
/// <summary>
|
|
|
|
|
/// Email address to check against your BMC supporters list.
|
|
|
|
|
/// Requires AccessToken configured via UseBuyMeACoffee(options => ...).
|
|
|
|
|
/// </summary>
|
|
|
|
|
public string? SupporterEmail
|
|
|
|
|
{
|
|
|
|
|
get => (string?)GetValue(SupporterEmailProperty);
|
|
|
|
|
set => SetValue(SupporterEmailProperty, value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// When true, the control auto-hides if SupporterEmail is a verified supporter. Default: false.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public bool HideIfSupporter
|
|
|
|
|
{
|
|
|
|
|
get => (bool)GetValue(HideIfSupporterProperty);
|
|
|
|
|
set => SetValue(HideIfSupporterProperty, value);
|
|
|
|
|
}
|
|
|
|
|
|
feat(scenarios): add buy me a coffee maui library
Create a .NET MAUI library for Buy Me a Coffee integration with branded button, QR code, and widget controls. Includes 8 theme presets (yellow, black, white, blue, violet, orange, red, green), customizable styling, and SkiaSharp-based rendering. Supports opening BMC pages in browser and generating QR codes for donations.
2026-03-03 23:19:45 -05:00
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
/// <summary>Raised when the user taps the Support button, before opening the browser.</summary>
|
|
|
|
|
public event EventHandler<SupportRequestedEventArgs>? SupportRequested;
|
|
|
|
|
|
|
|
|
|
// Internal UI elements
|
|
|
|
|
private Label _headerLabel = null!;
|
|
|
|
|
private Entry _amountEntry = null!;
|
|
|
|
|
private HorizontalStackLayout _chipsRow = null!;
|
|
|
|
|
private Entry _nameEntry = null!;
|
|
|
|
|
private Editor _messageEditor = null!;
|
|
|
|
|
private CheckBox _monthlyCheckBox = null!;
|
|
|
|
|
private HorizontalStackLayout _monthlyRow = null!;
|
|
|
|
|
private Border _supportButton = null!;
|
|
|
|
|
private Label _supportButtonLabel = null!;
|
|
|
|
|
private Label _footerLabel = null!;
|
|
|
|
|
|
|
|
|
|
private int _currentAmount;
|
|
|
|
|
|
|
|
|
|
public BuyMeACoffeeWidget()
|
|
|
|
|
{
|
|
|
|
|
_currentAmount = DefaultAmount;
|
|
|
|
|
BuildLayout();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void BuildLayout()
|
|
|
|
|
{
|
|
|
|
|
// Header
|
|
|
|
|
_headerLabel = new Label
|
|
|
|
|
{
|
|
|
|
|
Text = string.IsNullOrWhiteSpace(DisplayName) ? "Support" : $"Support {DisplayName}",
|
|
|
|
|
FontSize = 20,
|
|
|
|
|
FontAttributes = FontAttributes.Bold,
|
|
|
|
|
Margin = new Thickness(0, 0, 0, 8),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Amount row: $ + Entry + chips
|
|
|
|
|
var dollarLabel = new Label
|
|
|
|
|
{
|
|
|
|
|
Text = "$",
|
|
|
|
|
FontSize = 18,
|
|
|
|
|
VerticalOptions = LayoutOptions.Center,
|
|
|
|
|
TextColor = Colors.Gray,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
_amountEntry = new Entry
|
|
|
|
|
{
|
|
|
|
|
Text = _currentAmount.ToString(),
|
|
|
|
|
Keyboard = Keyboard.Numeric,
|
|
|
|
|
FontSize = 16,
|
|
|
|
|
Placeholder = "Enter amount",
|
|
|
|
|
HorizontalOptions = LayoutOptions.Fill,
|
|
|
|
|
VerticalOptions = LayoutOptions.Center,
|
|
|
|
|
};
|
|
|
|
|
_amountEntry.TextChanged += OnAmountTextChanged;
|
|
|
|
|
|
|
|
|
|
_chipsRow = new HorizontalStackLayout { Spacing = 6 };
|
|
|
|
|
BuildChips();
|
|
|
|
|
|
|
|
|
|
var amountRow = new Grid
|
|
|
|
|
{
|
|
|
|
|
ColumnDefinitions =
|
|
|
|
|
{
|
|
|
|
|
new ColumnDefinition(GridLength.Auto),
|
|
|
|
|
new ColumnDefinition(GridLength.Star),
|
|
|
|
|
new ColumnDefinition(GridLength.Auto),
|
|
|
|
|
},
|
|
|
|
|
ColumnSpacing = 8,
|
|
|
|
|
VerticalOptions = LayoutOptions.Center,
|
|
|
|
|
};
|
|
|
|
|
amountRow.Add(dollarLabel, 0);
|
|
|
|
|
amountRow.Add(_amountEntry, 1);
|
|
|
|
|
amountRow.Add(_chipsRow, 2);
|
|
|
|
|
|
|
|
|
|
var amountBorder = CreateFieldBorder(amountRow);
|
|
|
|
|
|
|
|
|
|
// Name field
|
|
|
|
|
_nameEntry = new Entry
|
|
|
|
|
{
|
|
|
|
|
Placeholder = "Name or @yoursocial",
|
|
|
|
|
FontSize = 14,
|
|
|
|
|
};
|
|
|
|
|
var nameBorder = CreateFieldBorder(_nameEntry);
|
|
|
|
|
|
|
|
|
|
// Message field
|
|
|
|
|
_messageEditor = new Editor
|
|
|
|
|
{
|
|
|
|
|
Placeholder = "Say something nice...",
|
|
|
|
|
FontSize = 14,
|
|
|
|
|
HeightRequest = 80,
|
|
|
|
|
AutoSize = EditorAutoSizeOption.TextChanges,
|
|
|
|
|
};
|
|
|
|
|
var messageBorder = CreateFieldBorder(_messageEditor);
|
|
|
|
|
|
|
|
|
|
// Monthly toggle
|
|
|
|
|
_monthlyCheckBox = new CheckBox
|
|
|
|
|
{
|
|
|
|
|
VerticalOptions = LayoutOptions.Center,
|
|
|
|
|
};
|
|
|
|
|
var monthlyLabel = new Label
|
|
|
|
|
{
|
|
|
|
|
Text = "Make this monthly",
|
|
|
|
|
FontSize = 14,
|
|
|
|
|
VerticalOptions = LayoutOptions.Center,
|
|
|
|
|
};
|
|
|
|
|
_monthlyRow = new HorizontalStackLayout
|
|
|
|
|
{
|
|
|
|
|
Spacing = 4,
|
|
|
|
|
IsVisible = ShowMonthlyOption,
|
|
|
|
|
Children = { _monthlyCheckBox, monthlyLabel }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Support button
|
|
|
|
|
_supportButtonLabel = new Label
|
|
|
|
|
{
|
|
|
|
|
Text = SupportButtonText,
|
|
|
|
|
FontSize = 16,
|
|
|
|
|
FontAttributes = FontAttributes.Bold,
|
|
|
|
|
TextColor = Colors.White,
|
|
|
|
|
HorizontalOptions = LayoutOptions.Center,
|
|
|
|
|
VerticalOptions = LayoutOptions.Center,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
_supportButton = new Border
|
|
|
|
|
{
|
|
|
|
|
BackgroundColor = AccentColor,
|
|
|
|
|
StrokeShape = new RoundRectangle { CornerRadius = new Microsoft.Maui.CornerRadius(24) },
|
|
|
|
|
Stroke = Colors.Transparent,
|
|
|
|
|
Padding = new Thickness(0, 14),
|
|
|
|
|
HorizontalOptions = LayoutOptions.Fill,
|
|
|
|
|
Content = _supportButtonLabel,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var supportTap = new TapGestureRecognizer();
|
|
|
|
|
supportTap.Tapped += OnSupportTapped;
|
|
|
|
|
_supportButton.GestureRecognizers.Add(supportTap);
|
|
|
|
|
|
|
|
|
|
var supportHover = new PointerGestureRecognizer();
|
|
|
|
|
supportHover.PointerEntered += (_, _) => _supportButton.Opacity = 0.85;
|
|
|
|
|
supportHover.PointerExited += (_, _) => _supportButton.Opacity = 1.0;
|
|
|
|
|
_supportButton.GestureRecognizers.Add(supportHover);
|
|
|
|
|
|
|
|
|
|
// Redirect note
|
|
|
|
|
var redirectNote = new Label
|
|
|
|
|
{
|
|
|
|
|
Text = "You'll complete your support on buymeacoffee.com",
|
|
|
|
|
FontSize = 11,
|
|
|
|
|
TextColor = Colors.Gray,
|
|
|
|
|
HorizontalOptions = LayoutOptions.Center,
|
|
|
|
|
Margin = new Thickness(0, -4, 0, 0),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Footer
|
|
|
|
|
var footerCup = new Image
|
|
|
|
|
{
|
|
|
|
|
Source = BmcBrandAssets.GetCupLogo(),
|
|
|
|
|
HeightRequest = 16,
|
|
|
|
|
Aspect = Aspect.AspectFit,
|
|
|
|
|
VerticalOptions = LayoutOptions.Center,
|
|
|
|
|
};
|
|
|
|
|
_footerLabel = new Label
|
|
|
|
|
{
|
|
|
|
|
Text = $"buymeacoffee.com/{Username}",
|
|
|
|
|
FontSize = 12,
|
|
|
|
|
TextColor = Colors.Gray,
|
|
|
|
|
VerticalOptions = LayoutOptions.Center,
|
|
|
|
|
TextDecorations = TextDecorations.Underline,
|
|
|
|
|
};
|
|
|
|
|
var footerStack = new HorizontalStackLayout
|
|
|
|
|
{
|
|
|
|
|
Spacing = 4,
|
|
|
|
|
HorizontalOptions = LayoutOptions.Center,
|
|
|
|
|
Children = { footerCup, _footerLabel }
|
|
|
|
|
};
|
|
|
|
|
var footerTap = new TapGestureRecognizer();
|
|
|
|
|
footerTap.Tapped += OnFooterTapped;
|
|
|
|
|
footerStack.GestureRecognizers.Add(footerTap);
|
|
|
|
|
|
|
|
|
|
// Card layout
|
|
|
|
|
var cardContent = new VerticalStackLayout
|
|
|
|
|
{
|
|
|
|
|
Spacing = 12,
|
|
|
|
|
Padding = new Thickness(20),
|
|
|
|
|
Children =
|
|
|
|
|
{
|
|
|
|
|
_headerLabel,
|
|
|
|
|
amountBorder,
|
|
|
|
|
nameBorder,
|
|
|
|
|
messageBorder,
|
|
|
|
|
_monthlyRow,
|
|
|
|
|
_supportButton,
|
|
|
|
|
redirectNote,
|
|
|
|
|
footerStack,
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var card = new Border
|
|
|
|
|
{
|
|
|
|
|
StrokeShape = new RoundRectangle { CornerRadius = new Microsoft.Maui.CornerRadius(BmcConstants.WidgetCornerRadius) },
|
|
|
|
|
Stroke = new SolidColorBrush(Color.FromArgb("#E0E0E0")),
|
|
|
|
|
StrokeThickness = 1,
|
|
|
|
|
BackgroundColor = Colors.White,
|
|
|
|
|
Shadow = new Shadow
|
|
|
|
|
{
|
|
|
|
|
Brush = new SolidColorBrush(Colors.Black),
|
|
|
|
|
Offset = new Point(0, 4),
|
|
|
|
|
Radius = 12,
|
|
|
|
|
Opacity = 0.10f,
|
|
|
|
|
},
|
|
|
|
|
Content = cardContent,
|
|
|
|
|
MaximumWidthRequest = 380,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Content = card;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private Border CreateFieldBorder(View content)
|
|
|
|
|
{
|
|
|
|
|
return new Border
|
|
|
|
|
{
|
|
|
|
|
StrokeShape = new RoundRectangle { CornerRadius = new Microsoft.Maui.CornerRadius(10) },
|
|
|
|
|
Stroke = new SolidColorBrush(Color.FromArgb("#E0E0E0")),
|
|
|
|
|
StrokeThickness = 1,
|
|
|
|
|
Padding = new Thickness(12, 6),
|
|
|
|
|
Content = content,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void BuildChips()
|
|
|
|
|
{
|
|
|
|
|
_chipsRow.Children.Clear();
|
|
|
|
|
foreach (var amount in SuggestedAmounts)
|
|
|
|
|
{
|
|
|
|
|
var chipLabel = new Label
|
|
|
|
|
{
|
|
|
|
|
Text = $"+{amount}",
|
|
|
|
|
FontSize = 13,
|
|
|
|
|
FontAttributes = FontAttributes.Bold,
|
|
|
|
|
TextColor = Color.FromArgb(BmcColors.BrandDark),
|
|
|
|
|
VerticalOptions = LayoutOptions.Center,
|
|
|
|
|
Padding = new Thickness(10, 4),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var chip = new Border
|
|
|
|
|
{
|
|
|
|
|
StrokeShape = new RoundRectangle { CornerRadius = new Microsoft.Maui.CornerRadius(6) },
|
|
|
|
|
Stroke = new SolidColorBrush(Color.FromArgb("#E0E0E0")),
|
|
|
|
|
StrokeThickness = 1,
|
|
|
|
|
BackgroundColor = Color.FromArgb("#F5F5F5"),
|
|
|
|
|
Content = chipLabel,
|
|
|
|
|
VerticalOptions = LayoutOptions.Center,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var chipTap = new TapGestureRecognizer();
|
|
|
|
|
var capturedAmount = amount;
|
|
|
|
|
chipTap.Tapped += (_, _) =>
|
|
|
|
|
{
|
|
|
|
|
_currentAmount = capturedAmount;
|
|
|
|
|
_amountEntry.Text = _currentAmount.ToString();
|
|
|
|
|
};
|
|
|
|
|
chip.GestureRecognizers.Add(chipTap);
|
|
|
|
|
|
|
|
|
|
_chipsRow.Children.Add(chip);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void OnAmountTextChanged(object? sender, TextChangedEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
if (int.TryParse(e.NewTextValue, out var amount) && amount >= 0)
|
|
|
|
|
_currentAmount = amount;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async void OnSupportTapped(object? sender, TappedEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
if (string.IsNullOrWhiteSpace(Username)) return;
|
|
|
|
|
|
|
|
|
|
// Fire event with collected data
|
|
|
|
|
SupportRequested?.Invoke(this, new SupportRequestedEventArgs
|
|
|
|
|
{
|
|
|
|
|
Username = Username,
|
|
|
|
|
Amount = _currentAmount,
|
|
|
|
|
Name = string.IsNullOrWhiteSpace(_nameEntry.Text) ? null : _nameEntry.Text,
|
|
|
|
|
Message = string.IsNullOrWhiteSpace(_messageEditor.Text) ? null : _messageEditor.Text,
|
|
|
|
|
IsMonthly = _monthlyCheckBox.IsChecked,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Animate
|
|
|
|
|
await _supportButton.ScaleToAsync(0.95, 80, Easing.CubicIn);
|
|
|
|
|
await _supportButton.ScaleToAsync(1.0, 80, Easing.CubicOut);
|
|
|
|
|
|
|
|
|
|
// Open browser
|
|
|
|
|
await Launcher.Default.OpenAsync(new Uri($"{BmcConstants.BaseUrl}{Username}"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async void OnFooterTapped(object? sender, TappedEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
if (string.IsNullOrWhiteSpace(Username)) return;
|
|
|
|
|
await Launcher.Default.OpenAsync(new Uri($"{BmcConstants.BaseUrl}{Username}"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#region Property Changed Handlers
|
|
|
|
|
|
|
|
|
|
private static void OnUsernameChanged(BindableObject bindable, object oldValue, object newValue)
|
|
|
|
|
{
|
|
|
|
|
if (bindable is BuyMeACoffeeWidget widget)
|
|
|
|
|
widget._footerLabel.Text = $"buymeacoffee.com/{newValue}";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void OnDisplayNameChanged(BindableObject bindable, object oldValue, object newValue)
|
|
|
|
|
{
|
|
|
|
|
if (bindable is BuyMeACoffeeWidget widget)
|
|
|
|
|
{
|
|
|
|
|
var name = (string)newValue;
|
|
|
|
|
widget._headerLabel.Text = string.IsNullOrWhiteSpace(name) ? "Support" : $"Support {name}";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void OnChipsChanged(BindableObject bindable, object oldValue, object newValue)
|
|
|
|
|
{
|
|
|
|
|
if (bindable is BuyMeACoffeeWidget widget)
|
|
|
|
|
widget.BuildChips();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void OnDefaultAmountChanged(BindableObject bindable, object oldValue, object newValue)
|
|
|
|
|
{
|
|
|
|
|
if (bindable is BuyMeACoffeeWidget widget)
|
|
|
|
|
{
|
|
|
|
|
widget._currentAmount = (int)newValue;
|
|
|
|
|
widget._amountEntry.Text = widget._currentAmount.ToString();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void OnAccentChanged(BindableObject bindable, object oldValue, object newValue)
|
|
|
|
|
{
|
|
|
|
|
if (bindable is BuyMeACoffeeWidget widget)
|
|
|
|
|
widget._supportButton.BackgroundColor = (Color)newValue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void OnShowMonthlyChanged(BindableObject bindable, object oldValue, object newValue)
|
|
|
|
|
{
|
|
|
|
|
if (bindable is BuyMeACoffeeWidget widget)
|
|
|
|
|
widget._monthlyRow.IsVisible = (bool)newValue;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-04 00:35:05 -05:00
|
|
|
private static void OnSupporterPropertyChanged(BindableObject bindable, object oldValue, object newValue)
|
|
|
|
|
{
|
|
|
|
|
if (bindable is BuyMeACoffeeWidget widget)
|
|
|
|
|
BmcSupporterCheck.CheckAndHide(widget, widget.SupporterEmail, widget.HideIfSupporter);
|
|
|
|
|
}
|
|
|
|
|
|
feat(scenarios): add buy me a coffee maui library
Create a .NET MAUI library for Buy Me a Coffee integration with branded button, QR code, and widget controls. Includes 8 theme presets (yellow, black, white, blue, violet, orange, red, green), customizable styling, and SkiaSharp-based rendering. Supports opening BMC pages in browser and generating QR codes for donations.
2026-03-03 23:19:45 -05:00
|
|
|
#endregion
|
|
|
|
|
}
|