417 lines
12 KiB
Dart
Raw Normal View History

2022-03-20 17:17:06 +08:00
import 'dart:async';
import 'package:appflowy/user/application/user_settings_service.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-user/user_setting.pb.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/size.dart';
2022-01-28 18:34:21 +08:00
import 'package:flowy_infra/theme.dart';
import 'package:flowy_infra/theme_extension.dart';
2022-01-28 18:34:21 +08:00
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
2022-01-28 18:34:21 +08:00
part 'appearance.freezed.dart';
const _white = Color(0xFFFFFFFF);
/// [AppearanceSettingsCubit] is used to modify the appearance of AppFlowy.
/// It includes the [AppTheme], [ThemeMode], [TextStyles] and [Locale].
class AppearanceSettingsCubit extends Cubit<AppearanceSettingsState> {
final AppearanceSettingsPB _setting;
AppearanceSettingsCubit(AppearanceSettingsPB setting)
: _setting = setting,
super(
AppearanceSettingsState.initial(
setting.theme,
setting.themeMode,
setting.font,
setting.monospaceFont,
setting.locale,
setting.isMenuCollapsed,
setting.menuOffset,
),
);
2022-01-28 18:34:21 +08:00
/// Update selected theme in the user's settings and emit an updated state
/// with the AppTheme named [themeName].
void setTheme(String themeName) {
_setting.theme = themeName;
_saveAppearanceSettings();
emit(state.copyWith(appTheme: AppTheme.fromName(themeName)));
}
2022-01-28 18:34:21 +08:00
/// Update the theme mode in the user's settings and emit an updated state.
void setThemeMode(ThemeMode themeMode) {
_setting.themeMode = _themeModeToPB(themeMode);
_saveAppearanceSettings();
emit(state.copyWith(themeMode: themeMode));
2022-01-28 18:34:21 +08:00
}
/// 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) {
if (!context.supportedLocales.contains(newLocale)) {
Log.warn("Unsupported locale: $newLocale, Fallback to locale: en");
newLocale = const Locale('en');
}
context.setLocale(newLocale).catchError((e) {
Log.warn('Catch error in setLocale: $e}');
});
if (state.locale != newLocale) {
_setting.locale.languageCode = newLocale.languageCode;
_setting.locale.countryCode = newLocale.countryCode ?? "";
_saveAppearanceSettings();
emit(state.copyWith(locale: newLocale));
2022-01-28 18:48:09 +08:00
}
2022-01-28 18:34:21 +08:00
}
// Saves the menus current visibility
void saveIsMenuCollapsed(bool collapsed) {
_setting.isMenuCollapsed = collapsed;
_saveAppearanceSettings();
}
// Saves the current resize offset of the menu
void saveMenuOffset(double offset) {
_setting.menuOffset = offset;
_saveAppearanceSettings();
}
/// Saves key/value setting to disk.
/// Removes the key if the passed in value is null
void setKeyValue(String key, String? value) {
if (key.isEmpty) {
Log.warn("The key should not be empty");
return;
}
2022-02-01 12:15:11 +08:00
if (value == null) {
_setting.settingKeyValue.remove(key);
}
if (_setting.settingKeyValue[key] != value) {
if (value == null) {
_setting.settingKeyValue.remove(key);
} else {
_setting.settingKeyValue[key] = value;
}
2022-10-25 17:30:57 +08:00
}
_saveAppearanceSettings();
2022-10-25 17:30:57 +08:00
}
2022-10-25 17:30:57 +08:00
String? getValue(String key) {
if (key.isEmpty) {
Log.warn("The key should not be empty");
return null;
}
2022-10-25 17:30:57 +08:00
return _setting.settingKeyValue[key];
}
/// Called when the application launches.
/// Uses the device locale when the application is opened for the first time.
void readLocaleWhenAppLaunch(BuildContext context) {
if (_setting.resetToDefault) {
_setting.resetToDefault = false;
_saveAppearanceSettings();
setLocale(context, context.deviceLocale);
return;
2022-02-01 12:15:11 +08:00
}
setLocale(context, state.locale);
}
Future<void> _saveAppearanceSettings() async {
UserSettingsBackendService().setAppearanceSetting(_setting).then((result) {
2022-10-25 17:30:57 +08:00
result.fold(
(l) => null,
(error) => Log.error(error),
);
});
}
}
ThemeMode _themeModeFromPB(ThemeModePB themeModePB) {
switch (themeModePB) {
case ThemeModePB.Light:
return ThemeMode.light;
case ThemeModePB.Dark:
return ThemeMode.dark;
case ThemeModePB.System:
default:
return ThemeMode.system;
}
}
ThemeModePB _themeModeToPB(ThemeMode themeMode) {
switch (themeMode) {
case ThemeMode.light:
return ThemeModePB.Light;
case ThemeMode.dark:
return ThemeModePB.Dark;
case ThemeMode.system:
default:
return ThemeModePB.System;
}
}
@freezed
class AppearanceSettingsState with _$AppearanceSettingsState {
const AppearanceSettingsState._();
const factory AppearanceSettingsState({
required AppTheme appTheme,
required ThemeMode themeMode,
required String font,
required String monospaceFont,
required Locale locale,
required bool isMenuCollapsed,
required double menuOffset,
}) = _AppearanceSettingsState;
factory AppearanceSettingsState.initial(
String themeName,
ThemeModePB themeModePB,
String font,
String monospaceFont,
LocaleSettingsPB localePB,
bool isMenuCollapsed,
double menuOffset,
) {
return AppearanceSettingsState(
appTheme: AppTheme.fromName(themeName),
font: font,
monospaceFont: monospaceFont,
themeMode: _themeModeFromPB(themeModePB),
locale: Locale(localePB.languageCode, localePB.countryCode),
isMenuCollapsed: isMenuCollapsed,
menuOffset: menuOffset,
);
}
ThemeData get lightTheme => _getThemeData(Brightness.light);
ThemeData get darkTheme => _getThemeData(Brightness.dark);
ThemeData _getThemeData(Brightness brightness) {
// Poppins and SF Mono are not well supported in some languages, so use the
// built-in font for the following languages.
final useBuiltInFontLanguages = [
const Locale('zh', 'CN'),
const Locale('zh', 'TW'),
];
String fontFamily = font;
String monospaceFontFamily = monospaceFont;
if (useBuiltInFontLanguages.contains(locale)) {
fontFamily = '';
monospaceFontFamily = '';
}
final theme = brightness == Brightness.light
? appTheme.lightTheme
: appTheme.darkTheme;
final colorScheme = ColorScheme(
brightness: brightness,
primary: theme.primary,
onPrimary: theme.onPrimary,
primaryContainer: theme.main2,
onPrimaryContainer: _white,
// page title hover color
secondary: theme.hoverBG1,
onSecondary: theme.shader1,
// setting value hover color
secondaryContainer: theme.selector,
onSecondaryContainer: theme.topbarBg,
tertiary: theme.shader7,
// Editor: toolbarColor
onTertiary: theme.toolbarColor,
tertiaryContainer: theme.questionBubbleBG,
background: theme.surface,
onBackground: theme.text,
surface: theme.surface,
// text&icon color when it is hovered
onSurface: theme.hoverFG,
// grey hover color
inverseSurface: theme.hoverBG3,
onError: theme.shader7,
error: theme.red,
outline: theme.shader4,
surfaceVariant: theme.sidebarBg,
shadow: theme.shadow,
);
const Set<MaterialState> scrollbarInteractiveStates = <MaterialState>{
MaterialState.pressed,
MaterialState.hovered,
MaterialState.dragged,
};
return ThemeData(
brightness: brightness,
dialogBackgroundColor: theme.surface,
Feat(appflowy_flutter): dark mode improvement for generic area/widgets (#2099) * chore: update color scheme for dark mode * chore: update dark color scheme 1. update the background color for side bar, surface and divider in dark mode 2. comment out dandelion and lavender theme temporarily * chore: update top bar BGcolor and icon color * chore: update text color * chore: update share button color on the top bar * chore: add tooltip theme data in global * chore: add hint and tertiary color and update font size pop up menu style * chore: update all the semibold texts color * chore: update all the hover color * chore: update setting BG color * chore: add FlowySvg to get the icon color through current theme 1. Add FlowySvg widget 2. Update all the icons those have hover effect to FlowySvg 3. Recover shader1 for the text color when it is in hovered * chore: update side bar UI 1. Update AddButton hover style 2. Update MenuAppHeader icon color and its hover style 3. Update NewAppButton(New page) font color 4. Update MenuUser username font color * chore: update SettingsDialog style in dart mode 1. Update title and text color 2. Update the hover color on FlowyTextButton 3. Update the LanguageSelectorDropdown background color and hover enter color * chore: update NewAppButton icon in dark mode * chore: update default icon color * chore: rename the hover color and update ViewSectionItem hover color from default theme color * chore: add question bubble background color * chore: update cover image button color * chore: remove fixed icon color on _AddCoverButton * chore: put Dandelion and Lavender color scheme back with basic modification * fix: delete unused import files and deprecated field * chore: add comma and put color back * chore: update AppFlowyPopover background color * chore: remove the hover color on primary and secondary button * chore: update shadow color in dark mode * chore: update SettingsMenuElement hover effect * chore: update the text color in DropdownMenuItem
2023-03-29 20:44:37 -05:00
textTheme: _getTextTheme(fontFamily: fontFamily, fontColor: theme.text),
textSelectionTheme: TextSelectionThemeData(
cursorColor: theme.main2,
selectionHandleColor: theme.main2,
),
Feat(appflowy_flutter): dark mode improvement for generic area/widgets (#2099) * chore: update color scheme for dark mode * chore: update dark color scheme 1. update the background color for side bar, surface and divider in dark mode 2. comment out dandelion and lavender theme temporarily * chore: update top bar BGcolor and icon color * chore: update text color * chore: update share button color on the top bar * chore: add tooltip theme data in global * chore: add hint and tertiary color and update font size pop up menu style * chore: update all the semibold texts color * chore: update all the hover color * chore: update setting BG color * chore: add FlowySvg to get the icon color through current theme 1. Add FlowySvg widget 2. Update all the icons those have hover effect to FlowySvg 3. Recover shader1 for the text color when it is in hovered * chore: update side bar UI 1. Update AddButton hover style 2. Update MenuAppHeader icon color and its hover style 3. Update NewAppButton(New page) font color 4. Update MenuUser username font color * chore: update SettingsDialog style in dart mode 1. Update title and text color 2. Update the hover color on FlowyTextButton 3. Update the LanguageSelectorDropdown background color and hover enter color * chore: update NewAppButton icon in dark mode * chore: update default icon color * chore: rename the hover color and update ViewSectionItem hover color from default theme color * chore: add question bubble background color * chore: update cover image button color * chore: remove fixed icon color on _AddCoverButton * chore: put Dandelion and Lavender color scheme back with basic modification * fix: delete unused import files and deprecated field * chore: add comma and put color back * chore: update AppFlowyPopover background color * chore: remove the hover color on primary and secondary button * chore: update shadow color in dark mode * chore: update SettingsMenuElement hover effect * chore: update the text color in DropdownMenuItem
2023-03-29 20:44:37 -05:00
iconTheme: IconThemeData(color: theme.icon),
tooltipTheme: TooltipThemeData(
textStyle: _getFontStyle(
fontFamily: fontFamily,
fontSize: FontSizes.s11,
fontWeight: FontWeight.w400,
fontColor: theme.surface,
),
),
scaffoldBackgroundColor: theme.surface,
snackBarTheme: SnackBarThemeData(
backgroundColor: colorScheme.primary,
contentTextStyle: TextStyle(color: colorScheme.onSurface),
),
scrollbarTheme: ScrollbarThemeData(
thumbColor: MaterialStateProperty.resolveWith((states) {
if (states.any(scrollbarInteractiveStates.contains)) {
return theme.shader7;
}
return theme.shader5;
}),
thickness: MaterialStateProperty.resolveWith((states) {
if (states.any(scrollbarInteractiveStates.contains)) {
return 4;
}
return 3.0;
}),
crossAxisMargin: 0.0,
mainAxisMargin: 6.0,
radius: Corners.s10Radius,
),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
//dropdown menu color
canvasColor: theme.surface,
Feat(appflowy_flutter): dark mode improvement for generic area/widgets (#2099) * chore: update color scheme for dark mode * chore: update dark color scheme 1. update the background color for side bar, surface and divider in dark mode 2. comment out dandelion and lavender theme temporarily * chore: update top bar BGcolor and icon color * chore: update text color * chore: update share button color on the top bar * chore: add tooltip theme data in global * chore: add hint and tertiary color and update font size pop up menu style * chore: update all the semibold texts color * chore: update all the hover color * chore: update setting BG color * chore: add FlowySvg to get the icon color through current theme 1. Add FlowySvg widget 2. Update all the icons those have hover effect to FlowySvg 3. Recover shader1 for the text color when it is in hovered * chore: update side bar UI 1. Update AddButton hover style 2. Update MenuAppHeader icon color and its hover style 3. Update NewAppButton(New page) font color 4. Update MenuUser username font color * chore: update SettingsDialog style in dart mode 1. Update title and text color 2. Update the hover color on FlowyTextButton 3. Update the LanguageSelectorDropdown background color and hover enter color * chore: update NewAppButton icon in dark mode * chore: update default icon color * chore: rename the hover color and update ViewSectionItem hover color from default theme color * chore: add question bubble background color * chore: update cover image button color * chore: remove fixed icon color on _AddCoverButton * chore: put Dandelion and Lavender color scheme back with basic modification * fix: delete unused import files and deprecated field * chore: add comma and put color back * chore: update AppFlowyPopover background color * chore: remove the hover color on primary and secondary button * chore: update shadow color in dark mode * chore: update SettingsMenuElement hover effect * chore: update the text color in DropdownMenuItem
2023-03-29 20:44:37 -05:00
dividerColor: theme.divider,
hintColor: theme.hint,
//action item hover color
hoverColor: theme.hoverBG2,
disabledColor: theme.shader4,
highlightColor: theme.main1,
indicatorColor: theme.main1,
Feat(appflowy_flutter): dark mode improvement for generic area/widgets (#2099) * chore: update color scheme for dark mode * chore: update dark color scheme 1. update the background color for side bar, surface and divider in dark mode 2. comment out dandelion and lavender theme temporarily * chore: update top bar BGcolor and icon color * chore: update text color * chore: update share button color on the top bar * chore: add tooltip theme data in global * chore: add hint and tertiary color and update font size pop up menu style * chore: update all the semibold texts color * chore: update all the hover color * chore: update setting BG color * chore: add FlowySvg to get the icon color through current theme 1. Add FlowySvg widget 2. Update all the icons those have hover effect to FlowySvg 3. Recover shader1 for the text color when it is in hovered * chore: update side bar UI 1. Update AddButton hover style 2. Update MenuAppHeader icon color and its hover style 3. Update NewAppButton(New page) font color 4. Update MenuUser username font color * chore: update SettingsDialog style in dart mode 1. Update title and text color 2. Update the hover color on FlowyTextButton 3. Update the LanguageSelectorDropdown background color and hover enter color * chore: update NewAppButton icon in dark mode * chore: update default icon color * chore: rename the hover color and update ViewSectionItem hover color from default theme color * chore: add question bubble background color * chore: update cover image button color * chore: remove fixed icon color on _AddCoverButton * chore: put Dandelion and Lavender color scheme back with basic modification * fix: delete unused import files and deprecated field * chore: add comma and put color back * chore: update AppFlowyPopover background color * chore: remove the hover color on primary and secondary button * chore: update shadow color in dark mode * chore: update SettingsMenuElement hover effect * chore: update the text color in DropdownMenuItem
2023-03-29 20:44:37 -05:00
cardColor: theme.input,
colorScheme: colorScheme,
extensions: [
AFThemeExtension(
warning: theme.yellow,
success: theme.green,
tint1: theme.tint1,
tint2: theme.tint2,
tint3: theme.tint3,
tint4: theme.tint4,
tint5: theme.tint5,
tint6: theme.tint6,
tint7: theme.tint7,
tint8: theme.tint8,
tint9: theme.tint9,
textColor: theme.text,
Feat(appflowy_flutter): dark mode improvement for generic area/widgets (#2099) * chore: update color scheme for dark mode * chore: update dark color scheme 1. update the background color for side bar, surface and divider in dark mode 2. comment out dandelion and lavender theme temporarily * chore: update top bar BGcolor and icon color * chore: update text color * chore: update share button color on the top bar * chore: add tooltip theme data in global * chore: add hint and tertiary color and update font size pop up menu style * chore: update all the semibold texts color * chore: update all the hover color * chore: update setting BG color * chore: add FlowySvg to get the icon color through current theme 1. Add FlowySvg widget 2. Update all the icons those have hover effect to FlowySvg 3. Recover shader1 for the text color when it is in hovered * chore: update side bar UI 1. Update AddButton hover style 2. Update MenuAppHeader icon color and its hover style 3. Update NewAppButton(New page) font color 4. Update MenuUser username font color * chore: update SettingsDialog style in dart mode 1. Update title and text color 2. Update the hover color on FlowyTextButton 3. Update the LanguageSelectorDropdown background color and hover enter color * chore: update NewAppButton icon in dark mode * chore: update default icon color * chore: rename the hover color and update ViewSectionItem hover color from default theme color * chore: add question bubble background color * chore: update cover image button color * chore: remove fixed icon color on _AddCoverButton * chore: put Dandelion and Lavender color scheme back with basic modification * fix: delete unused import files and deprecated field * chore: add comma and put color back * chore: update AppFlowyPopover background color * chore: remove the hover color on primary and secondary button * chore: update shadow color in dark mode * chore: update SettingsMenuElement hover effect * chore: update the text color in DropdownMenuItem
2023-03-29 20:44:37 -05:00
greyHover: theme.hoverBG1,
greySelect: theme.bg3,
lightGreyHover: theme.hoverBG3,
toggleOffFill: theme.shader5,
progressBarBGColor: theme.progressBarBGColor,
toggleButtonBGColor: theme.toggleButtonBGColor,
code: _getFontStyle(
fontFamily: monospaceFontFamily,
fontColor: theme.shader3,
),
callout: _getFontStyle(
fontFamily: fontFamily,
fontSize: FontSizes.s11,
fontColor: theme.shader3,
),
caption: _getFontStyle(
fontFamily: fontFamily,
fontSize: FontSizes.s11,
fontWeight: FontWeight.w400,
fontColor: theme.hint,
),
)
],
);
}
TextStyle _getFontStyle({
String? fontFamily,
double? fontSize,
FontWeight? fontWeight,
Color? fontColor,
double? letterSpacing,
double? lineHeight,
}) =>
TextStyle(
fontFamily: fontFamily,
fontSize: fontSize ?? FontSizes.s12,
color: fontColor,
fontWeight: fontWeight ?? FontWeight.w500,
fontFamilyFallback: const ["Noto Color Emoji"],
letterSpacing: (fontSize ?? FontSizes.s12) * (letterSpacing ?? 0.005),
height: lineHeight,
);
TextTheme _getTextTheme({
required String fontFamily,
required Color fontColor,
}) {
return TextTheme(
displayLarge: _getFontStyle(
fontFamily: fontFamily,
fontSize: FontSizes.s32,
fontColor: fontColor,
fontWeight: FontWeight.w600,
lineHeight: 42.0,
), // h2
displayMedium: _getFontStyle(
fontFamily: fontFamily,
fontSize: FontSizes.s24,
fontColor: fontColor,
fontWeight: FontWeight.w600,
lineHeight: 34.0,
), // h3
displaySmall: _getFontStyle(
fontFamily: fontFamily,
fontSize: FontSizes.s20,
fontColor: fontColor,
fontWeight: FontWeight.w600,
lineHeight: 28.0,
), // h4
titleLarge: _getFontStyle(
fontFamily: fontFamily,
fontSize: FontSizes.s18,
fontColor: fontColor,
fontWeight: FontWeight.w600,
), // title
titleMedium: _getFontStyle(
fontFamily: fontFamily,
fontSize: FontSizes.s16,
fontColor: fontColor,
fontWeight: FontWeight.w600,
), // heading
titleSmall: _getFontStyle(
fontFamily: fontFamily,
fontSize: FontSizes.s14,
fontColor: fontColor,
fontWeight: FontWeight.w600,
), // subheading
bodyMedium: _getFontStyle(
fontFamily: fontFamily,
fontColor: fontColor,
), // body-regular
bodySmall: _getFontStyle(
fontFamily: fontFamily,
fontColor: fontColor,
fontWeight: FontWeight.w400,
), // body-thin
);
}
2022-01-28 18:34:21 +08:00
}