Skip to content

Commit 3427566

Browse files
committed
feat: enable delete field in edit row detail page
1 parent 988e8db commit 3427566

File tree

12 files changed

+178
-39
lines changed

12 files changed

+178
-39
lines changed

frontend/app_flowy/assets/translations/en.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,8 @@
191191
"optionTitle": "Options",
192192
"addOption": "Add option",
193193
"editProperty": "Edit property",
194-
"newColumn": "New column"
194+
"newColumn": "New column",
195+
"deleteFieldPromptMessage": "Are you sure? This property will be deleted"
195196
},
196197
"row": {
197198
"duplicate": "Duplicate",

frontend/app_flowy/lib/plugins/board/presentation/board_page.dart

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -287,8 +287,13 @@ class _BoardContentState extends State<BoardContent> {
287287
);
288288
}
289289

290-
void _openCard(String gridId, GridFieldController fieldController,
291-
RowPB rowPB, GridRowCache rowCache, BuildContext context) {
290+
void _openCard(
291+
String gridId,
292+
GridFieldController fieldController,
293+
RowPB rowPB,
294+
GridRowCache rowCache,
295+
BuildContext context,
296+
) {
292297
final rowInfo = RowInfo(
293298
gridId: gridId,
294299
fields: UnmodifiableListView(fieldController.fieldContexts),

frontend/app_flowy/lib/plugins/grid/application/field/field_editor_bloc.dart

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
22
import 'package:flutter_bloc/flutter_bloc.dart';
33
import 'dart:async';
44
import 'package:dartz/dartz.dart';
5+
import 'field_service.dart';
56
import 'type_option/type_option_context.dart';
67
import 'package:freezed_annotation/freezed_annotation.dart';
78

@@ -15,10 +16,11 @@ class FieldEditorBloc extends Bloc<FieldEditorEvent, FieldEditorState> {
1516
FieldEditorBloc({
1617
required String gridId,
1718
required String fieldName,
19+
required bool isGroupField,
1820
required IFieldTypeOptionLoader loader,
1921
}) : dataController =
2022
TypeOptionDataController(gridId: gridId, loader: loader),
21-
super(FieldEditorState.initial(gridId, fieldName)) {
23+
super(FieldEditorState.initial(gridId, fieldName, isGroupField)) {
2224
on<FieldEditorEvent>(
2325
(event, emit) async {
2426
await event.when(
@@ -35,7 +37,23 @@ class FieldEditorBloc extends Bloc<FieldEditorEvent, FieldEditorState> {
3537
emit(state.copyWith(name: name));
3638
},
3739
didReceiveFieldChanged: (FieldPB field) {
38-
emit(state.copyWith(field: Some(field), name: field.name));
40+
emit(state.copyWith(
41+
field: Some(field),
42+
name: field.name,
43+
canDelete: field.isPrimary,
44+
));
45+
},
46+
deleteField: () {
47+
state.field.fold(
48+
() => null,
49+
(field) {
50+
final fieldService = FieldService(
51+
gridId: gridId,
52+
fieldId: field.id,
53+
);
54+
fieldService.deleteField();
55+
},
56+
);
3957
},
4058
);
4159
},
@@ -52,6 +70,7 @@ class FieldEditorBloc extends Bloc<FieldEditorEvent, FieldEditorState> {
5270
class FieldEditorEvent with _$FieldEditorEvent {
5371
const factory FieldEditorEvent.initial() = _InitialField;
5472
const factory FieldEditorEvent.updateName(String name) = _UpdateName;
73+
const factory FieldEditorEvent.deleteField() = _DeleteField;
5574
const factory FieldEditorEvent.didReceiveFieldChanged(FieldPB field) =
5675
_DidReceiveFieldChanged;
5776
}
@@ -63,16 +82,21 @@ class FieldEditorState with _$FieldEditorState {
6382
required String errorText,
6483
required String name,
6584
required Option<FieldPB> field,
85+
required bool canDelete,
86+
required bool isGroupField,
6687
}) = _FieldEditorState;
6788

6889
factory FieldEditorState.initial(
6990
String gridId,
7091
String fieldName,
92+
bool isGroupField,
7193
) =>
7294
FieldEditorState(
7395
gridId: gridId,
7496
errorText: '',
7597
field: none(),
98+
canDelete: false,
7699
name: fieldName,
100+
isGroupField: isGroupField,
77101
);
78102
}

frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/field_cell_action_sheet.dart

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import 'package:app_flowy/plugins/grid/application/field/type_option/type_option
22
import 'package:app_flowy/plugins/grid/presentation/widgets/header/field_editor.dart';
33
import 'package:app_flowy/startup/startup.dart';
44
import 'package:app_flowy/plugins/grid/application/prelude.dart';
5+
import 'package:app_flowy/workspace/presentation/widgets/dialogs.dart';
56
import 'package:flowy_infra/image.dart';
67
import 'package:flowy_infra/theme.dart';
78
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
@@ -215,9 +216,15 @@ extension _FieldActionExtension on FieldAction {
215216
.add(const FieldActionSheetEvent.duplicateField());
216217
break;
217218
case FieldAction.delete:
218-
context
219-
.read<FieldActionSheetBloc>()
220-
.add(const FieldActionSheetEvent.deleteField());
219+
FlowyAlertDialog(
220+
title: LocaleKeys.grid_field_deleteFieldPromptMessage.tr(),
221+
confirm: () {
222+
context
223+
.read<FieldActionSheetBloc>()
224+
.add(const FieldActionSheetEvent.deleteField());
225+
},
226+
).show(context);
227+
221228
break;
222229
}
223230
}

frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/field_editor.dart

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@ import 'package:app_flowy/plugins/grid/application/field/field_editor_bloc.dart'
22
import 'package:app_flowy/plugins/grid/application/field/type_option/type_option_context.dart';
33
import 'package:appflowy_popover/popover.dart';
44
import 'package:easy_localization/easy_localization.dart';
5+
import 'package:app_flowy/plugins/grid/presentation/layout/sizes.dart';
6+
import 'package:app_flowy/workspace/presentation/widgets/dialogs.dart';
7+
import 'package:easy_localization/easy_localization.dart';
8+
import 'package:flowy_infra/image.dart';
9+
import 'package:flowy_infra/theme.dart';
10+
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
11+
import 'package:flowy_infra_ui/style_widget/button.dart';
512
import 'package:flowy_infra_ui/style_widget/text.dart';
613
import 'package:flowy_infra_ui/widget/spacing.dart';
714
import 'package:flutter/material.dart';
@@ -13,13 +20,15 @@ import 'field_type_option_editor.dart';
1320
class FieldEditor extends StatefulWidget {
1421
final String gridId;
1522
final String fieldName;
23+
final bool isGroupField;
1624
final VoidCallback? onRemoved;
1725

1826
final IFieldTypeOptionLoader typeOptionLoader;
1927
const FieldEditor({
2028
required this.gridId,
2129
this.fieldName = "",
2230
required this.typeOptionLoader,
31+
this.isGroupField = false,
2332
this.onRemoved,
2433
Key? key,
2534
}) : super(key: key);
@@ -41,9 +50,10 @@ class _FieldEditorState extends State<FieldEditor> {
4150
Widget build(BuildContext context) {
4251
return BlocProvider(
4352
create: (context) => FieldEditorBloc(
44-
gridId: widget.gridId,
45-
fieldName: widget.fieldName,
46-
loader: widget.typeOptionLoader,
53+
gridId: gridId,
54+
fieldName: fieldName,
55+
isGroupField: isGroupField,
56+
loader: typeOptionLoader,
4757
)..add(const FieldEditorEvent.initial()),
4858
child: BlocBuilder<FieldEditorBloc, FieldEditorState>(
4959
buildWhen: (p, c) => false,
@@ -56,6 +66,8 @@ class _FieldEditorState extends State<FieldEditor> {
5666
const VSpace(10),
5767
const _FieldNameCell(),
5868
const VSpace(10),
69+
const _DeleteFieldButton(),
70+
const VSpace(10),
5971
_FieldTypeOptionCell(popoverMutex: popoverMutex),
6072
],
6173
);
@@ -114,3 +126,47 @@ class _FieldNameCell extends StatelessWidget {
114126
);
115127
}
116128
}
129+
130+
class _DeleteFieldButton extends StatelessWidget {
131+
const _DeleteFieldButton({Key? key}) : super(key: key);
132+
133+
@override
134+
Widget build(BuildContext context) {
135+
final theme = context.watch<AppTheme>();
136+
return BlocBuilder<FieldEditorBloc, FieldEditorState>(
137+
builder: (context, state) {
138+
final enable = !state.canDelete && !state.isGroupField;
139+
return SizedBox(
140+
height: GridSize.typeOptionItemHeight,
141+
child: FlowyButton(
142+
text: FlowyText.medium(
143+
LocaleKeys.grid_field_delete.tr(),
144+
fontSize: 12,
145+
color: enable ? null : theme.shader4,
146+
),
147+
hoverColor: theme.hover,
148+
onTap: () {
149+
if (enable) {
150+
FlowyAlertDialog(
151+
title: LocaleKeys.grid_field_deleteFieldPromptMessage.tr(),
152+
cancel: () {
153+
FlowyOverlay.of(context).remove(FieldEditor.identifier());
154+
},
155+
confirm: () {
156+
context
157+
.read<FieldEditorBloc>()
158+
.add(const FieldEditorEvent.deleteField());
159+
FlowyOverlay.of(context).remove(FieldEditor.identifier());
160+
},
161+
).show(context);
162+
}
163+
},
164+
leftIcon: svgWidget('grid/delete', color: theme.iconColor),
165+
),
166+
);
167+
},
168+
);
169+
}
170+
171+
void so() {}
172+
}

frontend/app_flowy/lib/plugins/grid/presentation/widgets/row/row_action_sheet.dart

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import 'package:app_flowy/plugins/grid/application/row/row_action_sheet_bloc.dart';
2+
import 'package:app_flowy/workspace/presentation/widgets/dialogs.dart';
23
import 'package:easy_localization/easy_localization.dart';
34
import 'package:app_flowy/generated/locale_keys.g.dart';
45
import 'package:flowy_infra/image.dart';
@@ -150,9 +151,15 @@ extension _RowActionExtension on _RowAction {
150151
.add(const RowActionSheetEvent.duplicateRow());
151152
break;
152153
case _RowAction.delete:
153-
context
154-
.read<RowActionSheetBloc>()
155-
.add(const RowActionSheetEvent.deleteRow());
154+
FlowyAlertDialog(
155+
title: LocaleKeys.grid_field_deleteFieldPromptMessage.tr(),
156+
confirm: () {
157+
context
158+
.read<RowActionSheetBloc>()
159+
.add(const RowActionSheetEvent.deleteRow());
160+
},
161+
).show(context);
162+
156163
break;
157164
}
158165
}

frontend/app_flowy/lib/plugins/grid/presentation/widgets/row/row_detail.dart

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ class _PropertyList extends StatelessWidget {
133133
),
134134
),
135135
),
136+
const VSpace(10),
136137
_CreateFieldButton(
137138
viewId: viewId,
138139
onClosed: () {
@@ -180,8 +181,9 @@ class _CreateFieldButton extends StatelessWidget {
180181
triggerActions: PopoverTriggerActionFlags.click,
181182
direction: PopoverDirection.bottomWithLeftAligned,
182183
onClose: onClosed,
183-
child: SizedBox(
184+
child: Container(
184185
height: 40,
186+
decoration: _makeBoxDecoration(context),
185187
child: FlowyButton(
186188
text: FlowyText.medium(
187189
LocaleKeys.grid_field_newColumn.tr(),
@@ -195,6 +197,15 @@ class _CreateFieldButton extends StatelessWidget {
195197
popupBuilder: (BuildContext context) => onOpened(),
196198
);
197199
}
200+
201+
BoxDecoration _makeBoxDecoration(BuildContext context) {
202+
final theme = context.read<AppTheme>();
203+
final borderSide = BorderSide(color: theme.shader6, width: 1.0);
204+
return BoxDecoration(
205+
color: theme.surface,
206+
border: Border(top: borderSide),
207+
);
208+
}
198209
}
199210

200211
class _RowDetailCell extends StatefulWidget {
@@ -247,6 +258,7 @@ class _RowDetailCellState extends State<_RowDetailCell> {
247258
child: FieldEditor(
248259
gridId: widget.cellId.gridId,
249260
fieldName: widget.cellId.fieldContext.field.name,
261+
isGroupField: widget.cellId.fieldContext.isGroupField,
250262
typeOptionLoader: FieldTypeOptionLoader(
251263
gridId: widget.cellId.gridId,
252264
field: widget.cellId.fieldContext.field,

frontend/app_flowy/lib/workspace/presentation/widgets/dialogs.dart

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ class _CreateTextFieldDialog extends State<TextFieldDialog> {
5656
FlowyFormTextInput(
5757
hintText: LocaleKeys.dialogCreatePageNameHint.tr(),
5858
initialValue: widget.value,
59-
textStyle: const TextStyle(fontSize: 24, fontWeight: FontWeight.w400),
59+
textStyle:
60+
const TextStyle(fontSize: 24, fontWeight: FontWeight.w400),
6061
autoFocus: true,
6162
onChanged: (text) {
6263
newValue = text;
@@ -120,7 +121,7 @@ class _CreateFlowyAlertDialog extends State<FlowyAlertDialog> {
120121
const VSpace(20),
121122
OkCancelButton(
122123
onOkPressed: widget.confirm!,
123-
onCancelPressed: widget.confirm,
124+
onCancelPressed: widget.cancel,
124125
)
125126
]
126127
],
@@ -158,7 +159,7 @@ class OkCancelDialog extends StatelessWidget {
158159
crossAxisAlignment: CrossAxisAlignment.start,
159160
children: <Widget>[
160161
if (title != null) ...[
161-
Text(title!.toUpperCase(), style: TextStyles.T1.textColor(theme.shader1)),
162+
FlowyText.medium(title!.toUpperCase(), color: theme.shader1),
162163
VSpace(Insets.sm * 1.5),
163164
Container(color: theme.bg1, height: 1),
164165
VSpace(Insets.m * 1.5),
@@ -185,7 +186,12 @@ class OkCancelButton extends StatelessWidget {
185186
final double? minHeight;
186187

187188
const OkCancelButton(
188-
{Key? key, this.onOkPressed, this.onCancelPressed, this.okTitle, this.cancelTitle, this.minHeight})
189+
{Key? key,
190+
this.onOkPressed,
191+
this.onCancelPressed,
192+
this.okTitle,
193+
this.cancelTitle,
194+
this.minHeight})
189195
: super(key: key);
190196

191197
@override
@@ -200,7 +206,7 @@ class OkCancelButton extends StatelessWidget {
200206
cancelTitle ?? LocaleKeys.button_Cancel.tr(),
201207
onPressed: () {
202208
onCancelPressed!();
203-
AppGlobals.nav.pop();
209+
Navigator.of(context).pop();
204210
},
205211
bigMode: true,
206212
),
@@ -210,7 +216,7 @@ class OkCancelButton extends StatelessWidget {
210216
okTitle ?? LocaleKeys.button_OK.tr(),
211217
onPressed: () {
212218
onOkPressed!();
213-
AppGlobals.nav.pop();
219+
Navigator.of(context).pop();
214220
},
215221
bigMode: true,
216222
),

0 commit comments

Comments
 (0)