Skip to content

Commit

Permalink
created object for custom theme
Browse files Browse the repository at this point in the history
id gets saved in shared preferences
  • Loading branch information
mikecoomber committed Sep 9, 2024
1 parent 0bb8c0c commit a333c32
Show file tree
Hide file tree
Showing 7 changed files with 195 additions and 170 deletions.
37 changes: 37 additions & 0 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,43 @@ class ZetaExample extends StatelessWidget {
return ZetaProvider(
// initialContrast: ZetaContrast.aa,
// initialThemeMode: ThemeMode.system,
customThemes: [
ZetaCustomTheme(
id: 'teal',
primary: ZetaPrimitivesLight().teal,
primaryDark: ZetaPrimitivesDark().teal,
secondary: ZetaPrimitivesLight().yellow,
secondaryDark: ZetaPrimitivesDark().yellow,
),
ZetaCustomTheme(
id: 'yellow',
primary: ZetaPrimitivesLight().yellow,
primaryDark: ZetaPrimitivesDark().yellow,
secondary: ZetaPrimitivesLight().red,
secondaryDark: ZetaPrimitivesDark().red,
),
ZetaCustomTheme(
id: 'red',
primary: ZetaPrimitivesLight().red,
primaryDark: ZetaPrimitivesDark().red,
secondary: ZetaPrimitivesLight().purple,
secondaryDark: ZetaPrimitivesDark().purple,
),
ZetaCustomTheme(
id: 'purple',
primary: ZetaPrimitivesLight().purple,
primaryDark: ZetaPrimitivesDark().purple,
secondary: ZetaPrimitivesLight().green,
secondaryDark: ZetaPrimitivesDark().green,
),
ZetaCustomTheme(
id: 'green',
primary: ZetaPrimitivesLight().green,
primaryDark: ZetaPrimitivesDark().green,
secondary: ZetaPrimitivesLight().blue,
secondaryDark: ZetaPrimitivesDark().blue,
),
],
builder: (context, lightTheme, darkTheme, themeMode) {
return MaterialApp.router(
routerConfig: router,
Expand Down
89 changes: 33 additions & 56 deletions example/lib/utils/theme_color_switch.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import 'package:flutter/material.dart';
import 'package:collection/collection.dart';
import 'package:zeta_flutter/zeta_flutter.dart';

class ZetaThemeColorSwitch extends StatefulWidget {
Expand All @@ -10,71 +9,49 @@ class ZetaThemeColorSwitch extends StatefulWidget {
}

class _ZetaThemeColorSwitchState extends State<ZetaThemeColorSwitch> {
String currentTheme = "default";

final Map<String, ZetaColorSwatch?> appThemes = {
"default": null,
"teal": ZetaPrimitivesLight().teal,
"yellow": ZetaPrimitivesLight().yellow,
"red": ZetaPrimitivesLight().red,
"purple": ZetaPrimitivesLight().purple,
"green": ZetaPrimitivesLight().green,
};

String get currentValue {
if (Zeta.of(context).brightness == Brightness.light) {
return appThemes.entries
.firstWhereOrNull((element) => element.value?.value == Zeta.of(context).colors.mainPrimary.value)
?.key ??
"default";
}
if (Zeta.of(context).brightness == Brightness.dark) {
return appThemes.entries
.firstWhereOrNull((element) => element.value?.shade50.value == Zeta.of(context).colors.mainPrimary.value)
?.key ??
"default";
}
return 'default';
}

@override
Widget build(BuildContext context) {
final zeta = Zeta.of(context);
final zetaProvider = ZetaProvider.of(context);

final Map<String?, Widget> items = {};
items.putIfAbsent(null, () => ZetaIcon(ZetaIcons.block));

zetaProvider.customThemes.forEach((e) {
final color = e.primary;
final name = e.id;
items.putIfAbsent(
name,
() => ZetaAvatar(
size: ZetaAvatarSize.xxs,
backgroundColor: zeta.colors.surfaceDefault,
image: ZetaIcon(
Icons.color_lens,
color: color ??
(Zeta.of(context).brightness == Brightness.light
? ZetaPrimitivesLight().blue
: ZetaPrimitivesDark().blue),
),
),
);
});

return DropdownButtonHideUnderline(
child: DropdownButton<String>(
value: currentValue,
child: DropdownButton<String?>(
value: zetaProvider.customThemeId,
elevation: 0,
padding: EdgeInsets.all(8),
icon: Nothing(),
dropdownColor: zeta.colors.borderDisabled,
items: appThemes.entries.map((e) {
final color = e.value;
final name = e.key;
return DropdownMenuItem<String>(
value: name,
alignment: Alignment.center,
child: ZetaAvatar(
size: ZetaAvatarSize.xxs,
backgroundColor: Zeta.of(context).colors.surfaceDefault,
image: ZetaIcon(
Icons.color_lens,
color: color ??
(Zeta.of(context).brightness == Brightness.light
? ZetaPrimitivesLight().blue
: ZetaPrimitivesDark().blue),
),
),
);
}).toList(),
items: items.entries
.map((e) => DropdownMenuItem<String?>(
value: e.key,
alignment: Alignment.center,
child: e.value,
))
.toList(),
onChanged: (value) {
final theme = appThemes[value];
if (theme != null && value != null) {
ZetaProvider.of(context).updateThemeData(primary: theme);
setState(() {
currentTheme = value;
});
}
ZetaProvider.of(context).updateCustomTheme(themeId: value);
},
),
);
Expand Down
5 changes: 5 additions & 0 deletions lib/src/theme/color_swatch.dart
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ class ZetaColorSwatch extends ColorSwatch<int> with EquatableMixin {
/// - 100, 90, 80, and 70 are darker shades of the primary color.
/// - 60 is the primary color itself.
/// - 50, 40, 30, 20, and 10 are progressively lighter shades of the primary color.
if (primary is ZetaColorSwatch) {
return primary;
} else if (primary is MaterialColor) {
return ZetaColorSwatch.fromMaterialColor(primary);
}
return ZetaColorSwatch(
primary: primary.value,
swatch: primary.generateSwatch(background: background),
Expand Down
51 changes: 51 additions & 0 deletions lib/src/theme/custom_theme.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import 'package:flutter/material.dart';

import 'color_swatch.dart';

/// A custom theme that can be used to define custom colors for the app.
class ZetaCustomTheme {
/// Constructs a [ZetaCustomTheme].
/// To define every shade of a color, provide a [ZetaColorSwatch] or a [MaterialColor].
/// If only a [Color] is provided, a [ZetaColorSwatch] will be automatically generated.
ZetaCustomTheme({
required this.id,
Color? primary,
Color? primaryDark,
Color? secondary,
Color? secondaryDark,
}) : assert(
primaryDark != null && primary != null,
'Primary dark cannot be set without a primary color',
),
assert(
secondary != null && secondaryDark != null,
'Secondary dark cannot be set without a secondary color',
),
primary = primary != null ? ZetaColorSwatch.fromColor(primary) : null,
primaryDark = primaryDark != null
? ZetaColorSwatch.fromColor(primaryDark)
: primary != null
? ZetaColorSwatch.inverse(ZetaColorSwatch.fromColor(primary))
: null,
secondary = secondary != null ? ZetaColorSwatch.fromColor(secondary) : null,
secondaryDark = secondaryDark != null
? ZetaColorSwatch.fromColor(secondaryDark)
: secondary != null
? ZetaColorSwatch.inverse(ZetaColorSwatch.fromColor(secondary))
: null;

/// The ID of the custom theme.
final String id;

/// The primary color of the custom theme.
final ZetaColorSwatch? primary;

/// The dark primary color of the custom theme.
final ZetaColorSwatch? primaryDark;

/// The secondary color of the custom theme.
final ZetaColorSwatch? secondary;

/// The dark secondary color of the custom theme.
final ZetaColorSwatch? secondaryDark;
}
1 change: 1 addition & 0 deletions lib/src/theme/theme.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export 'color_extensions.dart';
export 'color_swatch.dart';
export 'constants.dart';
export 'contrast.dart';
export 'custom_theme.dart';
export 'theme_service.dart';
export 'tokens.dart';
export 'typography.dart';
19 changes: 12 additions & 7 deletions lib/src/theme/theme_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ import 'contrast.dart';

const String _kThemeMode = 'themeMode';
const String _kContrast = 'contrast';
const String _kColor = 'color';
// TODO(colors): Revert this to include color also?
const String _kThemeId = 'theme_id';
// TODO(colors): Re-add custom font somewhere (not here)
// TODO(colors): Add tests
/// `ZetaThemeService` is an abstract class.
Expand All @@ -29,7 +28,7 @@ abstract class ZetaThemeService {
/// `ZetaContrast` defines different contrast styles to use across the application.
///
/// Returns a Future `(ZetaThemeData?, ThemeMode?, ZetaContrast?)`.
Future<(ThemeMode?, ZetaContrast?)> loadTheme();
Future<(ThemeMode?, ZetaContrast?, String?)> loadTheme();

/// Saves the provided theme data as the application's theme.
///
Expand All @@ -42,6 +41,7 @@ abstract class ZetaThemeService {
Future<void> saveTheme({
required ThemeMode themeMode,
required ZetaContrast contrast,
required String? themeId,
});
}

Expand All @@ -51,7 +51,7 @@ class ZetaDefaultThemeService extends ZetaThemeService {
const ZetaDefaultThemeService();

@override
Future<(ThemeMode?, ZetaContrast?)> loadTheme() async {
Future<(ThemeMode?, ZetaContrast?, String?)> loadTheme() async {
final preferences = await SharedPreferences.getInstance();

final modeString = preferences.getString(_kThemeMode);
Expand All @@ -65,17 +65,22 @@ class ZetaDefaultThemeService extends ZetaThemeService {
final contrastString = preferences.getString(_kContrast);
final contrast = contrastString == ZetaContrast.aaa.name ? ZetaContrast.aaa : ZetaContrast.aa;

return (themeMode, contrast);
final themeId = preferences.getString(_kThemeId);

return (themeMode, contrast, themeId);
}

@override
Future<void> saveTheme({
required ThemeMode themeMode,
required ZetaContrast contrast,
required String? themeId,
}) async {
final preferences = await SharedPreferences.getInstance();

await preferences.setString('themeMode', themeMode.name);
await preferences.setString('contrast', contrast.name);
await preferences.setString(_kThemeMode, themeMode.name);
await preferences.setString(_kContrast, contrast.name);

if (themeId != null) await preferences.setString(_kThemeId, themeId);
}
}
Loading

0 comments on commit a333c32

Please sign in to comment.