CW-376-picker-ui-issue (#919)

* feat: use common modal widget for repeated picker logic and display

* refactor: rename widget

* refactor: clear wrapper logic from picker widget and move title to hasTitle

* Minor code readability enhancements [skip ci]

---------

Co-authored-by: OmarHatem <omarh.ismail1@gmail.com>
wow-support
Rafael Saes 1 year ago committed by GitHub
parent 759e61f67e
commit e28e2fbdde
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,13 +1,9 @@
import 'dart:ui';
import 'package:cake_wallet/palette.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/standard_checkbox.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/src/widgets/alert_background.dart';
import 'package:cake_wallet/src/widgets/alert_close_button.dart';
import 'package:cake_wallet/src/widgets/picker_wrapper_widget.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
//import 'package:date_range_picker/date_range_picker.dart' as date_rage_picker;
@ -20,89 +16,93 @@ class FilterWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
const sectionDivider = const SectionDivider();
return AlertBackground(
child: Stack(
alignment: Alignment.center,
children: <Widget>[
Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Padding(
padding: EdgeInsets.only(left: 24, right: 24, top: 24),
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(24)),
child: Container(
color: Theme.of(context).textTheme!.bodyText1!.decorationColor!,
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Padding(
padding: EdgeInsets.all(24.0),
child: Text(
S.of(context).filter_by,
style: TextStyle(
color: Theme.of(context).primaryTextTheme.overline!.color!,
fontSize: 16,
fontFamily: 'Lato',
decoration: TextDecoration.none,
),
return PickerWrapperWidget(
children: [
Padding(
padding: EdgeInsets.only(left: 24, right: 24, top: 24),
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(24)),
child: Container(
color: Theme.of(context).textTheme!.bodyText1!.decorationColor!,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.all(24.0),
child: Text(
S.of(context).filter_by,
style: TextStyle(
color: Theme.of(context)
.primaryTextTheme
.overline!
.color!,
fontSize: 16,
fontFamily: 'Lato',
decoration: TextDecoration.none,
),
),
sectionDivider,
ListView.separated(
padding: EdgeInsets.zero,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: dashboardViewModel.filterItems.length,
separatorBuilder: (context, _) => sectionDivider,
itemBuilder: (_, index1) {
final title = dashboardViewModel.filterItems.keys.elementAt(index1);
final section = dashboardViewModel.filterItems.values.elementAt(index1);
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 20, left: 24, right: 24),
child: Text(
title,
style: TextStyle(
color: Theme.of(context).primaryTextTheme!.headline6!.color!,
fontSize: 16,
fontFamily: 'Lato',
fontWeight: FontWeight.bold,
decoration: TextDecoration.none),
),
),
sectionDivider,
ListView.separated(
padding: EdgeInsets.zero,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: dashboardViewModel.filterItems.length,
separatorBuilder: (context, _) => sectionDivider,
itemBuilder: (_, index1) {
final title = dashboardViewModel.filterItems.keys
.elementAt(index1);
final section = dashboardViewModel.filterItems.values
.elementAt(index1);
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding:
EdgeInsets.only(top: 20, left: 24, right: 24),
child: Text(
title,
style: TextStyle(
color: Theme.of(context)
.primaryTextTheme!
.headline6!
.color!,
fontSize: 16,
fontFamily: 'Lato',
fontWeight: FontWeight.bold,
decoration: TextDecoration.none),
),
ListView.builder(
padding: EdgeInsets.symmetric(vertical: 8.0),
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: section.length,
itemBuilder: (_, index2) {
final item = section[index2];
final content = Observer(
builder: (_) => StandardCheckbox(
value: item.value(),
caption: item.caption,
gradientBackground: true,
borderColor: Theme.of(context).dividerColor,
iconColor: Colors.white,
onChanged: (value) => item.onChanged(),
));
return FilterTile(child: content);
},
)
],
);
},
),
]),
),
),
),
],
),
ListView.builder(
padding: EdgeInsets.symmetric(vertical: 8.0),
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: section.length,
itemBuilder: (_, index2) {
final item = section[index2];
final content = Observer(
builder: (_) => StandardCheckbox(
value: item.value(),
caption: item.caption,
gradientBackground: true,
borderColor:
Theme.of(context).dividerColor,
iconColor: Colors.white,
onChanged: (value) =>
item.onChanged(),
));
return FilterTile(child: content);
},
)
],
);
},
),
]),
),
),
AlertCloseButton()
],
),
)
],
);
}
}

@ -1,8 +1,7 @@
import 'package:cake_wallet/palette.dart';
import 'package:cake_wallet/utils/responsive_layout_util.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/src/widgets/alert_background.dart';
import 'package:cake_wallet/src/widgets/alert_close_button.dart';
import 'package:cake_wallet/src/widgets/picker_wrapper_widget.dart';
class CheckBoxPicker extends StatefulWidget {
CheckBoxPicker({
@ -32,73 +31,57 @@ class CheckBoxPickerState extends State<CheckBoxPicker> {
@override
Widget build(BuildContext context) {
return AlertBackground(
child: Column(
children: [
Expanded(
child: Stack(
alignment: Alignment.center,
children: [
Column(
return PickerWrapperWidget(
children: [
if (widget.title.isNotEmpty)
Container(
padding: EdgeInsets.symmetric(horizontal: 24),
child: Text(
widget.title,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 18,
fontFamily: 'Lato',
fontWeight: FontWeight.bold,
decoration: TextDecoration.none,
color: Colors.white,
),
),
),
Padding(
padding: EdgeInsets.only(left: 24, right: 24, top: 24),
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(30)),
child: Container(
color: Theme.of(context).accentTextTheme.headline6!.color!,
child: ConstrainedBox(
constraints: BoxConstraints(
maxHeight: MediaQuery.of(context).size.height * 0.65,
maxWidth: ResponsiveLayoutUtil.kPopupWidth,
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
if (widget.title.isNotEmpty)
Container(
padding: EdgeInsets.symmetric(horizontal: 24),
child: Text(
widget.title,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 18,
fontFamily: 'Lato',
fontWeight: FontWeight.bold,
decoration: TextDecoration.none,
color: Colors.white,
),
),
),
Padding(
padding: EdgeInsets.only(left: 24, right: 24, top: 24),
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(30)),
child: Container(
color: Theme.of(context).accentTextTheme.headline6!.color!,
child: ConstrainedBox(
constraints: BoxConstraints(
maxHeight: MediaQuery.of(context).size.height * 0.65,
maxWidth: ResponsiveLayoutUtil.kPopupWidth,
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Flexible(
child: Stack(
alignment: Alignment.center,
children: <Widget>[
items.length > 3
? Scrollbar(
controller: controller,
child: itemsList(),
)
: itemsList(),
],
),
),
],
),
),
),
children: [
Flexible(
child: Stack(
alignment: Alignment.center,
children: <Widget>[
items.length > 3
? Scrollbar(
controller: controller,
child: itemsList(),
)
: itemsList(),
],
),
),
],
),
SizedBox(height: ResponsiveLayoutUtil.kPopupSpaceHeight),
AlertCloseButton(),
],
),
),
),
],
),
),
],
);
}
@ -111,7 +94,10 @@ class CheckBoxPickerState extends State<CheckBoxPicker> {
shrinkWrap: true,
separatorBuilder: (context, index) => widget.isSeparated
? Divider(
color: Theme.of(context).accentTextTheme.headline6!.backgroundColor!,
color: Theme.of(context)
.accentTextTheme
.headline6!
.backgroundColor!,
height: 1,
)
: const SizedBox(),

@ -2,9 +2,8 @@
import 'package:cake_wallet/utils/responsive_layout_util.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/src/widgets/alert_background.dart';
import 'package:cake_wallet/src/widgets/alert_close_button.dart';
import 'package:cw_core/currency.dart';
import 'package:cake_wallet/src/widgets/picker_wrapper_widget.dart';
class Picker<Item> extends StatefulWidget {
Picker({
@ -114,171 +113,130 @@ class _PickerState<Item> extends State<Picker<Item>> {
final mq = MediaQuery.of(context);
final bottom = mq.viewInsets.bottom;
final height = mq.size.height - bottom;
final screenCenter = height / 2;
double closeButtonBottom = 60;
double containerHeight = height * 0.65;
if (bottom > 0) {
// increase a bit or it gets too squished in the top
containerHeight = height * 0.75;
final containerCenter = containerHeight / 2;
final containerBottom = screenCenter - containerCenter;
final hasTitle = widget.title == null || widget.title!.isEmpty;
// position the close button right below the search container
closeButtonBottom = closeButtonBottom -
containerBottom +
(hasTitle ? padding : padding / 1.5);
}
return AlertBackground(
child: Column(
children: [
Expanded(
flex: 1,
child: Stack(
alignment: Alignment.center,
children: <Widget>[
Column(
return PickerWrapperWidget(
hasTitle: widget.title?.isNotEmpty ?? false,
children: [
if (widget.title?.isNotEmpty ?? false)
Container(
padding: EdgeInsets.symmetric(horizontal: padding),
child: Text(
widget.title!,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 18,
fontFamily: 'Lato',
fontWeight: FontWeight.bold,
decoration: TextDecoration.none,
color: Colors.white,
),
),
),
Padding(
padding: EdgeInsets.symmetric(horizontal: padding),
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(30)),
child: Container(
color: Theme.of(context).accentTextTheme.headline6!.color!,
child: ConstrainedBox(
constraints: BoxConstraints(
maxHeight: containerHeight,
maxWidth: ResponsiveLayoutUtil.kPopupWidth,
),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
if (widget.title?.isNotEmpty ?? false)
Container(
padding: EdgeInsets.symmetric(horizontal: padding),
child: Text(
widget.title!,
textAlign: TextAlign.center,
children: [
if (widget.hintText != null)
Padding(
padding: const EdgeInsets.all(16),
child: TextFormField(
controller: searchController,
style: TextStyle(
fontSize: 18,
fontFamily: 'Lato',
fontWeight: FontWeight.bold,
decoration: TextDecoration.none,
color: Colors.white,
color: Theme.of(context)
.primaryTextTheme
.headline6!
.color!),
decoration: InputDecoration(
hintText: widget.hintText,
prefixIcon:
Image.asset("assets/images/search_icon.png"),
filled: true,
fillColor: Theme.of(context)
.accentTextTheme
.headline3!
.color!,
alignLabelWithHint: false,
contentPadding: const EdgeInsets.symmetric(
vertical: 4, horizontal: 16),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(14),
borderSide: const BorderSide(
color: Colors.transparent,
)),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(14),
borderSide: const BorderSide(
color: Colors.transparent,
)),
),
),
),
Padding(
padding: EdgeInsets.symmetric(horizontal: padding),
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(30)),
child: Container(
color: Theme.of(context)
.accentTextTheme
.headline6!
.color!,
child: ConstrainedBox(
constraints: BoxConstraints(
maxHeight: containerHeight,
maxWidth: ResponsiveLayoutUtil.kPopupWidth,
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
if (widget.hintText != null)
Padding(
padding: const EdgeInsets.all(16),
child: TextFormField(
controller: searchController,
style: TextStyle(
color: Theme.of(context)
.primaryTextTheme
.headline6!
.color!),
decoration: InputDecoration(
hintText: widget.hintText,
prefixIcon: Image.asset(
"assets/images/search_icon.png"),
filled: true,
fillColor: Theme.of(context)
.accentTextTheme
.headline3!
.color!,
alignLabelWithHint: false,
contentPadding:
const EdgeInsets.symmetric(
vertical: 4, horizontal: 16),
enabledBorder: OutlineInputBorder(
borderRadius:
BorderRadius.circular(14),
borderSide: const BorderSide(
color: Colors.transparent,
)),
focusedBorder: OutlineInputBorder(
borderRadius:
BorderRadius.circular(14),
borderSide: const BorderSide(
color: Colors.transparent,
)),
),
Divider(
color: Theme.of(context)
.accentTextTheme
.headline6!
.backgroundColor!,
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)
.primaryTextTheme
.headline6!
.color!,
),
),
Divider(
color: Theme.of(context)
.accentTextTheme
.headline6!
.backgroundColor!,
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)
.primaryTextTheme
.headline6!
.color!,
),
),
)
: Offstage(),
],
),
),
],
),
),
),
)
: Offstage(),
],
),
)
),
],
),
SizedBox(height: ResponsiveLayoutUtil.kPopupSpaceHeight),
AlertCloseButton(bottom: closeButtonBottom),
],
),
),
),
// gives the extra spacing using MediaQuery.viewInsets.bottom
// to simulate a keyboard area
SizedBox(
height: bottom,
)
],
),
)
],
);
}

@ -0,0 +1,61 @@
import 'package:cake_wallet/utils/responsive_layout_util.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/src/widgets/alert_background.dart';
import 'package:cake_wallet/src/widgets/alert_close_button.dart';
class PickerWrapperWidget extends StatelessWidget {
PickerWrapperWidget({required this.children, this.hasTitle = false});
final List<Widget> children;
final bool hasTitle;
@override
Widget build(BuildContext context) {
final double padding = 24;
final mq = MediaQuery.of(context);
final bottom = mq.viewInsets.bottom;
final height = mq.size.height - bottom;
final screenCenter = height / 2;
double closeButtonBottom = 60;
double containerHeight = height * 0.65;
if (bottom > 0) {
// increase a bit or it gets too squished in the top
containerHeight = height * 0.75;
final containerCenter = containerHeight / 2;
final containerBottom = screenCenter - containerCenter;
// position the close button right below the search container
closeButtonBottom = closeButtonBottom -
containerBottom + (!hasTitle ? padding : padding / 1.5);
}
return AlertBackground(
child: Column(
children: [
Expanded(
flex: 1,
child: Stack(
alignment: Alignment.center,
children: <Widget>[
Column(
mainAxisSize: MainAxisSize.min,
children: children,
),
SizedBox(height: ResponsiveLayoutUtil.kPopupSpaceHeight),
AlertCloseButton(bottom: closeButtonBottom),
],
),
),
// gives the extra spacing using MediaQuery.viewInsets.bottom
// to simulate a keyboard area
SizedBox(
height: bottom,
)
],
),
);
}
}
Loading…
Cancel
Save