dynamic max fee rate value (#1395)

This commit is contained in:
Serhii 2024-04-25 19:28:18 +03:00 committed by GitHub
parent 190c8e06b9
commit 9ff6da3d5d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 54 additions and 9 deletions

View file

@ -291,4 +291,10 @@ class CWBitcoin extends Bitcoin {
outputsCount, outputsCount,
); );
} }
@override
int getMaxCustomFeeRate(Object wallet) {
final bitcoinWallet = wallet as ElectrumWallet;
return (bitcoinWallet.feeRate(BitcoinTransactionPriority.fast) * 1.1).round();
}
} }

View file

@ -675,6 +675,7 @@ class SendCardState extends State<SendCard> with AutomaticKeepAliveClientMixin<S
final selectedItem = items.indexOf(sendViewModel.transactionPriority); final selectedItem = items.indexOf(sendViewModel.transactionPriority);
final customItemIndex = sendViewModel.getCustomPriorityIndex(items); final customItemIndex = sendViewModel.getCustomPriorityIndex(items);
final isBitcoinWallet = sendViewModel.walletType == WalletType.bitcoin; final isBitcoinWallet = sendViewModel.walletType == WalletType.bitcoin;
final maxCustomFeeRate = sendViewModel.maxCustomFeeRate?.toDouble();
double? customFeeRate = isBitcoinWallet ? sendViewModel.customBitcoinFeeRate.toDouble() : null; double? customFeeRate = isBitcoinWallet ? sendViewModel.customBitcoinFeeRate.toDouble() : null;
await showPopUp<void>( await showPopUp<void>(
@ -689,6 +690,7 @@ class SendCardState extends State<SendCard> with AutomaticKeepAliveClientMixin<S
sendViewModel.displayFeeRate(priority, customFeeRate?.round()), sendViewModel.displayFeeRate(priority, customFeeRate?.round()),
selectedAtIndex: selectedIdx, selectedAtIndex: selectedIdx,
customItemIndex: customItemIndex, customItemIndex: customItemIndex,
maxValue: maxCustomFeeRate,
title: S.of(context).please_select, title: S.of(context).please_select,
headerEnabled: !isBitcoinWallet, headerEnabled: !isBitcoinWallet,
closeOnItemSelected: !isBitcoinWallet, closeOnItemSelected: !isBitcoinWallet,

View file

@ -37,6 +37,7 @@ class OtherSettingsPage extends BasePage {
customItemIndex: _otherSettingsViewModel.customPriorityItemIndex, customItemIndex: _otherSettingsViewModel.customPriorityItemIndex,
onItemSelected: _otherSettingsViewModel.onDisplayBitcoinPrioritySelected, onItemSelected: _otherSettingsViewModel.onDisplayBitcoinPrioritySelected,
customValue: _otherSettingsViewModel.customBitcoinFeeRate, customValue: _otherSettingsViewModel.customBitcoinFeeRate,
maxValue: _otherSettingsViewModel.maxCustomFeeRate?.toDouble(),
) : ) :
SettingsPickerCell( SettingsPickerCell(
title: S.current.settings_fee_priority, title: S.current.settings_fee_priority,

View file

@ -15,6 +15,7 @@ class SettingsPriorityPickerCell<ItemType> extends StandardListRow {
this.isGridView = false, this.isGridView = false,
this.matchingCriteria, this.matchingCriteria,
this.customValue, this.customValue,
this.maxValue,
this.customItemIndex, this.customItemIndex,
this.onItemSelected}) this.onItemSelected})
: super( : super(
@ -34,6 +35,7 @@ class SettingsPriorityPickerCell<ItemType> extends StandardListRow {
displayItem: (ItemType item) => displayItem!(item, sliderValue.round()), displayItem: (ItemType item) => displayItem!(item, sliderValue.round()),
selectedAtIndex: selectedAtIndex, selectedAtIndex: selectedAtIndex,
customItemIndex: customItemIndex, customItemIndex: customItemIndex,
maxValue: maxValue,
headerEnabled: false, headerEnabled: false,
closeOnItemSelected: false, closeOnItemSelected: false,
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
@ -61,6 +63,7 @@ class SettingsPriorityPickerCell<ItemType> extends StandardListRow {
final bool isGridView; final bool isGridView;
final bool Function(ItemType, String)? matchingCriteria; final bool Function(ItemType, String)? matchingCriteria;
double? customValue; double? customValue;
double? maxValue;
int? customItemIndex; int? customItemIndex;
@override @override

View file

@ -10,6 +10,7 @@ class StandardPickerListItem<T> extends TransactionDetailsListItem {
required this.onItemSelected, required this.onItemSelected,
required this.selectedIdx, required this.selectedIdx,
required this.customItemIndex, required this.customItemIndex,
this.maxValue,
required this.customValue}) required this.customValue})
: super(title: title, value: value); : super(title: title, value: value);
@ -18,6 +19,7 @@ class StandardPickerListItem<T> extends TransactionDetailsListItem {
final Function(double) onSliderChanged; final Function(double) onSliderChanged;
final Function(T) onItemSelected; final Function(T) onItemSelected;
final int selectedIdx; final int selectedIdx;
final double? maxValue;
final int customItemIndex; final int customItemIndex;
double customValue; double customValue;
} }

View file

@ -74,6 +74,7 @@ class RBFDetailsPage extends BasePage {
selectedIdx: item.selectedIdx, selectedIdx: item.selectedIdx,
customItemIndex: item.customItemIndex, customItemIndex: item.customItemIndex,
customValue: item.customValue, customValue: item.customValue,
maxValue: item.maxValue,
); );
} }

View file

@ -27,14 +27,21 @@ class Picker<Item> extends StatefulWidget {
this.headerEnabled = true, this.headerEnabled = true,
this.closeOnItemSelected = true, this.closeOnItemSelected = true,
this.sliderValue, this.sliderValue,
this.minValue,
this.maxValue,
this.customItemIndex, this.customItemIndex,
this.isWrapped = true, this.isWrapped = true,
this.borderColor, this.borderColor,
this.onSliderChanged, this.onSliderChanged,
this.matchingCriteria, this.matchingCriteria,
}) : assert(hintText == null || }) : assert(hintText == null || matchingCriteria != null) {
matchingCriteria != // make sure that if the search field is enabled then there is a searching criteria provided
null); // make sure that if the search field is enabled then there is a searching criteria provided if (sliderValue != null && maxValue != null) {
if (sliderValue! > maxValue!) {
sliderValue = maxValue;
}
}
}
final int selectedAtIndex; final int selectedAtIndex;
final List<Item> items; final List<Item> items;
@ -49,12 +56,14 @@ class Picker<Item> extends StatefulWidget {
final String? hintText; final String? hintText;
final bool headerEnabled; final bool headerEnabled;
final bool closeOnItemSelected; final bool closeOnItemSelected;
final double? sliderValue; double? sliderValue;
final double? minValue;
final int? customItemIndex; final int? customItemIndex;
final bool isWrapped; final bool isWrapped;
final Color? borderColor; final Color? borderColor;
final Function(double)? onSliderChanged; final Function(double)? onSliderChanged;
final bool Function(Item, String)? matchingCriteria; final bool Function(Item, String)? matchingCriteria;
final double? maxValue;
@override @override
_PickerState<Item> createState() => _PickerState<Item>(items, images, onItemSelected); _PickerState<Item> createState() => _PickerState<Item>(items, images, onItemSelected);
@ -211,8 +220,9 @@ class _PickerState<Item> extends State<Picker<Item>> {
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
fontFamily: 'Lato', fontFamily: 'Lato',
decoration: TextDecoration.none, decoration: TextDecoration.none,
color: color: Theme.of(context)
Theme.of(context).extension<CakeTextTheme>()!.titleColor, .extension<CakeTextTheme>()!
.titleColor,
), ),
), ),
) )
@ -491,8 +501,8 @@ class _PickerState<Item> extends State<Picker<Item>> {
child: Slider( child: Slider(
value: widget.sliderValue ?? 1, value: widget.sliderValue ?? 1,
onChanged: isActivated ? widget.onSliderChanged : null, onChanged: isActivated ? widget.onSliderChanged : null,
min: 1, min: widget.minValue ?? 1,
max: 100, max: widget.maxValue ?? 100,
divisions: 100, divisions: 100,
), ),
), ),

View file

@ -15,6 +15,7 @@ class StandardPickerList<T> extends StatefulWidget {
required this.selectedIdx, required this.selectedIdx,
required this.customItemIndex, required this.customItemIndex,
required this.customValue, required this.customValue,
this.maxValue,
}) : super(key: key); }) : super(key: key);
final String title; final String title;
@ -26,6 +27,7 @@ class StandardPickerList<T> extends StatefulWidget {
final String value; final String value;
final int selectedIdx; final int selectedIdx;
final double customValue; final double customValue;
final double? maxValue;
@override @override
_StandardPickerListState<T> createState() => _StandardPickerListState<T>(); _StandardPickerListState<T> createState() => _StandardPickerListState<T>();
@ -59,6 +61,7 @@ class _StandardPickerListState<T> extends State<StandardPickerList<T>> {
displayItem: adaptedDisplayItem, displayItem: adaptedDisplayItem,
selectedAtIndex: selectedIdx, selectedAtIndex: selectedIdx,
customItemIndex: widget.customItemIndex, customItemIndex: widget.customItemIndex,
maxValue: widget.maxValue,
headerEnabled: false, headerEnabled: false,
closeOnItemSelected: false, closeOnItemSelected: false,
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,

View file

@ -166,6 +166,13 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
return null; return null;
} }
int? get maxCustomFeeRate {
if (wallet.type == WalletType.bitcoin) {
return bitcoin!.getMaxCustomFeeRate(wallet);
}
return null;
}
@computed @computed
int get customBitcoinFeeRate => _settingsStore.customBitcoinFeeRate; int get customBitcoinFeeRate => _settingsStore.customBitcoinFeeRate;

View file

@ -140,6 +140,13 @@ abstract class OtherSettingsViewModelBase with Store {
return customItem != null ? priorities.indexOf(customItem) : null; return customItem != null ? priorities.indexOf(customItem) : null;
} }
int? get maxCustomFeeRate {
if (_wallet.type == WalletType.bitcoin) {
return bitcoin!.getMaxCustomFeeRate(_wallet);
}
return null;
}
@action @action
ProviderType onBuyProviderTypeSelected(ProviderType buyProviderType) => ProviderType onBuyProviderTypeSelected(ProviderType buyProviderType) =>
_settingsStore.defaultBuyProviders[walletType] = buyProviderType; _settingsStore.defaultBuyProviders[walletType] = buyProviderType;

View file

@ -348,12 +348,14 @@ abstract class TransactionDetailsViewModelBase with Store {
final customItem = priorities.firstWhereOrNull( final customItem = priorities.firstWhereOrNull(
(element) => element == sendViewModel.bitcoinTransactionPriorityCustom); (element) => element == sendViewModel.bitcoinTransactionPriorityCustom);
final customItemIndex = customItem != null ? priorities.indexOf(customItem) : null; final customItemIndex = customItem != null ? priorities.indexOf(customItem) : null;
final maxCustomFeeRate = sendViewModel.maxCustomFeeRate?.toDouble();
RBFListItems.add(StandardPickerListItem( RBFListItems.add(StandardPickerListItem(
title: S.current.estimated_new_fee, title: S.current.estimated_new_fee,
value: bitcoin!.formatterBitcoinAmountToString(amount: newFee) + ' ${walletTypeToCryptoCurrency(wallet.type)}', value: bitcoin!.formatterBitcoinAmountToString(amount: newFee) + ' ${walletTypeToCryptoCurrency(wallet.type)}',
items: priorityForWalletType(wallet.type), items: priorityForWalletType(wallet.type),
customValue: settingsStore.customBitcoinFeeRate.toDouble(), customValue: settingsStore.customBitcoinFeeRate.toDouble(),
maxValue: maxCustomFeeRate,
selectedIdx: selectedItem, selectedIdx: selectedItem,
customItemIndex: customItemIndex ?? 0, customItemIndex: customItemIndex ?? 0,
displayItem: (dynamic priority, double sliderValue) => displayItem: (dynamic priority, double sliderValue) =>

View file

@ -159,6 +159,7 @@ abstract class Bitcoin {
Future<bool> isChangeSufficientForFee(Object wallet, String txId, String newFee); Future<bool> isChangeSufficientForFee(Object wallet, String txId, String newFee);
int getFeeAmountForPriority(Object wallet, TransactionPriority priority, int inputsCount, int outputsCount, {int? size}); int getFeeAmountForPriority(Object wallet, TransactionPriority priority, int inputsCount, int outputsCount, {int? size});
int getFeeAmountWithFeeRate(Object wallet, int feeRate, int inputsCount, int outputsCount, {int? size}); int getFeeAmountWithFeeRate(Object wallet, int feeRate, int inputsCount, int outputsCount, {int? size});
int getMaxCustomFeeRate(Object wallet);
} }
"""; """;