Skip to content

Commit

Permalink
[feat] Allow user to select any Google Font (AppFlowy-IO#2895)
Browse files Browse the repository at this point in the history
* chore: add label for font selection drop down

* chore: add method to set font family

* feat: add drop down to setting appearance view

* feat: add fontFamily to document appearance cubit

* feat: add bloc provider to root for document appearance style

* feat: syncFont family from setting appearance dialog

* feat: plumbing for font style in editor

* fix: add blocprovider before pushing overlay

* chore: add kv_keys

* fix: use fontFamily in document appearance cubit

* fix: remove bloc providers because bloc is supplied in ancestor

* fix: remove unecessary bloc provider

* chore: add constraints to popover

* chore: add translation for search box

* feat: add levenshtein for string sort

* feat: add search bar view

* refactor: levenshtein

* chore: add tests for levenshtein algorithm

* feat: add unit tests for appearance cubit

* fix: analyzer warnings

* feat: sort by ascending if query is empty

* chore: add test for the font family setting widget

* feat: make comparison case insensitive

* feat: lazy load with listview.builder

Co-authored-by: Yijing Huang <hyj891204@gmail.com>

* fix: fonts loaded on open application

* fix: checkmark doesn't show

* fix: try catch before getFont

* fix: clear text editing value on close

* fix: remove autofocus for search text field

* chore: add tests

* feat: use sliver protocol

Co-authored-by: Yijing Huang <hyj891204@gmail.com>

* fix: avoid using intrinsic height

Co-authored-by: Yijing Huang <hyj891204@gmail.com>

* fix: extra paren caused build failure

* feat: switch order of font family setting

---------

Co-authored-by: Yijing Huang <hyj891204@gmail.com>
  • Loading branch information
a-wallen and hyj1204 authored Jul 4, 2023
1 parent 9fb8f22 commit 323cb3b
Show file tree
Hide file tree
Showing 15 changed files with 561 additions and 95 deletions.
4 changes: 4 additions & 0 deletions frontend/appflowy_flutter/assets/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,10 @@
"open": "Open Settings"
},
"appearance": {
"fontFamily": {
"label": "Font Family",
"search": "Search"
},
"themeMode": {
"label": "Theme Mode",
"light": "Light Mode",
Expand Down
5 changes: 5 additions & 0 deletions frontend/appflowy_flutter/lib/core/config/kv_keys.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,9 @@ class KVKeys {
/// The value is a json string with the following format:
/// {'height': 600.0, 'width': 800.0}
static const String windowSize = 'windowSize';

static const String kDocumentAppearanceFontSize =
'kDocumentAppearanceFontSize';
static const String kDocumentAppearanceFontFamily =
'kDocumentAppearanceFontFamily';
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import 'package:appflowy/plugins/database_view/grid/application/row/row_document
import 'package:appflowy/plugins/document/application/doc_bloc.dart';
import 'package:appflowy/plugins/document/presentation/editor_page.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_backend/protobuf/flowy-folder2/view.pb.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/widget/error_page.dart';
Expand Down Expand Up @@ -86,7 +85,6 @@ class _RowEditorState extends State<RowEditor> {
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider(create: (_) => DocumentAppearanceCubit()),
BlocProvider.value(value: documentBloc),
],
child: BlocBuilder<DocumentBloc, DocumentState>(
Expand Down
36 changes: 9 additions & 27 deletions frontend/appflowy_flutter/lib/plugins/document/document.dart
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,6 @@ class DocumentPluginBuilder extends PluginBuilder {

class DocumentPlugin extends Plugin<int> {
late PluginType _pluginType;
final DocumentAppearanceCubit _documentAppearanceCubit =
DocumentAppearanceCubit();

@override
final ViewPluginNotifier notifier;
Expand All @@ -52,20 +50,12 @@ class DocumentPlugin extends Plugin<int> {
Key? key,
}) : notifier = ViewPluginNotifier(view: view) {
_pluginType = pluginType;
_documentAppearanceCubit.fetch();
}

@override
void dispose() {
_documentAppearanceCubit.close();
super.dispose();
}

@override
PluginWidgetBuilder get widgetBuilder {
return DocumentPluginWidgetBuilder(
notifier: notifier,
documentAppearanceCubit: _documentAppearanceCubit,
);
}

Expand All @@ -81,11 +71,9 @@ class DocumentPluginWidgetBuilder extends PluginWidgetBuilder
final ViewPluginNotifier notifier;
ViewPB get view => notifier.view;
int? deletedViewIndex;
DocumentAppearanceCubit documentAppearanceCubit;

DocumentPluginWidgetBuilder({
required this.notifier,
required this.documentAppearanceCubit,
Key? key,
});

Expand All @@ -102,17 +90,14 @@ class DocumentPluginWidgetBuilder extends PluginWidgetBuilder
});
});

return BlocProvider.value(
value: documentAppearanceCubit,
child: BlocBuilder<DocumentAppearanceCubit, DocumentAppearance>(
builder: (_, state) {
return DocumentPage(
view: view,
onDeleted: () => context?.onDeleted(view, deletedViewIndex),
key: ValueKey(view.id),
);
},
),
return BlocBuilder<DocumentAppearanceCubit, DocumentAppearance>(
builder: (_, state) {
return DocumentPage(
view: view,
onDeleted: () => context?.onDeleted(view, deletedViewIndex),
key: ValueKey(view.id),
);
},
);
}

Expand All @@ -128,10 +113,7 @@ class DocumentPluginWidgetBuilder extends PluginWidgetBuilder
view: view,
),
const SizedBox(width: 10),
BlocProvider.value(
value: documentAppearanceCubit,
child: const DocumentMoreButton(),
),
const DocumentMoreButton(),
],
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,30 +28,32 @@ class EditorStyleCustomizer {
EditorStyle desktop() {
final theme = Theme.of(context);
final fontSize = context.read<DocumentAppearanceCubit>().state.fontSize;
final fontFamily = context.read<DocumentAppearanceCubit>().state.fontFamily;
return EditorStyle.desktop(
padding: padding,
backgroundColor: theme.colorScheme.surface,
cursorColor: theme.colorScheme.primary,
textStyleConfiguration: TextStyleConfiguration(
text: TextStyle(
fontFamily: 'Poppins',
text: baseTextStyle(fontFamily).copyWith(
fontSize: fontSize,
color: theme.colorScheme.onBackground,
height: 1.5,
),
bold: const TextStyle(
fontFamily: 'Poppins-Bold',
bold: baseTextStyle(fontFamily).copyWith(
fontWeight: FontWeight.w600,
),
italic: const TextStyle(fontStyle: FontStyle.italic),
underline: const TextStyle(decoration: TextDecoration.underline),
strikethrough: const TextStyle(decoration: TextDecoration.lineThrough),
href: TextStyle(
italic: baseTextStyle(fontFamily).copyWith(fontStyle: FontStyle.italic),
underline: baseTextStyle(fontFamily)
.copyWith(decoration: TextDecoration.underline),
strikethrough:
baseTextStyle(fontFamily)
.copyWith(decoration: TextDecoration.lineThrough),
href: baseTextStyle(fontFamily).copyWith(
color: theme.colorScheme.primary,
decoration: TextDecoration.underline,
),
code: GoogleFonts.robotoMono(
textStyle: TextStyle(
textStyle: baseTextStyle(fontFamily).copyWith(
fontSize: fontSize,
fontWeight: FontWeight.normal,
color: Colors.red,
Expand All @@ -66,30 +68,33 @@ class EditorStyleCustomizer {
EditorStyle mobile() {
final theme = Theme.of(context);
final fontSize = context.read<DocumentAppearanceCubit>().state.fontSize;
final fontFamily = context.read<DocumentAppearanceCubit>().state.fontFamily;

return EditorStyle.desktop(
padding: padding,
backgroundColor: theme.colorScheme.surface,
cursorColor: theme.colorScheme.primary,
textStyleConfiguration: TextStyleConfiguration(
text: TextStyle(
fontFamily: 'poppins',
text: baseTextStyle(fontFamily).copyWith(
fontSize: fontSize,
color: theme.colorScheme.onBackground,
height: 1.5,
),
bold: const TextStyle(
fontFamily: 'poppins-Bold',
bold: baseTextStyle(fontFamily).copyWith(
fontWeight: FontWeight.w600,
),
italic: const TextStyle(fontStyle: FontStyle.italic),
underline: const TextStyle(decoration: TextDecoration.underline),
strikethrough: const TextStyle(decoration: TextDecoration.lineThrough),
href: TextStyle(
italic: baseTextStyle(fontFamily).copyWith(fontStyle: FontStyle.italic),
underline: baseTextStyle(fontFamily)
.copyWith(decoration: TextDecoration.underline),
strikethrough:
baseTextStyle(fontFamily)
.copyWith(decoration: TextDecoration.lineThrough),
href: baseTextStyle(fontFamily).copyWith(
color: theme.colorScheme.primary,
decoration: TextDecoration.underline,
),
code: GoogleFonts.robotoMono(
textStyle: TextStyle(
textStyle: baseTextStyle(fontFamily).copyWith(
fontSize: fontSize,
fontWeight: FontWeight.normal,
color: Colors.red,
Expand Down Expand Up @@ -119,8 +124,8 @@ class EditorStyleCustomizer {
TextStyle codeBlockStyleBuilder() {
final theme = Theme.of(context);
final fontSize = context.read<DocumentAppearanceCubit>().state.fontSize;
return TextStyle(
fontFamily: 'poppins',
final fontFamily = context.read<DocumentAppearanceCubit>().state.fontFamily;
return baseTextStyle(fontFamily).copyWith(
fontSize: fontSize,
height: 1.5,
color: theme.colorScheme.onBackground,
Expand Down Expand Up @@ -157,6 +162,16 @@ class EditorStyleCustomizer {
);
}

TextStyle baseTextStyle(String fontFamily) {
try {
return GoogleFonts.getFont(
fontFamily,
);
} on Exception {
return GoogleFonts.getFont('Poppins');
}
}

InlineSpan customizeAttributeDecorator(
TextInsert textInsert,
TextSpan textSpan,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,37 @@
import 'package:appflowy/core/config/kv_keys.dart';
import 'package:bloc/bloc.dart';
import 'package:shared_preferences/shared_preferences.dart';

const String _kDocumentAppearanceFontSize = 'kDocumentAppearanceFontSize';

class DocumentAppearance {
const DocumentAppearance({
required this.fontSize,
required this.fontFamily,
});

final double fontSize;
// Will be supported...
// final String fontName;
final String fontFamily;

DocumentAppearance copyWith({double? fontSize}) {
DocumentAppearance copyWith({
double? fontSize,
String? fontFamily,
}) {
return DocumentAppearance(
fontSize: fontSize ?? this.fontSize,
fontFamily: fontFamily ?? this.fontFamily,
);
}
}

class DocumentAppearanceCubit extends Cubit<DocumentAppearance> {
DocumentAppearanceCubit() : super(const DocumentAppearance(fontSize: 16.0));
DocumentAppearanceCubit()
: super(const DocumentAppearance(fontSize: 16.0, fontFamily: 'Poppins'));

void fetch() async {
Future<void> fetch() async {
final prefs = await SharedPreferences.getInstance();
final fontSize = prefs.getDouble(_kDocumentAppearanceFontSize) ?? 16.0;
final fontSize =
prefs.getDouble(KVKeys.kDocumentAppearanceFontSize) ?? 16.0;
final fontFamily =
prefs.getString(KVKeys.kDocumentAppearanceFontFamily) ?? 'Poppins';

if (isClosed) {
return;
Expand All @@ -33,13 +40,14 @@ class DocumentAppearanceCubit extends Cubit<DocumentAppearance> {
emit(
state.copyWith(
fontSize: fontSize,
fontFamily: fontFamily,
),
);
}

void syncFontSize(double fontSize) async {
Future<void> syncFontSize(double fontSize) async {
final prefs = await SharedPreferences.getInstance();
prefs.setDouble(_kDocumentAppearanceFontSize, fontSize);
prefs.setDouble(KVKeys.kDocumentAppearanceFontSize, fontSize);

if (isClosed) {
return;
Expand All @@ -51,4 +59,19 @@ class DocumentAppearanceCubit extends Cubit<DocumentAppearance> {
),
);
}

Future<void> syncFontFamily(String fontFamily) async {
final prefs = await SharedPreferences.getInstance();
prefs.setString(KVKeys.kDocumentAppearanceFontFamily, fontFamily);

if (isClosed) {
return;
}

emit(
state.copyWith(
fontFamily: fontFamily,
),
);
}
}
10 changes: 8 additions & 2 deletions frontend/appflowy_flutter/lib/startup/tasks/app_widget.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:appflowy/plugins/document/presentation/more/cubit/document_appearance_cubit.dart';
import 'package:appflowy_editor/appflowy_editor.dart' hide Log;
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
Expand Down Expand Up @@ -79,8 +80,13 @@ class ApplicationWidget extends StatelessWidget {
final cubit = AppearanceSettingsCubit(appearanceSetting)
..readLocaleWhenAppLaunch(context);

return BlocProvider(
create: (context) => cubit,
return MultiBlocProvider(
providers: [
BlocProvider.value(value: cubit),
BlocProvider<DocumentAppearanceCubit>(
create: (_) => DocumentAppearanceCubit()..fetch(),
),
],
child: BlocBuilder<AppearanceSettingsCubit, AppearanceSettingsState>(
builder: (context, state) => MaterialApp(
builder: overlayManagerBuilder(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import 'package:flowy_infra/theme_extension.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:google_fonts/google_fonts.dart';

part 'appearance.freezed.dart';

Expand Down Expand Up @@ -49,6 +50,14 @@ class AppearanceSettingsCubit extends Cubit<AppearanceSettingsState> {
emit(state.copyWith(themeMode: themeMode));
}

/// Update selected font in the user's settings and emit an updated state
/// with the font name.
void setFontFamily(String fontFamilyName) {
_setting.font = fontFamilyName;
_saveAppearanceSettings();
emit(state.copyWith(font: fontFamilyName));
}

/// Updates the current locale and notify the listeners the locale was
/// changed. Fallback to [en] locale if [newLocale] is not supported.
void setLocale(BuildContext context, Locale newLocale) {
Expand Down Expand Up @@ -341,14 +350,24 @@ class AppearanceSettingsState with _$AppearanceSettingsState {
}

TextStyle _getFontStyle({
String? fontFamily,
required String fontFamily,
double? fontSize,
FontWeight? fontWeight,
Color? fontColor,
double? letterSpacing,
double? lineHeight,
}) =>
TextStyle(
}) {
try {
return GoogleFonts.getFont(
fontFamily,
fontSize: fontSize ?? FontSizes.s12,
color: fontColor,
fontWeight: fontWeight ?? FontWeight.w500,
letterSpacing: (fontSize ?? FontSizes.s12) * (letterSpacing ?? 0.005),
height: lineHeight,
);
} catch (e) {
return TextStyle(
fontFamily: fontFamily,
fontSize: fontSize ?? FontSizes.s12,
color: fontColor,
Expand All @@ -357,6 +376,8 @@ class AppearanceSettingsState with _$AppearanceSettingsState {
letterSpacing: (fontSize ?? FontSizes.s12) * (letterSpacing ?? 0.005),
height: lineHeight,
);
}
}

TextTheme _getTextTheme({
required String fontFamily,
Expand Down
Loading

0 comments on commit 323cb3b

Please sign in to comment.