smat_pay_payment_plugin 1.0.7
smat_pay_payment_plugin: ^1.0.7 copied to clipboard
A payment plugin form for Smatpay users.
example/lib/main.dart
import 'package:flutter/material.dart';
import 'package:smat_pay_payment_plugin/common/api_config.dart';
import 'package:smat_pay_payment_plugin/views/payment_form.dart';
const _brandIndigo = Color(0xFF2F1991);
const _brandPurple = Color(0xFF8141D5);
const _brandViolet = Color(0xFF5B35E5);
const _pageBackground = Color(0xFFF5F0FF);
const _cardBorder = Color(0xFFEAD7FF);
void main() {
runApp(const SmatPayExampleApp());
}
class SmatPayExampleApp extends StatelessWidget {
const SmatPayExampleApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'SmatPay Plugin Example',
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: _brandIndigo),
useMaterial3: true,
),
home: const _PaymentLauncher(),
);
}
}
class _PaymentLauncher extends StatefulWidget {
const _PaymentLauncher();
@override
State<_PaymentLauncher> createState() => _PaymentLauncherState();
}
class _PaymentLauncherState extends State<_PaymentLauncher> {
static const _sandboxBaseUrl = 'https://dev.smatpay.africa:8443';
static const _liveBaseUrl = 'https://live.smatpay.africa:8443';
final _formKey = GlobalKey<FormState>();
late final TextEditingController _paymentCodeController;
late final TextEditingController _baseUrlController;
EndpointMode _endpointMode = EndpointMode.test;
@override
void initState() {
super.initState();
_paymentCodeController = TextEditingController(
text: const String.fromEnvironment('SMATPAY_PAYMENT_CODE'),
);
_baseUrlController = TextEditingController(
text: const String.fromEnvironment(
'SMATPAY_BASE_URL',
defaultValue: _sandboxBaseUrl,
),
);
_endpointMode = const bool.fromEnvironment('SMATPAY_USE_LIVE')
? EndpointMode.live
: EndpointMode.test;
}
@override
void dispose() {
_paymentCodeController.dispose();
_baseUrlController.dispose();
super.dispose();
}
void _openPaymentForm() {
if (!(_formKey.currentState?.validate() ?? false)) {
return;
}
Navigator.of(context).push(
MaterialPageRoute<void>(
builder: (context) => PaymentForm(
paymentCode: _paymentCodeController.text.trim(),
baseUrl: _baseUrlController.text.trim(),
endpointMode: _endpointMode,
),
),
);
}
void _updateEndpointMode(EndpointMode? endpointMode) {
if (endpointMode == null || endpointMode == _endpointMode) {
return;
}
final currentBaseUrl = _baseUrlController.text.trim();
final usesDefaultBaseUrl =
currentBaseUrl == _sandboxBaseUrl || currentBaseUrl == _liveBaseUrl;
setState(() {
_endpointMode = endpointMode;
if (usesDefaultBaseUrl) {
_baseUrlController.text =
endpointMode == EndpointMode.test ? _sandboxBaseUrl : _liveBaseUrl;
}
});
}
String? _validateRequired(String? value, String name) {
if (value == null || value.trim().isEmpty) {
return 'Enter a $name.';
}
return null;
}
String? _validateBaseUrl(String? value) {
final baseUrl = value?.trim() ?? '';
final uri = Uri.tryParse(baseUrl);
if (uri == null || !uri.hasScheme || !uri.hasAuthority) {
return 'Enter a valid URL, including https://.';
}
return null;
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: _pageBackground,
body: SafeArea(
child: SingleChildScrollView(
padding: const EdgeInsets.all(24),
child: Center(
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 520),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 24),
const Text(
'SmatPay',
style: TextStyle(
color: _brandIndigo,
fontSize: 30,
fontWeight: FontWeight.w800,
letterSpacing: -0.8,
),
),
const SizedBox(height: 10),
const Text(
'Payment Plugin Example',
style: TextStyle(
color: Color(0xFF1A133D),
fontSize: 24,
fontWeight: FontWeight.w700,
),
),
const SizedBox(height: 8),
const Text(
'Configure a test payment request, then open the plugin form.',
style: TextStyle(color: Color(0xFF4B5563), height: 1.45),
),
const SizedBox(height: 28),
Card(
margin: EdgeInsets.zero,
elevation: 0,
color: Colors.white,
surfaceTintColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(24),
side: const BorderSide(color: _cardBorder),
),
child: Padding(
padding: const EdgeInsets.all(20),
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Text(
'Connection settings',
style: TextStyle(
color: Color(0xFF1A133D),
fontSize: 18,
fontWeight: FontWeight.w700,
),
),
const SizedBox(height: 20),
DropdownButtonFormField<EndpointMode>(
initialValue: _endpointMode,
decoration: const InputDecoration(
labelText: 'Environment',
border: OutlineInputBorder(),
),
items: const [
DropdownMenuItem(
value: EndpointMode.test,
child: Text('Sandbox'),
),
DropdownMenuItem(
value: EndpointMode.live,
child: Text('Production'),
),
],
onChanged: _updateEndpointMode,
),
const SizedBox(height: 16),
TextFormField(
controller: _baseUrlController,
keyboardType: TextInputType.url,
decoration: const InputDecoration(
labelText: 'Base URL',
hintText: _sandboxBaseUrl,
border: OutlineInputBorder(),
),
validator: _validateBaseUrl,
),
const SizedBox(height: 16),
TextFormField(
controller: _paymentCodeController,
decoration: const InputDecoration(
labelText: 'Payment code',
hintText: 'Paste a test payment code',
border: OutlineInputBorder(),
),
validator: (value) =>
_validateRequired(value, 'payment code'),
),
const SizedBox(height: 24),
DecoratedBox(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(28),
gradient: const LinearGradient(
colors: [_brandPurple, _brandViolet],
),
),
child: ElevatedButton.icon(
onPressed: _openPaymentForm,
icon: const Icon(Icons.open_in_new_rounded),
label: const Text('Open payment form'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.transparent,
foregroundColor: Colors.white,
shadowColor: Colors.transparent,
padding: const EdgeInsets.symmetric(
horizontal: 20,
vertical: 16,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(28),
),
),
),
),
],
),
),
),
),
const SizedBox(height: 18),
const Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Icon(
Icons.info_outline_rounded,
size: 18,
color: _brandIndigo,
),
SizedBox(width: 8),
Expanded(
child: Text(
'Use a sandbox payment code while testing. The base URL can also be supplied with --dart-define values.',
style: TextStyle(
color: Color(0xFF4B5563),
fontSize: 12,
height: 1.4,
),
),
),
],
),
],
),
),
),
),
),
);
}
}