|
1 | 1 | import 'package:flutter/material.dart';
|
2 | 2 | import 'package:flutter_bloc/flutter_bloc.dart';
|
| 3 | +import 'package:go_router/go_router.dart'; |
3 | 4 | import 'package:ht_main/l10n/l10n.dart';
|
| 5 | +import 'package:ht_main/router/routes.dart'; |
4 | 6 | import 'package:ht_main/settings/bloc/settings_bloc.dart';
|
5 |
| -import 'package:ht_main/shared/constants/constants.dart'; |
6 |
| -import 'package:ht_shared/ht_shared.dart'; // Use types from ht_shared |
| 7 | +import 'package:ht_main/shared/constants/app_spacing.dart'; |
7 | 8 |
|
8 | 9 | /// {@template appearance_settings_page}
|
9 |
| -/// A page for configuring appearance-related settings like theme and fonts. |
| 10 | +/// A menu page for navigating to theme and font appearance settings. |
10 | 11 | /// {@endtemplate}
|
11 | 12 | class AppearanceSettingsPage extends StatelessWidget {
|
12 | 13 | /// {@macro appearance_settings_page}
|
13 | 14 | const AppearanceSettingsPage({super.key});
|
14 | 15 |
|
15 |
| - // Helper to map AppBaseTheme enum to user-friendly strings |
16 |
| - String _baseThemeToString(AppBaseTheme mode, AppLocalizations l10n) { |
17 |
| - switch (mode) { |
18 |
| - case AppBaseTheme.light: |
19 |
| - return l10n.settingsAppearanceThemeModeLight; |
20 |
| - case AppBaseTheme.dark: |
21 |
| - return l10n.settingsAppearanceThemeModeDark; |
22 |
| - case AppBaseTheme.system: |
23 |
| - return l10n.settingsAppearanceThemeModeSystem; |
24 |
| - } |
25 |
| - } |
26 |
| - |
27 |
| - // Helper to map AppAccentTheme enum to user-friendly strings |
28 |
| - String _accentThemeToString(AppAccentTheme name, AppLocalizations l10n) { |
29 |
| - switch (name) { |
30 |
| - case AppAccentTheme.newsRed: |
31 |
| - return l10n.settingsAppearanceThemeNameRed; |
32 |
| - case AppAccentTheme.defaultBlue: |
33 |
| - return l10n.settingsAppearanceThemeNameBlue; |
34 |
| - case AppAccentTheme.graphiteGray: |
35 |
| - return l10n.settingsAppearanceThemeNameGrey; |
36 |
| - } |
37 |
| - } |
38 |
| - |
39 |
| - // Helper to map AppTextScaleFactor enum to user-friendly strings |
40 |
| - String _textScaleFactorToString( |
41 |
| - AppTextScaleFactor size, |
42 |
| - AppLocalizations l10n, |
43 |
| - ) { |
44 |
| - switch (size) { |
45 |
| - case AppTextScaleFactor.small: |
46 |
| - return l10n.settingsAppearanceFontSizeSmall; |
47 |
| - case AppTextScaleFactor.large: |
48 |
| - return l10n.settingsAppearanceFontSizeLarge; |
49 |
| - case AppTextScaleFactor.medium: |
50 |
| - return l10n.settingsAppearanceFontSizeMedium; |
51 |
| - case AppTextScaleFactor.extraLarge: |
52 |
| - return l10n.settingsAppearanceFontSizeExtraLarge; // Add l10n key |
53 |
| - } |
54 |
| - } |
55 |
| - |
56 |
| - // Helper to map font family string to user-friendly strings |
57 |
| - String _fontFamilyToString(String fontFamily, AppLocalizations l10n) { |
58 |
| - // This mapping might need to be more sophisticated if supporting multiple |
59 |
| - // specific fonts. For now, just return the string or a placeholder. |
60 |
| - // Consider adding specific l10n keys if needed, e.g., l10n.fontRoboto |
61 |
| - return fontFamily == 'SystemDefault' |
62 |
| - ? l10n |
63 |
| - .settingsAppearanceFontFamilySystemDefault // Add l10n key |
64 |
| - : fontFamily; |
65 |
| - } |
66 |
| - |
67 |
| - // TODO(cline): Replace with localized strings once localization issue is resolved. |
68 |
| - // Helper to map AppFontWeight enum to user-friendly strings (currently uses enum name) |
69 |
| - String _fontWeightToString(AppFontWeight weight, AppLocalizations l10n) { |
70 |
| - switch (weight) { |
71 |
| - case AppFontWeight.light: |
72 |
| - return 'Light'; // Temporary: Use enum name or placeholder |
73 |
| - case AppFontWeight.regular: |
74 |
| - return 'Regular'; // Temporary: Use enum name or placeholder |
75 |
| - case AppFontWeight.bold: |
76 |
| - return 'Bold'; // Temporary: Use enum name or placeholder |
77 |
| - } |
78 |
| - } |
79 |
| - |
80 | 16 | @override
|
81 | 17 | Widget build(BuildContext context) {
|
82 | 18 | final l10n = context.l10n;
|
83 |
| - final settingsBloc = context.watch<SettingsBloc>(); |
84 |
| - final state = settingsBloc.state; |
| 19 | + // SettingsBloc is watched to ensure settings are loaded, |
| 20 | + // though this page itself doesn't dispatch events. |
| 21 | + final settingsState = context.watch<SettingsBloc>().state; |
85 | 22 |
|
86 |
| - // Ensure we have loaded state before building controls |
87 |
| - if (state.status != SettingsStatus.success) { |
88 |
| - // Can show a minimal loading/error or rely on parent page handling |
| 23 | + if (settingsState.status != SettingsStatus.success) { |
89 | 24 | return Scaffold(
|
90 | 25 | appBar: AppBar(title: Text(l10n.settingsAppearanceTitle)),
|
91 |
| - body: const Center( |
92 |
| - child: CircularProgressIndicator(), |
93 |
| - ), // Simple loading |
| 26 | + body: const Center(child: CircularProgressIndicator()), |
94 | 27 | );
|
95 | 28 | }
|
96 | 29 |
|
97 | 30 | return Scaffold(
|
98 | 31 | appBar: AppBar(title: Text(l10n.settingsAppearanceTitle)),
|
99 | 32 | body: ListView(
|
100 |
| - padding: const EdgeInsets.all(AppSpacing.lg), |
| 33 | + padding: const EdgeInsets.symmetric(vertical: AppSpacing.md), |
101 | 34 | children: [
|
102 |
| - // --- Base Theme --- |
103 |
| - _buildDropdownSetting<AppBaseTheme>( |
104 |
| - context: context, |
105 |
| - title: l10n.settingsAppearanceThemeModeLabel, |
106 |
| - currentValue: state.userAppSettings!.displaySettings.baseTheme, |
107 |
| - items: AppBaseTheme.values, |
108 |
| - itemToString: (mode) => _baseThemeToString(mode, l10n), |
109 |
| - onChanged: (value) { |
110 |
| - if (value != null) { |
111 |
| - settingsBloc.add(SettingsAppThemeModeChanged(value)); |
112 |
| - } |
| 35 | + ListTile( |
| 36 | + leading: const Icon(Icons.color_lens_outlined), |
| 37 | + title: Text(l10n.settingsAppearanceTitle), // Placeholder: "Appearance Settings" |
| 38 | + trailing: const Icon(Icons.chevron_right), |
| 39 | + onTap: () { |
| 40 | + context.goNamed(Routes.settingsAppearanceThemeName); |
113 | 41 | },
|
114 | 42 | ),
|
115 |
| - const SizedBox(height: AppSpacing.lg), |
116 |
| - |
117 |
| - // --- Accent Theme --- |
118 |
| - _buildDropdownSetting<AppAccentTheme>( |
119 |
| - context: context, |
120 |
| - title: l10n.settingsAppearanceThemeNameLabel, |
121 |
| - currentValue: state.userAppSettings!.displaySettings.accentTheme, |
122 |
| - items: AppAccentTheme.values, |
123 |
| - itemToString: (name) => _accentThemeToString(name, l10n), |
124 |
| - onChanged: (value) { |
125 |
| - if (value != null) { |
126 |
| - context.read<SettingsBloc>().add( |
127 |
| - SettingsAppThemeNameChanged(value), |
128 |
| - ); |
129 |
| - } |
130 |
| - }, |
131 |
| - ), |
132 |
| - const SizedBox(height: AppSpacing.lg), |
133 |
| - |
134 |
| - // --- Text Scale Factor --- |
135 |
| - _buildDropdownSetting<AppTextScaleFactor>( |
136 |
| - context: context, |
137 |
| - title: |
138 |
| - l10n.settingsAppearanceAppFontSizeLabel, // Reusing key for text size |
139 |
| - currentValue: |
140 |
| - state.userAppSettings!.displaySettings.textScaleFactor, |
141 |
| - items: AppTextScaleFactor.values, |
142 |
| - itemToString: (size) => _textScaleFactorToString(size, l10n), |
143 |
| - onChanged: (value) { |
144 |
| - if (value != null) { |
145 |
| - context.read<SettingsBloc>().add( |
146 |
| - SettingsAppFontSizeChanged(value), |
147 |
| - ); |
148 |
| - } |
149 |
| - }, |
150 |
| - ), |
151 |
| - const SizedBox(height: AppSpacing.lg), |
152 |
| - |
153 |
| - // --- Font Family --- |
154 |
| - _buildDropdownSetting<String>( |
155 |
| - // Font family is a String |
156 |
| - context: context, |
157 |
| - title: |
158 |
| - l10n.settingsAppearanceAppFontTypeLabel, // Reusing key for font family |
159 |
| - currentValue: state.userAppSettings!.displaySettings.fontFamily, |
160 |
| - items: const [ |
161 |
| - 'SystemDefault', |
162 |
| - ], // Only SystemDefault supported for now |
163 |
| - itemToString: (fontFamily) => _fontFamilyToString(fontFamily, l10n), |
164 |
| - onChanged: (value) { |
165 |
| - if (value != null) { |
166 |
| - context.read<SettingsBloc>().add( |
167 |
| - SettingsAppFontTypeChanged(value), |
168 |
| - ); |
169 |
| - } |
170 |
| - }, |
171 |
| - ), |
172 |
| - const SizedBox(height: AppSpacing.lg), |
173 |
| - |
174 |
| - // --- Font Weight --- |
175 |
| - _buildDropdownSetting<AppFontWeight>( |
176 |
| - context: context, |
177 |
| - title: l10n.settingsAppearanceFontWeightLabel, // Add l10n key |
178 |
| - currentValue: state.userAppSettings!.displaySettings.fontWeight, |
179 |
| - items: AppFontWeight.values, |
180 |
| - itemToString: |
181 |
| - (weight) => _fontWeightToString(weight, l10n), // Use helper |
182 |
| - onChanged: (value) { |
183 |
| - if (value != null) { |
184 |
| - settingsBloc.add(SettingsAppFontWeightChanged(value)); |
185 |
| - } |
| 43 | + const Divider(indent: AppSpacing.lg, endIndent: AppSpacing.lg), |
| 44 | + ListTile( |
| 45 | + leading: const Icon(Icons.font_download_outlined), |
| 46 | + title: Text(l10n.settingsAppearanceTitle), // Placeholder: "Appearance Settings" |
| 47 | + trailing: const Icon(Icons.chevron_right), |
| 48 | + onTap: () { |
| 49 | + context.goNamed(Routes.settingsAppearanceFontName); |
186 | 50 | },
|
187 | 51 | ),
|
188 | 52 | ],
|
189 | 53 | ),
|
190 | 54 | );
|
191 | 55 | }
|
192 |
| - |
193 |
| - /// Generic helper to build a setting row with a title and a dropdown. |
194 |
| - Widget _buildDropdownSetting<T>({ |
195 |
| - required BuildContext context, |
196 |
| - required String title, |
197 |
| - required T currentValue, |
198 |
| - required List<T> items, |
199 |
| - required String Function(T) itemToString, |
200 |
| - required ValueChanged<T?> onChanged, |
201 |
| - }) { |
202 |
| - final textTheme = Theme.of(context).textTheme; |
203 |
| - return Column( |
204 |
| - crossAxisAlignment: CrossAxisAlignment.start, |
205 |
| - children: [ |
206 |
| - Text(title, style: textTheme.titleMedium), |
207 |
| - const SizedBox(height: AppSpacing.sm), |
208 |
| - DropdownButtonFormField<T>( |
209 |
| - value: currentValue, |
210 |
| - items: |
211 |
| - items.map((T value) { |
212 |
| - return DropdownMenuItem<T>( |
213 |
| - value: value, |
214 |
| - child: Text(itemToString(value)), |
215 |
| - ); |
216 |
| - }).toList(), |
217 |
| - onChanged: onChanged, |
218 |
| - decoration: const InputDecoration( |
219 |
| - border: OutlineInputBorder(), |
220 |
| - contentPadding: EdgeInsets.symmetric( |
221 |
| - horizontal: AppSpacing.md, |
222 |
| - vertical: AppSpacing.sm, |
223 |
| - ), |
224 |
| - ), |
225 |
| - ), |
226 |
| - ], |
227 |
| - ); |
228 |
| - } |
229 | 56 | }
|
0 commit comments