marco.pms.mobileapp/lib/model/my_paginated_table.dart

180 lines
5.5 KiB
Dart

import 'package:flutter/material.dart';
import 'package:marco/helpers/widgets/my_spacing.dart';
import 'package:marco/helpers/widgets/my_text.dart';
import 'package:marco/helpers/widgets/my_container.dart';
class MyPaginatedTable extends StatefulWidget {
final String? title;
final List<DataColumn> columns;
final List<DataRow> rows;
final double columnSpacing;
final double horizontalMargin;
const MyPaginatedTable({
super.key,
this.title,
required this.columns,
required this.rows,
this.columnSpacing = 23,
this.horizontalMargin = 35,
});
@override
_MyPaginatedTableState createState() => _MyPaginatedTableState();
}
class _MyPaginatedTableState extends State<MyPaginatedTable> {
int _start = 0;
int _rowsPerPage = 10;
@override
Widget build(BuildContext context) {
final visibleRows = widget.rows.skip(_start).take(_rowsPerPage).toList();
final totalRows = widget.rows.length;
final totalPages = (totalRows / _rowsPerPage).ceil();
final currentPage = (_start / _rowsPerPage).ceil() + 1;
return Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
if (widget.title != null)
Padding(
padding: MySpacing.xy(8, 6), // Using standard spacing for title
child: MyText.titleMedium(widget.title!, fontWeight: 600, fontSize: 20),
),
if (widget.rows.isEmpty)
Padding(
padding: MySpacing.all(16), // Standard padding for empty state
child: MyText.bodySmall('No data available'),
),
if (widget.rows.isNotEmpty)
LayoutBuilder(
builder: (context, constraints) {
final spacing = _calculateSmartSpacing(constraints.maxWidth);
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: MyContainer.bordered(
borderColor: Colors.black.withAlpha(40),
padding: EdgeInsets.zero,
child: DataTable(
columns: widget.columns,
rows: visibleRows,
columnSpacing: spacing,
horizontalMargin: widget.horizontalMargin,
),
),
);
},
),
MySpacing.height(8), // Standard height spacing after table
PaginatedFooter(
currentPage: currentPage,
totalPages: totalPages,
onPrevious: () {
setState(() {
_start = (_start - _rowsPerPage).clamp(0, totalRows - _rowsPerPage);
});
},
onNext: () {
setState(() {
_start = (_start + _rowsPerPage).clamp(0, totalRows - _rowsPerPage);
});
},
onPageSizeChanged: (newRowsPerPage) {
setState(() {
_rowsPerPage = newRowsPerPage;
_start = 0;
});
},
),
],
);
}
double _calculateSmartSpacing(double maxWidth) {
int columnCount = widget.columns.length;
double horizontalPadding = widget.horizontalMargin * 2;
double availableWidth = maxWidth - horizontalPadding;
// Desired min/max column spacing
const double minSpacing = 16;
const double maxSpacing = 80;
// Total width assuming minimal spacing
double minTotalWidth = (columnCount * minSpacing) + horizontalPadding;
if (minTotalWidth >= availableWidth) {
// Not enough room — return minimal spacing
return minSpacing;
}
// Fit evenly within the available width
double spacing = (availableWidth / columnCount) - 40; // 40 for estimated cell content width
return spacing.clamp(minSpacing, maxSpacing);
}
}
class PaginatedFooter extends StatelessWidget {
final int currentPage;
final int totalPages;
final VoidCallback onPrevious;
final VoidCallback onNext;
final Function(int) onPageSizeChanged;
const PaginatedFooter({
required this.currentPage,
required this.totalPages,
required this.onPrevious,
required this.onNext,
required this.onPageSizeChanged,
});
@override
Widget build(BuildContext context) {
return Padding(
padding: MySpacing.x(16), // Standard horizontal spacing for footer
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
if (currentPage > 1)
IconButton(
onPressed: onPrevious,
icon: Icon(Icons.chevron_left),
),
Text(
'Page $currentPage of $totalPages',
style: TextStyle(
fontSize: 16,
color: Theme.of(context).colorScheme.onBackground,
),
),
SizedBox(width: 8),
if (currentPage < totalPages)
IconButton(
onPressed: onNext,
icon: Icon(Icons.chevron_right),
),
SizedBox(width: 16),
PopupMenuButton<int>(
icon: Icon(Icons.more_vert),
onSelected: (value) {
onPageSizeChanged(value);
},
itemBuilder: (BuildContext context) {
return [5, 10, 20, 50].map((e) {
return PopupMenuItem<int>(
value: e,
child: Text('$e rows per page'),
);
}).toList();
},
),
],
),
),
);
}
}