flick_payment_sdk 1.0.4
flick_payment_sdk: ^1.0.4 copied to clipboard
A Flutter SDK for Flick Payment processing
example/lib/main.dart
import 'package:flutter/material.dart';
import 'package:flick_payment_sdk/flick_payment_sdk.dart';
import 'dart:async';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flick Payment App',
theme: ThemeData(
primarySwatch: Colors.orange,
fontFamily: 'SF Pro Display',
scaffoldBackgroundColor: const Color(0xFFF8F9FA),
),
debugShowCheckedModeBanner: false,
home: const SplashScreen(),
routes: {
'/login': (context) => const LoginScreen(),
'/dashboard': (context) => const DashboardScreen(),
'/send': (context) => const SendMoneyScreen(),
},
);
}
}
// Splash Screen
class SplashScreen extends StatefulWidget {
const SplashScreen({super.key});
@override
State<SplashScreen> createState() => _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen>
with SingleTickerProviderStateMixin {
late AnimationController _animationController;
late Animation<double> _scaleAnimation;
late Animation<double> _fadeAnimation;
@override
void initState() {
super.initState();
_animationController = AnimationController(
duration: const Duration(seconds: 2),
vsync: this,
);
_scaleAnimation = Tween<double>(begin: 0.5, end: 1.0).animate(
CurvedAnimation(parent: _animationController, curve: Curves.elasticOut),
);
_fadeAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(
CurvedAnimation(parent: _animationController, curve: Curves.easeIn),
);
_animationController.forward();
Timer(const Duration(seconds: 3), () {
Navigator.pushReplacementNamed(context, '/login');
});
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFFF97316),
body: Center(
child: AnimatedBuilder(
animation: _animationController,
builder: (context, child) {
return FadeTransition(
opacity: _fadeAnimation,
child: ScaleTransition(
scale: _scaleAnimation,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 120,
height: 120,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(30),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 20,
offset: const Offset(0, 10),
),
],
),
child: const Icon(
Icons.flash_on,
size: 60,
color: Color(0xFFF97316),
),
),
const SizedBox(height: 24),
const Text(
'Flick',
style: TextStyle(
fontSize: 36,
fontWeight: FontWeight.bold,
color: Colors.white,
letterSpacing: 2,
),
),
const SizedBox(height: 8),
const Text(
'Fast. Secure. Simple.',
style: TextStyle(
fontSize: 16,
color: Colors.white70,
),
),
],
),
),
);
},
),
),
);
}
}
// Login Screen
class LoginScreen extends StatefulWidget {
const LoginScreen({super.key});
@override
State<LoginScreen> createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> {
final _emailController = TextEditingController(text: '');
final _passwordController = TextEditingController();
bool _obscurePassword = true;
bool _isLoading = false;
@override
void dispose() {
_emailController.dispose();
_passwordController.dispose();
super.dispose();
}
void _login() async {
setState(() => _isLoading = true);
// Simulate login delay
await Future.delayed(const Duration(seconds: 2));
setState(() => _isLoading = false);
Navigator.pushReplacementNamed(context, '/dashboard');
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(24.0),
child: Column(
children: [
const SizedBox(height: 60),
// Logo
Container(
width: 80,
height: 80,
decoration: BoxDecoration(
color: const Color(0xFFF97316),
borderRadius: BorderRadius.circular(20),
),
child: const Icon(
Icons.flash_on,
size: 40,
color: Colors.white,
),
),
const SizedBox(height: 40),
// Email Field
Container(
decoration: BoxDecoration(
color: const Color(0xFFF8F9FA),
borderRadius: BorderRadius.circular(12),
),
child: TextField(
controller: _emailController,
decoration: const InputDecoration(
hintText: 'Email',
border: InputBorder.none,
contentPadding: EdgeInsets.all(16),
),
),
),
const SizedBox(height: 16),
// Password Field
Container(
decoration: BoxDecoration(
color: const Color(0xFFF8F9FA),
borderRadius: BorderRadius.circular(12),
),
child: TextField(
controller: _passwordController,
obscureText: _obscurePassword,
decoration: InputDecoration(
hintText: 'Password',
border: InputBorder.none,
contentPadding: const EdgeInsets.all(16),
suffixIcon: IconButton(
icon: Icon(
_obscurePassword
? Icons.visibility
: Icons.visibility_off,
color: Colors.grey,
),
onPressed: () {
setState(() => _obscurePassword = !_obscurePassword);
},
),
),
),
),
const SizedBox(height: 8),
// Forgot Password
Align(
alignment: Alignment.centerRight,
child: TextButton(
onPressed: () {},
child: const Text(
'Forgot Password?',
style: TextStyle(color: Color(0xFFF97316)),
),
),
),
const SizedBox(height: 24),
// Login Button
SizedBox(
width: double.infinity,
height: 56,
child: ElevatedButton(
onPressed: _isLoading ? null : _login,
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFFF97316),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(28),
),
),
child: _isLoading
? const CircularProgressIndicator(color: Colors.white)
: const Text(
'Login',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Colors.white,
),
),
),
),
const Spacer(),
// Sign Up
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text("Don't have an account? "),
TextButton(
onPressed: () {},
child: const Text(
'Sign up',
style: TextStyle(
color: Color(0xFFF97316),
fontWeight: FontWeight.w600,
),
),
),
],
),
],
),
),
),
);
}
}
// Dashboard Screen
class DashboardScreen extends StatefulWidget {
const DashboardScreen({super.key});
@override
State<DashboardScreen> createState() => _DashboardScreenState();
}
class _DashboardScreenState extends State<DashboardScreen> {
bool _isBalanceHidden = false;
final List<Transaction> _transactions = [
Transaction(
type: TransactionType.received,
amount: 5000.00,
date: DateTime(2024, 3, 1),
description: 'Salary Payment',
),
Transaction(
type: TransactionType.sent,
amount: 1500.00,
date: DateTime(2024, 3, 2),
description: 'Rent Payment',
),
Transaction(
type: TransactionType.sent,
amount: 220.00,
date: DateTime(2024, 3, 3),
description: 'Grocery Shopping',
),
Transaction(
type: TransactionType.sent,
amount: 45.00,
date: DateTime(2024, 3, 3),
description: 'Coffee & Breakfast',
),
Transaction(
type: TransactionType.received,
amount: 750.00,
date: DateTime(2024, 3, 4),
description: 'Freelance Project',
),
];
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: [
// Header
Padding(
padding: const EdgeInsets.all(24.0),
child: Row(
children: [
const CircleAvatar(
radius: 20,
backgroundColor: Color(0xFFF97316),
child: Text(
'M',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
),
const SizedBox(width: 12),
const Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Hey Mide!',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
Text(
'@mideajibade',
style: TextStyle(
color: Colors.grey,
fontSize: 14,
),
),
],
),
),
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: const Color(0xFFF8F9FA),
borderRadius: BorderRadius.circular(8),
),
child: const Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.monetization_on,
color: Color(0xFFF97316), size: 16),
SizedBox(width: 4),
Text('Earn \$50',
style: TextStyle(
fontSize: 12, fontWeight: FontWeight.w600)),
],
),
),
const SizedBox(width: 8),
const Icon(Icons.notifications_none, size: 24),
],
),
),
// Balance Card
Container(
margin: const EdgeInsets.symmetric(horizontal: 24),
padding: const EdgeInsets.all(24),
decoration: BoxDecoration(
gradient: const LinearGradient(
colors: [Color(0xFFF97316), Color(0xFFEA580C)],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: const Color(0xFFF97316).withOpacity(0.3),
blurRadius: 20,
offset: const Offset(0, 10),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
const Icon(Icons.flag, color: Colors.white, size: 20),
const SizedBox(width: 8),
const Text(
'USD Balance',
style: TextStyle(
color: Colors.white70,
fontSize: 14,
),
),
const Spacer(),
IconButton(
onPressed: () {
setState(() => _isBalanceHidden = !_isBalanceHidden);
},
icon: Icon(
_isBalanceHidden
? Icons.visibility
: Icons.visibility_off,
color: Colors.white70,
size: 20,
),
),
],
),
const SizedBox(height: 8),
Text(
_isBalanceHidden ? '€***.**' : '€30,329.45',
style: const TextStyle(
color: Colors.white,
fontSize: 32,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 16),
Row(
children: [
Expanded(
child: GestureDetector(
onTap: () => Navigator.pushNamed(context, '/send'),
child: Container(
padding: const EdgeInsets.symmetric(vertical: 12),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.2),
borderRadius: BorderRadius.circular(12),
),
child: const Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.arrow_upward,
color: Colors.white, size: 16),
SizedBox(width: 8),
Text(
'Send',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w600,
),
),
],
),
),
),
),
const SizedBox(width: 12),
Expanded(
child: Container(
padding: const EdgeInsets.symmetric(vertical: 12),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.2),
borderRadius: BorderRadius.circular(12),
),
child: const Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.add, color: Colors.white, size: 16),
SizedBox(width: 8),
Text(
'Fund',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w600,
),
),
],
),
),
),
],
),
],
),
),
const SizedBox(height: 32),
// Recent Transactions
Expanded(
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 24),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Recent Transactions',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 16),
Expanded(
child: ListView.builder(
itemCount: _transactions.length,
itemBuilder: (context, index) {
final transaction = _transactions[index];
return _buildTransactionItem(transaction);
},
),
),
],
),
),
),
],
),
),
);
}
Widget _buildTransactionItem(Transaction transaction) {
final isReceived = transaction.type == TransactionType.received;
return Container(
margin: const EdgeInsets.only(bottom: 12),
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 10,
offset: const Offset(0, 2),
),
],
),
child: Row(
children: [
Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: isReceived
? const Color(0xFF22C55E).withOpacity(0.1)
: const Color(0xFFEF4444).withOpacity(0.1),
borderRadius: BorderRadius.circular(10),
),
child: Icon(
isReceived ? Icons.arrow_downward : Icons.arrow_upward,
color: isReceived
? const Color(0xFF22C55E)
: const Color(0xFFEF4444),
size: 20,
),
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
isReceived ? 'Received' : 'Sent',
style: const TextStyle(
fontWeight: FontWeight.w600,
fontSize: 14,
),
),
Text(
'${transaction.date.day.toString().padLeft(2, '0')}-${transaction.date.month.toString().padLeft(2, '0')}-${transaction.date.year}',
style: const TextStyle(
color: Colors.grey,
fontSize: 12,
),
),
],
),
),
Text(
'${isReceived ? '+' : '-'} €${transaction.amount.toStringAsFixed(2)}',
style: TextStyle(
color: isReceived
? const Color(0xFF22C55E)
: const Color(0xFFEF4444),
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
],
),
);
}
}
// Send Money Screen
class SendMoneyScreen extends StatefulWidget {
const SendMoneyScreen({super.key});
@override
State<SendMoneyScreen> createState() => _SendMoneyScreenState();
}
class _SendMoneyScreenState extends State<SendMoneyScreen> {
double _selectedAmount = 0;
final _customAmountController = TextEditingController();
final List<double> _quickAmounts = [5, 50, 100];
@override
void dispose() {
_customAmountController.dispose();
super.dispose();
}
void _selectAmount(double amount) {
setState(() {
_selectedAmount = amount;
_customAmountController.clear();
});
}
void _onCustomAmountChanged(String value) {
final amount = double.tryParse(value);
setState(() {
_selectedAmount = amount ?? 0;
});
}
void _proceedToPayment() {
if (_selectedAmount >= 5) {
final amountInPence = (_selectedAmount * 100).toInt();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PaymentPage(
userAmount: _selectedAmount,
backendAmount: amountInPence.toString(),
),
),
);
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Minimum amount is €5')),
);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
backgroundColor: Colors.white,
elevation: 0,
leading: IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.black),
onPressed: () => Navigator.pop(context),
),
title: const Text(
'Send',
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
),
),
centerTitle: true,
),
body: Padding(
padding: const EdgeInsets.all(24.0),
child: Column(
children: [
const SizedBox(height: 40),
// Amount Display
Text(
'€${_selectedAmount.toStringAsFixed(0)}',
style: const TextStyle(
fontSize: 48,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
Text(
'Enter an amount from €5 - €500k',
style: TextStyle(
color: Colors.grey[600],
fontSize: 16,
),
),
const SizedBox(height: 40),
// Quick Amount Selection
const Align(
alignment: Alignment.centerLeft,
child: Text(
'Or quickly select amount',
style: TextStyle(
color: Colors.grey,
fontSize: 14,
),
),
),
const SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: _quickAmounts.map((amount) {
final isSelected = _selectedAmount == amount;
return GestureDetector(
onTap: () => _selectAmount(amount),
child: Container(
width: 80,
height: 40,
decoration: BoxDecoration(
color: isSelected
? const Color(0xFFF97316)
: Colors.grey[100],
borderRadius: BorderRadius.circular(20),
),
child: Center(
child: Text(
'€${amount.toInt()}',
style: TextStyle(
color: isSelected ? Colors.white : Colors.black,
fontWeight: FontWeight.w600,
),
),
),
),
);
}).toList(),
),
const SizedBox(height: 40),
// Continue Button
SizedBox(
width: double.infinity,
height: 56,
child: ElevatedButton(
onPressed: _selectedAmount >= 5 ? _proceedToPayment : null,
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFFF97316),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(28),
),
),
child: const Text(
'Continue',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Colors.white,
),
),
),
),
const Spacer(),
// Number Pad
_buildNumberPad(),
],
),
),
);
}
Widget _buildNumberPad() {
return Container(
padding: const EdgeInsets.symmetric(vertical: 20),
child: Column(
children: [
_buildNumberRow(['1', '2', '3']),
const SizedBox(height: 16),
_buildNumberRow(['4', '5', '6']),
const SizedBox(height: 16),
_buildNumberRow(['7', '8', '9']),
const SizedBox(height: 16),
_buildNumberRow(['', '0', '⌫']),
],
),
);
}
Widget _buildNumberRow(List<String> numbers) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: numbers.map((number) {
if (number.isEmpty) return const SizedBox(width: 60);
return GestureDetector(
onTap: () => _onNumberPressed(number),
child: Container(
width: 60,
height: 60,
decoration: BoxDecoration(
color: Colors.grey[100],
borderRadius: BorderRadius.circular(30),
),
child: Center(
child: Text(
number,
style: const TextStyle(
fontSize: 24,
fontWeight: FontWeight.w500,
),
),
),
),
);
}).toList(),
);
}
void _onNumberPressed(String number) {
if (number == '⌫') {
// Backspace
if (_selectedAmount >= 10) {
setState(() {
_selectedAmount = (_selectedAmount / 10).floor().toDouble();
});
} else {
setState(() => _selectedAmount = 0);
}
} else {
// Add digit
setState(() {
_selectedAmount = (_selectedAmount * 10) + double.parse(number);
if (_selectedAmount > 500000) _selectedAmount = 500000; // Max limit
});
}
}
}
// Payment Page (Enhanced)
class PaymentPage extends StatefulWidget {
final double userAmount;
final String backendAmount;
const PaymentPage({
super.key,
required this.userAmount,
required this.backendAmount,
});
@override
State<PaymentPage> createState() => _PaymentPageState();
}
class _PaymentPageState extends State<PaymentPage> {
final FlickPayment _flickPayment = FlickPayment();
@override
void initState() {
super.initState();
_initializePayment();
}
Future<void> _initializePayment() async {
final success = await _flickPayment.initialize(
PaymentConfig(
customerEmail: 'user@example.com',
amount: widget.backendAmount,
currency: 'GBP',
transactionId: 'Flick-${DateTime.now().millisecondsSinceEpoch}',
bearerToken: 'TokenFromFlick',
redirectUrl: "https://merchant.getflick.co/",
),
onPaymentCompleted: _showPaymentResult,
);
if (!mounted) return;
setState(() {});
if (!success) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
_flickPayment.initializationError ??
'Payment initialization failed',
),
duration: const Duration(seconds: 5),
),
);
}
}
void _showPaymentResult(PaymentStatusDetails statusDetails) {
if (statusDetails.transactionStatus.toLowerCase() == 'successful') {
_showSuccessDialog();
} else {
_showErrorDialog(statusDetails.description);
}
}
void _showSuccessDialog() {
showDialog(
context: context,
barrierDismissible: false,
builder: (context) => AlertDialog(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
width: 80,
height: 80,
decoration: BoxDecoration(
color: const Color(0xFF22C55E),
borderRadius: BorderRadius.circular(40),
),
child: const Icon(
Icons.check,
color: Colors.white,
size: 40,
),
),
const SizedBox(height: 24),
const Text(
'Payment Successful!',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
Text(
'\$${widget.userAmount.toStringAsFixed(2)} sent successfully',
style: TextStyle(
color: Colors.grey[600],
fontSize: 16,
),
),
const SizedBox(height: 24),
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: () {
Navigator.of(context).pushNamedAndRemoveUntil(
'/dashboard',
(route) => false,
);
},
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFFF97316),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
child: const Text(
'Done',
style: TextStyle(color: Colors.white),
),
),
),
],
),
),
);
}
void _showErrorDialog(String message) {
showDialog(
context: context,
builder: (context) => AlertDialog(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
width: 80,
height: 80,
decoration: BoxDecoration(
color: const Color(0xFFEF4444),
borderRadius: BorderRadius.circular(40),
),
child: const Icon(
Icons.close,
color: Colors.white,
size: 40,
),
),
const SizedBox(height: 24),
const Text(
'Payment Failed',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
Text(
message,
style: TextStyle(
color: Colors.grey[600],
fontSize: 16,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 24),
Row(
children: [
Expanded(
child: OutlinedButton(
onPressed: () => Navigator.pop(context),
style: OutlinedButton.styleFrom(
side: const BorderSide(color: Color(0xFFF97316)),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
child: const Text(
'Try Again',
style: TextStyle(color: Color(0xFFF97316)),
),
),
),
const SizedBox(width: 12),
Expanded(
child: ElevatedButton(
onPressed: () {
Navigator.of(context).pushNamedAndRemoveUntil(
'/dashboard',
(route) => false,
);
},
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFFF97316),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
child: const Text(
'Cancel',
style: TextStyle(color: Colors.white),
),
),
),
],
),
],
),
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
backgroundColor: Colors.white,
elevation: 0,
leading: IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.black),
onPressed: () => Navigator.pop(context),
),
title: const Text(
'Complete Payment',
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
),
),
centerTitle: true,
),
body: Padding(
padding: const EdgeInsets.all(24.0),
child: Column(
children: [
const SizedBox(height: 20),
// Payment Summary Card
Container(
width: double.infinity,
padding: const EdgeInsets.all(24),
decoration: BoxDecoration(
gradient: const LinearGradient(
colors: [Color(0xFFF97316), Color(0xFFEA580C)],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: const Color(0xFFF97316).withOpacity(0.3),
blurRadius: 20,
offset: const Offset(0, 10),
),
],
),
child: Column(
children: [
const Text(
'Amount to Pay',
style: TextStyle(
color: Colors.white70,
fontSize: 16,
),
),
const SizedBox(height: 8),
Text(
widget.userAmount.toStringAsFixed(2),
style: const TextStyle(
color: Colors.white,
fontSize: 48,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 16),
Container(
padding:
const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.2),
borderRadius: BorderRadius.circular(20),
),
child: const Text(
'Pay by Bank Transfer',
style: TextStyle(
color: Colors.white,
fontSize: 14,
fontWeight: FontWeight.w500,
),
),
),
],
),
),
const Spacer(),
// Payment Button
Container(
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
),
child: _flickPayment.createPaymentButton(context),
),
const SizedBox(height: 16),
// Terms and Conditions
Text(
'By continuing, you agree to our Terms of Service and Privacy Policy',
style: TextStyle(
color: Colors.grey[600],
fontSize: 12,
),
textAlign: TextAlign.center,
),
],
),
),
);
}
}
// Transaction Model
class Transaction {
final TransactionType type;
final double amount;
final DateTime date;
final String description;
Transaction({
required this.type,
required this.amount,
required this.date,
required this.description,
});
}
enum TransactionType { sent, received }