mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
fix: grid header cell refresh after field was changed
This commit is contained in:
parent
fc77e0857a
commit
fc4ed6c057
@ -0,0 +1,66 @@
|
|||||||
|
import 'package:app_flowy/workspace/application/grid/field/field_listener.dart';
|
||||||
|
import 'package:app_flowy/workspace/application/grid/field/field_service.dart';
|
||||||
|
import 'package:flowy_sdk/log.dart';
|
||||||
|
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Field;
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
part 'field_cell_bloc.freezed.dart';
|
||||||
|
|
||||||
|
class FieldCellBloc extends Bloc<FieldCellEvent, FieldCellState> {
|
||||||
|
final FieldListener _fieldListener;
|
||||||
|
|
||||||
|
FieldCellBloc({
|
||||||
|
required GridFieldCellContext cellContext,
|
||||||
|
}) : _fieldListener = FieldListener(fieldId: cellContext.field.id),
|
||||||
|
super(FieldCellState.initial(cellContext)) {
|
||||||
|
on<FieldCellEvent>(
|
||||||
|
(event, emit) async {
|
||||||
|
await event.map(
|
||||||
|
initial: (_InitialCell value) async {
|
||||||
|
_startListening();
|
||||||
|
},
|
||||||
|
didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) {
|
||||||
|
emit(state.copyWith(field: value.field));
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> close() async {
|
||||||
|
await _fieldListener.stop();
|
||||||
|
return super.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _startListening() {
|
||||||
|
_fieldListener.updateFieldNotifier.addPublishListener((result) {
|
||||||
|
result.fold(
|
||||||
|
(field) => add(FieldCellEvent.didReceiveFieldUpdate(field)),
|
||||||
|
(err) => Log.error(err),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
_fieldListener.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
class FieldCellEvent with _$FieldCellEvent {
|
||||||
|
const factory FieldCellEvent.initial() = _InitialCell;
|
||||||
|
const factory FieldCellEvent.didReceiveFieldUpdate(Field field) = _DidReceiveFieldUpdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
class FieldCellState with _$FieldCellState {
|
||||||
|
const factory FieldCellState({
|
||||||
|
required String gridId,
|
||||||
|
required Field field,
|
||||||
|
}) = _FieldCellState;
|
||||||
|
|
||||||
|
factory FieldCellState.initial(GridFieldCellContext cellContext) => FieldCellState(
|
||||||
|
gridId: cellContext.gridId,
|
||||||
|
field: cellContext.field,
|
||||||
|
);
|
||||||
|
}
|
@ -1,3 +1,4 @@
|
|||||||
|
import 'package:app_flowy/workspace/application/grid/field/field_cell_bloc.dart';
|
||||||
import 'package:app_flowy/workspace/application/grid/field/field_service.dart';
|
import 'package:app_flowy/workspace/application/grid/field/field_service.dart';
|
||||||
import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart';
|
import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart';
|
||||||
import 'package:flowy_infra/image.dart';
|
import 'package:flowy_infra/image.dart';
|
||||||
@ -12,46 +13,55 @@ import 'field_cell_action_sheet.dart';
|
|||||||
import 'field_editor.dart';
|
import 'field_editor.dart';
|
||||||
|
|
||||||
class GridFieldCell extends StatelessWidget {
|
class GridFieldCell extends StatelessWidget {
|
||||||
final GridFieldCellContext fieldCellContext;
|
final GridFieldCellContext cellContext;
|
||||||
const GridFieldCell(this.fieldCellContext, {Key? key}) : super(key: key);
|
const GridFieldCell(this.cellContext, {Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final theme = context.watch<AppTheme>();
|
final theme = context.watch<AppTheme>();
|
||||||
final field = fieldCellContext.field;
|
|
||||||
|
|
||||||
final button = FlowyButton(
|
return BlocProvider(
|
||||||
hoverColor: theme.hover,
|
create: (context) => FieldCellBloc(cellContext: cellContext)..add(const FieldCellEvent.initial()),
|
||||||
onTap: () => _showActionSheet(context),
|
child: BlocBuilder<FieldCellBloc, FieldCellState>(
|
||||||
rightIcon: svgWidget("editor/details", color: theme.iconColor),
|
builder: (context, state) {
|
||||||
leftIcon: svgWidget(field.fieldType.iconName(), color: theme.iconColor),
|
final button = FlowyButton(
|
||||||
text: FlowyText.medium(field.name, fontSize: 12),
|
hoverColor: theme.hover,
|
||||||
padding: GridSize.cellContentInsets,
|
onTap: () => _showActionSheet(context),
|
||||||
);
|
rightIcon: svgWidget("editor/details", color: theme.iconColor),
|
||||||
|
leftIcon: svgWidget(state.field.fieldType.iconName(), color: theme.iconColor),
|
||||||
|
text: FlowyText.medium(state.field.name, fontSize: 12),
|
||||||
|
padding: GridSize.cellContentInsets,
|
||||||
|
);
|
||||||
|
|
||||||
final borderSide = BorderSide(color: theme.shader4, width: 0.4);
|
final borderSide = BorderSide(color: theme.shader4, width: 0.4);
|
||||||
final decoration = BoxDecoration(border: Border(top: borderSide, right: borderSide, bottom: borderSide));
|
final decoration = BoxDecoration(border: Border(top: borderSide, right: borderSide, bottom: borderSide));
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
width: field.width.toDouble(),
|
width: state.field.width.toDouble(),
|
||||||
decoration: decoration,
|
decoration: decoration,
|
||||||
child: button,
|
child: button,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _showActionSheet(BuildContext context) {
|
void _showActionSheet(BuildContext context) {
|
||||||
|
final state = context.read<FieldCellBloc>().state;
|
||||||
GridFieldCellActionSheet(
|
GridFieldCellActionSheet(
|
||||||
fieldCellContext: fieldCellContext,
|
cellContext: GridFieldCellContext(gridId: state.gridId, field: state.field),
|
||||||
onEdited: () => _showFieldEditor(context),
|
onEdited: () => _showFieldEditor(context),
|
||||||
).show(context);
|
).show(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _showFieldEditor(BuildContext context) {
|
void _showFieldEditor(BuildContext context) {
|
||||||
|
final state = context.read<FieldCellBloc>().state;
|
||||||
|
|
||||||
FieldEditor(
|
FieldEditor(
|
||||||
gridId: fieldCellContext.gridId,
|
gridId: state.gridId,
|
||||||
fieldContextLoader: FieldContextLoaderAdaptor(
|
fieldContextLoader: FieldContextLoaderAdaptor(
|
||||||
gridId: fieldCellContext.gridId,
|
gridId: state.gridId,
|
||||||
field: fieldCellContext.field,
|
field: state.field,
|
||||||
),
|
),
|
||||||
).show(context);
|
).show(context);
|
||||||
}
|
}
|
||||||
|
@ -13,9 +13,9 @@ import 'package:easy_localization/easy_localization.dart';
|
|||||||
import 'package:app_flowy/generated/locale_keys.g.dart';
|
import 'package:app_flowy/generated/locale_keys.g.dart';
|
||||||
|
|
||||||
class GridFieldCellActionSheet extends StatelessWidget with FlowyOverlayDelegate {
|
class GridFieldCellActionSheet extends StatelessWidget with FlowyOverlayDelegate {
|
||||||
final GridFieldCellContext fieldCellContext;
|
final GridFieldCellContext cellContext;
|
||||||
final VoidCallback onEdited;
|
final VoidCallback onEdited;
|
||||||
const GridFieldCellActionSheet({required this.fieldCellContext, required this.onEdited, Key? key}) : super(key: key);
|
const GridFieldCellActionSheet({required this.cellContext, required this.onEdited, Key? key}) : super(key: key);
|
||||||
|
|
||||||
void show(BuildContext overlayContext) {
|
void show(BuildContext overlayContext) {
|
||||||
FlowyOverlay.of(overlayContext).insertWithAnchor(
|
FlowyOverlay.of(overlayContext).insertWithAnchor(
|
||||||
@ -33,7 +33,7 @@ class GridFieldCellActionSheet extends StatelessWidget with FlowyOverlayDelegate
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) => getIt<FieldActionSheetBloc>(param1: fieldCellContext),
|
create: (context) => getIt<FieldActionSheetBloc>(param1: cellContext),
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
@ -44,7 +44,7 @@ class GridFieldCellActionSheet extends StatelessWidget with FlowyOverlayDelegate
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
const VSpace(6),
|
const VSpace(6),
|
||||||
_FieldOperationList(fieldCellContext, () => FlowyOverlay.of(context).remove(identifier())),
|
_FieldOperationList(cellContext, () => FlowyOverlay.of(context).remove(identifier())),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -58,7 +58,7 @@ class _GridHeaderDelegate extends SliverPersistentHeaderDelegate {
|
|||||||
@override
|
@override
|
||||||
bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) {
|
bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) {
|
||||||
if (oldDelegate is _GridHeaderDelegate) {
|
if (oldDelegate is _GridHeaderDelegate) {
|
||||||
return fields != oldDelegate.fields;
|
return fields.length != oldDelegate.fields.length;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ edition = "2018"
|
|||||||
name = "dart_ffi"
|
name = "dart_ffi"
|
||||||
# this value will change depending on the target os
|
# this value will change depending on the target os
|
||||||
# default static lib
|
# default static lib
|
||||||
crate-type = ["staticlib"]
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
@ -58,7 +58,7 @@ impl ClientGridEditor {
|
|||||||
start_field_id,
|
start_field_id,
|
||||||
grid_id,
|
grid_id,
|
||||||
} = params;
|
} = params;
|
||||||
|
let field_id = field.id.clone();
|
||||||
let _ = self
|
let _ = self
|
||||||
.modify(|grid| {
|
.modify(|grid| {
|
||||||
if grid.contain_field(&field.id) {
|
if grid.contain_field(&field.id) {
|
||||||
@ -84,6 +84,7 @@ impl ClientGridEditor {
|
|||||||
})
|
})
|
||||||
.await?;
|
.await?;
|
||||||
let _ = self.notify_did_update_grid().await?;
|
let _ = self.notify_did_update_grid().await?;
|
||||||
|
let _ = self.notify_did_update_field(&field_id).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -409,12 +410,13 @@ impl ClientGridEditor {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(level = "trace", skip_all, err)]
|
||||||
async fn notify_did_update_field(&self, field_id: &str) -> FlowyResult<()> {
|
async fn notify_did_update_field(&self, field_id: &str) -> FlowyResult<()> {
|
||||||
let mut field_metas = self.get_field_metas(Some(vec![field_id])).await?;
|
let mut field_metas = self.get_field_metas(Some(vec![field_id])).await?;
|
||||||
debug_assert!(field_metas.len() == 1);
|
debug_assert!(field_metas.len() == 1);
|
||||||
|
|
||||||
if let Some(field_meta) = field_metas.pop() {
|
if let Some(field_meta) = field_metas.pop() {
|
||||||
send_dart_notification(&self.grid_id, GridNotification::DidUpdateField)
|
send_dart_notification(&field_id, GridNotification::DidUpdateField)
|
||||||
.payload(field_meta)
|
.payload(field_meta)
|
||||||
.send();
|
.send();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user