mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
fix: mobile field editing related bugs (#4534)
* fix: mobile field editing related bugs * chore: review * chore: restore podfile.lock
This commit is contained in:
parent
05a06980b9
commit
63c22feb8f
@ -69,7 +69,7 @@ class _MobileNewPropertyScreenState extends State<MobileNewPropertyScreen> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
body: FieldOptionEditor(
|
body: MobileFieldEditor(
|
||||||
mode: FieldOptionMode.add,
|
mode: FieldOptionMode.add,
|
||||||
defaultValues: optionValues,
|
defaultValues: optionValues,
|
||||||
onOptionValuesChanged: (optionValues) {
|
onOptionValuesChanged: (optionValues) {
|
||||||
|
@ -32,12 +32,12 @@ class MobileEditPropertyScreen extends StatefulWidget {
|
|||||||
|
|
||||||
class _MobileEditPropertyScreenState extends State<MobileEditPropertyScreen> {
|
class _MobileEditPropertyScreenState extends State<MobileEditPropertyScreen> {
|
||||||
late final FieldBackendService fieldService;
|
late final FieldBackendService fieldService;
|
||||||
late FieldOptionValues field;
|
late FieldOptionValues _fieldOptionValues;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
field = FieldOptionValues.fromField(field: widget.field.field);
|
_fieldOptionValues = FieldOptionValues.fromField(field: widget.field.field);
|
||||||
fieldService = FieldBackendService(
|
fieldService = FieldBackendService(
|
||||||
viewId: widget.viewId,
|
viewId: widget.viewId,
|
||||||
fieldId: widget.field.id,
|
fieldId: widget.field.id,
|
||||||
@ -49,7 +49,13 @@ class _MobileEditPropertyScreenState extends State<MobileEditPropertyScreen> {
|
|||||||
final viewId = widget.viewId;
|
final viewId = widget.viewId;
|
||||||
final fieldId = widget.field.id;
|
final fieldId = widget.field.id;
|
||||||
|
|
||||||
return Scaffold(
|
return PopScope(
|
||||||
|
onPopInvoked: (didPop) {
|
||||||
|
if (didPop) {
|
||||||
|
context.pop(_fieldOptionValues);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
title: FlowyText.medium(
|
title: FlowyText.medium(
|
||||||
@ -64,39 +70,24 @@ class _MobileEditPropertyScreenState extends State<MobileEditPropertyScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
leading: AppBarBackButton(
|
leading: AppBarBackButton(
|
||||||
onTap: () => context.pop(field),
|
onTap: () => context.pop(_fieldOptionValues),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
body: FieldOptionEditor(
|
body: MobileFieldEditor(
|
||||||
mode: FieldOptionMode.edit,
|
mode: FieldOptionMode.edit,
|
||||||
isPrimary: widget.field.isPrimary,
|
isPrimary: widget.field.isPrimary,
|
||||||
defaultValues: field,
|
defaultValues: _fieldOptionValues,
|
||||||
actions: [
|
actions: [
|
||||||
if (widget.field.fieldSettings?.visibility.isVisibleState() ?? true)
|
widget.field.fieldSettings?.visibility.isVisibleState() ?? true
|
||||||
FieldOptionAction.hide
|
? FieldOptionAction.hide
|
||||||
else
|
: FieldOptionAction.show,
|
||||||
FieldOptionAction.show,
|
|
||||||
FieldOptionAction.duplicate,
|
FieldOptionAction.duplicate,
|
||||||
FieldOptionAction.delete,
|
FieldOptionAction.delete,
|
||||||
],
|
],
|
||||||
onOptionValuesChanged: (newField) async {
|
onOptionValuesChanged: (newFieldOptionValues) {
|
||||||
if (newField.name != field.name) {
|
setState(() {
|
||||||
await fieldService.updateField(name: newField.name);
|
_fieldOptionValues = newFieldOptionValues;
|
||||||
}
|
});
|
||||||
|
|
||||||
if (newField.type != widget.field.fieldType) {
|
|
||||||
await fieldService.updateType(fieldType: newField.type);
|
|
||||||
}
|
|
||||||
|
|
||||||
final data = newField.getTypeOptionData();
|
|
||||||
if (data != null) {
|
|
||||||
await FieldBackendService.updateFieldTypeOption(
|
|
||||||
viewId: viewId,
|
|
||||||
fieldId: widget.field.id,
|
|
||||||
typeOptionData: data,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
// setState(() => field = newField);
|
|
||||||
},
|
},
|
||||||
onAction: (action) {
|
onAction: (action) {
|
||||||
final service = FieldServices(
|
final service = FieldServices(
|
||||||
@ -105,10 +96,11 @@ class _MobileEditPropertyScreenState extends State<MobileEditPropertyScreen> {
|
|||||||
);
|
);
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case FieldOptionAction.delete:
|
case FieldOptionAction.delete:
|
||||||
service.delete();
|
fieldService.delete();
|
||||||
break;
|
context.pop();
|
||||||
|
return;
|
||||||
case FieldOptionAction.duplicate:
|
case FieldOptionAction.duplicate:
|
||||||
service.duplicate();
|
fieldService.duplicate();
|
||||||
break;
|
break;
|
||||||
case FieldOptionAction.hide:
|
case FieldOptionAction.hide:
|
||||||
service.hide();
|
service.hide();
|
||||||
@ -117,9 +109,10 @@ class _MobileEditPropertyScreenState extends State<MobileEditPropertyScreen> {
|
|||||||
service.show();
|
service.show();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
context.pop(field);
|
context.pop(_fieldOptionValues);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,8 @@ import 'mobile_field_type_grid.dart';
|
|||||||
import 'mobile_field_type_option_editor.dart';
|
import 'mobile_field_type_option_editor.dart';
|
||||||
import 'mobile_quick_field_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(
|
void showCreateFieldBottomSheet(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
String viewId, {
|
String viewId, {
|
||||||
@ -24,9 +26,10 @@ void showCreateFieldBottomSheet(
|
|||||||
return DraggableScrollableSheet(
|
return DraggableScrollableSheet(
|
||||||
expand: false,
|
expand: false,
|
||||||
snap: true,
|
snap: true,
|
||||||
initialChildSize: 0.7,
|
initialChildSize: 0.97,
|
||||||
minChildSize: 0.7,
|
minChildSize: 0.97,
|
||||||
builder: (context, controller) => FieldOptions(
|
maxChildSize: 0.97,
|
||||||
|
builder: (context, controller) => MobileFieldTypeGrid(
|
||||||
scrollController: controller,
|
scrollController: controller,
|
||||||
mode: FieldOptionMode.add,
|
mode: FieldOptionMode.add,
|
||||||
onSelectFieldType: (type) async {
|
onSelectFieldType: (type) async {
|
||||||
@ -52,22 +55,22 @@ void showCreateFieldBottomSheet(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Used to edit a field.
|
||||||
Future<FieldOptionValues?> showEditFieldScreen(
|
Future<FieldOptionValues?> showEditFieldScreen(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
String viewId,
|
String viewId,
|
||||||
FieldInfo field,
|
FieldInfo field,
|
||||||
) async {
|
) {
|
||||||
final optionValues = await context.push<FieldOptionValues>(
|
return context.push<FieldOptionValues>(
|
||||||
MobileEditPropertyScreen.routeName,
|
MobileEditPropertyScreen.routeName,
|
||||||
extra: {
|
extra: {
|
||||||
MobileEditPropertyScreen.argViewId: viewId,
|
MobileEditPropertyScreen.argViewId: viewId,
|
||||||
MobileEditPropertyScreen.argField: field,
|
MobileEditPropertyScreen.argField: field,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
return optionValues;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Shows some quick field options in a bottom sheet.
|
||||||
void showQuickEditField(
|
void showQuickEditField(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
String viewId,
|
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(
|
Future<String?> showFieldPicker(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
String? selectedFieldId,
|
String? selectedFieldId,
|
||||||
|
@ -23,8 +23,8 @@ const _supportedFieldTypes = [
|
|||||||
FieldType.CreatedTime,
|
FieldType.CreatedTime,
|
||||||
];
|
];
|
||||||
|
|
||||||
class FieldOptions extends StatelessWidget {
|
class MobileFieldTypeGrid extends StatelessWidget {
|
||||||
const FieldOptions({
|
const MobileFieldTypeGrid({
|
||||||
super.key,
|
super.key,
|
||||||
required this.mode,
|
required this.mode,
|
||||||
required this.onSelectFieldType,
|
required this.onSelectFieldType,
|
||||||
|
@ -159,8 +159,8 @@ enum FieldOptionAction {
|
|||||||
delete,
|
delete,
|
||||||
}
|
}
|
||||||
|
|
||||||
class FieldOptionEditor extends StatefulWidget {
|
class MobileFieldEditor extends StatefulWidget {
|
||||||
const FieldOptionEditor({
|
const MobileFieldEditor({
|
||||||
super.key,
|
super.key,
|
||||||
required this.mode,
|
required this.mode,
|
||||||
required this.defaultValues,
|
required this.defaultValues,
|
||||||
@ -182,11 +182,12 @@ class FieldOptionEditor extends StatefulWidget {
|
|||||||
final bool isPrimary;
|
final bool isPrimary;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<FieldOptionEditor> createState() => _FieldOptionEditorState();
|
State<MobileFieldEditor> createState() => _MobileFieldEditorState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _FieldOptionEditorState extends State<FieldOptionEditor> {
|
class _MobileFieldEditorState extends State<MobileFieldEditor> {
|
||||||
final controller = TextEditingController();
|
final controller = TextEditingController();
|
||||||
|
bool isFieldNameChanged = false;
|
||||||
|
|
||||||
late FieldOptionValues values;
|
late FieldOptionValues values;
|
||||||
|
|
||||||
@ -219,6 +220,7 @@ class _FieldOptionEditorState extends State<FieldOptionEditor> {
|
|||||||
controller: controller,
|
controller: controller,
|
||||||
type: values.type,
|
type: values.type,
|
||||||
onTextChanged: (value) {
|
onTextChanged: (value) {
|
||||||
|
isFieldNameChanged = true;
|
||||||
_updateOptionValues(name: value);
|
_updateOptionValues(name: value);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -226,16 +228,18 @@ class _FieldOptionEditorState extends State<FieldOptionEditor> {
|
|||||||
if (!widget.isPrimary) ...[
|
if (!widget.isPrimary) ...[
|
||||||
_PropertyType(
|
_PropertyType(
|
||||||
type: values.type,
|
type: values.type,
|
||||||
onSelected: (type) => setState(
|
onSelected: (type) {
|
||||||
|
setState(
|
||||||
() {
|
() {
|
||||||
if (widget.mode == FieldOptionMode.add) {
|
if (widget.mode == FieldOptionMode.add &&
|
||||||
|
!isFieldNameChanged) {
|
||||||
controller.text = type.i18n;
|
controller.text = type.i18n;
|
||||||
_updateOptionValues(name: type.i18n, type: type);
|
_updateOptionValues(name: type.i18n);
|
||||||
} else {
|
|
||||||
_updateOptionValues(type: type);
|
|
||||||
}
|
}
|
||||||
|
_updateOptionValues(type: type);
|
||||||
|
},
|
||||||
|
);
|
||||||
},
|
},
|
||||||
),
|
|
||||||
),
|
),
|
||||||
const _Divider(),
|
const _Divider(),
|
||||||
if (option.isNotEmpty) ...[
|
if (option.isNotEmpty) ...[
|
||||||
@ -446,9 +450,10 @@ class _PropertyType extends StatelessWidget {
|
|||||||
return DraggableScrollableSheet(
|
return DraggableScrollableSheet(
|
||||||
expand: false,
|
expand: false,
|
||||||
snap: true,
|
snap: true,
|
||||||
initialChildSize: 0.7,
|
initialChildSize: 0.97,
|
||||||
minChildSize: 0.7,
|
minChildSize: 0.97,
|
||||||
builder: (context, controller) => FieldOptions(
|
maxChildSize: 0.97,
|
||||||
|
builder: (context, controller) => MobileFieldTypeGrid(
|
||||||
scrollController: controller,
|
scrollController: controller,
|
||||||
mode: FieldOptionMode.edit,
|
mode: FieldOptionMode.edit,
|
||||||
onSelectFieldType: (type) {
|
onSelectFieldType: (type) {
|
||||||
@ -894,10 +899,10 @@ class _SelectOptionTile extends StatefulWidget {
|
|||||||
final void Function(SelectOptionPB option) onUpdateOption;
|
final void Function(SelectOptionPB option) onUpdateOption;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<_SelectOptionTile> createState() => __SelectOptionTileState();
|
State<_SelectOptionTile> createState() => _SelectOptionTileState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class __SelectOptionTileState extends State<_SelectOptionTile> {
|
class _SelectOptionTileState extends State<_SelectOptionTile> {
|
||||||
final TextEditingController controller = TextEditingController();
|
final TextEditingController controller = TextEditingController();
|
||||||
late SelectOptionPB option;
|
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/base/app_bar_actions.dart';
|
||||||
import 'package:appflowy/mobile/presentation/database/card/card_detail/widgets/widgets.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_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/mobile/presentation/widgets/widgets.dart';
|
||||||
import 'package:appflowy/plugins/database/application/field/field_backend_service.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_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/plugins/database/widgets/setting/field_visibility_extension.dart';
|
||||||
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
|
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
@ -36,14 +38,15 @@ class _QuickEditFieldState extends State<QuickEditField> {
|
|||||||
fieldId: widget.fieldInfo.field.id,
|
fieldId: widget.fieldInfo.field.id,
|
||||||
);
|
);
|
||||||
|
|
||||||
late FieldType fieldType;
|
|
||||||
late FieldVisibility fieldVisibility;
|
late FieldVisibility fieldVisibility;
|
||||||
|
late FieldOptionValues _fieldOptionValues;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
fieldType = widget.fieldInfo.fieldType;
|
_fieldOptionValues =
|
||||||
|
FieldOptionValues.fromField(field: widget.fieldInfo.field);
|
||||||
fieldVisibility = widget.fieldInfo.fieldSettings?.visibility ??
|
fieldVisibility = widget.fieldInfo.fieldSettings?.visibility ??
|
||||||
FieldVisibility.AlwaysShown;
|
FieldVisibility.AlwaysShown;
|
||||||
controller.text = widget.fieldInfo.field.name;
|
controller.text = widget.fieldInfo.field.name;
|
||||||
@ -52,7 +55,6 @@ class _QuickEditFieldState extends State<QuickEditField> {
|
|||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
controller.dispose();
|
controller.dispose();
|
||||||
|
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,7 +66,7 @@ class _QuickEditFieldState extends State<QuickEditField> {
|
|||||||
const AppBarCloseButton(),
|
const AppBarCloseButton(),
|
||||||
OptionTextField(
|
OptionTextField(
|
||||||
controller: controller,
|
controller: controller,
|
||||||
type: fieldType,
|
type: _fieldOptionValues.type,
|
||||||
onTextChanged: (text) async {
|
onTextChanged: (text) async {
|
||||||
await service.updateName(text);
|
await service.updateName(text);
|
||||||
},
|
},
|
||||||
@ -77,18 +79,44 @@ class _QuickEditFieldState extends State<QuickEditField> {
|
|||||||
widget.fieldInfo.field.freeze();
|
widget.fieldInfo.field.freeze();
|
||||||
final field = widget.fieldInfo.field.rebuild((field) {
|
final field = widget.fieldInfo.field.rebuild((field) {
|
||||||
field.name = controller.text;
|
field.name = controller.text;
|
||||||
field.fieldType = fieldType;
|
field.fieldType = _fieldOptionValues.type;
|
||||||
|
field.typeOptionData =
|
||||||
|
_fieldOptionValues.getTypeOptionData() ?? [];
|
||||||
});
|
});
|
||||||
final optionValues = await showEditFieldScreen(
|
final fieldOptionValues = await showEditFieldScreen(
|
||||||
context,
|
context,
|
||||||
widget.viewId,
|
widget.viewId,
|
||||||
widget.fieldInfo.copyWith(field: field),
|
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(() {
|
setState(() {
|
||||||
fieldType = optionValues.type;
|
_fieldOptionValues = fieldOptionValues;
|
||||||
controller.text = optionValues.name;
|
controller.text = fieldOptionValues.name;
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
if (mounted) {
|
||||||
|
context.pop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -220,9 +220,7 @@ class DatabaseFieldListTile extends StatelessWidget {
|
|||||||
size: const Size.square(20),
|
size: const Size.square(20),
|
||||||
),
|
),
|
||||||
showTopBorder: showTopBorder,
|
showTopBorder: showTopBorder,
|
||||||
onTap: () {
|
onTap: () => showEditFieldScreen(context, viewId, fieldInfo),
|
||||||
showEditFieldScreen(context, viewId, fieldInfo);
|
|
||||||
},
|
|
||||||
onValueChanged: (value) {
|
onValueChanged: (value) {
|
||||||
final newVisibility = fieldInfo.visibility!.toggle();
|
final newVisibility = fieldInfo.visibility!.toggle();
|
||||||
context.read<DatabasePropertyBloc>().add(
|
context.read<DatabasePropertyBloc>().add(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user