mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-24 06:48:38 +02:00
Add rbf (#1323)
* Add initial checkbox for RBF * minor progress * minor progress * Minor progress * Debugging RBF * Minor fix * Fix RBF transaction inputs (now it's working) * New versions Fix issues with Monero.com * Add sending for Solana tokens exchanges * Add default keyword for P2WPKH [skip ci] * chore: Switch solana commitment to confirmed to reduced blockhash expiration (#1313) * Modify test workflow to send arm64-v8a build only * Fix workflow build path * Remove unnecessary reverse of txId * Update Replace by fee with the new bitcoin base implementation * btc custom fee priority * add feeRate to btc credential * UI fixes * add check if the change covers the fee * Update settings_store.dart * add check confirmation for rbf * add a check to see if the change is sufficient for the new fee * addressing PR comments * update localization files * addressing PR comments * minor fixes * Update transaction_details_view_model.dart * Minor Fix for building Monero.com [skip ci] * update localization files * add bump fee page * update localisation files * Update cw_bitcoin.dart * fix merge conflict * fix UI issues * Fix Conflicts, Fix RBF flow, some enhancements * prevent default custom fee rate * hide outputs and inputs items * minor fix [skip ci] * addressing PR comments * remove rbf checkbox * default picker value * minor ui change [skip ci] * min fee rate [skip ci] * Minor fix and some minor enhancements --------- Co-authored-by: OmarHatem <omarh.ismail1@gmail.com> Co-authored-by: Adegoke David <64401859+Blazebrain@users.noreply.github.com>
This commit is contained in:
co-authored by
OmarHatem
Adegoke David
parent
071643b662
commit
291aa710c6
@@ -31,7 +31,6 @@ class CheckboxWidgetState extends State<CheckboxWidget> {
|
||||
},
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Container(
|
||||
height: 24.0,
|
||||
|
||||
+254
-173
@@ -24,6 +24,13 @@ class Picker<Item> extends StatefulWidget {
|
||||
this.isGridView = false,
|
||||
this.isSeparated = true,
|
||||
this.hintText,
|
||||
this.headerEnabled = true,
|
||||
this.closeOnItemSelected = true,
|
||||
this.sliderValue,
|
||||
this.customItemIndex,
|
||||
this.isWrapped = true,
|
||||
this.borderColor,
|
||||
this.onSliderChanged,
|
||||
this.matchingCriteria,
|
||||
}) : assert(hintText == null ||
|
||||
matchingCriteria !=
|
||||
@@ -40,6 +47,13 @@ class Picker<Item> extends StatefulWidget {
|
||||
final bool isGridView;
|
||||
final bool isSeparated;
|
||||
final String? hintText;
|
||||
final bool headerEnabled;
|
||||
final bool closeOnItemSelected;
|
||||
final double? sliderValue;
|
||||
final int? customItemIndex;
|
||||
final bool isWrapped;
|
||||
final Color? borderColor;
|
||||
final Function(double)? onSliderChanged;
|
||||
final bool Function(Item, String)? matchingCriteria;
|
||||
|
||||
@override
|
||||
@@ -124,8 +138,7 @@ class _PickerState<Item> extends State<Picker<Item>> {
|
||||
containerHeight = height * 0.75;
|
||||
}
|
||||
|
||||
return PickerWrapperWidget(
|
||||
hasTitle: widget.title?.isNotEmpty ?? false,
|
||||
final content = Column (
|
||||
children: [
|
||||
if (widget.title?.isNotEmpty ?? false)
|
||||
Container(
|
||||
@@ -144,61 +157,71 @@ class _PickerState<Item> extends State<Picker<Item>> {
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: padding),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.all(Radius.circular(30)),
|
||||
child: Container(
|
||||
color: Theme.of(context).dialogTheme.backgroundColor,
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
maxHeight: containerHeight,
|
||||
maxWidth: ResponsiveLayoutUtilBase.kPopupWidth,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (widget.hintText != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: SearchBarWidget(searchController: searchController),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
border: Border.all(
|
||||
color: widget.borderColor ?? Colors.transparent,
|
||||
),
|
||||
),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.all(Radius.circular(30)),
|
||||
child: Container(
|
||||
color: Theme.of(context).dialogTheme.backgroundColor,
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
maxHeight: containerHeight,
|
||||
maxWidth: ResponsiveLayoutUtilBase.kPopupWidth,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (widget.hintText != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: SearchBarWidget(
|
||||
searchController: searchController, hintText: widget.hintText),
|
||||
),
|
||||
Divider(
|
||||
color: Theme.of(context).extension<PickerTheme>()!.dividerColor,
|
||||
height: 1,
|
||||
),
|
||||
Divider(
|
||||
color: Theme.of(context).extension<PickerTheme>()!.dividerColor,
|
||||
height: 1,
|
||||
),
|
||||
if (widget.selectedAtIndex != -1) buildSelectedItem(widget.selectedAtIndex),
|
||||
Flexible(
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: <Widget>[
|
||||
filteredItems.length > 3
|
||||
? Scrollbar(
|
||||
controller: controller,
|
||||
child: itemsList(),
|
||||
)
|
||||
: itemsList(),
|
||||
(widget.description?.isNotEmpty ?? false)
|
||||
? Positioned(
|
||||
bottom: padding,
|
||||
left: padding,
|
||||
right: padding,
|
||||
child: Text(
|
||||
widget.description!,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
fontFamily: 'Lato',
|
||||
decoration: TextDecoration.none,
|
||||
color:
|
||||
Theme.of(context).extension<CakeTextTheme>()!.titleColor,
|
||||
if (widget.selectedAtIndex != -1 && widget.headerEnabled)
|
||||
buildSelectedItem(widget.selectedAtIndex),
|
||||
Flexible(
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: <Widget>[
|
||||
filteredItems.length > 3
|
||||
? Scrollbar(
|
||||
controller: controller,
|
||||
child: itemsList(),
|
||||
)
|
||||
: itemsList(),
|
||||
(widget.description?.isNotEmpty ?? false)
|
||||
? Positioned(
|
||||
bottom: padding,
|
||||
left: padding,
|
||||
right: padding,
|
||||
child: Text(
|
||||
widget.description!,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
fontFamily: 'Lato',
|
||||
decoration: TextDecoration.none,
|
||||
color:
|
||||
Theme.of(context).extension<CakeTextTheme>()!.titleColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
: Offstage(),
|
||||
],
|
||||
)
|
||||
: Offstage(),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -206,9 +229,23 @@ class _PickerState<Item> extends State<Picker<Item>> {
|
||||
)
|
||||
],
|
||||
);
|
||||
|
||||
if (widget.isWrapped) {
|
||||
return PickerWrapperWidget(
|
||||
hasTitle: widget.title?.isNotEmpty ?? false,
|
||||
children: [content],
|
||||
);
|
||||
} else {
|
||||
return content;
|
||||
}
|
||||
}
|
||||
|
||||
Widget itemsList() {
|
||||
final itemCount = !widget.headerEnabled
|
||||
? items.length
|
||||
: filteredItems.isEmpty
|
||||
? 0
|
||||
: filteredItems.length;
|
||||
return Container(
|
||||
color: Theme.of(context).extension<PickerTheme>()!.dividerColor,
|
||||
child: widget.isGridView
|
||||
@@ -216,13 +253,16 @@ class _PickerState<Item> extends State<Picker<Item>> {
|
||||
padding: EdgeInsets.zero,
|
||||
controller: controller,
|
||||
shrinkWrap: true,
|
||||
itemCount: filteredItems.isEmpty ? 0 : filteredItems.length,
|
||||
itemCount: itemCount,
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 2,
|
||||
crossAxisSpacing: 2,
|
||||
childAspectRatio: 3,
|
||||
),
|
||||
itemBuilder: (context, index) => buildItem(index),
|
||||
itemBuilder: (context, index) =>
|
||||
!widget.headerEnabled && widget.selectedAtIndex == index
|
||||
? buildSelectedItem(index)
|
||||
: buildItem(index),
|
||||
)
|
||||
: ListView.separated(
|
||||
padding: EdgeInsets.zero,
|
||||
@@ -234,83 +274,97 @@ class _PickerState<Item> extends State<Picker<Item>> {
|
||||
height: 1,
|
||||
)
|
||||
: const SizedBox(),
|
||||
itemCount: filteredItems.isEmpty ? 0 : filteredItems.length,
|
||||
itemBuilder: (context, index) => buildItem(index),
|
||||
itemCount: itemCount,
|
||||
itemBuilder: (context, index) =>
|
||||
!widget.headerEnabled && widget.selectedAtIndex == index
|
||||
? buildSelectedItem(index)
|
||||
: buildItem(index),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildItem(int index) {
|
||||
final item = filteredItems[index];
|
||||
final item = widget.headerEnabled ? filteredItems[index] : items[index];
|
||||
|
||||
final tag = item is Currency ? item.tag : null;
|
||||
final icon = _getItemIcon(item);
|
||||
|
||||
final image = images.isNotEmpty ? filteredImages[index] : icon;
|
||||
|
||||
final isCustomItem = widget.customItemIndex != null && index == widget.customItemIndex;
|
||||
|
||||
final itemContent = Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: widget.mainAxisAlignment,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
image ?? Offstage(),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(left: image != null ? 12 : 0),
|
||||
child: Row(
|
||||
children: [
|
||||
Flexible(
|
||||
child: Text(
|
||||
widget.displayItem?.call(item) ?? item.toString(),
|
||||
softWrap: true,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
|
||||
decoration: TextDecoration.none,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (tag != null)
|
||||
Align(
|
||||
alignment: Alignment.topCenter,
|
||||
child: Container(
|
||||
width: 35.0,
|
||||
height: 18.0,
|
||||
child: Center(
|
||||
child: Text(
|
||||
tag,
|
||||
style: TextStyle(
|
||||
fontSize: 7.0,
|
||||
fontFamily: 'Lato',
|
||||
color: Theme.of(context).extension<CakeScrollbarTheme>()!.thumbColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(6.0),
|
||||
//border: Border.all(color: ),
|
||||
color: Theme.of(context).extension<CakeScrollbarTheme>()!.trackColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
if (widget.closeOnItemSelected) Navigator.of(context).pop();
|
||||
onItemSelected(item!);
|
||||
},
|
||||
child: Container(
|
||||
height: 55,
|
||||
height: isCustomItem ? 95 : 55,
|
||||
color: Theme.of(context).dialogTheme.backgroundColor,
|
||||
padding: EdgeInsets.symmetric(horizontal: 24),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: widget.mainAxisAlignment,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
image ?? Offstage(),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(left: image != null ? 12 : 0),
|
||||
child: Row(
|
||||
children: [
|
||||
Flexible(
|
||||
child: Text(
|
||||
widget.displayItem?.call(item) ?? item.toString(),
|
||||
softWrap: true,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
|
||||
decoration: TextDecoration.none,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (tag != null)
|
||||
Align(
|
||||
alignment: Alignment.topCenter,
|
||||
child: Container(
|
||||
width: 35.0,
|
||||
height: 18.0,
|
||||
child: Center(
|
||||
child: Text(
|
||||
tag,
|
||||
style: TextStyle(
|
||||
fontSize: 7.0,
|
||||
fontFamily: 'Lato',
|
||||
color:
|
||||
Theme.of(context).extension<CakeScrollbarTheme>()!.thumbColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(6.0),
|
||||
//border: Border.all(color: ),
|
||||
color: Theme.of(context).extension<CakeScrollbarTheme>()!.trackColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: isCustomItem
|
||||
? Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
itemContent,
|
||||
buildSlider(index: index, isActivated: widget.selectedAtIndex == index)
|
||||
],
|
||||
)
|
||||
: itemContent,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -323,69 +377,80 @@ class _PickerState<Item> extends State<Picker<Item>> {
|
||||
|
||||
final image = images.isNotEmpty ? images[index] : icon;
|
||||
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: Container(
|
||||
height: 55,
|
||||
color: Theme.of(context).dialogTheme.backgroundColor,
|
||||
padding: EdgeInsets.symmetric(horizontal: 24),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: widget.mainAxisAlignment,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
image ?? Offstage(),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(left: image != null ? 12 : 0),
|
||||
child: Row(
|
||||
children: [
|
||||
Flexible(
|
||||
child: Text(
|
||||
widget.displayItem?.call(item) ?? item.toString(),
|
||||
softWrap: true,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w700,
|
||||
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
|
||||
decoration: TextDecoration.none,
|
||||
final isCustomItem = widget.customItemIndex != null && index == widget.customItemIndex;
|
||||
|
||||
final itemContent = Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: widget.mainAxisAlignment,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
image ?? Offstage(),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(left: image != null ? 12 : 0),
|
||||
child: Row(
|
||||
children: [
|
||||
Flexible(
|
||||
child: Text(
|
||||
widget.displayItem?.call(item) ?? item.toString(),
|
||||
softWrap: true,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w700,
|
||||
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
|
||||
decoration: TextDecoration.none,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (tag != null)
|
||||
Align(
|
||||
alignment: Alignment.topCenter,
|
||||
child: Container(
|
||||
width: 35.0,
|
||||
height: 18.0,
|
||||
child: Center(
|
||||
child: Text(
|
||||
tag,
|
||||
style: TextStyle(
|
||||
fontSize: 7.0,
|
||||
fontFamily: 'Lato',
|
||||
color: Theme.of(context).extension<CakeScrollbarTheme>()!.thumbColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(6.0),
|
||||
//border: Border.all(color: ),
|
||||
color: Theme.of(context).extension<CakeScrollbarTheme>()!.trackColor,
|
||||
),
|
||||
),
|
||||
if (tag != null)
|
||||
Align(
|
||||
alignment: Alignment.topCenter,
|
||||
child: Container(
|
||||
width: 35.0,
|
||||
height: 18.0,
|
||||
child: Center(
|
||||
child: Text(
|
||||
tag,
|
||||
style: TextStyle(
|
||||
fontSize: 7.0,
|
||||
fontFamily: 'Lato',
|
||||
color:
|
||||
Theme.of(context).extension<CakeScrollbarTheme>()!.thumbColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(6.0),
|
||||
//border: Border.all(color: ),
|
||||
color: Theme.of(context).extension<CakeScrollbarTheme>()!.trackColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Icon(Icons.check_circle, color: Theme.of(context).primaryColor),
|
||||
],
|
||||
),
|
||||
),
|
||||
Icon(Icons.check_circle, color: Theme.of(context).primaryColor),
|
||||
],
|
||||
);
|
||||
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
if (widget.closeOnItemSelected) Navigator.of(context).pop();
|
||||
},
|
||||
child: Container(
|
||||
height: isCustomItem ? 95 : 55,
|
||||
color: Theme.of(context).dialogTheme.backgroundColor,
|
||||
padding: EdgeInsets.symmetric(horizontal: 24),
|
||||
child: isCustomItem
|
||||
? Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
itemContent,
|
||||
buildSlider(index: index, isActivated: widget.selectedAtIndex == index)
|
||||
],
|
||||
)
|
||||
: itemContent,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -418,4 +483,20 @@ class _PickerState<Item> extends State<Picker<Item>> {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
Widget buildSlider({required int index, required bool isActivated}) {
|
||||
return Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Slider(
|
||||
value: widget.sliderValue ?? 1,
|
||||
onChanged: isActivated ? widget.onSliderChanged : null,
|
||||
min: 1,
|
||||
max: 100,
|
||||
divisions: 100,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ class SearchBarWidget extends StatelessWidget {
|
||||
controller: searchController,
|
||||
style: TextStyle(color: Theme.of(context).extension<PickerTheme>()!.searchHintColor),
|
||||
decoration: InputDecoration(
|
||||
hintText: hintText ?? S.of(context).search_currency,
|
||||
hintText: hintText ?? S.of(context).search,
|
||||
hintStyle: TextStyle(color: Theme.of(context).extension<PickerTheme>()!.searchHintColor),
|
||||
prefixIcon: Image.asset("assets/images/search_icon.png",
|
||||
color: Theme.of(context).extension<PickerTheme>()!.searchIconColor),
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/transaction_trade_theme.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class StandardExpandableList<T> extends StatelessWidget {
|
||||
StandardExpandableList({
|
||||
required this.title,
|
||||
required this.expandableItems,
|
||||
this.decoration,
|
||||
});
|
||||
|
||||
final String title;
|
||||
final List<T> expandableItems;
|
||||
final Decoration? decoration;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
decoration: decoration ??
|
||||
BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.background,
|
||||
),
|
||||
child: Theme(
|
||||
data: Theme.of(context).copyWith(dividerColor: Colors.transparent),
|
||||
child: ExpansionTile(
|
||||
iconColor: Theme.of(context).extension<TransactionTradeTheme>()!.detailsTitlesColor,
|
||||
collapsedIconColor:
|
||||
Theme.of(context).extension<TransactionTradeTheme>()!.detailsTitlesColor,
|
||||
title: Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).extension<TransactionTradeTheme>()!.detailsTitlesColor,
|
||||
),
|
||||
textAlign: TextAlign.left,
|
||||
),
|
||||
children: expandableItems.map((item) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(left: 16.0, bottom: 8.0),
|
||||
child: Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
item.toString(),
|
||||
maxLines: 1,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor),
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
import 'package:cake_wallet/src/widgets/list_row.dart';
|
||||
import 'package:cake_wallet/src/widgets/picker.dart';
|
||||
import 'package:cake_wallet/themes/extensions/picker_theme.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class StandardPickerList<T> extends StatefulWidget {
|
||||
StandardPickerList({
|
||||
Key? key,
|
||||
required this.title,
|
||||
required this.value,
|
||||
required this.items,
|
||||
required this.displayItem,
|
||||
required this.onSliderChanged,
|
||||
required this.onItemSelected,
|
||||
required this.selectedIdx,
|
||||
required this.customItemIndex,
|
||||
required this.customValue,
|
||||
}) : super(key: key);
|
||||
|
||||
final String title;
|
||||
final List<T> items;
|
||||
final int customItemIndex;
|
||||
final String Function(T item, double sliderValue) displayItem;
|
||||
final Function(double) onSliderChanged;
|
||||
final Function(T) onItemSelected;
|
||||
final String value;
|
||||
final int selectedIdx;
|
||||
final double customValue;
|
||||
|
||||
@override
|
||||
_StandardPickerListState<T> createState() => _StandardPickerListState<T>();
|
||||
}
|
||||
|
||||
class _StandardPickerListState<T> extends State<StandardPickerList<T>> {
|
||||
late String value;
|
||||
late int selectedIdx;
|
||||
late double customValue;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
value = widget.value;
|
||||
selectedIdx = widget.selectedIdx;
|
||||
customValue = widget.customValue;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
String adaptedDisplayItem(T item) => widget.displayItem(item, customValue);
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
ListRow(title: '${widget.title}:', value: value),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 24, right: 24, top: 0, bottom: 24),
|
||||
child: Picker(
|
||||
items: widget.items,
|
||||
displayItem: adaptedDisplayItem,
|
||||
selectedAtIndex: selectedIdx,
|
||||
customItemIndex: widget.customItemIndex,
|
||||
headerEnabled: false,
|
||||
closeOnItemSelected: false,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
sliderValue: customValue,
|
||||
isWrapped: false,
|
||||
borderColor: Theme.of(context).extension<PickerTheme>()!.dividerColor,
|
||||
onSliderChanged: (newValue) {
|
||||
setState(() => customValue = newValue);
|
||||
value = widget.onSliderChanged(newValue).toString();
|
||||
},
|
||||
onItemSelected: (T item) {
|
||||
setState(() => selectedIdx = widget.items.indexOf(item));
|
||||
value = widget.onItemSelected(item).toString();
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user