Created
May 29, 2019 15:43
-
-
Save scottbaggett/70a9ab7a0e2d23cfd2d91aa39e2d57ef to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:flutter/cupertino.dart'; | |
import 'package:flutter/material.dart'; | |
import 'package:flutter_svg/svg.dart'; | |
import 'package:mgm_resorts/indigo_theme.dart'; | |
import 'package:mgm_resorts/widgets/fade_in_on_scroll.dart'; | |
import 'package:mgm_resorts/widgets/typography/typography.dart'; | |
import 'package:provider/provider.dart'; | |
import 'package:flutter_range_slider/flutter_range_slider.dart'; | |
class _FiltersViewModel with ChangeNotifier { | |
List _activeFilters = []; | |
double _sliderLowerValue = 0; | |
double _sliderUpperValue = 4; | |
_FiltersViewModel(); | |
set activeFilters(filters) { | |
_activeFilters = filters; | |
notifyListeners(); | |
} | |
void setSliderValues(lower, upper) { | |
_sliderLowerValue = lower; | |
_sliderUpperValue = upper; | |
print('slider lower: $_sliderLowerValue, upper: $_sliderUpperValue'); | |
notifyListeners(); | |
} | |
void toggleFilter(filter) { | |
_activeFilters.contains(filter) | |
? _activeFilters.remove(filter) | |
: _activeFilters.add(filter); | |
notifyListeners(); | |
} | |
void clearFilters() { | |
_activeFilters = []; | |
_sliderLowerValue = 0; | |
_sliderUpperValue = 4; | |
notifyListeners(); | |
} | |
double get sliderLowerValue => _sliderLowerValue; | |
double get sliderUpperValue => _sliderUpperValue; | |
List get activeFilters => _activeFilters; | |
} | |
class _ClearButton extends StatelessWidget { | |
const _ClearButton({Key key}) : super(key: key); | |
@override | |
Widget build(BuildContext context) { | |
var model = Provider.of<_FiltersViewModel>(context); | |
return GestureDetector( | |
onTap: () { | |
model.clearFilters(); | |
}, | |
child: Body("clear"), | |
); | |
} | |
} | |
class _AppBar extends StatelessWidget { | |
final ScrollController controller; | |
final _pageTitle = 'Filters'; | |
const _AppBar({ | |
Key key, | |
this.controller, | |
}) : super(key: key); | |
@override | |
Widget build(BuildContext context) { | |
return CupertinoSliverNavigationBar( | |
padding: EdgeInsetsDirectional.only(start: 0, end: 16), | |
backgroundColor: white, | |
border: Border(), | |
leading: IconButton( | |
padding: EdgeInsets.all(0), | |
alignment: Alignment.centerLeft, | |
icon: SvgPicture.asset('assets/svg/close.svg', color: black), | |
onPressed: () {}, | |
), | |
largeTitle: Text( | |
_pageTitle, | |
style: Theme.of(context).textTheme.display1, | |
), | |
trailing: _ClearButton(), | |
middle: FadeInOnScroll( | |
child: Text(_pageTitle), | |
controller: controller, | |
offset: 22, | |
), | |
); | |
} | |
} | |
class _FilterGroupTitle extends StatelessWidget { | |
final String title; | |
const _FilterGroupTitle({ | |
Key key, | |
@required this.title, | |
}) : assert(title != null), | |
super(key: key); | |
@override | |
Widget build(BuildContext context) { | |
return Container( | |
height: 32, | |
child: Text(title), | |
); | |
} | |
} | |
class FilterButton extends StatelessWidget { | |
final bool active; | |
final String label; | |
final Function onPressed; | |
const FilterButton({ | |
Key key, | |
this.active, | |
this.label, | |
this.onPressed, | |
}) : super(key: key); | |
@override | |
Widget build(BuildContext context) { | |
return (active) | |
? FlatButton( | |
color: indigo, | |
shape: RoundedRectangleBorder( | |
borderRadius: new BorderRadius.circular(4), | |
), | |
onPressed: () { | |
if (onPressed != null) onPressed(); | |
}, | |
child: Caption( | |
label, | |
height: 0.8, | |
color: white, | |
), | |
) | |
: OutlineButton( | |
onPressed: () { | |
if (onPressed != null) onPressed(); | |
}, | |
color: white, | |
splashColor: indigo, | |
borderSide: BorderSide(color: black), | |
highlightedBorderColor: indigo, | |
shape: RoundedRectangleBorder( | |
borderRadius: new BorderRadius.circular(4), | |
), | |
child: Caption( | |
label, | |
height: 0.8, | |
)); | |
} | |
} | |
class _FilterButtonGroupButtons extends StatelessWidget { | |
final List filters; | |
const _FilterButtonGroupButtons({Key key, this.filters}) : super(key: key); | |
@override | |
Widget build(BuildContext context) { | |
var model = Provider.of<_FiltersViewModel>(context); | |
return Wrap( | |
runSpacing: -4, | |
children: filters.map(( | |
filter, | |
) { | |
return Padding( | |
padding: const EdgeInsets.only(right: 6.0), | |
child: FilterButton( | |
label: filter, | |
active: model.activeFilters.contains(filter), | |
onPressed: () { | |
model.toggleFilter(filter); | |
}, | |
), | |
); | |
}).toList()); | |
} | |
} | |
class _FilterButtonGroup extends StatelessWidget { | |
final String title; | |
final List filters; | |
final List selectedFilters; | |
/// Allow the header to be pinned to the appbar as user scrolls | |
final bool pinned; | |
const _FilterButtonGroup({ | |
Key key, | |
this.title, | |
this.filters, | |
this.selectedFilters, | |
this.pinned = false, | |
}) : assert(filters != null), | |
super(key: key); | |
@override | |
Widget build(BuildContext context) { | |
return Container( | |
child: Column( | |
crossAxisAlignment: CrossAxisAlignment.start, | |
children: <Widget>[ | |
_FilterGroupTitle(title: title), | |
_FilterButtonGroupButtons(filters: filters), | |
], | |
), | |
); | |
} | |
} | |
class _PriceGraphClipper extends CustomClipper<Path> { | |
/// Adds a quadratic bezier segment that curves from the current | |
/// point to the given point (x2,y2), using the control point | |
/// (x1,y1). | |
// void quadraticBezierTo(double x1, double y1, double x2, double y2) | |
/// Adds a cubic bezier segment that curves from the current point | |
/// to the given point (x3,y3), using the control points (x1,y1) and | |
/// (x2,y2). | |
// void cubicTo(double x1, double y1, double x2, double y2, double x3, double y3) native 'Path_cubicTo'; | |
@override | |
Path getClip(Size size) { | |
var path = new Path(); | |
var w = size.width; | |
var h = size.height; | |
path.moveTo(0, h); | |
path.lineTo(20, h - 12); | |
path.lineTo(w / 6, h / 10); | |
path.lineTo(w / 4 + w / 8, 0); | |
path.lineTo(w / 2 + w / 8, h - 20); | |
path.lineTo(w * 0.8, h - 20); | |
path.lineTo(w, h); | |
path.close(); | |
return path; | |
} | |
@override | |
bool shouldReclip(CustomClipper<Path> oldClipper) => true; | |
} | |
class _PriceRangeGraph extends StatelessWidget { | |
const _PriceRangeGraph({Key key}) : super(key: key); | |
@override | |
Widget build(BuildContext context) { | |
return Padding( | |
padding: ThemePadding.insetHorizontalLarge, | |
child: ClipPath( | |
clipper: _PriceGraphClipper(), | |
child: Container( | |
color: Color(0xFFE0E2FD), | |
), | |
), | |
); | |
} | |
} | |
class _FilterPricePicker extends StatelessWidget { | |
const _FilterPricePicker({Key key}) : super(key: key); | |
@override | |
Widget build(BuildContext context) { | |
var model = Provider.of<_FiltersViewModel>(context); | |
var _disabled = Color(0xFFE0E2FD); | |
return Stack( | |
children: <Widget>[ | |
Container( | |
height: 80, | |
child: Column( | |
children: <Widget>[ | |
Expanded( | |
child: _PriceRangeGraph(), | |
), | |
SizedBox(height: 32), | |
], | |
), | |
), | |
Positioned( | |
bottom: -3, | |
left: 0, | |
right: 0, | |
child: Column( | |
children: <Widget>[ | |
RangeSlider( | |
min: 0, | |
max: 4, | |
divisions: 4, | |
lowerValue: model.sliderLowerValue, | |
upperValue: model.sliderUpperValue, | |
onChanged: (double lower, double upper) { | |
model.setSliderValues(lower, upper); | |
}, | |
), | |
Container( | |
width: MediaQuery.of(context).size.width, | |
child: Row( | |
mainAxisAlignment: MainAxisAlignment.spaceAround, | |
children: <Widget>[ | |
Caption( | |
"\$", | |
color: (model.sliderLowerValue < 1) ? indigo : _disabled, | |
), | |
Caption( | |
"\$\$", | |
color: (model.sliderLowerValue < 2 && | |
model.sliderUpperValue > 1) | |
? indigo | |
: _disabled, | |
), | |
Caption( | |
"\$\$\$", | |
color: (model.sliderLowerValue < 3 && | |
model.sliderUpperValue > 2) | |
? indigo | |
: _disabled, | |
), | |
Caption( | |
"\$\$\$\$", | |
color: (model.sliderUpperValue > 3) ? indigo : _disabled, | |
), | |
], | |
), | |
), | |
], | |
), | |
) | |
], | |
); | |
} | |
} | |
class Math {} | |
class Filters extends StatefulWidget { | |
@override | |
State<Filters> createState() => _Filters(); | |
} | |
class _Filters extends State<Filters> { | |
ScrollController _scrollController = ScrollController(); | |
@override | |
void initState() { | |
super.initState(); | |
} | |
_separator() { | |
return SliverToBoxAdapter( | |
child: Padding( | |
padding: const EdgeInsets.symmetric(vertical: 16.0), | |
child: Container(height: 1, color: inputGrey), | |
)); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return ChangeNotifierProvider<_FiltersViewModel>( | |
builder: (_) => _FiltersViewModel(), | |
child: Scaffold( | |
body: Container( | |
color: white, | |
child: SafeArea( | |
left: false, | |
right: false, | |
bottom: false, | |
child: CustomScrollView( | |
controller: _scrollController, | |
slivers: <Widget>[ | |
_AppBar( | |
controller: _scrollController, | |
), | |
SliverToBoxAdapter( | |
child: Container( | |
padding: ThemePadding.insetPrimary, | |
child: _FilterButtonGroup( | |
title: 'Category', | |
filters: [ | |
'Attractions', | |
'Cirque du Soleil', | |
'Comedy & Stand Up', | |
'Concerts', | |
'Magic', | |
'Mature Audiences', | |
'Sporting Events' | |
], | |
), | |
), | |
), | |
_separator(), | |
SliverToBoxAdapter( | |
child: Container( | |
padding: ThemePadding.insetPrimary, | |
child: _FilterButtonGroup( | |
title: 'Region', | |
filters: [ | |
'Las Vegas', | |
'Maryland', | |
'Massachusetts', | |
], | |
), | |
), | |
), | |
_separator(), | |
SliverToBoxAdapter( | |
child: Container( | |
padding: ThemePadding.insetPrimary, | |
child: _FilterGroupTitle(title: 'Price'), | |
), | |
), | |
SliverToBoxAdapter( | |
child: Container( | |
padding: ThemePadding.insetPrimary, | |
child: _FilterPricePicker(), | |
), | |
), | |
_separator(), | |
SliverToBoxAdapter( | |
child: Container( | |
padding: ThemePadding.insetPrimary, | |
child: _FilterButtonGroup( | |
title: 'Property', | |
filters: [ | |
'ARIA', | |
'Bellagio', | |
'Vdara', | |
'MGM Grand', | |
'Siganture', | |
'Mandalay Bay', | |
'Delano', | |
'Park MGM', | |
'NoMad', | |
'Mirage', | |
'New York-New York', | |
'Luxor', | |
'Excalibur', | |
'Circus Circus', | |
], | |
), | |
), | |
), | |
], | |
), | |
), | |
), | |
), | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment