π¨ SmartLib Theme - Effortless Flutter Theme Management
A zero-boilerplate, BLoC-powered Flutter theme management library that makes it incredibly simple to create, switch, and customize themesβlight, dark, or any style you dream of!
π Why Use This Library?
- β One-time setup: Initialize once, then forget about theme plumbing.
- β Custom themes made simple: Create themes with your brand colors in seconds.
- β Dynamic switching: Switch themes anywhere in your app with a single line of code.
- β Persistent themes: Themes stay saved across app restarts.
- β Scalable: Supports dozens of themes without performance issues.
Theming your Flutter project as Master
Based on a Medium article by Karo Hovhannisyan β one of the most skilled mobile architects in the industry β this library is perfect for apps that need flexible theming with zero complexity.
π¦ Built With
- Flutter (v3.7.2+)
- BLoC for state management
- SharedPreferences for persistence
- ThemeExtension for custom design tokens
π Quick Start Guide
0. TL;DR
Key Methods:
await AppThemeManager.init(themes: [])
- Wrap
MaterialApp
withAppThemeBuilder(theme: theme)
AppThemeManager.changeTheme(context: context, themeKey: 'key')
AppThemeManager.getCurrentTheme(context: context)
// Always returns the updated theme
1. Install the Package
Add to pubspec.yaml
:
dependencies:
smart_lib_theme: ^0.1.0 # Replace with latest version
Then run:
flutter pub get
2. Initialize the Theme Manager
In your main.dart
, define supported themes:
import 'package:flutter/material.dart';
import 'package:smart_lib_theme/core/theme/default/themes.dart';
import 'package:smart_lib_theme/features/theme/presentation/app_theme_manager.dart';
import 'package:smart_lib_theme/features/theme/presentation/widgets/app_theme_builder.dart';
Future<void> main() async {
await AppThemeManager.init(themes: [
AppTheme(key: 'light', themeData: AppDefaultThemesData().light),
AppTheme(key: 'dark', themeData: AppDefaultThemesData().dark),
]);
runApp(const MyApp());
}
β Replace
AppDefaultThemesData()
with your custom theme class (see below).
3. Wrap Your App with AppThemeBuilder
Ensures dynamic theme updates across the entire UI:
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return AppThemeBuilder(
builder: (theme) {
return MaterialApp(
title: 'Themed App',
theme: theme, // <-- Dynamic theme applied here
home: const HomePage(),
);
},
);
}
}
π§ One-time setup: Done once, works forever.
4. Switch Themes Dynamically
From any widget, change themes by passing the theme key:
GestureDetector(
onTap: () {
AppThemeManager.changeTheme(context: context, themeKey: 'dark');
},
child: Text('Switch to Dark Mode'),
)
π The UI updates instantly thanks to BLoC and
ThemeExtension
.
β οΈ If thethemeKey
doesnβt exist,ThemeExceptionConstants.notFoundKey
is thrown.
5. Access Theme Colors & Styles
Use BuildContext
extensions for colors and text styles:
Text(
'Styled Text',
style: context.textTheme().titleLarge?.copyWith(
color: context.appColors().onPrimary,
),
),
Container(
color: context.appColors().surface,
child: Text('Surface Background'),
),
π¨ All tokens (colors, shapes, text styles) are available via
context.appColors()
andcontext.textTheme()
.
π¨ Create Custom Themes
1. Define Your Own Colors
Extend AppThemeExtension
to define your brand palette:
class MyCustomThemeExtension extends AppThemeExtension {
MyCustomThemeExtension()
: super(
primary: Colors.purple,
onPrimary: Colors.white,
secondary: Colors.tealAccent,
onSecondary: Colors.black,
// Override other tokens as needed
);
}
2. Use Custom Themes in Initialization
Replace defaults with your custom themes:
await AppThemeManager.init(themes: [
AppTheme(key: 'custom', themeData: ThemeData(
extensions: [MyCustomThemeExtension()],
colorScheme: ColorScheme.fromSeed(seedColor: Colors.purple),
)),
]);
π― Now use
AppThemeManager.changeTheme(context, themeKey: 'custom')
to switch to your theme!
π§ͺ Example: Theme Switcher UI
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: context.appColors().surface,
body: Column(
children: [
const SizedBox(height: 300),
Center(
child: GestureDetector(
onTap: () => AppThemeManager.changeTheme(context: context, themeKey: 'light'),
child: Text('Light Theme'),
),
),
const SizedBox(height: 100),
Center(
child: GestureDetector(
onTap: () => AppThemeManager.changeTheme(context: context, themeKey: 'dark'),
child: Text('Dark Theme', style: context.textTheme().bodyMedium),
),
),
],
),
);
}
}
π¦ Folder Structure (Clean Architecture)
lib/
βββ core/ # Shared utilities (ThemeExtension, default themes)
β βββ theme/
β βββ default/ # Default light/dark themes
β βββ extensions/ # ThemeExtension definitions
β βββ data/ # Component-specific styling (buttons, text, etc.)
βββ features/
β βββ theme/
β βββ domain/ # Entities, use cases
β βββ data/ # Repository + SharedPreferences impl
β βββ presentation/ # BLoC, widgets, manager
βββ di/ # Dependency injection
π License
MIT License β see LICENSE for details.
π€ Contributing
Feel free to open issues or PRs! See CONTRIBUTING.md for guidelines.
π¬ Feedback
Have questions or suggestions? Reach out on GitHub or email me at dallakyanvanik@gmail.com.
β¨ Maintained by Vanik Dallakyan
Made with β€οΈ for Flutter developers everywhere.
Libraries
- core/theme/data/app_bar
- core/theme/data/color_scheme
- core/theme/data/dialog
- core/theme/data/divider
- core/theme/data/input_themes
- core/theme/data/progress_indicator
- core/theme/data/tab_bar
- core/theme/data/text
- core/theme/default/default_theme_extensions
- core/theme/default/themes
- core/theme/extensions/theme_ext
- core/theme/extensions/theme_extension
- core/utils/exception/constants/exception_constants
- di/dependency_injection
- features/theme/data/datasource/preferences/app_theme_preferences
- features/theme/data/datasource/preferences/app_theme_preferences_impl
- features/theme/data/repository/app_theme_repository_impl
- features/theme/domain/entity/app_theme
- features/theme/domain/repository/app_theme_repository
- features/theme/domain/use_cases/get_is_first_launch_use_case
- features/theme/domain/use_cases/save_app_theme_use_case
- features/theme/presentation/app_theme_manager
- features/theme/presentation/bloc/app_theme_bloc
- features/theme/presentation/bloc/app_theme_event
- features/theme/presentation/di/app_theme_di
- features/theme/presentation/widgets/app_theme_builder