mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-06-28 20:39:51 +00:00
Cw 1038 filter transaction popup not scrollable (#2207)
* ui:make overflowing filter sections scrollable * Update pull_request_template.md
This commit is contained in:
parent
66e1745ad9
commit
ffe1c115fa
3 changed files with 164 additions and 112 deletions
1
.github/pull_request_template.md
vendored
1
.github/pull_request_template.md
vendored
|
@ -11,3 +11,4 @@ Please include a summary of the changes and which issue is fixed / feature is ad
|
||||||
- [ ] Format code
|
- [ ] Format code
|
||||||
- [ ] Look for code duplication
|
- [ ] Look for code duplication
|
||||||
- [ ] Clear naming for variables and methods
|
- [ ] Clear naming for variables and methods
|
||||||
|
- [ ] Manual tests in accessibility mode (TalkBack on Android) passed
|
||||||
|
|
|
@ -1,123 +1,178 @@
|
||||||
|
import 'package:cake_wallet/src/widgets/alert_background.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/alert_close_button.dart';
|
||||||
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
||||||
import 'package:cake_wallet/src/screens/dashboard/widgets/filter_tile.dart';
|
import 'package:cake_wallet/src/screens/dashboard/widgets/filter_tile.dart';
|
||||||
import 'package:cake_wallet/src/widgets/section_divider.dart';
|
import 'package:cake_wallet/src/widgets/section_divider.dart';
|
||||||
import 'package:cake_wallet/src/widgets/standard_checkbox.dart';
|
import 'package:cake_wallet/src/widgets/standard_checkbox.dart';
|
||||||
import 'package:cake_wallet/themes/extensions/menu_theme.dart';
|
import 'package:cake_wallet/themes/extensions/menu_theme.dart';
|
||||||
import 'package:cake_wallet/view_model/dashboard/dropdown_filter_item.dart';
|
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||||
import 'package:cake_wallet/view_model/dashboard/dropdown_filter_item_widget.dart';
|
|
||||||
import 'package:cake_wallet/view_model/dashboard/filter_item.dart';
|
import 'package:cake_wallet/view_model/dashboard/filter_item.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:cake_wallet/src/widgets/picker_wrapper_widget.dart';
|
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||||
|
|
||||||
//import 'package:date_range_picker/date_range_picker.dart' as date_rage_picker;
|
|
||||||
import 'package:cake_wallet/themes/extensions/transaction_trade_theme.dart';
|
import 'package:cake_wallet/themes/extensions/transaction_trade_theme.dart';
|
||||||
|
|
||||||
class FilterWidget extends StatelessWidget {
|
class FilterWidget extends StatefulWidget {
|
||||||
FilterWidget({required this.filterItems});
|
const FilterWidget({required this.filterItems, this.onClose, Key? key}) : super(key: key);
|
||||||
|
|
||||||
final Map<String, List<FilterItem>> filterItems;
|
final Map<String, List<FilterItem>> filterItems;
|
||||||
|
final Function()? onClose;
|
||||||
|
|
||||||
|
@override
|
||||||
|
_FilterWidgetState createState() => _FilterWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _FilterWidgetState extends State<FilterWidget> {
|
||||||
|
final ScrollController _scrollController = ScrollController();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_scrollController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
const sectionDivider = const HorizontalSectionDivider();
|
return AlertBackground(
|
||||||
return PickerWrapperWidget(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
const Expanded(child: SizedBox()),
|
||||||
padding: EdgeInsets.only(left: 24, right: 24, top: 24),
|
Expanded(
|
||||||
child: ClipRRect(
|
flex: responsiveLayoutUtil.shouldRenderTabletUI ? 16 : 8,
|
||||||
borderRadius: BorderRadius.all(Radius.circular(24)),
|
child: LayoutBuilder(
|
||||||
child: Container(
|
builder: (context, constraints) {
|
||||||
color: Theme.of(context).extension<CakeMenuTheme>()!.backgroundColor,
|
double availableHeight = constraints.maxHeight;
|
||||||
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
return _buildFilterContent(context, availableHeight);
|
||||||
Padding(
|
},
|
||||||
padding: EdgeInsets.all(24.0),
|
),
|
||||||
child: Text(
|
),
|
||||||
S.of(context).filter_by,
|
Expanded(
|
||||||
style: TextStyle(
|
child: AlertCloseButton(
|
||||||
color:
|
key: const ValueKey('filter_wrapper_close_button_key'),
|
||||||
Theme.of(context).extension<TransactionTradeTheme>()!.detailsTitlesColor,
|
isPositioned: false,
|
||||||
fontSize: 16,
|
onTap: widget.onClose,
|
||||||
fontFamily: 'Lato',
|
),
|
||||||
decoration: TextDecoration.none,
|
),
|
||||||
),
|
const SizedBox(height: 24),
|
||||||
),
|
],
|
||||||
),
|
),
|
||||||
sectionDivider,
|
);
|
||||||
ListView.separated(
|
}
|
||||||
padding: EdgeInsets.zero,
|
|
||||||
shrinkWrap: true,
|
Widget _buildFilterContent(BuildContext context, double availableHeight) {
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
const sectionDivider = HorizontalSectionDivider();
|
||||||
itemCount: filterItems.length,
|
|
||||||
separatorBuilder: (context, _) => sectionDivider,
|
const double totalHeaderHeight = 73;
|
||||||
itemBuilder: (_, index1) {
|
const double filterTileMinHeight = 40;
|
||||||
final title = filterItems.keys.elementAt(index1);
|
double availableHeightForItems = availableHeight - totalHeaderHeight;
|
||||||
final section = filterItems.values.elementAt(index1);
|
|
||||||
return Column(
|
return Center(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
child: Column(
|
||||||
children: <Widget>[
|
mainAxisSize: MainAxisSize.min,
|
||||||
Padding(
|
children: [
|
||||||
padding: EdgeInsets.only(top: 20, left: 24, right: 24),
|
Padding(
|
||||||
child: Text(
|
padding: const EdgeInsets.only(left: 24, right: 24, top: 24),
|
||||||
title,
|
child: ClipRRect(
|
||||||
style: TextStyle(
|
borderRadius: BorderRadius.circular(24),
|
||||||
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
|
child: Container(
|
||||||
fontSize: 16,
|
color: Theme.of(context).extension<CakeMenuTheme>()!.backgroundColor,
|
||||||
fontFamily: 'Lato',
|
child: Column(
|
||||||
fontWeight: FontWeight.bold,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
decoration: TextDecoration.none),
|
children: [
|
||||||
),
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(24.0),
|
||||||
|
child: Text(
|
||||||
|
S.of(context).filter_by,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<TransactionTradeTheme>()!
|
||||||
|
.detailsTitlesColor,
|
||||||
|
fontSize: 16,
|
||||||
|
fontFamily: 'Lato',
|
||||||
|
decoration: TextDecoration.none,
|
||||||
),
|
),
|
||||||
ListView.builder(
|
),
|
||||||
padding: EdgeInsets.symmetric(horizontal: 28.0),
|
),
|
||||||
shrinkWrap: true,
|
sectionDivider,
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
ListView.separated(
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
shrinkWrap: true,
|
||||||
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
|
itemCount: widget.filterItems.length,
|
||||||
|
separatorBuilder: (context, _) => sectionDivider,
|
||||||
|
itemBuilder: (_, index1) {
|
||||||
|
final title = widget.filterItems.keys.elementAt(index1);
|
||||||
|
final section = widget.filterItems.values.elementAt(index1);
|
||||||
|
|
||||||
|
final double itemHeight =
|
||||||
|
availableHeightForItems / widget.filterItems.length;
|
||||||
|
|
||||||
|
final isSectionScrollable =
|
||||||
|
(itemHeight < (section.length * filterTileMinHeight));
|
||||||
|
|
||||||
|
final Widget sectionListView = ListView.builder(
|
||||||
|
controller: isSectionScrollable ? _scrollController : null,
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 28.0),
|
||||||
|
shrinkWrap: isSectionScrollable ? false : true,
|
||||||
|
physics: isSectionScrollable
|
||||||
|
? const BouncingScrollPhysics()
|
||||||
|
: const NeverScrollableScrollPhysics(),
|
||||||
itemCount: section.length,
|
itemCount: section.length,
|
||||||
itemBuilder: (_, index2) {
|
itemBuilder: (_, index2) {
|
||||||
final item = section[index2];
|
final item = section[index2];
|
||||||
|
|
||||||
if (item is DropdownFilterItem) {
|
|
||||||
return Padding(
|
|
||||||
padding: EdgeInsets.fromLTRB(8, 0, 8, 16),
|
|
||||||
child: Container(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
border: Border(
|
|
||||||
bottom: BorderSide(
|
|
||||||
width: 1.0,
|
|
||||||
color: Theme.of(context).extension<CakeTextTheme>()!.secondaryTextColor),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: DropdownFilterList(
|
|
||||||
items: item.items,
|
|
||||||
caption: item.caption,
|
|
||||||
selectedItem: item.selectedItem,
|
|
||||||
onItemSelected: item.onItemSelected,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
final content = Observer(
|
final content = Observer(
|
||||||
builder: (_) => StandardCheckbox(
|
builder: (_) => StandardCheckbox(
|
||||||
value: item.value(),
|
value: item.value(),
|
||||||
caption: item.caption,
|
caption: item.caption,
|
||||||
gradientBackground: true,
|
gradientBackground: true,
|
||||||
borderColor: Theme.of(context).dividerColor,
|
borderColor: Theme.of(context).dividerColor,
|
||||||
iconColor: Colors.white,
|
iconColor: Colors.white,
|
||||||
onChanged: (value) => item.onChanged(),
|
onChanged: (value) => item.onChanged(),
|
||||||
));
|
),
|
||||||
return FilterTile(child: content);
|
);
|
||||||
|
return FilterTile(
|
||||||
|
child: content,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
)
|
);
|
||||||
],
|
|
||||||
);
|
return Column(
|
||||||
},
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 20, left: 24, right: 24),
|
||||||
|
child: Text(
|
||||||
|
title,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
|
||||||
|
fontSize: 16,
|
||||||
|
fontFamily: 'Lato',
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
decoration: TextDecoration.none,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
height: isSectionScrollable ? itemHeight - totalHeaderHeight : null,
|
||||||
|
child: isSectionScrollable
|
||||||
|
? Scrollbar(
|
||||||
|
controller: _scrollController,
|
||||||
|
thumbVisibility: true,
|
||||||
|
child: sectionListView,
|
||||||
|
)
|
||||||
|
: sectionListView,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
]),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
],
|
||||||
],
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ class AlertCloseButton extends StatelessWidget {
|
||||||
this.image,
|
this.image,
|
||||||
this.bottom,
|
this.bottom,
|
||||||
this.onTap,
|
this.onTap,
|
||||||
|
this.isPositioned = true,
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -14,6 +15,7 @@ class AlertCloseButton extends StatelessWidget {
|
||||||
|
|
||||||
final Image? image;
|
final Image? image;
|
||||||
final double? bottom;
|
final double? bottom;
|
||||||
|
final bool isPositioned;
|
||||||
|
|
||||||
final closeButton = Image.asset(
|
final closeButton = Image.asset(
|
||||||
'assets/images/close.png',
|
'assets/images/close.png',
|
||||||
|
@ -22,24 +24,18 @@ class AlertCloseButton extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Positioned(
|
final button = GestureDetector(
|
||||||
bottom: bottom ?? 60,
|
|
||||||
child: GestureDetector(
|
|
||||||
onTap: onTap ?? () => Navigator.of(context).pop(),
|
onTap: onTap ?? () => Navigator.of(context).pop(),
|
||||||
child: Semantics(
|
child: Semantics(
|
||||||
label: S.of(context).close,
|
label: S.of(context).close,
|
||||||
button: true,
|
button: true,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
child: Container(
|
child: Container(
|
||||||
height: 42,
|
height: 42,
|
||||||
width: 42,
|
width: 42,
|
||||||
decoration: BoxDecoration(color: Colors.white, shape: BoxShape.circle),
|
decoration: BoxDecoration(color: Colors.white, shape: BoxShape.circle),
|
||||||
child: Center(
|
child: Center(child: image ?? closeButton))));
|
||||||
child: image ?? closeButton,
|
|
||||||
),
|
return isPositioned ? Positioned(bottom: bottom ?? 60, child: button) : button;
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue