feat: add CopyFunc to provider generator; add local solution provider; update dde data table style.
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
class ProviderModel {
|
||||
const ProviderModel();
|
||||
const ProviderModel({this.copyable = false});
|
||||
|
||||
final bool copyable;
|
||||
}
|
||||
|
||||
class ProviderModelProp {
|
||||
|
||||
@@ -37,6 +37,7 @@ class ProviderGenerator extends GeneratorForAnnotation<ProviderModel> {
|
||||
_genImports(className, needImports),
|
||||
_genClassDefine(element.displayName),
|
||||
_genNamedConstructors(element.constructors, element.displayName),
|
||||
_genCopyFunc(element.displayName, fields, annotation.read('copyable').boolValue),
|
||||
_genSetPropsFunc(fields),
|
||||
].whereNotNull();
|
||||
}
|
||||
@@ -71,6 +72,17 @@ String? _genNamedConstructors(List<ConstructorElement> constructors, String disp
|
||||
return _constructors.length > 0 ? _constructors.join('\n') : null;
|
||||
}
|
||||
|
||||
String? _genCopyFunc(String displayName, List<AnnotationField> fields, bool copyable) {
|
||||
if (!copyable) return null;
|
||||
return '''
|
||||
void copyFrom(${displayName} other) {
|
||||
bool changed = false;
|
||||
${fields.map((f) => 'if (other.${f.name}.diff(this.${f.name})) {this.${f.name} = other.${f.name}; changed = true; }').join('\n')}
|
||||
if (changed) notifyListeners();
|
||||
}
|
||||
''';
|
||||
}
|
||||
|
||||
String _genSetPropsFunc(List<AnnotationField> fields) => '''
|
||||
void setProps({
|
||||
${fields.map((f) => '${f.type.endsWith('?') ? '' : 'required '}${f.type} ${f.name},').join('\n')}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
export 'local_solutions_web.dart' if (dart.library.io) 'local_solutions_linux.dart';
|
||||
|
||||
import 'package:dde_gesture_manager/models/solution.dart';
|
||||
|
||||
abstract class LocalSolutionEntry {
|
||||
Solution solution;
|
||||
DateTime lastModifyTime;
|
||||
String path;
|
||||
|
||||
LocalSolutionEntry({
|
||||
required this.path,
|
||||
required this.solution,
|
||||
required this.lastModifyTime,
|
||||
});
|
||||
|
||||
save();
|
||||
}
|
||||
|
||||
abstract class LocalSolutionsInterface<T extends LocalSolutionEntry> {
|
||||
Future<List<T>> get solutionEntries;
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:dde_gesture_manager/builder/provider_annotation.dart';
|
||||
import 'package:dde_gesture_manager/extensions.dart';
|
||||
import 'package:dde_gesture_manager/models/solution.dart';
|
||||
import 'package:path/path.dart' show join;
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
|
||||
import 'local_solutions.dart';
|
||||
|
||||
export 'local_solutions.dart';
|
||||
|
||||
@ProviderModel()
|
||||
class LocalSolutions implements LocalSolutionsInterface<LocalSolutionEntryLinux> {
|
||||
LocalSolutions() {
|
||||
solutionEntries.then((value) => solutions = value);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<LocalSolutionEntryLinux>> get solutionEntries async {
|
||||
var _supportDirectory = await getApplicationSupportDirectory();
|
||||
var directory = Directory(join(_supportDirectory.path, 'solutions'));
|
||||
if (!directory.existsSync()) directory.createSync();
|
||||
directory.path.sout();
|
||||
return directory
|
||||
.list()
|
||||
.map<LocalSolutionEntryLinux?>((f) {
|
||||
LocalSolutionEntryLinux? entry;
|
||||
try {
|
||||
var content = File(f.path).readAsStringSync();
|
||||
entry = LocalSolutionEntryLinux(
|
||||
path: f.path, solution: Solution.parse(content), lastModifyTime: f.statSync().modified);
|
||||
} catch (e) {
|
||||
e.sout();
|
||||
}
|
||||
return entry;
|
||||
})
|
||||
.where((e) => e != null)
|
||||
.cast<LocalSolutionEntryLinux>()
|
||||
.toList();
|
||||
}
|
||||
|
||||
@ProviderModelProp()
|
||||
List<LocalSolutionEntry>? solutions;
|
||||
}
|
||||
|
||||
class LocalSolutionEntryLinux implements LocalSolutionEntry {
|
||||
@override
|
||||
String path;
|
||||
|
||||
@override
|
||||
Solution solution;
|
||||
|
||||
@override
|
||||
DateTime lastModifyTime;
|
||||
|
||||
LocalSolutionEntryLinux({
|
||||
required this.path,
|
||||
required this.solution,
|
||||
required this.lastModifyTime,
|
||||
});
|
||||
|
||||
@override
|
||||
save() {
|
||||
// TODO: implement save
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export 'local_solutions_web.provider.dart' if (dart.library.io) 'local_solutions_linux.provider.dart';
|
||||
@@ -0,0 +1,67 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:dde_gesture_manager/builder/provider_annotation.dart';
|
||||
import 'package:dde_gesture_manager/models/solution.dart';
|
||||
import 'package:dde_gesture_manager/extensions.dart';
|
||||
import 'dart:html';
|
||||
|
||||
import 'local_solutions.dart';
|
||||
export 'local_solutions.dart';
|
||||
|
||||
@ProviderModel()
|
||||
class LocalSolutions implements LocalSolutionsInterface<LocalSolutionEntryWeb> {
|
||||
LocalSolutions() {
|
||||
solutionEntries.then((value) => solutions = value);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<LocalSolutionEntryWeb>> get solutionEntries async {
|
||||
return window.localStorage.keys
|
||||
.map<LocalSolutionEntryWeb?>((key) {
|
||||
if (key.startsWith('solutions.')) {
|
||||
LocalSolutionEntryWeb? entry;
|
||||
try {
|
||||
var content = window.localStorage[key] ?? '';
|
||||
var solutionJson = json.decode(content);
|
||||
entry = LocalSolutionEntryWeb(
|
||||
path: key,
|
||||
solution: Solution.parse(solutionJson),
|
||||
lastModifyTime: DateTime.parse(solutionJson['modified_at']),
|
||||
);
|
||||
} catch (e) {
|
||||
e.sout();
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
})
|
||||
.where((e) => e != null)
|
||||
.cast<LocalSolutionEntryWeb>()
|
||||
.toList();
|
||||
}
|
||||
|
||||
@ProviderModelProp()
|
||||
List<LocalSolutionEntry>? solutions;
|
||||
}
|
||||
|
||||
class LocalSolutionEntryWeb implements LocalSolutionEntry {
|
||||
@override
|
||||
String path;
|
||||
|
||||
@override
|
||||
Solution solution;
|
||||
|
||||
@override
|
||||
DateTime lastModifyTime;
|
||||
|
||||
LocalSolutionEntryWeb({
|
||||
required this.path,
|
||||
required this.solution,
|
||||
required this.lastModifyTime,
|
||||
});
|
||||
|
||||
@override
|
||||
save() {
|
||||
// TODO: implement save
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ import 'dart:convert';
|
||||
import 'package:dde_gesture_manager/builder/provider_annotation.dart';
|
||||
import 'package:dde_gesture_manager/utils/helper.dart';
|
||||
|
||||
@ProviderModel()
|
||||
@ProviderModel(copyable: true)
|
||||
class Solution {
|
||||
@ProviderModelProp()
|
||||
String? name;
|
||||
@@ -45,7 +45,7 @@ enum GestureType {
|
||||
shortcut,
|
||||
}
|
||||
|
||||
@ProviderModel()
|
||||
@ProviderModel(copyable: true)
|
||||
class GestureProp {
|
||||
@ProviderModelProp()
|
||||
Gesture? gesture;
|
||||
|
||||
@@ -30,7 +30,9 @@ class GestureEditor extends StatelessWidget {
|
||||
Center(
|
||||
child: Text('${LocaleKeys.gesture_editor_gestures}.${H.getGestureName(gesture.gesture)}').tr(),
|
||||
),
|
||||
Text('${LocaleKeys.gesture_editor_directions}.${H.getGestureDirectionName(gesture.direction)}').tr(),
|
||||
Center(
|
||||
child: Text('${LocaleKeys.gesture_editor_directions}.${H.getGestureDirectionName(gesture.direction)}')
|
||||
.tr()),
|
||||
Center(
|
||||
child: Text('${gesture.fingers}'),
|
||||
),
|
||||
@@ -126,15 +128,15 @@ class GestureEditor extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
dataRowColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.hovered)) return Colors.grey;
|
||||
if (states.contains(MaterialState.selected)) return Colors.green;
|
||||
if (states.contains(MaterialState.hovered)) return context.t.dialogBackgroundColor;
|
||||
if (states.contains(MaterialState.selected)) return Colors.blueAccent;
|
||||
return null;
|
||||
}),
|
||||
columns: [
|
||||
DDataColumn(label: Text(LocaleKeys.gesture_editor_gesture.tr())),
|
||||
DDataColumn(label: Text(LocaleKeys.gesture_editor_direction.tr())),
|
||||
DDataColumn(label: Text(LocaleKeys.gesture_editor_fingers.tr())),
|
||||
DDataColumn(label: Text(LocaleKeys.gesture_editor_type.tr())),
|
||||
DDataColumn(label: Text(LocaleKeys.gesture_editor_gesture.tr()), center: true),
|
||||
DDataColumn(label: Text(LocaleKeys.gesture_editor_direction.tr()), center: true),
|
||||
DDataColumn(label: Text(LocaleKeys.gesture_editor_fingers.tr()), center: true),
|
||||
DDataColumn(label: Text(LocaleKeys.gesture_editor_type.tr()), center: true),
|
||||
DDataColumn(label: Text(LocaleKeys.gesture_editor_command.tr())),
|
||||
DDataColumn(label: Text(LocaleKeys.gesture_editor_remark.tr())),
|
||||
],
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:dde_gesture_manager/extensions.dart';
|
||||
import 'package:dde_gesture_manager/models/local_solutions_provider.dart';
|
||||
import 'package:dde_gesture_manager/models/solution.provider.dart';
|
||||
import 'package:dde_gesture_manager/pages/content.dart';
|
||||
import 'package:dde_gesture_manager/pages/footer.dart';
|
||||
@@ -65,6 +66,7 @@ class _HomePageState extends State<HomePage> {
|
||||
}
|
||||
''')),
|
||||
ChangeNotifierProvider(create: (context) => GesturePropProvider.empty()),
|
||||
ChangeNotifierProvider(create: (context) => LocalSolutionsProvider(),lazy: false),
|
||||
],
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
|
||||
@@ -1,20 +1,45 @@
|
||||
import 'package:dde_gesture_manager/constants/constants.dart';
|
||||
import 'package:dde_gesture_manager/extensions.dart';
|
||||
import 'package:dde_gesture_manager/models/content_layout.provider.dart';
|
||||
import 'package:dde_gesture_manager/models/local_solutions_provider.dart';
|
||||
import 'package:dde_gesture_manager/models/solution.provider.dart';
|
||||
import 'package:dde_gesture_manager/widgets/dde_button.dart';
|
||||
import 'package:flutter/animation.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/painting.dart';
|
||||
|
||||
class LocalManager extends StatelessWidget {
|
||||
class LocalManager extends StatefulWidget {
|
||||
const LocalManager({
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<LocalManager> createState() => _LocalManagerState();
|
||||
}
|
||||
|
||||
class _LocalManagerState extends State<LocalManager> {
|
||||
late ScrollController _scrollController;
|
||||
int? _hoveringIndex;
|
||||
int? _selectedIndex;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_scrollController = ScrollController();
|
||||
}
|
||||
|
||||
Color _getItemBackgroundColor(int index) {
|
||||
Color _color = index % 2 == 0 ? context.t.scaffoldBackgroundColor : context.t.backgroundColor;
|
||||
if (index == _hoveringIndex) _color = context.t.scaffoldBackgroundColor;
|
||||
if (index == _selectedIndex) _color = Colors.blueAccent;
|
||||
return _color;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var isOpen = context.watch<ContentLayoutProvider>().localManagerOpened == true;
|
||||
var localSolutions = context.watch<LocalSolutionsProvider>().solutions ?? [];
|
||||
return AnimatedContainer(
|
||||
duration: mediumDuration,
|
||||
curve: Curves.easeInOut,
|
||||
@@ -57,6 +82,57 @@ class LocalManager extends StatelessWidget {
|
||||
),
|
||||
],
|
||||
),
|
||||
Flexible(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Flexible(
|
||||
child: ListView.builder(
|
||||
controller: _scrollController,
|
||||
itemBuilder: (context, index) => GestureDetector(
|
||||
onDoubleTap: () {
|
||||
context.read<SolutionProvider>().copyFrom(localSolutions[index].solution);
|
||||
setState(() {
|
||||
_selectedIndex = index;
|
||||
});
|
||||
},
|
||||
onTap: () {
|
||||
setState(() {
|
||||
_selectedIndex = index;
|
||||
});
|
||||
},
|
||||
child: MouseRegion(
|
||||
cursor: SystemMouseCursors.click,
|
||||
onEnter: (_) {
|
||||
setState(() {
|
||||
_hoveringIndex = index;
|
||||
});
|
||||
},
|
||||
child: Container(
|
||||
color: _getItemBackgroundColor(index),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(right: 12.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(localSolutions[index].solution.name ?? ''),
|
||||
Text('456'),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
itemCount: localSolutions.length,
|
||||
),
|
||||
),
|
||||
Container(
|
||||
height: 150,
|
||||
color: Colors.black,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -30,6 +30,7 @@ class DDataColumn {
|
||||
this.tooltip,
|
||||
this.numeric = false,
|
||||
this.onSort,
|
||||
this.center = false,
|
||||
}) : assert(label != null);
|
||||
|
||||
/// The column heading.
|
||||
@@ -66,6 +67,8 @@ class DDataColumn {
|
||||
final DataColumnSortCallback? onSort;
|
||||
|
||||
bool get _debugInteractive => onSort != null;
|
||||
|
||||
final bool center;
|
||||
}
|
||||
|
||||
/// Row configuration and cell data for a [DataTable].
|
||||
@@ -735,68 +738,6 @@ class _DDataTableState extends State<DDataTable> {
|
||||
widget.rows.any((DDataRow row) => row._debugInteractive);
|
||||
}
|
||||
|
||||
void _handleSelectAll(bool? checked, bool someChecked) {
|
||||
// If some checkboxes are checked, all checkboxes are selected. Otherwise,
|
||||
// use the new checked value but default to false if it's null.
|
||||
final bool effectiveChecked = someChecked || (checked ?? false);
|
||||
if (widget.onSelectAll != null) {
|
||||
widget.onSelectAll!(effectiveChecked);
|
||||
} else {
|
||||
for (final DDataRow row in widget.rows) {
|
||||
if (row.onSelectChanged != null && row.selected != effectiveChecked) row.onSelectChanged!(effectiveChecked);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Widget _buildCheckbox({
|
||||
required BuildContext context,
|
||||
required bool? checked,
|
||||
required VoidCallback? onRowTap,
|
||||
required ValueChanged<bool?>? onCheckboxChanged,
|
||||
required MaterialStateProperty<Color?>? overlayColor,
|
||||
required bool tristate,
|
||||
}) {
|
||||
final ThemeData themeData = Theme.of(context);
|
||||
final double effectiveHorizontalMargin =
|
||||
widget.horizontalMargin ?? themeData.dataTableTheme.horizontalMargin ?? DDataTable._horizontalMargin;
|
||||
final double effectiveCheckboxHorizontalMarginStart = widget.checkboxHorizontalMargin ??
|
||||
themeData.dataTableTheme.checkboxHorizontalMargin ??
|
||||
effectiveHorizontalMargin;
|
||||
final double effectiveCheckboxHorizontalMarginEnd = widget.checkboxHorizontalMargin ??
|
||||
themeData.dataTableTheme.checkboxHorizontalMargin ??
|
||||
effectiveHorizontalMargin / 2.0;
|
||||
Widget contents = Semantics(
|
||||
container: true,
|
||||
child: Padding(
|
||||
padding: EdgeInsetsDirectional.only(
|
||||
start: effectiveCheckboxHorizontalMarginStart,
|
||||
end: effectiveCheckboxHorizontalMarginEnd,
|
||||
),
|
||||
child: Center(
|
||||
child: Checkbox(
|
||||
// TODO(per): Remove when Checkbox has theme, https://github.com/flutter/flutter/issues/53420.
|
||||
activeColor: themeData.colorScheme.primary,
|
||||
checkColor: themeData.colorScheme.onPrimary,
|
||||
value: checked,
|
||||
onChanged: onCheckboxChanged,
|
||||
tristate: tristate,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
if (onRowTap != null) {
|
||||
contents = TableRowInkWell(
|
||||
onTap: onRowTap,
|
||||
overlayColor: overlayColor,
|
||||
child: contents,
|
||||
);
|
||||
}
|
||||
return TableCell(
|
||||
verticalAlignment: TableCellVerticalAlignment.fill,
|
||||
child: contents,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildHeadingCell({
|
||||
required BuildContext context,
|
||||
required EdgeInsetsGeometry padding,
|
||||
@@ -806,11 +747,13 @@ class _DDataTableState extends State<DDataTable> {
|
||||
required VoidCallback? onSort,
|
||||
required bool sorted,
|
||||
required bool ascending,
|
||||
required bool center,
|
||||
required MaterialStateProperty<Color?>? overlayColor,
|
||||
}) {
|
||||
final ThemeData themeData = Theme.of(context);
|
||||
label = Row(
|
||||
textDirection: numeric ? TextDirection.rtl : null,
|
||||
mainAxisAlignment: center ? MainAxisAlignment.spaceAround : MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
label,
|
||||
if (onSort != null) ...<Widget>[
|
||||
@@ -935,24 +878,13 @@ class _DDataTableState extends State<DDataTable> {
|
||||
);
|
||||
final bool anyRowSelectable = widget.rows.any((DDataRow row) => row.onSelectChanged != null);
|
||||
final bool displayCheckboxColumn = widget.showCheckboxColumn && anyRowSelectable;
|
||||
final Iterable<DDataRow> rowsWithCheckbox =
|
||||
displayCheckboxColumn ? widget.rows.where((DDataRow row) => row.onSelectChanged != null) : <DDataRow>[];
|
||||
final Iterable<DDataRow> rowsChecked = rowsWithCheckbox.where((DDataRow row) => row.selected);
|
||||
final bool allChecked = displayCheckboxColumn && rowsChecked.length == rowsWithCheckbox.length;
|
||||
final bool anyChecked = displayCheckboxColumn && rowsChecked.isNotEmpty;
|
||||
final bool someChecked = anyChecked && !allChecked;
|
||||
final double effectiveHorizontalMargin =
|
||||
widget.horizontalMargin ?? theme.dataTableTheme.horizontalMargin ?? DDataTable._horizontalMargin;
|
||||
final double effectiveCheckboxHorizontalMarginStart =
|
||||
widget.checkboxHorizontalMargin ?? theme.dataTableTheme.checkboxHorizontalMargin ?? effectiveHorizontalMargin;
|
||||
final double effectiveCheckboxHorizontalMarginEnd = widget.checkboxHorizontalMargin ??
|
||||
theme.dataTableTheme.checkboxHorizontalMargin ??
|
||||
effectiveHorizontalMargin / 2.0;
|
||||
final double effectiveColumnSpacing =
|
||||
widget.columnSpacing ?? theme.dataTableTheme.columnSpacing ?? DDataTable._columnSpacing;
|
||||
|
||||
final List<TableColumnWidth> tableColumns = List<TableColumnWidth>.filled(
|
||||
widget.columns.length + (displayCheckboxColumn ? 1 : 0), const _NullTableColumnWidth());
|
||||
widget.columns.length, const _NullTableColumnWidth());
|
||||
final List<TableRow> tableRows = List<TableRow>.generate(
|
||||
widget.rows.length + 1, // the +1 is for the header row
|
||||
(int index) {
|
||||
@@ -989,34 +921,6 @@ class _DDataTableState extends State<DDataTable> {
|
||||
int rowIndex;
|
||||
|
||||
int displayColumnIndex = 0;
|
||||
if (displayCheckboxColumn) {
|
||||
tableColumns[0] = FixedColumnWidth(0);
|
||||
tableRows[0].children![0] = RectGetter.defaultKey(child: Container());
|
||||
// tableColumns[0] = FixedColumnWidth(
|
||||
// effectiveCheckboxHorizontalMarginStart + Checkbox.width + effectiveCheckboxHorizontalMarginEnd);
|
||||
// tableRows[0].children![0] = _buildCheckbox(
|
||||
// context: context,
|
||||
// checked: someChecked ? null : allChecked,
|
||||
// onRowTap: null,
|
||||
// onCheckboxChanged: (bool? checked) => _handleSelectAll(checked, someChecked),
|
||||
// overlayColor: null,
|
||||
// tristate: true,
|
||||
// );
|
||||
rowIndex = 1;
|
||||
for (final DDataRow row in widget.rows) {
|
||||
// tableRows[rowIndex].children![0] = _buildCheckbox(
|
||||
// context: context,
|
||||
// checked: row.selected,
|
||||
// onRowTap: row.onSelectChanged == null ? null : () => row.onSelectChanged?.call(!row.selected),
|
||||
// onCheckboxChanged: row.onSelectChanged,
|
||||
// overlayColor: row.color ?? effectiveDataRowColor,
|
||||
// tristate: false,
|
||||
// );
|
||||
tableRows[rowIndex].children![0] = Container();
|
||||
rowIndex += 1;
|
||||
}
|
||||
displayColumnIndex += 1;
|
||||
}
|
||||
|
||||
for (int dataColumnIndex = 0; dataColumnIndex < widget.columns.length; dataColumnIndex += 1) {
|
||||
final DDataColumn column = widget.columns[dataColumnIndex];
|
||||
@@ -1060,6 +964,7 @@ class _DDataTableState extends State<DDataTable> {
|
||||
sorted: dataColumnIndex == widget.sortColumnIndex,
|
||||
ascending: widget.sortAscending,
|
||||
overlayColor: effectiveHeadingRowColor,
|
||||
center: column.center,
|
||||
);
|
||||
rowIndex = 1;
|
||||
for (final DDataRow row in widget.rows) {
|
||||
@@ -1125,11 +1030,11 @@ class _DDataTableState extends State<DDataTable> {
|
||||
fit: StackFit.passthrough,
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: _headersRect?.first.height ?? 0),
|
||||
padding: EdgeInsets.only(top: _headersRect?.last.height ?? 0),
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.vertical,
|
||||
child: Transform.translate(
|
||||
offset: Offset(0, -(_headersRect?.first.height ?? 0)),
|
||||
offset: Offset(0, -(_headersRect?.last.height ?? 0)),
|
||||
child: Table(
|
||||
columnWidths: tableColumns.asMap(),
|
||||
children: tableRows,
|
||||
|
||||
@@ -34,6 +34,7 @@ dependencies:
|
||||
easy_localization: ^3.0.0
|
||||
glass_kit: ^2.0.1
|
||||
rect_getter: ^1.0.0
|
||||
path_provider: ^2.0.5
|
||||
xdg_directories_web:
|
||||
path: 3rd_party/xdg_directories_web
|
||||
|
||||
|
||||
Reference in New Issue
Block a user