diff --git a/lib/pages/wallet_view/transaction_views/tx_v2/boost_transaction_view.dart b/lib/pages/wallet_view/transaction_views/tx_v2/boost_transaction_view.dart index 4f7c34f9b..4a4f40504 100644 --- a/lib/pages/wallet_view/transaction_views/tx_v2/boost_transaction_view.dart +++ b/lib/pages/wallet_view/transaction_views/tx_v2/boost_transaction_view.dart @@ -15,7 +15,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:isar/isar.dart'; -import 'package:url_launcher/url_launcher.dart'; import '../../../../models/isar/models/blockchain_data/transaction.dart'; import '../../../../models/isar/models/blockchain_data/v2/transaction_v2.dart'; @@ -27,7 +26,6 @@ import '../../../../providers/providers.dart'; import '../../../../themes/stack_colors.dart'; import '../../../../utilities/amount/amount.dart'; import '../../../../utilities/amount/amount_formatter.dart'; -import '../../../../utilities/block_explorers.dart'; import '../../../../utilities/constants.dart'; import '../../../../utilities/logger.dart'; import '../../../../utilities/text_styles.dart'; @@ -39,9 +37,9 @@ import '../../../../wallets/isar/providers/wallet_info_provider.dart'; import '../../../../wallets/wallet/impl/epiccash_wallet.dart'; import '../../../../wallets/wallet/wallet_mixin_interfaces/spark_interface.dart'; import '../../../../widgets/background.dart'; +import '../../../../widgets/boost_fee_slider.dart'; import '../../../../widgets/conditional_parent.dart'; import '../../../../widgets/custom_buttons/app_bar_icon_button.dart'; -import '../../../../widgets/custom_buttons/blue_text_button.dart'; import '../../../../widgets/desktop/desktop_dialog.dart'; import '../../../../widgets/desktop/desktop_dialog_close_button.dart'; import '../../../../widgets/desktop/primary_button.dart'; @@ -94,6 +92,8 @@ class _BoostTransactionViewState extends ConsumerState { String? _sparkMemo; + BigInt customFee = BigInt.one; + @override void initState() { isDesktop = Util.isDesktop; @@ -1282,32 +1282,56 @@ class _BoostTransactionViewState extends ConsumerState { fee, ); - return Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - crossAxisAlignment: - CrossAxisAlignment.start, + return Column( children: [ - Column( + Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - "Transaction fee", - style: isDesktop - ? STextStyles - .desktopTextExtraExtraSmall( - context, - ) - : STextStyles.itemSubtitle( - context, - ), + Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text( + "Transaction fee", + style: isDesktop + ? STextStyles + .desktopTextExtraExtraSmall( + context, + ) + : STextStyles + .itemSubtitle( + context, + ), + ), + if (isDesktop) + const SizedBox( + height: 2, + ), + if (isDesktop) + SelectableText( + feeString, + style: isDesktop + ? STextStyles + .desktopTextExtraExtraSmall( + context, + ).copyWith( + color: Theme.of( + context) + .extension< + StackColors>()! + .textDark, + ) + : STextStyles + .itemSubtitle12( + context, + ), + ), + ], ), - if (isDesktop) - const SizedBox( - height: 2, - ), - if (isDesktop) + if (!isDesktop) SelectableText( feeString, style: isDesktop @@ -1325,28 +1349,25 @@ class _BoostTransactionViewState extends ConsumerState { context, ), ), - // TODO [prio=high]: Boost tx fee UI. + // if (isDesktop) + // IconCopyButton(data: feeString), ], ), - if (!isDesktop) - SelectableText( - feeString, - style: isDesktop - ? STextStyles - .desktopTextExtraExtraSmall( - context, - ).copyWith( - color: Theme.of(context) - .extension< - StackColors>()! - .textDark, - ) - : STextStyles.itemSubtitle12( - context, - ), + Padding( + padding: const EdgeInsets.only( + bottom: 12, + top: 16, ), - if (isDesktop) - IconCopyButton(data: feeString), + child: BoostFeeSlider( + coin: coin, + onFeeChanged: (fee) { + customFee = fee; + }, + min: fee.raw, + max: fee.raw * BigInt.from(4), + // TODO [prio=med]: The max fee should be set to an absurd fee. + ), + ) ], ); }, @@ -1493,142 +1514,142 @@ class _BoostTransactionViewState extends ConsumerState { // ], // ), // ), - isDesktop - ? const _Divider() - : const SizedBox( - height: 12, - ), - RoundedWhiteContainer( - padding: isDesktop - ? const EdgeInsets.all(16) - : const EdgeInsets.all(12), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - Text( - "Transaction ID", - style: isDesktop - ? STextStyles - .desktopTextExtraExtraSmall( - context, - ) - : STextStyles.itemSubtitle( - context, - ), - ), - const SizedBox( - height: 8, - ), - // Flexible( - // child: FittedBox( - // fit: BoxFit.scaleDown, - // child: - SelectableText( - _transaction.txid, - style: isDesktop - ? STextStyles - .desktopTextExtraExtraSmall( - context, - ).copyWith( - color: Theme.of(context) - .extension()! - .textDark, - ) - : STextStyles.itemSubtitle12( - context, - ), - ), - if (coin is! Epiccash) - const SizedBox( - height: 8, - ), - if (coin is! Epiccash) - CustomTextButton( - text: "Open in block explorer", - onTap: () async { - final uri = - getBlockExplorerTransactionUrlFor( - coin: coin, - txid: _transaction.txid, - ); - - if (ref - .read( - prefsChangeNotifierProvider, - ) - .hideBlockExplorerWarning == - false) { - final shouldContinue = - await showExplorerWarning( - "${uri.scheme}://${uri.host}", - ); - - if (!shouldContinue) { - return; - } - } - - // ref - // .read( - // shouldShowLockscreenOnResumeStateProvider - // .state) - // .state = false; - try { - await launchUrl( - uri, - mode: LaunchMode - .externalApplication, - ); - } catch (_) { - if (mounted) { - unawaited( - showDialog( - context: context, - builder: (_) => - StackOkDialog( - title: - "Could not open in block explorer", - message: - "Failed to open \"${uri.toString()}\"", - ), - ), - ); - } - } finally { - // Future.delayed( - // const Duration(seconds: 1), - // () => ref - // .read( - // shouldShowLockscreenOnResumeStateProvider - // .state) - // .state = true, - // ); - } - }, - ), - // ), - // ), - ], - ), - ), - if (isDesktop) - const SizedBox( - width: 12, - ), - if (isDesktop) - IconCopyButton( - data: _transaction.txid, - ), - ], - ), - ), + // isDesktop + // ? const _Divider() + // : const SizedBox( + // height: 12, + // ), + // RoundedWhiteContainer( + // padding: isDesktop + // ? const EdgeInsets.all(16) + // : const EdgeInsets.all(12), + // child: Row( + // crossAxisAlignment: CrossAxisAlignment.start, + // mainAxisAlignment: + // MainAxisAlignment.spaceBetween, + // children: [ + // Expanded( + // child: Column( + // crossAxisAlignment: + // CrossAxisAlignment.start, + // children: [ + // Text( + // "Transaction ID", + // style: isDesktop + // ? STextStyles + // .desktopTextExtraExtraSmall( + // context, + // ) + // : STextStyles.itemSubtitle( + // context, + // ), + // ), + // const SizedBox( + // height: 8, + // ), + // // Flexible( + // // child: FittedBox( + // // fit: BoxFit.scaleDown, + // // child: + // SelectableText( + // _transaction.txid, + // style: isDesktop + // ? STextStyles + // .desktopTextExtraExtraSmall( + // context, + // ).copyWith( + // color: Theme.of(context) + // .extension()! + // .textDark, + // ) + // : STextStyles.itemSubtitle12( + // context, + // ), + // ), + // if (coin is! Epiccash) + // const SizedBox( + // height: 8, + // ), + // if (coin is! Epiccash) + // CustomTextButton( + // text: "Open in block explorer", + // onTap: () async { + // final uri = + // getBlockExplorerTransactionUrlFor( + // coin: coin, + // txid: _transaction.txid, + // ); + // + // if (ref + // .read( + // prefsChangeNotifierProvider, + // ) + // .hideBlockExplorerWarning == + // false) { + // final shouldContinue = + // await showExplorerWarning( + // "${uri.scheme}://${uri.host}", + // ); + // + // if (!shouldContinue) { + // return; + // } + // } + // + // // ref + // // .read( + // // shouldShowLockscreenOnResumeStateProvider + // // .state) + // // .state = false; + // try { + // await launchUrl( + // uri, + // mode: LaunchMode + // .externalApplication, + // ); + // } catch (_) { + // if (mounted) { + // unawaited( + // showDialog( + // context: context, + // builder: (_) => + // StackOkDialog( + // title: + // "Could not open in block explorer", + // message: + // "Failed to open \"${uri.toString()}\"", + // ), + // ), + // ); + // } + // } finally { + // // Future.delayed( + // // const Duration(seconds: 1), + // // () => ref + // // .read( + // // shouldShowLockscreenOnResumeStateProvider + // // .state) + // // .state = true, + // // ); + // } + // }, + // ), + // // ), + // // ), + // ], + // ), + // ), + // if (isDesktop) + // const SizedBox( + // width: 12, + // ), + // if (isDesktop) + // IconCopyButton( + // data: _transaction.txid, + // ), + // ], + // ), + // ), // if ((coin is FiroTestNet || coin is Firo) && // _transaction.subType == "mint") // const SizedBox( diff --git a/lib/widgets/boost_fee_slider.dart b/lib/widgets/boost_fee_slider.dart new file mode 100644 index 000000000..2d5f7dd65 --- /dev/null +++ b/lib/widgets/boost_fee_slider.dart @@ -0,0 +1,122 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import '../utilities/amount/amount.dart'; +import '../utilities/amount/amount_formatter.dart'; +import '../wallets/crypto_currency/crypto_currency.dart'; // Update with your actual path + +class BoostFeeSlider extends ConsumerStatefulWidget { + final CryptoCurrency coin; + final Function(BigInt) onFeeChanged; + final BigInt min; + final BigInt max; + + BoostFeeSlider({ + required this.coin, + required this.onFeeChanged, + required this.min, + required this.max, + }); + + @override + _BoostFeeSliderState createState() => _BoostFeeSliderState(); +} + +class _BoostFeeSliderState extends ConsumerState { + double _currentSliderValue = 0; + late TextEditingController _textEditingController; + + @override + void initState() { + super.initState(); + _currentSliderValue = widget.min.toDouble(); + _textEditingController = TextEditingController( + text: ref.read(pAmountFormatter(widget.coin)).format( + Amount( + rawValue: BigInt.from(_currentSliderValue), + fractionDigits: widget.coin.fractionDigits), + withUnitName: false, + ), + ); + _textEditingController.addListener(() { + BigInt? value = + BigInt.tryParse(_textEditingController.text.replaceAll(',', '')); + if (value != null && value >= widget.min && value <= widget.max) { + setState(() { + _currentSliderValue = value.toDouble(); + widget.onFeeChanged(value); + }); + } + }); + } + + @override + void dispose() { + _textEditingController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + children: [ + Row( + children: [ + Expanded( + child: Slider( + value: _currentSliderValue, + min: widget.min.toDouble(), + max: widget.max.toDouble(), + divisions: (widget.max - widget.min).toInt(), + label: ref.read(pAmountFormatter(widget.coin)).format(Amount( + rawValue: BigInt.from(_currentSliderValue), + fractionDigits: widget.coin.fractionDigits)), + onChanged: (value) { + setState(() { + _currentSliderValue = value; + _textEditingController.text = ref + .read(pAmountFormatter(widget.coin)) + .format(Amount( + rawValue: BigInt.from(_currentSliderValue), + fractionDigits: widget.coin.fractionDigits)); + widget.onFeeChanged(BigInt.from(_currentSliderValue)); + }); + }, + ), + ), + SizedBox(width: 16), + Container( + width: 122, + child: TextField( + controller: _textEditingController, + keyboardType: TextInputType.number, + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly, + ], + decoration: InputDecoration( + border: OutlineInputBorder(), + ), + onChanged: (value) { + BigInt? newValue = + BigInt.tryParse(value.replaceAll(',', '')); + if (newValue != null && + newValue >= widget.min && + newValue <= widget.max) { + setState(() { + _currentSliderValue = newValue.toDouble(); + widget.onFeeChanged(newValue); + }); + } + }, + ), + ), + ], + ), + ], + ), + ); + } +}