WIP boost fee slider

This commit is contained in:
sneurlax 2024-06-12 14:23:04 -05:00 committed by julian
parent 6fa1bc75af
commit f2ca700a9f
2 changed files with 322 additions and 179 deletions
lib
pages/wallet_view/transaction_views/tx_v2
widgets

View file

@ -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<BoostTransactionView> {
String? _sparkMemo;
BigInt customFee = BigInt.one;
@override
void initState() {
isDesktop = Util.isDesktop;
@ -1282,32 +1282,56 @@ class _BoostTransactionViewState extends ConsumerState<BoostTransactionView> {
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<BoostTransactionView> {
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<BoostTransactionView> {
// ],
// ),
// ),
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<StackColors>()!
.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<void>(
context: context,
builder: (_) =>
StackOkDialog(
title:
"Could not open in block explorer",
message:
"Failed to open \"${uri.toString()}\"",
),
),
);
}
} finally {
// Future<void>.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<StackColors>()!
// .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<void>(
// context: context,
// builder: (_) =>
// StackOkDialog(
// title:
// "Could not open in block explorer",
// message:
// "Failed to open \"${uri.toString()}\"",
// ),
// ),
// );
// }
// } finally {
// // Future<void>.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(

View file

@ -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<BoostFeeSlider> {
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: <Widget>[
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);
});
}
},
),
),
],
),
],
),
);
}
}