전역 구조 리팩터링 및 테스트 확장

This commit is contained in:
JiWoong Sul
2025-09-29 01:51:47 +09:00
parent c00c0c9ab2
commit fef7108479
70 changed files with 7709 additions and 3185 deletions

View File

@@ -1,3 +1,5 @@
import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:shadcn_ui/shadcn_ui.dart';
@@ -5,54 +7,107 @@ import 'package:shadcn_ui/shadcn_ui.dart';
class SuperportTable extends StatelessWidget {
const SuperportTable({
super.key,
required this.columns,
required this.rows,
required List<Widget> columns,
required List<List<Widget>> rows,
this.columnSpanExtent,
this.rowHeight = 56,
this.maxHeight,
this.onRowTap,
this.emptyLabel = '데이터가 없습니다.',
});
}) : _columns = columns,
_rows = rows,
_headerCells = null,
_rowCells = null;
final List<Widget> columns;
final List<List<Widget>> rows;
const SuperportTable.fromCells({
super.key,
required List<ShadTableCell> header,
required List<List<ShadTableCell>> rows,
this.columnSpanExtent,
this.rowHeight = 56,
this.maxHeight,
this.onRowTap,
this.emptyLabel = '데이터가 없습니다.',
}) : _columns = null,
_rows = null,
_headerCells = header,
_rowCells = rows;
final List<Widget>? _columns;
final List<List<Widget>>? _rows;
final List<ShadTableCell>? _headerCells;
final List<List<ShadTableCell>>? _rowCells;
final TableSpanExtent? Function(int index)? columnSpanExtent;
final double rowHeight;
final double? maxHeight;
final void Function(int index)? onRowTap;
final String emptyLabel;
@override
Widget build(BuildContext context) {
if (rows.isEmpty) {
final theme = ShadTheme.of(context);
return Padding(
padding: const EdgeInsets.all(32),
child: Center(
child: Text(emptyLabel, style: theme.textTheme.muted),
),
);
}
late final List<ShadTableCell> headerCells;
late final List<List<ShadTableCell>> tableRows;
final tableRows = [
for (final row in rows)
row
.map(
(cell) => cell is ShadTableCell ? cell : ShadTableCell(child: cell),
)
.toList(),
];
return ShadTable.list(
header: columns
if (_rowCells case final rows?) {
if (rows.isEmpty) {
final theme = ShadTheme.of(context);
return Padding(
padding: const EdgeInsets.all(32),
child: Center(child: Text(emptyLabel, style: theme.textTheme.muted)),
);
}
final header = _headerCells;
if (header == null) {
throw StateError('header cells must not be null when using fromCells');
}
headerCells = header;
tableRows = rows;
} else {
final rows = _rows;
if (rows == null || rows.isEmpty) {
final theme = ShadTheme.of(context);
return Padding(
padding: const EdgeInsets.all(32),
child: Center(child: Text(emptyLabel, style: theme.textTheme.muted)),
);
}
headerCells = _columns!
.map(
(cell) => cell is ShadTableCell
? cell
: ShadTableCell.header(child: cell),
)
.toList(),
columnSpanExtent: columnSpanExtent,
rowSpanExtent: (_) => FixedTableSpanExtent(rowHeight),
onRowTap: onRowTap,
children: tableRows,
.toList();
tableRows = [
for (final row in rows)
row
.map(
(cell) =>
cell is ShadTableCell ? cell : ShadTableCell(child: cell),
)
.toList(),
];
}
final estimatedHeight = (tableRows.length + 1) * rowHeight;
final minHeight = rowHeight * 2;
final effectiveHeight = math.max(
minHeight,
maxHeight == null
? estimatedHeight
: math.min(estimatedHeight, maxHeight!),
);
return SizedBox(
height: effectiveHeight,
child: ShadTable.list(
header: headerCells,
columnSpanExtent: columnSpanExtent,
rowSpanExtent: (_) => FixedTableSpanExtent(rowHeight),
onRowTap: onRowTap,
primary: false,
children: tableRows,
),
);
}
}