feat: improve UI in MobileFieldEditor (#4042)

This commit is contained in:
Yijing Huang 2023-11-28 19:38:11 -07:00 committed by GitHub
parent 7da759c662
commit 551e012147
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 219 additions and 138 deletions

View File

@ -1,4 +1,7 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/presentation/database/card/card_property_edit/widgets/widgets.dart';
import 'package:appflowy/plugins/database_view/application/field/field_editor_bloc.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@ -33,13 +36,21 @@ class _MobileFieldNameTextFieldState extends State<MobileFieldNameTextField> {
@override
Widget build(BuildContext context) {
return TextField(
controller: controller,
onChanged: (newName) {
context
.read<FieldEditorBloc>()
.add(FieldEditorEvent.renameField(newName));
},
return PropertyEditContainer(
padding: EdgeInsets.zero,
child: TextField(
controller: controller,
decoration: InputDecoration(
hintText: LocaleKeys.board_propertyName.tr(),
enabledBorder: InputBorder.none,
focusedBorder: InputBorder.none,
),
onChanged: (newName) {
context
.read<FieldEditorBloc>()
.add(FieldEditorEvent.renameField(newName));
},
),
);
}
}

View File

@ -1,14 +1,12 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/presentation/database/card/card_detail/widgets/widgets.dart';
import 'package:appflowy/mobile/presentation/database/card/card_property_edit/mobile_field_type_option_editor.dart';
import 'package:appflowy/mobile/presentation/database/card/card_property_edit/widgets/property_title.dart';
import 'package:appflowy/mobile/presentation/database/card/card_property_edit/widgets/widgets.dart';
import 'package:appflowy/plugins/database_view/application/field/field_controller.dart';
import 'package:appflowy/plugins/database_view/application/field/field_editor_bloc.dart';
import 'package:appflowy/plugins/database_view/application/field/type_option/type_option_context.dart';
import 'package:appflowy/plugins/database_view/grid/application/row/row_detail_bloc.dart';
import 'package:appflowy/plugins/database_view/widgets/setting/field_visibility_extension.dart';
import 'package:appflowy/workspace/presentation/widgets/toggle/toggle.dart';
import 'package:appflowy/workspace/presentation/widgets/toggle/toggle_style.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/widget/spacing.dart';
@ -51,38 +49,42 @@ class MobileFieldEditor extends StatelessWidget {
context.read<FieldEditorBloc>().typeOptionController;
final fieldInfoVisibility =
fieldController.getField(field.id)?.visibility;
return Padding(
return Container(
padding: const EdgeInsets.all(16),
color: Theme.of(context).colorScheme.secondary,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// TODO(yijing): improve hint text
PropertyTitle(LocaleKeys.settings_user_name.tr()),
PropertyEditGroupTitle(LocaleKeys.settings_user_name.tr()),
BlocSelector<FieldEditorBloc, FieldEditorState, String>(
selector: (state) => state.field.name,
builder: (context, fieldName) =>
MobileFieldNameTextField(text: fieldName),
),
Row(
children: [
Expanded(
child: PropertyTitle(
LocaleKeys.grid_field_visibility.tr(),
const VSpace(16),
PropertyEditGroupTitle(LocaleKeys.grid_field_visibility.tr()),
PropertyEditContainer(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
PropertyTitle(
LocaleKeys.board_showOnCard.tr(),
),
),
VisibilitySwitch(
isFieldHidden: !(fieldInfoVisibility != null
? fieldInfoVisibility.isVisibleState()
: field.visibility),
onChanged: () => context.read<RowDetailBloc>().add(
RowDetailEvent.toggleFieldVisibility(
state.field.id,
VisibilitySwitch(
isFieldHidden: !(fieldInfoVisibility != null
? fieldInfoVisibility.isVisibleState()
: field.visibility),
onChanged: () => context.read<RowDetailBloc>().add(
RowDetailEvent.toggleFieldVisibility(
state.field.id,
),
),
),
),
],
),
],
),
),
const VSpace(8),
const VSpace(16),
PropertyEditGroupTitle(LocaleKeys.board_setting.tr()),
// edit property type and settings
if (!typeOptionLoader.field.isPrimary)
MobileFieldTypeOptionEditor(dataController: dataController),
@ -114,11 +116,10 @@ class _VisibilitySwitchState extends State<VisibilitySwitch> {
@override
Widget build(BuildContext context) {
return Toggle(
padding: EdgeInsets.zero,
return Switch.adaptive(
value: !_isFieldHidden,
style: ToggleStyle.mobile,
onChanged: (_) {
activeColor: Theme.of(context).colorScheme.primary,
onChanged: (value) {
setState(() {
_isFieldHidden = !_isFieldHidden;
widget.onChanged?.call();

View File

@ -1,6 +1,7 @@
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/presentation/database/card/card_property_edit/type_option_widget_builder/type_option_widget_builder.dart';
import 'package:appflowy/mobile/presentation/database/card/card_property_edit/widgets/widgets.dart';
import 'package:appflowy/mobile/presentation/widgets/show_flowy_mobile_bottom_sheet.dart';
import 'package:appflowy/plugins/database_view/application/field/field_type_option_edit_bloc.dart';
import 'package:appflowy/plugins/database_view/application/field/type_option/type_option_data_controller.dart';
@ -59,24 +60,25 @@ class _MobileSwitchFieldButton extends StatelessWidget {
(FieldTypeOptionEditBloc bloc) => bloc.state.field.fieldType,
);
return GestureDetector(
child: Row(
children: [
Text(
LocaleKeys.grid_field_propertyType.tr(),
style: Theme.of(context).textTheme.titleMedium,
),
const Spacer(),
FlowySvg(fieldType.icon()),
const HSpace(4),
Text(
fieldType.title(),
style: Theme.of(context).textTheme.titleMedium,
),
Icon(
Icons.arrow_forward_ios_sharp,
color: Theme.of(context).hintColor,
),
],
child: PropertyEditContainer(
child: Row(
children: [
PropertyTitle(
LocaleKeys.grid_field_propertyType.tr(),
),
const Spacer(),
FlowySvg(fieldType.icon()),
const HSpace(4),
Text(
fieldType.title(),
style: Theme.of(context).textTheme.titleMedium,
),
Icon(
Icons.arrow_forward_ios_sharp,
color: Theme.of(context).hintColor,
),
],
),
),
onTap: () => showFlowyMobileBottomSheet(
context,

View File

@ -1,3 +1,4 @@
import 'package:appflowy/mobile/presentation/database/card/card_property_edit/widgets/widgets.dart';
import 'package:appflowy/mobile/presentation/database/card/row/cells/date_cell/widgets/widgets.dart';
import 'package:appflowy/plugins/database_view/application/field/type_option/date_bloc.dart';
import 'package:appflowy/plugins/database_view/application/field/type_option/type_option_context.dart';
@ -38,39 +39,43 @@ class DateTypeOptionMobileWidget extends TypeOptionWidget {
typeOptionContext.typeOption = state.typeOption,
builder: (context, state) {
final List<Widget> children = [
DateFormatListTile(
currentFormatStr: state.typeOption.dateFormat.title(),
groupValue: context
.watch<DateTypeOptionBloc>()
.state
.typeOption
.dateFormat,
onChanged: (newFormat) {
if (newFormat != null) {
context.read<DateTypeOptionBloc>().add(
DateTypeOptionEvent.didSelectDateFormat(
newFormat,
),
);
}
},
PropertyEditContainer(
child: DateFormatListTile(
currentFormatStr: state.typeOption.dateFormat.title(),
groupValue: context
.watch<DateTypeOptionBloc>()
.state
.typeOption
.dateFormat,
onChanged: (newFormat) {
if (newFormat != null) {
context.read<DateTypeOptionBloc>().add(
DateTypeOptionEvent.didSelectDateFormat(
newFormat,
),
);
}
},
),
),
TimeFormatListTile(
currentFormatStr: state.typeOption.timeFormat.title(),
groupValue: context
.watch<DateTypeOptionBloc>()
.state
.typeOption
.timeFormat,
onChanged: (newFormat) {
if (newFormat != null) {
context.read<DateTypeOptionBloc>().add(
DateTypeOptionEvent.didSelectTimeFormat(
newFormat,
),
);
}
},
PropertyEditContainer(
child: TimeFormatListTile(
currentFormatStr: state.typeOption.timeFormat.title(),
groupValue: context
.watch<DateTypeOptionBloc>()
.state
.typeOption
.timeFormat,
onChanged: (newFormat) {
if (newFormat != null) {
context.read<DateTypeOptionBloc>().add(
DateTypeOptionEvent.didSelectTimeFormat(
newFormat,
),
);
}
},
),
),
];

View File

@ -1,4 +1,4 @@
import 'package:appflowy/mobile/presentation/database/card/card_property_edit/widgets/property_title.dart';
import 'package:appflowy/mobile/presentation/database/card/card_property_edit/widgets/widgets.dart';
import 'package:appflowy/mobile/presentation/widgets/widgets.dart';
import 'package:appflowy/plugins/database_view/application/field/type_option/number_bloc.dart';
import 'package:appflowy/plugins/database_view/application/field/type_option/number_format_bloc.dart';
@ -46,20 +46,22 @@ class NumberTypeOptionMobileWidget extends TypeOptionWidget {
typeOptionContext.typeOption = state.typeOption,
builder: (context, state) {
return GestureDetector(
child: Row(
children: [
PropertyTitle(LocaleKeys.grid_field_numberFormat.tr()),
const Spacer(),
const HSpace(4),
Text(
state.typeOption.format.title(),
style: Theme.of(context).textTheme.titleMedium,
),
Icon(
Icons.arrow_forward_ios,
color: Theme.of(context).hintColor,
),
],
child: PropertyEditContainer(
child: Row(
children: [
PropertyTitle(LocaleKeys.grid_field_numberFormat.tr()),
const Spacer(),
const HSpace(4),
Text(
state.typeOption.format.title(),
style: Theme.of(context).textTheme.titleMedium,
),
Icon(
Icons.arrow_forward_ios,
color: Theme.of(context).hintColor,
),
],
),
),
onTap: () => showFlowyMobileBottomSheet(
context,

View File

@ -1,3 +1,4 @@
import 'package:appflowy/mobile/presentation/database/card/card_property_edit/widgets/widgets.dart';
import 'package:appflowy/mobile/presentation/database/card/row/cells/date_cell/widgets/widgets.dart';
import 'package:appflowy/plugins/database_view/application/field/type_option/timestamp_bloc.dart';
import 'package:appflowy/plugins/database_view/application/field/type_option/type_option_context.dart';
@ -39,49 +40,53 @@ class TimestampTypeOptionMobileWidget extends TypeOptionWidget {
typeOptionContext.typeOption = state.typeOption,
builder: (context, state) {
final List<Widget> children = [
// used to add a separator padding at the top
const SizedBox.shrink(),
DateFormatListTile(
currentFormatStr: state.typeOption.dateFormat.title(),
groupValue: context
.watch<TimestampTypeOptionBloc>()
.state
.typeOption
.dateFormat,
onChanged: (newFormat) {
if (newFormat != null) {
context.read<TimestampTypeOptionBloc>().add(
TimestampTypeOptionEvent.didSelectDateFormat(
newFormat,
),
);
}
},
),
IncludeTimeSwitch(
switchValue: state.typeOption.includeTime,
onChanged: (value) => context
.read<TimestampTypeOptionBloc>()
.add(TimestampTypeOptionEvent.includeTime(value)),
),
if (state.typeOption.includeTime)
TimeFormatListTile(
currentFormatStr: state.typeOption.timeFormat.title(),
PropertyEditContainer(
child: DateFormatListTile(
currentFormatStr: state.typeOption.dateFormat.title(),
groupValue: context
.watch<TimestampTypeOptionBloc>()
.state
.typeOption
.timeFormat,
.dateFormat,
onChanged: (newFormat) {
if (newFormat != null) {
context.read<TimestampTypeOptionBloc>().add(
TimestampTypeOptionEvent.didSelectTimeFormat(
TimestampTypeOptionEvent.didSelectDateFormat(
newFormat,
),
);
}
},
),
),
PropertyEditContainer(
child: IncludeTimeSwitch(
switchValue: state.typeOption.includeTime,
onChanged: (value) => context
.read<TimestampTypeOptionBloc>()
.add(TimestampTypeOptionEvent.includeTime(value)),
),
),
if (state.typeOption.includeTime)
PropertyEditContainer(
child: TimeFormatListTile(
currentFormatStr: state.typeOption.timeFormat.title(),
groupValue: context
.watch<TimestampTypeOptionBloc>()
.state
.typeOption
.timeFormat,
onChanged: (newFormat) {
if (newFormat != null) {
context.read<TimestampTypeOptionBloc>().add(
TimestampTypeOptionEvent.didSelectTimeFormat(
newFormat,
),
);
}
},
),
),
];
return ListView.separated(

View File

@ -0,0 +1,26 @@
import 'package:flutter/material.dart';
class PropertyEditContainer extends StatelessWidget {
const PropertyEditContainer({
super.key,
required this.child,
this.padding,
});
final Widget child;
final EdgeInsets? padding;
@override
Widget build(BuildContext context) {
return Container(
height: 50,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface,
borderRadius: BorderRadius.circular(6),
),
alignment: Alignment.centerLeft,
padding: padding ?? const EdgeInsets.symmetric(horizontal: 8),
child: child,
);
}
}

View File

@ -0,0 +1,20 @@
import 'package:flutter/material.dart';
class PropertyEditGroupTitle extends StatelessWidget {
const PropertyEditGroupTitle(this.name, {super.key});
final String name;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: Text(
name,
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: Theme.of(context).colorScheme.onSurface,
),
),
);
}
}

View File

@ -11,7 +11,10 @@ class PropertyTitle extends StatelessWidget {
padding: const EdgeInsets.symmetric(vertical: 8),
child: Text(
name,
style: Theme.of(context).textTheme.titleMedium,
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: Theme.of(context).colorScheme.onBackground,
fontSize: 16,
),
),
);
}

View File

@ -0,0 +1,3 @@
export 'property_edit_group_title.dart';
export 'property_title.dart';
export 'property_edit_container.dart';

View File

@ -1,4 +1,5 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/presentation/database/card/card_property_edit/widgets/widgets.dart';
import 'package:appflowy/mobile/presentation/widgets/widgets.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/date_entities.pb.dart';
import 'package:easy_localization/easy_localization.dart';
@ -27,9 +28,8 @@ class DateFormatListTile extends StatelessWidget {
final style = Theme.of(context);
return Row(
children: [
Text(
PropertyTitle(
LocaleKeys.grid_field_dateFormat.tr(),
style: style.textTheme.titleMedium,
),
const Spacer(),
GestureDetector(

View File

@ -1,4 +1,5 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/presentation/database/card/card_property_edit/widgets/property_title.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
@ -16,9 +17,8 @@ class IncludeTimeSwitch extends StatelessWidget {
Widget build(BuildContext context) {
return Row(
children: [
Text(
PropertyTitle(
LocaleKeys.grid_field_includeTime.tr(),
style: Theme.of(context).textTheme.titleMedium,
),
const Spacer(),
Switch.adaptive(

View File

@ -1,4 +1,5 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/presentation/database/card/card_property_edit/widgets/widgets.dart';
import 'package:appflowy/mobile/presentation/widgets/widgets.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/date_entities.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/date_entities.pbenum.dart';
@ -28,9 +29,8 @@ class TimeFormatListTile extends StatelessWidget {
final style = Theme.of(context);
return Row(
children: [
Text(
PropertyTitle(
LocaleKeys.grid_field_timeFormat.tr(),
style: style.textTheme.titleMedium,
),
const Spacer(),
GestureDetector(

View File

@ -37,8 +37,8 @@ class MobileAppearance extends BaseAppearance {
brightness: brightness,
primary: _primaryColor,
onPrimary: Colors.white,
// TODO(yijing): add color later
secondary: Colors.white,
// group card & property edit background color
secondary: const Color(0xfff7f8fc), // shade 10
onSecondary: _onSecondaryColor,
error: const Color(0xffFB006D),
onError: const Color(0xffFB006D),

View File

@ -825,6 +825,9 @@
"cardActions": "Card Actions",
"cardDuplicated": "Card has been duplicated",
"cardDeleted": "Card has been deleted",
"showOnCard": "Show on card detail",
"setting": "Setting",
"propertyName": "Property name",
"menuName": "Board",
"showUngrouped": "Show ungrouped items",
"ungroupedButtonText": "Ungrouped",