From dcb070909c93b8ef39e8fa841c551a91da1123e9 Mon Sep 17 00:00:00 2001 From: "Lucas.Xu" Date: Tue, 9 Jan 2024 09:12:54 +0700 Subject: [PATCH] feat: support RTL layout on mobile (#4335) * feat: revamp theme mode settings * feat: support RTL layout on mobile --- .../appearance/appearance_setting_group.dart | 2 + .../setting/appearance/rtl_setting.dart | 83 ++++++++++++++++++ .../setting/appearance/theme_setting.dart | 85 ++++++++----------- frontend/resources/translations/en.json | 2 +- 4 files changed, 122 insertions(+), 50 deletions(-) create mode 100644 frontend/appflowy_flutter/lib/mobile/presentation/setting/appearance/rtl_setting.dart diff --git a/frontend/appflowy_flutter/lib/mobile/presentation/setting/appearance/appearance_setting_group.dart b/frontend/appflowy_flutter/lib/mobile/presentation/setting/appearance/appearance_setting_group.dart index c693425e5b..e926822fd4 100644 --- a/frontend/appflowy_flutter/lib/mobile/presentation/setting/appearance/appearance_setting_group.dart +++ b/frontend/appflowy_flutter/lib/mobile/presentation/setting/appearance/appearance_setting_group.dart @@ -1,4 +1,5 @@ import 'package:appflowy/generated/locale_keys.g.dart'; +import 'package:appflowy/mobile/presentation/setting/appearance/rtl_setting.dart'; import 'package:appflowy/mobile/presentation/setting/appearance/theme_setting.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; @@ -17,6 +18,7 @@ class AppearanceSettingGroup extends StatelessWidget { settingItemList: const [ ThemeSetting(), FontSetting(), + RTLSetting(), ], ); } diff --git a/frontend/appflowy_flutter/lib/mobile/presentation/setting/appearance/rtl_setting.dart b/frontend/appflowy_flutter/lib/mobile/presentation/setting/appearance/rtl_setting.dart new file mode 100644 index 0000000000..5dcd708457 --- /dev/null +++ b/frontend/appflowy_flutter/lib/mobile/presentation/setting/appearance/rtl_setting.dart @@ -0,0 +1,83 @@ +import 'package:appflowy/generated/locale_keys.g.dart'; +import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart'; +import 'package:appflowy/mobile/presentation/widgets/widgets.dart'; +import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flowy_infra_ui/flowy_infra_ui.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +import '../setting.dart'; + +class RTLSetting extends StatelessWidget { + const RTLSetting({ + super.key, + }); + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + final layoutDirection = + context.watch().state.layoutDirection; + return MobileSettingItem( + name: LocaleKeys.settings_appearance_textDirection_label.tr(), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + FlowyText( + _textDirectionLabelText(layoutDirection), + color: theme.colorScheme.onSurface, + ), + const Icon(Icons.chevron_right), + ], + ), + onTap: () { + showMobileBottomSheet( + context, + showHeader: true, + showDragHandle: true, + showDivider: false, + showCloseButton: false, + title: LocaleKeys.settings_appearance_textDirection_label.tr(), + padding: const EdgeInsets.fromLTRB(0, 8, 0, 48), + builder: (context) { + final layoutDirection = + context.watch().state.layoutDirection; + return Padding( + padding: const EdgeInsets.only(top: 10), + child: Column( + children: [ + FlowyOptionTile.checkbox( + text: LocaleKeys.settings_appearance_textDirection_ltr.tr(), + isSelected: layoutDirection == LayoutDirection.ltrLayout, + onTap: () => context + .read() + .setLayoutDirection(LayoutDirection.ltrLayout), + ), + FlowyOptionTile.checkbox( + showTopBorder: false, + text: LocaleKeys.settings_appearance_textDirection_rtl.tr(), + isSelected: layoutDirection == LayoutDirection.rtlLayout, + onTap: () => context + .read() + .setLayoutDirection(LayoutDirection.rtlLayout), + ), + ], + ), + ); + }, + ); + }, + ); + } + + String _textDirectionLabelText(LayoutDirection? textDirection) { + switch (textDirection) { + case LayoutDirection.rtlLayout: + return LocaleKeys.settings_appearance_textDirection_rtl.tr(); + case LayoutDirection.ltrLayout: + default: + return LocaleKeys.settings_appearance_textDirection_ltr.tr(); + } + } +} diff --git a/frontend/appflowy_flutter/lib/mobile/presentation/setting/appearance/theme_setting.dart b/frontend/appflowy_flutter/lib/mobile/presentation/setting/appearance/theme_setting.dart index 5e7d1e0d48..f897391003 100644 --- a/frontend/appflowy_flutter/lib/mobile/presentation/setting/appearance/theme_setting.dart +++ b/frontend/appflowy_flutter/lib/mobile/presentation/setting/appearance/theme_setting.dart @@ -1,5 +1,6 @@ import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart'; +import 'package:appflowy/mobile/presentation/widgets/widgets.dart'; import 'package:appflowy/util/theme_mode_extension.dart'; import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart'; import 'package:easy_localization/easy_localization.dart'; @@ -34,26 +35,43 @@ class ThemeSetting extends StatelessWidget { showMobileBottomSheet( context, showHeader: true, - showCloseButton: true, showDragHandle: true, + showDivider: false, + showCloseButton: false, title: LocaleKeys.settings_appearance_themeMode_label.tr(), - padding: const EdgeInsets.fromLTRB(16, 0, 16, 32), - builder: (_) { - return Column( - children: [ - _ThemeModeRadioListTile( - title: LocaleKeys.settings_appearance_themeMode_system.tr(), - value: ThemeMode.system, - ), - _ThemeModeRadioListTile( - title: LocaleKeys.settings_appearance_themeMode_light.tr(), - value: ThemeMode.light, - ), - _ThemeModeRadioListTile( - title: LocaleKeys.settings_appearance_themeMode_dark.tr(), - value: ThemeMode.dark, - ), - ], + padding: const EdgeInsets.fromLTRB(0, 8, 0, 48), + builder: (context) { + final themeMode = + context.read().state.themeMode; + return Padding( + padding: const EdgeInsets.only(top: 10), + child: Column( + children: [ + FlowyOptionTile.checkbox( + text: LocaleKeys.settings_appearance_themeMode_system.tr(), + isSelected: themeMode == ThemeMode.system, + onTap: () => context + .read() + .setThemeMode(ThemeMode.system), + ), + FlowyOptionTile.checkbox( + showTopBorder: false, + text: LocaleKeys.settings_appearance_themeMode_light.tr(), + isSelected: themeMode == ThemeMode.light, + onTap: () => context + .read() + .setThemeMode(ThemeMode.light), + ), + FlowyOptionTile.checkbox( + showTopBorder: false, + text: LocaleKeys.settings_appearance_themeMode_dark.tr(), + isSelected: themeMode == ThemeMode.dark, + onTap: () => context + .read() + .setThemeMode(ThemeMode.dark), + ), + ], + ), ); }, ); @@ -61,34 +79,3 @@ class ThemeSetting extends StatelessWidget { ); } } - -class _ThemeModeRadioListTile extends StatelessWidget { - const _ThemeModeRadioListTile({ - required this.title, - required this.value, - }); - final String title; - final ThemeMode value; - - @override - Widget build(BuildContext context) { - final theme = Theme.of(context); - return RadioListTile( - dense: true, - contentPadding: const EdgeInsets.fromLTRB(0, 0, 4, 0), - controlAffinity: ListTileControlAffinity.trailing, - title: Text( - title, - style: theme.textTheme.bodyMedium?.copyWith( - color: theme.colorScheme.onSurface, - ), - ), - groupValue: context.read().state.themeMode, - value: value, - onChanged: (selectedThemeMode) { - if (selectedThemeMode == null) return; - context.read().setThemeMode(selectedThemeMode); - }, - ); - } -} diff --git a/frontend/resources/translations/en.json b/frontend/resources/translations/en.json index 65954e3d07..140a4f2774 100644 --- a/frontend/resources/translations/en.json +++ b/frontend/resources/translations/en.json @@ -343,7 +343,7 @@ "rtl": "RTL" }, "textDirection": { - "label": "Default text direction", + "label": "Default Text Direction", "hint": "Specify whether text should start from left or right as the default.", "ltr": "LTR", "rtl": "RTL",