mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: support system default font family on desktop (#5279)
* fix: add permission check before selecting image in image block * feat: use system default font on desktop * fix: set appbar icon size to 30 * feat: add default font family on desktop
This commit is contained in:
@ -57,9 +57,9 @@ class DocumentAppearance {
|
||||
class DocumentAppearanceCubit extends Cubit<DocumentAppearance> {
|
||||
DocumentAppearanceCubit()
|
||||
: super(
|
||||
DocumentAppearance(
|
||||
const DocumentAppearance(
|
||||
fontSize: 16.0,
|
||||
fontFamily: builtInFontFamily(),
|
||||
fontFamily: defaultFontFamily,
|
||||
codeFontFamily: builtInCodeFontFamily,
|
||||
),
|
||||
);
|
||||
@ -69,7 +69,7 @@ class DocumentAppearanceCubit extends Cubit<DocumentAppearance> {
|
||||
final fontSize =
|
||||
prefs.getDouble(KVKeys.kDocumentAppearanceFontSize) ?? 16.0;
|
||||
final fontFamily = prefs.getString(KVKeys.kDocumentAppearanceFontFamily) ??
|
||||
builtInFontFamily();
|
||||
defaultFontFamily;
|
||||
final defaultTextDirection =
|
||||
prefs.getString(KVKeys.kDocumentAppearanceDefaultTextDirection);
|
||||
|
||||
|
@ -127,7 +127,7 @@ class _DocumentImmersiveCoverState extends State<DocumentImmersiveCover> {
|
||||
BuildContext context,
|
||||
DocumentImmersiveCoverState state,
|
||||
) {
|
||||
String? fontFamily = builtInFontFamily();
|
||||
String? fontFamily = defaultFontFamily;
|
||||
final documentFontFamily =
|
||||
context.read<DocumentPageStyleBloc>().state.fontFamily;
|
||||
if (documentFontFamily != null && fontFamily != documentFontFamily) {
|
||||
|
@ -1,6 +1,8 @@
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/shared/permission/permission_checker.dart';
|
||||
import 'package:appflowy/startup/startup.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart' hide Log;
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra/file_picker/file_picker_service.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
@ -20,22 +22,28 @@ class UploadImageFileWidget extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FlowyHover(
|
||||
child: FlowyButton(
|
||||
showDefaultBoxDecorationOnMobile: true,
|
||||
text: Container(
|
||||
margin: const EdgeInsets.all(4.0),
|
||||
alignment: Alignment.center,
|
||||
child: FlowyText(
|
||||
LocaleKeys.document_imageBlock_upload_placeholder.tr(),
|
||||
),
|
||||
final child = FlowyButton(
|
||||
showDefaultBoxDecorationOnMobile: true,
|
||||
text: Container(
|
||||
margin: const EdgeInsets.all(4.0),
|
||||
alignment: Alignment.center,
|
||||
child: FlowyText(
|
||||
LocaleKeys.document_imageBlock_upload_placeholder.tr(),
|
||||
),
|
||||
onTap: _uploadImage,
|
||||
),
|
||||
onTap: () => _uploadImage(context),
|
||||
);
|
||||
|
||||
if (PlatformExtension.isDesktopOrWeb) {
|
||||
return FlowyHover(
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
|
||||
return child;
|
||||
}
|
||||
|
||||
Future<void> _uploadImage() async {
|
||||
Future<void> _uploadImage(BuildContext context) async {
|
||||
if (PlatformExtension.isDesktopOrWeb) {
|
||||
// on desktop, the users can pick a image file from folder
|
||||
final result = await getIt<FilePickerService>().pickFiles(
|
||||
@ -45,6 +53,12 @@ class UploadImageFileWidget extends StatelessWidget {
|
||||
);
|
||||
onPickFile(result?.files.firstOrNull?.path);
|
||||
} else {
|
||||
final photoPermission =
|
||||
await PermissionChecker.checkPhotoPermission(context);
|
||||
if (!photoPermission) {
|
||||
Log.error('Has no permission to access the photo library');
|
||||
return;
|
||||
}
|
||||
// on mobile, the users can pick a image file from camera or image library
|
||||
final result = await ImagePicker().pickImage(source: ImageSource.gallery);
|
||||
onPickFile(result?.path);
|
||||
|
@ -5,7 +5,7 @@ import 'package:appflowy/plugins/document/application/document_appearance_cubit.
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/mobile_toolbar_v3/aa_menu/_toolbar_theme.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart';
|
||||
import 'package:appflowy/shared/google_fonts_extension.dart';
|
||||
import 'package:appflowy/util/google_font_family_extension.dart';
|
||||
import 'package:appflowy/util/font_family_extension.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
@ -4,13 +4,12 @@ import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/mobile/application/page_style/document_page_style_bloc.dart';
|
||||
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart';
|
||||
import 'package:appflowy/mobile/presentation/widgets/show_flowy_mobile_confirm_dialog.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/image/image_util.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/image/unsplash_image_widget.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/page_style/_page_cover_bottom_sheet.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/page_style/_page_style_util.dart';
|
||||
import 'package:appflowy/shared/feedback_gesture_detector.dart';
|
||||
import 'package:appflowy/startup/tasks/device_info_task.dart';
|
||||
import 'package:appflowy/shared/permission/permission_checker.dart';
|
||||
import 'package:appflowy/user/application/user_service.dart';
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
|
||||
@ -18,11 +17,9 @@ import 'package:appflowy_result/appflowy_result.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/snap_bar.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
|
||||
class PageStyleCoverImage extends StatelessWidget {
|
||||
PageStyleCoverImage({
|
||||
@ -121,7 +118,8 @@ class PageStyleCoverImage extends StatelessWidget {
|
||||
}
|
||||
|
||||
Future<void> _pickImage(BuildContext context) async {
|
||||
final photoPermission = await _checkPhotoPermission(context);
|
||||
final photoPermission =
|
||||
await PermissionChecker.checkPhotoPermission(context);
|
||||
if (!photoPermission) {
|
||||
Log.error('Has no permission to access the photo library');
|
||||
return;
|
||||
@ -129,9 +127,7 @@ class PageStyleCoverImage extends StatelessWidget {
|
||||
|
||||
XFile? result;
|
||||
try {
|
||||
result = await _imagePicker.pickImage(
|
||||
source: ImageSource.gallery,
|
||||
);
|
||||
result = await _imagePicker.pickImage(source: ImageSource.gallery);
|
||||
} catch (e) {
|
||||
Log.error('Error while picking image: $e');
|
||||
return;
|
||||
@ -224,54 +220,6 @@ class PageStyleCoverImage extends StatelessWidget {
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<bool> _checkPhotoPermission(BuildContext context) async {
|
||||
// check the permission first
|
||||
final status = await Permission.photos.status;
|
||||
// if the permission is permanently denied, we should open the app settings
|
||||
if (status.isPermanentlyDenied && context.mounted) {
|
||||
unawaited(
|
||||
showFlowyMobileConfirmDialog(
|
||||
context,
|
||||
title: FlowyText.semibold(
|
||||
LocaleKeys.pageStyle_photoPermissionTitle.tr(),
|
||||
maxLines: 3,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
content: FlowyText(
|
||||
LocaleKeys.pageStyle_photoPermissionDescription.tr(),
|
||||
maxLines: 5,
|
||||
textAlign: TextAlign.center,
|
||||
fontSize: 12.0,
|
||||
),
|
||||
actionAlignment: ConfirmDialogActionAlignment.vertical,
|
||||
actionButtonTitle: LocaleKeys.pageStyle_openSettings.tr(),
|
||||
actionButtonColor: Colors.blue,
|
||||
cancelButtonTitle: LocaleKeys.pageStyle_doNotAllow.tr(),
|
||||
cancelButtonColor: Colors.blue,
|
||||
onActionButtonPressed: () {
|
||||
openAppSettings();
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
return false;
|
||||
} else if (status.isDenied) {
|
||||
// https://github.com/Baseflow/flutter-permission-handler/issues/1262#issuecomment-2006340937
|
||||
Permission permission = Permission.photos;
|
||||
if (defaultTargetPlatform == TargetPlatform.android &&
|
||||
ApplicationInfo.androidSDKVersion <= 32) {
|
||||
permission = Permission.storage;
|
||||
}
|
||||
// if the permission is denied, we should request the permission
|
||||
final newStatus = await permission.request();
|
||||
if (newStatus.isDenied) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class _UnsplashCover extends StatelessWidget {
|
||||
|
@ -5,6 +5,7 @@ import 'package:appflowy/mobile/presentation/bottom_sheet/show_mobile_bottom_she
|
||||
import 'package:appflowy/mobile/presentation/setting/font/font_picker_screen.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/page_style/_page_style_util.dart';
|
||||
import 'package:appflowy/shared/feedback_gesture_detector.dart';
|
||||
import 'package:appflowy/util/font_family_extension.dart';
|
||||
import 'package:appflowy/workspace/application/settings/appearance/base_appearance.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
@ -163,11 +164,8 @@ class _FontButton extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<DocumentPageStyleBloc, DocumentPageStyleState>(
|
||||
builder: (context, state) {
|
||||
String fontFamily = state.fontFamily ?? builtInFontFamily();
|
||||
if (fontFamily == builtInFontFamily()) {
|
||||
fontFamily =
|
||||
LocaleKeys.settings_appearance_fontFamily_defaultFont.tr();
|
||||
}
|
||||
final fontFamilyDisplayName =
|
||||
(state.fontFamily ?? defaultFontFamily).fontFamilyDisplayName;
|
||||
return GestureDetector(
|
||||
onTap: () => _showFontSelector(context),
|
||||
behavior: HitTestBehavior.opaque,
|
||||
@ -182,7 +180,7 @@ class _FontButton extends StatelessWidget {
|
||||
const HSpace(16.0),
|
||||
FlowyText(LocaleKeys.titleBar_font.tr()),
|
||||
const Spacer(),
|
||||
FlowyText(fontFamily),
|
||||
FlowyText(fontFamilyDisplayName),
|
||||
const HSpace(6.0),
|
||||
const FlowySvg(FlowySvgs.m_page_style_arrow_right_s),
|
||||
const HSpace(12.0),
|
||||
@ -219,7 +217,7 @@ class _FontButton extends StatelessWidget {
|
||||
child: FontSelector(
|
||||
scrollController: controller,
|
||||
selectedFontFamilyName:
|
||||
state.fontFamily ?? builtInFontFamily(),
|
||||
state.fontFamily ?? defaultFontFamily,
|
||||
onFontFamilySelected: (fontFamilyName) {
|
||||
context.read<DocumentPageStyleBloc>().add(
|
||||
DocumentPageStyleEvent.updateFontFamily(
|
||||
|
@ -8,7 +8,7 @@ import 'package:appflowy/plugins/document/presentation/editor_plugins/mobile_too
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart';
|
||||
import 'package:appflowy/plugins/inline_actions/inline_actions_menu.dart';
|
||||
import 'package:appflowy/shared/google_fonts_extension.dart';
|
||||
import 'package:appflowy/util/google_font_family_extension.dart';
|
||||
import 'package:appflowy/util/font_family_extension.dart';
|
||||
import 'package:appflowy/workspace/application/appearance_defaults.dart';
|
||||
import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart';
|
||||
import 'package:appflowy/workspace/application/settings/appearance/base_appearance.dart';
|
||||
@ -92,7 +92,7 @@ class EditorStyleCustomizer {
|
||||
final theme = Theme.of(context);
|
||||
final fontSize = pageStyle.fontLayout.fontSize;
|
||||
final lineHeight = pageStyle.lineHeightLayout.lineHeight;
|
||||
final fontFamily = pageStyle.fontFamily ?? builtInFontFamily();
|
||||
final fontFamily = pageStyle.fontFamily ?? defaultFontFamily;
|
||||
final defaultTextDirection =
|
||||
context.read<DocumentAppearanceCubit>().state.defaultTextDirection;
|
||||
final baseTextStyle = this.baseTextStyle(fontFamily);
|
||||
@ -178,7 +178,7 @@ class EditorStyleCustomizer {
|
||||
TextStyle outlineBlockPlaceholderStyleBuilder() {
|
||||
final fontSize = context.read<DocumentAppearanceCubit>().state.fontSize;
|
||||
return TextStyle(
|
||||
fontFamily: builtInFontFamily(),
|
||||
fontFamily: defaultFontFamily,
|
||||
fontSize: fontSize,
|
||||
height: 1.5,
|
||||
color: Theme.of(context).colorScheme.onBackground.withOpacity(0.6),
|
||||
@ -219,7 +219,8 @@ class EditorStyleCustomizer {
|
||||
try {
|
||||
return getGoogleFontSafely(fontFamily, fontWeight: fontWeight);
|
||||
} on Exception {
|
||||
if ([builtInFontFamily(), builtInCodeFontFamily].contains(fontFamily)) {
|
||||
if ([defaultFontFamily, fallbackFontFamily, builtInCodeFontFamily]
|
||||
.contains(fontFamily)) {
|
||||
return TextStyle(fontFamily: fontFamily, fontWeight: fontWeight);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user