Notification Screen and tasq_adaptive_list enhancements

This commit is contained in:
2026-05-11 11:34:34 +08:00
parent 30b301765b
commit e9d1af867a
8 changed files with 499 additions and 165 deletions
+33 -6
View File
@@ -16,6 +16,7 @@ class TasQColumn<T> {
required this.header,
required this.cellBuilder,
this.technical = false,
this.hideOnMedium = false,
});
/// The column header text.
@@ -26,6 +27,11 @@ class TasQColumn<T> {
/// If true, applies monospace text style to the cell content.
final bool technical;
/// If true, this column is hidden on medium-width screens (< 1200px).
/// Use this for lower-priority columns (e.g. Timestamp, Status) that
/// would otherwise force a horizontal scrollbar on tablet viewports.
final bool hideOnMedium;
}
/// Builds a mobile tile for [TasQAdaptiveList].
@@ -351,6 +357,13 @@ class TasQAdaptiveList<T> extends StatelessWidget {
}
final contentWidth = constraints.maxWidth * contentFactor;
// On medium screens (< 1200px) hide columns that are marked hideOnMedium,
// preventing the horizontal scrollbar from appearing on tablet viewports.
final isMediumScreen = constraints.maxWidth < 1200;
final visibleColumns = isMediumScreen
? columns.where((c) => !c.hideOnMedium).toList()
: columns;
// Table width: mirrors PaginatedDataTable's own internal layout so the
// horizontal scrollbar appears exactly when columns would otherwise be
// squeezed below their minimum comfortable width.
@@ -362,10 +375,10 @@ class TasQAdaptiveList<T> extends StatelessWidget {
const double hMarginTotal = 16.0 * 2;
const double colSpacing = 20.0;
final actionsColumnCount = rowActions == null ? 0 : 1;
final totalCols = columns.length + actionsColumnCount;
final totalCols = visibleColumns.length + actionsColumnCount;
final minColumnsWidth =
hMarginTotal +
(columns.length * colMinW) +
(visibleColumns.length * colMinW) +
(actionsColumnCount * actMinW) +
(math.max(0, totalCols - 1) * colSpacing);
final tableWidth = math.max(contentWidth, minColumnsWidth);
@@ -388,7 +401,7 @@ class TasQAdaptiveList<T> extends StatelessWidget {
return _DesktopTableView<T>(
items: items,
columns: columns,
columns: visibleColumns,
rowActions: rowActions,
onRowTap: onRowTap,
maxRowsPerPage: rowsPerPage,
@@ -472,6 +485,11 @@ class _DesktopTableViewState<T> extends State<_DesktopTableView<T>> {
const double colHeaderH = 56.0;
const double footerH = 56.0;
const double defaultRowH = 48.0;
// Comfortable height used when the table is sparse (fewer items than the
// viewport can hold). Prevents 2 rows from each stretching to ~290px.
const double comfortableRowH = 52.0;
// Cap applied even when the table is full, so rows never become unwieldy.
const double maxRowH = 72.0;
const double cardPad = 8.0;
final double headerH = widget.tableHeader != null ? 64.0 : 0.0;
@@ -488,9 +506,18 @@ class _DesktopTableViewState<T> extends State<_DesktopTableView<T>> {
math.min(widget.maxRowsPerPage, itemCount),
);
// Expand each row to fill the leftover space so the table reaches
// exactly the bottom of the Expanded widget — no empty space.
final rowHeight = math.max(defaultRowH, availableForRows / rows);
// Only expand rows to fill leftover space when the table is "full"
// (items reach the viewport limit). Sparse tables use a comfortable fixed
// height instead — dividing 580px by 2 items would yield ~290px each.
//
// For full tables we must use exactFit (availableForRows / rows) so that
// rows × rowH == availableForRows exactly. Applying comfortableRowH as a
// lower-bound here caused overflow: e.g. 9 rows × 52px = 468px when only
// 444px was available → "BOTTOM OVERFLOWED BY 16 PIXELS".
final isTableFull = rows >= maxFitting;
final rowHeight = isTableFull
? math.min(maxRowH, availableForRows / rows)
: comfortableRowH;
return (rows, rowHeight);
}