mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: add quick edit panel (#4089)
* feat: add quick edit panel
* feat: improve datepicker color
* fix: quick edit field editor overflow
* chore: try to fix mobile ci
* Revert "chore: try to fix mobile ci"
This reverts commit 68f0ccecd6
.
This commit is contained in:
parent
d25830aece
commit
7d55153475
@ -2,24 +2,51 @@ import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
class AppBarBackButton extends StatelessWidget {
|
||||
const AppBarBackButton({
|
||||
super.key,
|
||||
required this.onTap,
|
||||
this.onTap,
|
||||
});
|
||||
|
||||
final VoidCallback onTap;
|
||||
final VoidCallback? onTap;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AppBarButton(
|
||||
onTap: onTap,
|
||||
onTap: onTap ?? () => context.pop(),
|
||||
child: const Icon(Icons.arrow_back_ios_new),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AppBarCloseButton extends StatelessWidget {
|
||||
const AppBarCloseButton({
|
||||
super.key,
|
||||
this.onTap,
|
||||
this.margin = const EdgeInsets.symmetric(
|
||||
horizontal: 16.0,
|
||||
vertical: 12.0,
|
||||
),
|
||||
});
|
||||
|
||||
final VoidCallback? onTap;
|
||||
final EdgeInsets margin;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FlowyButton(
|
||||
useIntrinsicWidth: true,
|
||||
text: const Icon(
|
||||
Icons.close,
|
||||
),
|
||||
margin: margin,
|
||||
onTap: onTap ?? () => context.pop(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AppBarCancelButton extends StatelessWidget {
|
||||
const AppBarCancelButton({
|
||||
super.key,
|
||||
|
@ -126,9 +126,7 @@ class _MobileViewPageState extends State<MobileViewPage> {
|
||||
),
|
||||
],
|
||||
),
|
||||
leading: AppBarBackButton(
|
||||
onTap: () => context.pop(),
|
||||
),
|
||||
leading: const AppBarBackButton(),
|
||||
actions: actions,
|
||||
),
|
||||
body: SafeArea(
|
||||
|
@ -1,3 +1,4 @@
|
||||
import 'package:appflowy/mobile/presentation/base/app_bar_actions.dart';
|
||||
import 'package:appflowy/plugins/base/drag_handler.dart';
|
||||
import 'package:flowy_infra/size.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart' hide WidgetBuilder;
|
||||
@ -15,6 +16,8 @@ Future<T?> showMobileBottomSheet<T>(
|
||||
bool showCloseButton = false,
|
||||
String title = '', // only works if showHeader is true
|
||||
Color? backgroundColor,
|
||||
bool isScrollControlled = true,
|
||||
BoxConstraints? constraints,
|
||||
}) async {
|
||||
assert(() {
|
||||
if (showCloseButton || title.isNotEmpty) assert(showHeader);
|
||||
@ -23,11 +26,12 @@ Future<T?> showMobileBottomSheet<T>(
|
||||
|
||||
return showModalBottomSheet<T>(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
isScrollControlled: isScrollControlled,
|
||||
enableDrag: isDragEnabled,
|
||||
useSafeArea: true,
|
||||
clipBehavior: Clip.antiAlias,
|
||||
backgroundColor: backgroundColor,
|
||||
constraints: constraints,
|
||||
shape: shape ??
|
||||
const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.vertical(
|
||||
@ -53,14 +57,8 @@ Future<T?> showMobileBottomSheet<T>(
|
||||
showCloseButton
|
||||
? Padding(
|
||||
padding: EdgeInsets.only(left: padding.left),
|
||||
child: FlowyButton(
|
||||
useIntrinsicWidth: true,
|
||||
text: const Icon(
|
||||
Icons.close,
|
||||
size: 24,
|
||||
),
|
||||
child: const AppBarCloseButton(
|
||||
margin: EdgeInsets.zero,
|
||||
onTap: () => Navigator.of(context).pop(),
|
||||
),
|
||||
)
|
||||
: const SizedBox.shrink(),
|
||||
|
@ -1,8 +1,7 @@
|
||||
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/_field_options_eidtor.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_service.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/field_settings/field_settings_service.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_backend_service.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
@ -13,18 +12,15 @@ class MobileEditPropertyScreen extends StatefulWidget {
|
||||
static const routeName = '/edit_property';
|
||||
static const argViewId = 'view_id';
|
||||
static const argField = 'field';
|
||||
static const argIsPrimary = 'is_primary';
|
||||
|
||||
const MobileEditPropertyScreen({
|
||||
super.key,
|
||||
required this.viewId,
|
||||
required this.field,
|
||||
this.isPrimary = false,
|
||||
});
|
||||
|
||||
final String viewId;
|
||||
final FieldPB field;
|
||||
final bool isPrimary;
|
||||
|
||||
@override
|
||||
State<MobileEditPropertyScreen> createState() =>
|
||||
@ -79,29 +75,25 @@ class _MobileEditPropertyScreenState extends State<MobileEditPropertyScreen> {
|
||||
}
|
||||
return FieldOptionEditor(
|
||||
mode: FieldOptionMode.edit,
|
||||
isPrimary: widget.isPrimary,
|
||||
isPrimary: widget.field.isPrimary,
|
||||
defaultValues: optionValues,
|
||||
onOptionValuesChanged: (optionValues) {
|
||||
this.optionValues = optionValues;
|
||||
},
|
||||
onAction: (action) {
|
||||
final service = FieldBackendService(
|
||||
final service = FieldServices(
|
||||
viewId: viewId,
|
||||
fieldId: fieldId,
|
||||
);
|
||||
switch (action) {
|
||||
case FieldOptionAction.delete:
|
||||
service.deleteField();
|
||||
service.delete();
|
||||
break;
|
||||
case FieldOptionAction.duplicate:
|
||||
service.duplicateField();
|
||||
service.duplicate();
|
||||
break;
|
||||
case FieldOptionAction.hide:
|
||||
FieldSettingsBackendService(viewId: viewId)
|
||||
.updateFieldSettings(
|
||||
fieldId: fieldId,
|
||||
fieldVisibility: FieldVisibility.AlwaysHidden,
|
||||
);
|
||||
service.hide();
|
||||
break;
|
||||
}
|
||||
context.pop();
|
||||
|
@ -6,6 +6,7 @@ import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/mobile/presentation/base/option_color_list.dart';
|
||||
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart';
|
||||
import 'package:appflowy/mobile/presentation/database/card/card_detail/widgets/_field_options.dart';
|
||||
import 'package:appflowy/mobile/presentation/database/card/card_detail/widgets/widgets.dart';
|
||||
import 'package:appflowy/mobile/presentation/widgets/widgets.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_service.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/field/type_option/number_format_bloc.dart';
|
||||
@ -190,7 +191,7 @@ class _FieldOptionEditorState extends State<FieldOptionEditor> {
|
||||
child: Column(
|
||||
children: [
|
||||
const _Divider(),
|
||||
_OptionTextField(
|
||||
OptionTextField(
|
||||
controller: controller,
|
||||
type: values.type,
|
||||
onTextChanged: (value) {
|
||||
@ -289,20 +290,24 @@ class _FieldOptionEditorState extends State<FieldOptionEditor> {
|
||||
leftIcon: const FlowySvg(FlowySvgs.hide_s),
|
||||
onTap: () => widget.onAction?.call(FieldOptionAction.hide),
|
||||
),
|
||||
if (!widget.isPrimary)
|
||||
if (!widget.isPrimary) ...[
|
||||
FlowyOptionTile.text(
|
||||
showTopBorder: false,
|
||||
text: LocaleKeys.button_duplicate.tr(),
|
||||
leftIcon: const FlowySvg(FlowySvgs.copy_s),
|
||||
onTap: () => widget.onAction?.call(FieldOptionAction.duplicate),
|
||||
),
|
||||
if (!widget.isPrimary)
|
||||
FlowyOptionTile.text(
|
||||
showTopBorder: false,
|
||||
text: LocaleKeys.button_delete.tr(),
|
||||
leftIcon: const FlowySvg(FlowySvgs.delete_s),
|
||||
textColor: Theme.of(context).colorScheme.error,
|
||||
leftIcon: FlowySvg(
|
||||
FlowySvgs.delete_s,
|
||||
color: Theme.of(context).colorScheme.error,
|
||||
),
|
||||
onTap: () => widget.onAction?.call(FieldOptionAction.delete),
|
||||
),
|
||||
],
|
||||
]
|
||||
};
|
||||
}
|
||||
@ -338,35 +343,6 @@ class _FieldOptionEditorState extends State<FieldOptionEditor> {
|
||||
}
|
||||
}
|
||||
|
||||
class _OptionTextField extends StatelessWidget {
|
||||
const _OptionTextField({
|
||||
required this.controller,
|
||||
required this.type,
|
||||
required this.onTextChanged,
|
||||
});
|
||||
|
||||
final TextEditingController controller;
|
||||
final FieldType type;
|
||||
final void Function(String value) onTextChanged;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FlowyOptionTile.textField(
|
||||
controller: controller,
|
||||
textFieldPadding: const EdgeInsets.symmetric(horizontal: 12.0),
|
||||
onTextChanged: onTextChanged,
|
||||
leftIcon: Padding(
|
||||
padding: const EdgeInsets.only(left: 16.0),
|
||||
child: FlowySvg(
|
||||
type.svgData,
|
||||
size: const Size.square(36.0),
|
||||
blendMode: null,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _PropertyType extends StatelessWidget {
|
||||
const _PropertyType({
|
||||
required this.type,
|
||||
|
@ -0,0 +1,35 @@
|
||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||
import 'package:appflowy/mobile/presentation/widgets/widgets.dart';
|
||||
import 'package:appflowy/util/field_type_extension.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class OptionTextField extends StatelessWidget {
|
||||
const OptionTextField({
|
||||
super.key,
|
||||
required this.controller,
|
||||
required this.type,
|
||||
required this.onTextChanged,
|
||||
});
|
||||
|
||||
final TextEditingController controller;
|
||||
final FieldType type;
|
||||
final void Function(String value) onTextChanged;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FlowyOptionTile.textField(
|
||||
controller: controller,
|
||||
textFieldPadding: const EdgeInsets.symmetric(horizontal: 12.0),
|
||||
onTextChanged: onTextChanged,
|
||||
leftIcon: Padding(
|
||||
padding: const EdgeInsets.only(left: 16.0),
|
||||
child: FlowySvg(
|
||||
type.svgData,
|
||||
size: const Size.square(36.0),
|
||||
blendMode: null,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
export 'mobile_field_name_text_field.dart';
|
||||
export 'mobile_create_field_button.dart';
|
||||
export 'mobile_field_name_text_field.dart';
|
||||
export 'mobile_row_property_list.dart';
|
||||
export 'option_text_field.dart';
|
||||
|
@ -77,15 +77,17 @@ class _MobileDateCellEditScreenState extends State<MobileDateCellEditScreen> {
|
||||
builder: (_, controller) => Material(
|
||||
child: ColoredBox(
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
child: SingleChildScrollView(
|
||||
controller: controller,
|
||||
child: Column(
|
||||
children: [
|
||||
const DragHandler(),
|
||||
_buildHeader(),
|
||||
_buildBody(),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
const DragHandler(),
|
||||
_buildHeader(),
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
controller: controller,
|
||||
child: _buildBody(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -3,6 +3,7 @@ import 'package:appflowy/mobile/presentation/database/card/card_detail/mobile_cr
|
||||
import 'package:appflowy/mobile/presentation/database/card/card_detail/mobile_edit_field_screen.dart';
|
||||
import 'package:appflowy/mobile/presentation/database/card/card_detail/widgets/_field_options.dart';
|
||||
import 'package:appflowy/mobile/presentation/database/card/card_detail/widgets/_field_options_eidtor.dart';
|
||||
import 'package:appflowy/mobile/presentation/database/field/quick_edit_field_bottom_sheet.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_info.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_service.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@ -43,7 +44,7 @@ void showCreateFieldBottomSheet(BuildContext context, String viewId) {
|
||||
);
|
||||
}
|
||||
|
||||
void showEditFieldScreen(
|
||||
Future<FieldOptionValues?> showEditFieldScreen(
|
||||
BuildContext context,
|
||||
String viewId,
|
||||
FieldInfo field,
|
||||
@ -53,7 +54,6 @@ void showEditFieldScreen(
|
||||
extra: {
|
||||
MobileEditPropertyScreen.argViewId: viewId,
|
||||
MobileEditPropertyScreen.argField: field.field,
|
||||
MobileEditPropertyScreen.argIsPrimary: field.isPrimary,
|
||||
},
|
||||
);
|
||||
if (optionValues != null) {
|
||||
@ -79,4 +79,30 @@ void showEditFieldScreen(
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return optionValues;
|
||||
}
|
||||
|
||||
void showQuickEditField(
|
||||
BuildContext context,
|
||||
String viewId,
|
||||
FieldInfo fieldInfo,
|
||||
) async {
|
||||
showMobileBottomSheet(
|
||||
context,
|
||||
padding: EdgeInsets.zero,
|
||||
backgroundColor: Theme.of(context).colorScheme.secondaryContainer,
|
||||
resizeToAvoidBottomInset: true,
|
||||
builder: (context) {
|
||||
return ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxHeight: 500),
|
||||
child: SingleChildScrollView(
|
||||
child: QuickEditField(
|
||||
viewId: viewId,
|
||||
fieldInfo: fieldInfo,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -0,0 +1,148 @@
|
||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||
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/bottom_sheet_create_field.dart';
|
||||
import 'package:appflowy/mobile/presentation/widgets/widgets.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_backend_service.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_info.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
class QuickEditField extends StatefulWidget {
|
||||
const QuickEditField({
|
||||
super.key,
|
||||
required this.viewId,
|
||||
required this.fieldInfo,
|
||||
});
|
||||
|
||||
final String viewId;
|
||||
final FieldInfo fieldInfo;
|
||||
|
||||
@override
|
||||
State<QuickEditField> createState() => _QuickEditFieldState();
|
||||
}
|
||||
|
||||
class _QuickEditFieldState extends State<QuickEditField> {
|
||||
final TextEditingController controller = TextEditingController();
|
||||
|
||||
late final FieldServices service = FieldServices(
|
||||
viewId: widget.viewId,
|
||||
fieldId: widget.fieldInfo.field.id,
|
||||
);
|
||||
|
||||
late FieldType fieldType;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
fieldType = widget.fieldInfo.fieldType;
|
||||
controller.text = widget.fieldInfo.field.name;
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const AppBarCloseButton(),
|
||||
OptionTextField(
|
||||
controller: controller,
|
||||
type: fieldType,
|
||||
onTextChanged: (text) async {
|
||||
await service.updateName(text);
|
||||
},
|
||||
),
|
||||
const _Divider(),
|
||||
FlowyOptionTile.text(
|
||||
text: LocaleKeys.grid_field_editProperty.tr(),
|
||||
leftIcon: const FlowySvg(FlowySvgs.edit_s),
|
||||
onTap: () async {
|
||||
final optionValues = await showEditFieldScreen(
|
||||
context,
|
||||
widget.viewId,
|
||||
widget.fieldInfo,
|
||||
);
|
||||
if (optionValues != null) {
|
||||
setState(() {
|
||||
fieldType = optionValues.type;
|
||||
controller.text = optionValues.name;
|
||||
});
|
||||
}
|
||||
},
|
||||
),
|
||||
FlowyOptionTile.text(
|
||||
showTopBorder: false,
|
||||
text: LocaleKeys.grid_field_hide.tr(),
|
||||
leftIcon: const FlowySvg(FlowySvgs.hide_s),
|
||||
onTap: () async {
|
||||
context.pop();
|
||||
await service.hide();
|
||||
},
|
||||
),
|
||||
FlowyOptionTile.text(
|
||||
showTopBorder: false,
|
||||
text: LocaleKeys.grid_field_insertLeft.tr(),
|
||||
leftIcon: const FlowySvg(FlowySvgs.insert_left_s),
|
||||
onTap: () async {
|
||||
context.pop();
|
||||
await service.insertLeft();
|
||||
},
|
||||
),
|
||||
FlowyOptionTile.text(
|
||||
showTopBorder: false,
|
||||
text: LocaleKeys.grid_field_insertRight.tr(),
|
||||
leftIcon: const FlowySvg(FlowySvgs.insert_right_s),
|
||||
onTap: () async {
|
||||
context.pop();
|
||||
await service.insertRight();
|
||||
},
|
||||
),
|
||||
if (!widget.fieldInfo.isPrimary) ...[
|
||||
FlowyOptionTile.text(
|
||||
showTopBorder: false,
|
||||
text: LocaleKeys.button_duplicate.tr(),
|
||||
leftIcon: const FlowySvg(FlowySvgs.copy_s),
|
||||
onTap: () async {
|
||||
context.pop();
|
||||
await service.duplicate();
|
||||
},
|
||||
),
|
||||
FlowyOptionTile.text(
|
||||
showTopBorder: false,
|
||||
text: LocaleKeys.button_delete.tr(),
|
||||
textColor: Theme.of(context).colorScheme.error,
|
||||
leftIcon: FlowySvg(
|
||||
FlowySvgs.delete_s,
|
||||
color: Theme.of(context).colorScheme.error,
|
||||
),
|
||||
onTap: () async {
|
||||
context.pop();
|
||||
await service.delete();
|
||||
},
|
||||
),
|
||||
],
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _Divider extends StatelessWidget {
|
||||
const _Divider();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const VSpace(20);
|
||||
}
|
||||
}
|
@ -54,9 +54,7 @@ class _LanguagePickerPageState extends State<LanguagePickerPage> {
|
||||
LocaleKeys.titleBar_font.tr(),
|
||||
fontSize: 14.0,
|
||||
),
|
||||
leading: AppBarBackButton(
|
||||
onTap: () => context.pop(),
|
||||
),
|
||||
leading: const AppBarBackButton(),
|
||||
),
|
||||
body: SafeArea(
|
||||
child: ListView.separated(
|
||||
|
@ -39,9 +39,7 @@ class _LanguagePickerPageState extends State<LanguagePickerPage> {
|
||||
LocaleKeys.titleBar_language.tr(),
|
||||
fontSize: 14.0,
|
||||
),
|
||||
leading: AppBarBackButton(
|
||||
onTap: () => context.pop(),
|
||||
),
|
||||
leading: const AppBarBackButton(),
|
||||
),
|
||||
body: SafeArea(
|
||||
child: ListView.separated(
|
||||
|
@ -17,6 +17,7 @@ class FlowyOptionTile extends StatelessWidget {
|
||||
this.showTopBorder = true,
|
||||
this.showBottomBorder = true,
|
||||
this.text,
|
||||
this.textColor,
|
||||
this.controller,
|
||||
this.leading,
|
||||
this.onTap,
|
||||
@ -33,6 +34,7 @@ class FlowyOptionTile extends StatelessWidget {
|
||||
|
||||
factory FlowyOptionTile.text({
|
||||
required String text,
|
||||
Color? textColor,
|
||||
bool showTopBorder = true,
|
||||
bool showBottomBorder = true,
|
||||
Widget? leftIcon,
|
||||
@ -42,6 +44,7 @@ class FlowyOptionTile extends StatelessWidget {
|
||||
return FlowyOptionTile._(
|
||||
type: FlowyOptionTileType.text,
|
||||
text: text,
|
||||
textColor: textColor,
|
||||
controller: null,
|
||||
onTap: onTap,
|
||||
showTopBorder: showTopBorder,
|
||||
@ -128,6 +131,7 @@ class FlowyOptionTile extends StatelessWidget {
|
||||
final bool showTopBorder;
|
||||
final bool showBottomBorder;
|
||||
final String? text;
|
||||
final Color? textColor;
|
||||
final TextEditingController? controller;
|
||||
final EdgeInsets textFieldPadding;
|
||||
final void Function()? onTap;
|
||||
@ -156,7 +160,7 @@ class FlowyOptionTile extends StatelessWidget {
|
||||
children: [
|
||||
_buildText(),
|
||||
..._buildTextField(),
|
||||
const Spacer(),
|
||||
if (controller == null) const Spacer(),
|
||||
trailing ?? const SizedBox.shrink(),
|
||||
const HSpace(12.0),
|
||||
],
|
||||
@ -188,6 +192,7 @@ class FlowyOptionTile extends StatelessWidget {
|
||||
useIntrinsicWidth: true,
|
||||
text: FlowyText(
|
||||
text!,
|
||||
color: textColor,
|
||||
),
|
||||
margin: const EdgeInsets.symmetric(
|
||||
horizontal: 16.0,
|
||||
@ -226,7 +231,6 @@ class FlowyOptionTile extends StatelessWidget {
|
||||
child: Container(
|
||||
constraints: const BoxConstraints.tightFor(
|
||||
height: 54.0,
|
||||
width: double.infinity,
|
||||
),
|
||||
alignment: Alignment.center,
|
||||
child: TextField(
|
||||
|
@ -26,9 +26,7 @@ class MobileColorPickerScreen extends StatelessWidget {
|
||||
title ?? LocaleKeys.titleBar_pageIcon.tr(),
|
||||
fontSize: 14.0,
|
||||
),
|
||||
leading: AppBarBackButton(
|
||||
onTap: () => context.pop(),
|
||||
),
|
||||
leading: const AppBarBackButton(),
|
||||
),
|
||||
body: SafeArea(
|
||||
child: FlowyMobileColorPicker(
|
||||
|
@ -4,7 +4,6 @@ import 'package:appflowy/plugins/base/icon/icon_picker.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
class IconPickerPage extends StatelessWidget {
|
||||
const IconPickerPage({
|
||||
@ -25,9 +24,7 @@ class IconPickerPage extends StatelessWidget {
|
||||
title ?? LocaleKeys.titleBar_pageIcon.tr(),
|
||||
fontSize: 14.0,
|
||||
),
|
||||
leading: AppBarBackButton(
|
||||
onTap: () => context.pop(),
|
||||
),
|
||||
leading: const AppBarBackButton(),
|
||||
),
|
||||
body: SafeArea(
|
||||
child: FlowyIconPicker(
|
||||
|
@ -0,0 +1,69 @@
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_service.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/field/type_option/type_option_service.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/field_settings/field_settings_service.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
|
||||
|
||||
// This class is used for combining the
|
||||
// 1. FieldBackendService
|
||||
// 2. FieldSettingsBackendService
|
||||
// 3. TypeOptionBackendService
|
||||
//
|
||||
// including,
|
||||
// hide, delete, duplicated,
|
||||
// insertLeft, insertRight,
|
||||
// updateName
|
||||
class FieldServices {
|
||||
FieldServices({
|
||||
required this.viewId,
|
||||
required this.fieldId,
|
||||
}) : fieldBackendService = FieldBackendService(
|
||||
viewId: viewId,
|
||||
fieldId: fieldId,
|
||||
),
|
||||
fieldSettingsService = FieldSettingsBackendService(
|
||||
viewId: viewId,
|
||||
);
|
||||
|
||||
final String viewId;
|
||||
final String fieldId;
|
||||
|
||||
final FieldBackendService fieldBackendService;
|
||||
final FieldSettingsBackendService fieldSettingsService;
|
||||
|
||||
Future<void> hide() async {
|
||||
await fieldSettingsService.updateFieldSettings(
|
||||
fieldId: fieldId,
|
||||
fieldVisibility: FieldVisibility.AlwaysHidden,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> delete() async {
|
||||
await fieldBackendService.deleteField();
|
||||
}
|
||||
|
||||
Future<void> duplicate() async {
|
||||
await fieldBackendService.duplicateField();
|
||||
}
|
||||
|
||||
Future<void> insertLeft() async {
|
||||
await TypeOptionBackendService.createFieldTypeOption(
|
||||
viewId: viewId,
|
||||
position: CreateFieldPosition.Before,
|
||||
targetFieldId: fieldId,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> insertRight() async {
|
||||
await TypeOptionBackendService.createFieldTypeOption(
|
||||
viewId: viewId,
|
||||
position: CreateFieldPosition.After,
|
||||
targetFieldId: fieldId,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> updateName(String name) async {
|
||||
await fieldBackendService.updateField(
|
||||
name: name,
|
||||
);
|
||||
}
|
||||
}
|
@ -30,7 +30,7 @@ class MobileFieldButton extends StatelessWidget {
|
||||
return SizedBox(
|
||||
width: fieldInfo.fieldSettings!.width.toDouble(),
|
||||
child: FlowyButton(
|
||||
onTap: () => showEditFieldScreen(context, viewId, fieldInfo),
|
||||
onTap: () => showQuickEditField(context, viewId, fieldInfo),
|
||||
radius: BorderRadius.zero,
|
||||
margin: const EdgeInsets.symmetric(vertical: 14, horizontal: 12),
|
||||
leftIconSize: const Size.square(18),
|
||||
|
@ -165,6 +165,8 @@ class _DateCellState extends GridCellState<GridDateCell> {
|
||||
showMobileBottomSheet(
|
||||
context,
|
||||
padding: EdgeInsets.zero,
|
||||
backgroundColor:
|
||||
Theme.of(context).colorScheme.secondaryContainer,
|
||||
builder: (context) {
|
||||
return MobileDateCellEditScreen(
|
||||
controller: widget.cellControllerBuilder.build()
|
||||
|
@ -23,9 +23,7 @@ class MobileCodeLanguagePickerScreen extends StatelessWidget {
|
||||
LocaleKeys.titleBar_language.tr(),
|
||||
fontSize: 14.0,
|
||||
),
|
||||
leading: AppBarBackButton(
|
||||
onTap: () => context.pop(),
|
||||
),
|
||||
leading: const AppBarBackButton(),
|
||||
),
|
||||
body: SafeArea(
|
||||
child: ListView.separated(
|
||||
|
@ -4,7 +4,6 @@ import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/text.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
class ImagePickerPage extends StatefulWidget {
|
||||
const ImagePickerPage({
|
||||
@ -28,9 +27,7 @@ class _ImagePickerPageState extends State<ImagePickerPage> {
|
||||
LocaleKeys.titleBar_pageIcon.tr(),
|
||||
fontSize: 14.0,
|
||||
),
|
||||
leading: AppBarBackButton(
|
||||
onTap: () => context.pop(),
|
||||
),
|
||||
leading: const AppBarBackButton(),
|
||||
),
|
||||
body: SafeArea(
|
||||
child: UploadImageMenu(
|
||||
|
@ -4,7 +4,6 @@ import 'package:appflowy/mobile/presentation/base/app_bar_actions.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
enum MobileBlockActionType {
|
||||
delete,
|
||||
@ -74,9 +73,7 @@ class MobileBlockSettingsScreen extends StatelessWidget {
|
||||
LocaleKeys.titleBar_actions.tr(),
|
||||
fontSize: 14.0,
|
||||
),
|
||||
leading: AppBarBackButton(
|
||||
onTap: () => context.pop(),
|
||||
),
|
||||
leading: const AppBarBackButton(),
|
||||
),
|
||||
body: SafeArea(
|
||||
child: ListView.separated(
|
||||
|
@ -386,7 +386,6 @@ GoRoute _mobileEditPropertyPageRoute() {
|
||||
child: MobileEditPropertyScreen(
|
||||
viewId: args[MobileEditPropertyScreen.argViewId],
|
||||
field: args[MobileEditPropertyScreen.argField],
|
||||
isPrimary: args[MobileEditPropertyScreen.argIsPrimary],
|
||||
),
|
||||
);
|
||||
},
|
||||
|
5
frontend/resources/flowy_icons/16x/insert_left.svg
Normal file
5
frontend/resources/flowy_icons/16x/insert_left.svg
Normal file
@ -0,0 +1,5 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M3.75 14.7222L3.75 5" stroke="#333333" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M11.875 5.625L7.5 10L11.875 14.375" stroke="#333333" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M7.5 10L16.25 10" stroke="#333333" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
After Width: | Height: | Size: 464 B |
5
frontend/resources/flowy_icons/16x/insert_right.svg
Normal file
5
frontend/resources/flowy_icons/16x/insert_right.svg
Normal file
@ -0,0 +1,5 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M16.25 14.7222L16.25 5" stroke="#333333" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M8.125 5.625L12.5 10L8.125 14.375" stroke="#333333" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M12.5 10L3.75 10" stroke="#333333" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
After Width: | Height: | Size: 465 B |
Loading…
Reference in New Issue
Block a user