Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ void main() async {
WidgetsFlutterBinding.ensureInitialized();
await FlutterSkin.init(
apiKey:
"fsk_dc0054468a27dde1671142669f2065f93870975bbb773f1af0ab5898797956db",
"fsk_b0ce429cfbded17bbca66eef6e68bd1f0b7fbf9d74be0c3a0ac8b2e0554b7919",
);
runApp(const MyApp());
}
Expand All @@ -19,6 +19,8 @@ class MyApp extends StatefulWidget {
}

class _MyAppState extends State<MyApp> {
ThemeMode _themeMode = ThemeMode.dark;

@override
void initState() {
super.initState();
Expand All @@ -31,8 +33,18 @@ class _MyAppState extends State<MyApp> {
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: FlutterSkin.toThemeData(),
home: const MyHomePage(title: 'Movie Browser'),
theme: FlutterSkin.toThemeData(fallbackTheme: ThemeData.light()),
darkTheme: FlutterSkin.darkTheme(fallbackTheme: ThemeData.dark()),
themeMode: _themeMode,
home: MyHomePage(
title: 'Movie Browser',
themeMode: _themeMode,
onThemeModeChanged: (themeMode) {
setState(() {
_themeMode = themeMode;
});
},
),
);
}
}
33 changes: 32 additions & 1 deletion example/lib/pages/home_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,16 @@ import '../widgets/movie_card.dart';
import '../widgets/movie_details_sidebar.dart';

class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
const MyHomePage({
super.key,
required this.title,
required this.themeMode,
required this.onThemeModeChanged,
});

final String title;
final ThemeMode themeMode;
final ValueChanged<ThemeMode> onThemeModeChanged;

@override
State<MyHomePage> createState() => _MyHomePageState();
Expand Down Expand Up @@ -104,6 +111,30 @@ class _MyHomePageState extends State<MyHomePage> {
widget.title,
style: TextStyle(color: theme.colorScheme.onPrimary),
),
actions: [
PopupMenuButton<ThemeMode>(
tooltip: 'Theme settings',
icon: Icon(
widget.themeMode == ThemeMode.dark
? Icons.dark_mode
: Icons.light_mode,
color: theme.colorScheme.onPrimary,
),
onSelected: widget.onThemeModeChanged,
itemBuilder: (context) => [
CheckedPopupMenuItem(
value: ThemeMode.light,
checked: widget.themeMode == ThemeMode.light,
child: const Text('Light mode'),
),
CheckedPopupMenuItem(
value: ThemeMode.dark,
checked: widget.themeMode == ThemeMode.dark,
child: const Text('Dark mode'),
),
],
),
],
),
body: Row(
children: [
Expand Down
37 changes: 37 additions & 0 deletions lib/flutter_skin.dart
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,43 @@ class FlutterSkin with WidgetsBindingObserver {
return null;
}

/// Query current active theme from remote config and return as ThemeData.
/// When there's no active theme, the result is null or fallbackTheme if provided.
static ThemeData? darkTheme({
ThemeData? fallbackTheme,
String? fallbackFont,
}) {
ProjectConfig? config = remoteConfig.projectConfig;
ColorScheme? darkTheme = config?.skin?.darkTheme;

String? fontFamily = (config?.skin?.fontFamily?.isEmpty == true)
? null
: config?.skin?.fontFamily;

String? googleFont = config?.skin?.googleFont?.isEmpty == true
? null
: config?.skin?.googleFont;

ThemeData remoteTheme = ThemeData(
colorScheme: darkTheme,
fontFamily:
fontFamily ??
(googleFont != null
? GoogleFonts.getFont(googleFont).fontFamily
: fallbackFont ?? 'Roboto'),
);
if (darkTheme == null) {
if (fallbackTheme != null) {
_logger.logWarning('No active theme found. Returning fallback theme.');
return fallbackTheme;
}
} else {
_logger.logMessage('Active theme found. Returning remote theme.');
return remoteTheme;
}
return null;
}

/// Query current active theme from remote config and return as ThemeData.
/// When there's no active theme, the result is null.
static ThemeData? get theme {
Expand Down
8 changes: 8 additions & 0 deletions lib/models/skin_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class SkinModel {
final DateTime? publishedAt;
final DateTime? deletedAt;
final ColorScheme? colors;
final ColorScheme? darkTheme;
final String? fontFamily;
final String? googleFont;

Expand All @@ -20,6 +21,7 @@ class SkinModel {
required this.version,
required this.createdAt,
required this.colors,
this.darkTheme,
this.fontFamily,
this.googleFont,
this.publishedAt,
Expand All @@ -29,6 +31,8 @@ class SkinModel {
/// Factory constructor to create SkinModel from a map
factory SkinModel.fromMap(Map<String, dynamic> map) {
final tokens = map['tokens'];
final darkTheme = map['darkTheme'];

return SkinModel(
id: map['id'] as String? ?? '',
projectId: map['projectId'] as String? ?? '',
Expand All @@ -46,6 +50,9 @@ class SkinModel {
colors: tokens is Map<String, dynamic>
? fromSchemaString(tokens)?.colors
: null,
darkTheme: darkTheme is Map<String, dynamic>
? fromSchemaString(darkTheme)?.colors
: null,
Comment thread
koukibadr marked this conversation as resolved.
fontFamily: map['font'] as String?,
googleFont: map['googleFont'] as String?,
);
Expand Down Expand Up @@ -77,6 +84,7 @@ class SkinModel {
'publishedAt': publishedAt?.toIso8601String(),
'deletedAt': deletedAt?.toIso8601String(),
'colors': colors != null ? colorSchemeToJson(colors!) : null,
'darkTheme': darkTheme != null ? colorSchemeToJson(darkTheme!) : null,
'font': fontFamily,
'googleFont': googleFont,
};
Expand Down
10 changes: 10 additions & 0 deletions test/mocks/skin_model_mocks.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@ var skinModelMock = SkinModel(
onBackground: Color(0xFF000000),
onSurface: Color(0xFF000000),
),
darkTheme: const ColorScheme.light(
primary: Color(0xFF6200EE),
secondary: Color(0xFF03DAC6),
background: Color(0xFFFFFFFF),
surface: Color(0xFFFFFFFF),
onPrimary: Color(0xFFFFFFFF),
onSecondary: Color(0xFF000000),
onBackground: Color(0xFF000000),
onSurface: Color(0xFF000000),
),
Comment thread
koukibadr marked this conversation as resolved.
id: 'mock_id',
projectId: 'mock_project_id',
isActive: true,
Expand Down
Loading