This commit is contained in:
tzw
2021-09-11 10:32:50 +06:30
75 changed files with 1112 additions and 522 deletions

View File

@@ -83,12 +83,16 @@ class MyDataRow {
///
/// The [cells] argument must not be null.
MyDataRow.byIndex({
<<<<<<< HEAD
int index = 0,
=======
int? index,
>>>>>>> upstream/master
this.selected = false,
this.onSelectChanged,
required this.cells,
}) : assert(cells != null),
key = ValueKey<int>(index);
key = ValueKey<int>(index!);
/// A [Key] that uniquely identifies this row. This is used to
/// ensure that if a row is added or removed, any stateful widgets
@@ -320,7 +324,7 @@ class MyDataTable extends StatelessWidget {
this.columnSpacing = 56.0,
this.oddLine,
this.evenLine,
@required this.rows,
required this.rows,
}) : assert(columns != null),
assert(columns.isNotEmpty),
assert(sortColumnIndex == null ||
@@ -451,10 +455,10 @@ class MyDataTable extends StatelessWidget {
Color(0x1E000000); // Dark theme variant is just a guess.
Widget _buildCheckbox({
Color color,
bool checked,
VoidCallback onRowTap,
ValueChanged<bool> onCheckboxChanged,
Color? color,
bool? checked,
VoidCallback? onRowTap,
ValueChanged<bool>? onCheckboxChanged,
}) {
Widget contents = Semantics(
container: true,
@@ -465,7 +469,9 @@ class MyDataTable extends StatelessWidget {
child: Checkbox(
activeColor: color,
value: checked,
onChanged: onCheckboxChanged,
onChanged: (bool? value) {
onCheckboxChanged!(value ?? false);
},
),
),
),
@@ -483,32 +489,33 @@ class MyDataTable extends StatelessWidget {
}
Widget _buildHeadingCell({
BuildContext context,
EdgeInsetsGeometry padding,
Widget label,
String tooltip,
bool numeric,
VoidCallback onSort,
bool sorted,
bool ascending,
required BuildContext context,
EdgeInsetsGeometry? padding,
Widget? label,
String? tooltip,
bool? numeric,
VoidCallback? onSort,
bool? sorted,
bool? ascending,
}) {
if (onSort != null) {
final Widget arrow = _SortArrow(
visible: sorted,
visible: sorted!,
down: sorted ? ascending : null,
duration: _sortArrowAnimationDuration,
);
const Widget arrowPadding = SizedBox(width: _sortArrowPadding);
label = Row(
textDirection: numeric ? TextDirection.rtl : null,
children: <Widget>[label, arrowPadding, arrow],
textDirection: (numeric ?? false) ? TextDirection.rtl : null,
children: <Widget>[label ?? Container(), arrowPadding, arrow],
);
}
label = Container(
padding: padding,
height: headingRowHeight,
alignment:
numeric ? Alignment.centerRight : AlignmentDirectional.centerStart,
alignment: (numeric ?? false)
? Alignment.centerRight
: AlignmentDirectional.centerStart,
child: AnimatedDefaultTextStyle(
style: TextStyle(
// TODO(ianh): font family should match Theme; see https://github.com/flutter/flutter/issues/3116
@@ -516,12 +523,16 @@ class MyDataTable extends StatelessWidget {
fontSize: _headingFontSize,
height: math.min(1.0, headingRowHeight / _headingFontSize),
color: (Theme.of(context).brightness == Brightness.light)
? ((onSort != null && sorted) ? Colors.black87 : Colors.black54)
: ((onSort != null && sorted) ? Colors.white : Colors.white70),
? ((onSort != null && (sorted ?? false))
? Colors.black87
: Colors.black54)
: ((onSort != null && (sorted ?? false))
? Colors.white
: Colors.white70),
),
softWrap: false,
duration: _sortArrowAnimationDuration,
child: label,
child: label ?? Container(),
),
);
if (tooltip != null) {
@@ -540,42 +551,43 @@ class MyDataTable extends StatelessWidget {
}
Widget _buildMyDataCell({
BuildContext context,
EdgeInsetsGeometry padding,
Widget label,
bool numeric,
bool placeholder,
bool showEditIcon,
VoidCallback onTap,
VoidCallback onSelectChanged,
required BuildContext context,
EdgeInsetsGeometry? padding,
Widget? label,
bool? numeric,
bool? placeholder,
bool? showEditIcon,
VoidCallback? onTap,
VoidCallback? onSelectChanged,
}) {
final bool isLightTheme = Theme.of(context).brightness == Brightness.light;
if (showEditIcon) {
if (showEditIcon ?? false) {
const Widget icon = Icon(Icons.edit, size: 18.0);
label = Expanded(child: label);
label = Expanded(child: label ?? Container());
label = Row(
textDirection: numeric ? TextDirection.rtl : null,
textDirection: (numeric ?? false) ? TextDirection.rtl : null,
children: <Widget>[label, icon],
);
}
label = Container(
padding: padding,
height: MyDataRowHeight,
alignment:
numeric ? Alignment.centerRight : AlignmentDirectional.centerStart,
alignment: (numeric ?? false)
? Alignment.centerRight
: AlignmentDirectional.centerStart,
child: DefaultTextStyle(
style: TextStyle(
// TODO(ianh): font family should be Roboto; see https://github.com/flutter/flutter/issues/3116
fontSize: 13.0,
color: isLightTheme
? (placeholder ? Colors.black38 : Colors.black87)
: (placeholder ? Colors.white38 : Colors.white70),
? ((placeholder ?? false) ? Colors.black38 : Colors.black87)
: ((placeholder ?? false) ? Colors.white38 : Colors.white70),
),
child: IconTheme.merge(
data: IconThemeData(
color: isLightTheme ? Colors.black54 : Colors.white70,
),
child: DropdownButtonHideUnderline(child: label),
child: DropdownButtonHideUnderline(child: label ?? Container()),
),
),
);
@@ -614,6 +626,10 @@ class MyDataTable extends StatelessWidget {
final List<TableColumnWidth> tableColumns = (columns.length +
(showCheckboxColumn ? 1 : 0)) as List<TableColumnWidth>;
<<<<<<< HEAD
=======
>>>>>>> upstream/master
final List<TableRow> tableRows = List<TableRow>.generate(
rows.length + 1, // the +1 is for the header row
(int index) {
@@ -626,36 +642,36 @@ class MyDataTable extends StatelessWidget {
: index.isEven && evenLine != null
? evenLine
: _kUnselectedDecoration,
children: List<Widget>(tableColumns.length),
children: tableColumns.map((e) => Container()).toList(),
);
},
);
int rowIndex;
int displayColumnIndex = 0;
if (showCheckboxColumn) {
tableColumns[0] = FixedColumnWidth(
horizontalMargin + Checkbox.width + horizontalMargin / 2.0);
tableRows[0].children[0] = _buildCheckbox(
color: theme.accentColor,
checked: allChecked,
onCheckboxChanged: _handleSelectAll,
);
rowIndex = 1;
for (MyDataRow row in rows) {
tableRows[rowIndex].children[0] = _buildCheckbox(
color: theme.accentColor,
checked: row.selected,
onRowTap: () => row.onSelectChanged != null
? row.onSelectChanged(!row.selected)
: null,
onCheckboxChanged: row.onSelectChanged,
);
rowIndex += 1;
}
displayColumnIndex += 1;
}
int displayColumnIndex = 0;
// if (showCheckboxColumn) {
// tableColumns[0] = FixedColumnWidth(
// horizontalMargin + Checkbox.width + horizontalMargin / 2.0);
// tableRows[0].children![0] = _buildCheckbox(
// color: theme.accentColor,
// checked: allChecked,
// onCheckboxChanged: _handleSelectAll,
// );
// rowIndex = 1;
// for (MyDataRow row in rows) {
// tableRows[rowIndex].children[0] = _buildCheckbox(
// color: theme.accentColor,
// checked: row.selected,
// onRowTap: () => row.onSelectChanged != null
// ? row.onSelectChanged(!row.selected)
// : null,
// onCheckboxChanged: row.onSelectChanged,
// );
// rowIndex += 1;
// }
// displayColumnIndex += 1;
// }
for (int MyDataColumnIndex = 0;
MyDataColumnIndex < columns.length;
@@ -688,14 +704,14 @@ class MyDataTable extends StatelessWidget {
} else {
tableColumns[displayColumnIndex] = const IntrinsicColumnWidth();
}
tableRows[0].children[displayColumnIndex] = _buildHeadingCell(
tableRows[0].children![displayColumnIndex] = _buildHeadingCell(
context: context,
padding: padding,
label: column.label,
tooltip: column.tooltip,
numeric: column.numeric,
onSort: () => column.onSort != null
? column.onSort(MyDataColumnIndex,
? column.onSort!(MyDataColumnIndex,
sortColumnIndex != MyDataColumnIndex || !sortAscending)
: null,
sorted: MyDataColumnIndex == sortColumnIndex,
@@ -704,7 +720,7 @@ class MyDataTable extends StatelessWidget {
rowIndex = 1;
for (MyDataRow row in rows) {
final MyDataCell cell = row.cells[MyDataColumnIndex];
tableRows[rowIndex].children[displayColumnIndex] = _buildMyDataCell(
tableRows[rowIndex].children?[displayColumnIndex] = _buildMyDataCell(
context: context,
padding: padding,
label: cell.child,
@@ -713,7 +729,7 @@ class MyDataTable extends StatelessWidget {
showEditIcon: cell.showEditIcon,
onTap: cell.onTap,
onSelectChanged: () => row.onSelectChanged != null
? row.onSelectChanged(!row.selected)
? row.onSelectChanged!(!row.selected)
: null,
);
rowIndex += 1;
@@ -745,11 +761,19 @@ class TableRowInkWell extends InkResponse {
/// Creates an ink well for a table row.
const TableRowInkWell({
Key? key,
<<<<<<< HEAD
Widget child,
GestureTapCallback onTap,
GestureTapCallback onDoubleTap,
GestureLongPressCallback onLongPress,
ValueChanged<bool> onHighlightChanged,
=======
Widget? child,
GestureTapCallback? onTap,
GestureTapCallback? onDoubleTap,
GestureLongPressCallback? onLongPress,
ValueChanged<bool>? onHighlightChanged,
>>>>>>> upstream/master
}) : super(
key: key,
child: child,
@@ -765,7 +789,7 @@ class TableRowInkWell extends InkResponse {
RectCallback getRectCallback(RenderBox referenceBox) {
return () {
RenderObject cell = referenceBox;
AbstractNode table = cell.parent;
AbstractNode? table = cell.parent;
final Matrix4 transform = Matrix4.identity();
while (table is RenderObject && table is! RenderTable) {
final RenderObject parentBox = table as RenderObject;
@@ -778,11 +802,11 @@ class TableRowInkWell extends InkResponse {
final TableCellParentData cellParentData =
cell.parentData as TableCellParentData;
assert(cellParentData.y != null);
final Rect rect = table.getRowBox(cellParentData.y);
final Rect rect = table.getRowBox(cellParentData.y!);
// The rect is in the table's coordinate space. We need to change it to the
// TableRowInkWell's coordinate space.
table.applyPaintTransform(cell, transform);
final Offset offset = MatrixUtils.getAsTranslation(transform);
final Offset? offset = MatrixUtils.getAsTranslation(transform);
if (offset != null) return rect.shift(-offset);
}
return Rect.zero;
@@ -804,17 +828,18 @@ class _SortArrow extends StatefulWidget {
this.duration,
}) : super(key: key);
final bool visible;
final bool? visible;
final bool down;
final bool? down;
final Duration duration;
final Duration? duration;
@override
_SortArrowState createState() => _SortArrowState();
}
class _SortArrowState extends State<_SortArrow> with TickerProviderStateMixin {
<<<<<<< HEAD
late AnimationController _opacityController;
late Animation<double> _opacityAnimation;
@@ -823,6 +848,16 @@ class _SortArrowState extends State<_SortArrow> with TickerProviderStateMixin {
double _orientationOffset = 0.0;
late bool _down;
=======
AnimationController? _opacityController;
Animation<double>? _opacityAnimation;
AnimationController? _orientationController;
Animation<double>? _orientationAnimation;
double _orientationOffset = 0.0;
bool? _down;
>>>>>>> upstream/master
static final Animatable<double> _turnTween =
Tween<double>(begin: 0.0, end: math.pi)
@@ -838,15 +873,16 @@ class _SortArrowState extends State<_SortArrow> with TickerProviderStateMixin {
),
curve: Curves.fastOutSlowIn,
)..addListener(_rebuild);
_opacityController.value = widget.visible ? 1.0 : 0.0;
_opacityController!.value = (widget.visible ?? false) ? 1.0 : 0.0;
_orientationController = AnimationController(
duration: widget.duration,
vsync: this,
);
_orientationAnimation = _orientationController.drive(_turnTween)
_orientationAnimation = _orientationController!.drive(_turnTween)
..addListener(_rebuild)
..addStatusListener(_resetOrientationAnimation);
if (widget.visible) _orientationOffset = widget.down ? 0.0 : math.pi;
if (widget.visible ?? false)
_orientationOffset = (widget.down ?? false) ? 0.0 : math.pi;
}
void _rebuild() {
@@ -857,9 +893,9 @@ class _SortArrowState extends State<_SortArrow> with TickerProviderStateMixin {
void _resetOrientationAnimation(AnimationStatus status) {
if (status == AnimationStatus.completed) {
assert(_orientationAnimation.value == math.pi);
assert(_orientationAnimation!.value == math.pi);
_orientationOffset += math.pi;
_orientationController.value =
_orientationController!.value =
0.0; // TODO(ianh): This triggers a pointless rebuild.
}
}
@@ -868,26 +904,30 @@ class _SortArrowState extends State<_SortArrow> with TickerProviderStateMixin {
void didUpdateWidget(_SortArrow oldWidget) {
super.didUpdateWidget(oldWidget);
bool skipArrow = false;
<<<<<<< HEAD
final bool newDown = widget.down;
=======
final bool newDown = widget.down ?? _down!;
>>>>>>> upstream/master
if (oldWidget.visible != widget.visible) {
if (widget.visible &&
(_opacityController.status == AnimationStatus.dismissed)) {
_orientationController.stop();
_orientationController.value = 0.0;
if (widget.visible! &&
(_opacityController!.status == AnimationStatus.dismissed)) {
_orientationController!.stop();
_orientationController!.value = 0.0;
_orientationOffset = newDown ? 0.0 : math.pi;
skipArrow = true;
}
if (widget.visible) {
_opacityController.forward();
if ((widget.visible ?? false)) {
_opacityController!.forward();
} else {
_opacityController.reverse();
_opacityController!.reverse();
}
}
if ((_down != newDown) && !skipArrow) {
if (_orientationController.status == AnimationStatus.dismissed) {
_orientationController.forward();
if (_orientationController!.status == AnimationStatus.dismissed) {
_orientationController?.forward();
} else {
_orientationController.reverse();
_orientationController?.reverse();
}
}
_down = newDown;
@@ -895,8 +935,8 @@ class _SortArrowState extends State<_SortArrow> with TickerProviderStateMixin {
@override
void dispose() {
_opacityController.dispose();
_orientationController.dispose();
_opacityController?.dispose();
_orientationController?.dispose();
super.dispose();
}
@@ -906,10 +946,10 @@ class _SortArrowState extends State<_SortArrow> with TickerProviderStateMixin {
@override
Widget build(BuildContext context) {
return Opacity(
opacity: _opacityAnimation.value,
opacity: _opacityAnimation!.value,
child: Transform(
transform:
Matrix4.rotationZ(_orientationOffset + _orientationAnimation.value)
Matrix4.rotationZ(_orientationOffset + _orientationAnimation!.value)
..setTranslationRaw(0.0, _arrowIconBaselineOffset, 0.0),
alignment: Alignment.center,
child: Icon(