fix(flutter_desktop): board card rebuild issue (#6424)

This commit is contained in:
Richard Shiue 2024-09-29 11:34:45 +08:00 committed by GitHub
parent 99c81fed56
commit 99c7252a15
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 130 additions and 71 deletions

View File

@ -125,7 +125,7 @@ class _RowCardState extends State<RowCard> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider.value( return BlocProvider.value(
value: _cardBloc, value: _cardBloc,
child: BlocConsumer<CardBloc, CardState>( child: BlocListener<CardBloc, CardState>(
listenWhen: (previous, current) => listenWhen: (previous, current) =>
previous.isEditing != current.isEditing, previous.isEditing != current.isEditing,
listener: (context, state) { listener: (context, state) {
@ -133,13 +133,14 @@ class _RowCardState extends State<RowCard> {
widget.onEndEditing(); widget.onEndEditing();
} }
}, },
builder: (context, state) => child: UniversalPlatform.isMobile ? _mobile() : _desktop(),
UniversalPlatform.isMobile ? _mobile(state) : _desktop(state),
), ),
); );
} }
Widget _mobile(CardState state) { Widget _mobile() {
return BlocBuilder<CardBloc, CardState>(
builder: (context, state) {
return GestureDetector( return GestureDetector(
onTap: () => widget.onTap(context), onTap: () => widget.onTap(context),
behavior: HitTestBehavior.opaque, behavior: HitTestBehavior.opaque,
@ -151,9 +152,11 @@ class _RowCardState extends State<RowCard> {
cells: state.cells, cells: state.cells,
), ),
); );
},
);
} }
Widget _desktop(CardState state) { Widget _desktop() {
final accessories = widget.styleConfiguration.showAccessory final accessories = widget.styleConfiguration.showAccessory
? const <CardAccessory>[ ? const <CardAccessory>[
EditCardAccessory(), EditCardAccessory(),
@ -170,20 +173,29 @@ class _RowCardState extends State<RowCard> {
rowId: _cardBloc.rowController.rowId, rowId: _cardBloc.rowController.rowId,
groupId: widget.groupId, groupId: widget.groupId,
), ),
child: RowCardContainer( child: Builder(
buildAccessoryWhen: () => state.isEditing == false, builder: (context) {
return RowCardContainer(
buildAccessoryWhen: () =>
!context.watch<CardBloc>().state.isEditing,
accessories: accessories ?? [], accessories: accessories ?? [],
openAccessory: _handleOpenAccessory, openAccessory: _handleOpenAccessory,
onTap: widget.onTap, onTap: widget.onTap,
onShiftTap: widget.onShiftTap, onShiftTap: widget.onShiftTap,
child: _CardContent( child: BlocBuilder<CardBloc, CardState>(
builder: (context, state) {
return _CardContent(
rowMeta: state.rowMeta, rowMeta: state.rowMeta,
cellBuilder: widget.cellBuilder, cellBuilder: widget.cellBuilder,
styleConfiguration: widget.styleConfiguration, styleConfiguration: widget.styleConfiguration,
cells: state.cells, cells: state.cells,
userProfile: widget.userProfile, userProfile: widget.userProfile,
isCompact: widget.isCompact, isCompact: widget.isCompact,
);
},
), ),
);
},
), ),
); );
} }
@ -250,25 +262,75 @@ class _CardContent extends StatelessWidget {
RowMetaPB rowMeta, RowMetaPB rowMeta,
List<CellMeta> cells, List<CellMeta> cells,
) { ) {
return cells.mapIndexed((int index, CellMeta cellMeta) { return cells
EditableCardNotifier? cellNotifier; .mapIndexed(
(int index, CellMeta cellMeta) => _CardContentCell(
if (index == 0) { cellBuilder: cellBuilder,
final bloc = context.read<CardBloc>(); cellMeta: cellMeta,
cellNotifier = EditableCardNotifier(isEditing: bloc.state.isEditing); rowMeta: rowMeta,
cellNotifier.isCellEditing.addListener(() { isTitle: index == 0,
final isEditing = cellNotifier!.isCellEditing.value; styleMap: styleConfiguration.cellStyleMap,
bloc.add(CardEvent.setIsEditing(isEditing)); ),
}); )
.toList();
}
} }
return cellBuilder.build( class _CardContentCell extends StatefulWidget {
cellContext: cellMeta.cellContext(), const _CardContentCell({
required this.cellBuilder,
required this.cellMeta,
required this.rowMeta,
required this.isTitle,
required this.styleMap,
});
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<CardBloc>().add(CardEvent.setIsEditing(isEditing));
}
@override
void dispose() {
cellNotifier?.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return BlocListener<CardBloc, CardState>(
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, cellNotifier: cellNotifier,
styleMap: styleConfiguration.cellStyleMap, hasNotes: !widget.rowMeta.isDocumentEmpty,
hasNotes: !rowMeta.isDocumentEmpty, ),
); );
}).toList();
} }
} }

View File

@ -68,7 +68,9 @@ class CardBloc extends Bloc<CardEvent, CardState> {
); );
}, },
setIsEditing: (bool isEditing) { setIsEditing: (bool isEditing) {
if (isEditing != state.isEditing) {
emit(state.copyWith(isEditing: isEditing)); emit(state.copyWith(isEditing: isEditing));
}
}, },
didUpdateRowMeta: (rowMeta) { didUpdateRowMeta: (rowMeta) {
emit(state.copyWith(rowMeta: rowMeta)); emit(state.copyWith(rowMeta: rowMeta));

View File

@ -28,19 +28,8 @@ class RowCardContainer extends StatelessWidget {
create: (_) => _CardContainerNotifier(), create: (_) => _CardContainerNotifier(),
child: Consumer<_CardContainerNotifier>( child: Consumer<_CardContainerNotifier>(
builder: (context, notifier, _) { builder: (context, notifier, _) {
Widget container = child; final shouldBuildAccessory =
bool shouldBuildAccessory = true; buildAccessoryWhen?.call() ?? true;
if (buildAccessoryWhen != null) {
shouldBuildAccessory = buildAccessoryWhen!.call();
}
if (shouldBuildAccessory && accessories.isNotEmpty) {
container = _CardEnterRegion(
accessories: accessories,
onTapAccessory: openAccessory,
child: container,
);
}
return GestureDetector( return GestureDetector(
behavior: HitTestBehavior.opaque, behavior: HitTestBehavior.opaque,
@ -53,7 +42,12 @@ class RowCardContainer extends StatelessWidget {
}, },
child: ConstrainedBox( child: ConstrainedBox(
constraints: const BoxConstraints(minHeight: 42), 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 { class _CardEnterRegion extends StatelessWidget {
const _CardEnterRegion({ const _CardEnterRegion({
required this.shouldBuildAccessory,
required this.child, required this.child,
required this.accessories, required this.accessories,
required this.onTapAccessory, required this.onTapAccessory,
}); });
final bool shouldBuildAccessory;
final Widget child; final Widget child;
final List<CardAccessory> accessories; final List<CardAccessory> accessories;
final void Function(AccessoryType) onTapAccessory; final void Function(AccessoryType) onTapAccessory;
@ -78,9 +74,9 @@ class _CardEnterRegion extends StatelessWidget {
return Selector<_CardContainerNotifier, bool>( return Selector<_CardContainerNotifier, bool>(
selector: (context, notifier) => notifier.onEnter, selector: (context, notifier) => notifier.onEnter,
builder: (context, onEnter, _) { builder: (context, onEnter, _) {
final List<Widget> children = [child]; final List<Widget> children = [
if (onEnter) { child,
children.add( if (onEnter && shouldBuildAccessory)
Positioned( Positioned(
top: 10.0, top: 10.0,
right: 10.0, right: 10.0,
@ -89,8 +85,7 @@ class _CardEnterRegion extends StatelessWidget {
onTapAccessory: onTapAccessory, onTapAccessory: onTapAccessory,
), ),
), ),
); ];
}
return MouseRegion( return MouseRegion(
cursor: SystemMouseCursors.click, cursor: SystemMouseCursors.click,

View File

@ -1559,10 +1559,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: platform name: platform
sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.5" version: "3.1.4"
plugin_platform_interface: plugin_platform_interface:
dependency: "direct dev" dependency: "direct dev"
description: description:
@ -1989,10 +1989,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: string_scanner name: string_scanner
sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.0" version: "1.2.0"
string_validator: string_validator:
dependency: "direct main" dependency: "direct main"
description: description:
@ -2311,10 +2311,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: vm_service name: vm_service
sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "14.2.5" version: "14.2.1"
watcher: watcher:
dependency: transitive dependency: transitive
description: description: