lycn_theme_engine 1.0.0
lycn_theme_engine: ^1.0.0 copied to clipboard
A reusable Flutter theme engine with configurable color tokens, custom statuses, runtime theme editing, persistence, and JSON import/export.
import 'package:flutter/material.dart';
import 'package:lycn_theme_engine/lycn_theme_engine.dart';
void main() {
runApp(const ExampleBootstrap());
}
class ExampleBootstrap extends StatefulWidget {
const ExampleBootstrap({super.key});
@override
State<ExampleBootstrap> createState() => _ExampleBootstrapState();
}
class _ExampleBootstrapState extends State<ExampleBootstrap> {
late final ThemeManager _themeManager;
@override
void initState() {
super.initState();
_themeManager = ThemeManager();
}
@override
void dispose() {
_themeManager.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return ThemeInitializer(
manager: _themeManager,
seed: const ThemeSeed(assetPath: 'assets/theme_seed.json'),
loading: const Material(
child: Center(child: CircularProgressIndicator()),
),
builder: (context) {
return LycnThemeApp(
manager: _themeManager,
title: 'LYCN Theme Engine',
home: HomeScreen(manager: _themeManager),
);
},
);
}
}
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key, required this.manager});
final ThemeManager manager;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('LYCN Theme Engine'),
actions: [ThemeModeToggle(manager: manager)],
),
body: Center(
child: SingleChildScrollView(
padding: const EdgeInsets.all(24),
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 700),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
'Theme Engine Demo',
style: Theme.of(context).textTheme.headlineMedium,
),
const SizedBox(height: 8),
Text(
'This application is using the LYCN Theme Engine package.',
style: Theme.of(context).textTheme.bodyLarge,
),
const SizedBox(height: 24),
Card(
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Theme Mode',
style: Theme.of(context).textTheme.titleLarge,
),
const SizedBox(height: 16),
ThemeModeSegmented(manager: manager),
],
),
),
),
const SizedBox(height: 16),
Card(
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Color Tokens',
style: Theme.of(context).textTheme.titleLarge,
),
const SizedBox(height: 16),
_ColorRow(
label: 'Primary',
color: manager.color('primary'),
),
_ColorRow(
label: 'Secondary',
color: manager.color('secondary'),
),
_ColorRow(
label: 'Tertiary',
color: manager.color('tertiary'),
),
_ColorRow(
label: 'Surface',
color: manager.color('bg.surface'),
),
],
),
),
),
const SizedBox(height: 16),
Card(
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Components',
style: Theme.of(context).textTheme.titleLarge,
),
const SizedBox(height: 16),
TextField(
decoration: const InputDecoration(
labelText: 'Example field',
hintText: 'Theme-aware input',
),
),
const SizedBox(height: 16),
Wrap(
spacing: 8,
runSpacing: 8,
children: [
ElevatedButton(
onPressed: () {},
child: const Text('Primary'),
),
FilledButton(
onPressed: () {},
child: const Text('Confirm'),
),
OutlinedButton(
onPressed: () {},
child: const Text('Other'),
),
],
),
],
),
),
),
const SizedBox(height: 16),
FilledButton.icon(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => ThemeManagerScreen(manager: manager),
),
);
},
icon: const Icon(Icons.palette),
label: const Text('Open Theme Manager'),
),
],
),
),
),
),
);
}
}
class _ColorRow extends StatelessWidget {
const _ColorRow({required this.label, required this.color});
final String label;
final Color color;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(bottom: 10),
child: Row(
children: [
Container(
width: 32,
height: 32,
decoration: BoxDecoration(
color: color,
borderRadius: BorderRadius.circular(8),
),
),
const SizedBox(width: 12),
Text(label),
const Spacer(),
Text(
'#${color.toARGB32().toRadixString(16).substring(2).toUpperCase()}',
),
],
),
);
}
}