1// Copyright 2016 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5import 'package:flutter/material.dart'; 6import 'package:flutter/rendering.dart'; 7 8import '../../gallery/demo.dart'; 9 10class Dessert { 11 Dessert(this.name, this.calories, this.fat, this.carbs, this.protein, this.sodium, this.calcium, this.iron); 12 final String name; 13 final int calories; 14 final double fat; 15 final int carbs; 16 final double protein; 17 final int sodium; 18 final int calcium; 19 final int iron; 20 21 bool selected = false; 22} 23 24class DessertDataSource extends DataTableSource { 25 final List<Dessert> _desserts = <Dessert>[ 26 Dessert('Frozen yogurt', 159, 6.0, 24, 4.0, 87, 14, 1), 27 Dessert('Ice cream sandwich', 237, 9.0, 37, 4.3, 129, 8, 1), 28 Dessert('Eclair', 262, 16.0, 24, 6.0, 337, 6, 7), 29 Dessert('Cupcake', 305, 3.7, 67, 4.3, 413, 3, 8), 30 Dessert('Gingerbread', 356, 16.0, 49, 3.9, 327, 7, 16), 31 Dessert('Jelly bean', 375, 0.0, 94, 0.0, 50, 0, 0), 32 Dessert('Lollipop', 392, 0.2, 98, 0.0, 38, 0, 2), 33 Dessert('Honeycomb', 408, 3.2, 87, 6.5, 562, 0, 45), 34 Dessert('Donut', 452, 25.0, 51, 4.9, 326, 2, 22), 35 Dessert('KitKat', 518, 26.0, 65, 7.0, 54, 12, 6), 36 37 Dessert('Frozen yogurt with sugar', 168, 6.0, 26, 4.0, 87, 14, 1), 38 Dessert('Ice cream sandwich with sugar', 246, 9.0, 39, 4.3, 129, 8, 1), 39 Dessert('Eclair with sugar', 271, 16.0, 26, 6.0, 337, 6, 7), 40 Dessert('Cupcake with sugar', 314, 3.7, 69, 4.3, 413, 3, 8), 41 Dessert('Gingerbread with sugar', 345, 16.0, 51, 3.9, 327, 7, 16), 42 Dessert('Jelly bean with sugar', 364, 0.0, 96, 0.0, 50, 0, 0), 43 Dessert('Lollipop with sugar', 401, 0.2, 100, 0.0, 38, 0, 2), 44 Dessert('Honeycomb with sugar', 417, 3.2, 89, 6.5, 562, 0, 45), 45 Dessert('Donut with sugar', 461, 25.0, 53, 4.9, 326, 2, 22), 46 Dessert('KitKat with sugar', 527, 26.0, 67, 7.0, 54, 12, 6), 47 48 Dessert('Frozen yogurt with honey', 223, 6.0, 36, 4.0, 87, 14, 1), 49 Dessert('Ice cream sandwich with honey', 301, 9.0, 49, 4.3, 129, 8, 1), 50 Dessert('Eclair with honey', 326, 16.0, 36, 6.0, 337, 6, 7), 51 Dessert('Cupcake with honey', 369, 3.7, 79, 4.3, 413, 3, 8), 52 Dessert('Gingerbread with honey', 420, 16.0, 61, 3.9, 327, 7, 16), 53 Dessert('Jelly bean with honey', 439, 0.0, 106, 0.0, 50, 0, 0), 54 Dessert('Lollipop with honey', 456, 0.2, 110, 0.0, 38, 0, 2), 55 Dessert('Honeycomb with honey', 472, 3.2, 99, 6.5, 562, 0, 45), 56 Dessert('Donut with honey', 516, 25.0, 63, 4.9, 326, 2, 22), 57 Dessert('KitKat with honey', 582, 26.0, 77, 7.0, 54, 12, 6), 58 59 Dessert('Frozen yogurt with milk', 262, 8.4, 36, 12.0, 194, 44, 1), 60 Dessert('Ice cream sandwich with milk', 339, 11.4, 49, 12.3, 236, 38, 1), 61 Dessert('Eclair with milk', 365, 18.4, 36, 14.0, 444, 36, 7), 62 Dessert('Cupcake with milk', 408, 6.1, 79, 12.3, 520, 33, 8), 63 Dessert('Gingerbread with milk', 459, 18.4, 61, 11.9, 434, 37, 16), 64 Dessert('Jelly bean with milk', 478, 2.4, 106, 8.0, 157, 30, 0), 65 Dessert('Lollipop with milk', 495, 2.6, 110, 8.0, 145, 30, 2), 66 Dessert('Honeycomb with milk', 511, 5.6, 99, 14.5, 669, 30, 45), 67 Dessert('Donut with milk', 555, 27.4, 63, 12.9, 433, 32, 22), 68 Dessert('KitKat with milk', 621, 28.4, 77, 15.0, 161, 42, 6), 69 70 Dessert('Coconut slice and frozen yogurt', 318, 21.0, 31, 5.5, 96, 14, 7), 71 Dessert('Coconut slice and ice cream sandwich', 396, 24.0, 44, 5.8, 138, 8, 7), 72 Dessert('Coconut slice and eclair', 421, 31.0, 31, 7.5, 346, 6, 13), 73 Dessert('Coconut slice and cupcake', 464, 18.7, 74, 5.8, 422, 3, 14), 74 Dessert('Coconut slice and gingerbread', 515, 31.0, 56, 5.4, 316, 7, 22), 75 Dessert('Coconut slice and jelly bean', 534, 15.0, 101, 1.5, 59, 0, 6), 76 Dessert('Coconut slice and lollipop', 551, 15.2, 105, 1.5, 47, 0, 8), 77 Dessert('Coconut slice and honeycomb', 567, 18.2, 94, 8.0, 571, 0, 51), 78 Dessert('Coconut slice and donut', 611, 40.0, 58, 6.4, 335, 2, 28), 79 Dessert('Coconut slice and KitKat', 677, 41.0, 72, 8.5, 63, 12, 12), 80 ]; 81 82 void _sort<T>(Comparable<T> getField(Dessert d), bool ascending) { 83 _desserts.sort((Dessert a, Dessert b) { 84 if (!ascending) { 85 final Dessert c = a; 86 a = b; 87 b = c; 88 } 89 final Comparable<T> aValue = getField(a); 90 final Comparable<T> bValue = getField(b); 91 return Comparable.compare(aValue, bValue); 92 }); 93 notifyListeners(); 94 } 95 96 int _selectedCount = 0; 97 98 @override 99 DataRow getRow(int index) { 100 assert(index >= 0); 101 if (index >= _desserts.length) 102 return null; 103 final Dessert dessert = _desserts[index]; 104 return DataRow.byIndex( 105 index: index, 106 selected: dessert.selected, 107 onSelectChanged: (bool value) { 108 if (dessert.selected != value) { 109 _selectedCount += value ? 1 : -1; 110 assert(_selectedCount >= 0); 111 dessert.selected = value; 112 notifyListeners(); 113 } 114 }, 115 cells: <DataCell>[ 116 DataCell(Text('${dessert.name}')), 117 DataCell(Text('${dessert.calories}')), 118 DataCell(Text('${dessert.fat.toStringAsFixed(1)}')), 119 DataCell(Text('${dessert.carbs}')), 120 DataCell(Text('${dessert.protein.toStringAsFixed(1)}')), 121 DataCell(Text('${dessert.sodium}')), 122 DataCell(Text('${dessert.calcium}%')), 123 DataCell(Text('${dessert.iron}%')), 124 ], 125 ); 126 } 127 128 @override 129 int get rowCount => _desserts.length; 130 131 @override 132 bool get isRowCountApproximate => false; 133 134 @override 135 int get selectedRowCount => _selectedCount; 136 137 void _selectAll(bool checked) { 138 for (Dessert dessert in _desserts) 139 dessert.selected = checked; 140 _selectedCount = checked ? _desserts.length : 0; 141 notifyListeners(); 142 } 143} 144 145class DataTableDemo extends StatefulWidget { 146 static const String routeName = '/material/data-table'; 147 148 @override 149 _DataTableDemoState createState() => _DataTableDemoState(); 150} 151 152class _DataTableDemoState extends State<DataTableDemo> { 153 int _rowsPerPage = PaginatedDataTable.defaultRowsPerPage; 154 int _sortColumnIndex; 155 bool _sortAscending = true; 156 final DessertDataSource _dessertsDataSource = DessertDataSource(); 157 158 void _sort<T>(Comparable<T> getField(Dessert d), int columnIndex, bool ascending) { 159 _dessertsDataSource._sort<T>(getField, ascending); 160 setState(() { 161 _sortColumnIndex = columnIndex; 162 _sortAscending = ascending; 163 }); 164 } 165 166 @override 167 Widget build(BuildContext context) { 168 return Scaffold( 169 appBar: AppBar( 170 title: const Text('Data tables'), 171 actions: <Widget>[ 172 MaterialDemoDocumentationButton(DataTableDemo.routeName), 173 ], 174 ), 175 body: Scrollbar( 176 child: ListView( 177 padding: const EdgeInsets.all(20.0), 178 children: <Widget>[ 179 PaginatedDataTable( 180 header: const Text('Nutrition'), 181 rowsPerPage: _rowsPerPage, 182 onRowsPerPageChanged: (int value) { setState(() { _rowsPerPage = value; }); }, 183 sortColumnIndex: _sortColumnIndex, 184 sortAscending: _sortAscending, 185 onSelectAll: _dessertsDataSource._selectAll, 186 columns: <DataColumn>[ 187 DataColumn( 188 label: const Text('Dessert (100g serving)'), 189 onSort: (int columnIndex, bool ascending) => _sort<String>((Dessert d) => d.name, columnIndex, ascending), 190 ), 191 DataColumn( 192 label: const Text('Calories'), 193 tooltip: 'The total amount of food energy in the given serving size.', 194 numeric: true, 195 onSort: (int columnIndex, bool ascending) => _sort<num>((Dessert d) => d.calories, columnIndex, ascending), 196 ), 197 DataColumn( 198 label: const Text('Fat (g)'), 199 numeric: true, 200 onSort: (int columnIndex, bool ascending) => _sort<num>((Dessert d) => d.fat, columnIndex, ascending), 201 ), 202 DataColumn( 203 label: const Text('Carbs (g)'), 204 numeric: true, 205 onSort: (int columnIndex, bool ascending) => _sort<num>((Dessert d) => d.carbs, columnIndex, ascending), 206 ), 207 DataColumn( 208 label: const Text('Protein (g)'), 209 numeric: true, 210 onSort: (int columnIndex, bool ascending) => _sort<num>((Dessert d) => d.protein, columnIndex, ascending), 211 ), 212 DataColumn( 213 label: const Text('Sodium (mg)'), 214 numeric: true, 215 onSort: (int columnIndex, bool ascending) => _sort<num>((Dessert d) => d.sodium, columnIndex, ascending), 216 ), 217 DataColumn( 218 label: const Text('Calcium (%)'), 219 tooltip: 'The amount of calcium as a percentage of the recommended daily amount.', 220 numeric: true, 221 onSort: (int columnIndex, bool ascending) => _sort<num>((Dessert d) => d.calcium, columnIndex, ascending), 222 ), 223 DataColumn( 224 label: const Text('Iron (%)'), 225 numeric: true, 226 onSort: (int columnIndex, bool ascending) => _sort<num>((Dessert d) => d.iron, columnIndex, ascending), 227 ), 228 ], 229 source: _dessertsDataSource, 230 ), 231 ], 232 ), 233 ), 234 ); 235 } 236} 237