From ae1b5bb63a2794a6866d88d79ef99710ebf8e7fe Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Sun, 14 Nov 2021 01:23:55 +0200 Subject: [PATCH] Add scrollbars to tables --- .../app/tables/app_paginated_data_table.dart | 42 +++-- lib/ui/app/tables/entity_list.dart | 149 ++++++++++-------- 2 files changed, 107 insertions(+), 84 deletions(-) diff --git a/lib/ui/app/tables/app_paginated_data_table.dart b/lib/ui/app/tables/app_paginated_data_table.dart index 6dc40c4bf..c766dbc5c 100644 --- a/lib/ui/app/tables/app_paginated_data_table.dart +++ b/lib/ui/app/tables/app_paginated_data_table.dart @@ -8,6 +8,7 @@ import 'package:flutter/material.dart' hide DataRow, DataCell, DataColumn; import 'package:flutter/widgets.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/gestures.dart' show DragStartBehavior; +import 'package:invoiceninja_flutter/ui/app/app_scrollbar.dart'; import 'package:invoiceninja_flutter/ui/app/tables/app_data_table.dart'; import 'package:invoiceninja_flutter/ui/app/tables/app_data_table_source.dart'; @@ -223,11 +224,13 @@ class AppPaginatedDataTableState extends State { int _firstRowIndex; int _rowCount; bool _rowCountApproximate; + ScrollController _controller; final Map _rows = {}; @override void initState() { super.initState(); + _controller = ScrollController(); _firstRowIndex = PageStorage.of(context)?.readState(context) as int ?? widget.initialFirstRowIndex ?? 0; @@ -247,6 +250,7 @@ class AppPaginatedDataTableState extends State { @override void dispose() { + _controller.dispose(); widget.source.removeListener(_handleDataSourceChanged); super.dispose(); } @@ -470,23 +474,27 @@ class AppPaginatedDataTableState extends State { ), ), */ - SingleChildScrollView( - scrollDirection: Axis.horizontal, - dragStartBehavior: widget.dragStartBehavior, - child: ConstrainedBox( - constraints: BoxConstraints(minWidth: constraints.minWidth), - child: AppDataTable( - key: _tableKey, - columns: widget.columns, - sortColumnIndex: widget.sortColumnIndex, - sortAscending: widget.sortAscending, - onSelectAll: widget.onSelectAll, - dataRowHeight: widget.dataRowHeight, - headingRowHeight: widget.headingRowHeight, - horizontalMargin: widget.horizontalMargin, - columnSpacing: widget.columnSpacing, - showCheckboxColumn: widget.showCheckboxColumn, - rows: _getRows(_firstRowIndex, widget.rowsPerPage), + Scrollbar( + controller: _controller, + child: SingleChildScrollView( + controller: _controller, + scrollDirection: Axis.horizontal, + dragStartBehavior: widget.dragStartBehavior, + child: ConstrainedBox( + constraints: BoxConstraints(minWidth: constraints.minWidth), + child: AppDataTable( + key: _tableKey, + columns: widget.columns, + sortColumnIndex: widget.sortColumnIndex, + sortAscending: widget.sortAscending, + onSelectAll: widget.onSelectAll, + dataRowHeight: widget.dataRowHeight, + headingRowHeight: widget.headingRowHeight, + horizontalMargin: widget.horizontalMargin, + columnSpacing: widget.columnSpacing, + showCheckboxColumn: widget.showCheckboxColumn, + rows: _getRows(_firstRowIndex, widget.rowsPerPage), + ), ), ), ), diff --git a/lib/ui/app/tables/entity_list.dart b/lib/ui/app/tables/entity_list.dart index 6c3e3550d..5a677cba2 100644 --- a/lib/ui/app/tables/entity_list.dart +++ b/lib/ui/app/tables/entity_list.dart @@ -10,6 +10,7 @@ import 'package:invoiceninja_flutter/redux/app/app_actions.dart'; import 'package:invoiceninja_flutter/redux/app/app_state.dart'; import 'package:invoiceninja_flutter/redux/ui/pref_state.dart'; import 'package:invoiceninja_flutter/ui/app/app_border.dart'; +import 'package:invoiceninja_flutter/ui/app/app_scrollbar.dart'; import 'package:invoiceninja_flutter/ui/app/entities/entity_actions_dialog.dart'; import 'package:invoiceninja_flutter/ui/app/forms/save_cancel_buttons.dart'; import 'package:invoiceninja_flutter/ui/app/help_text.dart'; @@ -60,11 +61,14 @@ class _EntityListState extends State { EntityDataTableSource dataTableSource; int _firstRowIndex = 0; + ScrollController _controller; @override void initState() { super.initState(); + _controller = ScrollController(); + final entityType = widget.entityType; final state = widget.state; final entityList = widget.entityList; @@ -107,6 +111,12 @@ class _EntityListState extends State { dataTableSource.notifyListeners(); } + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { final store = StoreProvider.of(context); @@ -229,74 +239,79 @@ class _EntityListState extends State { }, ), Expanded( - child: SingleChildScrollView( - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 16), - child: AppPaginatedDataTable( - onSelectAll: (value) { - final startIndex = - min(_firstRowIndex, entityList.length - 1); - final endIndex = - min(_firstRowIndex + rowsPerPage, entityList.length); - final entities = entityList - .sublist(startIndex, endIndex) - .map( - (String entityId) => entityMap[entityId]) - .where((invoice) => - value != listUIState.isSelected(invoice.id)) - .toList(); - handleEntitiesActions( - entities, EntityAction.toggleMultiselect); - }, - columns: [ - if (!isInMultiselect) DataColumn(label: SizedBox()), - ...widget.tableColumns.map((field) { - String label = - AppLocalization.of(context).lookup(field); - if (field.startsWith('custom')) { - final key = field.replaceFirst( - 'custom', entityType.snakeCase); - label = state.company.getCustomFieldLabel(key); - } - var maxWidth = kTableColumnWidthMax; - var minWidth = kTableColumnWidthMin; - if (field == ProductFields.description) { - maxWidth *= 5; - minWidth *= 5; - } - return DataColumn( - label: Container( - constraints: BoxConstraints( - minWidth: minWidth, - maxWidth: maxWidth, + child: AppScrollbar( + controller: _controller, + child: SingleChildScrollView( + controller: _controller, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 16), + child: AppPaginatedDataTable( + onSelectAll: (value) { + final startIndex = + min(_firstRowIndex, entityList.length - 1); + final endIndex = min( + _firstRowIndex + rowsPerPage, entityList.length); + final entities = entityList + .sublist(startIndex, endIndex) + .map( + (String entityId) => entityMap[entityId]) + .where((invoice) => + value != listUIState.isSelected(invoice.id)) + .toList(); + handleEntitiesActions( + entities, EntityAction.toggleMultiselect); + }, + columns: [ + if (!isInMultiselect) DataColumn(label: SizedBox()), + ...widget.tableColumns.map((field) { + String label = + AppLocalization.of(context).lookup(field); + if (field.startsWith('custom')) { + final key = field.replaceFirst( + 'custom', entityType.snakeCase); + label = state.company.getCustomFieldLabel(key); + } + var maxWidth = kTableColumnWidthMax; + var minWidth = kTableColumnWidthMin; + if (field == ProductFields.description) { + maxWidth *= 5; + minWidth *= 5; + } + return DataColumn( + label: Container( + constraints: BoxConstraints( + minWidth: minWidth, + maxWidth: maxWidth, + ), + child: Text( + label, + overflow: TextOverflow.ellipsis, + ), ), - child: Text( - label, - overflow: TextOverflow.ellipsis, - ), - ), - onSort: (int columnIndex, bool ascending) { - widget.onSortColumn(field); - }); - }), - ], - source: dataTableSource, - sortColumnIndex: - widget.tableColumns.contains(listUIState.sortField) - ? widget.tableColumns.indexOf(listUIState.sortField) - : 0, - sortAscending: listUIState.sortAscending, - rowsPerPage: state.prefState.rowsPerPage, - onPageChanged: (row) => _firstRowIndex = row, - initialFirstRowIndex: _firstRowIndex, - availableRowsPerPage: [ - 10, - 25, - 50, - ], - onRowsPerPageChanged: (value) { - store.dispatch(UpdateUserPreferences(rowsPerPage: value)); - }, + onSort: (int columnIndex, bool ascending) { + widget.onSortColumn(field); + }); + }), + ], + source: dataTableSource, + sortColumnIndex: widget.tableColumns + .contains(listUIState.sortField) + ? widget.tableColumns.indexOf(listUIState.sortField) + : 0, + sortAscending: listUIState.sortAscending, + rowsPerPage: state.prefState.rowsPerPage, + onPageChanged: (row) => _firstRowIndex = row, + initialFirstRowIndex: _firstRowIndex, + availableRowsPerPage: [ + 10, + 25, + 50, + ], + onRowsPerPageChanged: (value) { + store.dispatch( + UpdateUserPreferences(rowsPerPage: value)); + }, + ), ), ), ),