diff --git a/lib/data/models/transaction_cubit.dart b/lib/data/models/transaction_cubit.dart index 0ec452f8a3d6e7df90a658a7264446d27c32edec..fb54f6a35f3bb8a94d74f287b8e7f733885a0847 100644 --- a/lib/data/models/transaction_cubit.dart +++ b/lib/data/models/transaction_cubit.dart @@ -31,7 +31,7 @@ class TransactionsCubit extends HydratedCubit<TransactionsAndBalanceState> { Future<void> fetchTransactions(NodeListCubit cubit) async { logger('Loading transactions'); final Map<String, dynamic>? txData = - await gva().history(SharedPreferencesHelper().getPubKey()); + await gvaHistoryAndBalance(SharedPreferencesHelper().getPubKey()); if (txData == null) { logger('Failed to get transactions'); return; diff --git a/lib/g1/api.dart b/lib/g1/api.dart index e7caa27550fb1e929dcba81af9a2bc93347a0a4b..93b9f489a9e4125df4463264da5de2f581d0eb1b 100644 --- a/lib/g1/api.dart +++ b/lib/g1/api.dart @@ -411,10 +411,7 @@ Future<String> pay( final String node = output; try { final Gva gva = Gva(node: node); - logger('Trying $node to get balance'); final CesiumWallet wallet = await SharedPreferencesHelper().getWallet(); - logger('Current balance ${await gva.balance(wallet.pubkey)}'); - // logger('Current balance ${await gva.balance(wallet.pubkey)}'); logger( 'Trying $node to send $amount to $to with comment ${comment ?? ''}'); @@ -448,40 +445,33 @@ String getGvaNode() { } } -Future<double> gvaBalance() async { - final String output = getGvaNode(); - if (Uri.tryParse(output) != null) { - final String node = output; - try { - final Gva gva = Gva(node: node); - logger('Trying $node to get balance'); - final String pubKey = SharedPreferencesHelper().getPubKey(); - final double balance = await gva.balance(pubKey); - logger('Current balance $balance'); - return balance; - } catch (e, stacktrace) { - // move logger outside main - logger(e); - logger(stacktrace); - throw Exception('Oops! failed to obtain balance'); - } +Future<Map<String, dynamic>?> gvaHistoryAndBalance(String pubKey) async { + final List<Node> nodes = NodeManager().nodeList(NodeType.gva); + if (nodes.isEmpty) { + nodes.addAll(defaultGvaNodes); } - throw Exception('Sorry: I cannot find a working node to get your balance'); -} - -Gva gva() { - final String output = getGvaNode(); - if (Uri.tryParse(output) != null) { - final String node = output; + for (int i = 0; i < nodes.length; i++) { + final Node node = nodes[i]; + if (node.errors >= NodeManager.maxNodeErrors) { + logger('Too much errors skip ${node.url}'); + continue; + } try { - final Gva gva = Gva(node: node); - return gva; - } catch (e, stacktrace) { - // move logger outside main - logger(e); - logger(stacktrace); - throw Exception('Oops! failed to obtain balance'); + final String output = getGvaNode(); + if (Uri.tryParse(output) != null) { + final String node = output; + final Gva gva = Gva(node: node); + final Map<String, dynamic>? result = await gva.history(pubKey); + return result; + } + } catch (e) { + logger('Error trying ${node.url} $e'); + logger('Increasing node errors of ${node.url} (${node.errors})'); + NodeManager() + .updateNode(NodeType.gva, node.copyWith(errors: node.errors + 1)); + continue; } } - throw Exception('Sorry: I cannot find a working node to get your balance'); + throw Exception( + 'Sorry: I cannot find a working node to get your transactions'); } diff --git a/lib/ui/widgets/fourth_screen/transaction_page.dart b/lib/ui/widgets/fourth_screen/transaction_page.dart index aefc10e448cb2b4fb7f3da5e52979a768f556f46..523a2ec79d5294d0396edf723af6a8141158c308 100644 --- a/lib/ui/widgets/fourth_screen/transaction_page.dart +++ b/lib/ui/widgets/fourth_screen/transaction_page.dart @@ -11,7 +11,6 @@ import '../../../data/models/transaction.dart'; import '../../../data/models/transaction_cubit.dart'; import '../../../shared_prefs.dart'; import '../../ui_helpers.dart'; -import '../loading_box.dart'; import 'transaction_chart.dart'; import 'transaction_item.dart'; @@ -52,20 +51,18 @@ class _TransactionsAndBalanceWidgetState if (/* _transScrollController.position.pixels == _transScrollController.position.maxScrollExtent || */ _transScrollController.offset == 0) { - await _refreshTransactions(); + // await _refreshTransactions(); + _refreshIndicatorKey.currentState?.show(); } } Future<void> _refreshTransactions() async { - setState(() { - isLoading = true; - }); - await transCubit.fetchTransactions(nodeListCubit); - setState(() { - isLoading = false; - }); + return transCubit.fetchTransactions(nodeListCubit); } + final GlobalKey<RefreshIndicatorState> _refreshIndicatorKey = + GlobalKey<RefreshIndicatorState>(); + @override Widget build(BuildContext context) { final String myPubKey = SharedPreferencesHelper().getPubKey(); @@ -76,67 +73,70 @@ class _TransactionsAndBalanceWidgetState final ContactsCubit contactsCubit = context.read<ContactsCubit>(); final List<Transaction> transactions = transBalanceState.transactions; final double balance = transBalanceState.balance; - if (!isLoading) { - return BackdropScaffold( - appBar: BackdropAppBar( - backgroundColor: Theme.of(context).colorScheme.inversePrimary, - title: Text(tr('balance')), - actions: <Widget>[ - IconButton( - icon: const Icon(Icons.refresh), - onPressed: () { - _refreshTransactions(); - }, - ), - const BackdropToggleButton( - // The default - // icon: AnimatedIcons.close_menu, - ) - ], - ), - backLayer: Center( - child: Container( - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.inversePrimary, - border: Border.all( - color: Theme.of(context).colorScheme.inversePrimary, - width: 3), - /* borderRadius: const BorderRadius.only( + return BackdropScaffold( + appBar: BackdropAppBar( + backgroundColor: Theme.of(context).colorScheme.inversePrimary, + title: Text(tr('balance')), + actions: <Widget>[ + IconButton( + icon: const Icon(Icons.refresh), + onPressed: () { + _refreshIndicatorKey.currentState?.show(); + // _refreshTransactions(); + }, + ), + const BackdropToggleButton( + // The default + // icon: AnimatedIcons.close_menu, + ) + ], + ), + backLayer: Center( + child: Container( + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.inversePrimary, + border: Border.all( + color: Theme.of(context).colorScheme.inversePrimary, + width: 3), + /* borderRadius: const BorderRadius.only( topLeft: Radius.circular(8), topRight: Radius.circular(8), ), */ - ), - child: Scrollbar( - child: ListView( - // controller: scrollController, - children: <Widget>[ - Padding( - padding: const EdgeInsets.symmetric(vertical: 10.0), - child: Center( - child: Text( - formatKAmount(context, balance), - style: TextStyle( - fontSize: 36.0, - color: balance == 0 - ? Colors.lightBlue - : Colors.lightBlue, - fontWeight: FontWeight.bold), - )), - ), - if (!kReleaseMode) TransactionChart() - /*BalanceChart( + ), + child: Scrollbar( + child: ListView( + // controller: scrollController, + children: <Widget>[ + Padding( + padding: const EdgeInsets.symmetric(vertical: 10.0), + child: Center( + child: Text( + formatKAmount(context, balance), + style: TextStyle( + fontSize: 36.0, + color: + balance == 0 ? Colors.lightBlue : Colors.lightBlue, + fontWeight: FontWeight.bold), + )), + ), + if (!kReleaseMode) TransactionChart() + /*BalanceChart( transactions: .transactions),*/ - ], - )), + ], )), - subHeader: BackdropSubHeader( - title: Text(tr('transactions')), + )), + subHeader: BackdropSubHeader( + title: Text(tr('transactions')), + divider: Divider( + color: Theme.of(context).colorScheme.surfaceVariant, + height: 0, ), - frontLayer: Center( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: <Widget>[ - /* Container( + ), + frontLayer: Center( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: <Widget>[ + /* Container( /* color: Theme .of(context) .colorScheme @@ -146,31 +146,37 @@ class _TransactionsAndBalanceWidgetState child: const Padding( padding: EdgeInsets.symmetric(horizontal: 16), child: Header(text: 'transactions'))), */ - Expanded( + Expanded( child: Padding( - padding: const EdgeInsets.fromLTRB(0, 0, 0, 50), - child: transactions.isEmpty - ? Padding( - padding: const EdgeInsets.symmetric( - horizontal: 20), - child: Center( - child: Text(tr('no_transactions')))) - : ListView.builder( - physics: - const AlwaysScrollableScrollPhysics(), - shrinkWrap: true, - controller: _transScrollController, - itemCount: transactions.length, - // Size of elements - // itemExtent: 100, - itemBuilder: - (BuildContext context, int index) { - return TransactionListItem( - index: index, - transaction: transactions[index], - avatar: avatar(null), - ); - /* + padding: const EdgeInsets.fromLTRB(0, 0, 0, 50), + child: transactions.isEmpty + ? Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: Center(child: Text(tr('no_transactions')))) + : RefreshIndicator( + key: _refreshIndicatorKey, + color: Colors.white, + backgroundColor: + Theme.of(context).colorScheme.primary, + strokeWidth: 4.0, + onRefresh: () async { + return _refreshTransactions(); + }, + // Pull from top to show refresh indicator. + child: ListView.builder( + physics: const AlwaysScrollableScrollPhysics(), + shrinkWrap: true, + controller: _transScrollController, + itemCount: transactions.length, + // Size of elements + // itemExtent: 100, + itemBuilder: (BuildContext context, int index) { + return TransactionListItem( + index: index, + transaction: transactions[index], + avatar: avatar(null), + ); + /* Slidable( // Specify a key if the Slidable is dismissible. @@ -238,14 +244,11 @@ class _TransactionsAndBalanceWidgetState : Colors.blue)), )); */ - }, - )), - ) - ]), - )); - } else { - return const LoadingScreen(); - } + }, + )), + )) + ]), + )); }); }