mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
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:
parent
9824d5980a
commit
415f121720
@ -202,4 +202,4 @@ SPEC CHECKSUMS:
|
||||
|
||||
PODFILE CHECKSUM: 8c681999c7764593c94846b2a64b44d86f7a27ac
|
||||
|
||||
COCOAPODS: 1.11.3
|
||||
COCOAPODS: 1.12.1
|
||||
|
@ -515,7 +515,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEAD_CODE_STRIPPING = NO;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
DEVELOPMENT_TEAM = VHB67HRSZG;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = AppFlowy;
|
||||
|
@ -34,7 +34,6 @@ class AppBarCancelButton extends StatelessWidget {
|
||||
onTap: onTap,
|
||||
child: FlowyText(
|
||||
LocaleKeys.button_cancel.tr(),
|
||||
fontSize: 16.0,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -17,7 +17,6 @@ class MobileViewItemBottomSheetHeader extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
@ -44,9 +43,14 @@ class MobileViewItemBottomSheetHeader extends StatelessWidget {
|
||||
},
|
||||
),
|
||||
// title
|
||||
Text(
|
||||
view.name,
|
||||
style: theme.textTheme.labelSmall,
|
||||
ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
maxWidth: MediaQuery.of(context).size.width * 0.6,
|
||||
),
|
||||
child: FlowyText.medium(
|
||||
view.name,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
const HSpace(24.0),
|
||||
],
|
||||
|
@ -64,7 +64,6 @@ Future<T?> showMobileBottomSheet<T>(
|
||||
: const SizedBox.shrink(),
|
||||
FlowyText(
|
||||
title,
|
||||
fontSize: 16.0,
|
||||
),
|
||||
showCloseButton
|
||||
? HSpace(padding.right + 24)
|
||||
|
@ -1,6 +1,6 @@
|
||||
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/_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_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
@ -46,9 +46,8 @@ class _MobileNewPropertyScreenState extends State<MobileNewPropertyScreen> {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
centerTitle: true,
|
||||
title: FlowyText(
|
||||
title: FlowyText.medium(
|
||||
LocaleKeys.grid_field_newProperty.tr(),
|
||||
fontSize: 16.0,
|
||||
),
|
||||
leading: AppBarCancelButton(
|
||||
onTap: () => context.pop(),
|
||||
@ -62,7 +61,7 @@ class _MobileNewPropertyScreenState extends State<MobileNewPropertyScreen> {
|
||||
),
|
||||
],
|
||||
),
|
||||
body: FieldOption(
|
||||
body: FieldOptionEditor(
|
||||
mode: FieldOptionMode.add,
|
||||
defaultValues: optionValues,
|
||||
onOptionValuesChanged: (optionValues) {
|
||||
@ -88,10 +87,9 @@ class _SaveButton extends StatelessWidget {
|
||||
alignment: Alignment.center,
|
||||
child: GestureDetector(
|
||||
onTap: onSave,
|
||||
child: FlowyText(
|
||||
child: FlowyText.medium(
|
||||
LocaleKeys.button_save.tr(),
|
||||
color: const Color(0xFF00ADDC),
|
||||
fontSize: 16.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -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),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -75,7 +75,7 @@ class _FieldHeader extends StatelessWidget {
|
||||
),
|
||||
FlowyText.medium(
|
||||
LocaleKeys.titleBar_addField.tr(),
|
||||
fontSize: 16.0,
|
||||
fontSize: 17.0,
|
||||
),
|
||||
const HSpace(120),
|
||||
],
|
||||
@ -106,7 +106,9 @@ class _Field extends StatelessWidget {
|
||||
size: Size.square(width / 4.0),
|
||||
),
|
||||
const VSpace(6.0),
|
||||
FlowyText(type.i18n),
|
||||
FlowyText(
|
||||
type.i18n,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
@ -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/database/card/card_detail/widgets/_field_options.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/type_option_service.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.name,
|
||||
this.dateFormate,
|
||||
this.includeTime = false,
|
||||
this.timeFormat,
|
||||
this.numberFormat,
|
||||
this.selectOption = const [],
|
||||
@ -43,7 +43,6 @@ class FieldOptionValues {
|
||||
|
||||
// FieldType.Date
|
||||
DateFormatPB? dateFormate;
|
||||
bool includeTime;
|
||||
TimeFormatPB? timeFormat;
|
||||
|
||||
// FieldType.Num
|
||||
@ -56,65 +55,110 @@ class FieldOptionValues {
|
||||
Future<void> create({
|
||||
required String viewId,
|
||||
}) 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(
|
||||
viewId: viewId,
|
||||
fieldType: type,
|
||||
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 {
|
||||
const FieldOption({
|
||||
enum FieldOptionAction {
|
||||
hide,
|
||||
duplicate,
|
||||
delete,
|
||||
}
|
||||
|
||||
class FieldOptionEditor extends StatefulWidget {
|
||||
const FieldOptionEditor({
|
||||
super.key,
|
||||
required this.mode,
|
||||
required this.defaultValues,
|
||||
required this.onOptionValuesChanged,
|
||||
this.onAction,
|
||||
this.isPrimary = false,
|
||||
});
|
||||
|
||||
final FieldOptionMode mode;
|
||||
final FieldOptionValues defaultValues;
|
||||
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
|
||||
State<FieldOption> createState() => _FieldOptionState();
|
||||
State<FieldOptionEditor> createState() => _FieldOptionEditorState();
|
||||
}
|
||||
|
||||
class _FieldOptionState extends State<FieldOption> {
|
||||
class _FieldOptionEditorState extends State<FieldOptionEditor> {
|
||||
final controller = TextEditingController();
|
||||
|
||||
late FieldOptionValues values;
|
||||
@ -124,7 +168,7 @@ class _FieldOptionState extends State<FieldOption> {
|
||||
super.initState();
|
||||
|
||||
values = widget.defaultValues;
|
||||
controller.text = values.type.i18n;
|
||||
controller.text = values.name;
|
||||
}
|
||||
|
||||
@override
|
||||
@ -136,6 +180,7 @@ class _FieldOptionState extends State<FieldOption> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final option = _buildOption();
|
||||
return Container(
|
||||
color: Theme.of(context).colorScheme.secondaryContainer,
|
||||
height: MediaQuery.of(context).size.height,
|
||||
@ -151,18 +196,26 @@ class _FieldOptionState extends State<FieldOption> {
|
||||
},
|
||||
),
|
||||
const _Divider(),
|
||||
_PropertyType(
|
||||
type: values.type,
|
||||
onSelected: (type) => setState(
|
||||
() {
|
||||
controller.text = type.i18n;
|
||||
_updateOptionValues(type: type, name: type.i18n);
|
||||
},
|
||||
if (!widget.isPrimary) ...[
|
||||
_PropertyType(
|
||||
type: values.type,
|
||||
onSelected: (type) => setState(
|
||||
() {
|
||||
if (widget.mode == FieldOptionMode.add) {
|
||||
controller.text = type.i18n;
|
||||
}
|
||||
_updateOptionValues(type: type, name: type.i18n);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
const _Divider(),
|
||||
..._buildOption(),
|
||||
const _Divider(),
|
||||
if (option.isNotEmpty) ...[
|
||||
...option,
|
||||
const _Divider(),
|
||||
],
|
||||
],
|
||||
..._buildOptionActions(),
|
||||
const _Divider(),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -171,18 +224,6 @@ class _FieldOptionState extends State<FieldOption> {
|
||||
|
||||
List<Widget> _buildOption() {
|
||||
switch (values.type) {
|
||||
case FieldType.RichText:
|
||||
return [
|
||||
const _TextOption(),
|
||||
];
|
||||
case FieldType.URL:
|
||||
return [
|
||||
const _URLOption(),
|
||||
];
|
||||
case FieldType.Checkbox:
|
||||
return [
|
||||
const _CheckboxOption(),
|
||||
];
|
||||
case FieldType.Number:
|
||||
return [
|
||||
_NumberOption(
|
||||
@ -204,10 +245,8 @@ class _FieldOptionState extends State<FieldOption> {
|
||||
),
|
||||
const _Divider(),
|
||||
_TimeOption(
|
||||
includeTime: values.includeTime,
|
||||
selectedFormat: values.timeFormat ?? TimeFormatPB.TwelveHour,
|
||||
onSelected: (includeTime, format) => _updateOptionValues(
|
||||
includeTime: includeTime,
|
||||
onSelected: (format) => _updateOptionValues(
|
||||
timeFormat: format,
|
||||
),
|
||||
),
|
||||
@ -244,19 +283,24 @@ class _FieldOptionState extends State<FieldOption> {
|
||||
FieldOptionMode.add => [],
|
||||
FieldOptionMode.edit => [
|
||||
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(),
|
||||
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,
|
||||
String? name,
|
||||
DateFormatPB? dateFormate,
|
||||
bool? includeTime,
|
||||
TimeFormatPB? timeFormat,
|
||||
NumberFormatPB? numberFormat,
|
||||
List<SelectOptionPB>? selectOption,
|
||||
@ -279,9 +322,6 @@ class _FieldOptionState extends State<FieldOption> {
|
||||
if (dateFormate != null) {
|
||||
values.dateFormate = dateFormate;
|
||||
}
|
||||
if (includeTime != null) {
|
||||
values.includeTime = includeTime;
|
||||
}
|
||||
if (timeFormat != null) {
|
||||
values.timeFormat = timeFormat;
|
||||
}
|
||||
@ -348,7 +388,6 @@ class _PropertyType extends StatelessWidget {
|
||||
FlowyText(
|
||||
type.i18n,
|
||||
color: Theme.of(context).hintColor,
|
||||
fontSize: 16.0,
|
||||
),
|
||||
const HSpace(4.0),
|
||||
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 {
|
||||
const _DateOption({
|
||||
required this.selectedFormat,
|
||||
@ -456,7 +468,6 @@ class _DateOptionState extends State<_DateOption> {
|
||||
),
|
||||
child: FlowyText(
|
||||
LocaleKeys.grid_field_dateFormat.tr(),
|
||||
fontSize: 16.0,
|
||||
color: Theme.of(context).hintColor,
|
||||
),
|
||||
),
|
||||
@ -480,14 +491,12 @@ class _DateOptionState extends State<_DateOption> {
|
||||
|
||||
class _TimeOption extends StatefulWidget {
|
||||
const _TimeOption({
|
||||
required this.includeTime,
|
||||
required this.selectedFormat,
|
||||
required this.onSelected,
|
||||
});
|
||||
|
||||
final bool includeTime;
|
||||
final TimeFormatPB selectedFormat;
|
||||
final Function(bool includeTime, TimeFormatPB format) onSelected;
|
||||
final Function(TimeFormatPB format) onSelected;
|
||||
|
||||
@override
|
||||
State<_TimeOption> createState() => _TimeOptionState();
|
||||
@ -495,14 +504,12 @@ class _TimeOption extends StatefulWidget {
|
||||
|
||||
class _TimeOptionState extends State<_TimeOption> {
|
||||
TimeFormatPB selectedFormat = TimeFormatPB.TwelveHour;
|
||||
bool includeTime = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
selectedFormat = widget.selectedFormat;
|
||||
includeTime = widget.includeTime;
|
||||
}
|
||||
|
||||
@override
|
||||
@ -517,34 +524,22 @@ class _TimeOptionState extends State<_TimeOption> {
|
||||
),
|
||||
child: FlowyText(
|
||||
LocaleKeys.grid_field_timeFormat.tr(),
|
||||
fontSize: 16.0,
|
||||
color: Theme.of(context).hintColor,
|
||||
),
|
||||
),
|
||||
FlowyOptionTile.switcher(
|
||||
text: LocaleKeys.grid_field_includeTime.tr(),
|
||||
isSelected: includeTime,
|
||||
onValueChanged: (includeTime) {
|
||||
widget.onSelected(includeTime, selectedFormat);
|
||||
setState(() {
|
||||
this.includeTime = includeTime;
|
||||
});
|
||||
},
|
||||
),
|
||||
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;
|
||||
});
|
||||
},
|
||||
);
|
||||
}),
|
||||
...TimeFormatPB.values.mapIndexed((index, format) {
|
||||
return FlowyOptionTile.checkbox(
|
||||
text: format.title(),
|
||||
isSelected: selectedFormat == format,
|
||||
showTopBorder: false,
|
||||
onTap: () {
|
||||
widget.onSelected(format);
|
||||
setState(() {
|
||||
selectedFormat = format;
|
||||
});
|
||||
},
|
||||
);
|
||||
}),
|
||||
],
|
||||
);
|
||||
}
|
||||
@ -569,7 +564,6 @@ class _NumberOption extends StatelessWidget {
|
||||
FlowyText(
|
||||
selectedFormat.title(),
|
||||
color: Theme.of(context).hintColor,
|
||||
fontSize: 16.0,
|
||||
),
|
||||
const HSpace(4.0),
|
||||
FlowySvg(
|
||||
@ -663,7 +657,6 @@ class _SelectOption extends StatelessWidget {
|
||||
),
|
||||
child: FlowyText(
|
||||
LocaleKeys.grid_field_optionTitle.tr(),
|
||||
fontSize: 16.0,
|
||||
color: Theme.of(context).hintColor,
|
||||
),
|
||||
),
|
@ -58,7 +58,9 @@ class _MobileDateCellEditScreenState extends State<MobileDateCellEditScreen> {
|
||||
Widget _buildFullScreen() {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(LocaleKeys.titleBar_date.tr()),
|
||||
title: FlowyText.medium(
|
||||
LocaleKeys.titleBar_date.tr(),
|
||||
),
|
||||
),
|
||||
body: _buildBody(),
|
||||
);
|
||||
@ -117,7 +119,7 @@ class _MobileDateCellEditScreenState extends State<MobileDateCellEditScreen> {
|
||||
}
|
||||
|
||||
Widget _buildHeader() {
|
||||
const iconWidth = 36.0;
|
||||
const iconWidth = 30.0;
|
||||
const height = 44.0;
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
@ -139,7 +141,7 @@ class _MobileDateCellEditScreenState extends State<MobileDateCellEditScreen> {
|
||||
alignment: Alignment.center,
|
||||
child: FlowyText.medium(
|
||||
LocaleKeys.grid_field_dateFieldName.tr(),
|
||||
fontSize: 18,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
].map((e) => SizedBox(height: height, child: e)).toList(),
|
||||
|
@ -9,14 +9,14 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
class MobileCalendarEventsScreen extends StatefulWidget {
|
||||
static const routeName = "/calendar-events";
|
||||
static const routeName = '/calendar_events';
|
||||
|
||||
// GoRouter Arguments
|
||||
static const calendarBlocKey = "calendar_bloc";
|
||||
static const calendarDateKey = "date";
|
||||
static const calendarEventsKey = "events";
|
||||
static const calendarRowCacheKey = "row_cache";
|
||||
static const calendarViewIdKey = "view_id";
|
||||
static const calendarBlocKey = 'calendar_bloc';
|
||||
static const calendarDateKey = 'date';
|
||||
static const calendarEventsKey = 'events';
|
||||
static const calendarRowCacheKey = 'row_cache';
|
||||
static const calendarViewIdKey = 'view_id';
|
||||
|
||||
const MobileCalendarEventsScreen({
|
||||
super.key,
|
||||
|
@ -137,7 +137,7 @@ class _TrashButton extends StatelessWidget {
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
leftIconSize: const Size.square(24),
|
||||
text: FlowyText(
|
||||
text: FlowyText.medium(
|
||||
LocaleKeys.trash_text.tr(),
|
||||
fontSize: 18.0,
|
||||
),
|
||||
|
@ -80,8 +80,8 @@ class _RecentViews extends StatelessWidget {
|
||||
separatorBuilder: () => const HSpace(8),
|
||||
children: recentViews
|
||||
.map(
|
||||
(view) => SizedBox(
|
||||
width: 150,
|
||||
(view) => SizedBox.square(
|
||||
dimension: 148,
|
||||
child: MobileRecentView(view: view),
|
||||
),
|
||||
)
|
||||
|
@ -96,8 +96,8 @@ class _MobileRecentViewState extends State<MobileRecentView> {
|
||||
),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(8, 16, 8, 2),
|
||||
child: FlowyText(
|
||||
padding: const EdgeInsets.fromLTRB(8, 18, 8, 2),
|
||||
child: FlowyText.medium(
|
||||
view.name,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
@ -110,7 +110,7 @@ class _MobileRecentViewState extends State<MobileRecentView> {
|
||||
Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 4),
|
||||
padding: const EdgeInsets.only(left: 8.0),
|
||||
child: icon.isNotEmpty
|
||||
? EmojiText(
|
||||
emoji: icon,
|
||||
|
@ -307,7 +307,7 @@ class _SingleMobileInnerViewItemState extends State<SingleMobileInnerViewItem> {
|
||||
const HSpace(8),
|
||||
// title
|
||||
Expanded(
|
||||
child: FlowyText.regular(
|
||||
child: FlowyText.medium(
|
||||
widget.view.name,
|
||||
fontSize: 18.0,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
|
@ -1,5 +1,5 @@
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
/// Widget for the root/initial pages in the bottom navigation bar.
|
||||
class RootPlaceholderScreen extends StatelessWidget {
|
||||
@ -24,31 +24,10 @@ class RootPlaceholderScreen extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('Root of section $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'),
|
||||
),
|
||||
],
|
||||
),
|
||||
centerTitle: true,
|
||||
title: FlowyText.medium(label),
|
||||
),
|
||||
body: const SizedBox.shrink(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,8 @@ class FlowyOptionTile extends StatelessWidget {
|
||||
this.onTap,
|
||||
this.trailing,
|
||||
this.textFieldPadding = const EdgeInsets.symmetric(
|
||||
horizontal: 16.0,
|
||||
horizontal: 12.0,
|
||||
vertical: 2.0,
|
||||
),
|
||||
this.isSelected = false,
|
||||
this.textFieldHintText,
|
||||
@ -55,7 +56,8 @@ class FlowyOptionTile extends StatelessWidget {
|
||||
void Function(String value)? onTextChanged,
|
||||
void Function(String value)? onTextSubmitted,
|
||||
EdgeInsets textFieldPadding = const EdgeInsets.symmetric(
|
||||
horizontal: 16.0,
|
||||
horizontal: 12.0,
|
||||
vertical: 2.0,
|
||||
),
|
||||
bool showTopBorder = true,
|
||||
bool showBottomBorder = true,
|
||||
@ -150,6 +152,7 @@ class FlowyOptionTile extends StatelessWidget {
|
||||
showTopBorder: showTopBorder,
|
||||
showBottomBorder: showBottomBorder,
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
_buildText(),
|
||||
..._buildTextField(),
|
||||
@ -185,7 +188,6 @@ class FlowyOptionTile extends StatelessWidget {
|
||||
useIntrinsicWidth: true,
|
||||
text: FlowyText(
|
||||
text!,
|
||||
fontSize: 16.0,
|
||||
),
|
||||
margin: const EdgeInsets.symmetric(
|
||||
horizontal: 16.0,
|
||||
@ -206,7 +208,6 @@ class FlowyOptionTile extends StatelessWidget {
|
||||
),
|
||||
child: FlowyText(
|
||||
text!,
|
||||
fontSize: 16.0,
|
||||
),
|
||||
);
|
||||
}
|
||||
@ -222,11 +223,12 @@ class FlowyOptionTile extends StatelessWidget {
|
||||
return [
|
||||
if (leading != null) leading!,
|
||||
Expanded(
|
||||
child: ConstrainedBox(
|
||||
child: Container(
|
||||
constraints: const BoxConstraints.tightFor(
|
||||
height: 52.0,
|
||||
height: 54.0,
|
||||
width: double.infinity,
|
||||
),
|
||||
alignment: Alignment.center,
|
||||
child: TextField(
|
||||
controller: controller,
|
||||
textInputAction: TextInputAction.done,
|
||||
|
@ -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/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-error/errors.pb.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
|
||||
/// 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.
|
||||
@ -56,6 +56,17 @@ class FieldBackendService {
|
||||
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() {
|
||||
final payload = DeleteFieldPayloadPB.create()
|
||||
..viewId = viewId
|
||||
|
@ -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/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/_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/grid/application/grid_bloc.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/application/grid_header_bloc.dart';
|
||||
|
@ -1,12 +1,12 @@
|
||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet_database_field_editor.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/mobile/presentation/database/card/card_detail/mobile_edit_field_screen.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_info.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_service.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
import 'field_type_extension.dart';
|
||||
|
||||
@ -41,19 +41,41 @@ class MobileFieldButton extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
child: FlowyButton(
|
||||
onTap: () {
|
||||
showPaginatedBottomSheet(
|
||||
context,
|
||||
page: SheetPage(
|
||||
title: LocaleKeys.grid_field_editProperty.tr(),
|
||||
body: MobileDBBottomSheetFieldEditor(
|
||||
viewId: viewId,
|
||||
field: fieldInfo.field,
|
||||
fieldController: fieldController,
|
||||
),
|
||||
),
|
||||
onTap: () async {
|
||||
final optionValues = await context.push<FieldOptionValues>(
|
||||
MobileEditPropertyScreen.routeName,
|
||||
extra: {
|
||||
MobileEditPropertyScreen.argViewId: viewId,
|
||||
MobileEditPropertyScreen.argField: fieldInfo.field,
|
||||
MobileEditPropertyScreen.argIsPrimary: fieldInfo.isPrimary,
|
||||
},
|
||||
);
|
||||
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),
|
||||
leftIcon: FlowySvg(
|
||||
fieldInfo.fieldType.icon(),
|
||||
|
@ -41,9 +41,7 @@ class _MobileDatePickerState extends State<MobileDatePicker> {
|
||||
|
||||
Widget _buildCalendar(BuildContext context) {
|
||||
const selectedColor = Color(0xFF00BCF0);
|
||||
final textStyle = Theme.of(context).textTheme.bodyMedium!.copyWith(
|
||||
fontSize: 16.0,
|
||||
);
|
||||
final textStyle = Theme.of(context).textTheme.bodyMedium!.copyWith();
|
||||
const boxDecoration = BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
);
|
||||
@ -156,7 +154,6 @@ class _MobileDatePickerState extends State<MobileDatePicker> {
|
||||
builder: (_, value, ___) {
|
||||
return FlowyText(
|
||||
DateFormat.yMMMM(value.$2).format(value.$1),
|
||||
fontSize: 16.0,
|
||||
);
|
||||
},
|
||||
),
|
||||
|
@ -426,6 +426,7 @@ class DocumentCoverState extends State<DocumentCover> {
|
||||
children: [
|
||||
IntrinsicWidth(
|
||||
child: RoundedTextButton(
|
||||
fontSize: 14,
|
||||
onPressed: () {
|
||||
showMobileBottomSheet(
|
||||
context,
|
||||
|
@ -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/inline_actions/inline_actions_menu.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:collection/collection.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
@ -160,7 +161,7 @@ class EditorStyleCustomizer {
|
||||
final theme = Theme.of(context);
|
||||
final fontSize = context.read<DocumentAppearanceCubit>().state.fontSize;
|
||||
return TextStyle(
|
||||
fontFamily: 'poppins',
|
||||
fontFamily: builtInFontFamily,
|
||||
fontSize: fontSize,
|
||||
height: 1.5,
|
||||
color: theme.colorScheme.onBackground.withOpacity(0.6),
|
||||
@ -207,7 +208,7 @@ class EditorStyleCustomizer {
|
||||
fontWeight: fontWeight,
|
||||
);
|
||||
} on Exception {
|
||||
return GoogleFonts.getFont('Poppins');
|
||||
return GoogleFonts.getFont(builtInFontFamily);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
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:shared_preferences/shared_preferences.dart';
|
||||
|
||||
@ -28,14 +29,19 @@ class DocumentAppearance {
|
||||
|
||||
class DocumentAppearanceCubit extends Cubit<DocumentAppearance> {
|
||||
DocumentAppearanceCubit()
|
||||
: super(const DocumentAppearance(fontSize: 16.0, fontFamily: 'Poppins'));
|
||||
: super(
|
||||
const DocumentAppearance(
|
||||
fontSize: 16.0,
|
||||
fontFamily: builtInFontFamily,
|
||||
),
|
||||
);
|
||||
|
||||
Future<void> fetch() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
final fontSize =
|
||||
prefs.getDouble(KVKeys.kDocumentAppearanceFontSize) ?? 16.0;
|
||||
final fontFamily =
|
||||
prefs.getString(KVKeys.kDocumentAppearanceFontFamily) ?? 'Poppins';
|
||||
final fontFamily = prefs.getString(KVKeys.kDocumentAppearanceFontFamily) ??
|
||||
builtInFontFamily;
|
||||
final defaultTextDirection =
|
||||
prefs.getString(KVKeys.kDocumentAppearanceDefaultTextDirection);
|
||||
|
||||
|
@ -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_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_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/date_picker/mobile_date_picker_screen.dart';
|
||||
import 'package:appflowy/mobile/presentation/database/mobile_calendar_events_screen.dart';
|
||||
@ -64,6 +65,7 @@ GoRouter generateRouter(Widget child) {
|
||||
_mobileDateCellEditScreenRoute(),
|
||||
_mobileCreateRowFieldScreenRoute(),
|
||||
_mobileNewPropertyPageRoute(),
|
||||
_mobileEditPropertyPageRoute(),
|
||||
|
||||
// home
|
||||
// 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() {
|
||||
return GoRoute(
|
||||
path: MobileCalendarEventsScreen.routeName,
|
||||
parentNavigatorKey: AppGlobals.rootNavKey,
|
||||
pageBuilder: (context, state) {
|
||||
final args = state.extra as Map<String, dynamic>;
|
||||
|
||||
|
@ -3,6 +3,8 @@ import 'package:flowy_infra/theme.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
|
||||
const builtInFontFamily = 'Poppins';
|
||||
|
||||
abstract class BaseAppearance {
|
||||
final white = const Color(0xFFFFFFFF);
|
||||
|
||||
@ -20,25 +22,36 @@ abstract class BaseAppearance {
|
||||
double? letterSpacing,
|
||||
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 {
|
||||
return GoogleFonts.getFont(
|
||||
fontFamily,
|
||||
fontSize: fontSize ?? FontSizes.s12,
|
||||
fontSize: fontSize,
|
||||
color: fontColor,
|
||||
fontWeight: fontWeight ?? FontWeight.w500,
|
||||
letterSpacing: (fontSize ?? FontSizes.s12) * (letterSpacing ?? 0.005),
|
||||
fontWeight: fontWeight,
|
||||
letterSpacing: letterSpacing,
|
||||
height: lineHeight,
|
||||
);
|
||||
} catch (e) {
|
||||
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,
|
||||
);
|
||||
return textStyle;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,10 @@ class MobileAppearance extends BaseAppearance {
|
||||
|
||||
final fontStyle = getFontStyle(
|
||||
fontFamily: fontFamily,
|
||||
fontSize: 16.0,
|
||||
fontWeight: FontWeight.w400,
|
||||
);
|
||||
|
||||
final codeFontStyle = getFontStyle(
|
||||
fontFamily: codeFontFamily,
|
||||
);
|
||||
@ -196,9 +199,7 @@ class MobileAppearance extends BaseAppearance {
|
||||
// body2 14 Regular
|
||||
bodyMedium: fontStyle.copyWith(
|
||||
color: colorTheme.onBackground,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
// height: 1.2,
|
||||
letterSpacing: 0.07,
|
||||
),
|
||||
// Trash empty title
|
||||
|
@ -1,7 +1,8 @@
|
||||
import 'package:appflowy/user/application/user_settings_service.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:bloc_test/bloc_test.dart';
|
||||
import 'package:flowy_infra/theme.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
@ -35,7 +36,7 @@ void main() {
|
||||
AppTheme.fallback,
|
||||
),
|
||||
verify: (bloc) {
|
||||
expect(bloc.state.font, 'Poppins');
|
||||
expect(bloc.state.font, builtInFontFamily);
|
||||
expect(bloc.state.monospaceFont, 'SF Mono');
|
||||
expect(bloc.state.themeMode, ThemeMode.system);
|
||||
},
|
||||
|
@ -1,5 +1,6 @@
|
||||
import 'package:appflowy/core/config/kv_keys.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_test/flutter_test.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
@ -26,7 +27,7 @@ void main() {
|
||||
|
||||
test('Initial state', () {
|
||||
expect(cubit.state.fontSize, 16.0);
|
||||
expect(cubit.state.fontFamily, 'Poppins');
|
||||
expect(cubit.state.fontFamily, builtInFontFamily);
|
||||
});
|
||||
|
||||
test('Fetch document appearance from SharedPreferences', () async {
|
||||
|
@ -1,5 +1,6 @@
|
||||
import 'package:appflowy/plugins/document/presentation/editor_style.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_test/flutter_test.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
@ -39,7 +40,7 @@ void main() {
|
||||
expect(result, isA<TextStyle>());
|
||||
expect(
|
||||
result.fontFamily,
|
||||
GoogleFonts.getFont('Poppins').fontFamily,
|
||||
GoogleFonts.getFont(builtInFontFamily).fontFamily,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@ -1,5 +1,6 @@
|
||||
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/base_appearance.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:flutter/material.dart';
|
||||
@ -57,7 +58,7 @@ void main() {
|
||||
],
|
||||
child: const Scaffold(
|
||||
body: ThemeFontFamilySetting(
|
||||
currentFontFamily: 'Poppins',
|
||||
currentFontFamily: builtInFontFamily,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -70,7 +71,7 @@ void main() {
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// Verify the initial font family
|
||||
expect(find.text('Poppins'), findsAtLeastNWidgets(1));
|
||||
expect(find.text(builtInFontFamily), findsAtLeastNWidgets(1));
|
||||
when(() => appearanceSettingsCubit.setFontFamily(any<String>()))
|
||||
.thenAnswer((_) async {});
|
||||
verifyNever(() => appearanceSettingsCubit.setFontFamily(any<String>()));
|
||||
|
Loading…
Reference in New Issue
Block a user