null safety
This commit is contained in:
@@ -75,7 +75,7 @@ class MyDataRow {
|
|||||||
this.key,
|
this.key,
|
||||||
this.selected = false,
|
this.selected = false,
|
||||||
this.onSelectChanged,
|
this.onSelectChanged,
|
||||||
@required this.cells,
|
required this.cells,
|
||||||
}) : assert(cells != null);
|
}) : assert(cells != null);
|
||||||
|
|
||||||
/// Creates the configuration for a row of a [MyDataTable], deriving
|
/// Creates the configuration for a row of a [MyDataTable], deriving
|
||||||
@@ -83,12 +83,12 @@ class MyDataRow {
|
|||||||
///
|
///
|
||||||
/// The [cells] argument must not be null.
|
/// The [cells] argument must not be null.
|
||||||
MyDataRow.byIndex({
|
MyDataRow.byIndex({
|
||||||
int index,
|
int? index,
|
||||||
this.selected = false,
|
this.selected = false,
|
||||||
this.onSelectChanged,
|
this.onSelectChanged,
|
||||||
@required this.cells,
|
required this.cells,
|
||||||
}) : assert(cells != null),
|
}) : assert(cells != null),
|
||||||
key = ValueKey<int>(index);
|
key = ValueKey<int>(index!);
|
||||||
|
|
||||||
/// A [Key] that uniquely identifies this row. This is used to
|
/// A [Key] that uniquely identifies this row. This is used to
|
||||||
/// ensure that if a row is added or removed, any stateful widgets
|
/// ensure that if a row is added or removed, any stateful widgets
|
||||||
@@ -96,7 +96,7 @@ class MyDataRow {
|
|||||||
/// remain on the right row visually.
|
/// remain on the right row visually.
|
||||||
///
|
///
|
||||||
/// If the table never changes once created, no key is necessary.
|
/// If the table never changes once created, no key is necessary.
|
||||||
final LocalKey key;
|
final LocalKey? key;
|
||||||
|
|
||||||
/// Called when the user selects or unselects a selectable row.
|
/// Called when the user selects or unselects a selectable row.
|
||||||
///
|
///
|
||||||
@@ -111,7 +111,7 @@ class MyDataRow {
|
|||||||
/// A row whose [onSelectChanged] callback is null is ignored for
|
/// A row whose [onSelectChanged] callback is null is ignored for
|
||||||
/// the purposes of determining the state of the "all" checkbox,
|
/// the purposes of determining the state of the "all" checkbox,
|
||||||
/// and its checkbox is disabled.
|
/// and its checkbox is disabled.
|
||||||
final ValueChanged<bool> onSelectChanged;
|
final ValueChanged<bool>? onSelectChanged;
|
||||||
|
|
||||||
/// Whether the row is selected.
|
/// Whether the row is selected.
|
||||||
///
|
///
|
||||||
@@ -193,7 +193,7 @@ class MyDataCell {
|
|||||||
/// If non-null, tapping the cell will call this callback. If
|
/// If non-null, tapping the cell will call this callback. If
|
||||||
/// null, tapping the cell will attempt to select the row (if
|
/// null, tapping the cell will attempt to select the row (if
|
||||||
/// [MyDataRow.onSelectChanged] is provided).
|
/// [MyDataRow.onSelectChanged] is provided).
|
||||||
final VoidCallback onTap;
|
final VoidCallback? onTap;
|
||||||
|
|
||||||
bool get _debugInteractive => onTap != null;
|
bool get _debugInteractive => onTap != null;
|
||||||
}
|
}
|
||||||
@@ -309,8 +309,8 @@ class MyDataTable extends StatelessWidget {
|
|||||||
/// the sort order is ascending, this should be true (the default),
|
/// the sort order is ascending, this should be true (the default),
|
||||||
/// otherwise it should be false.
|
/// otherwise it should be false.
|
||||||
MyDataTable({
|
MyDataTable({
|
||||||
Key key,
|
Key? key,
|
||||||
@required this.columns,
|
required this.columns,
|
||||||
this.sortColumnIndex,
|
this.sortColumnIndex,
|
||||||
this.sortAscending = true,
|
this.sortAscending = true,
|
||||||
this.onSelectAll,
|
this.onSelectAll,
|
||||||
@@ -320,7 +320,7 @@ class MyDataTable extends StatelessWidget {
|
|||||||
this.columnSpacing = 56.0,
|
this.columnSpacing = 56.0,
|
||||||
this.oddLine,
|
this.oddLine,
|
||||||
this.evenLine,
|
this.evenLine,
|
||||||
@required this.rows,
|
required this.rows,
|
||||||
}) : assert(columns != null),
|
}) : assert(columns != null),
|
||||||
assert(columns.isNotEmpty),
|
assert(columns.isNotEmpty),
|
||||||
assert(sortColumnIndex == null ||
|
assert(sortColumnIndex == null ||
|
||||||
@@ -339,8 +339,8 @@ class MyDataTable extends StatelessWidget {
|
|||||||
/// The configuration and labels for the columns in the table.
|
/// The configuration and labels for the columns in the table.
|
||||||
final List<MyDataColumn> columns;
|
final List<MyDataColumn> columns;
|
||||||
|
|
||||||
final Decoration oddLine;
|
final Decoration? oddLine;
|
||||||
final Decoration evenLine;
|
final Decoration? evenLine;
|
||||||
|
|
||||||
/// The current primary sort key's column.
|
/// The current primary sort key's column.
|
||||||
///
|
///
|
||||||
@@ -353,7 +353,7 @@ class MyDataTable extends StatelessWidget {
|
|||||||
///
|
///
|
||||||
/// When this is null, it implies that the table's sort order does
|
/// When this is null, it implies that the table's sort order does
|
||||||
/// not correspond to any of the columns.
|
/// not correspond to any of the columns.
|
||||||
final int sortColumnIndex;
|
final int? sortColumnIndex;
|
||||||
|
|
||||||
/// Whether the column mentioned in [sortColumnIndex], if any, is sorted
|
/// Whether the column mentioned in [sortColumnIndex], if any, is sorted
|
||||||
/// in ascending order.
|
/// in ascending order.
|
||||||
@@ -376,7 +376,7 @@ class MyDataTable extends StatelessWidget {
|
|||||||
/// To control whether a particular row is selectable or not, see
|
/// To control whether a particular row is selectable or not, see
|
||||||
/// [MyDataRow.onSelectChanged]. This callback is only relevant if any
|
/// [MyDataRow.onSelectChanged]. This callback is only relevant if any
|
||||||
/// row is selectable.
|
/// row is selectable.
|
||||||
final ValueSetter<bool> onSelectAll;
|
final ValueSetter<bool>? onSelectAll;
|
||||||
|
|
||||||
/// The height of each row (excluding the row that contains column headings).
|
/// The height of each row (excluding the row that contains column headings).
|
||||||
///
|
///
|
||||||
@@ -413,11 +413,10 @@ class MyDataTable extends StatelessWidget {
|
|||||||
// non-numeric, if there is exactly one, otherwise null.
|
// non-numeric, if there is exactly one, otherwise null.
|
||||||
final int _onlyTextColumn;
|
final int _onlyTextColumn;
|
||||||
static int _initOnlyTextColumn(List<MyDataColumn> columns) {
|
static int _initOnlyTextColumn(List<MyDataColumn> columns) {
|
||||||
int result;
|
int result = 0;
|
||||||
for (int index = 0; index < columns.length; index += 1) {
|
for (int index = 0; index < columns.length; index += 1) {
|
||||||
final MyDataColumn column = columns[index];
|
final MyDataColumn column = columns[index];
|
||||||
if (!column.numeric) {
|
if (!column.numeric) {
|
||||||
if (result != null) return null;
|
|
||||||
result = index;
|
result = index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -433,11 +432,11 @@ class MyDataTable extends StatelessWidget {
|
|||||||
|
|
||||||
void _handleSelectAll(bool checked) {
|
void _handleSelectAll(bool checked) {
|
||||||
if (onSelectAll != null) {
|
if (onSelectAll != null) {
|
||||||
onSelectAll(checked);
|
onSelectAll!(checked);
|
||||||
} else {
|
} else {
|
||||||
for (MyDataRow row in rows) {
|
for (MyDataRow row in rows) {
|
||||||
if ((row.onSelectChanged != null) && (row.selected != checked))
|
if ((row.onSelectChanged != null) && (row.selected != checked))
|
||||||
row.onSelectChanged(checked);
|
row.onSelectChanged!(checked);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -452,10 +451,10 @@ class MyDataTable extends StatelessWidget {
|
|||||||
Color(0x1E000000); // Dark theme variant is just a guess.
|
Color(0x1E000000); // Dark theme variant is just a guess.
|
||||||
|
|
||||||
Widget _buildCheckbox({
|
Widget _buildCheckbox({
|
||||||
Color color,
|
Color? color,
|
||||||
bool checked,
|
bool? checked,
|
||||||
VoidCallback onRowTap,
|
VoidCallback? onRowTap,
|
||||||
ValueChanged<bool> onCheckboxChanged,
|
ValueChanged<bool>? onCheckboxChanged,
|
||||||
}) {
|
}) {
|
||||||
Widget contents = Semantics(
|
Widget contents = Semantics(
|
||||||
container: true,
|
container: true,
|
||||||
@@ -466,7 +465,9 @@ class MyDataTable extends StatelessWidget {
|
|||||||
child: Checkbox(
|
child: Checkbox(
|
||||||
activeColor: color,
|
activeColor: color,
|
||||||
value: checked,
|
value: checked,
|
||||||
onChanged: onCheckboxChanged,
|
onChanged: (bool? value) {
|
||||||
|
onCheckboxChanged!(value ?? false);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -484,32 +485,33 @@ class MyDataTable extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildHeadingCell({
|
Widget _buildHeadingCell({
|
||||||
BuildContext context,
|
required BuildContext context,
|
||||||
EdgeInsetsGeometry padding,
|
EdgeInsetsGeometry? padding,
|
||||||
Widget label,
|
Widget? label,
|
||||||
String tooltip,
|
String? tooltip,
|
||||||
bool numeric,
|
bool? numeric,
|
||||||
VoidCallback onSort,
|
VoidCallback? onSort,
|
||||||
bool sorted,
|
bool? sorted,
|
||||||
bool ascending,
|
bool? ascending,
|
||||||
}) {
|
}) {
|
||||||
if (onSort != null) {
|
if (onSort != null) {
|
||||||
final Widget arrow = _SortArrow(
|
final Widget arrow = _SortArrow(
|
||||||
visible: sorted,
|
visible: sorted!,
|
||||||
down: sorted ? ascending : null,
|
down: sorted ? ascending : null,
|
||||||
duration: _sortArrowAnimationDuration,
|
duration: _sortArrowAnimationDuration,
|
||||||
);
|
);
|
||||||
const Widget arrowPadding = SizedBox(width: _sortArrowPadding);
|
const Widget arrowPadding = SizedBox(width: _sortArrowPadding);
|
||||||
label = Row(
|
label = Row(
|
||||||
textDirection: numeric ? TextDirection.rtl : null,
|
textDirection: (numeric ?? false) ? TextDirection.rtl : null,
|
||||||
children: <Widget>[label, arrowPadding, arrow],
|
children: <Widget>[label ?? Container(), arrowPadding, arrow],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
label = Container(
|
label = Container(
|
||||||
padding: padding,
|
padding: padding,
|
||||||
height: headingRowHeight,
|
height: headingRowHeight,
|
||||||
alignment:
|
alignment: (numeric ?? false)
|
||||||
numeric ? Alignment.centerRight : AlignmentDirectional.centerStart,
|
? Alignment.centerRight
|
||||||
|
: AlignmentDirectional.centerStart,
|
||||||
child: AnimatedDefaultTextStyle(
|
child: AnimatedDefaultTextStyle(
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
// TODO(ianh): font family should match Theme; see https://github.com/flutter/flutter/issues/3116
|
// TODO(ianh): font family should match Theme; see https://github.com/flutter/flutter/issues/3116
|
||||||
@@ -517,12 +519,16 @@ class MyDataTable extends StatelessWidget {
|
|||||||
fontSize: _headingFontSize,
|
fontSize: _headingFontSize,
|
||||||
height: math.min(1.0, headingRowHeight / _headingFontSize),
|
height: math.min(1.0, headingRowHeight / _headingFontSize),
|
||||||
color: (Theme.of(context).brightness == Brightness.light)
|
color: (Theme.of(context).brightness == Brightness.light)
|
||||||
? ((onSort != null && sorted) ? Colors.black87 : Colors.black54)
|
? ((onSort != null && (sorted ?? false))
|
||||||
: ((onSort != null && sorted) ? Colors.white : Colors.white70),
|
? Colors.black87
|
||||||
|
: Colors.black54)
|
||||||
|
: ((onSort != null && (sorted ?? false))
|
||||||
|
? Colors.white
|
||||||
|
: Colors.white70),
|
||||||
),
|
),
|
||||||
softWrap: false,
|
softWrap: false,
|
||||||
duration: _sortArrowAnimationDuration,
|
duration: _sortArrowAnimationDuration,
|
||||||
child: label,
|
child: label ?? Container(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
if (tooltip != null) {
|
if (tooltip != null) {
|
||||||
@@ -541,42 +547,43 @@ class MyDataTable extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildMyDataCell({
|
Widget _buildMyDataCell({
|
||||||
BuildContext context,
|
required BuildContext context,
|
||||||
EdgeInsetsGeometry padding,
|
EdgeInsetsGeometry? padding,
|
||||||
Widget label,
|
Widget? label,
|
||||||
bool numeric,
|
bool? numeric,
|
||||||
bool placeholder,
|
bool? placeholder,
|
||||||
bool showEditIcon,
|
bool? showEditIcon,
|
||||||
VoidCallback onTap,
|
VoidCallback? onTap,
|
||||||
VoidCallback onSelectChanged,
|
VoidCallback? onSelectChanged,
|
||||||
}) {
|
}) {
|
||||||
final bool isLightTheme = Theme.of(context).brightness == Brightness.light;
|
final bool isLightTheme = Theme.of(context).brightness == Brightness.light;
|
||||||
if (showEditIcon) {
|
if (showEditIcon ?? false) {
|
||||||
const Widget icon = Icon(Icons.edit, size: 18.0);
|
const Widget icon = Icon(Icons.edit, size: 18.0);
|
||||||
label = Expanded(child: label);
|
label = Expanded(child: label ?? Container());
|
||||||
label = Row(
|
label = Row(
|
||||||
textDirection: numeric ? TextDirection.rtl : null,
|
textDirection: (numeric ?? false) ? TextDirection.rtl : null,
|
||||||
children: <Widget>[label, icon],
|
children: <Widget>[label, icon],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
label = Container(
|
label = Container(
|
||||||
padding: padding,
|
padding: padding,
|
||||||
height: MyDataRowHeight,
|
height: MyDataRowHeight,
|
||||||
alignment:
|
alignment: (numeric ?? false)
|
||||||
numeric ? Alignment.centerRight : AlignmentDirectional.centerStart,
|
? Alignment.centerRight
|
||||||
|
: AlignmentDirectional.centerStart,
|
||||||
child: DefaultTextStyle(
|
child: DefaultTextStyle(
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
// TODO(ianh): font family should be Roboto; see https://github.com/flutter/flutter/issues/3116
|
// TODO(ianh): font family should be Roboto; see https://github.com/flutter/flutter/issues/3116
|
||||||
fontSize: 13.0,
|
fontSize: 13.0,
|
||||||
color: isLightTheme
|
color: isLightTheme
|
||||||
? (placeholder ? Colors.black38 : Colors.black87)
|
? ((placeholder ?? false) ? Colors.black38 : Colors.black87)
|
||||||
: (placeholder ? Colors.white38 : Colors.white70),
|
: ((placeholder ?? false) ? Colors.white38 : Colors.white70),
|
||||||
),
|
),
|
||||||
child: IconTheme.merge(
|
child: IconTheme.merge(
|
||||||
data: IconThemeData(
|
data: IconThemeData(
|
||||||
color: isLightTheme ? Colors.black54 : Colors.white70,
|
color: isLightTheme ? Colors.black54 : Colors.white70,
|
||||||
),
|
),
|
||||||
child: DropdownButtonHideUnderline(child: label),
|
child: DropdownButtonHideUnderline(child: label ?? Container()),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -613,8 +620,9 @@ class MyDataTable extends StatelessWidget {
|
|||||||
final bool showCheckboxColumn = false;
|
final bool showCheckboxColumn = false;
|
||||||
final bool allChecked = false;
|
final bool allChecked = false;
|
||||||
|
|
||||||
final List<TableColumnWidth> tableColumns =
|
final List<TableColumnWidth> tableColumns = (columns.length +
|
||||||
List<TableColumnWidth>(columns.length + (showCheckboxColumn ? 1 : 0));
|
(showCheckboxColumn ? 1 : 0)) as List<TableColumnWidth>;
|
||||||
|
|
||||||
final List<TableRow> tableRows = List<TableRow>.generate(
|
final List<TableRow> tableRows = List<TableRow>.generate(
|
||||||
rows.length + 1, // the +1 is for the header row
|
rows.length + 1, // the +1 is for the header row
|
||||||
(int index) {
|
(int index) {
|
||||||
@@ -627,7 +635,7 @@ class MyDataTable extends StatelessWidget {
|
|||||||
: index.isEven && evenLine != null
|
: index.isEven && evenLine != null
|
||||||
? evenLine
|
? evenLine
|
||||||
: _kUnselectedDecoration,
|
: _kUnselectedDecoration,
|
||||||
children: List<Widget>(tableColumns.length),
|
children: tableColumns.map((e) => Container()).toList(),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -635,28 +643,28 @@ class MyDataTable extends StatelessWidget {
|
|||||||
int rowIndex;
|
int rowIndex;
|
||||||
|
|
||||||
int displayColumnIndex = 0;
|
int displayColumnIndex = 0;
|
||||||
if (showCheckboxColumn) {
|
// if (showCheckboxColumn) {
|
||||||
tableColumns[0] = FixedColumnWidth(
|
// tableColumns[0] = FixedColumnWidth(
|
||||||
horizontalMargin + Checkbox.width + horizontalMargin / 2.0);
|
// horizontalMargin + Checkbox.width + horizontalMargin / 2.0);
|
||||||
tableRows[0].children[0] = _buildCheckbox(
|
// tableRows[0].children![0] = _buildCheckbox(
|
||||||
color: theme.accentColor,
|
// color: theme.accentColor,
|
||||||
checked: allChecked,
|
// checked: allChecked,
|
||||||
onCheckboxChanged: _handleSelectAll,
|
// onCheckboxChanged: _handleSelectAll,
|
||||||
);
|
// );
|
||||||
rowIndex = 1;
|
// rowIndex = 1;
|
||||||
for (MyDataRow row in rows) {
|
// for (MyDataRow row in rows) {
|
||||||
tableRows[rowIndex].children[0] = _buildCheckbox(
|
// tableRows[rowIndex].children[0] = _buildCheckbox(
|
||||||
color: theme.accentColor,
|
// color: theme.accentColor,
|
||||||
checked: row.selected,
|
// checked: row.selected,
|
||||||
onRowTap: () => row.onSelectChanged != null
|
// onRowTap: () => row.onSelectChanged != null
|
||||||
? row.onSelectChanged(!row.selected)
|
// ? row.onSelectChanged(!row.selected)
|
||||||
: null,
|
// : null,
|
||||||
onCheckboxChanged: row.onSelectChanged,
|
// onCheckboxChanged: row.onSelectChanged,
|
||||||
);
|
// );
|
||||||
rowIndex += 1;
|
// rowIndex += 1;
|
||||||
}
|
// }
|
||||||
displayColumnIndex += 1;
|
// displayColumnIndex += 1;
|
||||||
}
|
// }
|
||||||
|
|
||||||
for (int MyDataColumnIndex = 0;
|
for (int MyDataColumnIndex = 0;
|
||||||
MyDataColumnIndex < columns.length;
|
MyDataColumnIndex < columns.length;
|
||||||
@@ -689,14 +697,14 @@ class MyDataTable extends StatelessWidget {
|
|||||||
} else {
|
} else {
|
||||||
tableColumns[displayColumnIndex] = const IntrinsicColumnWidth();
|
tableColumns[displayColumnIndex] = const IntrinsicColumnWidth();
|
||||||
}
|
}
|
||||||
tableRows[0].children[displayColumnIndex] = _buildHeadingCell(
|
tableRows[0].children![displayColumnIndex] = _buildHeadingCell(
|
||||||
context: context,
|
context: context,
|
||||||
padding: padding,
|
padding: padding,
|
||||||
label: column.label,
|
label: column.label,
|
||||||
tooltip: column.tooltip,
|
tooltip: column.tooltip,
|
||||||
numeric: column.numeric,
|
numeric: column.numeric,
|
||||||
onSort: () => column.onSort != null
|
onSort: () => column.onSort != null
|
||||||
? column.onSort(MyDataColumnIndex,
|
? column.onSort!(MyDataColumnIndex,
|
||||||
sortColumnIndex != MyDataColumnIndex || !sortAscending)
|
sortColumnIndex != MyDataColumnIndex || !sortAscending)
|
||||||
: null,
|
: null,
|
||||||
sorted: MyDataColumnIndex == sortColumnIndex,
|
sorted: MyDataColumnIndex == sortColumnIndex,
|
||||||
@@ -705,7 +713,7 @@ class MyDataTable extends StatelessWidget {
|
|||||||
rowIndex = 1;
|
rowIndex = 1;
|
||||||
for (MyDataRow row in rows) {
|
for (MyDataRow row in rows) {
|
||||||
final MyDataCell cell = row.cells[MyDataColumnIndex];
|
final MyDataCell cell = row.cells[MyDataColumnIndex];
|
||||||
tableRows[rowIndex].children[displayColumnIndex] = _buildMyDataCell(
|
tableRows[rowIndex].children?[displayColumnIndex] = _buildMyDataCell(
|
||||||
context: context,
|
context: context,
|
||||||
padding: padding,
|
padding: padding,
|
||||||
label: cell.child,
|
label: cell.child,
|
||||||
@@ -714,7 +722,7 @@ class MyDataTable extends StatelessWidget {
|
|||||||
showEditIcon: cell.showEditIcon,
|
showEditIcon: cell.showEditIcon,
|
||||||
onTap: cell.onTap,
|
onTap: cell.onTap,
|
||||||
onSelectChanged: () => row.onSelectChanged != null
|
onSelectChanged: () => row.onSelectChanged != null
|
||||||
? row.onSelectChanged(!row.selected)
|
? row.onSelectChanged!(!row.selected)
|
||||||
: null,
|
: null,
|
||||||
);
|
);
|
||||||
rowIndex += 1;
|
rowIndex += 1;
|
||||||
@@ -745,12 +753,12 @@ class MyDataTable extends StatelessWidget {
|
|||||||
class TableRowInkWell extends InkResponse {
|
class TableRowInkWell extends InkResponse {
|
||||||
/// Creates an ink well for a table row.
|
/// Creates an ink well for a table row.
|
||||||
const TableRowInkWell({
|
const TableRowInkWell({
|
||||||
Key key,
|
Key? key,
|
||||||
Widget child,
|
Widget? child,
|
||||||
GestureTapCallback onTap,
|
GestureTapCallback? onTap,
|
||||||
GestureTapCallback onDoubleTap,
|
GestureTapCallback? onDoubleTap,
|
||||||
GestureLongPressCallback onLongPress,
|
GestureLongPressCallback? onLongPress,
|
||||||
ValueChanged<bool> onHighlightChanged,
|
ValueChanged<bool>? onHighlightChanged,
|
||||||
}) : super(
|
}) : super(
|
||||||
key: key,
|
key: key,
|
||||||
child: child,
|
child: child,
|
||||||
@@ -766,7 +774,7 @@ class TableRowInkWell extends InkResponse {
|
|||||||
RectCallback getRectCallback(RenderBox referenceBox) {
|
RectCallback getRectCallback(RenderBox referenceBox) {
|
||||||
return () {
|
return () {
|
||||||
RenderObject cell = referenceBox;
|
RenderObject cell = referenceBox;
|
||||||
AbstractNode table = cell.parent;
|
AbstractNode? table = cell.parent;
|
||||||
final Matrix4 transform = Matrix4.identity();
|
final Matrix4 transform = Matrix4.identity();
|
||||||
while (table is RenderObject && table is! RenderTable) {
|
while (table is RenderObject && table is! RenderTable) {
|
||||||
final RenderObject parentBox = table as RenderObject;
|
final RenderObject parentBox = table as RenderObject;
|
||||||
@@ -779,11 +787,11 @@ class TableRowInkWell extends InkResponse {
|
|||||||
final TableCellParentData cellParentData =
|
final TableCellParentData cellParentData =
|
||||||
cell.parentData as TableCellParentData;
|
cell.parentData as TableCellParentData;
|
||||||
assert(cellParentData.y != null);
|
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
|
// The rect is in the table's coordinate space. We need to change it to the
|
||||||
// TableRowInkWell's coordinate space.
|
// TableRowInkWell's coordinate space.
|
||||||
table.applyPaintTransform(cell, transform);
|
table.applyPaintTransform(cell, transform);
|
||||||
final Offset offset = MatrixUtils.getAsTranslation(transform);
|
final Offset? offset = MatrixUtils.getAsTranslation(transform);
|
||||||
if (offset != null) return rect.shift(-offset);
|
if (offset != null) return rect.shift(-offset);
|
||||||
}
|
}
|
||||||
return Rect.zero;
|
return Rect.zero;
|
||||||
@@ -799,31 +807,31 @@ class TableRowInkWell extends InkResponse {
|
|||||||
|
|
||||||
class _SortArrow extends StatefulWidget {
|
class _SortArrow extends StatefulWidget {
|
||||||
const _SortArrow({
|
const _SortArrow({
|
||||||
Key key,
|
Key? key,
|
||||||
this.visible,
|
this.visible,
|
||||||
this.down,
|
this.down,
|
||||||
this.duration,
|
this.duration,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
final bool visible;
|
final bool? visible;
|
||||||
|
|
||||||
final bool down;
|
final bool? down;
|
||||||
|
|
||||||
final Duration duration;
|
final Duration? duration;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_SortArrowState createState() => _SortArrowState();
|
_SortArrowState createState() => _SortArrowState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _SortArrowState extends State<_SortArrow> with TickerProviderStateMixin {
|
class _SortArrowState extends State<_SortArrow> with TickerProviderStateMixin {
|
||||||
AnimationController _opacityController;
|
AnimationController? _opacityController;
|
||||||
Animation<double> _opacityAnimation;
|
Animation<double>? _opacityAnimation;
|
||||||
|
|
||||||
AnimationController _orientationController;
|
AnimationController? _orientationController;
|
||||||
Animation<double> _orientationAnimation;
|
Animation<double>? _orientationAnimation;
|
||||||
double _orientationOffset = 0.0;
|
double _orientationOffset = 0.0;
|
||||||
|
|
||||||
bool _down;
|
bool? _down;
|
||||||
|
|
||||||
static final Animatable<double> _turnTween =
|
static final Animatable<double> _turnTween =
|
||||||
Tween<double>(begin: 0.0, end: math.pi)
|
Tween<double>(begin: 0.0, end: math.pi)
|
||||||
@@ -839,15 +847,16 @@ class _SortArrowState extends State<_SortArrow> with TickerProviderStateMixin {
|
|||||||
),
|
),
|
||||||
curve: Curves.fastOutSlowIn,
|
curve: Curves.fastOutSlowIn,
|
||||||
)..addListener(_rebuild);
|
)..addListener(_rebuild);
|
||||||
_opacityController.value = widget.visible ? 1.0 : 0.0;
|
_opacityController!.value = (widget.visible ?? false) ? 1.0 : 0.0;
|
||||||
_orientationController = AnimationController(
|
_orientationController = AnimationController(
|
||||||
duration: widget.duration,
|
duration: widget.duration,
|
||||||
vsync: this,
|
vsync: this,
|
||||||
);
|
);
|
||||||
_orientationAnimation = _orientationController.drive(_turnTween)
|
_orientationAnimation = _orientationController!.drive(_turnTween)
|
||||||
..addListener(_rebuild)
|
..addListener(_rebuild)
|
||||||
..addStatusListener(_resetOrientationAnimation);
|
..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() {
|
void _rebuild() {
|
||||||
@@ -858,9 +867,9 @@ class _SortArrowState extends State<_SortArrow> with TickerProviderStateMixin {
|
|||||||
|
|
||||||
void _resetOrientationAnimation(AnimationStatus status) {
|
void _resetOrientationAnimation(AnimationStatus status) {
|
||||||
if (status == AnimationStatus.completed) {
|
if (status == AnimationStatus.completed) {
|
||||||
assert(_orientationAnimation.value == math.pi);
|
assert(_orientationAnimation!.value == math.pi);
|
||||||
_orientationOffset += math.pi;
|
_orientationOffset += math.pi;
|
||||||
_orientationController.value =
|
_orientationController!.value =
|
||||||
0.0; // TODO(ianh): This triggers a pointless rebuild.
|
0.0; // TODO(ianh): This triggers a pointless rebuild.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -869,26 +878,26 @@ class _SortArrowState extends State<_SortArrow> with TickerProviderStateMixin {
|
|||||||
void didUpdateWidget(_SortArrow oldWidget) {
|
void didUpdateWidget(_SortArrow oldWidget) {
|
||||||
super.didUpdateWidget(oldWidget);
|
super.didUpdateWidget(oldWidget);
|
||||||
bool skipArrow = false;
|
bool skipArrow = false;
|
||||||
final bool newDown = widget.down ?? _down;
|
final bool newDown = widget.down ?? _down!;
|
||||||
if (oldWidget.visible != widget.visible) {
|
if (oldWidget.visible != widget.visible) {
|
||||||
if (widget.visible &&
|
if (widget.visible! &&
|
||||||
(_opacityController.status == AnimationStatus.dismissed)) {
|
(_opacityController!.status == AnimationStatus.dismissed)) {
|
||||||
_orientationController.stop();
|
_orientationController!.stop();
|
||||||
_orientationController.value = 0.0;
|
_orientationController!.value = 0.0;
|
||||||
_orientationOffset = newDown ? 0.0 : math.pi;
|
_orientationOffset = newDown ? 0.0 : math.pi;
|
||||||
skipArrow = true;
|
skipArrow = true;
|
||||||
}
|
}
|
||||||
if (widget.visible) {
|
if ((widget.visible ?? false)) {
|
||||||
_opacityController.forward();
|
_opacityController!.forward();
|
||||||
} else {
|
} else {
|
||||||
_opacityController.reverse();
|
_opacityController!.reverse();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((_down != newDown) && !skipArrow) {
|
if ((_down != newDown) && !skipArrow) {
|
||||||
if (_orientationController.status == AnimationStatus.dismissed) {
|
if (_orientationController!.status == AnimationStatus.dismissed) {
|
||||||
_orientationController.forward();
|
_orientationController?.forward();
|
||||||
} else {
|
} else {
|
||||||
_orientationController.reverse();
|
_orientationController?.reverse();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_down = newDown;
|
_down = newDown;
|
||||||
@@ -896,8 +905,8 @@ class _SortArrowState extends State<_SortArrow> with TickerProviderStateMixin {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_opacityController.dispose();
|
_opacityController?.dispose();
|
||||||
_orientationController.dispose();
|
_orientationController?.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -907,10 +916,10 @@ class _SortArrowState extends State<_SortArrow> with TickerProviderStateMixin {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Opacity(
|
return Opacity(
|
||||||
opacity: _opacityAnimation.value,
|
opacity: _opacityAnimation!.value,
|
||||||
child: Transform(
|
child: Transform(
|
||||||
transform:
|
transform:
|
||||||
Matrix4.rotationZ(_orientationOffset + _orientationAnimation.value)
|
Matrix4.rotationZ(_orientationOffset + _orientationAnimation!.value)
|
||||||
..setTranslationRaw(0.0, _arrowIconBaselineOffset, 0.0),
|
..setTranslationRaw(0.0, _arrowIconBaselineOffset, 0.0),
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
child: Icon(
|
child: Icon(
|
||||||
|
|||||||
Reference in New Issue
Block a user