Unverified Commit 2f611f14 authored by Per Classon's avatar Per Classon Committed by GitHub

Make header optional in PaginatedDataTable (#69610)

parent 96a78c08
...@@ -37,8 +37,7 @@ import 'theme.dart'; ...@@ -37,8 +37,7 @@ import 'theme.dart';
class PaginatedDataTable extends StatefulWidget { class PaginatedDataTable extends StatefulWidget {
/// Creates a widget describing a paginated [DataTable] on a [Card]. /// Creates a widget describing a paginated [DataTable] on a [Card].
/// ///
/// The [header] should give the card's header, typically a [Text] widget. It /// The [header] should give the card's header, typically a [Text] widget.
/// must not be null.
/// ///
/// The [columns] argument must be a list of as many [DataColumn] objects as /// The [columns] argument must be a list of as many [DataColumn] objects as
/// the table is to have columns, ignoring the leading checkbox column if any. /// the table is to have columns, ignoring the leading checkbox column if any.
...@@ -64,7 +63,7 @@ class PaginatedDataTable extends StatefulWidget { ...@@ -64,7 +63,7 @@ class PaginatedDataTable extends StatefulWidget {
/// both have defaults, though, so don't have to be specified). /// both have defaults, though, so don't have to be specified).
PaginatedDataTable({ PaginatedDataTable({
Key? key, Key? key,
required this.header, this.header,
this.actions, this.actions,
required this.columns, required this.columns,
this.sortColumnIndex, this.sortColumnIndex,
...@@ -82,7 +81,7 @@ class PaginatedDataTable extends StatefulWidget { ...@@ -82,7 +81,7 @@ class PaginatedDataTable extends StatefulWidget {
this.onRowsPerPageChanged, this.onRowsPerPageChanged,
this.dragStartBehavior = DragStartBehavior.start, this.dragStartBehavior = DragStartBehavior.start,
required this.source, required this.source,
}) : assert(header != null), }) : assert(actions == null || (actions != null && header != null)),
assert(columns != null), assert(columns != null),
assert(dragStartBehavior != null), assert(dragStartBehavior != null),
assert(columns.isNotEmpty), assert(columns.isNotEmpty),
...@@ -103,17 +102,19 @@ class PaginatedDataTable extends StatefulWidget { ...@@ -103,17 +102,19 @@ class PaginatedDataTable extends StatefulWidget {
assert(source != null), assert(source != null),
super(key: key); super(key: key);
/// The table card's header. /// The table card's optional header.
/// ///
/// This is typically a [Text] widget, but can also be a [ButtonBar] with /// This is typically a [Text] widget, but can also be a [Row] of
/// [TextButton]s. Suitable defaults are automatically provided for the font, /// [TextButton]s. To show icon buttons at the top end side of the table with
/// button color, button padding, and so forth. /// a header, set the [actions] property.
/// ///
/// If items in the table are selectable, then, when the selection is not /// If items in the table are selectable, then, when the selection is not
/// empty, the header is replaced by a count of the selected items. /// empty, the header is replaced by a count of the selected items. The
final Widget header; /// [actions] are still visible when items are selected.
final Widget? header;
/// Icon buttons to show at the top right of the table. /// Icon buttons to show at the top end side of the table. The [header] must
/// not be null to show the actions.
/// ///
/// Typically, the exact actions included in this list will vary based on /// Typically, the exact actions included in this list will vary based on
/// whether any rows are selected or not. /// whether any rows are selected or not.
...@@ -337,8 +338,8 @@ class PaginatedDataTableState extends State<PaginatedDataTable> { ...@@ -337,8 +338,8 @@ class PaginatedDataTableState extends State<PaginatedDataTable> {
// HEADER // HEADER
final List<Widget> headerWidgets = <Widget>[]; final List<Widget> headerWidgets = <Widget>[];
double startPadding = 24.0; double startPadding = 24.0;
if (_selectedRowCount == 0) { if (_selectedRowCount == 0 && widget.header != null) {
headerWidgets.add(Expanded(child: widget.header)); headerWidgets.add(Expanded(child: widget.header!));
if (widget.header is ButtonBar) { if (widget.header is ButtonBar) {
// We adjust the padding when a button bar is present, because the // We adjust the padding when a button bar is present, because the
// ButtonBar introduces 2 pixels of outside padding, plus 2 pixels // ButtonBar introduces 2 pixels of outside padding, plus 2 pixels
...@@ -347,7 +348,7 @@ class PaginatedDataTableState extends State<PaginatedDataTable> { ...@@ -347,7 +348,7 @@ class PaginatedDataTableState extends State<PaginatedDataTable> {
// inside of the button to line up with the 24.0 left inset. // inside of the button to line up with the 24.0 left inset.
startPadding = 12.0; startPadding = 12.0;
} }
} else { } else if (widget.header != null) {
headerWidgets.add(Expanded( headerWidgets.add(Expanded(
child: Text(localizations.selectedRowCountTitle(_selectedRowCount)), child: Text(localizations.selectedRowCountTitle(_selectedRowCount)),
)); ));
...@@ -432,32 +433,33 @@ class PaginatedDataTableState extends State<PaginatedDataTable> { ...@@ -432,32 +433,33 @@ class PaginatedDataTableState extends State<PaginatedDataTable> {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[ children: <Widget>[
Semantics( if (headerWidgets.isNotEmpty)
container: true, Semantics(
child: DefaultTextStyle( container: true,
// These typographic styles aren't quite the regular ones. We pick the closest ones from the regular child: DefaultTextStyle(
// list and then tweak them appropriately. // These typographic styles aren't quite the regular ones. We pick the closest ones from the regular
// See https://material.io/design/components/data-tables.html#tables-within-cards // list and then tweak them appropriately.
style: _selectedRowCount > 0 ? themeData.textTheme.subtitle1!.copyWith(color: themeData.accentColor) // See https://material.io/design/components/data-tables.html#tables-within-cards
: themeData.textTheme.headline6!.copyWith(fontWeight: FontWeight.w400), style: _selectedRowCount > 0 ? themeData.textTheme.subtitle1!.copyWith(color: themeData.accentColor)
child: IconTheme.merge( : themeData.textTheme.headline6!.copyWith(fontWeight: FontWeight.w400),
data: const IconThemeData( child: IconTheme.merge(
opacity: 0.54 data: const IconThemeData(
), opacity: 0.54
child: Ink( ),
height: 64.0, child: Ink(
color: _selectedRowCount > 0 ? themeData.secondaryHeaderColor : null, height: 64.0,
child: Padding( color: _selectedRowCount > 0 ? themeData.secondaryHeaderColor : null,
padding: EdgeInsetsDirectional.only(start: startPadding, end: 14.0), child: Padding(
child: Row( padding: EdgeInsetsDirectional.only(start: startPadding, end: 14.0),
mainAxisAlignment: MainAxisAlignment.end, child: Row(
children: headerWidgets, mainAxisAlignment: MainAxisAlignment.end,
children: headerWidgets,
),
), ),
), ),
), ),
), ),
), ),
),
SingleChildScrollView( SingleChildScrollView(
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
dragStartBehavior: widget.dragStartBehavior, dragStartBehavior: widget.dragStartBehavior,
......
...@@ -229,6 +229,43 @@ void main() { ...@@ -229,6 +229,43 @@ void main() {
expect(tester.getTopRight(find.text('8')).dx, tester.getTopRight(find.text('Rows per page:')).dx + 40.0); // per spec expect(tester.getTopRight(find.text('8')).dx, tester.getTopRight(find.text('Rows per page:')).dx + 40.0); // per spec
}); });
testWidgets('PaginatedDataTable with and without header and actions', (WidgetTester tester) async {
await binding.setSurfaceSize(const Size(800, 800));
const String headerText = 'HEADER';
final List<Widget> actions = <Widget>[
IconButton(onPressed: () {}, icon: const Icon(Icons.add)),
];
Widget buildTable({String? header, List<Widget>? actions}) => MaterialApp(
home: PaginatedDataTable(
header: header != null ? Text(header) : null,
actions: actions,
source: TestDataSource(onSelectChanged: (bool? value) {}),
showCheckboxColumn: true,
columns: const <DataColumn>[
DataColumn(label: Text('Name')),
DataColumn(label: Text('Calories'), numeric: true),
DataColumn(label: Text('Generation')),
],
),
);
await tester.pumpWidget(buildTable(header: headerText));
expect(find.text(headerText), findsOneWidget);
expect(find.byIcon(Icons.add), findsNothing);
await tester.pumpWidget(buildTable(header: headerText, actions: actions));
expect(find.text(headerText), findsOneWidget);
expect(find.byIcon(Icons.add), findsOneWidget);
await tester.pumpWidget(buildTable());
expect(find.text(headerText), findsNothing);
expect(find.byIcon(Icons.add), findsNothing);
expect(() => buildTable(actions: actions), throwsAssertionError);
await binding.setSurfaceSize(null);
});
testWidgets('PaginatedDataTable with large text', (WidgetTester tester) async { testWidgets('PaginatedDataTable with large text', (WidgetTester tester) async {
final TestDataSource source = TestDataSource(); final TestDataSource source = TestDataSource();
await tester.pumpWidget(MaterialApp( await tester.pumpWidget(MaterialApp(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment