fix: mobile field editing related bugs ()

* fix: mobile field editing related bugs

* chore: review

* chore: restore podfile.lock
This commit is contained in:
Richard Shiue 2024-01-29 13:19:35 +08:00 committed by GitHub
parent 05a06980b9
commit 63c22feb8f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 136 additions and 108 deletions

@ -69,7 +69,7 @@ class _MobileNewPropertyScreenState extends State<MobileNewPropertyScreen> {
),
],
),
body: FieldOptionEditor(
body: MobileFieldEditor(
mode: FieldOptionMode.add,
defaultValues: optionValues,
onOptionValuesChanged: (optionValues) {

@ -32,12 +32,12 @@ class MobileEditPropertyScreen extends StatefulWidget {
class _MobileEditPropertyScreenState extends State<MobileEditPropertyScreen> {
late final FieldBackendService fieldService;
late FieldOptionValues field;
late FieldOptionValues _fieldOptionValues;
@override
void initState() {
super.initState();
field = FieldOptionValues.fromField(field: widget.field.field);
_fieldOptionValues = FieldOptionValues.fromField(field: widget.field.field);
fieldService = FieldBackendService(
viewId: widget.viewId,
fieldId: widget.field.id,
@ -49,76 +49,69 @@ class _MobileEditPropertyScreenState extends State<MobileEditPropertyScreen> {
final viewId = widget.viewId;
final fieldId = widget.field.id;
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: FlowyText.medium(
LocaleKeys.grid_field_editProperty.tr(),
),
elevation: 0,
bottom: const PreferredSize(
preferredSize: Size.fromHeight(1),
child: Divider(
height: 1,
thickness: 1,
return PopScope(
onPopInvoked: (didPop) {
if (didPop) {
context.pop(_fieldOptionValues);
}
},
child: Scaffold(
appBar: AppBar(
centerTitle: true,
title: FlowyText.medium(
LocaleKeys.grid_field_editProperty.tr(),
),
elevation: 0,
bottom: const PreferredSize(
preferredSize: Size.fromHeight(1),
child: Divider(
height: 1,
thickness: 1,
),
),
leading: AppBarBackButton(
onTap: () => context.pop(_fieldOptionValues),
),
),
leading: AppBarBackButton(
onTap: () => context.pop(field),
),
),
body: FieldOptionEditor(
mode: FieldOptionMode.edit,
isPrimary: widget.field.isPrimary,
defaultValues: field,
actions: [
if (widget.field.fieldSettings?.visibility.isVisibleState() ?? true)
FieldOptionAction.hide
else
FieldOptionAction.show,
FieldOptionAction.duplicate,
FieldOptionAction.delete,
],
onOptionValuesChanged: (newField) async {
if (newField.name != field.name) {
await fieldService.updateField(name: newField.name);
}
if (newField.type != widget.field.fieldType) {
await fieldService.updateType(fieldType: newField.type);
}
final data = newField.getTypeOptionData();
if (data != null) {
await FieldBackendService.updateFieldTypeOption(
body: MobileFieldEditor(
mode: FieldOptionMode.edit,
isPrimary: widget.field.isPrimary,
defaultValues: _fieldOptionValues,
actions: [
widget.field.fieldSettings?.visibility.isVisibleState() ?? true
? FieldOptionAction.hide
: FieldOptionAction.show,
FieldOptionAction.duplicate,
FieldOptionAction.delete,
],
onOptionValuesChanged: (newFieldOptionValues) {
setState(() {
_fieldOptionValues = newFieldOptionValues;
});
},
onAction: (action) {
final service = FieldServices(
viewId: viewId,
fieldId: widget.field.id,
typeOptionData: data,
fieldId: fieldId,
);
}
// setState(() => field = newField);
},
onAction: (action) {
final service = FieldServices(
viewId: viewId,
fieldId: fieldId,
);
switch (action) {
case FieldOptionAction.delete:
service.delete();
break;
case FieldOptionAction.duplicate:
service.duplicate();
break;
case FieldOptionAction.hide:
service.hide();
break;
case FieldOptionAction.show:
service.show();
break;
}
context.pop(field);
},
switch (action) {
case FieldOptionAction.delete:
fieldService.delete();
context.pop();
return;
case FieldOptionAction.duplicate:
fieldService.duplicate();
break;
case FieldOptionAction.hide:
service.hide();
break;
case FieldOptionAction.show:
service.show();
break;
}
context.pop(_fieldOptionValues);
},
),
),
);
}

@ -12,6 +12,8 @@ import 'mobile_field_type_grid.dart';
import 'mobile_field_type_option_editor.dart';
import 'mobile_quick_field_editor.dart';
/// Shows the field type grid and upon selection, allow users to edit the
/// field's properties and saving it when the user clicks save.
void showCreateFieldBottomSheet(
BuildContext context,
String viewId, {
@ -24,9 +26,10 @@ void showCreateFieldBottomSheet(
return DraggableScrollableSheet(
expand: false,
snap: true,
initialChildSize: 0.7,
minChildSize: 0.7,
builder: (context, controller) => FieldOptions(
initialChildSize: 0.97,
minChildSize: 0.97,
maxChildSize: 0.97,
builder: (context, controller) => MobileFieldTypeGrid(
scrollController: controller,
mode: FieldOptionMode.add,
onSelectFieldType: (type) async {
@ -52,22 +55,22 @@ void showCreateFieldBottomSheet(
);
}
/// Used to edit a field.
Future<FieldOptionValues?> showEditFieldScreen(
BuildContext context,
String viewId,
FieldInfo field,
) async {
final optionValues = await context.push<FieldOptionValues>(
) {
return context.push<FieldOptionValues>(
MobileEditPropertyScreen.routeName,
extra: {
MobileEditPropertyScreen.argViewId: viewId,
MobileEditPropertyScreen.argField: field,
},
);
return optionValues;
}
/// Shows some quick field options in a bottom sheet.
void showQuickEditField(
BuildContext context,
String viewId,
@ -89,6 +92,7 @@ void showQuickEditField(
);
}
/// Display a list of fields in the current database that users can choose from.
Future<String?> showFieldPicker(
BuildContext context,
String? selectedFieldId,

@ -23,8 +23,8 @@ const _supportedFieldTypes = [
FieldType.CreatedTime,
];
class FieldOptions extends StatelessWidget {
const FieldOptions({
class MobileFieldTypeGrid extends StatelessWidget {
const MobileFieldTypeGrid({
super.key,
required this.mode,
required this.onSelectFieldType,

@ -159,8 +159,8 @@ enum FieldOptionAction {
delete,
}
class FieldOptionEditor extends StatefulWidget {
const FieldOptionEditor({
class MobileFieldEditor extends StatefulWidget {
const MobileFieldEditor({
super.key,
required this.mode,
required this.defaultValues,
@ -182,11 +182,12 @@ class FieldOptionEditor extends StatefulWidget {
final bool isPrimary;
@override
State<FieldOptionEditor> createState() => _FieldOptionEditorState();
State<MobileFieldEditor> createState() => _MobileFieldEditorState();
}
class _FieldOptionEditorState extends State<FieldOptionEditor> {
class _MobileFieldEditorState extends State<MobileFieldEditor> {
final controller = TextEditingController();
bool isFieldNameChanged = false;
late FieldOptionValues values;
@ -219,6 +220,7 @@ class _FieldOptionEditorState extends State<FieldOptionEditor> {
controller: controller,
type: values.type,
onTextChanged: (value) {
isFieldNameChanged = true;
_updateOptionValues(name: value);
},
),
@ -226,16 +228,18 @@ class _FieldOptionEditorState extends State<FieldOptionEditor> {
if (!widget.isPrimary) ...[
_PropertyType(
type: values.type,
onSelected: (type) => setState(
() {
if (widget.mode == FieldOptionMode.add) {
controller.text = type.i18n;
_updateOptionValues(name: type.i18n, type: type);
} else {
onSelected: (type) {
setState(
() {
if (widget.mode == FieldOptionMode.add &&
!isFieldNameChanged) {
controller.text = type.i18n;
_updateOptionValues(name: type.i18n);
}
_updateOptionValues(type: type);
}
},
),
},
);
},
),
const _Divider(),
if (option.isNotEmpty) ...[
@ -446,9 +450,10 @@ class _PropertyType extends StatelessWidget {
return DraggableScrollableSheet(
expand: false,
snap: true,
initialChildSize: 0.7,
minChildSize: 0.7,
builder: (context, controller) => FieldOptions(
initialChildSize: 0.97,
minChildSize: 0.97,
maxChildSize: 0.97,
builder: (context, controller) => MobileFieldTypeGrid(
scrollController: controller,
mode: FieldOptionMode.edit,
onSelectFieldType: (type) {
@ -894,10 +899,10 @@ class _SelectOptionTile extends StatefulWidget {
final void Function(SelectOptionPB option) onUpdateOption;
@override
State<_SelectOptionTile> createState() => __SelectOptionTileState();
State<_SelectOptionTile> createState() => _SelectOptionTileState();
}
class __SelectOptionTileState extends State<_SelectOptionTile> {
class _SelectOptionTileState extends State<_SelectOptionTile> {
final TextEditingController controller = TextEditingController();
late SelectOptionPB option;

@ -3,9 +3,11 @@ import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/presentation/base/app_bar_actions.dart';
import 'package:appflowy/mobile/presentation/database/card/card_detail/widgets/widgets.dart';
import 'package:appflowy/mobile/presentation/database/field/mobile_field_bottom_sheets.dart';
import 'package:appflowy/mobile/presentation/database/field/mobile_field_type_option_editor.dart';
import 'package:appflowy/mobile/presentation/widgets/widgets.dart';
import 'package:appflowy/plugins/database/application/field/field_backend_service.dart';
import 'package:appflowy/plugins/database/application/field/field_info.dart';
import 'package:appflowy/plugins/database/application/field/field_service.dart';
import 'package:appflowy/plugins/database/widgets/setting/field_visibility_extension.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
import 'package:easy_localization/easy_localization.dart';
@ -36,14 +38,15 @@ class _QuickEditFieldState extends State<QuickEditField> {
fieldId: widget.fieldInfo.field.id,
);
late FieldType fieldType;
late FieldVisibility fieldVisibility;
late FieldOptionValues _fieldOptionValues;
@override
void initState() {
super.initState();
fieldType = widget.fieldInfo.fieldType;
_fieldOptionValues =
FieldOptionValues.fromField(field: widget.fieldInfo.field);
fieldVisibility = widget.fieldInfo.fieldSettings?.visibility ??
FieldVisibility.AlwaysShown;
controller.text = widget.fieldInfo.field.name;
@ -52,7 +55,6 @@ class _QuickEditFieldState extends State<QuickEditField> {
@override
void dispose() {
controller.dispose();
super.dispose();
}
@ -64,7 +66,7 @@ class _QuickEditFieldState extends State<QuickEditField> {
const AppBarCloseButton(),
OptionTextField(
controller: controller,
type: fieldType,
type: _fieldOptionValues.type,
onTextChanged: (text) async {
await service.updateName(text);
},
@ -77,18 +79,44 @@ class _QuickEditFieldState extends State<QuickEditField> {
widget.fieldInfo.field.freeze();
final field = widget.fieldInfo.field.rebuild((field) {
field.name = controller.text;
field.fieldType = fieldType;
field.fieldType = _fieldOptionValues.type;
field.typeOptionData =
_fieldOptionValues.getTypeOptionData() ?? [];
});
final optionValues = await showEditFieldScreen(
final fieldOptionValues = await showEditFieldScreen(
context,
widget.viewId,
widget.fieldInfo.copyWith(field: field),
);
if (optionValues != null) {
if (fieldOptionValues != null) {
if (fieldOptionValues.name != _fieldOptionValues.name) {
await service.updateName(fieldOptionValues.name);
}
if (fieldOptionValues.type != _fieldOptionValues.type) {
await FieldBackendService.updateFieldType(
viewId: widget.viewId,
fieldId: widget.fieldInfo.id,
fieldType: fieldOptionValues.type,
);
}
final data = fieldOptionValues.getTypeOptionData();
if (data != null) {
await FieldBackendService.updateFieldTypeOption(
viewId: widget.viewId,
fieldId: widget.fieldInfo.id,
typeOptionData: data,
);
}
setState(() {
fieldType = optionValues.type;
controller.text = optionValues.name;
_fieldOptionValues = fieldOptionValues;
controller.text = fieldOptionValues.name;
});
} else {
if (mounted) {
context.pop();
}
}
},
),

@ -220,9 +220,7 @@ class DatabaseFieldListTile extends StatelessWidget {
size: const Size.square(20),
),
showTopBorder: showTopBorder,
onTap: () {
showEditFieldScreen(context, viewId, fieldInfo);
},
onTap: () => showEditFieldScreen(context, viewId, fieldInfo),
onValueChanged: (value) {
final newVisibility = fieldInfo.visibility!.toggle();
context.read<DatabasePropertyBloc>().add(