Skip to content

Commit

Permalink
Version 3.1.0.
Browse files Browse the repository at this point in the history
  • Loading branch information
edufolly committed May 8, 2024
1 parent 8079b5d commit bdcd434
Show file tree
Hide file tree
Showing 8 changed files with 158 additions and 108 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## [3.1.0] - 2024-05-08

* Updating TableField.
* Renaming HeaderCell to HeaderText.
* Adding new properties to TableIconButton.

## [3.0.2] - 2024-04-11

* Adding leadingWidth to AbstractEdit and AbstractList.
Expand Down
4 changes: 2 additions & 2 deletions example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ description: A new Flutter project.

publish_to: 'none'

version: 3.0.2+211
version: 3.1.0+212

environment:
sdk: ">=3.3.0 <4.0.0"
flutter: ">=3.19.0"

dependencies:
# https://pub.dev/packages/connectivity_plus
connectivity_plus: 6.0.2
connectivity_plus: 6.0.3

flutter:
sdk: flutter
Expand Down
1 change: 0 additions & 1 deletion lib/fields/list_field.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import 'package:sprintf/sprintf.dart';
///
///
///
// TODO(edufolly): Create controller?
class ListField<
T extends AbstractModel<ID>,
B extends AbstractBuilder<T, ID>,
Expand Down
167 changes: 101 additions & 66 deletions lib/fields/table_field.dart
Original file line number Diff line number Diff line change
@@ -1,51 +1,48 @@
import 'package:flutter/material.dart';
import 'package:folly_fields/crud/abstract_builder.dart';
import 'package:folly_fields/crud/abstract_consumer.dart';
import 'package:folly_fields/crud/abstract_model.dart';
import 'package:folly_fields/responsive/responsive.dart';
import 'package:folly_fields/responsive/responsive_builder.dart';
import 'package:folly_fields/responsive/responsive_form_field.dart';
import 'package:folly_fields/responsive/responsive_grid.dart';
import 'package:folly_fields/widgets/empty_button.dart';
import 'package:folly_fields/widgets/field_group.dart';
import 'package:folly_fields/widgets/folly_divider.dart';
import 'package:folly_fields/widgets/header_cell.dart';
import 'package:folly_fields/widgets/table_button.dart';
import 'package:folly_fields/widgets/table_icon_button.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:sprintf/sprintf.dart';

///
///
///
// TODO(edufolly): Test layout with DataTable.
// TODO(edufolly): Customize messages.
// TODO(edufolly): Create controller??
class TableField<T extends AbstractModel<ID>, ID>
extends ResponsiveFormField<List<T>> {
class TableField<T> extends ResponsiveFormField<List<T>> {
///
///
///
TableField({
required List<T> super.initialValue,
required AbstractBuilder<T, ID> builder,
required AbstractConsumer<T, ID> consumer,
required String plural,
required String single,
required T Function() create,
required List<Responsive> Function(
BuildContext context,
T row,
int index,
List<T> data,
List<String> columnsHeaders, {
List<T> data, {
required bool isCard,
required bool enabled,
required Function(List<T> value) didChange,
}) buildRow,
List<String> columnHeaders = const <String>[],
List<Widget> columnHeaders = const <Widget>[],
List<int>? columnsFlex,
Future<bool> Function(BuildContext context, List<T> data)? beforeAdd,
Future<bool> Function(BuildContext context, T row, int index, List<T> data)?
removeRow,
FormFieldSetter<List<T>>? onSaved,
FormFieldValidator<List<T>>? validator,
String? Function(List<T>)? validator,
void Function(List<T>)? onSaved,
super.enabled,
bool showAddButton = true,
bool showTopAddButton = true,
bool withDivider = true,
AutovalidateMode autoValidateMode = AutovalidateMode.disabled,
Widget Function(
BuildContext context,
Expand All @@ -62,6 +59,9 @@ class TableField<T extends AbstractModel<ID>, ID>
super.minHeight,
ResponsiveSize? changeToCard,
double? elevation,
String emptyListText = 'Sem %s até o momento.',
String removeText = 'Remover %s',
String addText = 'Adicionar %s',
super.key,
}) : assert(
columnsFlex == null || columnsFlex.length == columnHeaders.length,
Expand All @@ -70,25 +70,16 @@ class TableField<T extends AbstractModel<ID>, ID>
),
super(
onSaved: enabled && onSaved != null
? (List<T>? value) => onSaved(value)
? (List<T>? value) => onSaved(value!)
: null,
validator: enabled && validator != null
? (List<T>? value) => validator(value)
? (List<T>? value) => validator(value!)
: null,
autovalidateMode: autoValidateMode,
builder: (FormFieldState<List<T>> field) {
TextStyle? columnHeaderTheme =
Theme.of(field.context).textTheme.titleSmall;

if (columnHeaderTheme != null && !enabled) {
columnHeaderTheme = columnHeaderTheme.copyWith(
color: Theme.of(field.context).disabledColor,
);
}

InputDecoration effectiveDecoration = (decoration ??
InputDecoration(
labelText: builder.superPlural(field.context),
labelText: plural,
border: const OutlineInputBorder(),
counterText: '',
enabled: enabled,
Expand All @@ -100,21 +91,17 @@ class TableField<T extends AbstractModel<ID>, ID>
padding: padding,
decoration: effectiveDecoration,
children: <Widget>[
if (field.value!.isEmpty)

/// Empty table
/// Empty
if (field.value?.isEmpty ?? true)
SizedBox(
height: 75,
child: Center(
child: Text(
'Sem ${builder.superPlural(field.context)} '
'até o momento.',
),
child: Text(sprintf(emptyListText, <dynamic>[plural])),
),
)
else

/// Table
/// Table
else
ResponsiveBuilder(
builder: (
BuildContext context,
Expand All @@ -123,12 +110,13 @@ class TableField<T extends AbstractModel<ID>, ID>
bool isCard = false;
List<Widget> columnData = <Widget>[];

/// Card
if (changeToCard != null &&
responsiveSize <= changeToCard) {
isCard = true;

/// Table data
for (final MapEntry<int, T> (:int key, :T value)
/// Card data
for (final MapEntry<int, T>(:int key, :T value)
in field.value!.asMap().entries) {
columnData.add(
Padding(
Expand All @@ -144,8 +132,9 @@ class TableField<T extends AbstractModel<ID>, ID>
value,
key,
field.value!,
columnHeaders,
isCard: isCard,
enabled: enabled,
didChange: field.didChange,
),

/// Delete button
Expand All @@ -154,7 +143,10 @@ class TableField<T extends AbstractModel<ID>, ID>
enabled: enabled,
iconData: FontAwesomeIcons.trashCan,
padding: const EdgeInsets.all(8),
label: 'REMOVER ITEM',
label: sprintf(
removeText,
<dynamic>[single],
).toUpperCase(),
onPressed: () async {
bool go = await removeRow(
field.context,
Expand All @@ -176,6 +168,8 @@ class TableField<T extends AbstractModel<ID>, ID>
),
);
}

/// Table
} else {
/// Header
if (columnHeaders.isNotEmpty) {
Expand All @@ -184,30 +178,62 @@ class TableField<T extends AbstractModel<ID>, ID>
children: <Widget>[
/// Columns Names
...columnHeaders.asMap().entries.map<Widget>(
(MapEntry<int, String> entry) =>
HeaderCell(
flex: columnsFlex?[entry.key] ?? 1,
child: Text(
entry.value,
style: columnHeaderTheme,
),
(MapEntry<int, Widget> entry) {
int flex = columnsFlex?[entry.key] ?? 1;

if (flex < 1) {
return entry.value;
}

return Flexible(
flex: flex,
child: SizedBox(
width: double.infinity,
child: entry.value,
),
),
);
},
),

/// Empty column to delete button
if (removeRow != null) const EmptyButton(),
if (removeRow != null)
showTopAddButton
? TableIconButton(
enabled: enabled,
iconData: FontAwesomeIcons.plus,
tooltip: sprintf(
addText,
<dynamic>[single],
),
onPressed: () async {
if (beforeAdd != null) {
bool go = await beforeAdd(
field.context,
field.value!,
);
if (!go) {
return;
}
}

field.value!.insert(0, create());
field.didChange(field.value);
},
)
: const EmptyButton(),
],
),
);
}

/// Table data
for (final MapEntry<int, T> (:int key, :T value)
for (final MapEntry<int, T>(:int key, :T value)
in field.value!.asMap().entries) {
columnData.addAll(
<Widget>[
/// Divider
FollyDivider(enabled: enabled),
if (withDivider || key == 0)
FollyDivider(enabled: enabled),

/// Row
Row(
Expand All @@ -219,27 +245,36 @@ class TableField<T extends AbstractModel<ID>, ID>
value,
key,
field.value!,
List<String>.filled(
columnHeaders.length,
'',
),
isCard: isCard,
enabled: enabled,
didChange: field.didChange,
).asMap().entries.map<Widget>(
(MapEntry<int, Widget> entry) =>
Flexible(
flex: columnsFlex?[entry.key] ?? 1,
child: SizedBox(
width: double.infinity,
child: entry.value,
),
(MapEntry<int, Widget> entry) {
int flex = columnsFlex?[entry.key] ?? 1;

if (flex < 1) {
return entry.value;
}

return Flexible(
flex: flex,
child: SizedBox(
width: double.infinity,
child: entry.value,
),
),
);
},
),

/// Delete button
if (removeRow != null)
TableIconButton(
enabled: enabled,
iconData: FontAwesomeIcons.trashCan,
tooltip: sprintf(
removeText,
<dynamic>[single],
),
onPressed: () async {
bool go = await removeRow(
field.context,
Expand Down Expand Up @@ -281,7 +316,7 @@ class TableField<T extends AbstractModel<ID>, ID>
TableButton(
enabled: enabled,
iconData: FontAwesomeIcons.plus,
label: 'Adicionar ${builder.superSingle(field.context)}',
label: sprintf(addText, <dynamic>[single]).toUpperCase(),
onPressed: () async {
if (beforeAdd != null) {
bool go = await beforeAdd(field.context, field.value!);
Expand All @@ -290,7 +325,7 @@ class TableField<T extends AbstractModel<ID>, ID>
}
}

field.value!.add(consumer.fromJson(<String, dynamic>{}));
field.value!.add(create());
field.didChange(field.value);
},
),
Expand Down
37 changes: 0 additions & 37 deletions lib/widgets/header_cell.dart

This file was deleted.

Loading

0 comments on commit bdcd434

Please sign in to comment.