chore: hide edit button when start editing

This commit is contained in:
appflowy 2022-09-07 11:33:42 +08:00
parent 951206db71
commit 29e7e01146
5 changed files with 69 additions and 30 deletions

View File

@ -7,7 +7,6 @@ import 'package:flowy_sdk/protobuf/flowy-grid/block_entities.pb.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:freezed_annotation/freezed_annotation.dart';
import 'dart:async'; import 'dart:async';
import 'card_data_controller.dart'; import 'card_data_controller.dart';
part 'card_bloc.freezed.dart'; part 'card_bloc.freezed.dart';
@ -21,6 +20,7 @@ class BoardCardBloc extends Bloc<BoardCardEvent, BoardCardState> {
required this.groupFieldId, required this.groupFieldId,
required String gridId, required String gridId,
required CardDataController dataController, required CardDataController dataController,
required bool isEditing,
}) : _rowService = RowFFIService( }) : _rowService = RowFFIService(
gridId: gridId, gridId: gridId,
blockId: dataController.rowPB.blockId, blockId: dataController.rowPB.blockId,
@ -30,6 +30,7 @@ class BoardCardBloc extends Bloc<BoardCardEvent, BoardCardState> {
BoardCardState.initial( BoardCardState.initial(
dataController.rowPB, dataController.rowPB,
_makeCells(groupFieldId, dataController.loadData()), _makeCells(groupFieldId, dataController.loadData()),
isEditing,
), ),
) { ) {
on<BoardCardEvent>( on<BoardCardEvent>(
@ -44,6 +45,9 @@ class BoardCardBloc extends Bloc<BoardCardEvent, BoardCardState> {
changeReason: reason, changeReason: reason,
)); ));
}, },
setIsEditing: (bool isEditing) {
emit(state.copyWith(isEditing: isEditing));
},
); );
}, },
); );
@ -92,6 +96,7 @@ List<BoardCellEquatable> _makeCells(
@freezed @freezed
class BoardCardEvent with _$BoardCardEvent { class BoardCardEvent with _$BoardCardEvent {
const factory BoardCardEvent.initial() = _InitialRow; const factory BoardCardEvent.initial() = _InitialRow;
const factory BoardCardEvent.setIsEditing(bool isEditing) = _IsEditing;
const factory BoardCardEvent.didReceiveCells( const factory BoardCardEvent.didReceiveCells(
List<BoardCellEquatable> cells, List<BoardCellEquatable> cells,
RowsChangedReason reason, RowsChangedReason reason,
@ -103,13 +108,19 @@ class BoardCardState with _$BoardCardState {
const factory BoardCardState({ const factory BoardCardState({
required RowPB rowPB, required RowPB rowPB,
required List<BoardCellEquatable> cells, required List<BoardCellEquatable> cells,
required bool isEditing,
RowsChangedReason? changeReason, RowsChangedReason? changeReason,
}) = _BoardCardState; }) = _BoardCardState;
factory BoardCardState.initial(RowPB rowPB, List<BoardCellEquatable> cells) => factory BoardCardState.initial(
RowPB rowPB,
List<BoardCellEquatable> cells,
bool isEditing,
) =>
BoardCardState( BoardCardState(
rowPB: rowPB, rowPB: rowPB,
cells: cells, cells: cells,
isEditing: isEditing,
); );
} }

View File

@ -1,5 +1,4 @@
import 'package:app_flowy/plugins/grid/application/prelude.dart'; import 'package:app_flowy/plugins/grid/application/prelude.dart';
import 'package:flowy_infra/notifier.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
abstract class FocusableBoardCell { abstract class FocusableBoardCell {
@ -7,47 +6,57 @@ abstract class FocusableBoardCell {
} }
class EditableCellNotifier { class EditableCellNotifier {
final Notifier becomeFirstResponder = Notifier();
final Notifier resignFirstResponder = Notifier();
final ValueNotifier<bool> isCellEditing; final ValueNotifier<bool> isCellEditing;
EditableCellNotifier({bool isEditing = false}) EditableCellNotifier({bool isEditing = false})
: isCellEditing = ValueNotifier(isEditing); : isCellEditing = ValueNotifier(isEditing);
void dispose() { void dispose() {
becomeFirstResponder.dispose();
resignFirstResponder.dispose();
isCellEditing.dispose(); isCellEditing.dispose();
} }
} }
class EditableRowNotifier { class EditableRowNotifier {
final Map<EditableCellId, EditableCellNotifier> _cells = {}; final Map<EditableCellId, EditableCellNotifier> _cells = {};
final ValueNotifier<bool> isEditing;
EditableRowNotifier({required bool isEditing})
: isEditing = ValueNotifier(isEditing);
void insertCell( void insertCell(
GridCellIdentifier cellIdentifier, GridCellIdentifier cellIdentifier,
EditableCellNotifier notifier, EditableCellNotifier notifier,
) { ) {
assert(
_cells.values.isEmpty,
'Only one cell can receive the notification',
);
final id = EditableCellId.from(cellIdentifier); final id = EditableCellId.from(cellIdentifier);
_cells[id]?.dispose(); _cells[id]?.dispose();
notifier.isCellEditing.addListener(() {}); notifier.isCellEditing.addListener(() {
isEditing.value = notifier.isCellEditing.value;
});
_cells[EditableCellId.from(cellIdentifier)] = notifier; _cells[EditableCellId.from(cellIdentifier)] = notifier;
} }
void becomeFirstResponder() { void becomeFirstResponder() {
for (final notifier in _cells.values) { if (_cells.values.isEmpty) return;
notifier.becomeFirstResponder.notify(); assert(
} _cells.values.length == 1,
'Only one cell can receive the notification',
);
_cells.values.first.isCellEditing.value = true;
} }
void resignFirstResponder() { void resignFirstResponder() {
for (final notifier in _cells.values) { if (_cells.values.isEmpty) return;
notifier.resignFirstResponder.notify(); assert(
} _cells.values.length == 1,
'Only one cell can receive the notification',
);
_cells.values.first.isCellEditing.value = false;
} }
void clear() { void clear() {
@ -59,7 +68,7 @@ class EditableRowNotifier {
void dispose() { void dispose() {
for (final notifier in _cells.values) { for (final notifier in _cells.values) {
notifier.resignFirstResponder.notify(); notifier.dispose();
} }
_cells.clear(); _cells.clear();

View File

@ -54,17 +54,16 @@ class _BoardTextCellState extends State<BoardTextCell> {
} }
void _bindEditableNotifier() { void _bindEditableNotifier() {
widget.editableNotifier?.becomeFirstResponder.addListener(() { widget.editableNotifier?.isCellEditing.addListener(() {
if (!mounted) return; if (!mounted) return;
final isEditing = widget.editableNotifier?.isCellEditing.value ?? false;
if (isEditing) {
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
focusNode.requestFocus(); focusNode.requestFocus();
}); });
_cellBloc.add(const BoardTextCellEvent.enableEdit(true)); }
}); _cellBloc.add(BoardTextCellEvent.enableEdit(isEditing));
widget.editableNotifier?.resignFirstResponder.addListener(() {
if (!mounted) return;
_cellBloc.add(const BoardTextCellEvent.enableEdit(false));
}); });
} }

View File

@ -42,12 +42,19 @@ class _BoardCardState extends State<BoardCard> {
@override @override
void initState() { void initState() {
rowNotifier = EditableRowNotifier(); rowNotifier = EditableRowNotifier(isEditing: widget.isEditing);
_cardBloc = BoardCardBloc( _cardBloc = BoardCardBloc(
gridId: widget.gridId, gridId: widget.gridId,
groupFieldId: widget.fieldId, groupFieldId: widget.fieldId,
dataController: widget.dataController, dataController: widget.dataController,
isEditing: widget.isEditing,
)..add(const BoardCardEvent.initial()); )..add(const BoardCardEvent.initial());
rowNotifier.isEditing.addListener(() {
if (!mounted) return;
_cardBloc.add(BoardCardEvent.setIsEditing(rowNotifier.isEditing.value));
});
super.initState(); super.initState();
} }
@ -57,13 +64,15 @@ class _BoardCardState extends State<BoardCard> {
value: _cardBloc, value: _cardBloc,
child: BlocBuilder<BoardCardBloc, BoardCardState>( child: BlocBuilder<BoardCardBloc, BoardCardState>(
buildWhen: (previous, current) { buildWhen: (previous, current) {
if (previous.cells.length != current.cells.length) { if (previous.cells.length != current.cells.length ||
previous.isEditing != current.isEditing) {
return true; return true;
} }
return !listEquals(previous.cells, current.cells); return !listEquals(previous.cells, current.cells);
}, },
builder: (context, state) { builder: (context, state) {
return BoardCardContainer( return BoardCardContainer(
buildAccessoryWhen: () => state.isEditing == false,
accessoryBuilder: (context) { accessoryBuilder: (context) {
return [ return [
_CardEditOption( _CardEditOption(
@ -98,7 +107,11 @@ class _BoardCardState extends State<BoardCard> {
(int index, GridCellIdentifier cellId) { (int index, GridCellIdentifier cellId) {
EditableCellNotifier cellNotifier; EditableCellNotifier cellNotifier;
if (index == 0) { if (index == 0) {
cellNotifier = EditableCellNotifier(isEditing: widget.isEditing); // Only use the first cell to receive user's input when click the edit
// button
cellNotifier = EditableCellNotifier(
isEditing: rowNotifier.isEditing.value,
);
rowNotifier.insertCell(cellId, cellNotifier); rowNotifier.insertCell(cellId, cellNotifier);
} else { } else {
cellNotifier = EditableCellNotifier(); cellNotifier = EditableCellNotifier();

View File

@ -7,11 +7,13 @@ import 'package:styled_widget/styled_widget.dart';
class BoardCardContainer extends StatelessWidget { class BoardCardContainer extends StatelessWidget {
final Widget child; final Widget child;
final CardAccessoryBuilder? accessoryBuilder; final CardAccessoryBuilder? accessoryBuilder;
final bool Function()? buildAccessoryWhen;
final void Function(BuildContext) onTap; final void Function(BuildContext) onTap;
const BoardCardContainer({ const BoardCardContainer({
required this.child, required this.child,
required this.onTap, required this.onTap,
this.accessoryBuilder, this.accessoryBuilder,
this.buildAccessoryWhen,
Key? key, Key? key,
}) : super(key: key); }) : super(key: key);
@ -22,7 +24,12 @@ class BoardCardContainer extends StatelessWidget {
child: Consumer<_CardContainerNotifier>( child: Consumer<_CardContainerNotifier>(
builder: (context, notifier, _) { builder: (context, notifier, _) {
Widget container = Center(child: child); Widget container = Center(child: child);
if (accessoryBuilder != null) { bool shouldBuildAccessory = true;
if (buildAccessoryWhen != null) {
shouldBuildAccessory = buildAccessoryWhen!.call();
}
if (accessoryBuilder != null && shouldBuildAccessory) {
final accessories = accessoryBuilder!(context); final accessories = accessoryBuilder!(context);
if (accessories.isNotEmpty) { if (accessories.isNotEmpty) {
container = _CardEnterRegion( container = _CardEnterRegion(