Skip to content

Commit

Permalink
Merge pull request #3 from tomasweigenast/footer-remove-btn
Browse files Browse the repository at this point in the history
add option to remove footer bar and improve docs
  • Loading branch information
tomasweigenast authored Jul 22, 2023
2 parents 39caf73 + 0452f21 commit 3f2074c
Show file tree
Hide file tree
Showing 10 changed files with 171 additions and 63 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 1.3.0

- Add option to completely remove the footer.
- Improve `PagedDataTableTheme` documentation.

## 1.2.0

- Upgrade Flutter version
Expand Down
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,13 @@ By using a `PagedDataTableController<TKey, TValue>` (being `TKey` and `TValue` t

## Customization

### Theming

You can configure every `PagedDataTable` widget by providing a `PagedDataTableTheme` to your
widget tree, or configure individual widgets by setting the `theme` property to the `PagedDataTable` you want to configure.

Every property in the `PagedDataTableThemeData` is well documented.

### Custom column

If you want to make a custom column, that is not editable, extend the `BaseTableColumn<TType>` class and render you widget in the `buildCell` method. It gives you the `item` that is going to be displayed and the `index` of the row.
Expand Down
46 changes: 31 additions & 15 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,16 @@ class MyApp extends StatelessWidget {
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorScheme: const ColorScheme.light(primary: Colors.deepPurple, secondary: Colors.teal),
colorScheme: const ColorScheme.light(
primary: Colors.deepPurple, secondary: Colors.teal),
textTheme: GoogleFonts.robotoTextTheme(),
cardTheme: CardTheme(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)),
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)),
),
popupMenuTheme: PopupMenuThemeData(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(30)))),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30)))),
home: const MainView(),
);
}
Expand All @@ -61,7 +64,8 @@ const kCustomPagedDataTableTheme = PagedDataTableThemeData(
headerBackgroundColor: Color(0xFF80CBC4),
filtersHeaderBackgroundColor: Color(0xFF80CBC4),
footerBackgroundColor: Color(0xFF80CBC4),
textStyle: TextStyle(decoration: TextDecoration.underline, fontWeight: FontWeight.normal),
textStyle: TextStyle(
decoration: TextDecoration.underline, fontWeight: FontWeight.normal),
rowsTextStyle: TextStyle(decoration: TextDecoration.overline),
buttonsColor: Colors.white,
chipTheme: ChipThemeData(
Expand Down Expand Up @@ -108,7 +112,8 @@ class _MainViewState extends State<MainView> {
cellBuilder: (item) => Text(item.id.toString()),
sizeFactor: .05,
),
TableColumn(title: "Author", cellBuilder: (item) => Text(item.author)),
TableColumn(
title: "Author", cellBuilder: (item) => Text(item.author)),
LargeTextTableColumn(
title: "Content",
getter: (post) => post.content,
Expand All @@ -122,7 +127,8 @@ class _MainViewState extends State<MainView> {
id: "createdAt",
title: "Created At",
sortable: true,
cellBuilder: (item) => Text(DateFormat.yMd().format(item.createdAt))),
cellBuilder: (item) =>
Text(DateFormat.yMd().format(item.createdAt))),
DropdownTableColumn<Post, Gender>(
title: "Gender",
sizeFactor: null,
Expand All @@ -135,10 +141,13 @@ class _MainViewState extends State<MainView> {
items: const [
DropdownMenuItem(value: Gender.male, child: Text("Male")),
DropdownMenuItem(value: Gender.female, child: Text("Female")),
DropdownMenuItem(value: Gender.unespecified, child: Text("Unspecified")),
DropdownMenuItem(
value: Gender.unespecified, child: Text("Unspecified")),
],
),
TableColumn(title: "Enabled", cellBuilder: (item) => Text(item.isEnabled ? "Yes" : "No")),
TableColumn(
title: "Enabled",
cellBuilder: (item) => Text(item.isEnabled ? "Yes" : "No")),
TextTableColumn(
title: "Number",
id: "number",
Expand All @@ -162,20 +171,26 @@ class _MainViewState extends State<MainView> {
return true;
}),
TableColumn(
title: "Fixed Value", cellBuilder: (item) => const Text("abc"), sizeFactor: null),
title: "Fixed Value",
cellBuilder: (item) => const Text("abc"),
sizeFactor: null),
],
filters: [
TextTableFilter(
id: "authorName", title: "Author's name", chipFormatter: (text) => "By $text"),
id: "authorName",
title: "Author's name",
chipFormatter: (text) => "By $text"),
DropdownTableFilter<Gender>(
id: "gender",
title: "Gender",
defaultValue: Gender.male,
chipFormatter: (gender) => 'Only ${gender.name.toLowerCase()} posts',
chipFormatter: (gender) =>
'Only ${gender.name.toLowerCase()} posts',
items: const [
DropdownMenuItem(value: Gender.male, child: Text("Male")),
DropdownMenuItem(value: Gender.female, child: Text("Female")),
DropdownMenuItem(value: Gender.unespecified, child: Text("Unspecified")),
DropdownMenuItem(
value: Gender.unespecified, child: Text("Unspecified")),
]),
DatePickerTableFilter(
id: "date",
Expand Down Expand Up @@ -235,7 +250,8 @@ class _MainViewState extends State<MainView> {
var selectedPosts = tableController.getSelectedRows();
debugPrint("SELECTED ROWS ----------------------------");
debugPrint(selectedPosts
.map((e) => "Id [${e.id}] Author [${e.author}] Gender [${e.authorGender.name}]")
.map((e) =>
"Id [${e.id}] Author [${e.author}] Gender [${e.authorGender.name}]")
.join("\n"));
debugPrint("------------------------------------------");
}),
Expand All @@ -247,8 +263,8 @@ class _MainViewState extends State<MainView> {
FilterMenuItem(
title: const Text("Select random row"),
onTap: () {
tableController
.selectRow(Random(DateTime.now().microsecondsSinceEpoch).nextInt(10));
tableController.selectRow(
Random(DateTime.now().microsecondsSinceEpoch).nextInt(10));
}),
const FilterMenuDivider(),
FilterMenuItem(
Expand Down
2 changes: 1 addition & 1 deletion example/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ packages:
path: ".."
relative: true
source: path
version: "1.2.0"
version: "1.3.0"
path:
dependency: transitive
description:
Expand Down
15 changes: 10 additions & 5 deletions lib/src/controls.dart
Original file line number Diff line number Diff line change
Expand Up @@ -118,12 +118,14 @@ class _DateTimeRangePicker extends HookWidget {
);
}

String _format(DateFormat dateFormat, ObjectRef<DateTimeRange?> currentValueRef) {
String _format(
DateFormat dateFormat, ObjectRef<DateTimeRange?> currentValueRef) {
return "${dateFormat.format(currentValueRef.value!.start)} - ${dateFormat.format(currentValueRef.value!.end)}";
}
}

class _DropdownButtonCell<TType extends Object, T extends Object> extends HookWidget {
class _DropdownButtonCell<TType extends Object, T extends Object>
extends HookWidget {
final T? initialValue;
final List<DropdownMenuItem<T>> items;
final InputDecoration? decoration;
Expand Down Expand Up @@ -151,7 +153,8 @@ class _DropdownButtonCell<TType extends Object, T extends Object> extends HookWi
child: DropdownButtonFormField<T>(
focusNode: focusNode,
items: items,
decoration: decoration ?? const InputDecoration(border: InputBorder.none),
decoration:
decoration ?? const InputDecoration(border: InputBorder.none),
value: currentValueRef.value,
onChanged: isLoadingN.value
? null
Expand Down Expand Up @@ -343,8 +346,10 @@ class _EditableTextField extends HookWidget {
message: currentValueRef.value,
margin: tooltipMargin,
padding: tooltipPadding,
child: Text(currentValueRef.value, overflow: TextOverflow.ellipsis))
: Text(currentValueRef.value, overflow: TextOverflow.ellipsis)));
child: Text(currentValueRef.value,
overflow: TextOverflow.ellipsis))
: Text(currentValueRef.value,
overflow: TextOverflow.ellipsis)));
}
}

Expand Down
32 changes: 23 additions & 9 deletions lib/src/paged_datatable.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ part 'types.dart';
/// A paginated DataTable that allows page caching and filtering
/// [TKey] is the type of the page token
/// [TResult] is the type of data the data table will show.
class PagedDataTable<TKey extends Object, TResult extends Object> extends StatelessWidget {
class PagedDataTable<TKey extends Object, TResult extends Object>
extends StatelessWidget {
final FetchCallback<TKey, TResult> fetchPage;
final TKey initialPage;
final List<TableFilter>? filters;
Expand Down Expand Up @@ -75,8 +76,9 @@ class PagedDataTable<TKey extends Object, TResult extends Object> extends Statel
refreshListener: refreshListener),
builder: (context, widget) {
var state = context.read<_PagedDataTableState<TKey, TResult>>();
final localTheme =
PagedDataTableTheme.maybeOf(context) ?? theme ?? _kDefaultPagedDataTableTheme;
final localTheme = PagedDataTableTheme.maybeOf(context) ??
theme ??
_kDefaultPagedDataTableTheme;

Widget child = Material(
color: localTheme.backgroundColor,
Expand All @@ -89,7 +91,9 @@ class PagedDataTable<TKey extends Object, TResult extends Object> extends Statel
return Column(
children: [
/* FILTER TAB */
if (header != null || menu != null || state.filters.isNotEmpty) ...[
if (header != null ||
menu != null ||
state.filters.isNotEmpty) ...[
_PagedDataTableFilterTab<TKey, TResult>(menu, header),
Divider(height: 0, color: localTheme.dividerColor),
],
Expand All @@ -101,12 +105,18 @@ class PagedDataTable<TKey extends Object, TResult extends Object> extends Statel
/* ITEMS */
Expanded(
child: _PagedDataTableRows<TKey, TResult>(
rowsSelectable, customRowBuilder, noItemsFoundBuilder, errorBuilder, width),
rowsSelectable,
customRowBuilder,
noItemsFoundBuilder,
errorBuilder,
width),
),

/* FOOTER */
Divider(height: 0, color: localTheme.dividerColor),
_PagedDataTableFooter<TKey, TResult>(footer)
if (theme?.configuration.footer.visible ?? true) ...[
Divider(height: 0, color: localTheme.dividerColor),
_PagedDataTableFooter<TKey, TResult>(footer)
]
],
);
}),
Expand All @@ -115,10 +125,14 @@ class PagedDataTable<TKey extends Object, TResult extends Object> extends Statel
// apply configuration to this widget only
if (theme != null) {
child = PagedDataTableTheme(data: theme!, child: child);
assert(theme!.rowColors != null ? theme!.rowColors!.length == 2 : true,
assert(
theme!.rowColors != null ? theme!.rowColors!.length == 2 : true,
"rowColors must contain exactly two colors");
} else {
assert(localTheme.rowColors != null ? localTheme.rowColors!.length == 2 : true,
assert(
localTheme.rowColors != null
? localTheme.rowColors!.length == 2
: true,
"rowColors must contain exactly two colors");
}

Expand Down
25 changes: 16 additions & 9 deletions lib/src/paged_datatable_menu.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,12 @@ class _PagedDataTableMenu extends StatelessWidget {
}
}

void _showMenu({required BuildContext context, required List<BaseFilterMenuItem> items}) {
void _showMenu(
{required BuildContext context, required List<BaseFilterMenuItem> items}) {
final RenderBox button = context.findRenderObject() as RenderBox;
var offset = button.localToGlobal(Offset.zero);
var position = RelativeRect.fromLTRB(offset.dx + 10, offset.dy + button.size.height - 10, 0, 0);
var position = RelativeRect.fromLTRB(
offset.dx + 10, offset.dy + button.size.height - 10, 0, 0);

// var rect = RelativeRect.fromLTRB(offset.dx + 10, offset.dy + size.height - 10, 0, 0);

Expand All @@ -45,8 +47,10 @@ void _showMenu({required BuildContext context, required List<BaseFilterMenuItem>
_PopupMenuRoute(
items: items,
position: position,
barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel,
capturedThemes: InheritedTheme.capture(from: context, to: navigator.context)));
barrierLabel:
MaterialLocalizations.of(context).modalBarrierDismissLabel,
capturedThemes:
InheritedTheme.capture(from: context, to: navigator.context)));
}

class _PopupMenuRoute<T> extends PopupRoute<T> {
Expand Down Expand Up @@ -94,8 +98,8 @@ class _PopupMenuRoute<T> extends PopupRoute<T> {
final String barrierLabel;

@override
Widget buildPage(
BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
Widget buildPage(BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation) {
final menu = _PagedDataTableMenu(items: items);
final MediaQueryData mediaQuery = MediaQuery.of(context);
return MediaQuery.removePadding(
Expand Down Expand Up @@ -162,12 +166,14 @@ class _PopupMenuRouteLayout extends SingleChildLayoutDelegate {

if (x < _kMenuScreenPadding + padding.left) {
x = _kMenuScreenPadding + padding.left;
} else if (x + childSize.width > size.width - _kMenuScreenPadding - padding.right) {
} else if (x + childSize.width >
size.width - _kMenuScreenPadding - padding.right) {
x = size.width - childSize.width - _kMenuScreenPadding - padding.right;
}
if (y < _kMenuScreenPadding + padding.top) {
y = _kMenuScreenPadding + padding.top;
} else if (y + childSize.height > size.height - _kMenuScreenPadding - padding.bottom) {
} else if (y + childSize.height >
size.height - _kMenuScreenPadding - padding.bottom) {
y = size.height - padding.bottom - _kMenuScreenPadding - childSize.height;
}

Expand Down Expand Up @@ -201,7 +207,8 @@ class _AutoAnimatedSize extends StatefulWidget {
State<StatefulWidget> createState() => _AutoAnimatedSizeState();
}

class _AutoAnimatedSizeState extends State<_AutoAnimatedSize> with SingleTickerProviderStateMixin {
class _AutoAnimatedSizeState extends State<_AutoAnimatedSize>
with SingleTickerProviderStateMixin {
bool showChild = false;

@override
Expand Down
Loading

0 comments on commit 3f2074c

Please sign in to comment.