chore: add textTheme to AppTheme (#1448)

* chore: add textTheme to AppTheme

* chore: extend scaled font size options

* chore: add text styles to extension and rename extension to AFThemeExtension

* chore: use 2021 material design text style tokens
This commit is contained in:
Richard Shiue
2022-11-17 15:28:57 +08:00
committed by GitHub
parent eb35fb25af
commit f00a78746e
16 changed files with 138 additions and 40 deletions

View File

@ -189,7 +189,7 @@ class _Background extends StatelessWidget {
return FlowyHoverContainer( return FlowyHoverContainer(
style: HoverStyle( style: HoverStyle(
borderRadius: Corners.s6Border, borderRadius: Corners.s6Border,
hoverColor: CustomColors.of(context).lightGreyHover, hoverColor: AFThemeExtension.of(context).lightGreyHover,
), ),
); );
} else { } else {
@ -210,7 +210,8 @@ class CellAccessoryContainer extends StatelessWidget {
final children = final children =
accessories.where((accessory) => accessory.enable()).map((accessory) { accessories.where((accessory) => accessory.enable()).map((accessory) {
final hover = FlowyHover( final hover = FlowyHover(
style: HoverStyle(hoverColor: CustomColors.of(context).lightGreyHover), style:
HoverStyle(hoverColor: AFThemeExtension.of(context).lightGreyHover),
builder: (_, onHover) => Container( builder: (_, onHover) => Container(
width: 26, width: 26,
height: 26, height: 26,

View File

@ -201,7 +201,7 @@ class _CellCalendarWidgetState extends State<_CellCalendarWidget> {
borderRadius: const BorderRadius.all(Radius.circular(6)), borderRadius: const BorderRadius.all(Radius.circular(6)),
), ),
todayDecoration: BoxDecoration( todayDecoration: BoxDecoration(
color: CustomColors.of(context).lightGreyHover, color: AFThemeExtension.of(context).lightGreyHover,
shape: BoxShape.rectangle, shape: BoxShape.rectangle,
borderRadius: const BorderRadius.all(Radius.circular(6)), borderRadius: const BorderRadius.all(Radius.circular(6)),
), ),

View File

@ -10,23 +10,23 @@ extension SelectOptionColorExtension on SelectOptionColorPB {
Color make(BuildContext context) { Color make(BuildContext context) {
switch (this) { switch (this) {
case SelectOptionColorPB.Purple: case SelectOptionColorPB.Purple:
return CustomColors.tint1; return AFThemeExtension.tint1;
case SelectOptionColorPB.Pink: case SelectOptionColorPB.Pink:
return CustomColors.tint2; return AFThemeExtension.tint2;
case SelectOptionColorPB.LightPink: case SelectOptionColorPB.LightPink:
return CustomColors.tint3; return AFThemeExtension.tint3;
case SelectOptionColorPB.Orange: case SelectOptionColorPB.Orange:
return CustomColors.tint4; return AFThemeExtension.tint4;
case SelectOptionColorPB.Yellow: case SelectOptionColorPB.Yellow:
return CustomColors.tint5; return AFThemeExtension.tint5;
case SelectOptionColorPB.Lime: case SelectOptionColorPB.Lime:
return CustomColors.tint6; return AFThemeExtension.tint6;
case SelectOptionColorPB.Green: case SelectOptionColorPB.Green:
return CustomColors.tint7; return AFThemeExtension.tint7;
case SelectOptionColorPB.Aqua: case SelectOptionColorPB.Aqua:
return CustomColors.tint8; return AFThemeExtension.tint8;
case SelectOptionColorPB.Blue: case SelectOptionColorPB.Blue:
return CustomColors.tint9; return AFThemeExtension.tint9;
default: default:
throw ArgumentError; throw ArgumentError;
} }

View File

@ -214,7 +214,7 @@ class _CreateOptionCell extends StatelessWidget {
const HSpace(10), const HSpace(10),
SelectOptionTag( SelectOptionTag(
name: name, name: name,
color: CustomColors.of(context).lightGreyHover, color: AFThemeExtension.of(context).lightGreyHover,
onSelected: () => context onSelected: () => context
.read<SelectOptionCellEditorBloc>() .read<SelectOptionCellEditorBloc>()
.add(SelectOptionEditorEvent.newOption(name)), .add(SelectOptionEditorEvent.newOption(name)),

View File

@ -15,7 +15,7 @@ class GridAddRowButton extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return FlowyButton( return FlowyButton(
text: FlowyText.medium(LocaleKeys.grid_row_newRow.tr(), fontSize: 12), text: FlowyText.medium(LocaleKeys.grid_row_newRow.tr(), fontSize: 12),
hoverColor: CustomColors.of(context).lightGreyHover, hoverColor: AFThemeExtension.of(context).lightGreyHover,
onTap: () => context.read<GridBloc>().add(const GridEvent.createRow()), onTap: () => context.read<GridBloc>().add(const GridEvent.createRow()),
leftIcon: svgWidget( leftIcon: svgWidget(
"home/add", "home/add",

View File

@ -166,7 +166,7 @@ class FieldCellButton extends StatelessWidget {
.replaceAll(Characters(''), Characters('\u{200B}')) .replaceAll(Characters(''), Characters('\u{200B}'))
.toString(); .toString();
return FlowyButton( return FlowyButton(
hoverColor: CustomColors.of(context).lightGreyHover, hoverColor: AFThemeExtension.of(context).lightGreyHover,
onTap: onTap, onTap: onTap,
leftIcon: svgWidget( leftIcon: svgWidget(
field.fieldType.iconName(), field.fieldType.iconName(),

View File

@ -182,7 +182,7 @@ class CreateFieldButton extends StatelessWidget {
LocaleKeys.grid_field_newColumn.tr(), LocaleKeys.grid_field_newColumn.tr(),
fontSize: 12, fontSize: 12,
), ),
hoverColor: CustomColors.of(context).lightGreyHover, hoverColor: AFThemeExtension.of(context).lightGreyHover,
onTap: () {}, onTap: () {},
leftIcon: svgWidget( leftIcon: svgWidget(
"home/add", "home/add",

View File

@ -202,7 +202,7 @@ class _CreateFieldButtonState extends State<_CreateFieldButton> {
LocaleKeys.grid_field_newColumn.tr(), LocaleKeys.grid_field_newColumn.tr(),
fontSize: 12, fontSize: 12,
), ),
hoverColor: CustomColors.of(context).lightGreyHover, hoverColor: AFThemeExtension.of(context).lightGreyHover,
onTap: () {}, onTap: () {},
leftIcon: svgWidget("home/add"), leftIcon: svgWidget("home/add"),
), ),

View File

@ -56,7 +56,7 @@ class WelcomeScreen extends StatelessWidget {
child: FlowyTextButton( child: FlowyTextButton(
LocaleKeys.workspace_create.tr(), LocaleKeys.workspace_create.tr(),
fontSize: 14, fontSize: 14,
hoverColor: CustomColors.of(context).lightGreyHover, hoverColor: AFThemeExtension.of(context).lightGreyHover,
onPressed: () { onPressed: () {
context.read<WelcomeBloc>().add( context.read<WelcomeBloc>().add(
WelcomeEvent.createWorkspace(LocaleKeys.workspace_hint.tr(), "")); WelcomeEvent.createWorkspace(LocaleKeys.workspace_hint.tr(), ""));
@ -100,7 +100,7 @@ class WorkspaceItem extends StatelessWidget {
height: 46, height: 46,
child: FlowyTextButton( child: FlowyTextButton(
workspace.name, workspace.name,
hoverColor: CustomColors.of(context).lightGreyHover, hoverColor: AFThemeExtension.of(context).lightGreyHover,
fontSize: 14, fontSize: 14,
onPressed: () => onPressed(workspace), onPressed: () => onPressed(workspace),
), ),

View File

@ -51,7 +51,7 @@ class ViewSectionItem extends StatelessWidget {
onTap: () => onSelected(blocContext.read<ViewBloc>().state.view), onTap: () => onSelected(blocContext.read<ViewBloc>().state.view),
child: FlowyHover( child: FlowyHover(
style: HoverStyle( style: HoverStyle(
hoverColor: CustomColors.of(context).greySelect, hoverColor: AFThemeExtension.of(context).greySelect,
), ),
// If current state.isEditing is true, the hover should not // If current state.isEditing is true, the hover should not
// rebuild when onEnter/onExit events happened. // rebuild when onEnter/onExit events happened.

View File

@ -26,7 +26,7 @@ class Toggle extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final backgroundColor = value final backgroundColor = value
? activeBackgroundColor ?? Theme.of(context).colorScheme.primary ? activeBackgroundColor ?? Theme.of(context).colorScheme.primary
: activeBackgroundColor ?? CustomColors.of(context).toggleOffFill; : activeBackgroundColor ?? AFThemeExtension.of(context).toggleOffFill;
return GestureDetector( return GestureDetector(
onTap: (() => onChanged(value)), onTap: (() => onChanged(value)),
child: Padding( child: Padding(

View File

@ -1,7 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@immutable @immutable
class CustomColors extends ThemeExtension<CustomColors> { class AFThemeExtension extends ThemeExtension<AFThemeExtension> {
final Color? warning; final Color? warning;
final Color? success; final Color? success;
@ -20,51 +20,67 @@ class CustomColors extends ThemeExtension<CustomColors> {
final Color lightGreyHover; final Color lightGreyHover;
final Color toggleOffFill; final Color toggleOffFill;
const CustomColors({ final TextStyle code;
final TextStyle callout;
final TextStyle caption;
const AFThemeExtension({
required this.warning, required this.warning,
required this.success, required this.success,
required this.greyHover, required this.greyHover,
required this.greySelect, required this.greySelect,
required this.lightGreyHover, required this.lightGreyHover,
required this.toggleOffFill, required this.toggleOffFill,
required this.code,
required this.callout,
required this.caption,
}); });
static CustomColors of(BuildContext context) { static AFThemeExtension of(BuildContext context) {
return Theme.of(context).extension<CustomColors>()!; return Theme.of(context).extension<AFThemeExtension>()!;
} }
@override @override
CustomColors copyWith({ AFThemeExtension copyWith({
Color? warning, Color? warning,
Color? success, Color? success,
Color? greyHover, Color? greyHover,
Color? greySelect, Color? greySelect,
Color? lightGreyHover, Color? lightGreyHover,
Color? toggleOffFill, Color? toggleOffFill,
TextStyle? code,
TextStyle? callout,
TextStyle? caption,
}) { }) {
return CustomColors( return AFThemeExtension(
warning: warning ?? this.warning, warning: warning ?? this.warning,
success: success ?? this.success, success: success ?? this.success,
greyHover: greyHover ?? this.greyHover, greyHover: greyHover ?? this.greyHover,
greySelect: greySelect ?? this.greySelect, greySelect: greySelect ?? this.greySelect,
lightGreyHover: lightGreyHover ?? this.lightGreyHover, lightGreyHover: lightGreyHover ?? this.lightGreyHover,
toggleOffFill: toggleOffFill ?? this.toggleOffFill, toggleOffFill: toggleOffFill ?? this.toggleOffFill,
code: code ?? this.code,
callout: callout ?? this.callout,
caption: caption ?? this.caption,
); );
} }
@override @override
ThemeExtension<CustomColors> lerp( ThemeExtension<AFThemeExtension> lerp(
ThemeExtension<CustomColors>? other, double t) { ThemeExtension<AFThemeExtension>? other, double t) {
if (other is! CustomColors) { if (other is! AFThemeExtension) {
return this; return this;
} }
return CustomColors( return AFThemeExtension(
warning: Color.lerp(warning, other.warning, t), warning: Color.lerp(warning, other.warning, t),
success: Color.lerp(success, other.success, t), success: Color.lerp(success, other.success, t),
greyHover: Color.lerp(greyHover, other.greyHover, t)!, greyHover: Color.lerp(greyHover, other.greyHover, t)!,
greySelect: Color.lerp(greySelect, other.greySelect, t)!, greySelect: Color.lerp(greySelect, other.greySelect, t)!,
lightGreyHover: Color.lerp(lightGreyHover, other.lightGreyHover, t)!, lightGreyHover: Color.lerp(lightGreyHover, other.lightGreyHover, t)!,
toggleOffFill: Color.lerp(toggleOffFill, other.toggleOffFill, t)!, toggleOffFill: Color.lerp(toggleOffFill, other.toggleOffFill, t)!,
code: other.code,
callout: other.callout,
caption: other.caption,
); );
} }
} }

View File

@ -43,6 +43,14 @@ class FontSizes {
static double get s16 => 16 * scale; static double get s16 => 16 * scale;
static double get s18 => 18 * scale; static double get s18 => 18 * scale;
static double get s20 => 20 * scale;
static double get s24 => 24 * scale;
static double get s32 => 32 * scale;
static double get s44 => 44 * scale;
} }
class Sizes { class Sizes {

View File

@ -1,6 +1,7 @@
import 'package:flowy_infra/size.dart'; import 'package:flowy_infra/size.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
// preserved until deprecation
class Fonts { class Fonts {
static String general = "Poppins"; static String general = "Poppins";
@ -10,6 +11,7 @@ class Fonts {
} }
class TextStyles { class TextStyles {
// preserved until deprecation
static TextStyle general({ static TextStyle general({
double? fontSize, double? fontSize,
FontWeight fontWeight = FontWeight.w500, FontWeight fontWeight = FontWeight.w500,
@ -70,4 +72,64 @@ class TextStyles {
fontSize: FontSizes.s11, fontSize: FontSizes.s11,
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
); );
final String font;
final Color color;
TextStyles({
required this.font,
required this.color,
});
TextStyle getFontStyle({
String? fontFamily,
double? fontSize,
FontWeight? fontWeight,
Color? fontColor,
double? letterSpacing,
double? lineHeight,
}) =>
TextStyle(
fontFamily: fontFamily ?? font,
fontSize: fontSize ?? FontSizes.s12,
color: fontColor ?? color,
fontWeight: fontWeight ?? FontWeight.w500,
fontFamilyFallback: const ["Noto Color Emoji"],
letterSpacing: (fontSize ?? FontSizes.s12) * (letterSpacing ?? 0.005),
height: lineHeight,
);
TextTheme generateTextTheme() {
return TextTheme(
displayLarge: getFontStyle(
fontSize: FontSizes.s32,
fontWeight: FontWeight.w600,
lineHeight: 42.0,
), // h2
displayMedium: getFontStyle(
fontSize: FontSizes.s24,
fontWeight: FontWeight.w600,
lineHeight: 34.0,
), // h3
displaySmall: getFontStyle(
fontSize: FontSizes.s20,
fontWeight: FontWeight.w600,
lineHeight: 28.0,
), // h4
titleLarge: getFontStyle(
fontSize: FontSizes.s18,
fontWeight: FontWeight.w600,
), // title
titleMedium: getFontStyle(
fontSize: FontSizes.s16,
fontWeight: FontWeight.w600,
), // heading
titleSmall: getFontStyle(
fontSize: FontSizes.s14,
fontWeight: FontWeight.w600,
), // subheading
bodyMedium: getFontStyle(), // body-regular
bodySmall: getFontStyle(fontWeight: FontWeight.w400), // body-thin
);
}
} }

View File

@ -1,3 +1,5 @@
import 'package:flowy_infra/size.dart';
import 'package:flowy_infra/text_style.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'color_extension.dart'; import 'color_extension.dart';
@ -19,7 +21,7 @@ String themeTypeToString(Brightness brightness) {
} }
} }
// Color Pallettes // Color Palettes
const _black = Color(0xff000000); const _black = Color(0xff000000);
const _white = Color(0xFFFFFFFF); const _white = Color(0xFFFFFFFF);
@ -154,11 +156,10 @@ class AppTheme {
} }
ThemeData get themeData { ThemeData get themeData {
final textTheme = TextStyles(font: font, color: shader1);
return ThemeData( return ThemeData(
brightness: brightness, brightness: brightness,
textTheme: TextTheme( textTheme: textTheme.generateTextTheme(),
bodyText2: TextStyle(color: shader1),
),
textSelectionTheme: TextSelectionThemeData( textSelectionTheme: TextSelectionThemeData(
cursorColor: main2, selectionHandleColor: main2), cursorColor: main2, selectionHandleColor: main2),
primaryIconTheme: IconThemeData(color: hover), primaryIconTheme: IconThemeData(color: hover),
@ -195,13 +196,23 @@ class AppTheme {
shadow: shadow, shadow: shadow,
), ),
extensions: [ extensions: [
CustomColors( AFThemeExtension(
warning: yellow, warning: yellow,
success: green, success: green,
greyHover: bg2, greyHover: bg2,
greySelect: bg3, greySelect: bg3,
lightGreyHover: shader6, lightGreyHover: shader6,
toggleOffFill: shader5, toggleOffFill: shader5,
code: textTheme.getFontStyle(fontFamily: monospaceFont),
callout: textTheme.getFontStyle(
fontSize: FontSizes.s11,
fontColor: shader3,
),
caption: textTheme.getFontStyle(
fontSize: FontSizes.s11,
fontWeight: FontWeight.w400,
fontColor: shader3,
),
) )
], ],
); );

View File

@ -138,13 +138,13 @@ class ScrollbarState extends State<StyledScrollbar> {
// Handle color // Handle color
var handleColor = widget.handleColor ?? var handleColor = widget.handleColor ??
(Theme.of(context).brightness == Brightness.dark (Theme.of(context).brightness == Brightness.dark
? CustomColors.of(context).greyHover.withOpacity(.2) ? AFThemeExtension.of(context).greyHover.withOpacity(.2)
: CustomColors.of(context).greyHover); : AFThemeExtension.of(context).greyHover);
// Track color // Track color
var trackColor = widget.trackColor ?? var trackColor = widget.trackColor ??
(Theme.of(context).brightness == Brightness.dark (Theme.of(context).brightness == Brightness.dark
? CustomColors.of(context).greyHover.withOpacity(.1) ? AFThemeExtension.of(context).greyHover.withOpacity(.1)
: CustomColors.of(context).greyHover.withOpacity(.3)); : AFThemeExtension.of(context).greyHover.withOpacity(.3));
//Layout the stack, it just contains a child, and //Layout the stack, it just contains a child, and
return Stack(children: <Widget>[ return Stack(children: <Widget>[