From 99c7252a15366c0f9861c90c82708d282b70f3e3 Mon Sep 17 00:00:00 2001 From: Richard Shiue <71320345+richardshiue@users.noreply.github.com> Date: Sun, 29 Sep 2024 11:34:45 +0800 Subject: [PATCH] fix(flutter_desktop): board card rebuild issue (#6424) --- .../plugins/database/widgets/card/card.dart | 152 ++++++++++++------ .../database/widgets/card/card_bloc.dart | 4 +- .../card/container/card_container.dart | 33 ++-- frontend/appflowy_flutter/pubspec.lock | 12 +- 4 files changed, 130 insertions(+), 71 deletions(-) diff --git a/frontend/appflowy_flutter/lib/plugins/database/widgets/card/card.dart b/frontend/appflowy_flutter/lib/plugins/database/widgets/card/card.dart index 9c261c06cb..3ee506f918 100644 --- a/frontend/appflowy_flutter/lib/plugins/database/widgets/card/card.dart +++ b/frontend/appflowy_flutter/lib/plugins/database/widgets/card/card.dart @@ -125,7 +125,7 @@ class _RowCardState extends State { Widget build(BuildContext context) { return BlocProvider.value( value: _cardBloc, - child: BlocConsumer( + child: BlocListener( listenWhen: (previous, current) => previous.isEditing != current.isEditing, listener: (context, state) { @@ -133,27 +133,30 @@ class _RowCardState extends State { widget.onEndEditing(); } }, - builder: (context, state) => - UniversalPlatform.isMobile ? _mobile(state) : _desktop(state), + child: UniversalPlatform.isMobile ? _mobile() : _desktop(), ), ); } - Widget _mobile(CardState state) { - return GestureDetector( - onTap: () => widget.onTap(context), - behavior: HitTestBehavior.opaque, - child: MobileCardContent( - userProfile: widget.userProfile, - rowMeta: state.rowMeta, - cellBuilder: widget.cellBuilder, - styleConfiguration: widget.styleConfiguration, - cells: state.cells, - ), + Widget _mobile() { + return BlocBuilder( + builder: (context, state) { + return GestureDetector( + onTap: () => widget.onTap(context), + behavior: HitTestBehavior.opaque, + child: MobileCardContent( + userProfile: widget.userProfile, + rowMeta: state.rowMeta, + cellBuilder: widget.cellBuilder, + styleConfiguration: widget.styleConfiguration, + cells: state.cells, + ), + ); + }, ); } - Widget _desktop(CardState state) { + Widget _desktop() { final accessories = widget.styleConfiguration.showAccessory ? const [ EditCardAccessory(), @@ -170,20 +173,29 @@ class _RowCardState extends State { rowId: _cardBloc.rowController.rowId, groupId: widget.groupId, ), - child: RowCardContainer( - buildAccessoryWhen: () => state.isEditing == false, - accessories: accessories ?? [], - openAccessory: _handleOpenAccessory, - onTap: widget.onTap, - onShiftTap: widget.onShiftTap, - child: _CardContent( - rowMeta: state.rowMeta, - cellBuilder: widget.cellBuilder, - styleConfiguration: widget.styleConfiguration, - cells: state.cells, - userProfile: widget.userProfile, - isCompact: widget.isCompact, - ), + child: Builder( + builder: (context) { + return RowCardContainer( + buildAccessoryWhen: () => + !context.watch().state.isEditing, + accessories: accessories ?? [], + openAccessory: _handleOpenAccessory, + onTap: widget.onTap, + onShiftTap: widget.onShiftTap, + child: BlocBuilder( + builder: (context, state) { + return _CardContent( + rowMeta: state.rowMeta, + cellBuilder: widget.cellBuilder, + styleConfiguration: widget.styleConfiguration, + cells: state.cells, + userProfile: widget.userProfile, + isCompact: widget.isCompact, + ); + }, + ), + ); + }, ), ); } @@ -250,25 +262,75 @@ class _CardContent extends StatelessWidget { RowMetaPB rowMeta, List cells, ) { - return cells.mapIndexed((int index, CellMeta cellMeta) { - EditableCardNotifier? cellNotifier; + return cells + .mapIndexed( + (int index, CellMeta cellMeta) => _CardContentCell( + cellBuilder: cellBuilder, + cellMeta: cellMeta, + rowMeta: rowMeta, + isTitle: index == 0, + styleMap: styleConfiguration.cellStyleMap, + ), + ) + .toList(); + } +} - if (index == 0) { - final bloc = context.read(); - cellNotifier = EditableCardNotifier(isEditing: bloc.state.isEditing); - cellNotifier.isCellEditing.addListener(() { - final isEditing = cellNotifier!.isCellEditing.value; - bloc.add(CardEvent.setIsEditing(isEditing)); - }); - } +class _CardContentCell extends StatefulWidget { + const _CardContentCell({ + required this.cellBuilder, + required this.cellMeta, + required this.rowMeta, + required this.isTitle, + required this.styleMap, + }); - return cellBuilder.build( - cellContext: cellMeta.cellContext(), + final CellMeta cellMeta; + final RowMetaPB rowMeta; + final CardCellBuilder cellBuilder; + final CardCellStyleMap styleMap; + final bool isTitle; + + @override + State<_CardContentCell> createState() => _CardContentCellState(); +} + +class _CardContentCellState extends State<_CardContentCell> { + late final EditableCardNotifier? cellNotifier; + + @override + void initState() { + super.initState(); + cellNotifier = widget.isTitle ? EditableCardNotifier() : null; + cellNotifier?.isCellEditing.addListener(listener); + } + + void listener() { + final isEditing = cellNotifier!.isCellEditing.value; + context.read().add(CardEvent.setIsEditing(isEditing)); + } + + @override + void dispose() { + cellNotifier?.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return BlocListener( + listenWhen: (previous, current) => + previous.isEditing != current.isEditing, + listener: (context, state) { + cellNotifier?.isCellEditing.value = state.isEditing; + }, + child: widget.cellBuilder.build( + cellContext: widget.cellMeta.cellContext(), + styleMap: widget.styleMap, cellNotifier: cellNotifier, - styleMap: styleConfiguration.cellStyleMap, - hasNotes: !rowMeta.isDocumentEmpty, - ); - }).toList(); + hasNotes: !widget.rowMeta.isDocumentEmpty, + ), + ); } } diff --git a/frontend/appflowy_flutter/lib/plugins/database/widgets/card/card_bloc.dart b/frontend/appflowy_flutter/lib/plugins/database/widgets/card/card_bloc.dart index a8ede243f7..04f9bb652c 100644 --- a/frontend/appflowy_flutter/lib/plugins/database/widgets/card/card_bloc.dart +++ b/frontend/appflowy_flutter/lib/plugins/database/widgets/card/card_bloc.dart @@ -68,7 +68,9 @@ class CardBloc extends Bloc { ); }, setIsEditing: (bool isEditing) { - emit(state.copyWith(isEditing: isEditing)); + if (isEditing != state.isEditing) { + emit(state.copyWith(isEditing: isEditing)); + } }, didUpdateRowMeta: (rowMeta) { emit(state.copyWith(rowMeta: rowMeta)); diff --git a/frontend/appflowy_flutter/lib/plugins/database/widgets/card/container/card_container.dart b/frontend/appflowy_flutter/lib/plugins/database/widgets/card/container/card_container.dart index 51e7ef4d80..4e31df24b5 100644 --- a/frontend/appflowy_flutter/lib/plugins/database/widgets/card/container/card_container.dart +++ b/frontend/appflowy_flutter/lib/plugins/database/widgets/card/container/card_container.dart @@ -28,19 +28,8 @@ class RowCardContainer extends StatelessWidget { create: (_) => _CardContainerNotifier(), child: Consumer<_CardContainerNotifier>( builder: (context, notifier, _) { - Widget container = child; - bool shouldBuildAccessory = true; - if (buildAccessoryWhen != null) { - shouldBuildAccessory = buildAccessoryWhen!.call(); - } - - if (shouldBuildAccessory && accessories.isNotEmpty) { - container = _CardEnterRegion( - accessories: accessories, - onTapAccessory: openAccessory, - child: container, - ); - } + final shouldBuildAccessory = + buildAccessoryWhen?.call() ?? true; return GestureDetector( behavior: HitTestBehavior.opaque, @@ -53,7 +42,12 @@ class RowCardContainer extends StatelessWidget { }, child: ConstrainedBox( constraints: const BoxConstraints(minHeight: 42), - child: container, + child: _CardEnterRegion( + shouldBuildAccessory: shouldBuildAccessory, + accessories: accessories, + onTapAccessory: openAccessory, + child: child, + ), ), ); }, @@ -64,11 +58,13 @@ class RowCardContainer extends StatelessWidget { class _CardEnterRegion extends StatelessWidget { const _CardEnterRegion({ + required this.shouldBuildAccessory, required this.child, required this.accessories, required this.onTapAccessory, }); + final bool shouldBuildAccessory; final Widget child; final List accessories; final void Function(AccessoryType) onTapAccessory; @@ -78,9 +74,9 @@ class _CardEnterRegion extends StatelessWidget { return Selector<_CardContainerNotifier, bool>( selector: (context, notifier) => notifier.onEnter, builder: (context, onEnter, _) { - final List children = [child]; - if (onEnter) { - children.add( + final List children = [ + child, + if (onEnter && shouldBuildAccessory) Positioned( top: 10.0, right: 10.0, @@ -89,8 +85,7 @@ class _CardEnterRegion extends StatelessWidget { onTapAccessory: onTapAccessory, ), ), - ); - } + ]; return MouseRegion( cursor: SystemMouseCursors.click, diff --git a/frontend/appflowy_flutter/pubspec.lock b/frontend/appflowy_flutter/pubspec.lock index ab4f254d6b..d727f3f784 100644 --- a/frontend/appflowy_flutter/pubspec.lock +++ b/frontend/appflowy_flutter/pubspec.lock @@ -1559,10 +1559,10 @@ packages: dependency: transitive description: name: platform - sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" + sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" url: "https://pub.dev" source: hosted - version: "3.1.5" + version: "3.1.4" plugin_platform_interface: dependency: "direct dev" description: @@ -1989,10 +1989,10 @@ packages: dependency: transitive description: name: string_scanner - sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.2.0" string_validator: dependency: "direct main" description: @@ -2311,10 +2311,10 @@ packages: dependency: transitive description: name: vm_service - sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" + sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec" url: "https://pub.dev" source: hosted - version: "14.2.5" + version: "14.2.1" watcher: dependency: transitive description: