Last active
August 18, 2022 10:57
-
-
Save PlugFox/1e011d3b3737d59697e09bc6e59f422f to your computer and use it in GitHub Desktop.
Filter example pass controller through constructor
This file contains 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
/* | |
* Filter example pass controller through constructor | |
* https://gist.github.com/PlugFox/1e011d3b3737d59697e09bc6e59f422f | |
* https://dartpad.dev/1e011d3b3737d59697e09bc6e59f422f | |
* Matiunin Mikhail <plugfox@gmail.com>, 19 May 2022 | |
*/ | |
import 'dart:async'; | |
import 'dart:math' as math; | |
import 'package:flutter/material.dart'; | |
void main() => runZonedGuarded<Future<void>>(() async { | |
runApp(const App()); | |
}, (error, stackTrace) { | |
print('Error: $error, stackTrace: $stackTrace'); | |
}); | |
/// {@template app} | |
/// App widget | |
/// {@endtemplate} | |
class App extends StatelessWidget { | |
/// {@macro app} | |
const App({ | |
Key? key, | |
}) : super(key: key); | |
@override | |
Widget build(BuildContext context) => const MaterialApp( | |
title: 'Filter example', | |
debugShowCheckedModeBanner: false, | |
home: HomeScreen(), | |
); | |
} // App | |
// --- Home screen with filter --- // | |
/// {@template main} | |
/// HomeScreen widget | |
/// {@endtemplate} | |
class HomeScreen extends StatefulWidget { | |
/// {@macro main} | |
const HomeScreen({ | |
Key? key, | |
}) : super(key: key); | |
@override | |
State<HomeScreen> createState() => _HomeScreenState(); | |
} // HomeScreen | |
/// State for widget HomeScreen | |
class _HomeScreenState extends State<HomeScreen> { | |
static final math.Random _rnd = math.Random(); | |
static const int _kMax = 100; | |
final List<int> _sourceList = | |
Iterable<int>.generate(_kMax, (_) => _rnd.nextInt(_kMax)) | |
.toList(growable: false); | |
final ValueNotifier<Filter> _filterController = | |
ValueNotifier<Filter>(const Filter()); | |
@override | |
void dispose() { | |
_filterController.dispose(); | |
super.dispose(); | |
} | |
/// Open filter dialog | |
Future<void> _openFilter(BuildContext context) => showDialog<Filter?>( | |
context: context, | |
builder: (context) => FilterDialog(controller: _filterController), | |
); | |
bool _applyFilter(int data, Filter filter) { | |
if (data.isEven && filter.even) { | |
return true; | |
} else if (data.isOdd && filter.odd) { | |
return true; | |
} | |
return false; | |
} | |
@override | |
Widget build(BuildContext context) => Scaffold( | |
appBar: AppBar( | |
title: const Text('Home Screen'), | |
actions: <Widget>[ | |
// Filter button: | |
CircleAvatar( | |
radius: 20, | |
child: IconButton( | |
onPressed: () => _openFilter(context), | |
icon: const Icon(Icons.filter_list), | |
), | |
), | |
const SizedBox(width: 14), | |
], | |
), | |
// Body content: | |
body: SafeArea( | |
child: ValueListenableBuilder<Filter>( | |
valueListenable: _filterController, | |
builder: (context, filter, _) { | |
final list = _sourceList | |
.where((element) => _applyFilter(element, filter)) | |
.toList(growable: false); | |
return ListView.builder( | |
itemCount: list.length, | |
itemBuilder: (context, index) => ListTile( | |
title: Text( | |
list[index].toString(), | |
), | |
subtitle: Text( | |
list[index].isEven ? 'even' : 'odd', | |
), | |
), | |
); | |
}, | |
), | |
), | |
); | |
} // _HomeScreenState | |
/// Filter result | |
@immutable | |
class Filter { | |
/// Filter result | |
const Filter({ | |
this.even = true, | |
this.odd = true, | |
}); | |
/// Show even numbers | |
final bool even; | |
/// Show odd numbers | |
final bool odd; | |
} | |
/// {@template filter_dialog} | |
/// FilterDialog widget | |
/// {@endtemplate} | |
class FilterDialog extends StatefulWidget { | |
/// {@macro filter_dialog} | |
const FilterDialog({ | |
required this.controller, | |
Key? key, | |
}) : super(key: key); | |
final ValueNotifier<Filter> controller; | |
@override | |
State<FilterDialog> createState() => _FilterDialogState(); | |
} // FilterDialog | |
/// State for widget FilterDialog | |
class _FilterDialogState extends State<FilterDialog> { | |
bool _even = true; | |
bool _odd = true; | |
@override | |
void initState() { | |
super.initState(); | |
_even = widget.controller.value.even; | |
_odd = widget.controller.value.odd; | |
} | |
void _cancel(BuildContext context) => Navigator.pop(context, null); | |
void _accept(BuildContext context) { | |
widget.controller.value = Filter(even: _even, odd: _odd); | |
Navigator.pop(context, null); | |
} | |
@override | |
Widget build(BuildContext context) => SimpleDialog( | |
title: const Text('Filter dialog'), | |
children: <Widget>[ | |
StatefulBuilder( | |
builder: (context, setState) => CheckboxListTile( | |
title: const Text('Even'), | |
value: _even, | |
onChanged: (value) => setState( | |
() => _even = value ?? false, | |
), | |
), | |
), | |
StatefulBuilder( | |
builder: (context, setState) => CheckboxListTile( | |
title: const Text('Odd'), | |
value: _odd, | |
onChanged: (value) => setState( | |
() => _odd = value ?? false, | |
), | |
), | |
), | |
Row( | |
mainAxisSize: MainAxisSize.max, | |
mainAxisAlignment: MainAxisAlignment.spaceEvenly, | |
crossAxisAlignment: CrossAxisAlignment.center, | |
children: <Widget>[ | |
OutlinedButton( | |
onPressed: () => _cancel(context), | |
child: const Text('Cancel'), | |
), | |
ElevatedButton( | |
onPressed: () => _accept(context), | |
child: const Text('Accept'), | |
), | |
], | |
) | |
], | |
); | |
} // _FilterDialogState |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment