Skip to content

Commit f86e9b2

Browse files
committed
feat: enable delete field in edit row detail page
1 parent 9f845ad commit f86e9b2

File tree

12 files changed

+173
-36
lines changed

12 files changed

+173
-36
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
@@ -286,8 +286,13 @@ class _BoardContentState extends State<BoardContent> {
286286
);
287287
}
288288

289-
void _openCard(String gridId, GridFieldController fieldController,
290-
RowPB rowPB, GridRowCache rowCache, BuildContext context) {
289+
void _openCard(
290+
String gridId,
291+
GridFieldController fieldController,
292+
RowPB rowPB,
293+
GridRowCache rowCache,
294+
BuildContext context,
295+
) {
291296
final rowInfo = RowInfo(
292297
gridId: gridId,
293298
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
@@ -1,5 +1,6 @@
11
import 'package:app_flowy/startup/startup.dart';
22
import 'package:app_flowy/plugins/grid/application/prelude.dart';
3+
import 'package:app_flowy/workspace/presentation/widgets/dialogs.dart';
34
import 'package:flowy_infra/image.dart';
45
import 'package:flowy_infra/theme.dart';
56
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
@@ -206,9 +207,15 @@ extension _FieldActionExtension on FieldAction {
206207
.add(const FieldActionSheetEvent.duplicateField());
207208
break;
208209
case FieldAction.delete:
209-
context
210-
.read<FieldActionSheetBloc>()
211-
.add(const FieldActionSheetEvent.deleteField());
210+
FlowyAlertDialog(
211+
title: LocaleKeys.grid_field_deleteFieldPromptMessage.tr(),
212+
confirm: () {
213+
context
214+
.read<FieldActionSheetBloc>()
215+
.add(const FieldActionSheetEvent.deleteField());
216+
},
217+
).show(context);
218+
212219
break;
213220
}
214221
}

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

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
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';
3+
import 'package:app_flowy/plugins/grid/presentation/layout/sizes.dart';
4+
import 'package:app_flowy/workspace/presentation/widgets/dialogs.dart';
35
import 'package:easy_localization/easy_localization.dart';
6+
import 'package:flowy_infra/image.dart';
7+
import 'package:flowy_infra/theme.dart';
48
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
9+
import 'package:flowy_infra_ui/style_widget/button.dart';
510
import 'package:flowy_infra_ui/style_widget/text.dart';
611
import 'package:flowy_infra_ui/widget/spacing.dart';
712
import 'package:flutter/material.dart';
@@ -13,13 +18,15 @@ import 'field_type_option_editor.dart';
1318
class FieldEditor extends StatelessWidget with FlowyOverlayDelegate {
1419
final String gridId;
1520
final String fieldName;
21+
final bool isGroupField;
1622
final VoidCallback? onRemoved;
1723

1824
final IFieldTypeOptionLoader typeOptionLoader;
1925
const FieldEditor({
2026
required this.gridId,
2127
this.fieldName = "",
2228
required this.typeOptionLoader,
29+
this.isGroupField = false,
2330
this.onRemoved,
2431
Key? key,
2532
}) : super(key: key);
@@ -30,6 +37,7 @@ class FieldEditor extends StatelessWidget with FlowyOverlayDelegate {
3037
create: (context) => FieldEditorBloc(
3138
gridId: gridId,
3239
fieldName: fieldName,
40+
isGroupField: isGroupField,
3341
loader: typeOptionLoader,
3442
)..add(const FieldEditorEvent.initial()),
3543
child: BlocBuilder<FieldEditorBloc, FieldEditorState>(
@@ -43,6 +51,8 @@ class FieldEditor extends StatelessWidget with FlowyOverlayDelegate {
4351
const VSpace(10),
4452
const _FieldNameCell(),
4553
const VSpace(10),
54+
const _DeleteFieldButton(),
55+
const VSpace(10),
4656
const _FieldTypeOptionCell(),
4757
],
4858
);
@@ -121,3 +131,47 @@ class _FieldNameCell extends StatelessWidget {
121131
);
122132
}
123133
}
134+
135+
class _DeleteFieldButton extends StatelessWidget {
136+
const _DeleteFieldButton({Key? key}) : super(key: key);
137+
138+
@override
139+
Widget build(BuildContext context) {
140+
final theme = context.watch<AppTheme>();
141+
return BlocBuilder<FieldEditorBloc, FieldEditorState>(
142+
builder: (context, state) {
143+
final enable = !state.canDelete && !state.isGroupField;
144+
return SizedBox(
145+
height: GridSize.typeOptionItemHeight,
146+
child: FlowyButton(
147+
text: FlowyText.medium(
148+
LocaleKeys.grid_field_delete.tr(),
149+
fontSize: 12,
150+
color: enable ? null : theme.shader4,
151+
),
152+
hoverColor: theme.hover,
153+
onTap: () {
154+
if (enable) {
155+
FlowyAlertDialog(
156+
title: LocaleKeys.grid_field_deleteFieldPromptMessage.tr(),
157+
cancel: () {
158+
FlowyOverlay.of(context).remove(FieldEditor.identifier());
159+
},
160+
confirm: () {
161+
context
162+
.read<FieldEditorBloc>()
163+
.add(const FieldEditorEvent.deleteField());
164+
FlowyOverlay.of(context).remove(FieldEditor.identifier());
165+
},
166+
).show(context);
167+
}
168+
},
169+
leftIcon: svgWidget('grid/delete', color: theme.iconColor),
170+
),
171+
);
172+
},
173+
);
174+
}
175+
176+
void so() {}
177+
}

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
@@ -146,6 +146,7 @@ class _PropertyList extends StatelessWidget {
146146
),
147147
),
148148
),
149+
const VSpace(10),
149150
_CreateFieldButton(
150151
viewId: viewId,
151152
onCreated: () {
@@ -185,8 +186,9 @@ class _CreateFieldButton extends StatelessWidget {
185186
Widget build(BuildContext context) {
186187
final theme = context.read<AppTheme>();
187188

188-
return SizedBox(
189+
return Container(
189190
height: 40,
191+
decoration: _makeBoxDecoration(context),
190192
child: FlowyButton(
191193
text: FlowyText.medium(
192194
LocaleKeys.grid_field_newColumn.tr(),
@@ -198,6 +200,15 @@ class _CreateFieldButton extends StatelessWidget {
198200
),
199201
);
200202
}
203+
204+
BoxDecoration _makeBoxDecoration(BuildContext context) {
205+
final theme = context.read<AppTheme>();
206+
final borderSide = BorderSide(color: theme.shader6, width: 1.0);
207+
return BoxDecoration(
208+
color: theme.surface,
209+
border: Border(top: borderSide),
210+
);
211+
}
201212
}
202213

203214
class _RowDetailCell extends StatelessWidget {
@@ -251,6 +262,7 @@ class _RowDetailCell extends StatelessWidget {
251262
FieldEditor(
252263
gridId: cellId.gridId,
253264
fieldName: cellId.fieldContext.name,
265+
isGroupField: cellId.fieldContext.isGroupField,
254266
typeOptionLoader: FieldTypeOptionLoader(
255267
gridId: cellId.gridId,
256268
field: 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)