From 1d8ab2088c353624cc934b4d4bfdd3884c7adeac Mon Sep 17 00:00:00 2001 From: Vusumuzi Khoza Date: Mon, 1 Jun 2026 20:49:53 +0200 Subject: [PATCH] usability fixes --- lib/screens/home/home_controller.dart | 8 +- lib/screens/home/home_controller.freezed.dart | 43 +++--- lib/screens/home/home_controller.g.dart | 2 + lib/screens/home/home_screen.dart | 134 ++++++++++++++++-- lib/screens/pay/pay_controller.dart | 13 +- lib/screens/pay/pay_screen.dart | 5 +- 6 files changed, 167 insertions(+), 38 deletions(-) diff --git a/lib/screens/home/home_controller.dart b/lib/screens/home/home_controller.dart index dbeb2a0..d8f1d5c 100644 --- a/lib/screens/home/home_controller.dart +++ b/lib/screens/home/home_controller.dart @@ -58,6 +58,7 @@ abstract class Category with _$Category { @freezed abstract class BillProvider with _$BillProvider { const factory BillProvider({ + required String id, required String clientId, required String name, required String description, @@ -100,7 +101,7 @@ class HomeController extends ChangeNotifier { return ApiResponse.success(model.accounts); } - Future>> getProviders() async { + Future>> getProviders(String currency) async { try { model.filterableProviders = getFakeProviders(); model.transactions = getFakeTransactions(); @@ -108,7 +109,9 @@ class HomeController extends ChangeNotifier { model.isLoading = true; if (!_disposed) notifyListeners(); - final response = await http.get('/public/providers?sort=priority,asc'); + final response = await http.get( + '/public/providers?currency=$currency&sort=priority,asc', + ); List providers = PageableModel.fromJson(response).content .map((e) => BillProvider.fromJson(e as Map)) .toList(); @@ -258,6 +261,7 @@ class HomeController extends ChangeNotifier { List getFakeProviders() { return [ BillProvider( + id: '1', clientId: 'econet_airtime', name: 'Econet Airtime', description: 'Econet Airtime', diff --git a/lib/screens/home/home_controller.freezed.dart b/lib/screens/home/home_controller.freezed.dart index 93ee640..cc57d8c 100644 --- a/lib/screens/home/home_controller.freezed.dart +++ b/lib/screens/home/home_controller.freezed.dart @@ -287,7 +287,7 @@ as String, /// @nodoc mixin _$BillProvider { - String get clientId; String get name; String get description; bool get requiresAccount; bool get requiresAmount; bool? get requiresAmountFromMerchant; bool get requiresPhone; bool? get requiresReversal; String? get additionalDataString; String? get processorType; String get uid; String get image; String get label; String get category; String? get accountFieldName; + String get id; String get clientId; String get name; String get description; bool get requiresAccount; bool get requiresAmount; bool? get requiresAmountFromMerchant; bool get requiresPhone; bool? get requiresReversal; String? get additionalDataString; String? get processorType; String get uid; String get image; String get label; String get category; String? get accountFieldName; /// Create a copy of BillProvider /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) @@ -300,16 +300,16 @@ $BillProviderCopyWith get copyWith => _$BillProviderCopyWithImpl Object.hash(runtimeType,clientId,name,description,requiresAccount,requiresAmount,requiresAmountFromMerchant,requiresPhone,requiresReversal,additionalDataString,processorType,uid,image,label,category,accountFieldName); +int get hashCode => Object.hash(runtimeType,id,clientId,name,description,requiresAccount,requiresAmount,requiresAmountFromMerchant,requiresPhone,requiresReversal,additionalDataString,processorType,uid,image,label,category,accountFieldName); @override String toString() { - return 'BillProvider(clientId: $clientId, name: $name, description: $description, requiresAccount: $requiresAccount, requiresAmount: $requiresAmount, requiresAmountFromMerchant: $requiresAmountFromMerchant, requiresPhone: $requiresPhone, requiresReversal: $requiresReversal, additionalDataString: $additionalDataString, processorType: $processorType, uid: $uid, image: $image, label: $label, category: $category, accountFieldName: $accountFieldName)'; + return 'BillProvider(id: $id, clientId: $clientId, name: $name, description: $description, requiresAccount: $requiresAccount, requiresAmount: $requiresAmount, requiresAmountFromMerchant: $requiresAmountFromMerchant, requiresPhone: $requiresPhone, requiresReversal: $requiresReversal, additionalDataString: $additionalDataString, processorType: $processorType, uid: $uid, image: $image, label: $label, category: $category, accountFieldName: $accountFieldName)'; } @@ -320,7 +320,7 @@ abstract mixin class $BillProviderCopyWith<$Res> { factory $BillProviderCopyWith(BillProvider value, $Res Function(BillProvider) _then) = _$BillProviderCopyWithImpl; @useResult $Res call({ - String clientId, String name, String description, bool requiresAccount, bool requiresAmount, bool? requiresAmountFromMerchant, bool requiresPhone, bool? requiresReversal, String? additionalDataString, String? processorType, String uid, String image, String label, String category, String? accountFieldName + String id, String clientId, String name, String description, bool requiresAccount, bool requiresAmount, bool? requiresAmountFromMerchant, bool requiresPhone, bool? requiresReversal, String? additionalDataString, String? processorType, String uid, String image, String label, String category, String? accountFieldName }); @@ -337,9 +337,10 @@ class _$BillProviderCopyWithImpl<$Res> /// Create a copy of BillProvider /// with the given fields replaced by the non-null parameter values. -@pragma('vm:prefer-inline') @override $Res call({Object? clientId = null,Object? name = null,Object? description = null,Object? requiresAccount = null,Object? requiresAmount = null,Object? requiresAmountFromMerchant = freezed,Object? requiresPhone = null,Object? requiresReversal = freezed,Object? additionalDataString = freezed,Object? processorType = freezed,Object? uid = null,Object? image = null,Object? label = null,Object? category = null,Object? accountFieldName = freezed,}) { +@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? clientId = null,Object? name = null,Object? description = null,Object? requiresAccount = null,Object? requiresAmount = null,Object? requiresAmountFromMerchant = freezed,Object? requiresPhone = null,Object? requiresReversal = freezed,Object? additionalDataString = freezed,Object? processorType = freezed,Object? uid = null,Object? image = null,Object? label = null,Object? category = null,Object? accountFieldName = freezed,}) { return _then(_self.copyWith( -clientId: null == clientId ? _self.clientId : clientId // ignore: cast_nullable_to_non_nullable +id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable +as String,clientId: null == clientId ? _self.clientId : clientId // ignore: cast_nullable_to_non_nullable as String,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable as String,description: null == description ? _self.description : description // ignore: cast_nullable_to_non_nullable as String,requiresAccount: null == requiresAccount ? _self.requiresAccount : requiresAccount // ignore: cast_nullable_to_non_nullable @@ -439,10 +440,10 @@ return $default(_that);case _: /// } /// ``` -@optionalTypeArgs TResult maybeWhen(TResult Function( String clientId, String name, String description, bool requiresAccount, bool requiresAmount, bool? requiresAmountFromMerchant, bool requiresPhone, bool? requiresReversal, String? additionalDataString, String? processorType, String uid, String image, String label, String category, String? accountFieldName)? $default,{required TResult orElse(),}) {final _that = this; +@optionalTypeArgs TResult maybeWhen(TResult Function( String id, String clientId, String name, String description, bool requiresAccount, bool requiresAmount, bool? requiresAmountFromMerchant, bool requiresPhone, bool? requiresReversal, String? additionalDataString, String? processorType, String uid, String image, String label, String category, String? accountFieldName)? $default,{required TResult orElse(),}) {final _that = this; switch (_that) { case _BillProvider() when $default != null: -return $default(_that.clientId,_that.name,_that.description,_that.requiresAccount,_that.requiresAmount,_that.requiresAmountFromMerchant,_that.requiresPhone,_that.requiresReversal,_that.additionalDataString,_that.processorType,_that.uid,_that.image,_that.label,_that.category,_that.accountFieldName);case _: +return $default(_that.id,_that.clientId,_that.name,_that.description,_that.requiresAccount,_that.requiresAmount,_that.requiresAmountFromMerchant,_that.requiresPhone,_that.requiresReversal,_that.additionalDataString,_that.processorType,_that.uid,_that.image,_that.label,_that.category,_that.accountFieldName);case _: return orElse(); } @@ -460,10 +461,10 @@ return $default(_that.clientId,_that.name,_that.description,_that.requiresAccoun /// } /// ``` -@optionalTypeArgs TResult when(TResult Function( String clientId, String name, String description, bool requiresAccount, bool requiresAmount, bool? requiresAmountFromMerchant, bool requiresPhone, bool? requiresReversal, String? additionalDataString, String? processorType, String uid, String image, String label, String category, String? accountFieldName) $default,) {final _that = this; +@optionalTypeArgs TResult when(TResult Function( String id, String clientId, String name, String description, bool requiresAccount, bool requiresAmount, bool? requiresAmountFromMerchant, bool requiresPhone, bool? requiresReversal, String? additionalDataString, String? processorType, String uid, String image, String label, String category, String? accountFieldName) $default,) {final _that = this; switch (_that) { case _BillProvider(): -return $default(_that.clientId,_that.name,_that.description,_that.requiresAccount,_that.requiresAmount,_that.requiresAmountFromMerchant,_that.requiresPhone,_that.requiresReversal,_that.additionalDataString,_that.processorType,_that.uid,_that.image,_that.label,_that.category,_that.accountFieldName);case _: +return $default(_that.id,_that.clientId,_that.name,_that.description,_that.requiresAccount,_that.requiresAmount,_that.requiresAmountFromMerchant,_that.requiresPhone,_that.requiresReversal,_that.additionalDataString,_that.processorType,_that.uid,_that.image,_that.label,_that.category,_that.accountFieldName);case _: throw StateError('Unexpected subclass'); } @@ -480,10 +481,10 @@ return $default(_that.clientId,_that.name,_that.description,_that.requiresAccoun /// } /// ``` -@optionalTypeArgs TResult? whenOrNull(TResult? Function( String clientId, String name, String description, bool requiresAccount, bool requiresAmount, bool? requiresAmountFromMerchant, bool requiresPhone, bool? requiresReversal, String? additionalDataString, String? processorType, String uid, String image, String label, String category, String? accountFieldName)? $default,) {final _that = this; +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String id, String clientId, String name, String description, bool requiresAccount, bool requiresAmount, bool? requiresAmountFromMerchant, bool requiresPhone, bool? requiresReversal, String? additionalDataString, String? processorType, String uid, String image, String label, String category, String? accountFieldName)? $default,) {final _that = this; switch (_that) { case _BillProvider() when $default != null: -return $default(_that.clientId,_that.name,_that.description,_that.requiresAccount,_that.requiresAmount,_that.requiresAmountFromMerchant,_that.requiresPhone,_that.requiresReversal,_that.additionalDataString,_that.processorType,_that.uid,_that.image,_that.label,_that.category,_that.accountFieldName);case _: +return $default(_that.id,_that.clientId,_that.name,_that.description,_that.requiresAccount,_that.requiresAmount,_that.requiresAmountFromMerchant,_that.requiresPhone,_that.requiresReversal,_that.additionalDataString,_that.processorType,_that.uid,_that.image,_that.label,_that.category,_that.accountFieldName);case _: return null; } @@ -495,9 +496,10 @@ return $default(_that.clientId,_that.name,_that.description,_that.requiresAccoun @JsonSerializable() class _BillProvider implements BillProvider { - const _BillProvider({required this.clientId, required this.name, required this.description, required this.requiresAccount, required this.requiresAmount, required this.requiresAmountFromMerchant, required this.requiresPhone, required this.requiresReversal, required this.additionalDataString, required this.processorType, required this.uid, required this.image, required this.label, required this.category, required this.accountFieldName}); + const _BillProvider({required this.id, required this.clientId, required this.name, required this.description, required this.requiresAccount, required this.requiresAmount, required this.requiresAmountFromMerchant, required this.requiresPhone, required this.requiresReversal, required this.additionalDataString, required this.processorType, required this.uid, required this.image, required this.label, required this.category, required this.accountFieldName}); factory _BillProvider.fromJson(Map json) => _$BillProviderFromJson(json); +@override final String id; @override final String clientId; @override final String name; @override final String description; @@ -527,16 +529,16 @@ Map toJson() { @override bool operator ==(Object other) { - return identical(this, other) || (other.runtimeType == runtimeType&&other is _BillProvider&&(identical(other.clientId, clientId) || other.clientId == clientId)&&(identical(other.name, name) || other.name == name)&&(identical(other.description, description) || other.description == description)&&(identical(other.requiresAccount, requiresAccount) || other.requiresAccount == requiresAccount)&&(identical(other.requiresAmount, requiresAmount) || other.requiresAmount == requiresAmount)&&(identical(other.requiresAmountFromMerchant, requiresAmountFromMerchant) || other.requiresAmountFromMerchant == requiresAmountFromMerchant)&&(identical(other.requiresPhone, requiresPhone) || other.requiresPhone == requiresPhone)&&(identical(other.requiresReversal, requiresReversal) || other.requiresReversal == requiresReversal)&&(identical(other.additionalDataString, additionalDataString) || other.additionalDataString == additionalDataString)&&(identical(other.processorType, processorType) || other.processorType == processorType)&&(identical(other.uid, uid) || other.uid == uid)&&(identical(other.image, image) || other.image == image)&&(identical(other.label, label) || other.label == label)&&(identical(other.category, category) || other.category == category)&&(identical(other.accountFieldName, accountFieldName) || other.accountFieldName == accountFieldName)); + return identical(this, other) || (other.runtimeType == runtimeType&&other is _BillProvider&&(identical(other.id, id) || other.id == id)&&(identical(other.clientId, clientId) || other.clientId == clientId)&&(identical(other.name, name) || other.name == name)&&(identical(other.description, description) || other.description == description)&&(identical(other.requiresAccount, requiresAccount) || other.requiresAccount == requiresAccount)&&(identical(other.requiresAmount, requiresAmount) || other.requiresAmount == requiresAmount)&&(identical(other.requiresAmountFromMerchant, requiresAmountFromMerchant) || other.requiresAmountFromMerchant == requiresAmountFromMerchant)&&(identical(other.requiresPhone, requiresPhone) || other.requiresPhone == requiresPhone)&&(identical(other.requiresReversal, requiresReversal) || other.requiresReversal == requiresReversal)&&(identical(other.additionalDataString, additionalDataString) || other.additionalDataString == additionalDataString)&&(identical(other.processorType, processorType) || other.processorType == processorType)&&(identical(other.uid, uid) || other.uid == uid)&&(identical(other.image, image) || other.image == image)&&(identical(other.label, label) || other.label == label)&&(identical(other.category, category) || other.category == category)&&(identical(other.accountFieldName, accountFieldName) || other.accountFieldName == accountFieldName)); } @JsonKey(includeFromJson: false, includeToJson: false) @override -int get hashCode => Object.hash(runtimeType,clientId,name,description,requiresAccount,requiresAmount,requiresAmountFromMerchant,requiresPhone,requiresReversal,additionalDataString,processorType,uid,image,label,category,accountFieldName); +int get hashCode => Object.hash(runtimeType,id,clientId,name,description,requiresAccount,requiresAmount,requiresAmountFromMerchant,requiresPhone,requiresReversal,additionalDataString,processorType,uid,image,label,category,accountFieldName); @override String toString() { - return 'BillProvider(clientId: $clientId, name: $name, description: $description, requiresAccount: $requiresAccount, requiresAmount: $requiresAmount, requiresAmountFromMerchant: $requiresAmountFromMerchant, requiresPhone: $requiresPhone, requiresReversal: $requiresReversal, additionalDataString: $additionalDataString, processorType: $processorType, uid: $uid, image: $image, label: $label, category: $category, accountFieldName: $accountFieldName)'; + return 'BillProvider(id: $id, clientId: $clientId, name: $name, description: $description, requiresAccount: $requiresAccount, requiresAmount: $requiresAmount, requiresAmountFromMerchant: $requiresAmountFromMerchant, requiresPhone: $requiresPhone, requiresReversal: $requiresReversal, additionalDataString: $additionalDataString, processorType: $processorType, uid: $uid, image: $image, label: $label, category: $category, accountFieldName: $accountFieldName)'; } @@ -547,7 +549,7 @@ abstract mixin class _$BillProviderCopyWith<$Res> implements $BillProviderCopyWi factory _$BillProviderCopyWith(_BillProvider value, $Res Function(_BillProvider) _then) = __$BillProviderCopyWithImpl; @override @useResult $Res call({ - String clientId, String name, String description, bool requiresAccount, bool requiresAmount, bool? requiresAmountFromMerchant, bool requiresPhone, bool? requiresReversal, String? additionalDataString, String? processorType, String uid, String image, String label, String category, String? accountFieldName + String id, String clientId, String name, String description, bool requiresAccount, bool requiresAmount, bool? requiresAmountFromMerchant, bool requiresPhone, bool? requiresReversal, String? additionalDataString, String? processorType, String uid, String image, String label, String category, String? accountFieldName }); @@ -564,9 +566,10 @@ class __$BillProviderCopyWithImpl<$Res> /// Create a copy of BillProvider /// with the given fields replaced by the non-null parameter values. -@override @pragma('vm:prefer-inline') $Res call({Object? clientId = null,Object? name = null,Object? description = null,Object? requiresAccount = null,Object? requiresAmount = null,Object? requiresAmountFromMerchant = freezed,Object? requiresPhone = null,Object? requiresReversal = freezed,Object? additionalDataString = freezed,Object? processorType = freezed,Object? uid = null,Object? image = null,Object? label = null,Object? category = null,Object? accountFieldName = freezed,}) { +@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? clientId = null,Object? name = null,Object? description = null,Object? requiresAccount = null,Object? requiresAmount = null,Object? requiresAmountFromMerchant = freezed,Object? requiresPhone = null,Object? requiresReversal = freezed,Object? additionalDataString = freezed,Object? processorType = freezed,Object? uid = null,Object? image = null,Object? label = null,Object? category = null,Object? accountFieldName = freezed,}) { return _then(_BillProvider( -clientId: null == clientId ? _self.clientId : clientId // ignore: cast_nullable_to_non_nullable +id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable +as String,clientId: null == clientId ? _self.clientId : clientId // ignore: cast_nullable_to_non_nullable as String,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable as String,description: null == description ? _self.description : description // ignore: cast_nullable_to_non_nullable as String,requiresAccount: null == requiresAccount ? _self.requiresAccount : requiresAccount // ignore: cast_nullable_to_non_nullable diff --git a/lib/screens/home/home_controller.g.dart b/lib/screens/home/home_controller.g.dart index 36b1e1f..4fd0b28 100644 --- a/lib/screens/home/home_controller.g.dart +++ b/lib/screens/home/home_controller.g.dart @@ -22,6 +22,7 @@ Map _$CategoryToJson(_Category instance) => { _BillProvider _$BillProviderFromJson(Map json) => _BillProvider( + id: json['id'] as String, clientId: json['clientId'] as String, name: json['name'] as String, description: json['description'] as String, @@ -41,6 +42,7 @@ _BillProvider _$BillProviderFromJson(Map json) => Map _$BillProviderToJson(_BillProvider instance) => { + 'id': instance.id, 'clientId': instance.clientId, 'name': instance.name, 'description': instance.description, diff --git a/lib/screens/home/home_screen.dart b/lib/screens/home/home_screen.dart index aca3c13..fbb0d2d 100644 --- a/lib/screens/home/home_screen.dart +++ b/lib/screens/home/home_screen.dart @@ -25,6 +25,7 @@ class _HomeScreenState extends State with TickerProviderStateMixin { late final router = GoRouter.of(context); bool _isLoggedIn = false; + bool _isZWGSelected = false; String initials = ''; late AnimationController _providersAnimController; @@ -103,7 +104,7 @@ class _HomeScreenState extends State with TickerProviderStateMixin { homeController = HomeController(context); await homeController.getAccounts(); await homeController.getCategories(); - await homeController.getProviders(); + await homeController.getProviders(_isZWGSelected ? "ZWG" : "USD"); prefs = await SharedPreferences.getInstance(); @@ -124,7 +125,7 @@ class _HomeScreenState extends State with TickerProviderStateMixin { Future _onRefresh() async { await homeController.getAccounts(); await homeController.getCategories(); - await homeController.getProviders(); + await homeController.getProviders(_isZWGSelected ? "ZWG" : "USD"); prefs = await SharedPreferences.getInstance(); if (prefs.getString("userId") != null) { @@ -343,14 +344,127 @@ class _HomeScreenState extends State with TickerProviderStateMixin { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ _buildSectionLabel(theme, isDark, Icons.grid_view_rounded, "Pay"), - IconButton( - icon: Icon( - Icons.refresh_rounded, - color: isDark ? Colors.white54 : Colors.black54, - size: 20, - ), - onPressed: _onRefresh, - tooltip: 'Refresh', + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + padding: const EdgeInsets.symmetric( + horizontal: 8, + vertical: 2, + ), + decoration: BoxDecoration( + color: isDark ? const Color(0xFF1E1E1E) : Colors.white, + borderRadius: BorderRadius.circular(20), + border: Border.all( + color: isDark + ? Colors.white.withValues(alpha: 0.12) + : Colors.black.withValues(alpha: 0.08), + ), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + 'USD', + style: TextStyle( + fontSize: 11, + fontWeight: FontWeight.w600, + color: !_isZWGSelected + ? theme.colorScheme.primary + : isDark + ? Colors.white54 + : Colors.black45, + ), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 4), + child: GestureDetector( + onTap: () { + setState(() { + _isZWGSelected = !_isZWGSelected; + }); + if (_isZWGSelected) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Center( + child: const Text( + 'ZWG currency not supported yet', + ), + ), + behavior: SnackBarBehavior.floating, + backgroundColor: theme.colorScheme.primary, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + duration: const Duration(seconds: 3), + width: 300, + ), + ); + } + + Future.delayed( + const Duration(milliseconds: 1000), + () { + setState(() { + _isZWGSelected = !_isZWGSelected; + }); + }, + ); + }, + child: AnimatedContainer( + duration: const Duration(milliseconds: 200), + width: 32, + height: 18, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + color: _isZWGSelected + ? theme.colorScheme.primary + : Colors.grey.shade300, + ), + child: AnimatedAlign( + duration: const Duration(milliseconds: 200), + alignment: _isZWGSelected + ? Alignment.centerRight + : Alignment.centerLeft, + child: Container( + width: 14, + height: 14, + margin: const EdgeInsets.all(2), + decoration: const BoxDecoration( + color: Colors.white, + shape: BoxShape.circle, + ), + ), + ), + ), + ), + ), + Text( + 'ZWG', + style: TextStyle( + fontSize: 11, + fontWeight: FontWeight.w600, + color: _isZWGSelected + ? theme.colorScheme.primary + : isDark + ? Colors.white54 + : Colors.black45, + ), + ), + ], + ), + ), + const SizedBox(width: 4), + IconButton( + icon: Icon( + Icons.refresh_rounded, + color: isDark ? Colors.white54 : Colors.black54, + size: 20, + ), + onPressed: _onRefresh, + tooltip: 'Refresh', + ), + ], ), ], ), diff --git a/lib/screens/pay/pay_controller.dart b/lib/screens/pay/pay_controller.dart index 59b97a7..39fa8de 100644 --- a/lib/screens/pay/pay_controller.dart +++ b/lib/screens/pay/pay_controller.dart @@ -73,7 +73,9 @@ class PayController extends ChangeNotifier { // formData can come from a repeat transaction // otherwise build it from elements of the normal flow - Future>> doTransaction([tc.FormData? formData]) async { + Future>> doTransaction([ + tc.FormData? formData, + ]) async { try { model.isLoading = true; notifyListeners(); @@ -129,7 +131,9 @@ class PayController extends ChangeNotifier { logger.e(s); model.isLoading = false; notifyListeners(); - return ApiResponse.failure("Network error. Please try again or contact support"); + return ApiResponse.failure( + "Network error. Please try again or contact support", + ); } catch (e, s) { logger.e(s); model.isLoading = false; @@ -170,8 +174,9 @@ class PayController extends ChangeNotifier { notifyListeners(); List response = await http.get('/public/payment-processors'); - model.paymentProcessors = - response.map((e) => PaymentProcessor.fromJson(e)).toList(); + model.paymentProcessors = response + .map((e) => PaymentProcessor.fromJson(e)) + .toList(); model.isLoading = false; notifyListeners(); diff --git a/lib/screens/pay/pay_screen.dart b/lib/screens/pay/pay_screen.dart index 5eb8d65..ba7c6b0 100644 --- a/lib/screens/pay/pay_screen.dart +++ b/lib/screens/pay/pay_screen.dart @@ -65,7 +65,7 @@ class _PayScreenState extends State with TickerProviderStateMixin { controller = PayController(context); controller.getPaymentProcessors(); - controller.getProducts(controller.model.selectedProvider?.uid ?? ""); + controller.getProducts(controller.model.selectedProvider?.id ?? ""); transactionController = Provider.of( context, listen: false, @@ -303,7 +303,8 @@ class _PayScreenState extends State with TickerProviderStateMixin { if (showAdditionalRecipientDetails) _buildAdditionalRecipientDetails(), const SizedBox(height: 7), - if (controller.model.products.isNotEmpty) + if (controller.model.products.isNotEmpty || + controller.model.isLoading) _buildBillProductSelector(controller), const SizedBox(height: 7), _buildPhoneField(),