diff --git a/lib/features/fund_transfer/screens/fund_transfer_screen.dart b/lib/features/fund_transfer/screens/fund_transfer_screen.dart index 834340e..441b5de 100644 --- a/lib/features/fund_transfer/screens/fund_transfer_screen.dart +++ b/lib/features/fund_transfer/screens/fund_transfer_screen.dart @@ -1,5 +1,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:kmobile/features/fund_transfer/screens/transaction_pin_screen.dart'; import 'package:material_symbols_icons/material_symbols_icons.dart'; class FundTransferScreen extends StatefulWidget { @@ -21,6 +22,10 @@ class _FundTransferScreen extends State { } else if (key == 'done') { if (kDebugMode) { print('Amount entered: $amount'); + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const TransactionPinScreen())); } } else { amount += key; @@ -36,9 +41,8 @@ class _FundTransferScreen extends State { ); } else if (value == 'back') { return GestureDetector( - onTap: () => onKeyTap(value), - child: const Icon(Symbols.backspace, size: 30) - ); + onTap: () => onKeyTap(value), + child: const Icon(Symbols.backspace, size: 30)); } else { return GestureDetector( onTap: () => onKeyTap(value), @@ -91,39 +95,38 @@ class _FundTransferScreen extends State { ), ], ), - body: Padding( - padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 16.0), - child: Column( - children: [ - const SizedBox(height: 40), - const Text('Enter Amount', style: TextStyle(fontSize: 20)), - const SizedBox(height: 20), - Container( - padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16), - decoration: BoxDecoration( - color: Colors.grey.shade200, - borderRadius: BorderRadius.circular(12), - ), - child: Text( - amount.isEmpty ? "0" : amount, - style: const TextStyle(fontSize: 32, fontWeight: FontWeight.bold), - ), + body: Column( + children: [ + const Spacer(), + const Text('Enter Amount', style: TextStyle(fontSize: 20)), + const SizedBox(height: 20), + Container( + padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16), + decoration: BoxDecoration( + color: Colors.grey.shade200, + borderRadius: BorderRadius.circular(12), ), - const SizedBox(height: 40), - Expanded( - child: GridView.builder( - itemCount: keys.length, - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 3, - childAspectRatio: 1.2, - mainAxisSpacing: 12, - crossAxisSpacing: 12, - ), - itemBuilder: (_, index) => buildKey(keys[index]), - ), + child: Text( + amount.isEmpty ? "0" : amount, + style: const TextStyle(fontSize: 32, fontWeight: FontWeight.bold), ), - ], - ), + ), + const Spacer(), + Container( + padding: const EdgeInsets.all(16.0), + color: Colors.white, + child: GridView.count( + crossAxisCount: 3, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + mainAxisSpacing: 12, + crossAxisSpacing: 12, + childAspectRatio: 1.2, + children: + keys.map((key) => buildKey(key)).toList(), + ), + ), + ], ), ); } diff --git a/lib/features/fund_transfer/screens/transaction_pin_screen.dart b/lib/features/fund_transfer/screens/transaction_pin_screen.dart new file mode 100644 index 0000000..8c6a700 --- /dev/null +++ b/lib/features/fund_transfer/screens/transaction_pin_screen.dart @@ -0,0 +1,139 @@ +import 'package:flutter/material.dart'; +import 'package:kmobile/features/fund_transfer/screens/transaction_success_screen.dart'; +import 'package:material_symbols_icons/material_symbols_icons.dart'; + +class TransactionPinScreen extends StatefulWidget { + const TransactionPinScreen({super.key}); + + @override + State createState() => _TransactionPinScreen(); +} + +class _TransactionPinScreen extends State { + final List _pin = []; + + void _onKeyPressed(String value) { + setState(() { + if (value == 'back') { + if (_pin.isNotEmpty) _pin.removeLast(); + } else if (_pin.length < 6) { + _pin.add(value); + } + }); + } + + Widget _buildPinIndicators() { + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: List.generate(6, (index) { + return Container( + margin: const EdgeInsets.symmetric(horizontal: 8), + width: 20, + height: 20, + decoration: BoxDecoration( + shape: BoxShape.circle, + border: Border.all(color: Colors.blue, width: 2), + color: index < _pin.length ? Colors.blue : Colors.transparent, + ), + ); + }), + ); + } + + Widget _buildKey(String label, {IconData? icon}) { + return Expanded( + child: InkWell( + onTap: () { + if (label == 'back') { + _onKeyPressed('back'); + } else if (label == 'done') { + // Handle submit if needed + if (_pin.length == 6) { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const TransactionSuccessScreen())); + } else { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text("Please enter a 6-digit TPIN")), + ); + } + } else { + _onKeyPressed(label); + } + }, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 20), + child: Center( + child: icon != null + ? Icon(icon, size: 28) + : Text(label, style: const TextStyle(fontSize: 24)), + ), + ), + ), + ); + } + + Widget _buildKeypad() { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + Row(children: [_buildKey('1'), _buildKey('2'), _buildKey('3')]), + Row(children: [_buildKey('4'), _buildKey('5'), _buildKey('6')]), + Row(children: [_buildKey('7'), _buildKey('8'), _buildKey('9')]), + Row(children: [ + _buildKey('done', icon: Icons.check), + _buildKey('0'), + _buildKey('back', icon: Icons.backspace_outlined), + ]), + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + leading: IconButton( + icon: const Icon(Symbols.arrow_back_ios_new), + onPressed: () { + Navigator.pop(context); + }, + ), + title: const Text( + 'TPIN', + style: TextStyle(color: Colors.black, fontWeight: FontWeight.w500), + ), + centerTitle: false, + actions: const [ + Padding( + padding: EdgeInsets.only(right: 10.0), + child: CircleAvatar( + backgroundImage: AssetImage('assets/images/avatar.jpg'), + // Replace with your image + radius: 20, + ), + ), + ], + ), + + body: Padding( + padding: const EdgeInsets.only(bottom: 20.0), + child: Column( + children: [ + const Spacer(), + const Text( + 'Enter Your TPIN', + style: TextStyle(fontSize: 18), + ), + const SizedBox(height: 20), + _buildPinIndicators(), + const Spacer(), + _buildKeypad(), + ], + ), + ), + ); + } + +} \ No newline at end of file diff --git a/lib/features/fund_transfer/screens/transaction_success_screen.dart b/lib/features/fund_transfer/screens/transaction_success_screen.dart new file mode 100644 index 0000000..d5715cf --- /dev/null +++ b/lib/features/fund_transfer/screens/transaction_success_screen.dart @@ -0,0 +1,140 @@ +import 'dart:io'; +import 'dart:typed_data'; +import 'package:flutter/material.dart'; +import 'package:path_provider/path_provider.dart'; +import 'package:screenshot/screenshot.dart'; +import 'package:social_share/social_share.dart'; + +import '../../dashboard/screens/dashboard_screen.dart'; + +class TransactionSuccessScreen extends StatefulWidget { + const TransactionSuccessScreen({super.key}); + + @override + State createState() => _TransactionSuccessScreen(); +} + +class _TransactionSuccessScreen extends State { + final String transactionDate = "18th March, 2025 04:30 PM"; + final String referenceNumber = "TXN32131093012931993"; + + final ScreenshotController _screenshotController = ScreenshotController(); + + Future _shareScreenshot() async { + final Uint8List? imageBytes = await _screenshotController.capture(); + if (imageBytes != null) { + final directory = await getTemporaryDirectory(); + final imagePath = File('${directory.path}/transaction_success.png'); + await imagePath.writeAsBytes(imageBytes); + + SocialShare.shareOptions( + "Transaction Successful", + imagePath: imagePath.path, + ); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: SafeArea( + child: Stack( + children: [ + // Main content + Align( + alignment: Alignment.center, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const CircleAvatar( + radius: 50, + backgroundColor: Colors.blue, + child: Icon( + Icons.check, + color: Colors.white, + size: 60, + ), + ), + const SizedBox(height: 24), + const Text( + "Transaction Successful", + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.w600, + ), + textAlign: TextAlign.center, + ), + const SizedBox(height: 6), + Text( + "On $transactionDate", + style: const TextStyle( + fontSize: 14, + color: Colors.black54, + ), + textAlign: TextAlign.center, + ), + const SizedBox(height: 16), + Text( + "Reference No: $referenceNumber", + style: const TextStyle( + fontSize: 12, + color: Colors.black87, + ), + textAlign: TextAlign.center, + ), + ], + ), + ), + + // Buttons at the bottom + Align( + alignment: Alignment.bottomCenter, + child: Padding( + padding: const EdgeInsets.fromLTRB(36, 0, 36, 25), + child: Row( + children: [ + Expanded( + child: OutlinedButton.icon( + onPressed: _shareScreenshot, + icon: const Icon(Icons.share, size: 18), + label: const Text("Share"), + style: ElevatedButton.styleFrom( + shape: const StadiumBorder(), + padding: const EdgeInsets.symmetric(vertical: 16), + backgroundColor: Colors.white, + foregroundColor: Colors.blueAccent, + side: const BorderSide(color: Colors.black, width: 1), + elevation: 0 + ), + ), + ), + const SizedBox(width: 12), + Expanded( + child: ElevatedButton( + onPressed: () { + // Done action + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const DashboardScreen())); + }, + style: ElevatedButton.styleFrom( + shape: const StadiumBorder(), + padding: const EdgeInsets.symmetric(vertical: 16), + backgroundColor: Colors.blue[900], + foregroundColor: Colors.white, + ), + child: const Text("Done"), + ), + ), + ], + ), + ), + ), + ], + ), + ), + ); + } + +} \ No newline at end of file diff --git a/pubspec.lock b/pubspec.lock index 735222a..ba6185b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -393,7 +393,7 @@ packages: source: hosted version: "1.1.0" path_provider: - dependency: transitive + dependency: "direct main" description: name: path_provider sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" @@ -472,6 +472,14 @@ packages: url: "https://pub.dev" source: hosted version: "6.1.5" + screenshot: + dependency: "direct main" + description: + name: screenshot + sha256: "63817697a7835e6ce82add4228e15d233b74d42975c143ad8cfe07009fab866b" + url: "https://pub.dev" + source: hosted + version: "3.0.0" shared_preferences: dependency: "direct main" description: @@ -533,6 +541,14 @@ packages: description: flutter source: sdk version: "0.0.0" + social_share: + dependency: "direct main" + description: + name: social_share + sha256: eb19a0f6f5a29c7bb71e5bb1991145eb52472184363b6e2da70695befd8be041 + url: "https://pub.dev" + source: hosted + version: "2.3.1" source_span: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 99f49d9..c0f7539 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -47,6 +47,10 @@ dependencies: material_symbols_icons: ^4.2815.0 shared_preferences: ^2.5.3 url_launcher: ^6.3.1 + social_share: ^2.3.1 + screenshot: ^3.0.0 + path_provider: ^2.1.5 + dev_dependencies: flutter_test: