Skip to content

Instantly share code, notes, and snippets.

@SuperPenguin
Last active June 28, 2022 17:14
Show Gist options
  • Save SuperPenguin/3ecf0aa4eea05cdef9f3a76e4c411c80 to your computer and use it in GitHub Desktop.
Save SuperPenguin/3ecf0aa4eea05cdef9f3a76e4c411c80 to your computer and use it in GitHub Desktop.
ThemeExtension example
import 'package:flutter/material.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(const App());
}
class App extends StatefulWidget {
const App({Key? key}) : super(key: key);
@override
State<App> createState() => AppState();
static AppState of(BuildContext context) {
return context.findAncestorStateOfType<AppState>()!;
}
}
class AppState extends State<App> {
ThemeMode _themeMode = ThemeMode.light;
void setThemeMode(ThemeMode themeMode) {
if (_themeMode != themeMode) {
setState(() {
_themeMode = themeMode;
});
}
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Desktop App',
themeMode: _themeMode,
theme: ThemeData(
brightness: Brightness.light,
extensions: {
// or you can make
// PenguinThemeData(
// backColor: ...,
// bellyColor: ...,
// ),
PenguinThemeData.defaultLight,
},
),
darkTheme: ThemeData(
brightness: Brightness.dark,
extensions: {
PenguinThemeData.defaultDark,
},
),
home: const HomePage(),
);
}
}
class Penguin extends StatelessWidget {
const Penguin({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final penguinTheme = PenguinThemeData.of(context);
return Row(
mainAxisSize: MainAxisSize.min,
children: [
Card(
color: penguinTheme.backColor,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'Back',
style: TextStyle(
color: ThemeData.estimateBrightnessForColor(
penguinTheme.backColor) ==
Brightness.light
? Colors.black
: Colors.white,
),
),
),
),
Card(
color: penguinTheme.bellyColor,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'Belly',
style: TextStyle(
color: ThemeData.estimateBrightnessForColor(
penguinTheme.bellyColor) ==
Brightness.light
? Colors.black
: Colors.white,
),
),
),
),
],
);
}
}
@immutable
class PenguinThemeData extends ThemeExtension<PenguinThemeData> {
const PenguinThemeData({
required this.backColor,
required this.bellyColor,
});
final Color backColor;
final Color bellyColor;
static const defaultLight = PenguinThemeData(
backColor: Colors.grey,
bellyColor: Colors.white,
);
static const defaultDark = PenguinThemeData(
backColor: Colors.black,
bellyColor: Colors.grey,
);
static PenguinThemeData of(BuildContext context) {
final theme = Theme.of(context);
final penguinTheme =
theme.extensions[PenguinThemeData] as PenguinThemeData?;
if (penguinTheme != null) {
return penguinTheme;
}
return theme.brightness == Brightness.light ? defaultLight : defaultDark;
}
@override
ThemeExtension<PenguinThemeData> copyWith({
Color? backColor,
Color? bellyColor,
}) {
return PenguinThemeData(
backColor: backColor ?? this.backColor,
bellyColor: bellyColor ?? this.bellyColor,
);
}
@override
ThemeExtension<PenguinThemeData> lerp(
ThemeExtension<PenguinThemeData>? other,
double t,
) {
if (other is! PenguinThemeData) return this;
return PenguinThemeData(
backColor: Color.lerp(backColor, other.backColor, t)!,
bellyColor: Color.lerp(bellyColor, other.bellyColor, t)!,
);
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is PenguinThemeData &&
other.backColor == backColor &&
other.bellyColor == bellyColor;
}
@override
int get hashCode {
return Object.hashAll([
backColor,
bellyColor,
]);
}
}
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('AppBar'),
),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Penguin(),
Row(
mainAxisSize: MainAxisSize.min,
children: [
TextButton(
onPressed: () => App.of(context).setThemeMode(
ThemeMode.light,
),
child: const Text('Light'),
),
TextButton(
onPressed: () => App.of(context).setThemeMode(
ThemeMode.dark,
),
child: const Text('Dark'),
),
],
),
],
),
),
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment