feat: add CopyFunc to provider generator; add local solution provider; update dde data table style.

pull/2/head
DebuggerX 4 years ago
parent e819ba46e0
commit 094d74b746

@ -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

Loading…
Cancel
Save