diff --git a/frontend/app_flowy/lib/startup/tasks/application_widget.dart b/frontend/app_flowy/lib/startup/tasks/application_widget.dart index a30d87ef22..a01d64f902 100644 --- a/frontend/app_flowy/lib/startup/tasks/application_widget.dart +++ b/frontend/app_flowy/lib/startup/tasks/application_widget.dart @@ -1,5 +1,6 @@ import 'package:app_flowy/startup/startup.dart'; -import 'package:app_flowy/workspace/presentation/theme/theme_model.dart'; +import 'package:app_flowy/user/infrastructure/repos/user_setting_repo.dart'; +import 'package:app_flowy/workspace/application/appearance.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart'; @@ -15,9 +16,14 @@ class AppWidgetTask extends LaunchTask { LaunchTaskType get type => LaunchTaskType.appLauncher; @override - Future initialize(LaunchContext context) { + Future initialize(LaunchContext context) async { final widget = context.getIt().create(); - final app = ApplicationWidget(child: widget); + final setting = await UserSettingReppsitory().getAppearanceSettings(); + final settingModel = AppearanceSettingModel(setting); + final app = ApplicationWidget( + child: widget, + settingModel: settingModel, + ); BlocOverrides.runZoned( () { runApp( @@ -37,36 +43,40 @@ class AppWidgetTask extends LaunchTask { class ApplicationWidget extends StatelessWidget { final Widget child; + final AppearanceSettingModel settingModel; + const ApplicationWidget({ Key? key, required this.child, + required this.settingModel, }) : super(key: key); @override - Widget build(BuildContext context) => ChangeNotifierProvider( - create: (context) => ThemeModel(), - builder: (context, _) { - const ratio = 1.73; - const minWidth = 800.0; - setWindowMinSize(const Size(minWidth, minWidth / ratio)); + Widget build(BuildContext context) => ChangeNotifierProvider.value( + value: settingModel, + builder: (context, _) { + const ratio = 1.73; + const minWidth = 800.0; + setWindowMinSize(const Size(minWidth, minWidth / ratio)); + AppTheme theme = context.select( + (value) => value.theme, + ); - ThemeType themeType = context.select((value) => value.theme); - AppTheme theme = AppTheme.fromType(themeType); - - return Provider.value( - value: theme, - child: MaterialApp( - builder: overlayManagerBuilder(), - debugShowCheckedModeBanner: false, - theme: theme.themeData, - localizationsDelegates: context.localizationDelegates, - supportedLocales: context.supportedLocales, - locale: context.locale, - navigatorKey: AppGlobals.rootNavKey, - home: child, - ), - ); - }); + return Provider.value( + value: theme, + child: MaterialApp( + builder: overlayManagerBuilder(), + debugShowCheckedModeBanner: false, + theme: theme.themeData, + localizationsDelegates: context.localizationDelegates, + supportedLocales: context.supportedLocales, + locale: context.locale, + navigatorKey: AppGlobals.rootNavKey, + home: child, + ), + ); + }, + ); } class AppGlobals { diff --git a/frontend/app_flowy/lib/user/infrastructure/repos/user_setting_repo.dart b/frontend/app_flowy/lib/user/infrastructure/repos/user_setting_repo.dart new file mode 100644 index 0000000000..60bb10528f --- /dev/null +++ b/frontend/app_flowy/lib/user/infrastructure/repos/user_setting_repo.dart @@ -0,0 +1,24 @@ +import 'package:dartz/dartz.dart'; +import 'package:flowy_sdk/dispatch/dispatch.dart'; +import 'package:flowy_sdk/flowy_sdk.dart'; +import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-user-data-model/user_setting.pb.dart'; + +class UserSettingReppsitory { + Future getAppearanceSettings() async { + final result = await UserEventGetAppearanceSetting().send(); + + return result.fold( + (AppearanceSettings setting) { + return setting; + }, + (error) { + throw FlowySDKException(ExceptionType.AppearanceSettingsIsEmpty); + }, + ); + } + + Future> setAppearanceSettings(AppearanceSettings settings) { + return UserEventSetAppearanceSetting(settings).send(); + } +} diff --git a/frontend/app_flowy/lib/workspace/application/appearance.dart b/frontend/app_flowy/lib/workspace/application/appearance.dart new file mode 100644 index 0000000000..0a53d50094 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/appearance.dart @@ -0,0 +1,37 @@ +import 'package:app_flowy/user/infrastructure/repos/user_setting_repo.dart'; +import 'package:equatable/equatable.dart'; +import 'package:flowy_infra/theme.dart'; +import 'package:flowy_sdk/protobuf/flowy-user-data-model/user_setting.pb.dart'; +import 'package:flutter/material.dart'; + +class AppearanceSettingModel extends ChangeNotifier with EquatableMixin { + AppearanceSettings setting; + AppTheme _theme; + + AppearanceSettingModel(this.setting) : _theme = AppTheme.fromName(name: setting.theme); + AppTheme get theme => _theme; + + Future save() async { + await UserSettingReppsitory().setAppearanceSettings(setting); + } + + @override + List get props { + return [setting.hashCode]; + } + + void swapTheme() { + final themeType = (_theme.ty == ThemeType.light ? ThemeType.dark : ThemeType.light); + + if (_theme.ty != themeType) { + _theme = AppTheme.fromType(themeType); + setting.theme = themeTypeToString(themeType); + notifyListeners(); + save(); + } + } + + void setLanguage(String language) { + // TODO: save the language settings + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/settings/widgets/settings_appearance_view.dart b/frontend/app_flowy/lib/workspace/presentation/settings/widgets/settings_appearance_view.dart index 6cfe8ed62d..9b42a0437b 100644 --- a/frontend/app_flowy/lib/workspace/presentation/settings/widgets/settings_appearance_view.dart +++ b/frontend/app_flowy/lib/workspace/presentation/settings/widgets/settings_appearance_view.dart @@ -1,5 +1,5 @@ import 'package:app_flowy/generated/locale_keys.g.dart'; -import 'package:app_flowy/workspace/presentation/theme/theme_model.dart'; +import 'package:app_flowy/workspace/application/appearance.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flowy_infra/theme.dart'; import 'package:flutter/material.dart'; @@ -31,7 +31,7 @@ class SettingsAppearanceView extends StatelessWidget { Switch( value: theme.isDark, onChanged: (val) { - context.read().swapTheme(); + context.read().swapTheme(); }, ), Text( diff --git a/frontend/app_flowy/lib/workspace/presentation/theme/theme_model.dart b/frontend/app_flowy/lib/workspace/presentation/theme/theme_model.dart deleted file mode 100644 index 9853897325..0000000000 --- a/frontend/app_flowy/lib/workspace/presentation/theme/theme_model.dart +++ /dev/null @@ -1,25 +0,0 @@ -import 'package:equatable/equatable.dart'; -import 'package:flowy_infra/theme.dart'; -import 'package:flutter/material.dart'; - -class ThemeModel extends ChangeNotifier with EquatableMixin { - ThemeType _theme = ThemeType.light; - - @override - List get props { - return [_theme]; - } - - ThemeType get theme => _theme; - - set theme(ThemeType value) { - if (_theme != value) { - _theme = value; - notifyListeners(); - } - } - - void swapTheme() { - theme = (theme == ThemeType.light ? ThemeType.dark : ThemeType.light); - } -} diff --git a/frontend/app_flowy/packages/flowy_infra/lib/theme.dart b/frontend/app_flowy/packages/flowy_infra/lib/theme.dart index bb7f91916a..97f65e9e4b 100644 --- a/frontend/app_flowy/packages/flowy_infra/lib/theme.dart +++ b/frontend/app_flowy/packages/flowy_infra/lib/theme.dart @@ -6,14 +6,30 @@ enum ThemeType { dark, } +ThemeType themeTypeFromString(String name) { + ThemeType themeType = ThemeType.light; + if (name == "dark") { + themeType = ThemeType.dark; + } + return themeType; +} + +String themeTypeToString(ThemeType ty) { + switch (ty) { + case ThemeType.light: + return "light"; + case ThemeType.dark: + return "dark"; + } +} + //Color Pallettes const _black = Color(0xff000000); const _grey = Color(0xff808080); const _white = Color(0xFFFFFFFF); class AppTheme { - static ThemeType defaultTheme = ThemeType.light; - + ThemeType ty; bool isDark; late Color surface; // late Color hover; @@ -53,13 +69,17 @@ class AppTheme { late Color shadowColor; /// Default constructor - AppTheme({this.isDark = false}); + AppTheme({required this.ty, this.isDark = false}); + + factory AppTheme.fromName({required String name}) { + return AppTheme.fromType(themeTypeFromString(name)); + } /// fromType factory constructor - factory AppTheme.fromType(ThemeType t) { - switch (t) { + factory AppTheme.fromType(ThemeType themeType) { + switch (themeType) { case ThemeType.light: - return AppTheme(isDark: false) + return AppTheme(ty: themeType, isDark: false) ..surface = Colors.white ..hover = const Color(0xFFe0f8ff) // ..selector = const Color(0xfff2fcff) @@ -93,7 +113,7 @@ class AppTheme { ..shadowColor = _black; case ThemeType.dark: - return AppTheme(isDark: true) + return AppTheme(ty: themeType, isDark: true) ..surface = const Color(0xff292929) ..hover = const Color(0xff1f1f1f) ..selector = const Color(0xff333333) diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/code_gen.dart b/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/code_gen.dart index 7d929e15a9..1029bbfd78 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/code_gen.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/code_gen.dart @@ -536,13 +536,13 @@ class UserEventCheckUser { } } -class UserEventUpdateAppearanceSetting { +class UserEventSetAppearanceSetting { AppearanceSettings request; - UserEventUpdateAppearanceSetting(this.request); + UserEventSetAppearanceSetting(this.request); Future> send() { final request = FFIRequest.create() - ..event = UserEvent.UpdateAppearanceSetting.toString() + ..event = UserEvent.SetAppearanceSetting.toString() ..payload = requestToBytes(this.request); return Dispatch.asyncRequest(request) diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dispatch.dart b/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dispatch.dart index 03bff83a8e..a9255a7e87 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dispatch.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dispatch.dart @@ -26,6 +26,7 @@ import 'package:flowy_sdk/protobuf/flowy-collaboration/protobuf.dart'; import 'package:flowy_sdk/protobuf/lib-infra/protobuf.dart'; import 'package:protobuf/protobuf.dart'; import 'dart:convert' show utf8; +import '../protobuf/flowy-user-data-model/user_setting.pb.dart'; import 'error.dart'; part 'code_gen.dart'; diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/flowy_sdk.dart b/frontend/app_flowy/packages/flowy_sdk/lib/flowy_sdk.dart index ff386f2bf7..f6f34113cf 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/flowy_sdk.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/flowy_sdk.dart @@ -7,6 +7,15 @@ import 'dart:ffi'; import 'ffi.dart' as ffi; import 'package:ffi/ffi.dart'; +enum ExceptionType { + AppearanceSettingsIsEmpty, +} + +class FlowySDKException implements Exception { + ExceptionType type; + FlowySDKException(this.type); +} + class FlowySDK { static const MethodChannel _channel = MethodChannel('flowy_sdk'); static Future get platformVersion async { diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/event_map.pbenum.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/event_map.pbenum.dart index eb527f71cb..b3c597bebb 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/event_map.pbenum.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/event_map.pbenum.dart @@ -17,7 +17,7 @@ class UserEvent extends $pb.ProtobufEnum { static const UserEvent UpdateUser = UserEvent._(4, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UpdateUser'); static const UserEvent GetUserProfile = UserEvent._(5, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetUserProfile'); static const UserEvent CheckUser = UserEvent._(6, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'CheckUser'); - static const UserEvent UpdateAppearanceSetting = UserEvent._(7, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UpdateAppearanceSetting'); + static const UserEvent SetAppearanceSetting = UserEvent._(7, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'SetAppearanceSetting'); static const UserEvent GetAppearanceSetting = UserEvent._(8, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetAppearanceSetting'); static const $core.List values = [ @@ -28,7 +28,7 @@ class UserEvent extends $pb.ProtobufEnum { UpdateUser, GetUserProfile, CheckUser, - UpdateAppearanceSetting, + SetAppearanceSetting, GetAppearanceSetting, ]; diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/event_map.pbjson.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/event_map.pbjson.dart index 29eac1bfc6..04e776effc 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/event_map.pbjson.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/event_map.pbjson.dart @@ -19,10 +19,10 @@ const UserEvent$json = const { const {'1': 'UpdateUser', '2': 4}, const {'1': 'GetUserProfile', '2': 5}, const {'1': 'CheckUser', '2': 6}, - const {'1': 'UpdateAppearanceSetting', '2': 7}, + const {'1': 'SetAppearanceSetting', '2': 7}, const {'1': 'GetAppearanceSetting', '2': 8}, ], }; /// Descriptor for `UserEvent`. Decode as a `google.protobuf.EnumDescriptorProto`. -final $typed_data.Uint8List userEventDescriptor = $convert.base64Decode('CglVc2VyRXZlbnQSDAoISW5pdFVzZXIQABIKCgZTaWduSW4QARIKCgZTaWduVXAQAhILCgdTaWduT3V0EAMSDgoKVXBkYXRlVXNlchAEEhIKDkdldFVzZXJQcm9maWxlEAUSDQoJQ2hlY2tVc2VyEAYSGwoXVXBkYXRlQXBwZWFyYW5jZVNldHRpbmcQBxIYChRHZXRBcHBlYXJhbmNlU2V0dGluZxAI'); +final $typed_data.Uint8List userEventDescriptor = $convert.base64Decode('CglVc2VyRXZlbnQSDAoISW5pdFVzZXIQABIKCgZTaWduSW4QARIKCgZTaWduVXAQAhILCgdTaWduT3V0EAMSDgoKVXBkYXRlVXNlchAEEhIKDkdldFVzZXJQcm9maWxlEAUSDQoJQ2hlY2tVc2VyEAYSGAoUU2V0QXBwZWFyYW5jZVNldHRpbmcQBxIYChRHZXRBcHBlYXJhbmNlU2V0dGluZxAI'); diff --git a/frontend/app_flowy/pubspec.lock b/frontend/app_flowy/pubspec.lock index 8f8bcb543c..e00e5ccb9f 100644 --- a/frontend/app_flowy/pubspec.lock +++ b/frontend/app_flowy/pubspec.lock @@ -688,6 +688,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.12.11" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.2" meta: dependency: transitive description: @@ -1077,7 +1084,7 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.4.3" + version: "0.4.8" textstyle_extensions: dependency: transitive description: diff --git a/frontend/rust-lib/flowy-user/src/event_map.rs b/frontend/rust-lib/flowy-user/src/event_map.rs index 97d45f3a4d..c0eb97e845 100644 --- a/frontend/rust-lib/flowy-user/src/event_map.rs +++ b/frontend/rust-lib/flowy-user/src/event_map.rs @@ -17,7 +17,7 @@ pub fn create(user_session: Arc) -> Module { .event(UserEvent::SignOut, sign_out) .event(UserEvent::UpdateUser, update_user_handler) .event(UserEvent::CheckUser, check_user_handler) - .event(UserEvent::UpdateAppearanceSetting, update_appearance_setting) + .event(UserEvent::SetAppearanceSetting, set_appearance_setting) .event(UserEvent::GetAppearanceSetting, get_appearance_setting) } @@ -58,7 +58,7 @@ pub enum UserEvent { CheckUser = 6, #[event(input = "AppearanceSettings")] - UpdateAppearanceSetting = 7, + SetAppearanceSetting = 7, #[event(output = "AppearanceSettings")] GetAppearanceSetting = 8, diff --git a/frontend/rust-lib/flowy-user/src/handlers/user_handler.rs b/frontend/rust-lib/flowy-user/src/handlers/user_handler.rs index da2b12bbe0..933d5b1fd5 100644 --- a/frontend/rust-lib/flowy-user/src/handlers/user_handler.rs +++ b/frontend/rust-lib/flowy-user/src/handlers/user_handler.rs @@ -44,7 +44,7 @@ pub async fn update_user_handler( const APPEARANCE_SETTING_CACHE_KEY: &str = "appearance_settings"; #[tracing::instrument(skip(data), err)] -pub async fn update_appearance_setting(data: Data) -> Result<(), FlowyError> { +pub async fn set_appearance_setting(data: Data) -> Result<(), FlowyError> { let mut setting = data.into_inner(); if setting.theme.is_empty() { setting.theme = APPEARANCE_DEFAULT_THEME.to_string(); diff --git a/frontend/rust-lib/flowy-user/src/protobuf/model/event_map.rs b/frontend/rust-lib/flowy-user/src/protobuf/model/event_map.rs index 318a599732..f9151d58e5 100644 --- a/frontend/rust-lib/flowy-user/src/protobuf/model/event_map.rs +++ b/frontend/rust-lib/flowy-user/src/protobuf/model/event_map.rs @@ -32,7 +32,7 @@ pub enum UserEvent { UpdateUser = 4, GetUserProfile = 5, CheckUser = 6, - UpdateAppearanceSetting = 7, + SetAppearanceSetting = 7, GetAppearanceSetting = 8, } @@ -50,7 +50,7 @@ impl ::protobuf::ProtobufEnum for UserEvent { 4 => ::std::option::Option::Some(UserEvent::UpdateUser), 5 => ::std::option::Option::Some(UserEvent::GetUserProfile), 6 => ::std::option::Option::Some(UserEvent::CheckUser), - 7 => ::std::option::Option::Some(UserEvent::UpdateAppearanceSetting), + 7 => ::std::option::Option::Some(UserEvent::SetAppearanceSetting), 8 => ::std::option::Option::Some(UserEvent::GetAppearanceSetting), _ => ::std::option::Option::None } @@ -65,7 +65,7 @@ impl ::protobuf::ProtobufEnum for UserEvent { UserEvent::UpdateUser, UserEvent::GetUserProfile, UserEvent::CheckUser, - UserEvent::UpdateAppearanceSetting, + UserEvent::SetAppearanceSetting, UserEvent::GetAppearanceSetting, ]; values @@ -95,10 +95,10 @@ impl ::protobuf::reflect::ProtobufValue for UserEvent { } static file_descriptor_proto_data: &'static [u8] = b"\ - \n\x0fevent_map.proto*\xa8\x01\n\tUserEvent\x12\x0c\n\x08InitUser\x10\0\ + \n\x0fevent_map.proto*\xa5\x01\n\tUserEvent\x12\x0c\n\x08InitUser\x10\0\ \x12\n\n\x06SignIn\x10\x01\x12\n\n\x06SignUp\x10\x02\x12\x0b\n\x07SignOu\ t\x10\x03\x12\x0e\n\nUpdateUser\x10\x04\x12\x12\n\x0eGetUserProfile\x10\ - \x05\x12\r\n\tCheckUser\x10\x06\x12\x1b\n\x17UpdateAppearanceSetting\x10\ + \x05\x12\r\n\tCheckUser\x10\x06\x12\x18\n\x14SetAppearanceSetting\x10\ \x07\x12\x18\n\x14GetAppearanceSetting\x10\x08J\x9b\x03\n\x06\x12\x04\0\ \0\x0c\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\x02\x05\0\x12\x04\x02\0\ \x0c\x01\n\n\n\x03\x05\0\x01\x12\x03\x02\x05\x0e\n\x0b\n\x04\x05\0\x02\0\ @@ -116,8 +116,8 @@ static file_descriptor_proto_data: &'static [u8] = b"\ \x04\x12\n\x0c\n\x05\x05\0\x02\x05\x02\x12\x03\x08\x15\x16\n\x0b\n\x04\ \x05\0\x02\x06\x12\x03\t\x04\x12\n\x0c\n\x05\x05\0\x02\x06\x01\x12\x03\t\ \x04\r\n\x0c\n\x05\x05\0\x02\x06\x02\x12\x03\t\x10\x11\n\x0b\n\x04\x05\0\ - \x02\x07\x12\x03\n\x04\x20\n\x0c\n\x05\x05\0\x02\x07\x01\x12\x03\n\x04\ - \x1b\n\x0c\n\x05\x05\0\x02\x07\x02\x12\x03\n\x1e\x1f\n\x0b\n\x04\x05\0\ + \x02\x07\x12\x03\n\x04\x1d\n\x0c\n\x05\x05\0\x02\x07\x01\x12\x03\n\x04\ + \x18\n\x0c\n\x05\x05\0\x02\x07\x02\x12\x03\n\x1b\x1c\n\x0b\n\x04\x05\0\ \x02\x08\x12\x03\x0b\x04\x1d\n\x0c\n\x05\x05\0\x02\x08\x01\x12\x03\x0b\ \x04\x18\n\x0c\n\x05\x05\0\x02\x08\x02\x12\x03\x0b\x1b\x1cb\x06proto3\ "; diff --git a/frontend/rust-lib/flowy-user/src/protobuf/proto/event_map.proto b/frontend/rust-lib/flowy-user/src/protobuf/proto/event_map.proto index 78e4675557..581f710cb2 100644 --- a/frontend/rust-lib/flowy-user/src/protobuf/proto/event_map.proto +++ b/frontend/rust-lib/flowy-user/src/protobuf/proto/event_map.proto @@ -8,6 +8,6 @@ enum UserEvent { UpdateUser = 4; GetUserProfile = 5; CheckUser = 6; - UpdateAppearanceSetting = 7; + SetAppearanceSetting = 7; GetAppearanceSetting = 8; } diff --git a/shared-lib/flowy-user-data-model/src/entities/user_setting.rs b/shared-lib/flowy-user-data-model/src/entities/user_setting.rs index c4f9655dc3..86bcd2a72b 100644 --- a/shared-lib/flowy-user-data-model/src/entities/user_setting.rs +++ b/shared-lib/flowy-user-data-model/src/entities/user_setting.rs @@ -19,7 +19,7 @@ pub struct AppearanceSettings { pub language: String, } -pub const APPEARANCE_DEFAULT_THEME: &str = "light"; +pub const APPEARANCE_DEFAULT_THEME: &str = "dark"; pub const APPEARANCE_DEFAULT_LANGUAGE: &str = "en"; impl std::default::Default for AppearanceSettings {