theme_extensions_gen 0.1.0
theme_extensions_gen: ^0.1.0 copied to clipboard
Theme Extensions Generator
example/lib/main.dart
import 'dart:math';
import 'package:example/theme_manager.dart';
import 'package:example/theme_manager_scope.dart';
import 'package:flutter/material.dart';
import 'package:templates/generated/theme_extensions/context_extensions.dart';
import 'package:theme_dark/generated/theme_extensions.dart';
import 'package:theme_light/generated/theme_extensions.dart';
void main() {
runApp(
ThemeManagerScope(
notifier: ThemeManager(themeExtensionsLight, themeExtensionsDark),
child: const MyApp(),
),
);
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return BrandedAppBuilder(
builder: (context, theme) {
return MaterialApp(
title: 'Theme Extensions Example',
debugShowCheckedModeBanner: false,
theme: theme,
home: const MyHomePage(),
);
},
);
}
}
typedef BrandedAppThemeBuilder = Widget Function(
BuildContext context,
ThemeData theme,
);
class BrandedAppBuilder extends StatelessWidget {
const BrandedAppBuilder({
required this.builder,
super.key,
});
final BrandedAppThemeBuilder builder;
@override
Widget build(BuildContext context) {
final manager = ThemeManagerScope.of(context);
return builder(
context,
_createThemeData(manager.isLight, manager.extensions),
);
}
ThemeData _createThemeData(
bool isLight,
List<ThemeExtension> extensions,
) =>
ThemeData(
colorScheme: ColorScheme.fromSeed(
brightness: isLight ? Brightness.light : Brightness.dark,
seedColor: Colors.indigo,
),
extensions: extensions,
splashFactory: NoSplash.splashFactory,
);
}
class MyHomePage extends StatelessWidget {
const MyHomePage({super.key});
@override
Widget build(BuildContext context) {
final textTheme = context.brandedTextTheme;
return Scaffold(
appBar: AppBar(
title: const Text('Theme Extensions Example'),
centerTitle: true,
elevation: 0,
forceMaterialTransparency: true,
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(24),
child: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 20,
children: [
const Center(child: BrandedButton()),
const BrandedCard(),
Text('Title', style: textTheme.title),
Text('Subtitle', style: textTheme.subtitle),
Text('Primary text', style: textTheme.primaryText),
Text('Secondary text', style: textTheme.secondaryText),
const BrandedChips(),
],
),
),
),
bottomNavigationBar: const BottomAppBar(
child: Center(child: ThemeSwitcher()),
),
);
}
}
class ChipsStateNotifier extends ChangeNotifier {
ChipsStateNotifier({
required int count,
}) : _selectedFlags = List.generate(count, (i) => Random().nextBool());
final List<bool> _selectedFlags;
bool isSelected(int index) => _selectedFlags[index];
void toggle(int index) {
_selectedFlags[index] = !_selectedFlags[index];
notifyListeners();
}
}
class BrandedChips extends StatelessWidget {
const BrandedChips({super.key});
static const _chipLabels = [
'New',
'Popular',
'Trending',
'Featured',
'Recommended',
'Sale',
'Hot',
'Exclusive',
'Limited',
'Best Seller',
];
@override
Widget build(BuildContext context) {
return Wrap(
spacing: 8,
runSpacing: 8,
children: [
for (int i = 0; i < _chipLabels.length; i++)
BrandedChip(
isSelected: Random().nextBool(),
text: _chipLabels[i],
),
],
);
}
}
class BrandedChip extends StatelessWidget {
const BrandedChip({
required this.isSelected,
required this.text,
super.key,
});
final bool isSelected;
final String text;
@override
Widget build(BuildContext context) {
final theme = context.brandedChipTheme;
return Container(
decoration: isSelected ? theme.decorationSelected : theme.decoration,
padding: theme.padding,
child: Text(
text,
style: isSelected ? theme.textStyleSelected : theme.textStyle,
),
);
}
}
class ThemeSwitcher extends StatelessWidget {
const ThemeSwitcher({super.key});
@override
Widget build(BuildContext context) {
final manager = ThemeManagerScope.of(context);
return Switch(
value: manager.isLight,
onChanged: (newState) => manager.toggle(),
);
}
}
class BrandedButton extends StatelessWidget {
const BrandedButton({super.key});
@override
Widget build(BuildContext context) {
final theme = context.brandedButtonTheme;
return Container(
height: theme.height,
decoration: theme.decoration,
padding: theme.padding,
child: Center(
widthFactor: 1,
child: Text('Branded Button', style: theme.textStyle, maxLines: 1),
),
);
}
}
class BrandedCard extends StatelessWidget {
const BrandedCard({super.key});
@override
Widget build(BuildContext context) {
final theme = context.brandedCardTheme;
return Container(
decoration: theme.decoration,
padding: theme.padding,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Card Title',
style: theme.titleStyle,
maxLines: 1,
),
SizedBox(height: theme.titleGapY),
Text(
_cardDescription,
style: theme.descriptionStyle,
),
],
),
);
}
}
const _cardDescription = 'Discover new destinations with our travel guide. '
'Explore hidden gems, top-rated attractions, and local favorites to make '
'every trip unforgettable. Plan your journey with expert tips and '
'recommendations tailored for you. From city escapes to nature retreats, '
'find the perfect spot for any mood.';