Theme Tuner

A Flutter package for easily managing multiple themes in your application using the BLoC pattern.

Features

  • Light and dark theme support
  • Custom theme creation
  • System theme detection and automatic switching
  • Theme persistence using SharedPreferences
  • Smooth theme transitions with animations
  • BLoC state management for clean architecture

Installation

Add theme_tuner to your pubspec.yaml:

dependencies:
  theme_tuner: ^0.0.2

πŸš€ Basic Usage

import 'package:flutter/material.dart';
import 'package:theme_tuner/theme_tuner.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return RepositoryProvider(
      create: (context) => ThemeRepository(),
      child: BlocProvider(
        create: (context) => ThemeBloc(
          themeRepository: context.read<ThemeRepository>(),
        )..add(ThemeInitialEvent()),
        child: BlocBuilder<ThemeBloc, ThemeState>(
          builder: (context, state) {
            if (state is ThemeLoaded) {
              return MaterialApp(
                title: 'My App',
                theme: state.themeModel.themeData,
                home: const HomePage(),
              );
            }
            return const MaterialApp(
              home: Scaffold(body: Center(child: CircularProgressIndicator())),
            );
          },
        ),
      ),
    );
  }
}

πŸŽ›οΈ Changing Themes

Dispatch the appropriate event to the ThemeBloc:

context.read<ThemeBloc>().add(ThemeChangedEvent(ThemeType.light));
context.read<ThemeBloc>().add(ThemeChangedEvent(ThemeType.dark));
context.read<ThemeBloc>().add(ThemeChangedEvent(ThemeType.green));
context.read<ThemeBloc>().add(ThemeChangedEvent(ThemeType.purple));
context.read<ThemeBloc>().add(ThemeFollowSystemEvent());
context.read<ThemeBloc>().add(CustomThemeEvent(primaryColor: Colors.orange));

πŸ§ͺ Theme Settings Page Example

class ThemeSettingsPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Theme Settings')),
      body: ListView(
        children: [
          ListTile(
            title: const Text('Light Theme'),
            leading: const Icon(Icons.light_mode),
            onTap: () => context.read<ThemeBloc>().add(ThemeChangedEvent(ThemeType.light)),
          ),
          ListTile(
            title: const Text('Dark Theme'),
            leading: const Icon(Icons.dark_mode),
            onTap: () => context.read<ThemeBloc>().add(ThemeChangedEvent(ThemeType.dark)),
          ),
          ListTile(
            title: const Text('System Theme'),
            leading: const Icon(Icons.brightness_auto),
            onTap: () => context.read<ThemeBloc>().add(ThemeFollowSystemEvent()),
          ),
        ],
      ),
    );
  }
}

🎨 Custom Theme with Color Picker

void showColorPicker(BuildContext context) {
  Color pickerColor = Theme.of(context).primaryColor;

  showDialog(
    context: context,
    builder: (context) {
      return AlertDialog(
        title: const Text('Pick a theme color'),
        content: SingleChildScrollView(
          child: ColorPicker(
            pickerColor: pickerColor,
            onColorChanged: (color) {
              pickerColor = color;
            },
          ),
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.of(context).pop(),
            child: const Text('Cancel'),
          ),
          ElevatedButton(
            onPressed: () {
              context.read<ThemeBloc>().add(CustomThemeEvent(primaryColor: pickerColor));
              Navigator.of(context).pop();
            },
            child: const Text('Apply'),
          ),
        ],
      );
    },
  );
}

πŸ–₯️ System Theme Integration

When users select the System Theme option, ThemeTuner will automatically adapt between light and dark themes based on the OS settings.

βš™οΈ Advanced Configuration

Custom Theme Definitions

static final ThemeModel customRed = ThemeModel(
  type: ThemeType.custom,
  themeData: ThemeData(
    brightness: Brightness.light,
    primarySwatch: Colors.red,
  ),
);

Theme Extensions

class CustomThemeExtension extends ThemeExtension<CustomThemeExtension> {
  final Color specialColor;
  final BorderRadius borderRadius;

  CustomThemeExtension({
    required this.specialColor,
    required this.borderRadius,
  });

  @override
  CustomThemeExtension copyWith({
    Color? specialColor,
    BorderRadius? borderRadius,
  }) {
    return CustomThemeExtension(
      specialColor: specialColor ?? this.specialColor,
      borderRadius: borderRadius ?? this.borderRadius,
    );
  }

  @override
  CustomThemeExtension lerp(ThemeExtension<CustomThemeExtension>? other, double t) {
    if (other is! CustomThemeExtension) return this;
    return CustomThemeExtension(
      specialColor: Color.lerp(specialColor, other.specialColor, t)!,
      borderRadius: BorderRadius.lerp(borderRadius, other.borderRadius, t)!,
    );
  }
}

Add to your theme:

themeData: ThemeData().copyWith(
  extensions: [
    CustomThemeExtension(
      specialColor: Colors.amber,
      borderRadius: BorderRadius.circular(8),
    ),
  ],
);

Use in widgets:

final customTheme = Theme.of(context).extension<CustomThemeExtension>()!;
Container(
  decoration: BoxDecoration(
    color: customTheme.specialColor,
    borderRadius: customTheme.borderRadius,
  ),
);

πŸ™Œ Contributions Welcome

Feel free to open issues, suggest features, or submit pull requests!
Let’s make Flutter theme management smarter and smoother together.

Connect with me

If you have any bugs or issues , If you want to explain my code please contact me on :


MAIL ME 

__NimeshPiyumantha__ https://www.linkedin.com/public-profile/settings?trk=d_flagship3_profile_self_view_public_profile Nimesh Piyumantha _.nimmaa._

repo license repo size GitHub forks GitHub stars GitHub LastCommit

@2025 Nimesh Piyumantha, Inc.All rights reserved