mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
fix: cell focus issue on windows (#2880)
* fix: cell focus issue on windows * fix: try to fix * fix: cell focus not working on Windows platform there are multiple text cells * docs: add documentation * chore: adjust row detail page ui * test: add test * test: fix test --------- Co-authored-by: vedon <vedon.fu@gmail.com>
This commit is contained in:
parent
f1bfcb6066
commit
a29c8ab27a
@ -1,4 +1,5 @@
|
|||||||
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
|
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
|
||||||
|
import 'package:appflowy_backend/protobuf/flowy-folder2/protobuf.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:integration_test/integration_test.dart';
|
import 'package:integration_test/integration_test.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
@ -47,6 +48,44 @@ void main() {
|
|||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Makesure the text cells are filled with the right content when there are
|
||||||
|
// multiple text cell
|
||||||
|
testWidgets('edit multiple text cells', (tester) async {
|
||||||
|
await tester.initializeAppFlowy();
|
||||||
|
await tester.tapGoButton();
|
||||||
|
await tester.createNewPageWithName(ViewLayoutPB.Grid, 'my grid');
|
||||||
|
await tester.createField(FieldType.RichText, 'description');
|
||||||
|
|
||||||
|
await tester.editCell(
|
||||||
|
rowIndex: 0,
|
||||||
|
fieldType: FieldType.RichText,
|
||||||
|
input: 'hello',
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.editCell(
|
||||||
|
rowIndex: 0,
|
||||||
|
fieldType: FieldType.RichText,
|
||||||
|
input: 'world',
|
||||||
|
cellIndex: 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.assertCellContent(
|
||||||
|
rowIndex: 0,
|
||||||
|
fieldType: FieldType.RichText,
|
||||||
|
content: 'hello',
|
||||||
|
cellIndex: 0,
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.assertCellContent(
|
||||||
|
rowIndex: 0,
|
||||||
|
fieldType: FieldType.RichText,
|
||||||
|
content: 'world',
|
||||||
|
cellIndex: 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
});
|
||||||
|
|
||||||
testWidgets('edit number cell', (tester) async {
|
testWidgets('edit number cell', (tester) async {
|
||||||
await tester.initializeAppFlowy();
|
await tester.initializeAppFlowy();
|
||||||
await tester.tapGoButton();
|
await tester.tapGoButton();
|
||||||
|
@ -108,22 +108,26 @@ extension AppFlowyDatabaseTest on WidgetTester {
|
|||||||
required int rowIndex,
|
required int rowIndex,
|
||||||
required FieldType fieldType,
|
required FieldType fieldType,
|
||||||
required String input,
|
required String input,
|
||||||
|
int cellIndex = 0,
|
||||||
}) async {
|
}) async {
|
||||||
final cell = cellFinder(rowIndex, fieldType);
|
final cell = cellFinder(rowIndex, fieldType, cellIndex: cellIndex);
|
||||||
|
|
||||||
expect(cell, findsOneWidget);
|
expect(cell, findsOneWidget);
|
||||||
await enterText(cell, input);
|
await enterText(cell, input);
|
||||||
await pumpAndSettle();
|
await pumpAndSettle();
|
||||||
}
|
}
|
||||||
|
|
||||||
Finder cellFinder(int rowIndex, FieldType fieldType) {
|
///
|
||||||
|
Finder cellFinder(int rowIndex, FieldType fieldType, {int cellIndex = 0}) {
|
||||||
final findRow = find.byType(GridRow, skipOffstage: false);
|
final findRow = find.byType(GridRow, skipOffstage: false);
|
||||||
final findCell = finderForFieldType(fieldType);
|
final findCell = finderForFieldType(fieldType);
|
||||||
return find.descendant(
|
return find
|
||||||
|
.descendant(
|
||||||
of: findRow.at(rowIndex),
|
of: findRow.at(rowIndex),
|
||||||
matching: findCell,
|
matching: findCell,
|
||||||
skipOffstage: false,
|
skipOffstage: false,
|
||||||
);
|
)
|
||||||
|
.at(cellIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> tapCheckboxCellInGrid({
|
Future<void> tapCheckboxCellInGrid({
|
||||||
@ -173,8 +177,9 @@ extension AppFlowyDatabaseTest on WidgetTester {
|
|||||||
required int rowIndex,
|
required int rowIndex,
|
||||||
required FieldType fieldType,
|
required FieldType fieldType,
|
||||||
required String content,
|
required String content,
|
||||||
|
int cellIndex = 0,
|
||||||
}) async {
|
}) async {
|
||||||
final findCell = cellFinder(rowIndex, fieldType);
|
final findCell = cellFinder(rowIndex, fieldType, cellIndex: cellIndex);
|
||||||
final findContent = find.descendant(
|
final findContent = find.descendant(
|
||||||
of: findCell,
|
of: findCell,
|
||||||
matching: find.text(content),
|
matching: find.text(content),
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||||
import 'package:appflowy/plugins/database_view/application/row/row_service.dart';
|
import 'package:appflowy/plugins/database_view/application/row/row_service.dart';
|
||||||
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/toolbar/grid_setting_bar.dart';
|
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/toolbar/grid_setting_bar.dart';
|
||||||
@ -241,7 +243,40 @@ class _GridRows extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
return ScrollConfiguration(
|
return ScrollConfiguration(
|
||||||
behavior: behavior,
|
behavior: behavior,
|
||||||
child: ReorderableListView.builder(
|
child: _renderList(context, state, rowInfos),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _renderList(
|
||||||
|
BuildContext context,
|
||||||
|
GridState state,
|
||||||
|
List<RowInfo> rowInfos,
|
||||||
|
) {
|
||||||
|
if (Platform.isWindows) {
|
||||||
|
// Workaround: On Windows, the focusing of the text cell is not working
|
||||||
|
// properly when the list is reorderable. So using the ListView instead.
|
||||||
|
return ListView.builder(
|
||||||
|
controller: scrollController.verticalController,
|
||||||
|
itemCount: rowInfos.length + 1, // the extra item is the footer
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
if (index < rowInfos.length) {
|
||||||
|
final rowInfo = rowInfos[index];
|
||||||
|
return _renderRow(
|
||||||
|
context,
|
||||||
|
rowInfo.rowId,
|
||||||
|
isDraggable: false,
|
||||||
|
index: index,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return const GridRowBottomBar(key: Key('gridFooter'));
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return ReorderableListView.builder(
|
||||||
/// TODO(Xazin): Resolve inconsistent scrollbar behavior
|
/// TODO(Xazin): Resolve inconsistent scrollbar behavior
|
||||||
/// This is a workaround related to
|
/// This is a workaround related to
|
||||||
/// https://github.com/flutter/flutter/issues/25652
|
/// https://github.com/flutter/flutter/issues/25652
|
||||||
@ -253,14 +288,11 @@ class _GridRows extends StatelessWidget {
|
|||||||
child: Opacity(opacity: .5, child: child),
|
child: Opacity(opacity: .5, child: child),
|
||||||
),
|
),
|
||||||
onReorder: (fromIndex, newIndex) {
|
onReorder: (fromIndex, newIndex) {
|
||||||
final toIndex =
|
final toIndex = newIndex > fromIndex ? newIndex - 1 : newIndex;
|
||||||
newIndex > fromIndex ? newIndex - 1 : newIndex;
|
|
||||||
if (fromIndex == toIndex) {
|
if (fromIndex == toIndex) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
context
|
context.read<GridBloc>().add(GridEvent.moveRow(fromIndex, toIndex));
|
||||||
.read<GridBloc>()
|
|
||||||
.add(GridEvent.moveRow(fromIndex, toIndex));
|
|
||||||
},
|
},
|
||||||
itemCount: rowInfos.length + 1, // the extra item is the footer
|
itemCount: rowInfos.length + 1, // the extra item is the footer
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
@ -275,13 +307,9 @@ class _GridRows extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
return const GridRowBottomBar(key: Key('gridFooter'));
|
return const GridRowBottomBar(key: Key('gridFooter'));
|
||||||
},
|
},
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Widget _renderRow(
|
Widget _renderRow(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
|
@ -138,7 +138,6 @@ class _OptionNameTextField extends StatelessWidget {
|
|||||||
return FlowyTextField(
|
return FlowyTextField(
|
||||||
autoFocus: autoFocus,
|
autoFocus: autoFocus,
|
||||||
text: name,
|
text: name,
|
||||||
maxLength: 30,
|
|
||||||
submitOnLeave: true,
|
submitOnLeave: true,
|
||||||
onSubmitted: (newName) {
|
onSubmitted: (newName) {
|
||||||
if (name != newName) {
|
if (name != newName) {
|
||||||
|
@ -103,11 +103,11 @@ class BlankCell extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
abstract class CellEditable {
|
abstract class CellEditable {
|
||||||
GridCellFocusListener get beginFocus;
|
RequestFocusListener get requestFocus;
|
||||||
|
|
||||||
ValueNotifier<bool> get onCellFocus;
|
ValueNotifier<bool> get onCellFocus;
|
||||||
|
|
||||||
ValueNotifier<bool> get onCellEditing;
|
// ValueNotifier<bool> get onCellEditing;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef AccessoryBuilder = List<GridCellAccessoryBuilder> Function(
|
typedef AccessoryBuilder = List<GridCellAccessoryBuilder> Function(
|
||||||
@ -125,11 +125,7 @@ abstract class CellAccessory extends Widget {
|
|||||||
|
|
||||||
abstract class GridCellWidget extends StatefulWidget
|
abstract class GridCellWidget extends StatefulWidget
|
||||||
implements CellAccessory, CellEditable, CellShortcuts {
|
implements CellAccessory, CellEditable, CellShortcuts {
|
||||||
GridCellWidget({Key? key}) : super(key: key) {
|
GridCellWidget({super.key});
|
||||||
onCellEditing.addListener(() {
|
|
||||||
onCellFocus.value = onCellEditing.value;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
final ValueNotifier<bool> onCellFocus = ValueNotifier<bool>(false);
|
final ValueNotifier<bool> onCellFocus = ValueNotifier<bool>(false);
|
||||||
@ -138,8 +134,8 @@ abstract class GridCellWidget extends StatefulWidget
|
|||||||
@override
|
@override
|
||||||
ValueNotifier<bool> get onAccessoryHover => onCellFocus;
|
ValueNotifier<bool> get onAccessoryHover => onCellFocus;
|
||||||
|
|
||||||
@override
|
// @override
|
||||||
final ValueNotifier<bool> onCellEditing = ValueNotifier<bool>(false);
|
// final ValueNotifier<bool> onCellEditing = ValueNotifier<bool>(false);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<GridCellAccessoryBuilder> Function(
|
List<GridCellAccessoryBuilder> Function(
|
||||||
@ -147,7 +143,7 @@ abstract class GridCellWidget extends StatefulWidget
|
|||||||
)? get accessoryBuilder => null;
|
)? get accessoryBuilder => null;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
final GridCellFocusListener beginFocus = GridCellFocusListener();
|
final RequestFocusListener requestFocus = RequestFocusListener();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
final Map<CellKeyboardKey, CellKeyboardAction> shortcutHandlers = {};
|
final Map<CellKeyboardKey, CellKeyboardAction> shortcutHandlers = {};
|
||||||
@ -156,7 +152,7 @@ abstract class GridCellWidget extends StatefulWidget
|
|||||||
abstract class GridCellState<T extends GridCellWidget> extends State<T> {
|
abstract class GridCellState<T extends GridCellWidget> extends State<T> {
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
widget.beginFocus.setListener(() => requestBeginFocus());
|
widget.requestFocus.setListener(requestBeginFocus);
|
||||||
widget.shortcutHandlers[CellKeyboardKey.onCopy] = () => onCopy();
|
widget.shortcutHandlers[CellKeyboardKey.onCopy] = () => onCopy();
|
||||||
widget.shortcutHandlers[CellKeyboardKey.onInsert] = () {
|
widget.shortcutHandlers[CellKeyboardKey.onInsert] = () {
|
||||||
Clipboard.getData("text/plain").then((data) {
|
Clipboard.getData("text/plain").then((data) {
|
||||||
@ -172,17 +168,18 @@ abstract class GridCellState<T extends GridCellWidget> extends State<T> {
|
|||||||
@override
|
@override
|
||||||
void didUpdateWidget(covariant T oldWidget) {
|
void didUpdateWidget(covariant T oldWidget) {
|
||||||
if (oldWidget != this) {
|
if (oldWidget != this) {
|
||||||
widget.beginFocus.setListener(() => requestBeginFocus());
|
widget.requestFocus.setListener(requestBeginFocus);
|
||||||
}
|
}
|
||||||
super.didUpdateWidget(oldWidget);
|
super.didUpdateWidget(oldWidget);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
widget.beginFocus.removeAllListener();
|
widget.requestFocus.removeAllListener();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Subclass can override this method to request focus.
|
||||||
void requestBeginFocus();
|
void requestBeginFocus();
|
||||||
|
|
||||||
String? onCopy() => null;
|
String? onCopy() => null;
|
||||||
@ -190,9 +187,9 @@ abstract class GridCellState<T extends GridCellWidget> extends State<T> {
|
|||||||
void onInsert(String value) {}
|
void onInsert(String value) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class GridFocusNodeCellState<T extends GridCellWidget>
|
abstract class GridEditableTextCell<T extends GridCellWidget>
|
||||||
extends GridCellState<T> {
|
extends GridCellState<T> {
|
||||||
SingleListenerFocusNode focusNode = SingleListenerFocusNode();
|
SingleListenerFocusNode get focusNode;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@ -226,9 +223,9 @@ abstract class GridFocusNodeCellState<T extends GridCellWidget>
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _listenOnFocusNodeChanged() {
|
void _listenOnFocusNodeChanged() {
|
||||||
widget.onCellEditing.value = focusNode.hasFocus;
|
widget.onCellFocus.value = focusNode.hasFocus;
|
||||||
focusNode.setListener(() {
|
focusNode.setListener(() {
|
||||||
widget.onCellEditing.value = focusNode.hasFocus;
|
widget.onCellFocus.value = focusNode.hasFocus;
|
||||||
focusChanged();
|
focusChanged();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -236,7 +233,7 @@ abstract class GridFocusNodeCellState<T extends GridCellWidget>
|
|||||||
Future<void> focusChanged() async {}
|
Future<void> focusChanged() async {}
|
||||||
}
|
}
|
||||||
|
|
||||||
class GridCellFocusListener extends ChangeNotifier {
|
class RequestFocusListener extends ChangeNotifier {
|
||||||
VoidCallback? _listener;
|
VoidCallback? _listener;
|
||||||
|
|
||||||
void setListener(VoidCallback listener) {
|
void setListener(VoidCallback listener) {
|
||||||
|
@ -51,8 +51,8 @@ class CellContainer extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
behavior: HitTestBehavior.translucent,
|
behavior: HitTestBehavior.opaque,
|
||||||
onTap: () => child.beginFocus.notify(),
|
onTap: () => child.requestFocus.notify(),
|
||||||
child: Container(
|
child: Container(
|
||||||
constraints: BoxConstraints(maxWidth: width, minHeight: 46),
|
constraints: BoxConstraints(maxWidth: width, minHeight: 46),
|
||||||
decoration: _makeBoxDecoration(context, isFocus),
|
decoration: _makeBoxDecoration(context, isFocus),
|
||||||
|
@ -45,14 +45,14 @@ class GridChecklistCellState extends GridCellState<GridChecklistCell> {
|
|||||||
triggerActions: PopoverTriggerFlags.none,
|
triggerActions: PopoverTriggerFlags.none,
|
||||||
popupBuilder: (BuildContext context) {
|
popupBuilder: (BuildContext context) {
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
widget.onCellEditing.value = true;
|
widget.onCellFocus.value = true;
|
||||||
});
|
});
|
||||||
return GridChecklistCellEditor(
|
return GridChecklistCellEditor(
|
||||||
cellController:
|
cellController:
|
||||||
widget.cellControllerBuilder.build() as ChecklistCellController,
|
widget.cellControllerBuilder.build() as ChecklistCellController,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
onClose: () => widget.onCellEditing.value = false,
|
onClose: () => widget.onCellFocus.value = false,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: GridSize.cellContentInsets,
|
padding: GridSize.cellContentInsets,
|
||||||
child: BlocBuilder<ChecklistCardCellBloc, ChecklistCellState>(
|
child: BlocBuilder<ChecklistCardCellBloc, ChecklistCellState>(
|
||||||
|
@ -90,11 +90,11 @@ class _DateCellState extends GridCellState<GridDateCell> {
|
|||||||
return DateCellEditor(
|
return DateCellEditor(
|
||||||
cellController: widget.cellControllerBuilder.build()
|
cellController: widget.cellControllerBuilder.build()
|
||||||
as DateCellController,
|
as DateCellController,
|
||||||
onDismissed: () => widget.onCellEditing.value = false,
|
onDismissed: () => widget.onCellFocus.value = false,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
onClose: () {
|
onClose: () {
|
||||||
widget.onCellEditing.value = false;
|
widget.onCellFocus.value = false;
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -115,7 +115,7 @@ class _DateCellState extends GridCellState<GridDateCell> {
|
|||||||
_popover.show();
|
_popover.show();
|
||||||
|
|
||||||
if (widget.editable) {
|
if (widget.editable) {
|
||||||
widget.onCellEditing.value = true;
|
widget.onCellFocus.value = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,13 +16,16 @@ class GridNumberCell extends GridCellWidget {
|
|||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
GridFocusNodeCellState<GridNumberCell> createState() => _NumberCellState();
|
GridEditableTextCell<GridNumberCell> createState() => _NumberCellState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _NumberCellState extends GridFocusNodeCellState<GridNumberCell> {
|
class _NumberCellState extends GridEditableTextCell<GridNumberCell> {
|
||||||
late NumberCellBloc _cellBloc;
|
late NumberCellBloc _cellBloc;
|
||||||
late TextEditingController _controller;
|
late TextEditingController _controller;
|
||||||
|
|
||||||
|
@override
|
||||||
|
SingleListenerFocusNode focusNode = SingleListenerFocusNode();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
final cellController =
|
final cellController =
|
||||||
|
@ -62,7 +62,7 @@ class _SingleSelectCellState extends GridCellState<GridSingleSelectCell> {
|
|||||||
return SelectOptionWrap(
|
return SelectOptionWrap(
|
||||||
selectOptions: state.selectedOptions,
|
selectOptions: state.selectedOptions,
|
||||||
cellStyle: widget.cellStyle,
|
cellStyle: widget.cellStyle,
|
||||||
onCellEditing: widget.onCellEditing,
|
onCellEditing: widget.onCellFocus,
|
||||||
popoverController: _popover,
|
popoverController: _popover,
|
||||||
cellControllerBuilder: widget.cellControllerBuilder,
|
cellControllerBuilder: widget.cellControllerBuilder,
|
||||||
);
|
);
|
||||||
@ -125,7 +125,7 @@ class _MultiSelectCellState extends GridCellState<GridMultiSelectCell> {
|
|||||||
return SelectOptionWrap(
|
return SelectOptionWrap(
|
||||||
selectOptions: state.selectedOptions,
|
selectOptions: state.selectedOptions,
|
||||||
cellStyle: widget.cellStyle,
|
cellStyle: widget.cellStyle,
|
||||||
onCellEditing: widget.onCellEditing,
|
onCellEditing: widget.onCellFocus,
|
||||||
popoverController: _popover,
|
popoverController: _popover,
|
||||||
cellControllerBuilder: widget.cellControllerBuilder,
|
cellControllerBuilder: widget.cellControllerBuilder,
|
||||||
);
|
);
|
||||||
|
@ -157,7 +157,6 @@ class _TextField extends StatelessWidget {
|
|||||||
options: state.options,
|
options: state.options,
|
||||||
selectedOptionMap: optionMap,
|
selectedOptionMap: optionMap,
|
||||||
distanceToText: _editorPanelWidth * 0.7,
|
distanceToText: _editorPanelWidth * 0.7,
|
||||||
maxLength: 30,
|
|
||||||
tagController: tagController,
|
tagController: tagController,
|
||||||
textSeparators: const [','],
|
textSeparators: const [','],
|
||||||
onClick: () => popoverMutex.close(),
|
onClick: () => popoverMutex.close(),
|
||||||
|
@ -41,13 +41,16 @@ class GridTextCell extends GridCellWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
GridFocusNodeCellState<GridTextCell> createState() => _GridTextCellState();
|
GridEditableTextCell<GridTextCell> createState() => _GridTextCellState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _GridTextCellState extends GridFocusNodeCellState<GridTextCell> {
|
class _GridTextCellState extends GridEditableTextCell<GridTextCell> {
|
||||||
late TextCellBloc _cellBloc;
|
late TextCellBloc _cellBloc;
|
||||||
late TextEditingController _controller;
|
late TextEditingController _controller;
|
||||||
|
|
||||||
|
@override
|
||||||
|
SingleListenerFocusNode focusNode = SingleListenerFocusNode();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
final cellController =
|
final cellController =
|
||||||
|
@ -108,11 +108,14 @@ class GridURLCell extends GridCellWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _GridURLCellState extends GridFocusNodeCellState<GridURLCell> {
|
class _GridURLCellState extends GridEditableTextCell<GridURLCell> {
|
||||||
final _popoverController = PopoverController();
|
final _popoverController = PopoverController();
|
||||||
late final URLCellBloc _cellBloc;
|
late final URLCellBloc _cellBloc;
|
||||||
late final TextEditingController _controller;
|
late final TextEditingController _controller;
|
||||||
|
|
||||||
|
@override
|
||||||
|
SingleListenerFocusNode focusNode = SingleListenerFocusNode();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
@ -182,7 +185,7 @@ class _GridURLCellState extends GridFocusNodeCellState<GridURLCell> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void requestBeginFocus() {
|
void requestBeginFocus() {
|
||||||
widget.onCellEditing.value = true;
|
widget.onCellFocus.value = true;
|
||||||
_popoverController.show();
|
_popoverController.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,8 +85,8 @@ class _PropertyCellState extends State<_PropertyCell> {
|
|||||||
final cell = widget.cellBuilder.build(widget.cellContext, style: style);
|
final cell = widget.cellBuilder.build(widget.cellContext, style: style);
|
||||||
|
|
||||||
final gesture = GestureDetector(
|
final gesture = GestureDetector(
|
||||||
behavior: HitTestBehavior.translucent,
|
behavior: HitTestBehavior.opaque,
|
||||||
onTap: () => cell.beginFocus.notify(),
|
onTap: () => cell.requestFocus.notify(),
|
||||||
child: AccessoryHover(
|
child: AccessoryHover(
|
||||||
contentPadding: const EdgeInsets.symmetric(horizontal: 3, vertical: 3),
|
contentPadding: const EdgeInsets.symmetric(horizontal: 3, vertical: 3),
|
||||||
child: cell,
|
child: cell,
|
||||||
@ -97,8 +97,8 @@ class _PropertyCellState extends State<_PropertyCell> {
|
|||||||
child: ConstrainedBox(
|
child: ConstrainedBox(
|
||||||
constraints: const BoxConstraints(minHeight: 30),
|
constraints: const BoxConstraints(minHeight: 30),
|
||||||
child: Row(
|
child: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
AppFlowyPopover(
|
AppFlowyPopover(
|
||||||
controller: popover,
|
controller: popover,
|
||||||
@ -108,6 +108,7 @@ class _PropertyCellState extends State<_PropertyCell> {
|
|||||||
popupBuilder: (popoverContext) => buildFieldEditor(),
|
popupBuilder: (popoverContext) => buildFieldEditor(),
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
width: 150,
|
width: 150,
|
||||||
|
height: 40,
|
||||||
child: FieldCellButton(
|
child: FieldCellButton(
|
||||||
field: widget.cellContext.fieldInfo.field,
|
field: widget.cellContext.fieldInfo.field,
|
||||||
onTap: () => popover.show(),
|
onTap: () => popover.show(),
|
||||||
|
20
frontend/appflowy_tauri/src-tauri/Cargo.lock
generated
20
frontend/appflowy_tauri/src-tauri/Cargo.lock
generated
@ -105,7 +105,7 @@ checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "appflowy-integrate"
|
name = "appflowy-integrate"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e9f7fc#e9f7fc76192f2dbb2379f1a02310047763bd4426"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=06e942#06e942cb6433c94b5ecfe1d431b64bba625fc09c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"collab",
|
"collab",
|
||||||
@ -1030,7 +1030,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab"
|
name = "collab"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e9f7fc#e9f7fc76192f2dbb2379f1a02310047763bd4426"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=06e942#06e942cb6433c94b5ecfe1d431b64bba625fc09c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bytes",
|
"bytes",
|
||||||
@ -1048,7 +1048,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab-client-ws"
|
name = "collab-client-ws"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e9f7fc#e9f7fc76192f2dbb2379f1a02310047763bd4426"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=06e942#06e942cb6433c94b5ecfe1d431b64bba625fc09c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"collab-sync",
|
"collab-sync",
|
||||||
@ -1066,7 +1066,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab-database"
|
name = "collab-database"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e9f7fc#e9f7fc76192f2dbb2379f1a02310047763bd4426"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=06e942#06e942cb6433c94b5ecfe1d431b64bba625fc09c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
@ -1092,7 +1092,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab-derive"
|
name = "collab-derive"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e9f7fc#e9f7fc76192f2dbb2379f1a02310047763bd4426"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=06e942#06e942cb6433c94b5ecfe1d431b64bba625fc09c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -1104,7 +1104,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab-document"
|
name = "collab-document"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e9f7fc#e9f7fc76192f2dbb2379f1a02310047763bd4426"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=06e942#06e942cb6433c94b5ecfe1d431b64bba625fc09c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"collab",
|
"collab",
|
||||||
@ -1122,7 +1122,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab-folder"
|
name = "collab-folder"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e9f7fc#e9f7fc76192f2dbb2379f1a02310047763bd4426"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=06e942#06e942cb6433c94b5ecfe1d431b64bba625fc09c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"chrono",
|
"chrono",
|
||||||
@ -1142,7 +1142,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab-persistence"
|
name = "collab-persistence"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e9f7fc#e9f7fc76192f2dbb2379f1a02310047763bd4426"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=06e942#06e942cb6433c94b5ecfe1d431b64bba625fc09c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bincode",
|
"bincode",
|
||||||
"chrono",
|
"chrono",
|
||||||
@ -1162,7 +1162,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab-plugins"
|
name = "collab-plugins"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e9f7fc#e9f7fc76192f2dbb2379f1a02310047763bd4426"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=06e942#06e942cb6433c94b5ecfe1d431b64bba625fc09c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
@ -1193,7 +1193,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab-sync"
|
name = "collab-sync"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e9f7fc#e9f7fc76192f2dbb2379f1a02310047763bd4426"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=06e942#06e942cb6433c94b5ecfe1d431b64bba625fc09c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"collab",
|
"collab",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user