mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2025-01-09 20:29:57 +00:00
WIP boost fee slider
This commit is contained in:
parent
6fa1bc75af
commit
f2ca700a9f
2 changed files with 322 additions and 179 deletions
|
@ -15,7 +15,6 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:isar/isar.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/transaction.dart';
|
||||||
import '../../../../models/isar/models/blockchain_data/v2/transaction_v2.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 '../../../../themes/stack_colors.dart';
|
||||||
import '../../../../utilities/amount/amount.dart';
|
import '../../../../utilities/amount/amount.dart';
|
||||||
import '../../../../utilities/amount/amount_formatter.dart';
|
import '../../../../utilities/amount/amount_formatter.dart';
|
||||||
import '../../../../utilities/block_explorers.dart';
|
|
||||||
import '../../../../utilities/constants.dart';
|
import '../../../../utilities/constants.dart';
|
||||||
import '../../../../utilities/logger.dart';
|
import '../../../../utilities/logger.dart';
|
||||||
import '../../../../utilities/text_styles.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/impl/epiccash_wallet.dart';
|
||||||
import '../../../../wallets/wallet/wallet_mixin_interfaces/spark_interface.dart';
|
import '../../../../wallets/wallet/wallet_mixin_interfaces/spark_interface.dart';
|
||||||
import '../../../../widgets/background.dart';
|
import '../../../../widgets/background.dart';
|
||||||
|
import '../../../../widgets/boost_fee_slider.dart';
|
||||||
import '../../../../widgets/conditional_parent.dart';
|
import '../../../../widgets/conditional_parent.dart';
|
||||||
import '../../../../widgets/custom_buttons/app_bar_icon_button.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.dart';
|
||||||
import '../../../../widgets/desktop/desktop_dialog_close_button.dart';
|
import '../../../../widgets/desktop/desktop_dialog_close_button.dart';
|
||||||
import '../../../../widgets/desktop/primary_button.dart';
|
import '../../../../widgets/desktop/primary_button.dart';
|
||||||
|
@ -94,6 +92,8 @@ class _BoostTransactionViewState extends ConsumerState<BoostTransactionView> {
|
||||||
|
|
||||||
String? _sparkMemo;
|
String? _sparkMemo;
|
||||||
|
|
||||||
|
BigInt customFee = BigInt.one;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
isDesktop = Util.isDesktop;
|
isDesktop = Util.isDesktop;
|
||||||
|
@ -1282,32 +1282,56 @@ class _BoostTransactionViewState extends ConsumerState<BoostTransactionView> {
|
||||||
fee,
|
fee,
|
||||||
);
|
);
|
||||||
|
|
||||||
return Row(
|
return Column(
|
||||||
mainAxisAlignment:
|
|
||||||
MainAxisAlignment.spaceBetween,
|
|
||||||
crossAxisAlignment:
|
|
||||||
CrossAxisAlignment.start,
|
|
||||||
children: [
|
children: [
|
||||||
Column(
|
Row(
|
||||||
|
mainAxisAlignment:
|
||||||
|
MainAxisAlignment.spaceBetween,
|
||||||
crossAxisAlignment:
|
crossAxisAlignment:
|
||||||
CrossAxisAlignment.start,
|
CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Column(
|
||||||
"Transaction fee",
|
crossAxisAlignment:
|
||||||
style: isDesktop
|
CrossAxisAlignment.start,
|
||||||
? STextStyles
|
children: [
|
||||||
.desktopTextExtraExtraSmall(
|
Text(
|
||||||
context,
|
"Transaction fee",
|
||||||
)
|
style: isDesktop
|
||||||
: STextStyles.itemSubtitle(
|
? STextStyles
|
||||||
context,
|
.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)
|
if (!isDesktop)
|
||||||
const SizedBox(
|
|
||||||
height: 2,
|
|
||||||
),
|
|
||||||
if (isDesktop)
|
|
||||||
SelectableText(
|
SelectableText(
|
||||||
feeString,
|
feeString,
|
||||||
style: isDesktop
|
style: isDesktop
|
||||||
|
@ -1325,28 +1349,25 @@ class _BoostTransactionViewState extends ConsumerState<BoostTransactionView> {
|
||||||
context,
|
context,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
// TODO [prio=high]: Boost tx fee UI.
|
// if (isDesktop)
|
||||||
|
// IconCopyButton(data: feeString),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
if (!isDesktop)
|
Padding(
|
||||||
SelectableText(
|
padding: const EdgeInsets.only(
|
||||||
feeString,
|
bottom: 12,
|
||||||
style: isDesktop
|
top: 16,
|
||||||
? STextStyles
|
|
||||||
.desktopTextExtraExtraSmall(
|
|
||||||
context,
|
|
||||||
).copyWith(
|
|
||||||
color: Theme.of(context)
|
|
||||||
.extension<
|
|
||||||
StackColors>()!
|
|
||||||
.textDark,
|
|
||||||
)
|
|
||||||
: STextStyles.itemSubtitle12(
|
|
||||||
context,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
if (isDesktop)
|
child: BoostFeeSlider(
|
||||||
IconCopyButton(data: feeString),
|
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
|
// isDesktop
|
||||||
? const _Divider()
|
// ? const _Divider()
|
||||||
: const SizedBox(
|
// : const SizedBox(
|
||||||
height: 12,
|
// height: 12,
|
||||||
),
|
// ),
|
||||||
RoundedWhiteContainer(
|
// RoundedWhiteContainer(
|
||||||
padding: isDesktop
|
// padding: isDesktop
|
||||||
? const EdgeInsets.all(16)
|
// ? const EdgeInsets.all(16)
|
||||||
: const EdgeInsets.all(12),
|
// : const EdgeInsets.all(12),
|
||||||
child: Row(
|
// child: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
mainAxisAlignment:
|
// mainAxisAlignment:
|
||||||
MainAxisAlignment.spaceBetween,
|
// MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
// children: [
|
||||||
Expanded(
|
// Expanded(
|
||||||
child: Column(
|
// child: Column(
|
||||||
crossAxisAlignment:
|
// crossAxisAlignment:
|
||||||
CrossAxisAlignment.start,
|
// CrossAxisAlignment.start,
|
||||||
children: [
|
// children: [
|
||||||
Text(
|
// Text(
|
||||||
"Transaction ID",
|
// "Transaction ID",
|
||||||
style: isDesktop
|
// style: isDesktop
|
||||||
? STextStyles
|
// ? STextStyles
|
||||||
.desktopTextExtraExtraSmall(
|
// .desktopTextExtraExtraSmall(
|
||||||
context,
|
// context,
|
||||||
)
|
// )
|
||||||
: STextStyles.itemSubtitle(
|
// : STextStyles.itemSubtitle(
|
||||||
context,
|
// context,
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
const SizedBox(
|
// const SizedBox(
|
||||||
height: 8,
|
// height: 8,
|
||||||
),
|
// ),
|
||||||
// Flexible(
|
// // Flexible(
|
||||||
// child: FittedBox(
|
// // child: FittedBox(
|
||||||
// fit: BoxFit.scaleDown,
|
// // fit: BoxFit.scaleDown,
|
||||||
// child:
|
// // child:
|
||||||
SelectableText(
|
// SelectableText(
|
||||||
_transaction.txid,
|
// _transaction.txid,
|
||||||
style: isDesktop
|
// style: isDesktop
|
||||||
? STextStyles
|
// ? STextStyles
|
||||||
.desktopTextExtraExtraSmall(
|
// .desktopTextExtraExtraSmall(
|
||||||
context,
|
// context,
|
||||||
).copyWith(
|
// ).copyWith(
|
||||||
color: Theme.of(context)
|
// color: Theme.of(context)
|
||||||
.extension<StackColors>()!
|
// .extension<StackColors>()!
|
||||||
.textDark,
|
// .textDark,
|
||||||
)
|
// )
|
||||||
: STextStyles.itemSubtitle12(
|
// : STextStyles.itemSubtitle12(
|
||||||
context,
|
// context,
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
if (coin is! Epiccash)
|
// if (coin is! Epiccash)
|
||||||
const SizedBox(
|
// const SizedBox(
|
||||||
height: 8,
|
// height: 8,
|
||||||
),
|
// ),
|
||||||
if (coin is! Epiccash)
|
// if (coin is! Epiccash)
|
||||||
CustomTextButton(
|
// CustomTextButton(
|
||||||
text: "Open in block explorer",
|
// text: "Open in block explorer",
|
||||||
onTap: () async {
|
// onTap: () async {
|
||||||
final uri =
|
// final uri =
|
||||||
getBlockExplorerTransactionUrlFor(
|
// getBlockExplorerTransactionUrlFor(
|
||||||
coin: coin,
|
// coin: coin,
|
||||||
txid: _transaction.txid,
|
// txid: _transaction.txid,
|
||||||
);
|
// );
|
||||||
|
//
|
||||||
if (ref
|
// if (ref
|
||||||
.read(
|
// .read(
|
||||||
prefsChangeNotifierProvider,
|
// prefsChangeNotifierProvider,
|
||||||
)
|
// )
|
||||||
.hideBlockExplorerWarning ==
|
// .hideBlockExplorerWarning ==
|
||||||
false) {
|
// false) {
|
||||||
final shouldContinue =
|
// final shouldContinue =
|
||||||
await showExplorerWarning(
|
// await showExplorerWarning(
|
||||||
"${uri.scheme}://${uri.host}",
|
// "${uri.scheme}://${uri.host}",
|
||||||
);
|
// );
|
||||||
|
//
|
||||||
if (!shouldContinue) {
|
// if (!shouldContinue) {
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// ref
|
// // ref
|
||||||
// .read(
|
// // .read(
|
||||||
// shouldShowLockscreenOnResumeStateProvider
|
// // shouldShowLockscreenOnResumeStateProvider
|
||||||
// .state)
|
// // .state)
|
||||||
// .state = false;
|
// // .state = false;
|
||||||
try {
|
// try {
|
||||||
await launchUrl(
|
// await launchUrl(
|
||||||
uri,
|
// uri,
|
||||||
mode: LaunchMode
|
// mode: LaunchMode
|
||||||
.externalApplication,
|
// .externalApplication,
|
||||||
);
|
// );
|
||||||
} catch (_) {
|
// } catch (_) {
|
||||||
if (mounted) {
|
// if (mounted) {
|
||||||
unawaited(
|
// unawaited(
|
||||||
showDialog<void>(
|
// showDialog<void>(
|
||||||
context: context,
|
// context: context,
|
||||||
builder: (_) =>
|
// builder: (_) =>
|
||||||
StackOkDialog(
|
// StackOkDialog(
|
||||||
title:
|
// title:
|
||||||
"Could not open in block explorer",
|
// "Could not open in block explorer",
|
||||||
message:
|
// message:
|
||||||
"Failed to open \"${uri.toString()}\"",
|
// "Failed to open \"${uri.toString()}\"",
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
} finally {
|
// } finally {
|
||||||
// Future<void>.delayed(
|
// // Future<void>.delayed(
|
||||||
// const Duration(seconds: 1),
|
// // const Duration(seconds: 1),
|
||||||
// () => ref
|
// // () => ref
|
||||||
// .read(
|
// // .read(
|
||||||
// shouldShowLockscreenOnResumeStateProvider
|
// // shouldShowLockscreenOnResumeStateProvider
|
||||||
// .state)
|
// // .state)
|
||||||
// .state = true,
|
// // .state = true,
|
||||||
// );
|
// // );
|
||||||
}
|
// }
|
||||||
},
|
// },
|
||||||
),
|
// ),
|
||||||
// ),
|
// // ),
|
||||||
// ),
|
// // ),
|
||||||
],
|
// ],
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
if (isDesktop)
|
// if (isDesktop)
|
||||||
const SizedBox(
|
// const SizedBox(
|
||||||
width: 12,
|
// width: 12,
|
||||||
),
|
// ),
|
||||||
if (isDesktop)
|
// if (isDesktop)
|
||||||
IconCopyButton(
|
// IconCopyButton(
|
||||||
data: _transaction.txid,
|
// data: _transaction.txid,
|
||||||
),
|
// ),
|
||||||
],
|
// ],
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
// if ((coin is FiroTestNet || coin is Firo) &&
|
// if ((coin is FiroTestNet || coin is Firo) &&
|
||||||
// _transaction.subType == "mint")
|
// _transaction.subType == "mint")
|
||||||
// const SizedBox(
|
// const SizedBox(
|
||||||
|
|
122
lib/widgets/boost_fee_slider.dart
Normal file
122
lib/widgets/boost_fee_slider.dart
Normal 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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue