feat: edit property (#4065)

* feat: edit property

* feat: disable actions if field is primary

* feat: remove include time

* chore: set title to medium

* fix: flutter analyze

* chore: update built in text style

* chore: update text style

* fix: unable to click the calendar day
This commit is contained in:
Lucas.Xu
2023-12-02 20:39:03 +08:00
committed by GitHub
parent 9824d5980a
commit 415f121720
31 changed files with 447 additions and 253 deletions

View File

@ -202,4 +202,4 @@ SPEC CHECKSUMS:
PODFILE CHECKSUM: 8c681999c7764593c94846b2a64b44d86f7a27ac PODFILE CHECKSUM: 8c681999c7764593c94846b2a64b44d86f7a27ac
COCOAPODS: 1.11.3 COCOAPODS: 1.12.1

View File

@ -515,7 +515,7 @@
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEAD_CODE_STRIPPING = NO; DEAD_CODE_STRIPPING = NO;
DEVELOPMENT_TEAM = ""; DEVELOPMENT_TEAM = VHB67HRSZG;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = AppFlowy; INFOPLIST_KEY_CFBundleDisplayName = AppFlowy;

View File

@ -34,7 +34,6 @@ class AppBarCancelButton extends StatelessWidget {
onTap: onTap, onTap: onTap,
child: FlowyText( child: FlowyText(
LocaleKeys.button_cancel.tr(), LocaleKeys.button_cancel.tr(),
fontSize: 16.0,
), ),
); );
} }

View File

@ -17,7 +17,6 @@ class MobileViewItemBottomSheetHeader extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = Theme.of(context);
return Row( return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
@ -44,9 +43,14 @@ class MobileViewItemBottomSheetHeader extends StatelessWidget {
}, },
), ),
// title // title
Text( ConstrainedBox(
view.name, constraints: BoxConstraints(
style: theme.textTheme.labelSmall, maxWidth: MediaQuery.of(context).size.width * 0.6,
),
child: FlowyText.medium(
view.name,
overflow: TextOverflow.ellipsis,
),
), ),
const HSpace(24.0), const HSpace(24.0),
], ],

View File

@ -64,7 +64,6 @@ Future<T?> showMobileBottomSheet<T>(
: const SizedBox.shrink(), : const SizedBox.shrink(),
FlowyText( FlowyText(
title, title,
fontSize: 16.0,
), ),
showCloseButton showCloseButton
? HSpace(padding.right + 24) ? HSpace(padding.right + 24)

View File

@ -1,6 +1,6 @@
import 'package:appflowy/generated/locale_keys.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/base/app_bar_actions.dart';
import 'package:appflowy/mobile/presentation/database/card/card_detail/widgets/_new_field_option.dart'; import 'package:appflowy/mobile/presentation/database/card/card_detail/widgets/_field_options_eidtor.dart';
import 'package:appflowy/util/field_type_extension.dart'; import 'package:appflowy/util/field_type_extension.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart'; import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
@ -46,9 +46,8 @@ class _MobileNewPropertyScreenState extends State<MobileNewPropertyScreen> {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
centerTitle: true, centerTitle: true,
title: FlowyText( title: FlowyText.medium(
LocaleKeys.grid_field_newProperty.tr(), LocaleKeys.grid_field_newProperty.tr(),
fontSize: 16.0,
), ),
leading: AppBarCancelButton( leading: AppBarCancelButton(
onTap: () => context.pop(), onTap: () => context.pop(),
@ -62,7 +61,7 @@ class _MobileNewPropertyScreenState extends State<MobileNewPropertyScreen> {
), ),
], ],
), ),
body: FieldOption( body: FieldOptionEditor(
mode: FieldOptionMode.add, mode: FieldOptionMode.add,
defaultValues: optionValues, defaultValues: optionValues,
onOptionValuesChanged: (optionValues) { onOptionValuesChanged: (optionValues) {
@ -88,10 +87,9 @@ class _SaveButton extends StatelessWidget {
alignment: Alignment.center, alignment: Alignment.center,
child: GestureDetector( child: GestureDetector(
onTap: onSave, onTap: onSave,
child: FlowyText( child: FlowyText.medium(
LocaleKeys.button_save.tr(), LocaleKeys.button_save.tr(),
color: const Color(0xFF00ADDC), color: const Color(0xFF00ADDC),
fontSize: 16.0,
), ),
), ),
), ),

View File

@ -0,0 +1,139 @@
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_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 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() =>
_MobileEditPropertyScreenState();
}
class _MobileEditPropertyScreenState extends State<MobileEditPropertyScreen> {
late Future<FieldOptionValues?> future;
FieldOptionValues? optionValues;
@override
void initState() {
super.initState();
future = FieldOptionValues.get(
viewId: widget.viewId,
fieldId: widget.field.id,
fieldType: widget.field.fieldType,
);
}
@override
Widget build(BuildContext context) {
final viewId = widget.viewId;
final fieldId = widget.field.id;
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: FlowyText.medium(
LocaleKeys.grid_field_editProperty.tr(),
),
leading: AppBarCancelButton(
onTap: () => context.pop(),
),
leadingWidth: 120,
actions: [
_SaveButton(
onSave: () {
context.pop(optionValues);
},
),
],
),
body: FutureBuilder<FieldOptionValues?>(
future: future,
builder: (context, snapshot) {
final optionValues = snapshot.data;
if (optionValues == null) {
return const Center(child: CircularProgressIndicator.adaptive());
}
return FieldOptionEditor(
mode: FieldOptionMode.edit,
isPrimary: widget.isPrimary,
defaultValues: optionValues,
onOptionValuesChanged: (optionValues) {
this.optionValues = optionValues;
},
onAction: (action) {
final service = FieldBackendService(
viewId: viewId,
fieldId: fieldId,
);
switch (action) {
case FieldOptionAction.delete:
service.deleteField();
break;
case FieldOptionAction.duplicate:
service.duplicateField();
break;
case FieldOptionAction.hide:
FieldSettingsBackendService(viewId: viewId)
.updateFieldSettings(
fieldId: fieldId,
fieldVisibility: FieldVisibility.AlwaysHidden,
);
break;
}
context.pop();
},
);
},
),
);
}
}
class _SaveButton extends StatelessWidget {
const _SaveButton({
required this.onSave,
});
final VoidCallback onSave;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(right: 16.0),
child: Align(
alignment: Alignment.center,
child: GestureDetector(
onTap: onSave,
child: FlowyText.medium(
LocaleKeys.button_save.tr(),
color: const Color(0xFF00ADDC),
),
),
),
);
}
}

View File

@ -75,7 +75,7 @@ class _FieldHeader extends StatelessWidget {
), ),
FlowyText.medium( FlowyText.medium(
LocaleKeys.titleBar_addField.tr(), LocaleKeys.titleBar_addField.tr(),
fontSize: 16.0, fontSize: 17.0,
), ),
const HSpace(120), const HSpace(120),
], ],
@ -106,7 +106,9 @@ class _Field extends StatelessWidget {
size: Size.square(width / 4.0), size: Size.square(width / 4.0),
), ),
const VSpace(6.0), const VSpace(6.0),
FlowyText(type.i18n), FlowyText(
type.i18n,
),
], ],
), ),
); );

View File

@ -7,6 +7,7 @@ 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/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/_field_options.dart';
import 'package:appflowy/mobile/presentation/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'; import 'package:appflowy/plugins/database_view/application/field/type_option/number_format_bloc.dart';
import 'package:appflowy/plugins/database_view/application/field/type_option/type_option_service.dart'; import 'package:appflowy/plugins/database_view/application/field/type_option/type_option_service.dart';
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/header/type_option/date.dart'; import 'package:appflowy/plugins/database_view/grid/presentation/widgets/header/type_option/date.dart';
@ -32,7 +33,6 @@ class FieldOptionValues {
required this.type, required this.type,
required this.name, required this.name,
this.dateFormate, this.dateFormate,
this.includeTime = false,
this.timeFormat, this.timeFormat,
this.numberFormat, this.numberFormat,
this.selectOption = const [], this.selectOption = const [],
@ -43,7 +43,6 @@ class FieldOptionValues {
// FieldType.Date // FieldType.Date
DateFormatPB? dateFormate; DateFormatPB? dateFormate;
bool includeTime;
TimeFormatPB? timeFormat; TimeFormatPB? timeFormat;
// FieldType.Num // FieldType.Num
@ -56,65 +55,110 @@ class FieldOptionValues {
Future<void> create({ Future<void> create({
required String viewId, required String viewId,
}) async { }) async {
Uint8List? typeOptionData;
switch (type) {
case FieldType.RichText:
break;
case FieldType.URL:
break;
case FieldType.Checkbox:
break;
case FieldType.Number:
typeOptionData = NumberTypeOptionPB(
format: numberFormat,
).writeToBuffer();
break;
case FieldType.DateTime:
typeOptionData = DateTypeOptionPB(
dateFormat: dateFormate,
timeFormat: timeFormat,
).writeToBuffer();
break;
case FieldType.SingleSelect:
typeOptionData = SingleSelectTypeOptionPB(
options: selectOption,
).writeToBuffer();
case FieldType.MultiSelect:
typeOptionData = MultiSelectTypeOptionPB(
options: selectOption,
).writeToBuffer();
break;
default:
throw UnimplementedError();
}
await TypeOptionBackendService.createFieldTypeOption( await TypeOptionBackendService.createFieldTypeOption(
viewId: viewId, viewId: viewId,
fieldType: type, fieldType: type,
fieldName: name, fieldName: name,
typeOptionData: typeOptionData, typeOptionData: toTypeOptionBuffer(),
);
}
Uint8List? toTypeOptionBuffer() {
switch (type) {
case FieldType.RichText:
case FieldType.URL:
case FieldType.Checkbox:
return null;
case FieldType.Number:
return NumberTypeOptionPB(
format: numberFormat,
).writeToBuffer();
case FieldType.DateTime:
return DateTypeOptionPB(
dateFormat: dateFormate,
timeFormat: timeFormat,
).writeToBuffer();
case FieldType.SingleSelect:
return SingleSelectTypeOptionPB(
options: selectOption,
).writeToBuffer();
case FieldType.MultiSelect:
return MultiSelectTypeOptionPB(
options: selectOption,
).writeToBuffer();
default:
throw UnimplementedError();
}
}
static Future<FieldOptionValues?> get({
required String viewId,
required String fieldId,
required FieldType fieldType,
}) async {
final service = FieldBackendService(viewId: viewId, fieldId: fieldId);
final result = await service.getFieldTypeOptionData(fieldType: fieldType);
return result.fold(
(option) {
final type = option.field_2.fieldType;
final buffer = option.typeOptionData;
return FieldOptionValues(
type: type,
name: option.field_2.name,
numberFormat: type == FieldType.Number
? NumberTypeOptionPB.fromBuffer(buffer).format
: null,
dateFormate: type == FieldType.DateTime
? DateTypeOptionPB.fromBuffer(buffer).dateFormat
: null,
timeFormat: type == FieldType.DateTime
? DateTypeOptionPB.fromBuffer(buffer).timeFormat
: null,
selectOption: switch (type) {
FieldType.SingleSelect =>
SingleSelectTypeOptionPB.fromBuffer(buffer).options,
FieldType.MultiSelect =>
MultiSelectTypeOptionPB.fromBuffer(buffer).options,
_ => [],
},
);
},
(error) => null,
); );
} }
} }
class FieldOption extends StatefulWidget { enum FieldOptionAction {
const FieldOption({ hide,
duplicate,
delete,
}
class FieldOptionEditor extends StatefulWidget {
const FieldOptionEditor({
super.key, super.key,
required this.mode, required this.mode,
required this.defaultValues, required this.defaultValues,
required this.onOptionValuesChanged, required this.onOptionValuesChanged,
this.onAction,
this.isPrimary = false,
}); });
final FieldOptionMode mode; final FieldOptionMode mode;
final FieldOptionValues defaultValues; final FieldOptionValues defaultValues;
final void Function(FieldOptionValues values) onOptionValuesChanged; final void Function(FieldOptionValues values) onOptionValuesChanged;
// only used in edit mode
final void Function(FieldOptionAction action)? onAction;
// the primary field can't be deleted, duplicated, and changed type
final bool isPrimary;
@override @override
State<FieldOption> createState() => _FieldOptionState(); State<FieldOptionEditor> createState() => _FieldOptionEditorState();
} }
class _FieldOptionState extends State<FieldOption> { class _FieldOptionEditorState extends State<FieldOptionEditor> {
final controller = TextEditingController(); final controller = TextEditingController();
late FieldOptionValues values; late FieldOptionValues values;
@ -124,7 +168,7 @@ class _FieldOptionState extends State<FieldOption> {
super.initState(); super.initState();
values = widget.defaultValues; values = widget.defaultValues;
controller.text = values.type.i18n; controller.text = values.name;
} }
@override @override
@ -136,6 +180,7 @@ class _FieldOptionState extends State<FieldOption> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final option = _buildOption();
return Container( return Container(
color: Theme.of(context).colorScheme.secondaryContainer, color: Theme.of(context).colorScheme.secondaryContainer,
height: MediaQuery.of(context).size.height, height: MediaQuery.of(context).size.height,
@ -151,18 +196,26 @@ class _FieldOptionState extends State<FieldOption> {
}, },
), ),
const _Divider(), const _Divider(),
_PropertyType( if (!widget.isPrimary) ...[
type: values.type, _PropertyType(
onSelected: (type) => setState( type: values.type,
() { onSelected: (type) => setState(
controller.text = type.i18n; () {
_updateOptionValues(type: type, name: type.i18n); if (widget.mode == FieldOptionMode.add) {
}, controller.text = type.i18n;
}
_updateOptionValues(type: type, name: type.i18n);
},
),
), ),
), const _Divider(),
const _Divider(), if (option.isNotEmpty) ...[
..._buildOption(), ...option,
const _Divider(),
],
],
..._buildOptionActions(), ..._buildOptionActions(),
const _Divider(),
], ],
), ),
), ),
@ -171,18 +224,6 @@ class _FieldOptionState extends State<FieldOption> {
List<Widget> _buildOption() { List<Widget> _buildOption() {
switch (values.type) { switch (values.type) {
case FieldType.RichText:
return [
const _TextOption(),
];
case FieldType.URL:
return [
const _URLOption(),
];
case FieldType.Checkbox:
return [
const _CheckboxOption(),
];
case FieldType.Number: case FieldType.Number:
return [ return [
_NumberOption( _NumberOption(
@ -204,10 +245,8 @@ class _FieldOptionState extends State<FieldOption> {
), ),
const _Divider(), const _Divider(),
_TimeOption( _TimeOption(
includeTime: values.includeTime,
selectedFormat: values.timeFormat ?? TimeFormatPB.TwelveHour, selectedFormat: values.timeFormat ?? TimeFormatPB.TwelveHour,
onSelected: (includeTime, format) => _updateOptionValues( onSelected: (format) => _updateOptionValues(
includeTime: includeTime,
timeFormat: format, timeFormat: format,
), ),
), ),
@ -244,19 +283,24 @@ class _FieldOptionState extends State<FieldOption> {
FieldOptionMode.add => [], FieldOptionMode.add => [],
FieldOptionMode.edit => [ FieldOptionMode.edit => [
FlowyOptionTile.text( FlowyOptionTile.text(
text: LocaleKeys.button_delete.tr(),
leftIcon: const FlowySvg(FlowySvgs.delete_s),
),
FlowyOptionTile.text(
showTopBorder: false,
text: LocaleKeys.button_duplicate.tr(),
leftIcon: const FlowySvg(FlowySvgs.copy_s),
),
FlowyOptionTile.text(
showTopBorder: false,
text: LocaleKeys.grid_field_hide.tr(), text: LocaleKeys.grid_field_hide.tr(),
leftIcon: const FlowySvg(FlowySvgs.hide_s), leftIcon: const FlowySvg(FlowySvgs.hide_s),
onTap: () => widget.onAction?.call(FieldOptionAction.hide),
), ),
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),
onTap: () => widget.onAction?.call(FieldOptionAction.delete),
),
] ]
}; };
} }
@ -265,7 +309,6 @@ class _FieldOptionState extends State<FieldOption> {
FieldType? type, FieldType? type,
String? name, String? name,
DateFormatPB? dateFormate, DateFormatPB? dateFormate,
bool? includeTime,
TimeFormatPB? timeFormat, TimeFormatPB? timeFormat,
NumberFormatPB? numberFormat, NumberFormatPB? numberFormat,
List<SelectOptionPB>? selectOption, List<SelectOptionPB>? selectOption,
@ -279,9 +322,6 @@ class _FieldOptionState extends State<FieldOption> {
if (dateFormate != null) { if (dateFormate != null) {
values.dateFormate = dateFormate; values.dateFormate = dateFormate;
} }
if (includeTime != null) {
values.includeTime = includeTime;
}
if (timeFormat != null) { if (timeFormat != null) {
values.timeFormat = timeFormat; values.timeFormat = timeFormat;
} }
@ -348,7 +388,6 @@ class _PropertyType extends StatelessWidget {
FlowyText( FlowyText(
type.i18n, type.i18n,
color: Theme.of(context).hintColor, color: Theme.of(context).hintColor,
fontSize: 16.0,
), ),
const HSpace(4.0), const HSpace(4.0),
FlowySvg( FlowySvg(
@ -394,33 +433,6 @@ class _Divider extends StatelessWidget {
} }
} }
class _TextOption extends StatelessWidget {
const _TextOption();
@override
Widget build(BuildContext context) {
return const SizedBox.shrink();
}
}
class _URLOption extends StatelessWidget {
const _URLOption();
@override
Widget build(BuildContext context) {
return const SizedBox.shrink();
}
}
class _CheckboxOption extends StatelessWidget {
const _CheckboxOption();
@override
Widget build(BuildContext context) {
return const SizedBox.shrink();
}
}
class _DateOption extends StatefulWidget { class _DateOption extends StatefulWidget {
const _DateOption({ const _DateOption({
required this.selectedFormat, required this.selectedFormat,
@ -456,7 +468,6 @@ class _DateOptionState extends State<_DateOption> {
), ),
child: FlowyText( child: FlowyText(
LocaleKeys.grid_field_dateFormat.tr(), LocaleKeys.grid_field_dateFormat.tr(),
fontSize: 16.0,
color: Theme.of(context).hintColor, color: Theme.of(context).hintColor,
), ),
), ),
@ -480,14 +491,12 @@ class _DateOptionState extends State<_DateOption> {
class _TimeOption extends StatefulWidget { class _TimeOption extends StatefulWidget {
const _TimeOption({ const _TimeOption({
required this.includeTime,
required this.selectedFormat, required this.selectedFormat,
required this.onSelected, required this.onSelected,
}); });
final bool includeTime;
final TimeFormatPB selectedFormat; final TimeFormatPB selectedFormat;
final Function(bool includeTime, TimeFormatPB format) onSelected; final Function(TimeFormatPB format) onSelected;
@override @override
State<_TimeOption> createState() => _TimeOptionState(); State<_TimeOption> createState() => _TimeOptionState();
@ -495,14 +504,12 @@ class _TimeOption extends StatefulWidget {
class _TimeOptionState extends State<_TimeOption> { class _TimeOptionState extends State<_TimeOption> {
TimeFormatPB selectedFormat = TimeFormatPB.TwelveHour; TimeFormatPB selectedFormat = TimeFormatPB.TwelveHour;
bool includeTime = false;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
selectedFormat = widget.selectedFormat; selectedFormat = widget.selectedFormat;
includeTime = widget.includeTime;
} }
@override @override
@ -517,34 +524,22 @@ class _TimeOptionState extends State<_TimeOption> {
), ),
child: FlowyText( child: FlowyText(
LocaleKeys.grid_field_timeFormat.tr(), LocaleKeys.grid_field_timeFormat.tr(),
fontSize: 16.0,
color: Theme.of(context).hintColor, color: Theme.of(context).hintColor,
), ),
), ),
FlowyOptionTile.switcher( ...TimeFormatPB.values.mapIndexed((index, format) {
text: LocaleKeys.grid_field_includeTime.tr(), return FlowyOptionTile.checkbox(
isSelected: includeTime, text: format.title(),
onValueChanged: (includeTime) { isSelected: selectedFormat == format,
widget.onSelected(includeTime, selectedFormat); showTopBorder: false,
setState(() { onTap: () {
this.includeTime = includeTime; widget.onSelected(format);
}); setState(() {
}, selectedFormat = format;
), });
if (includeTime) },
...TimeFormatPB.values.mapIndexed((index, format) { );
return FlowyOptionTile.checkbox( }),
text: format.title(),
isSelected: selectedFormat == format,
showTopBorder: false,
onTap: () {
widget.onSelected(includeTime, format);
setState(() {
selectedFormat = format;
});
},
);
}),
], ],
); );
} }
@ -569,7 +564,6 @@ class _NumberOption extends StatelessWidget {
FlowyText( FlowyText(
selectedFormat.title(), selectedFormat.title(),
color: Theme.of(context).hintColor, color: Theme.of(context).hintColor,
fontSize: 16.0,
), ),
const HSpace(4.0), const HSpace(4.0),
FlowySvg( FlowySvg(
@ -663,7 +657,6 @@ class _SelectOption extends StatelessWidget {
), ),
child: FlowyText( child: FlowyText(
LocaleKeys.grid_field_optionTitle.tr(), LocaleKeys.grid_field_optionTitle.tr(),
fontSize: 16.0,
color: Theme.of(context).hintColor, color: Theme.of(context).hintColor,
), ),
), ),

View File

@ -58,7 +58,9 @@ class _MobileDateCellEditScreenState extends State<MobileDateCellEditScreen> {
Widget _buildFullScreen() { Widget _buildFullScreen() {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: Text(LocaleKeys.titleBar_date.tr()), title: FlowyText.medium(
LocaleKeys.titleBar_date.tr(),
),
), ),
body: _buildBody(), body: _buildBody(),
); );
@ -117,7 +119,7 @@ class _MobileDateCellEditScreenState extends State<MobileDateCellEditScreen> {
} }
Widget _buildHeader() { Widget _buildHeader() {
const iconWidth = 36.0; const iconWidth = 30.0;
const height = 44.0; const height = 44.0;
return Padding( return Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0), padding: const EdgeInsets.symmetric(horizontal: 8.0),
@ -139,7 +141,7 @@ class _MobileDateCellEditScreenState extends State<MobileDateCellEditScreen> {
alignment: Alignment.center, alignment: Alignment.center,
child: FlowyText.medium( child: FlowyText.medium(
LocaleKeys.grid_field_dateFieldName.tr(), LocaleKeys.grid_field_dateFieldName.tr(),
fontSize: 18, fontSize: 16,
), ),
), ),
].map((e) => SizedBox(height: height, child: e)).toList(), ].map((e) => SizedBox(height: height, child: e)).toList(),

View File

@ -9,14 +9,14 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
class MobileCalendarEventsScreen extends StatefulWidget { class MobileCalendarEventsScreen extends StatefulWidget {
static const routeName = "/calendar-events"; static const routeName = '/calendar_events';
// GoRouter Arguments // GoRouter Arguments
static const calendarBlocKey = "calendar_bloc"; static const calendarBlocKey = 'calendar_bloc';
static const calendarDateKey = "date"; static const calendarDateKey = 'date';
static const calendarEventsKey = "events"; static const calendarEventsKey = 'events';
static const calendarRowCacheKey = "row_cache"; static const calendarRowCacheKey = 'row_cache';
static const calendarViewIdKey = "view_id"; static const calendarViewIdKey = 'view_id';
const MobileCalendarEventsScreen({ const MobileCalendarEventsScreen({
super.key, super.key,

View File

@ -137,7 +137,7 @@ class _TrashButton extends StatelessWidget {
color: Theme.of(context).colorScheme.onSurface, color: Theme.of(context).colorScheme.onSurface,
), ),
leftIconSize: const Size.square(24), leftIconSize: const Size.square(24),
text: FlowyText( text: FlowyText.medium(
LocaleKeys.trash_text.tr(), LocaleKeys.trash_text.tr(),
fontSize: 18.0, fontSize: 18.0,
), ),

View File

@ -80,8 +80,8 @@ class _RecentViews extends StatelessWidget {
separatorBuilder: () => const HSpace(8), separatorBuilder: () => const HSpace(8),
children: recentViews children: recentViews
.map( .map(
(view) => SizedBox( (view) => SizedBox.square(
width: 150, dimension: 148,
child: MobileRecentView(view: view), child: MobileRecentView(view: view),
), ),
) )

View File

@ -96,8 +96,8 @@ class _MobileRecentViewState extends State<MobileRecentView> {
), ),
Expanded( Expanded(
child: Padding( child: Padding(
padding: const EdgeInsets.fromLTRB(8, 16, 8, 2), padding: const EdgeInsets.fromLTRB(8, 18, 8, 2),
child: FlowyText( child: FlowyText.medium(
view.name, view.name,
maxLines: 2, maxLines: 2,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
@ -110,7 +110,7 @@ class _MobileRecentViewState extends State<MobileRecentView> {
Align( Align(
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: Padding( child: Padding(
padding: const EdgeInsets.only(left: 4), padding: const EdgeInsets.only(left: 8.0),
child: icon.isNotEmpty child: icon.isNotEmpty
? EmojiText( ? EmojiText(
emoji: icon, emoji: icon,

View File

@ -307,7 +307,7 @@ class _SingleMobileInnerViewItemState extends State<SingleMobileInnerViewItem> {
const HSpace(8), const HSpace(8),
// title // title
Expanded( Expanded(
child: FlowyText.regular( child: FlowyText.medium(
widget.view.name, widget.view.name,
fontSize: 18.0, fontSize: 18.0,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,

View File

@ -1,5 +1,5 @@
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
/// Widget for the root/initial pages in the bottom navigation bar. /// Widget for the root/initial pages in the bottom navigation bar.
class RootPlaceholderScreen extends StatelessWidget { class RootPlaceholderScreen extends StatelessWidget {
@ -24,31 +24,10 @@ class RootPlaceholderScreen extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: Text('Root of section $label'), centerTitle: true,
), title: FlowyText.medium(label),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text('$label Page', style: Theme.of(context).textTheme.titleLarge),
const Padding(padding: EdgeInsets.all(4)),
TextButton(
onPressed: () {
context.go(detailsPath, extra: '$label-XYZ');
},
child: const Text('View details'),
),
const Padding(padding: EdgeInsets.all(4)),
if (secondDetailsPath != null)
TextButton(
onPressed: () {
context.go(secondDetailsPath!);
},
child: const Text('View more details'),
),
],
),
), ),
body: const SizedBox.shrink(),
); );
} }
} }

View File

@ -22,7 +22,8 @@ class FlowyOptionTile extends StatelessWidget {
this.onTap, this.onTap,
this.trailing, this.trailing,
this.textFieldPadding = const EdgeInsets.symmetric( this.textFieldPadding = const EdgeInsets.symmetric(
horizontal: 16.0, horizontal: 12.0,
vertical: 2.0,
), ),
this.isSelected = false, this.isSelected = false,
this.textFieldHintText, this.textFieldHintText,
@ -55,7 +56,8 @@ class FlowyOptionTile extends StatelessWidget {
void Function(String value)? onTextChanged, void Function(String value)? onTextChanged,
void Function(String value)? onTextSubmitted, void Function(String value)? onTextSubmitted,
EdgeInsets textFieldPadding = const EdgeInsets.symmetric( EdgeInsets textFieldPadding = const EdgeInsets.symmetric(
horizontal: 16.0, horizontal: 12.0,
vertical: 2.0,
), ),
bool showTopBorder = true, bool showTopBorder = true,
bool showBottomBorder = true, bool showBottomBorder = true,
@ -150,6 +152,7 @@ class FlowyOptionTile extends StatelessWidget {
showTopBorder: showTopBorder, showTopBorder: showTopBorder,
showBottomBorder: showBottomBorder, showBottomBorder: showBottomBorder,
child: Row( child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
_buildText(), _buildText(),
..._buildTextField(), ..._buildTextField(),
@ -185,7 +188,6 @@ class FlowyOptionTile extends StatelessWidget {
useIntrinsicWidth: true, useIntrinsicWidth: true,
text: FlowyText( text: FlowyText(
text!, text!,
fontSize: 16.0,
), ),
margin: const EdgeInsets.symmetric( margin: const EdgeInsets.symmetric(
horizontal: 16.0, horizontal: 16.0,
@ -206,7 +208,6 @@ class FlowyOptionTile extends StatelessWidget {
), ),
child: FlowyText( child: FlowyText(
text!, text!,
fontSize: 16.0,
), ),
); );
} }
@ -222,11 +223,12 @@ class FlowyOptionTile extends StatelessWidget {
return [ return [
if (leading != null) leading!, if (leading != null) leading!,
Expanded( Expanded(
child: ConstrainedBox( child: Container(
constraints: const BoxConstraints.tightFor( constraints: const BoxConstraints.tightFor(
height: 52.0, height: 54.0,
width: double.infinity, width: double.infinity,
), ),
alignment: Alignment.center,
child: TextField( child: TextField(
controller: controller, controller: controller,
textInputAction: TextInputAction.done, textInputAction: TextInputAction.done,

View File

@ -1,8 +1,8 @@
import 'package:appflowy_backend/protobuf/flowy-database2/database_entities.pb.dart';
import 'package:dartz/dartz.dart';
import 'package:appflowy_backend/dispatch/dispatch.dart'; import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-database2/database_entities.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:dartz/dartz.dart';
/// FieldService consists of lots of event functions. We define the events in the backend(Rust), /// FieldService consists of lots of event functions. We define the events in the backend(Rust),
/// you can find the corresponding event implementation in event_map.rs of the corresponding crate. /// you can find the corresponding event implementation in event_map.rs of the corresponding crate.
@ -56,6 +56,17 @@ class FieldBackendService {
return DatabaseEventUpdateFieldTypeOption(payload).send(); return DatabaseEventUpdateFieldTypeOption(payload).send();
} }
Future<Either<Unit, FlowyError>> updateFieldType({
required FieldType fieldType,
}) {
final payload = UpdateFieldTypePayloadPB.create()
..viewId = viewId
..fieldId = fieldId
..fieldType = fieldType;
return DatabaseEventUpdateFieldType(payload).send();
}
Future<Either<Unit, FlowyError>> deleteField() { Future<Either<Unit, FlowyError>> deleteField() {
final payload = DeleteFieldPayloadPB.create() final payload = DeleteFieldPayloadPB.create()
..viewId = viewId ..viewId = viewId

View File

@ -3,7 +3,7 @@ import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart'; import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart';
import 'package:appflowy/mobile/presentation/database/card/card_detail/mobile_create_field_screen.dart'; import 'package:appflowy/mobile/presentation/database/card/card_detail/mobile_create_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.dart';
import 'package:appflowy/mobile/presentation/database/card/card_detail/widgets/_new_field_option.dart'; import 'package:appflowy/mobile/presentation/database/card/card_detail/widgets/_field_options_eidtor.dart';
import 'package:appflowy/plugins/database_view/application/field/field_controller.dart'; import 'package:appflowy/plugins/database_view/application/field/field_controller.dart';
import 'package:appflowy/plugins/database_view/grid/application/grid_bloc.dart'; import 'package:appflowy/plugins/database_view/grid/application/grid_bloc.dart';
import 'package:appflowy/plugins/database_view/grid/application/grid_header_bloc.dart'; import 'package:appflowy/plugins/database_view/grid/application/grid_header_bloc.dart';

View File

@ -1,12 +1,12 @@
import 'package:appflowy/generated/flowy_svgs.g.dart'; import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/mobile/presentation/database/card/card_detail/mobile_edit_field_screen.dart';
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet_database_field_editor.dart'; import 'package:appflowy/mobile/presentation/database/card/card_detail/widgets/_field_options_eidtor.dart';
import 'package:appflowy/mobile/presentation/widgets/flowy_paginated_bottom_sheet.dart';
import 'package:appflowy/plugins/database_view/application/field/field_info.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:appflowy/plugins/database_view/application/field/field_controller.dart'; import 'package:appflowy/plugins/database_view/application/field/field_controller.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:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'field_type_extension.dart'; import 'field_type_extension.dart';
@ -41,19 +41,41 @@ class MobileFieldButton extends StatelessWidget {
), ),
), ),
child: FlowyButton( child: FlowyButton(
onTap: () { onTap: () async {
showPaginatedBottomSheet( final optionValues = await context.push<FieldOptionValues>(
context, MobileEditPropertyScreen.routeName,
page: SheetPage( extra: {
title: LocaleKeys.grid_field_editProperty.tr(), MobileEditPropertyScreen.argViewId: viewId,
body: MobileDBBottomSheetFieldEditor( MobileEditPropertyScreen.argField: fieldInfo.field,
viewId: viewId, MobileEditPropertyScreen.argIsPrimary: fieldInfo.isPrimary,
field: fieldInfo.field, },
fieldController: fieldController,
),
),
); );
if (optionValues != null) {
final fieldId = fieldInfo.field.id;
final service = FieldBackendService(
viewId: viewId,
fieldId: fieldId,
);
if (optionValues.name != fieldInfo.name) {
await service.updateField(name: optionValues.name);
}
if (optionValues.type != fieldInfo.fieldType) {
await service.updateFieldType(fieldType: optionValues.type);
}
final data = optionValues.toTypeOptionBuffer();
if (data != null) {
await FieldBackendService.updateFieldTypeOption(
viewId: viewId,
fieldId: fieldId,
typeOptionData: data,
);
}
}
}, },
radius: BorderRadius.zero,
margin: const EdgeInsets.symmetric(vertical: 12, horizontal: 8), margin: const EdgeInsets.symmetric(vertical: 12, horizontal: 8),
leftIcon: FlowySvg( leftIcon: FlowySvg(
fieldInfo.fieldType.icon(), fieldInfo.fieldType.icon(),

View File

@ -41,9 +41,7 @@ class _MobileDatePickerState extends State<MobileDatePicker> {
Widget _buildCalendar(BuildContext context) { Widget _buildCalendar(BuildContext context) {
const selectedColor = Color(0xFF00BCF0); const selectedColor = Color(0xFF00BCF0);
final textStyle = Theme.of(context).textTheme.bodyMedium!.copyWith( final textStyle = Theme.of(context).textTheme.bodyMedium!.copyWith();
fontSize: 16.0,
);
const boxDecoration = BoxDecoration( const boxDecoration = BoxDecoration(
shape: BoxShape.circle, shape: BoxShape.circle,
); );
@ -156,7 +154,6 @@ class _MobileDatePickerState extends State<MobileDatePicker> {
builder: (_, value, ___) { builder: (_, value, ___) {
return FlowyText( return FlowyText(
DateFormat.yMMMM(value.$2).format(value.$1), DateFormat.yMMMM(value.$2).format(value.$1),
fontSize: 16.0,
); );
}, },
), ),

View File

@ -426,6 +426,7 @@ class DocumentCoverState extends State<DocumentCover> {
children: [ children: [
IntrinsicWidth( IntrinsicWidth(
child: RoundedTextButton( child: RoundedTextButton(
fontSize: 14,
onPressed: () { onPressed: () {
showMobileBottomSheet( showMobileBottomSheet(
context, context,

View File

@ -6,6 +6,7 @@ import 'package:appflowy/plugins/document/presentation/editor_plugins/mobile_too
import 'package:appflowy/plugins/document/presentation/more/cubit/document_appearance_cubit.dart'; import 'package:appflowy/plugins/document/presentation/more/cubit/document_appearance_cubit.dart';
import 'package:appflowy/plugins/inline_actions/inline_actions_menu.dart'; import 'package:appflowy/plugins/inline_actions/inline_actions_menu.dart';
import 'package:appflowy/util/google_font_family_extension.dart'; import 'package:appflowy/util/google_font_family_extension.dart';
import 'package:appflowy/workspace/application/settings/appearance/base_appearance.dart';
import 'package:appflowy_editor/appflowy_editor.dart' hide Log; import 'package:appflowy_editor/appflowy_editor.dart' hide Log;
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
@ -160,7 +161,7 @@ class EditorStyleCustomizer {
final theme = Theme.of(context); final theme = Theme.of(context);
final fontSize = context.read<DocumentAppearanceCubit>().state.fontSize; final fontSize = context.read<DocumentAppearanceCubit>().state.fontSize;
return TextStyle( return TextStyle(
fontFamily: 'poppins', fontFamily: builtInFontFamily,
fontSize: fontSize, fontSize: fontSize,
height: 1.5, height: 1.5,
color: theme.colorScheme.onBackground.withOpacity(0.6), color: theme.colorScheme.onBackground.withOpacity(0.6),
@ -207,7 +208,7 @@ class EditorStyleCustomizer {
fontWeight: fontWeight, fontWeight: fontWeight,
); );
} on Exception { } on Exception {
return GoogleFonts.getFont('Poppins'); return GoogleFonts.getFont(builtInFontFamily);
} }
} }

View File

@ -1,4 +1,5 @@
import 'package:appflowy/core/config/kv_keys.dart'; import 'package:appflowy/core/config/kv_keys.dart';
import 'package:appflowy/workspace/application/settings/appearance/base_appearance.dart';
import 'package:bloc/bloc.dart'; import 'package:bloc/bloc.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
@ -28,14 +29,19 @@ class DocumentAppearance {
class DocumentAppearanceCubit extends Cubit<DocumentAppearance> { class DocumentAppearanceCubit extends Cubit<DocumentAppearance> {
DocumentAppearanceCubit() DocumentAppearanceCubit()
: super(const DocumentAppearance(fontSize: 16.0, fontFamily: 'Poppins')); : super(
const DocumentAppearance(
fontSize: 16.0,
fontFamily: builtInFontFamily,
),
);
Future<void> fetch() async { Future<void> fetch() async {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
final fontSize = final fontSize =
prefs.getDouble(KVKeys.kDocumentAppearanceFontSize) ?? 16.0; prefs.getDouble(KVKeys.kDocumentAppearanceFontSize) ?? 16.0;
final fontFamily = final fontFamily = prefs.getString(KVKeys.kDocumentAppearanceFontFamily) ??
prefs.getString(KVKeys.kDocumentAppearanceFontFamily) ?? 'Poppins'; builtInFontFamily;
final defaultTextDirection = final defaultTextDirection =
prefs.getString(KVKeys.kDocumentAppearanceDefaultTextDirection); prefs.getString(KVKeys.kDocumentAppearanceDefaultTextDirection);

View File

@ -2,6 +2,7 @@ import 'package:appflowy/mobile/presentation/database/board/mobile_board_screen.
import 'package:appflowy/mobile/presentation/database/card/card.dart'; import 'package:appflowy/mobile/presentation/database/card/card.dart';
import 'package:appflowy/mobile/presentation/database/card/card_detail/mobile_create_field_screen.dart'; import 'package:appflowy/mobile/presentation/database/card/card_detail/mobile_create_field_screen.dart';
import 'package:appflowy/mobile/presentation/database/card/card_detail/mobile_create_row_field_screen.dart'; import 'package:appflowy/mobile/presentation/database/card/card_detail/mobile_create_row_field_screen.dart';
import 'package:appflowy/mobile/presentation/database/card/card_detail/mobile_edit_field_screen.dart';
import 'package:appflowy/mobile/presentation/database/card/card_property_edit/card_property_edit_screen.dart'; import 'package:appflowy/mobile/presentation/database/card/card_property_edit/card_property_edit_screen.dart';
import 'package:appflowy/mobile/presentation/database/date_picker/mobile_date_picker_screen.dart'; import 'package:appflowy/mobile/presentation/database/date_picker/mobile_date_picker_screen.dart';
import 'package:appflowy/mobile/presentation/database/mobile_calendar_events_screen.dart'; import 'package:appflowy/mobile/presentation/database/mobile_calendar_events_screen.dart';
@ -64,6 +65,7 @@ GoRouter generateRouter(Widget child) {
_mobileDateCellEditScreenRoute(), _mobileDateCellEditScreenRoute(),
_mobileCreateRowFieldScreenRoute(), _mobileCreateRowFieldScreenRoute(),
_mobileNewPropertyPageRoute(), _mobileNewPropertyPageRoute(),
_mobileEditPropertyPageRoute(),
// home // home
// MobileHomeSettingPage is outside the bottom navigation bar, thus it is not in the StatefulShellRoute. // MobileHomeSettingPage is outside the bottom navigation bar, thus it is not in the StatefulShellRoute.
@ -373,9 +375,28 @@ GoRoute _mobileNewPropertyPageRoute() {
); );
} }
GoRoute _mobileEditPropertyPageRoute() {
return GoRoute(
parentNavigatorKey: AppGlobals.rootNavKey,
path: MobileEditPropertyScreen.routeName,
pageBuilder: (context, state) {
final args = state.extra as Map<String, dynamic>;
return MaterialPage(
fullscreenDialog: true,
child: MobileEditPropertyScreen(
viewId: args[MobileEditPropertyScreen.argViewId],
field: args[MobileEditPropertyScreen.argField],
isPrimary: args[MobileEditPropertyScreen.argIsPrimary],
),
);
},
);
}
GoRoute _mobileCalendarEventsPageRoute() { GoRoute _mobileCalendarEventsPageRoute() {
return GoRoute( return GoRoute(
path: MobileCalendarEventsScreen.routeName, path: MobileCalendarEventsScreen.routeName,
parentNavigatorKey: AppGlobals.rootNavKey,
pageBuilder: (context, state) { pageBuilder: (context, state) {
final args = state.extra as Map<String, dynamic>; final args = state.extra as Map<String, dynamic>;

View File

@ -3,6 +3,8 @@ import 'package:flowy_infra/theme.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
const builtInFontFamily = 'Poppins';
abstract class BaseAppearance { abstract class BaseAppearance {
final white = const Color(0xFFFFFFFF); final white = const Color(0xFFFFFFFF);
@ -20,25 +22,36 @@ abstract class BaseAppearance {
double? letterSpacing, double? letterSpacing,
double? lineHeight, double? lineHeight,
}) { }) {
fontSize = fontSize ?? FontSizes.s12;
fontWeight = fontWeight ?? FontWeight.w400;
letterSpacing = fontSize * (letterSpacing ?? 0.005);
final textStyle = TextStyle(
fontFamily: fontFamily,
fontSize: fontSize,
color: fontColor,
fontWeight: fontWeight,
fontFamilyFallback: const [builtInFontFamily],
letterSpacing: letterSpacing,
height: lineHeight,
);
// we embed Poppins font in the app, so we can use it without GoogleFonts
if (fontFamily == builtInFontFamily) {
return textStyle;
}
try { try {
return GoogleFonts.getFont( return GoogleFonts.getFont(
fontFamily, fontFamily,
fontSize: fontSize ?? FontSizes.s12, fontSize: fontSize,
color: fontColor, color: fontColor,
fontWeight: fontWeight ?? FontWeight.w500, fontWeight: fontWeight,
letterSpacing: (fontSize ?? FontSizes.s12) * (letterSpacing ?? 0.005), letterSpacing: letterSpacing,
height: lineHeight, height: lineHeight,
); );
} catch (e) { } catch (e) {
return TextStyle( return textStyle;
fontFamily: fontFamily,
fontSize: fontSize ?? FontSizes.s12,
color: fontColor,
fontWeight: fontWeight ?? FontWeight.w500,
fontFamilyFallback: const ['Poppins'],
letterSpacing: (fontSize ?? FontSizes.s12) * (letterSpacing ?? 0.005),
height: lineHeight,
);
} }
} }

View File

@ -24,7 +24,10 @@ class MobileAppearance extends BaseAppearance {
final fontStyle = getFontStyle( final fontStyle = getFontStyle(
fontFamily: fontFamily, fontFamily: fontFamily,
fontSize: 16.0,
fontWeight: FontWeight.w400,
); );
final codeFontStyle = getFontStyle( final codeFontStyle = getFontStyle(
fontFamily: codeFontFamily, fontFamily: codeFontFamily,
); );
@ -196,9 +199,7 @@ class MobileAppearance extends BaseAppearance {
// body2 14 Regular // body2 14 Regular
bodyMedium: fontStyle.copyWith( bodyMedium: fontStyle.copyWith(
color: colorTheme.onBackground, color: colorTheme.onBackground,
fontSize: 14,
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
// height: 1.2,
letterSpacing: 0.07, letterSpacing: 0.07,
), ),
// Trash empty title // Trash empty title

View File

@ -1,7 +1,8 @@
import 'package:appflowy/user/application/user_settings_service.dart'; import 'package:appflowy/user/application/user_settings_service.dart';
import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart'; import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart';
import 'package:bloc_test/bloc_test.dart'; import 'package:appflowy/workspace/application/settings/appearance/base_appearance.dart';
import 'package:appflowy_backend/protobuf/flowy-user/user_setting.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-user/user_setting.pb.dart';
import 'package:bloc_test/bloc_test.dart';
import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra/theme.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
@ -35,7 +36,7 @@ void main() {
AppTheme.fallback, AppTheme.fallback,
), ),
verify: (bloc) { verify: (bloc) {
expect(bloc.state.font, 'Poppins'); expect(bloc.state.font, builtInFontFamily);
expect(bloc.state.monospaceFont, 'SF Mono'); expect(bloc.state.monospaceFont, 'SF Mono');
expect(bloc.state.themeMode, ThemeMode.system); expect(bloc.state.themeMode, ThemeMode.system);
}, },

View File

@ -1,5 +1,6 @@
import 'package:appflowy/core/config/kv_keys.dart'; import 'package:appflowy/core/config/kv_keys.dart';
import 'package:appflowy/plugins/document/presentation/more/cubit/document_appearance_cubit.dart'; import 'package:appflowy/plugins/document/presentation/more/cubit/document_appearance_cubit.dart';
import 'package:appflowy/workspace/application/settings/appearance/base_appearance.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
@ -26,7 +27,7 @@ void main() {
test('Initial state', () { test('Initial state', () {
expect(cubit.state.fontSize, 16.0); expect(cubit.state.fontSize, 16.0);
expect(cubit.state.fontFamily, 'Poppins'); expect(cubit.state.fontFamily, builtInFontFamily);
}); });
test('Fetch document appearance from SharedPreferences', () async { test('Fetch document appearance from SharedPreferences', () async {

View File

@ -1,5 +1,6 @@
import 'package:appflowy/plugins/document/presentation/editor_style.dart'; import 'package:appflowy/plugins/document/presentation/editor_style.dart';
import 'package:appflowy/plugins/document/presentation/more/cubit/document_appearance_cubit.dart'; import 'package:appflowy/plugins/document/presentation/more/cubit/document_appearance_cubit.dart';
import 'package:appflowy/workspace/application/settings/appearance/base_appearance.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
@ -39,7 +40,7 @@ void main() {
expect(result, isA<TextStyle>()); expect(result, isA<TextStyle>());
expect( expect(
result.fontFamily, result.fontFamily,
GoogleFonts.getFont('Poppins').fontFamily, GoogleFonts.getFont(builtInFontFamily).fontFamily,
); );
}); });
}); });

View File

@ -1,5 +1,6 @@
import 'package:appflowy/plugins/document/presentation/more/cubit/document_appearance_cubit.dart'; import 'package:appflowy/plugins/document/presentation/more/cubit/document_appearance_cubit.dart';
import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart'; import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart';
import 'package:appflowy/workspace/application/settings/appearance/base_appearance.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/settings_appearance/font_family_setting.dart'; import 'package:appflowy/workspace/presentation/settings/widgets/settings_appearance/font_family_setting.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -57,7 +58,7 @@ void main() {
], ],
child: const Scaffold( child: const Scaffold(
body: ThemeFontFamilySetting( body: ThemeFontFamilySetting(
currentFontFamily: 'Poppins', currentFontFamily: builtInFontFamily,
), ),
), ),
), ),
@ -70,7 +71,7 @@ void main() {
await tester.pumpAndSettle(); await tester.pumpAndSettle();
// Verify the initial font family // Verify the initial font family
expect(find.text('Poppins'), findsAtLeastNWidgets(1)); expect(find.text(builtInFontFamily), findsAtLeastNWidgets(1));
when(() => appearanceSettingsCubit.setFontFamily(any<String>())) when(() => appearanceSettingsCubit.setFontFamily(any<String>()))
.thenAnswer((_) async {}); .thenAnswer((_) async {});
verifyNever(() => appearanceSettingsCubit.setFontFamily(any<String>())); verifyNever(() => appearanceSettingsCubit.setFontFamily(any<String>()));