diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png index 75f520d..d06ffdf 100644 Binary files a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png index 935e409..48ea1fe 100644 Binary files a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png index 5ee407d..98660b0 100644 Binary files a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index ae86a4a..5509de8 100644 Binary files a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png index 21c6763..e605276 100644 Binary files a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/lib/models/pageable_model.dart b/lib/models/pageable_model.dart new file mode 100644 index 0000000..b505ecb --- /dev/null +++ b/lib/models/pageable_model.dart @@ -0,0 +1,119 @@ +class PageableModel { + final List content; + final Pageable pageable; + final int totalPages; + final int totalElements; + final bool last; + final int size; + final int number; + final Sort sort; + final int numberOfElements; + final bool first; + final bool empty; + + PageableModel({ + required this.content, + required this.pageable, + required this.totalPages, + required this.totalElements, + required this.last, + required this.size, + required this.number, + required this.sort, + required this.numberOfElements, + required this.first, + required this.empty, + }); + + factory PageableModel.fromJson(Map json) { + return PageableModel( + content: json['content'] ?? [], + pageable: Pageable.fromJson(json['pageable']), + totalPages: json['totalPages'], + totalElements: json['totalElements'], + last: json['last'], + size: json['size'], + number: json['number'], + sort: Sort.fromJson(json['sort']), + numberOfElements: json['numberOfElements'], + first: json['first'], + empty: json['empty'], + ); + } + + Map toJson() { + return { + 'content': content, + 'pageable': pageable.toJson(), + 'totalPages': totalPages, + 'totalElements': totalElements, + 'last': last, + 'size': size, + 'number': number, + 'sort': sort.toJson(), + 'numberOfElements': numberOfElements, + 'first': first, + 'empty': empty, + }; + } +} + +class Pageable { + final int pageNumber; + final int pageSize; + final Sort sort; + final int offset; + final bool paged; + final bool unpaged; + + Pageable({ + required this.pageNumber, + required this.pageSize, + required this.sort, + required this.offset, + required this.paged, + required this.unpaged, + }); + + factory Pageable.fromJson(Map json) { + return Pageable( + pageNumber: json['pageNumber'], + pageSize: json['pageSize'], + sort: Sort.fromJson(json['sort']), + offset: json['offset'], + paged: json['paged'], + unpaged: json['unpaged'], + ); + } + + Map toJson() { + return { + 'pageNumber': pageNumber, + 'pageSize': pageSize, + 'sort': sort.toJson(), + 'offset': offset, + 'paged': paged, + 'unpaged': unpaged, + }; + } +} + +class Sort { + final bool sorted; + final bool empty; + final bool unsorted; + + Sort({required this.sorted, required this.empty, required this.unsorted}); + + factory Sort.fromJson(Map json) { + return Sort( + sorted: json['sorted'], + empty: json['empty'], + unsorted: json['unsorted'], + ); + } + + Map toJson() { + return {'sorted': sorted, 'empty': empty, 'unsorted': unsorted}; + } +} diff --git a/lib/screens/confirm/confirm_screen.dart b/lib/screens/confirm/confirm_screen.dart index c350e86..270115b 100644 --- a/lib/screens/confirm/confirm_screen.dart +++ b/lib/screens/confirm/confirm_screen.dart @@ -92,179 +92,203 @@ class _ConfirmScreenState extends State crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( + padding: EdgeInsets.all(15), decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - width: 1.0, - color: Theme.of(context).colorScheme.primary, + border: Border.all( + color: Theme.of( + context, + ).colorScheme.primary.withOpacity(0.3), + ), + borderRadius: BorderRadius.circular(10), + ), + + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + decoration: BoxDecoration( + border: Border( + bottom: BorderSide( + width: 1.0, + color: + Theme.of(context).colorScheme.primary, + ), + ), + ), + padding: EdgeInsets.only( + bottom: 4.0, + ), // Adjust spacing + child: Text( + "PROVIDER DETAILS", + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), ), - ), - ), - padding: EdgeInsets.only( - bottom: 4.0, - ), // Adjust spacing - child: Text( - "PROVIDER DETAILS", - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - ), - ), - ), - ...controller - .transactionController - .model - .confirmationData["additionalData"] - .map((data) { - return Column( - children: [ - const SizedBox(height: 10), - Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Text( - data["name"] ?? "", - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, + ...controller + .transactionController + .model + .confirmationData["additionalData"] + .map((data) { + return Column( + children: [ + const SizedBox(height: 10), + Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Text( + data["name"] ?? "", + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + Text( + data["value"] ?? "", + style: TextStyle(fontSize: 16), + ), + ], ), - ), - Text( - data["value"] ?? "", - style: TextStyle(fontSize: 16), - ), - ], + ], + ); + }) + .toList(), + const SizedBox(height: 30), + Container( + decoration: BoxDecoration( + border: Border( + bottom: BorderSide( + width: 1.0, + color: + Theme.of(context).colorScheme.primary, + ), + ), + ), + padding: EdgeInsets.only( + bottom: 4.0, + ), // Adjust spacing + child: Text( + "TRANSACTIONS DETAILS", + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + ), + const SizedBox(height: 20), + Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Text( + "Amount", + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + Text( + controller + .transactionController + .model + .confirmationData["amount"] + .toString(), + style: TextStyle(fontSize: 16), ), ], - ); - }) - .toList(), - const SizedBox(height: 30), - Container( - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - width: 1.0, - color: Theme.of(context).colorScheme.primary, ), - ), + const SizedBox(height: 10), + Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Text( + "Our Charge", + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + Text( + controller + .transactionController + .model + .confirmationData["charge"] + .toString(), + style: TextStyle(fontSize: 16), + ), + ], + ), + const SizedBox(height: 10), + Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Text( + "Gateway Charge", + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + Text( + controller + .transactionController + .model + .confirmationData["gatewayCharge"] + .toString(), + style: TextStyle(fontSize: 16), + ), + ], + ), + const SizedBox(height: 10), + Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Text( + "Tax", + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + Text( + controller + .transactionController + .model + .confirmationData["tax"] + .toString(), + style: TextStyle(fontSize: 16), + ), + ], + ), + const SizedBox(height: 10), + Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Text( + "Total Amount", + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + Text( + controller + .transactionController + .model + .confirmationData["totalAmount"] + .toString(), + style: TextStyle(fontSize: 16), + ), + ], + ), + ], ), - padding: EdgeInsets.only( - bottom: 4.0, - ), // Adjust spacing - child: Text( - "TRANSACTIONS DETAILS", - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - ), - ), - ), - const SizedBox(height: 20), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - "Amount", - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - ), - ), - Text( - controller - .transactionController - .model - .confirmationData["amount"] - .toString(), - style: TextStyle(fontSize: 16), - ), - ], - ), - const SizedBox(height: 10), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - "Our Charge", - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - ), - ), - Text( - controller - .transactionController - .model - .confirmationData["charge"] - .toString(), - style: TextStyle(fontSize: 16), - ), - ], - ), - const SizedBox(height: 10), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - "Gateway Charge", - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - ), - ), - Text( - controller - .transactionController - .model - .confirmationData["gatewayCharge"] - .toString(), - style: TextStyle(fontSize: 16), - ), - ], - ), - const SizedBox(height: 10), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - "Tax", - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - ), - ), - Text( - controller - .transactionController - .model - .confirmationData["tax"] - .toString(), - style: TextStyle(fontSize: 16), - ), - ], - ), - const SizedBox(height: 10), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - "Total Amount", - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - ), - ), - Text( - controller - .transactionController - .model - .confirmationData["totalAmount"] - .toString(), - style: TextStyle(fontSize: 16), - ), - ], ), const SizedBox(height: 20), _buildPaymentProcessorButton(), diff --git a/lib/screens/history/history_controller.dart b/lib/screens/history/history_controller.dart index 0b8a323..c5602ae 100644 --- a/lib/screens/history/history_controller.dart +++ b/lib/screens/history/history_controller.dart @@ -1,7 +1,10 @@ import 'package:flutter/material.dart'; import 'package:qpay/http/http.dart'; +import 'package:qpay/models/pageable_model.dart'; class HistoryModel { + PageableModel? pageableModel; + List> transactions = []; bool isLoading = false; String? errorMessage; @@ -26,16 +29,29 @@ class HistoryController extends ChangeNotifier { Future getTransactions(Map params) async { model.isLoading = true; - model.transactions = getFakeTransactions(); + if (params['page'] == '0') { + model.transactions = getFakeTransactions(); + } notifyListeners(); try { params['type'] = 'REQUEST'; - List response = await http.get( + Map response = await http.get( '/transaction?${buildQueryParameters(params)}', ); + + if (params['page'] == '0') { + model.transactions = []; + } + + model.pageableModel = PageableModel.fromJson(response); + + // pagination adds to current list instead of replacing it model.transactions = - response.map((e) => e as Map).toList(); + model.transactions + + model.pageableModel!.content + .map((e) => e as Map) + .toList(); } catch (e) { logger.e(e); _showErrorSnackBar( diff --git a/lib/screens/history/history_screen.dart b/lib/screens/history/history_screen.dart index b6ce009..3e1e980 100644 --- a/lib/screens/history/history_screen.dart +++ b/lib/screens/history/history_screen.dart @@ -24,6 +24,7 @@ class _HistoryScreenState extends State final TextEditingController _searchController = TextEditingController(); final Map _queryParams = {}; final List> _alignListAnimations = []; + final int _pageSize = 8; @override void initState() { @@ -57,7 +58,12 @@ class _HistoryScreenState extends State void setupData() async { prefs = await SharedPreferences.getInstance(); - await controller.getTransactions({'userId': prefs.getString("userId")!}); + await controller.getTransactions({ + 'userId': prefs.getString("userId")!, + 'page': '0', + 'size': _pageSize.toString(), + 'sort': 'createdAt,desc', + }); } @override @@ -99,13 +105,38 @@ class _HistoryScreenState extends State ], ), if (controller.model.transactions.isNotEmpty) - ListView( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), + Column( children: [ - ...controller.model.transactions.map( - (e) => _buildTransactionItem(e, context), + ListView( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + children: [ + ...controller.model.transactions.map( + (e) => _buildTransactionItem(e, context), + ), + ], ), + SizedBox(height: 10), + if (controller.model.pageableModel != null && + controller.model.pageableModel!.number < + controller.model.pageableModel!.totalPages) + OutlinedButton( + child: Text('Load more'), + onPressed: () { + controller.getTransactions({ + 'userId': prefs.getString("userId")!, + 'page': + (controller + .model + .pageableModel! + .number + + 1) + .toString(), + 'size': _pageSize.toString(), + 'sort': 'createdAt,desc', + }); + }, + ), ], ), ], diff --git a/lib/screens/home/home_controller.dart b/lib/screens/home/home_controller.dart index b554f21..062d6c5 100644 --- a/lib/screens/home/home_controller.dart +++ b/lib/screens/home/home_controller.dart @@ -1,8 +1,7 @@ -import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; -import 'package:logger/logger.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:qpay/http/http.dart'; +import 'package:qpay/models/pageable_model.dart'; part 'home_controller.freezed.dart'; part 'home_controller.g.dart'; @@ -116,11 +115,14 @@ class HomeController extends ChangeNotifier { notifyListeners(); try { - List response = await http.get( - '/transaction?userId=$userId&type=REQUEST', + Map response = await http.get( + '/transaction?sort=createdAt,desc&size=3&page=0&userId=$userId&type=REQUEST', ); + + PageableModel pageableModel = PageableModel.fromJson(response); + model.transactions = - response.map((e) => e as Map).toList(); + pageableModel.content.map((e) => e as Map).toList(); } catch (e) { logger.e(e); _showErrorSnackBar( diff --git a/lib/screens/home/home_screen.dart b/lib/screens/home/home_screen.dart index a68a9f7..7b94215 100644 --- a/lib/screens/home/home_screen.dart +++ b/lib/screens/home/home_screen.dart @@ -221,18 +221,6 @@ class _HomeScreenState extends State fontWeight: FontWeight.bold, ), ), - TextButton( - onPressed: () { - context.go('/history'); - }, - child: Text( - 'View All', - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - ), - ), - ), ], ), const SizedBox(height: 5), @@ -250,13 +238,26 @@ class _HomeScreenState extends State ], ), if (homeController.model.transactions.isNotEmpty) - ListView( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), + Column( children: [ - ...homeController.model.transactions.map( - (e) => _buildTransactionItem(e, context), + ListView( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + children: [ + ...homeController.model.transactions.map( + (e) => _buildTransactionItem(e, context), + ), + ], ), + SizedBox(height: 10), + if (homeController.model.transactions.length > + 2) + OutlinedButton( + child: Text('View All'), + onPressed: () { + context.go('/history'); + }, + ), ], ), ], diff --git a/lib/screens/pay/pay_controller.dart b/lib/screens/pay/pay_controller.dart index 305401c..3adae13 100644 --- a/lib/screens/pay/pay_controller.dart +++ b/lib/screens/pay/pay_controller.dart @@ -189,7 +189,7 @@ class PayController extends ChangeNotifier { void updatePhone(String phone) { transactionController.model.formData = transactionController.model.formData - .copyWith(creditPhone: phone); + .copyWith(debitPhone: phone); notifyListeners(); } diff --git a/lib/screens/receipt/receipt_screen.dart b/lib/screens/receipt/receipt_screen.dart index f9f908a..9c10d0e 100644 --- a/lib/screens/receipt/receipt_screen.dart +++ b/lib/screens/receipt/receipt_screen.dart @@ -125,237 +125,240 @@ class _ReceiptScreenState extends State child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Container( - padding: EdgeInsets.all(20), - decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [ - Theme.of( - context, - ).colorScheme.primary.withOpacity(0.1), - Theme.of(context).colorScheme.tertiary - .withOpacity(0.05), - Theme.of(context).colorScheme.tertiary - .withOpacity(0.15), - ], - stops: [0.0, 0.5, 1.0], - ), - border: Border.all( - color: Theme.of( - context, - ).colorScheme.primary.withOpacity(0.3), - ), - borderRadius: BorderRadius.circular(10), - boxShadow: [ - BoxShadow( + Skeletonizer( + enabled: receiptController.model.isLoading, + child: Container( + padding: EdgeInsets.all(20), + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [ + Theme.of(context).colorScheme.primary + .withOpacity(0.1), + Theme.of(context).colorScheme.tertiary + .withOpacity(0.05), + Theme.of(context).colorScheme.tertiary + .withOpacity(0.15), + ], + stops: [0.0, 0.5, 1.0], + ), + border: Border.all( color: Theme.of( context, - ).colorScheme.primary.withOpacity(0.1), - blurRadius: 10, - spreadRadius: 1, - offset: Offset(0, 2), + ).colorScheme.primary.withOpacity(0.3), ), - ], - ), - child: Column( - crossAxisAlignment: - CrossAxisAlignment.center, - children: [ - Row( - mainAxisAlignment: - MainAxisAlignment.center, - crossAxisAlignment: - CrossAxisAlignment.center, - children: [ - Icon( - transactionController - .model - .receiptData?["status"] == - 'SUCCESS' - ? Icons.check_circle - : transactionController - .model - .receiptData?["status"] == - 'PENDING' - ? Icons.pending - : Icons.cancel, - size: 18, - color: - transactionController - .model - .receiptData?["status"] == - 'SUCCESS' - ? Colors.green - : transactionController - .model - .receiptData?["status"] == - 'PENDING' - ? Colors.orange - : Colors.red, - ), - SizedBox(width: 5), - Text( - receiptController - .model - .receiptData?["debitCurrency"] ?? - "", - style: TextStyle( - fontSize: 26, - fontWeight: FontWeight.bold, + borderRadius: BorderRadius.circular(10), + boxShadow: [ + BoxShadow( + color: Theme.of(context) + .colorScheme + .primary + .withOpacity(0.1), + blurRadius: 10, + spreadRadius: 1, + offset: Offset(0, 2), + ), + ], + ), + child: Column( + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + Row( + mainAxisAlignment: + MainAxisAlignment.center, + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + Icon( + transactionController + .model + .receiptData?["status"] == + 'SUCCESS' + ? Icons.check_circle + : transactionController + .model + .receiptData?["status"] == + 'PENDING' + ? Icons.pending + : Icons.cancel, + size: 18, + color: + transactionController + .model + .receiptData?["status"] == + 'SUCCESS' + ? Colors.green + : transactionController + .model + .receiptData?["status"] == + 'PENDING' + ? Colors.orange + : Colors.red, ), - ), - SizedBox(width: 5), - Text( - receiptController - .model - .receiptData?["totalAmount"] - .toStringAsFixed(2) ?? - "", - style: TextStyle(fontSize: 26), - ), - ], - ), - Column( - crossAxisAlignment: - CrossAxisAlignment.center, - children: [ - SizedBox(height: 5), - // receiptController - // .model - // .receiptData?["providerImage"] != - // null - // ? Image.asset( - // 'assets/${receiptController.model.receiptData?["providerImage"] ?? ''}', - // width: 50, - // ) - // : SizedBox.shrink(), - Text( - receiptController - .model - .receiptData?["billName"] ?? - "", - style: TextStyle(fontSize: 14), - ), - ], - ), - SizedBox(height: 10), - Row( - mainAxisAlignment: - MainAxisAlignment.spaceEvenly, - children: [ - Column( - children: [ - Container( - width: 50, - height: 50, - decoration: BoxDecoration( - shape: BoxShape.circle, - color: Colors.white, - border: Border.all( - color: Theme.of(context) - .colorScheme - .primary - .withOpacity(0.3), - width: 1, + SizedBox(width: 5), + Text( + receiptController + .model + .receiptData?["debitCurrency"] ?? + "", + style: TextStyle( + fontSize: 26, + fontWeight: FontWeight.bold, + ), + ), + SizedBox(width: 5), + Text( + receiptController + .model + .receiptData?["totalAmount"] + .toStringAsFixed(2) ?? + "", + style: TextStyle(fontSize: 26), + ), + ], + ), + Column( + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + SizedBox(height: 5), + // receiptController + // .model + // .receiptData?["providerImage"] != + // null + // ? Image.asset( + // 'assets/${receiptController.model.receiptData?["providerImage"] ?? ''}', + // width: 50, + // ) + // : SizedBox.shrink(), + Text( + receiptController + .model + .receiptData?["billName"] ?? + "", + style: TextStyle(fontSize: 14), + ), + ], + ), + SizedBox(height: 10), + Row( + mainAxisAlignment: + MainAxisAlignment.spaceEvenly, + children: [ + Column( + children: [ + Container( + width: 50, + height: 50, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Colors.white, + border: Border.all( + color: Theme.of(context) + .colorScheme + .primary + .withOpacity(0.3), + width: 1, + ), ), - ), - child: - receiptController - .model - .isLoading - ? Center( - child: SizedBox( - width: 24, - height: 24, - child: CircularProgressIndicator( - strokeWidth: 2.5, - valueColor: - AlwaysStoppedAnimation< - Color - >( - Theme.of( - context, - ) - .colorScheme - .primary, - ), + child: + receiptController + .model + .isLoading + ? Center( + child: SizedBox( + width: 24, + height: 24, + child: CircularProgressIndicator( + strokeWidth: + 2.5, + valueColor: AlwaysStoppedAnimation< + Color + >( + Theme.of( + context, + ) + .colorScheme + .primary, + ), + ), + ), + ) + : IconButton( + onPressed: () { + receiptController + .repeatTransaction( + context, + ); + }, + icon: Icon( + Icons.repeat, + color: + Theme.of( + context, + ) + .colorScheme + .primary, + size: 24, ), ), - ) - : IconButton( - onPressed: () { - receiptController - .repeatTransaction( - context, - ); - }, - icon: Icon( - Icons.repeat, - color: - Theme.of( - context, - ) - .colorScheme - .primary, - size: 24, - ), - ), - ), - SizedBox(height: 8), - Text( - "Repeat", - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, ), - ), - ], - ), - Column( - children: [ - Container( - width: 50, - height: 50, - decoration: BoxDecoration( - shape: BoxShape.circle, - color: Colors.white, - border: Border.all( - color: Theme.of(context) - .colorScheme - .primary - .withOpacity(0.3), - width: 1, + SizedBox(height: 8), + Text( + "Repeat", + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, ), ), - child: IconButton( - onPressed: () { - _captureImage(); - }, - icon: Icon( - Icons.share, - color: - Theme.of( - context, - ).colorScheme.primary, - size: 24, + ], + ), + Column( + children: [ + Container( + width: 50, + height: 50, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Colors.white, + border: Border.all( + color: Theme.of(context) + .colorScheme + .primary + .withOpacity(0.3), + width: 1, + ), + ), + child: IconButton( + onPressed: () { + _captureImage(); + }, + icon: Icon( + Icons.share, + color: + Theme.of( + context, + ).colorScheme.primary, + size: 24, + ), ), ), - ), - SizedBox(height: 8), - Text( - "Share", - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, + SizedBox(height: 8), + Text( + "Share", + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + ), ), - ), - ], - ), - ], - ), - ], + ], + ), + ], + ), + ], + ), ), ), SizedBox(height: 20), @@ -405,247 +408,325 @@ class _ReceiptScreenState extends State SizedBox( height: MediaQuery.of(context).size.height * - 0.4, + 0.5, child: TabBarView( controller: _tabController, children: [ - Column( - children: [ - const SizedBox(height: 20), - if (receiptController - .model - .receiptData?["additionalData"] == - null) + Padding( + padding: const EdgeInsets.all(10.0), + child: Column( + children: [ Skeletonizer( enabled: receiptController .model .isLoading, - child: Column( + child: Row( + mainAxisAlignment: + MainAxisAlignment + .spaceBetween, children: [ - SizedBox(height: 20), - Center( - child: Text( - "No details found", + Text( + "Status", + style: TextStyle( + fontSize: 16, + fontWeight: + FontWeight.bold, + ), + ), + Text( + transactionController + .model + .receiptData?["status"] ?? + "", + style: TextStyle( + fontSize: 16, ), ), ], ), ), - if (receiptController + const SizedBox(height: 10), + Skeletonizer( + enabled: + receiptController + .model + .isLoading, + child: Row( + mainAxisAlignment: + MainAxisAlignment + .spaceBetween, + children: [ + Text( + "From", + style: TextStyle( + fontSize: 16, + fontWeight: + FontWeight.bold, + ), + ), + Text( + receiptController + .model + .receiptData?["debitPhone"] ?? + "", + style: TextStyle( + fontSize: 16, + ), + ), + ], + ), + ), + const SizedBox(height: 10), + Skeletonizer( + enabled: + receiptController + .model + .isLoading, + child: Row( + mainAxisAlignment: + MainAxisAlignment + .spaceBetween, + children: [ + Text( + "To", + style: TextStyle( + fontSize: 16, + fontWeight: + FontWeight.bold, + ), + ), + Text( + receiptController + .model + .receiptData?["creditAccount"] ?? + "", + style: TextStyle( + fontSize: 16, + ), + ), + ], + ), + ), + const SizedBox(height: 10), + Divider( + color: Colors.grey[300], + thickness: 1, + ), + const SizedBox(height: 10), + if (receiptController + .model + .receiptData?["additionalData"] == + null) + Skeletonizer( + enabled: + receiptController + .model + .isLoading, + child: Column( + children: [ + SizedBox(height: 20), + Center( + child: Text( + "No details found", + ), + ), + ], + ), + ), + if (receiptController + .model + .receiptData?["additionalData"] != + null) + ...receiptController .model - .receiptData?["additionalData"] != - null) - ...receiptController - .model - .receiptData?["additionalData"] - .map((data) { - return Column( - children: [ - Row( - mainAxisAlignment: - MainAxisAlignment - .spaceBetween, - children: [ - Text( - data["name"] ?? - "", - style: TextStyle( - fontSize: 16, - fontWeight: - FontWeight - .bold, + .receiptData?["additionalData"] + .map((data) { + return Column( + children: [ + Row( + mainAxisAlignment: + MainAxisAlignment + .spaceBetween, + children: [ + Text( + data["name"] ?? + "", + style: TextStyle( + fontSize: + 16, + fontWeight: + FontWeight + .bold, + ), ), - ), - Text( - data["value"] ?? - "", - style: - TextStyle( - fontSize: - 16, - ), - ), - ], - ), - const SizedBox( - height: 10, - ), - ], - ); - }) - .toList(), - ], + Text( + data["value"] ?? + "", + style: + TextStyle( + fontSize: + 16, + ), + ), + ], + ), + const SizedBox( + height: 10, + ), + ], + ); + }) + .toList(), + ], + ), ), - Column( - children: [ - const SizedBox(height: 20), - Row( - mainAxisAlignment: - MainAxisAlignment - .spaceBetween, - children: [ - Text( - "Status", - style: TextStyle( - fontSize: 16, - fontWeight: - FontWeight.bold, + Padding( + padding: const EdgeInsets.all(10.0), + child: Column( + children: [ + Row( + mainAxisAlignment: + MainAxisAlignment + .spaceBetween, + children: [ + Text( + "Amount", + style: TextStyle( + fontSize: 16, + fontWeight: + FontWeight.bold, + ), ), - ), - Text( - transactionController - .model - .receiptData?["status"] ?? - "", - style: TextStyle( - fontSize: 16, + Text( + transactionController + .model + .receiptData?["amount"] + .toStringAsFixed( + 2, + ) ?? + "0.00", + style: TextStyle( + fontSize: 16, + ), ), - ), - ], - ), - const SizedBox(height: 10), - Row( - mainAxisAlignment: - MainAxisAlignment - .spaceBetween, - children: [ - Text( - "Amount", - style: TextStyle( - fontSize: 16, - fontWeight: - FontWeight.bold, + ], + ), + const SizedBox(height: 10), + Row( + mainAxisAlignment: + MainAxisAlignment + .spaceBetween, + children: [ + Text( + "Our Charge", + style: TextStyle( + fontSize: 16, + fontWeight: + FontWeight.bold, + ), ), - ), - Text( - transactionController - .model - .receiptData?["amount"] - .toStringAsFixed( - 2, - ) ?? - "0.00", - style: TextStyle( - fontSize: 16, + Text( + transactionController + .model + .receiptData?["charge"] + .toStringAsFixed( + 2, + ) ?? + "0.00", + style: TextStyle( + fontSize: 16, + ), ), - ), - ], - ), - const SizedBox(height: 10), - Row( - mainAxisAlignment: - MainAxisAlignment - .spaceBetween, - children: [ - Text( - "Our Charge", - style: TextStyle( - fontSize: 16, - fontWeight: - FontWeight.bold, + ], + ), + const SizedBox(height: 10), + Row( + mainAxisAlignment: + MainAxisAlignment + .spaceBetween, + children: [ + Text( + "Gateway Charge", + style: TextStyle( + fontSize: 16, + fontWeight: + FontWeight.bold, + ), ), - ), - Text( - transactionController - .model - .receiptData?["charge"] - .toStringAsFixed( - 2, - ) ?? - "0.00", - style: TextStyle( - fontSize: 16, + Text( + transactionController + .model + .receiptData?["gatewayCharge"] + .toStringAsFixed( + 2, + ) ?? + "0.00", + style: TextStyle( + fontSize: 16, + ), ), - ), - ], - ), - const SizedBox(height: 10), - Row( - mainAxisAlignment: - MainAxisAlignment - .spaceBetween, - children: [ - Text( - "Gateway Charge", - style: TextStyle( - fontSize: 16, - fontWeight: - FontWeight.bold, + ], + ), + const SizedBox(height: 10), + Row( + mainAxisAlignment: + MainAxisAlignment + .spaceBetween, + children: [ + Text( + "Tax", + style: TextStyle( + fontSize: 16, + fontWeight: + FontWeight.bold, + ), ), - ), - Text( - transactionController - .model - .receiptData?["gatewayCharge"] - .toStringAsFixed( - 2, - ) ?? - "0.00", - style: TextStyle( - fontSize: 16, + Text( + transactionController + .model + .receiptData?["tax"] + .toStringAsFixed( + 2, + ) ?? + "0.00", + style: TextStyle( + fontSize: 16, + ), ), - ), - ], - ), - const SizedBox(height: 10), - Row( - mainAxisAlignment: - MainAxisAlignment - .spaceBetween, - children: [ - Text( - "Tax", - style: TextStyle( - fontSize: 16, - fontWeight: - FontWeight.bold, + ], + ), + const SizedBox(height: 10), + Row( + mainAxisAlignment: + MainAxisAlignment + .spaceBetween, + children: [ + Text( + "Total Amount", + style: TextStyle( + fontSize: 16, + fontWeight: + FontWeight.bold, + ), ), - ), - Text( - transactionController - .model - .receiptData?["tax"] - .toStringAsFixed( - 2, - ) ?? - "0.00", - style: TextStyle( - fontSize: 16, + Text( + transactionController + .model + .receiptData?["totalAmount"] + .toStringAsFixed( + 2, + ) ?? + "0.00", + style: TextStyle( + fontSize: 16, + ), ), - ), - ], - ), - const SizedBox(height: 10), - Row( - mainAxisAlignment: - MainAxisAlignment - .spaceBetween, - children: [ - Text( - "Total Amount", - style: TextStyle( - fontSize: 16, - fontWeight: - FontWeight.bold, - ), - ), - Text( - transactionController - .model - .receiptData?["totalAmount"] - .toStringAsFixed( - 2, - ) ?? - "0.00", - style: TextStyle( - fontSize: 16, - ), - ), - ], - ), - const SizedBox(height: 20), - ], + ], + ), + const SizedBox(height: 20), + ], + ), ), ], ),