7.1 KiB
7.1 KiB
Payment Overlay Widget
A reusable payment verification overlay that supports both 6-digit PIN input and biometric authentication for secure payment processing.
Features
- 6-digit PIN Input: Secure numeric PIN entry with automatic focus management
- Biometric Authentication: Support for fingerprint and face recognition
- Order Summary: Display payment details including amount, description, and remarks
- Integrated API Calls: Automatically handles payment processing via
/orders/{orderId}/pay
- Error Handling: Comprehensive error handling with user-friendly messages
- Loading States: Visual feedback during payment processing
- Responsive Design: Adapts to different screen sizes and orientations
- Customizable: Flexible callbacks and styling options
- Accessibility: Screen reader support and proper focus management
- Localization: Full i18n support with easy_localization
Usage
import 'package:flutter/material.dart';
import 'package:solian/models/wallet.dart';
import 'package:solian/widgets/payment/payment_overlay.dart';
// Create an order
final order = SnWalletOrder(
id: 'order_123',
amount: 2500, // $25.00 in cents
currency: 'USD',
description: 'Premium Subscription',
remarks: 'Monthly billing',
status: 'pending',
);
// Show payment overlay
PaymentOverlay.show(
context: context,
order: order,
onPaymentSuccess: (completedOrder) {
// Handle successful payment
print('Payment completed: ${completedOrder.id}');
// Navigate to success page or update UI
},
onPaymentError: (error) {
// Handle payment error
print('Payment failed: $error');
// Show error message to user
},
onCancel: () {
Navigator.of(context).pop();
print('Payment cancelled');
},
enableBiometric: true,
);
Advanced Usage with Loading States
bool isLoading = false;
PaymentOverlay.show(
context: context,
order: order,
enableBiometric: true,
isLoading: isLoading,
onPinSubmit: (String pin) async {
setState(() => isLoading = true);
try {
await processPaymentWithPin(pin);
Navigator.of(context).pop();
} catch (e) {
showErrorDialog(e.toString());
} finally {
setState(() => isLoading = false);
}
},
onBiometricAuth: () async {
setState(() => isLoading = true);
try {
final authenticated = await authenticateWithBiometrics();
if (authenticated) {
await processPaymentWithBiometrics();
Navigator.of(context).pop();
}
} catch (e) {
showErrorDialog(e.toString());
} finally {
setState(() => isLoading = false);
}
},
);
Parameters
PaymentOverlay.show()
Parameter | Type | Required | Description |
---|---|---|---|
context |
BuildContext |
✅ | The build context for showing the overlay |
order |
SnWalletOrder |
✅ | The order to be paid |
onPaymentSuccess |
Function(SnWalletOrder)? |
❌ | Callback when payment succeeds with completed order |
onPaymentError |
Function(String)? |
❌ | Callback when payment fails with error message |
onCancel |
VoidCallback? |
❌ | Callback when payment is cancelled |
enableBiometric |
bool |
❌ | Whether to show biometric option (default: true) |
API Integration
The PaymentOverlay automatically handles payment processing by calling the /orders/{orderId}/pay
endpoint with the following request body:
PIN Payment
{
"pin": "123456"
}
Biometric Payment
{
"biometric": true
}
Response
The API should return the completed SnWalletOrder
object:
{
"id": "order_123",
"amount": 2500,
"currency": "USD",
"description": "Premium Subscription",
"status": "completed",
"processorReference": "txn_abc123",
// ... other order fields
}
Error Handling
The widget handles common HTTP status codes:
401
: Invalid PIN or biometric authentication failed400
: Bad request with custom error message- Other errors: Generic payment failed message
Implementation Example
import 'package:local_auth/local_auth.dart';
class BiometricService {
final LocalAuthentication _auth = LocalAuthentication();
Future<bool> isAvailable() async {
final isAvailable = await _auth.canCheckBiometrics;
final isDeviceSupported = await _auth.isDeviceSupported();
return isAvailable && isDeviceSupported;
}
Future<bool> authenticate() async {
try {
final bool didAuthenticate = await _auth.authenticate(
localizedReason: 'Please authenticate to complete payment',
options: const AuthenticationOptions(
biometricOnly: true,
stickyAuth: true,
),
);
return didAuthenticate;
} catch (e) {
print('Biometric authentication error: $e');
return false;
}
}
}
Localization
Add these keys to your localization files:
{
"paymentVerification": "Payment Verification",
"paymentSummary": "Payment Summary",
"amount": "Amount",
"description": "Description",
"pinCode": "PIN Code",
"biometric": "Biometric",
"enterPinToConfirm": "Enter your 6-digit PIN to confirm payment",
"clearPin": "Clear PIN",
"useBiometricToConfirm": "Use biometric authentication to confirm payment",
"touchSensorToAuthenticate": "Touch the sensor to authenticate",
"authenticating": "Authenticating...",
"authenticateNow": "Authenticate Now",
"confirm": "Confirm",
"cancel": "Cancel",
"paymentFailed": "Payment failed. Please try again.",
"invalidPin": "Invalid PIN. Please try again.",
"biometricAuthFailed": "Biometric authentication failed. Please try again.",
"paymentSuccess": "Payment completed successfully!",
"paymentError": "Payment failed: {error}"
}
Styling
The widget automatically adapts to your app's theme. It uses:
Theme.of(context).colorScheme.primary
for primary elementsTheme.of(context).colorScheme.surface
for backgroundsTheme.of(context).textTheme
for typography
Security Considerations
- PIN Handling: The PIN is passed as a string to your callback. Ensure you handle it securely and don't log it.
- Biometric Authentication: Always verify biometric authentication on your backend.
- Network Security: Use HTTPS for all payment-related API calls.
- Data Validation: Validate all payment data on your backend before processing.
Example Integration
See payment_overlay_example.dart
for a complete working example that demonstrates:
- How to show the overlay
- Handling PIN and biometric authentication
- Processing payments
- Error handling
- Loading states
Dependencies
flutter/material.dart
- Material Design componentsflutter/services.dart
- Input formatters and system servicesflutter_riverpod/flutter_riverpod.dart
- State management and dependency injectiongap/gap.dart
- Spacing widgetsmaterial_symbols_icons/symbols.dart
- Material Symbols iconseasy_localization/easy_localization.dart
- Internationalizationdio/dio.dart
- HTTP client for API callssolian/models/wallet.dart
- Wallet order modelsolian/widgets/common/sheet_scaffold.dart
- Sheet scaffold widgetsolian/pods/network.dart
- API client provider