diff --git a/lib/data/models/multi_wallet_transaction_cubit.dart b/lib/data/models/multi_wallet_transaction_cubit.dart index 0348f9a299bc5c40d337e651dbad6f4f2062c495..1ba5cc4f0a8eaebab13bc432c875ed866cad8805 100644 --- a/lib/data/models/multi_wallet_transaction_cubit.dart +++ b/lib/data/models/multi_wallet_transaction_cubit.dart @@ -22,6 +22,7 @@ import 'transaction.dart'; import 'transaction_state.dart'; import 'transaction_type.dart'; import 'transactions_bloc.dart'; +import 'utxo_cubit.dart'; class MultiWalletTransactionCubit extends HydratedCubit<MultiWalletTransactionState> { @@ -121,7 +122,7 @@ class MultiWalletTransactionCubit String _getTxKey(Transaction t) => '${t.to.pubKey}-${t.comment}-${t.amount}'; Future<List<Transaction>> fetchTransactions( - NodeListCubit cubit, AppCubit appCubit, + NodeListCubit cubit, UtxoCubit utxoCubit, AppCubit appCubit, {int retries = 5, int? pageSize, String? cursor, String? pubKey}) async { pubKey = _defKey(pubKey); final TransactionState currentState = _getStateOfWallet(pubKey); diff --git a/lib/data/models/transaction_cubit.dart b/lib/data/models/transaction_cubit_remove.dart similarity index 100% rename from lib/data/models/transaction_cubit.dart rename to lib/data/models/transaction_cubit_remove.dart diff --git a/lib/data/models/transactions_bloc.dart b/lib/data/models/transactions_bloc.dart index db268e2652a04c36a4454b578b3687878de5e399..30912f434ed60a0ac6d046328c5e89cbfb607c0f 100644 --- a/lib/data/models/transactions_bloc.dart +++ b/lib/data/models/transactions_bloc.dart @@ -10,6 +10,7 @@ import 'app_cubit.dart'; import 'multi_wallet_transaction_cubit.dart'; import 'node_list_cubit.dart'; import 'transaction.dart'; +import 'utxo_cubit.dart'; part 'transactions_state.dart'; @@ -29,6 +30,7 @@ class TransactionsBloc { late AppCubit appCubit; late NodeListCubit nodeListCubit; late MultiWalletTransactionCubit transCubit; + late UtxoCubit utxoCubit; static const int _pageSize = 20; @@ -71,10 +73,11 @@ class TransactionsBloc { } void init(MultiWalletTransactionCubit transCubit, NodeListCubit nodeListCubit, - AppCubit appCubit) { + AppCubit appCubit, UtxoCubit utxoCubit) { this.appCubit = appCubit; this.transCubit = transCubit; this.nodeListCubit = nodeListCubit; + this.utxoCubit = utxoCubit; } Stream<TransactionsState> _fetchTransactionsList(String? pageKey) async* { @@ -98,8 +101,8 @@ class TransactionsBloc { itemList: transCubit.transactions, ); } else { - final List<Transaction> fetchedItems = - await transCubit.fetchTransactions(nodeListCubit, appCubit, + final List<Transaction> fetchedItems = await transCubit + .fetchTransactions(nodeListCubit, utxoCubit, appCubit, cursor: pageKey, pageSize: _pageSize); final bool isLastPage = fetchedItems.length < _pageSize; diff --git a/lib/data/models/utxo.dart b/lib/data/models/utxo.dart new file mode 100644 index 0000000000000000000000000000000000000000..7e4a1950c237daed8d4fc9ce0d2989c6932e1807 --- /dev/null +++ b/lib/data/models/utxo.dart @@ -0,0 +1,32 @@ +import 'package:copy_with_extension/copy_with_extension.dart'; +import 'package:equatable/equatable.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'utxo.g.dart'; + +@JsonSerializable() +@CopyWith() +class Utxo extends Equatable { + const Utxo( + {required this.txHash, + required this.amount, + required this.base, + required this.outputIndex, + required this.writtenTime, + required this.writtenBlock}); + + factory Utxo.fromJson(Map<String, dynamic> json) => _$UtxoFromJson(json); + + Map<String, dynamic> toJson() => _$UtxoToJson(this); + + final String txHash; + final double amount; + final int base; + final int outputIndex; + final double writtenTime; + final double writtenBlock; + + @override + List<Object?> get props => + <dynamic>[txHash, amount, base, outputIndex, writtenTime, writtenBlock]; +} diff --git a/lib/data/models/utxo.g.dart b/lib/data/models/utxo.g.dart new file mode 100644 index 0000000000000000000000000000000000000000..9e34513bd2ee196a7227ef1b0583decccfc5ca5c --- /dev/null +++ b/lib/data/models/utxo.g.dart @@ -0,0 +1,136 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'utxo.dart'; + +// ************************************************************************** +// CopyWithGenerator +// ************************************************************************** + +abstract class _$UtxoCWProxy { + Utxo txHash(String txHash); + + Utxo amount(double amount); + + Utxo base(int base); + + Utxo outputIndex(int outputIndex); + + Utxo writtenTime(double writtenTime); + + Utxo writtenBlock(double writtenBlock); + + /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `Utxo(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. + /// + /// Usage + /// ```dart + /// Utxo(...).copyWith(id: 12, name: "My name") + /// ```` + Utxo call({ + String? txHash, + double? amount, + int? base, + int? outputIndex, + double? writtenTime, + double? writtenBlock, + }); +} + +/// Proxy class for `copyWith` functionality. This is a callable class and can be used as follows: `instanceOfUtxo.copyWith(...)`. Additionally contains functions for specific fields e.g. `instanceOfUtxo.copyWith.fieldName(...)` +class _$UtxoCWProxyImpl implements _$UtxoCWProxy { + const _$UtxoCWProxyImpl(this._value); + + final Utxo _value; + + @override + Utxo txHash(String txHash) => this(txHash: txHash); + + @override + Utxo amount(double amount) => this(amount: amount); + + @override + Utxo base(int base) => this(base: base); + + @override + Utxo outputIndex(int outputIndex) => this(outputIndex: outputIndex); + + @override + Utxo writtenTime(double writtenTime) => this(writtenTime: writtenTime); + + @override + Utxo writtenBlock(double writtenBlock) => this(writtenBlock: writtenBlock); + + @override + + /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `Utxo(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. + /// + /// Usage + /// ```dart + /// Utxo(...).copyWith(id: 12, name: "My name") + /// ```` + Utxo call({ + Object? txHash = const $CopyWithPlaceholder(), + Object? amount = const $CopyWithPlaceholder(), + Object? base = const $CopyWithPlaceholder(), + Object? outputIndex = const $CopyWithPlaceholder(), + Object? writtenTime = const $CopyWithPlaceholder(), + Object? writtenBlock = const $CopyWithPlaceholder(), + }) { + return Utxo( + txHash: txHash == const $CopyWithPlaceholder() || txHash == null + ? _value.txHash + // ignore: cast_nullable_to_non_nullable + : txHash as String, + amount: amount == const $CopyWithPlaceholder() || amount == null + ? _value.amount + // ignore: cast_nullable_to_non_nullable + : amount as double, + base: base == const $CopyWithPlaceholder() || base == null + ? _value.base + // ignore: cast_nullable_to_non_nullable + : base as int, + outputIndex: + outputIndex == const $CopyWithPlaceholder() || outputIndex == null + ? _value.outputIndex + // ignore: cast_nullable_to_non_nullable + : outputIndex as int, + writtenTime: + writtenTime == const $CopyWithPlaceholder() || writtenTime == null + ? _value.writtenTime + // ignore: cast_nullable_to_non_nullable + : writtenTime as double, + writtenBlock: + writtenBlock == const $CopyWithPlaceholder() || writtenBlock == null + ? _value.writtenBlock + // ignore: cast_nullable_to_non_nullable + : writtenBlock as double, + ); + } +} + +extension $UtxoCopyWith on Utxo { + /// Returns a callable class that can be used as follows: `instanceOfUtxo.copyWith(...)` or like so:`instanceOfUtxo.copyWith.fieldName(...)`. + // ignore: library_private_types_in_public_api + _$UtxoCWProxy get copyWith => _$UtxoCWProxyImpl(this); +} + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +Utxo _$UtxoFromJson(Map<String, dynamic> json) => Utxo( + txHash: json['txHash'] as String, + amount: (json['amount'] as num).toDouble(), + base: json['base'] as int, + outputIndex: json['outputIndex'] as int, + writtenTime: (json['writtenTime'] as num).toDouble(), + writtenBlock: (json['writtenBlock'] as num).toDouble(), + ); + +Map<String, dynamic> _$UtxoToJson(Utxo instance) => <String, dynamic>{ + 'txHash': instance.txHash, + 'amount': instance.amount, + 'base': instance.base, + 'outputIndex': instance.outputIndex, + 'writtenTime': instance.writtenTime, + 'writtenBlock': instance.writtenBlock, + }; diff --git a/lib/data/models/utxo_cubit.dart b/lib/data/models/utxo_cubit.dart new file mode 100644 index 0000000000000000000000000000000000000000..3ca4c969f54c0c04cabab9af4523ea60e1171854 --- /dev/null +++ b/lib/data/models/utxo_cubit.dart @@ -0,0 +1,115 @@ +import 'package:flutter/foundation.dart'; +import 'package:hydrated_bloc/hydrated_bloc.dart'; +import 'package:tuple/tuple.dart'; + +import '../../g1/api.dart'; +import 'node.dart'; +import 'utxo.dart'; +import 'utxo_state.dart'; + +class UtxoCubit extends HydratedCubit<UtxoState> { + UtxoCubit() : super(UtxoInitial()); + + @override + String get storagePrefix => kIsWeb ? 'UtxoCubit' : super.storagePrefix; + + @override + UtxoState? fromJson(Map<String, dynamic> json) { + return UtxoLoaded.fromJson(json); + } + + @override + Map<String, dynamic>? toJson(UtxoState state) { + return state is UtxoLoaded ? state.toJson() : <String, dynamic>{}; + } + + Future<void> fetchUtxos(String myPubKey) async { + emit(UtxosLoading()); + try { + bool hasMore = true; + while (hasMore) { + // For now I get all the utxos (lets improve this in the future, only getting the amount needed) + final Tuple2<Map<String, dynamic>?, Node> utxoDataResult = + await gvaFetchUtxosOfScript( + pubKeyRaw: myPubKey, + cursor: + state is UtxoLoaded ? (state as UtxoLoaded).cursor : null); + if (utxoDataResult.item1 != null) { + final List<Utxo> utxos = <Utxo>[]; + double total = state is UtxoLoaded ? (state as UtxoLoaded).total : 0; + for (final dynamic utxoRaw + in utxoDataResult.item1!['utxos'] as List<dynamic>) { + final Utxo utxo = Utxo.fromJson(utxoRaw as Map<String, dynamic>); + total += utxo.amount; + utxos.add(utxo); + } + hasMore = utxoDataResult.item1!['hasNextPage'] as bool; + final UtxoState newState = UtxoLoaded( + utxos: utxos, + total: total, + hasNextPage: utxoDataResult.item1!['hasNextPage'] as bool, + cursor: utxoDataResult.item1!['endCursor'] as String?); + emit(newState); + } + } + } catch (e) { + emit(UtxosError(e.toString())); + } + } + + List<Utxo>? consume(double amount) { + final List<Utxo> selectedUtxos = <Utxo>[]; + double coveredAmount = 0; + final Map<String, Utxo> updatedConsumedUtxos = <String, Utxo>{}; + + if (state is UtxoLoaded) { + final UtxoLoaded currentState = state as UtxoLoaded; + + for (final Utxo utxo in currentState.utxos) { + if (coveredAmount >= amount) { + break; + } + + double availableAmount = utxo.amount; + if (currentState.consumedUtxos.containsKey(utxo.txHash)) { + availableAmount = currentState.consumedUtxos[utxo.txHash]!.amount; + if (availableAmount == 0) { + // It's totally consumed, so skip it (but keep the record) + updatedConsumedUtxos[utxo.txHash] = utxo; + continue; + } + } + + final double consumeAmount = + (amount - coveredAmount).clamp(0, availableAmount); + coveredAmount += consumeAmount; + + // Update consumed UTXOs + final Utxo updatedUtxo = + currentState.consumedUtxos.containsKey(utxo.txHash) + ? currentState.consumedUtxos[utxo.txHash]! + .copyWith(amount: availableAmount - consumeAmount) + : utxo.copyWith(amount: utxo.amount - consumeAmount); + updatedConsumedUtxos[utxo.txHash] = updatedUtxo; + + if (consumeAmount > 0) + selectedUtxos.add(utxo.copyWith(amount: consumeAmount)); + } + + if (coveredAmount < amount) { + emit(UtxosError('Insufficient UTXOs to cover the requested amount')); + return null; + } + + // Emit a new state + emit(currentState.copyWith( + consumedUtxos: updatedConsumedUtxos, + // Update other fields if necessary + )); + return selectedUtxos; + } else { + emit(UtxosError('Wrong utxo state')); + return null; + } + } +} diff --git a/lib/data/models/utxo_state.dart b/lib/data/models/utxo_state.dart new file mode 100644 index 0000000000000000000000000000000000000000..d6031c131f07764d8c79f085f923771736f1e8fa --- /dev/null +++ b/lib/data/models/utxo_state.dart @@ -0,0 +1,46 @@ +import 'package:copy_with_extension/copy_with_extension.dart'; +import 'package:equatable/equatable.dart'; +import 'package:json_annotation/json_annotation.dart'; + +import 'utxo.dart'; + +part 'utxo_state.g.dart'; + +abstract class UtxoState {} + +class UtxoInitial extends UtxoState {} + +class UtxosLoading extends UtxoState {} + +class UtxosError extends UtxoState { + UtxosError(this.message); + + final String message; +} + +@JsonSerializable() +@CopyWith() +class UtxoLoaded extends UtxoState with EquatableMixin { + UtxoLoaded( + {required this.utxos, + Map<String, Utxo>? consumedUtxos, + required this.hasNextPage, + required this.cursor, + this.total = 0.0}) + : consumedUtxos = consumedUtxos ?? <String, Utxo>{}; + + factory UtxoLoaded.fromJson(Map<String, dynamic> json) => + _$UtxoLoadedFromJson(json); + + final List<Utxo> utxos; + final Map<String, Utxo> consumedUtxos; + final double total; + final bool hasNextPage; + final String? cursor; + + Map<String, dynamic> toJson() => _$UtxoLoadedToJson(this); + + @override + List<Object?> get props => + <Object?>[utxos, consumedUtxos, hasNextPage, cursor, total]; +} diff --git a/lib/data/models/utxo_state.g.dart b/lib/data/models/utxo_state.g.dart new file mode 100644 index 0000000000000000000000000000000000000000..c25c9028763eaada9a7bda99134585d3772ab5b6 --- /dev/null +++ b/lib/data/models/utxo_state.g.dart @@ -0,0 +1,127 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'utxo_state.dart'; + +// ************************************************************************** +// CopyWithGenerator +// ************************************************************************** + +abstract class _$UtxoLoadedCWProxy { + UtxoLoaded utxos(List<Utxo> utxos); + + UtxoLoaded consumedUtxos(Map<String, Utxo>? consumedUtxos); + + UtxoLoaded hasNextPage(bool hasNextPage); + + UtxoLoaded cursor(String? cursor); + + UtxoLoaded total(double total); + + /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `UtxoLoaded(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. + /// + /// Usage + /// ```dart + /// UtxoLoaded(...).copyWith(id: 12, name: "My name") + /// ```` + UtxoLoaded call({ + List<Utxo>? utxos, + Map<String, Utxo>? consumedUtxos, + bool? hasNextPage, + String? cursor, + double? total, + }); +} + +/// Proxy class for `copyWith` functionality. This is a callable class and can be used as follows: `instanceOfUtxoLoaded.copyWith(...)`. Additionally contains functions for specific fields e.g. `instanceOfUtxoLoaded.copyWith.fieldName(...)` +class _$UtxoLoadedCWProxyImpl implements _$UtxoLoadedCWProxy { + const _$UtxoLoadedCWProxyImpl(this._value); + + final UtxoLoaded _value; + + @override + UtxoLoaded utxos(List<Utxo> utxos) => this(utxos: utxos); + + @override + UtxoLoaded consumedUtxos(Map<String, Utxo>? consumedUtxos) => + this(consumedUtxos: consumedUtxos); + + @override + UtxoLoaded hasNextPage(bool hasNextPage) => this(hasNextPage: hasNextPage); + + @override + UtxoLoaded cursor(String? cursor) => this(cursor: cursor); + + @override + UtxoLoaded total(double total) => this(total: total); + + @override + + /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `UtxoLoaded(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. + /// + /// Usage + /// ```dart + /// UtxoLoaded(...).copyWith(id: 12, name: "My name") + /// ```` + UtxoLoaded call({ + Object? utxos = const $CopyWithPlaceholder(), + Object? consumedUtxos = const $CopyWithPlaceholder(), + Object? hasNextPage = const $CopyWithPlaceholder(), + Object? cursor = const $CopyWithPlaceholder(), + Object? total = const $CopyWithPlaceholder(), + }) { + return UtxoLoaded( + utxos: utxos == const $CopyWithPlaceholder() || utxos == null + ? _value.utxos + // ignore: cast_nullable_to_non_nullable + : utxos as List<Utxo>, + consumedUtxos: consumedUtxos == const $CopyWithPlaceholder() + ? _value.consumedUtxos + // ignore: cast_nullable_to_non_nullable + : consumedUtxos as Map<String, Utxo>?, + hasNextPage: + hasNextPage == const $CopyWithPlaceholder() || hasNextPage == null + ? _value.hasNextPage + // ignore: cast_nullable_to_non_nullable + : hasNextPage as bool, + cursor: cursor == const $CopyWithPlaceholder() + ? _value.cursor + // ignore: cast_nullable_to_non_nullable + : cursor as String?, + total: total == const $CopyWithPlaceholder() || total == null + ? _value.total + // ignore: cast_nullable_to_non_nullable + : total as double, + ); + } +} + +extension $UtxoLoadedCopyWith on UtxoLoaded { + /// Returns a callable class that can be used as follows: `instanceOfUtxoLoaded.copyWith(...)` or like so:`instanceOfUtxoLoaded.copyWith.fieldName(...)`. + // ignore: library_private_types_in_public_api + _$UtxoLoadedCWProxy get copyWith => _$UtxoLoadedCWProxyImpl(this); +} + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +UtxoLoaded _$UtxoLoadedFromJson(Map<String, dynamic> json) => UtxoLoaded( + utxos: (json['utxos'] as List<dynamic>) + .map((e) => Utxo.fromJson(e as Map<String, dynamic>)) + .toList(), + consumedUtxos: (json['consumedUtxos'] as Map<String, dynamic>?)?.map( + (k, e) => MapEntry(k, Utxo.fromJson(e as Map<String, dynamic>)), + ), + hasNextPage: json['hasNextPage'] as bool, + cursor: json['cursor'] as String?, + total: (json['total'] as num?)?.toDouble() ?? 0.0, + ); + +Map<String, dynamic> _$UtxoLoadedToJson(UtxoLoaded instance) => + <String, dynamic>{ + 'utxos': instance.utxos, + 'consumedUtxos': instance.consumedUtxos, + 'total': instance.total, + 'hasNextPage': instance.hasNextPage, + 'cursor': instance.cursor, + }; diff --git a/lib/g1/api.dart b/lib/g1/api.dart index 0f6087d4ba79329d439bf54d4837f1d23c7511cb..20bcc2b1a5f733005e4ec3a247f39b6f495b1644 100644 --- a/lib/g1/api.dart +++ b/lib/g1/api.dart @@ -662,6 +662,18 @@ Future<Tuple2<String?, Node>> gvaNick(String pubKey) async { pubKey, (Gva gva) => gva.getUsername(extractPublicKey(pubKey))); } +Future<Tuple2<Map<String, dynamic>?, Node>> gvaFetchUtxosOfScript( + {required String pubKeyRaw, + int pageSize = 100, + String? cursor, + int? amount}) { + final String pubKey = extractPublicKey(pubKeyRaw); + return gvaFunctionWrapper<Map<String, dynamic>>( + pubKey, + (Gva gva) => gva.fetchUtxosOfScript( + script: pubKey, pageSize: pageSize, amount: amount, cursor: cursor)); +} + Future<Tuple2<T?, Node>> gvaFunctionWrapper<T>( String pubKey, Future<T?> Function(Gva) specificFunction) async { final List<Node> nodes = _getBestGvaNodes(); diff --git a/lib/main.dart b/lib/main.dart index 5372779ab5a4473294c52ef0643bbee4d8a53c8f..c6ea96f3a13d51149de78f06189f80a446e3ea12 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -42,7 +42,8 @@ import 'data/models/node_manager.dart'; import 'data/models/node_type.dart'; import 'data/models/payment_cubit.dart'; import 'data/models/theme_cubit.dart'; -import 'data/models/transaction_cubit.dart'; +import 'data/models/transaction_cubit_remove.dart'; +import 'data/models/utxo_cubit.dart'; import 'g1/api.dart'; import 'g1/g1_helper.dart'; import 'shared_prefs_helper.dart'; @@ -148,7 +149,9 @@ void main() async { create: (BuildContext context) => NodeListCubit()), BlocProvider<ContactsCubit>( create: (BuildContext context) => ContactsCubit()), - // TODO(vjrj): Remove when clean the state of this + BlocProvider<UtxoCubit>( + create: (BuildContext context) => UtxoCubit()), + // TODO(vjrj): Remove when clean the state of this after upgrades BlocProvider<TransactionCubitRemove>( create: (BuildContext context) => TransactionCubitRemove()), BlocProvider<MultiWalletTransactionCubit>( diff --git a/lib/ui/ui_helpers.dart b/lib/ui/ui_helpers.dart index 72c97104bd6999bd703838cff510a2f5f62cc3b2..40d5966ed2b4895eeccc245e9236c476f24c9e9e 100644 --- a/lib/ui/ui_helpers.dart +++ b/lib/ui/ui_helpers.dart @@ -20,6 +20,7 @@ import '../data/models/cesium_card.dart'; import '../data/models/contact.dart'; import '../data/models/multi_wallet_transaction_cubit.dart'; import '../data/models/node_list_cubit.dart'; +import '../data/models/utxo_cubit.dart'; import '../g1/api.dart'; import '../g1/currency.dart'; import '../shared_prefs_helper.dart'; @@ -263,6 +264,7 @@ void initGetItAll() { MultiWalletTransactionCubit()); getIt.registerSingleton<AppCubit>(AppCubit()); getIt.registerSingleton<NodeListCubit>(NodeListCubit()); + getIt.registerSingleton<UtxoCubit>(UtxoCubit()); } } @@ -290,12 +292,13 @@ Future<void> fetchTransactionsFromBackground([bool init = true]) async { loggerDev('Initialized background context'); final GetIt getIt = GetIt.instance; final AppCubit appCubit = getIt.get<AppCubit>(); + final UtxoCubit utxoCubit = getIt.get<UtxoCubit>(); final MultiWalletTransactionCubit transCubit = getIt.get<MultiWalletTransactionCubit>(); final NodeListCubit nodeListCubit = getIt.get<NodeListCubit>(); for (final CesiumCard card in SharedPreferencesHelper().cards) { loggerDev('Fetching transactions for ${card.pubKey} in background'); - transCubit.fetchTransactions(nodeListCubit, appCubit, + transCubit.fetchTransactions(nodeListCubit, utxoCubit, appCubit, pubKey: card.pubKey); } if (inDevelopment) { @@ -315,8 +318,10 @@ Future<void> fetchTransactions(BuildContext context) async { final MultiWalletTransactionCubit transCubit = context.read<MultiWalletTransactionCubit>(); final NodeListCubit nodeListCubit = context.read<NodeListCubit>(); + final UtxoCubit utxoCubit = context.read<UtxoCubit>(); for (final CesiumCard card in SharedPreferencesHelper().cards) { - transCubit.fetchTransactions(nodeListCubit, appCubit, pubKey: card.pubKey); + transCubit.fetchTransactions(nodeListCubit, utxoCubit, appCubit, + pubKey: card.pubKey); } } diff --git a/lib/ui/widgets/fourth_screen/transaction_page.dart b/lib/ui/widgets/fourth_screen/transaction_page.dart index 06da55bd68d274b31e70fa760a89bb76ff4caa36..5f90f55eba2f44f8f63ecb0d0804c4d1bb71d78b 100644 --- a/lib/ui/widgets/fourth_screen/transaction_page.dart +++ b/lib/ui/widgets/fourth_screen/transaction_page.dart @@ -16,6 +16,7 @@ import '../../../data/models/node_list_cubit.dart'; import '../../../data/models/theme_cubit.dart'; import '../../../data/models/transaction.dart'; import '../../../data/models/transactions_bloc.dart'; +import '../../../data/models/utxo_cubit.dart'; import '../../../g1/currency.dart'; import '../../../shared_prefs_helper.dart'; import '../../logger.dart'; @@ -43,6 +44,7 @@ class _TransactionsAndBalanceWidgetState late AppCubit appCubit; late NodeListCubit nodeListCubit; late MultiWalletTransactionCubit transCubit; + late UtxoCubit utxoCubit; final PagingController<String?, Transaction> _pagingController = PagingController<String?, Transaction>(firstPageKey: null); @@ -62,7 +64,8 @@ class _TransactionsAndBalanceWidgetState appCubit = context.read<AppCubit>(); transCubit = context.read<MultiWalletTransactionCubit>(); nodeListCubit = context.read<NodeListCubit>(); - _bloc.init(transCubit, nodeListCubit, appCubit); + utxoCubit = context.read<UtxoCubit>(); + _bloc.init(transCubit, nodeListCubit, appCubit, utxoCubit); _pagingController.addPageRequestListener((String? cursor) { _bloc.onPageRequestSink.add(cursor); }); @@ -114,7 +117,7 @@ class _TransactionsAndBalanceWidgetState _refresh(); } catch (e) { logger('Failed via _refresh, lets try a basic fetchTransactions'); - transCubit.fetchTransactions(nodeListCubit, appCubit); + transCubit.fetchTransactions(nodeListCubit, utxoCubit, appCubit); } }); tutorial = FourthTutorial(context); diff --git a/pubspec.lock b/pubspec.lock index 8613d6663394cfff978ae5e99baa05d83a899f39..35923306400dd55b99f1d0c927fe8ff935bdef74 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -380,11 +380,9 @@ packages: durt: dependency: "direct main" description: - path: "." - ref: HEAD - resolved-ref: c1fb263a8d03c470590b6b234413b221767fdb9d - url: "https://git.duniter.org/vjrj/durt.git" - source: git + path: "../durt" + relative: true + source: path version: "0.1.6" easy_debounce: dependency: "direct main" diff --git a/pubspec.yaml b/pubspec.yaml index e8faaf545e34951591aa7011313042e10160bec6..e2f48b092382f3df5adc9d478cdfa487b85aa8cb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -18,192 +18,192 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev version: 1.0.2 environment: - sdk: ">=3.0.0 <4.0.0" + sdk: ">=3.0.0 <4.0.0" dependencies: - flutter: - sdk: flutter - bloc: ^8.1.0 - flutter_bloc: ^8.1.1 - hydrated_bloc: ^9.0.0 - equatable: ^2.0.5 - flutter_displaymode: ^0.6.0 - easy_localization: ^3.0.1 - hive: ^2.2.3 - url_launcher: ^6.1.7 - hive_flutter: ^1.1.0 - flutter_svg: ^2.0.2 - flutter_dotenv: ^5.0.2 - http: ^0.13.5 - easy_logger: ^0.0.2 - qr_flutter: ^4.0.0 - introduction_screen: ^3.1.6 - responsive_framework: ^0.2.0 - #durt: ^0.1.6 - durt: - # path: ../durt - git: - url: https://git.duniter.org/vjrj/durt.git - flutter_neumorphic: - git: - url: https://github.com/den0206/Flutter-Neumorphic.git - ref: feature/remoce_accentcolor - shared_preferences: ^2.0.18 - vibration: ^1.7.6 - clipboard: ^0.1.3 - # See: https://github.com/leocavalcante/encrypt/issues/314 - encrypt: 5.0.1 - universal_html: ^2.0.9 - fl_chart: ^0.63.0 - json_annotation: ^4.8.0 - flutter_slidable: ^3.0.0 - sentry_flutter: ^7.8.0 - copy_with_extension: ^5.0.2 - timeago: ^3.5.0 - once: ^1.5.1 - pattern_lock: ^2.0.0 - package_info_plus: ^4.1.0 - share_plus: ^7.1.0 - sentry_logging: ^7.8.0 - pwa_install: ^0.0.5 - file_saver: ^0.2.1 - filesystem_picker: ^3.1.0 - path: ^1.8.2 - path_provider: ^2.0.14 - awesome_notifications: ^0.7.5-dev.3 - cron: ^0.5.1 - barcode_scan2: ^4.2.4 - jsqr: ^0.1.4 - web_browser_detect: ^2.0.3 - tuple: ^2.0.1 - infinite_scroll_pagination: ^4.0.0 - easy_debounce: ^2.0.3 - tutorial_coach_mark: ^1.2.8 - lehttp_overrides: ^1.0.2 - feedback_gitlab: ^2.2.0 - connectivity_wrapper: ^1.1.3 - rxdart: ^0.27.7 - fast_image_resizer: ^0.0.2 - toggle_switch: ^2.1.0 - fast_base58: ^0.2.1 - crypto: ^3.0.3 - flutter_nfc_kit: ^3.3.3 - ndef: ^0.3.1 - uni_links: ^0.5.1 - feedback: ^2.6.0 - sentry_dart_plugin: ^1.5.0 - check_vpn_connection: ^0.0.2 - provider: ^6.0.5 - we_slide: ^2.4.0 - workmanager: ^0.5.1 - get_it: ^7.6.4 - l10n_esperanto: ^2.0.6 + flutter: + sdk: flutter + bloc: ^8.1.0 + flutter_bloc: ^8.1.1 + hydrated_bloc: ^9.0.0 + equatable: ^2.0.5 + flutter_displaymode: ^0.6.0 + easy_localization: ^3.0.1 + hive: ^2.2.3 + url_launcher: ^6.1.7 + hive_flutter: ^1.1.0 + flutter_svg: ^2.0.2 + flutter_dotenv: ^5.0.2 + http: ^0.13.5 + easy_logger: ^0.0.2 + qr_flutter: ^4.0.0 + introduction_screen: ^3.1.6 + responsive_framework: ^0.2.0 + #durt: ^0.1.6 + durt: + path: ../durt + #git: + # url: https://git.duniter.org/vjrj/durt.git + flutter_neumorphic: + git: + url: https://github.com/den0206/Flutter-Neumorphic.git + ref: feature/remoce_accentcolor + shared_preferences: ^2.0.18 + vibration: ^1.7.6 + clipboard: ^0.1.3 + # See: https://github.com/leocavalcante/encrypt/issues/314 + encrypt: 5.0.1 + universal_html: ^2.0.9 + fl_chart: ^0.63.0 + json_annotation: ^4.8.0 + flutter_slidable: ^3.0.0 + sentry_flutter: ^7.8.0 + copy_with_extension: ^5.0.2 + timeago: ^3.5.0 + once: ^1.5.1 + pattern_lock: ^2.0.0 + package_info_plus: ^4.1.0 + share_plus: ^7.1.0 + sentry_logging: ^7.8.0 + pwa_install: ^0.0.5 + file_saver: ^0.2.1 + filesystem_picker: ^3.1.0 + path: ^1.8.2 + path_provider: ^2.0.14 + awesome_notifications: ^0.7.5-dev.3 + cron: ^0.5.1 + barcode_scan2: ^4.2.4 + jsqr: ^0.1.4 + web_browser_detect: ^2.0.3 + tuple: ^2.0.1 + infinite_scroll_pagination: ^4.0.0 + easy_debounce: ^2.0.3 + tutorial_coach_mark: ^1.2.8 + lehttp_overrides: ^1.0.2 + feedback_gitlab: ^2.2.0 + connectivity_wrapper: ^1.1.3 + rxdart: ^0.27.7 + fast_image_resizer: ^0.0.2 + toggle_switch: ^2.1.0 + fast_base58: ^0.2.1 + crypto: ^3.0.3 + flutter_nfc_kit: ^3.3.3 + ndef: ^0.3.1 + uni_links: ^0.5.1 + feedback: ^2.6.0 + sentry_dart_plugin: ^1.5.0 + check_vpn_connection: ^0.0.2 + provider: ^6.0.5 + we_slide: ^2.4.0 + workmanager: ^0.5.1 + get_it: ^7.6.4 + l10n_esperanto: ^2.0.6 dev_dependencies: - flutter_test: - sdk: flutter - flutter_lints: ^2.0.1 - build_runner: ^2.3.3 - json_serializable: ^6.6.1 - copy_with_extension_gen: any + flutter_test: + sdk: flutter + flutter_lints: ^2.0.1 + build_runner: ^2.3.3 + json_serializable: ^6.6.1 + copy_with_extension_gen: any # source: https://stackoverflow.com/a/75332857/8301867 dependency_overrides: - web_socket_channel: 2.2.0 - intl: ^0.18.1 + web_socket_channel: 2.2.0 + intl: ^0.18.1 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec # The following section is specific to Flutter. flutter: - # The following line ensures that the Material Icons font is - # included with your application, so that you can use the icons in - # the material Icons class. - uses-material-design: true + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true - assets: - - assets/translations/ - - assets/img/gbrevedot.svg - - assets/img/gbrevedot.png - - assets/img/gbrevedot_color.png - - assets/img/gbrevedot_alt.svg - - assets/img/gbrevedot_alt.png - - assets/.env.development - - assets/env.production.txt - - assets/env-test.production.txt - - assets/img/undraw_intro_1.png - - assets/img/undraw_intro_2.png - - assets/img/undraw_intro_3.png - - assets/img/undraw_intro_4.png - - assets/img/undraw_intro_5.png - - assets/img/chip.svg - - assets/img/logo.png - - assets/img/favicon.png - - assets/img/logo-duniter.png - - assets/img/logo-cesium.png - - assets/tx.json - - assets/gva-tx.json - - assets/img/animated-bell.gif - - assets/img/pos.png + assets: + - assets/translations/ + - assets/img/gbrevedot.svg + - assets/img/gbrevedot.png + - assets/img/gbrevedot_color.png + - assets/img/gbrevedot_alt.svg + - assets/img/gbrevedot_alt.png + - assets/.env.development + - assets/env.production.txt + - assets/env-test.production.txt + - assets/img/undraw_intro_1.png + - assets/img/undraw_intro_2.png + - assets/img/undraw_intro_3.png + - assets/img/undraw_intro_4.png + - assets/img/undraw_intro_5.png + - assets/img/chip.svg + - assets/img/logo.png + - assets/img/favicon.png + - assets/img/logo-duniter.png + - assets/img/logo-cesium.png + - assets/tx.json + - assets/gva-tx.json + - assets/img/animated-bell.gif + - assets/img/pos.png - fonts: - - family: Nunito - fonts: - - asset: assets/fonts/Nunito-Bold.ttf - weight: 700 - - asset: assets/fonts/Nunito-Medium.ttf - weight: 500 - - asset: assets/fonts/Nunito-Regular.ttf - weight: 400 - - asset: assets/fonts/Nunito-Light.ttf - weight: 300 - - family: SourceCodePro - fonts: - - asset: assets/fonts/SourceCodePro-Regular.ttf + fonts: + - family: Nunito + fonts: + - asset: assets/fonts/Nunito-Bold.ttf + weight: 700 + - asset: assets/fonts/Nunito-Medium.ttf + weight: 500 + - asset: assets/fonts/Nunito-Regular.ttf + weight: 400 + - asset: assets/fonts/Nunito-Light.ttf + weight: 300 + - family: SourceCodePro + fonts: + - asset: assets/fonts/SourceCodePro-Regular.ttf - # To add assets to your application, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg + # To add assets to your application, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/assets-and-images/#resolution-aware. + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware. - # For details regarding adding assets from package dependencies, see - # https://flutter.dev/assets-and-images/#from-packages + # For details regarding adding assets from package dependencies, see + # https://flutter.dev/assets-and-images/#from-packages - # To add custom fonts to your application, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts from package dependencies, - # see https://flutter.dev/custom-fonts/#from-packages + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.dev/custom-fonts/#from-packages sentry: - upload_debug_symbols: true - upload_source_maps: true - upload_sources: true - project: ginkgo - org: comunes - url: https://sentry.comunes.org - #wait_for_processing: false - #log_level: error # possible values: trace, debug, info, warn, error - log_level: info # possible values: trace, debug, info, warn, error - # release: default: name@version from pubspec - #web_build_path: ... - # commits: auto - ignore_missing: true + upload_debug_symbols: true + upload_source_maps: true + upload_sources: true + project: ginkgo + org: comunes + url: https://sentry.comunes.org + #wait_for_processing: false + #log_level: error # possible values: trace, debug, info, warn, error + log_level: info # possible values: trace, debug, info, warn, error + # release: default: name@version from pubspec + #web_build_path: ... + # commits: auto + ignore_missing: true