🎨 SmartLib Theme - Effortless Flutter Theme Management

Pub Version
GitHub Repo
License
Contributions Welcome

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


πŸš€ Quick Start Guide

0. TL;DR

Key Methods:

  1. await AppThemeManager.init(themes: [])
  2. Wrap MaterialApp with AppThemeBuilder(theme: theme)
  3. AppThemeManager.changeTheme(themeKey: 'key') // no BuildContext needed; the user stays on the current page
  4. AppThemeManager.currentThemeKey / AppThemeManager.getCurrentTheme() // Always returns the updated theme

1. Install the Package

Add to pubspec.yaml:

dependencies:  
  smart_lib_theme: ^1.2.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/smart_lib_theme.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.

🧭 Navigation is preserved: switching themes only swaps the theme passed to MaterialApp, so the user stays on the same page and page state is kept. If you use MaterialApp.router, create your router (e.g. GoRouter) outside the builder β€” a router created inside it would be rebuilt on every theme change and reset navigation.


4. Switch Themes Dynamically

From any widget, change themes by passing the theme key:

GestureDetector(  
  onTap: () {  
    AppThemeManager.changeTheme(themeKey: 'dark');  
  },  
  child: Text('Switch to Dark Mode'),  
)  

πŸ”„ The UI updates instantly thanks to BLoC and ThemeExtension.
⚠️ If the themeKey doesn’t exist, an AppThemeException is thrown (message: ThemeExceptionConstants.notFoundKey).


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() and context.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(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(themeKey: 'light'),  
              child: Text('Light Theme'),  
            ),  
          ),  
          const SizedBox(height: 100),  
          Center(  
            child: GestureDetector(  
              onTap: () => AppThemeManager.changeTheme(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.