Skip to content

Commit dcb0709

Browse files
authored
feat: support RTL layout on mobile (#4335)
* feat: revamp theme mode settings * feat: support RTL layout on mobile
1 parent 332a677 commit dcb0709

File tree

4 files changed

+122
-50
lines changed

4 files changed

+122
-50
lines changed

frontend/appflowy_flutter/lib/mobile/presentation/setting/appearance/appearance_setting_group.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import 'package:appflowy/generated/locale_keys.g.dart';
2+
import 'package:appflowy/mobile/presentation/setting/appearance/rtl_setting.dart';
23
import 'package:appflowy/mobile/presentation/setting/appearance/theme_setting.dart';
34
import 'package:easy_localization/easy_localization.dart';
45
import 'package:flutter/material.dart';
@@ -17,6 +18,7 @@ class AppearanceSettingGroup extends StatelessWidget {
1718
settingItemList: const [
1819
ThemeSetting(),
1920
FontSetting(),
21+
RTLSetting(),
2022
],
2123
);
2224
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import 'package:appflowy/generated/locale_keys.g.dart';
2+
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart';
3+
import 'package:appflowy/mobile/presentation/widgets/widgets.dart';
4+
import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart';
5+
import 'package:easy_localization/easy_localization.dart';
6+
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
7+
import 'package:flutter/material.dart';
8+
import 'package:flutter_bloc/flutter_bloc.dart';
9+
10+
import '../setting.dart';
11+
12+
class RTLSetting extends StatelessWidget {
13+
const RTLSetting({
14+
super.key,
15+
});
16+
17+
@override
18+
Widget build(BuildContext context) {
19+
final theme = Theme.of(context);
20+
final layoutDirection =
21+
context.watch<AppearanceSettingsCubit>().state.layoutDirection;
22+
return MobileSettingItem(
23+
name: LocaleKeys.settings_appearance_textDirection_label.tr(),
24+
trailing: Row(
25+
mainAxisSize: MainAxisSize.min,
26+
children: [
27+
FlowyText(
28+
_textDirectionLabelText(layoutDirection),
29+
color: theme.colorScheme.onSurface,
30+
),
31+
const Icon(Icons.chevron_right),
32+
],
33+
),
34+
onTap: () {
35+
showMobileBottomSheet(
36+
context,
37+
showHeader: true,
38+
showDragHandle: true,
39+
showDivider: false,
40+
showCloseButton: false,
41+
title: LocaleKeys.settings_appearance_textDirection_label.tr(),
42+
padding: const EdgeInsets.fromLTRB(0, 8, 0, 48),
43+
builder: (context) {
44+
final layoutDirection =
45+
context.watch<AppearanceSettingsCubit>().state.layoutDirection;
46+
return Padding(
47+
padding: const EdgeInsets.only(top: 10),
48+
child: Column(
49+
children: [
50+
FlowyOptionTile.checkbox(
51+
text: LocaleKeys.settings_appearance_textDirection_ltr.tr(),
52+
isSelected: layoutDirection == LayoutDirection.ltrLayout,
53+
onTap: () => context
54+
.read<AppearanceSettingsCubit>()
55+
.setLayoutDirection(LayoutDirection.ltrLayout),
56+
),
57+
FlowyOptionTile.checkbox(
58+
showTopBorder: false,
59+
text: LocaleKeys.settings_appearance_textDirection_rtl.tr(),
60+
isSelected: layoutDirection == LayoutDirection.rtlLayout,
61+
onTap: () => context
62+
.read<AppearanceSettingsCubit>()
63+
.setLayoutDirection(LayoutDirection.rtlLayout),
64+
),
65+
],
66+
),
67+
);
68+
},
69+
);
70+
},
71+
);
72+
}
73+
74+
String _textDirectionLabelText(LayoutDirection? textDirection) {
75+
switch (textDirection) {
76+
case LayoutDirection.rtlLayout:
77+
return LocaleKeys.settings_appearance_textDirection_rtl.tr();
78+
case LayoutDirection.ltrLayout:
79+
default:
80+
return LocaleKeys.settings_appearance_textDirection_ltr.tr();
81+
}
82+
}
83+
}
Lines changed: 36 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import 'package:appflowy/generated/locale_keys.g.dart';
22
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart';
3+
import 'package:appflowy/mobile/presentation/widgets/widgets.dart';
34
import 'package:appflowy/util/theme_mode_extension.dart';
45
import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart';
56
import 'package:easy_localization/easy_localization.dart';
@@ -34,61 +35,47 @@ class ThemeSetting extends StatelessWidget {
3435
showMobileBottomSheet(
3536
context,
3637
showHeader: true,
37-
showCloseButton: true,
3838
showDragHandle: true,
39+
showDivider: false,
40+
showCloseButton: false,
3941
title: LocaleKeys.settings_appearance_themeMode_label.tr(),
40-
padding: const EdgeInsets.fromLTRB(16, 0, 16, 32),
41-
builder: (_) {
42-
return Column(
43-
children: [
44-
_ThemeModeRadioListTile(
45-
title: LocaleKeys.settings_appearance_themeMode_system.tr(),
46-
value: ThemeMode.system,
47-
),
48-
_ThemeModeRadioListTile(
49-
title: LocaleKeys.settings_appearance_themeMode_light.tr(),
50-
value: ThemeMode.light,
51-
),
52-
_ThemeModeRadioListTile(
53-
title: LocaleKeys.settings_appearance_themeMode_dark.tr(),
54-
value: ThemeMode.dark,
55-
),
56-
],
42+
padding: const EdgeInsets.fromLTRB(0, 8, 0, 48),
43+
builder: (context) {
44+
final themeMode =
45+
context.read<AppearanceSettingsCubit>().state.themeMode;
46+
return Padding(
47+
padding: const EdgeInsets.only(top: 10),
48+
child: Column(
49+
children: [
50+
FlowyOptionTile.checkbox(
51+
text: LocaleKeys.settings_appearance_themeMode_system.tr(),
52+
isSelected: themeMode == ThemeMode.system,
53+
onTap: () => context
54+
.read<AppearanceSettingsCubit>()
55+
.setThemeMode(ThemeMode.system),
56+
),
57+
FlowyOptionTile.checkbox(
58+
showTopBorder: false,
59+
text: LocaleKeys.settings_appearance_themeMode_light.tr(),
60+
isSelected: themeMode == ThemeMode.light,
61+
onTap: () => context
62+
.read<AppearanceSettingsCubit>()
63+
.setThemeMode(ThemeMode.light),
64+
),
65+
FlowyOptionTile.checkbox(
66+
showTopBorder: false,
67+
text: LocaleKeys.settings_appearance_themeMode_dark.tr(),
68+
isSelected: themeMode == ThemeMode.dark,
69+
onTap: () => context
70+
.read<AppearanceSettingsCubit>()
71+
.setThemeMode(ThemeMode.dark),
72+
),
73+
],
74+
),
5775
);
5876
},
5977
);
6078
},
6179
);
6280
}
6381
}
64-
65-
class _ThemeModeRadioListTile extends StatelessWidget {
66-
const _ThemeModeRadioListTile({
67-
required this.title,
68-
required this.value,
69-
});
70-
final String title;
71-
final ThemeMode value;
72-
73-
@override
74-
Widget build(BuildContext context) {
75-
final theme = Theme.of(context);
76-
return RadioListTile<ThemeMode>(
77-
dense: true,
78-
contentPadding: const EdgeInsets.fromLTRB(0, 0, 4, 0),
79-
controlAffinity: ListTileControlAffinity.trailing,
80-
title: Text(
81-
title,
82-
style: theme.textTheme.bodyMedium?.copyWith(
83-
color: theme.colorScheme.onSurface,
84-
),
85-
),
86-
groupValue: context.read<AppearanceSettingsCubit>().state.themeMode,
87-
value: value,
88-
onChanged: (selectedThemeMode) {
89-
if (selectedThemeMode == null) return;
90-
context.read<AppearanceSettingsCubit>().setThemeMode(selectedThemeMode);
91-
},
92-
);
93-
}
94-
}

frontend/resources/translations/en.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@
343343
"rtl": "RTL"
344344
},
345345
"textDirection": {
346-
"label": "Default text direction",
346+
"label": "Default Text Direction",
347347
"hint": "Specify whether text should start from left or right as the default.",
348348
"ltr": "LTR",
349349
"rtl": "RTL",

0 commit comments

Comments
 (0)