Skip to content

Commit d5e6ff3

Browse files
authored
feat(cat-voices): theme mode switch (#927)
* feat(cat-voices): theme mode switch * chore: spelling issues * refactor: use voices switch
1 parent face4cf commit d5e6ff3

File tree

11 files changed

+115
-25
lines changed

11 files changed

+115
-25
lines changed

.config/dictionaries/project.dic

+1
Original file line numberDiff line numberDiff line change
@@ -293,3 +293,4 @@ xctestrun
293293
xcworkspace
294294
xvfb
295295
yoroi
296+
appbar

catalyst_voices/lib/app/view/app_content.dart

+26-9
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,30 @@ import 'package:flutter_localized_locales/flutter_localized_locales.dart';
66

77
const _restorationScopeId = 'rootVoices';
88

9-
final class AppContent extends StatelessWidget {
9+
final class AppContent extends StatefulWidget {
1010
final RouterConfig<Object> routerConfig;
1111

1212
const AppContent({
1313
super.key,
1414
required this.routerConfig,
1515
});
1616

17-
List<LocalizationsDelegate<dynamic>> get _localizationsDelegates {
18-
return const [
19-
...VoicesLocalizations.localizationsDelegates,
20-
LocaleNamesLocalizationsDelegate(),
21-
];
17+
@override
18+
State<AppContent> createState() => AppContentState();
19+
20+
/// Returns the state associated with the [AppContent].
21+
static AppContentState of(BuildContext context) {
22+
return context.findAncestorStateOfType<AppContentState>()!;
23+
}
24+
}
25+
26+
class AppContentState extends State<AppContent> {
27+
ThemeMode _themeMode = ThemeMode.light;
28+
29+
void updateThemeMode(ThemeMode themeMode) {
30+
setState(() {
31+
_themeMode = themeMode;
32+
});
2233
}
2334

2435
@override
@@ -28,9 +39,8 @@ final class AppContent extends StatelessWidget {
2839
localizationsDelegates: _localizationsDelegates,
2940
supportedLocales: VoicesLocalizations.supportedLocales,
3041
localeListResolutionCallback: basicLocaleListResolution,
31-
routerConfig: routerConfig,
32-
// Light mode is "go to" for now.
33-
themeMode: ThemeMode.light,
42+
routerConfig: widget.routerConfig,
43+
themeMode: _themeMode,
3444
theme: ThemeBuilder.buildTheme(
3545
brand: Brand.catalyst,
3646
brightness: Brightness.light,
@@ -46,4 +56,11 @@ final class AppContent extends StatelessWidget {
4656
},
4757
);
4858
}
59+
60+
List<LocalizationsDelegate<dynamic>> get _localizationsDelegates {
61+
return const [
62+
...VoicesLocalizations.localizationsDelegates,
63+
LocaleNamesLocalizationsDelegate(),
64+
];
65+
}
4966
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import 'package:catalyst_voices/app/app.dart';
2+
import 'package:catalyst_voices/widgets/widgets.dart';
3+
import 'package:flutter/material.dart';
4+
5+
/// A switch that updates the app theme mode.
6+
class SpacesThemeModeSwitch extends StatelessWidget {
7+
const SpacesThemeModeSwitch({super.key});
8+
9+
@override
10+
Widget build(BuildContext context) {
11+
return VoicesThemeModeSwitch(
12+
onChanged: AppContent.of(context).updateThemeMode,
13+
);
14+
}
15+
}

catalyst_voices/lib/pages/spaces/spaces_shell_page.dart

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import 'package:catalyst_voices/common/ext/ext.dart';
22
import 'package:catalyst_voices/pages/registration/registration_dialog.dart';
3+
import 'package:catalyst_voices/pages/spaces/appbar/spaces_theme_mode_switch.dart';
34
import 'package:catalyst_voices/pages/spaces/drawer/spaces_drawer.dart';
45
import 'package:catalyst_voices/widgets/widgets.dart';
56
import 'package:catalyst_voices_blocs/catalyst_voices_blocs.dart';
@@ -62,6 +63,7 @@ class _SpacesShellPageState extends State<SpacesShellPage> {
6263
leading: isVisitor ? null : const DrawerToggleButton(),
6364
automaticallyImplyLeading: false,
6465
actions: [
66+
const SpacesThemeModeSwitch(),
6567
SessionActionHeader(
6668
onGetStartedTap: _showAccountSetup,
6769
),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import 'package:catalyst_voices/widgets/toggles/voices_switch.dart';
2+
import 'package:catalyst_voices_localization/catalyst_voices_localization.dart';
3+
import 'package:flutter/material.dart';
4+
5+
/// A switch that toggles between light & dark theme mode.
6+
class VoicesThemeModeSwitch extends StatelessWidget {
7+
final ValueChanged<ThemeMode> onChanged;
8+
9+
const VoicesThemeModeSwitch({
10+
super.key,
11+
required this.onChanged,
12+
});
13+
14+
@override
15+
Widget build(BuildContext context) {
16+
return Row(
17+
mainAxisSize: MainAxisSize.min,
18+
children: [
19+
Text('${context.l10n.themeLight} / ${context.l10n.themeDark}'),
20+
const SizedBox(width: 8),
21+
VoicesSwitch(
22+
value: Theme.of(context).brightness == Brightness.dark,
23+
onChanged: (value) {
24+
onChanged(
25+
value ? ThemeMode.dark : ThemeMode.light,
26+
);
27+
},
28+
),
29+
],
30+
);
31+
}
32+
}

catalyst_voices/lib/widgets/widgets.dart

+1
Original file line numberDiff line numberDiff line change
@@ -67,5 +67,6 @@ export 'toggles/voices_checkbox.dart';
6767
export 'toggles/voices_checkbox_group.dart';
6868
export 'toggles/voices_radio.dart';
6969
export 'toggles/voices_switch.dart';
70+
export 'toggles/voices_theme_mode_switch.dart';
7071
export 'tooltips/voices_plain_tooltip.dart';
7172
export 'tooltips/voices_rich_tooltip.dart';

catalyst_voices/packages/catalyst_voices_localization/lib/generated/catalyst_voices_localizations.dart

+12
Original file line numberDiff line numberDiff line change
@@ -1132,6 +1132,18 @@ abstract class VoicesLocalizations {
11321132
/// **'Total'**
11331133
String get total;
11341134

1135+
/// Refers to a light theme mode.
1136+
///
1137+
/// In en, this message translates to:
1138+
/// **'Light'**
1139+
String get themeLight;
1140+
1141+
/// Refers to a dark theme mode.
1142+
///
1143+
/// In en, this message translates to:
1144+
/// **'Dark'**
1145+
String get themeDark;
1146+
11351147
/// A title on keychain deleted dialog
11361148
///
11371149
/// In en, this message translates to:

catalyst_voices/packages/catalyst_voices_localization/lib/generated/catalyst_voices_localizations_en.dart

+6
Original file line numberDiff line numberDiff line change
@@ -601,6 +601,12 @@ class VoicesLocalizationsEn extends VoicesLocalizations {
601601
@override
602602
String get total => 'Total';
603603

604+
@override
605+
String get themeLight => 'Light';
606+
607+
@override
608+
String get themeDark => 'Dark';
609+
604610
@override
605611
String get keychainDeletedDialogTitle => 'Catalyst keychain removed';
606612

catalyst_voices/packages/catalyst_voices_localization/lib/generated/catalyst_voices_localizations_es.dart

+6
Original file line numberDiff line numberDiff line change
@@ -601,6 +601,12 @@ class VoicesLocalizationsEs extends VoicesLocalizations {
601601
@override
602602
String get total => 'Total';
603603

604+
@override
605+
String get themeLight => 'Light';
606+
607+
@override
608+
String get themeDark => 'Dark';
609+
604610
@override
605611
String get keychainDeletedDialogTitle => 'Catalyst keychain removed';
606612

catalyst_voices/packages/catalyst_voices_localization/lib/l10n/intl_en.arb

+8
Original file line numberDiff line numberDiff line change
@@ -708,6 +708,14 @@
708708
"yes": "Yes",
709709
"no": "No",
710710
"total": "Total",
711+
"themeLight": "Light",
712+
"@themeLight": {
713+
"description": "Refers to a light theme mode."
714+
},
715+
"themeDark": "Dark",
716+
"@themeDark": {
717+
"description": "Refers to a dark theme mode."
718+
},
711719
"keychainDeletedDialogTitle": "Catalyst keychain removed",
712720
"@keychainDeletedDialogTitle": {
713721
"description": "A title on keychain deleted dialog"

catalyst_voices/uikit_example/lib/main.dart

+6-16
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import 'package:catalyst_voices/widgets/toggles/voices_theme_mode_switch.dart';
12
import 'package:catalyst_voices_blocs/catalyst_voices_blocs.dart';
23
import 'package:catalyst_voices_brands/catalyst_voices_brands.dart';
34
import 'package:catalyst_voices_localization/generated/catalyst_voices_localizations.dart';
@@ -92,22 +93,11 @@ class _ThemeModeSwitcherWrapper extends StatelessWidget {
9293
color: Theme.of(context).colorScheme.surface,
9394
child: Padding(
9495
padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 16),
95-
child: Row(
96-
mainAxisAlignment: MainAxisAlignment.end,
97-
children: [
98-
const Text('Light / Dark'),
99-
Padding(
100-
padding: const EdgeInsets.only(left: 8),
101-
child: Switch(
102-
value: Theme.of(context).brightness == Brightness.dark,
103-
onChanged: (value) {
104-
onChanged(
105-
value ? ThemeMode.dark : ThemeMode.light,
106-
);
107-
},
108-
),
109-
),
110-
],
96+
child: Align(
97+
alignment: Alignment.centerRight,
98+
child: VoicesThemeModeSwitch(
99+
onChanged: onChanged,
100+
),
111101
),
112102
),
113103
),

0 commit comments

Comments
 (0)