iteo / theme_tailor Goto Github PK
View Code? Open in Web Editor NEWCode generator for Flutter's theme extension classes.
Home Page: https://pub.dev/packages/theme_tailor
License: MIT License
Code generator for Flutter's theme extension classes.
Home Page: https://pub.dev/packages/theme_tailor
License: MIT License
dart run build_runner build --delete-conflicting-outputs
[INFO] Generating build script completed, took 426ms
[WARNING] ../../.puro/shared/pub_cache/hosted/pub.dev/theme_tailor-3.0.0/lib/builder.dart:11:45: Error: Member not found: 'TailorMixin.fromJson'.
[TailorAnnotationsGenerator(TailorMixin.fromJson(options.config))],
^^^^^^^^
[INFO] Precompiling build script... completed, took 1.2s
[SEVERE] Failed to precompile build script .dart_tool/build/entrypoint/build.dart.
This is likely caused by a misconfigured builder definition.
// ignore_for_file: public_member_api_docs, sort_constructors_first
import 'package:flutter/material.dart';
import 'package:theme_tailor_annotation/theme_tailor_annotation.dart';
part 'theme_extension.tailor.dart';
@TailorMixinComponent()
class AppColors extends ThemeExtension<AppColors> with _$AppColorsTailorMixin {
const AppColors({
required this.color100,
required this.color200,
required this.color300,
required this.textColor100,
required this.textColor200,
required this.textColor300,
required this.buttonSplashColor,
required this.buttonBorderColor,
required this.homePageSliverHeaderTextColor1,
required this.homePageSliverHeaderTextColor2,
});
final Color color100;
final Color color200;
final Color color300;
final Color textColor100;
final Color textColor200;
final Color textColor300;
final Color homePageSliverHeaderTextColor1;
final Color homePageSliverHeaderTextColor2;
final Color buttonSplashColor;
final Color buttonBorderColor;
}
dart run build_runner build --delete-conflicting-outputs
work
3.3.0
3.0.0
terminal
Could be nice to rework Arrays to Theme classes.
Currently it is not obvious to find certain color for the certain theme to change for example.
@tailor
class _$MyTheme {
static List<Color> background = [darkColor, lightColor, orangeColor, greenColor, ...];
static List<Color> iconColor = [darkColor, lightColor, orangeColor, greenColor, ...];
static List<TextStyle> h1 = [darkStyle, lightStyle, orangeStyle, greenStyle, ...];
static List<TextStyle> h2 = [darkStyle, lightStyle, orangeStyle, greenStyle, ...];
}
into
@tailor
class _$MyThemeOrangeColors {
static Color background = orangeColor;
static Color iconColor = orangeColor;
}
@tailor
class _$MyThemeOrangeTextStyles {
static TextStyle h1 = orangeStyle;
static TextStyle h2 = orangeStyle;
}
and etc
@Rongix Some of the features of theme_tailor: ^1.1.0
like const themes have updated annotations (@Tailor(constantThemes: true)
) which are not available on pub via theme_tailor_annotation: ^1.0.3
Upon researching how to migrate from an older version (2.0.0) to the latest one, I wanted to check out the migration example on how to do that. Upon opening the link at the bottom of the migration section, it redirected me to a 404 - Not found
page instead of the migration example.
To see an example of how to migrate, head out to [example: migration_example](https://github.com/Iteo/theme_tailor/blob/main/packages/theme_tailor/example/lib/migration_from_tailor_to_tailor_mixin.dart)
A page to proper migration documentation should be opened.
Irrelevant
2.0.0
iOS, Android, Web, Windows, macOS, Linux
None
When using theme_tailor
and generating themeGetter
like for example:
// some_theme.dart
@Tailor(themeGetter: ThemeGetter.onBuildContext)
class _$SomeTheme { ... }
the generated code looks like:
// some_theme.tailor.dart
extension SomeThemeBuildContext on BuildContext {
SomeTheme get someTheme =>
Theme.of(this).extension<SomeTheme>()!;
}
This work well with material
apps as they are all based on Theme
.
Currently when using fluent_ui the generated tailor extensions do not work because
the package comes with its own FluentTheme and FluentThemeData where ThemeExtensions
get registered.
To make it work again the generated code had to look like:
// some_theme.tailor.dart
extension SomeThemeBuildContext on BuildContext {
SomeTheme get someTheme =>
FluentTheme.of(this).extension<SomeTheme>()!; // <- Replace Theme with FluentTheme
}
This could be solved by allowing to configure the class where the extensions are expected to be registered at.
Tailor
annotation@Tailor(themeGetter: ThemeGetter.onBuildContext, themeClassName = 'FluentTheme')
class _$SomeTheme { ... }
targets:
$default:
builders:
theme_tailor:
options:
themeClassName: FluentTheme # defaults to Theme
This might be useful for the future to make theme_tailor
work with other ui libs like macos_ui
or eventually cupertino
if they begin to support registering theme extensions in their respective themes.
Assuming a class TileTheme
, this is how they'd be implemented in the generated code:
static TileTheme? maybeOf(BuildContext context) {
return Theme.of(context).extension<TileTheme>();
}
static TileTheme of(BuildContext context) {
return maybeOf(context)!;
}
I am not sure if this is the correct place to ask or put this.
After accidentally pasting flutter pub run
from somewhere else I have managed to get to my code generated whereas flutter run
would not go ahead nor give me a relevant error message.
ChatGPT explained that "flutter run
is used to run your Flutter application, while flutter pub run
is used to execute scripts or executables provided by packages in your project". I am in no way qualified to judge on that but if there's other newbies like me who got confused, this might help. Cheers
Hi,
if u not set the themes property:
@Tailor(themes: ['light', 'dark'])
just type this:
@Tailor
you will receive the following error message and the tailor file not generated:
type 'Null' is not a subtype of type 'List<dynamic>' in type cast
regards
Is there any know limitations why Tailor doesn't support non-list types for @Tailor
approach?
I guess using non-list types can reduce boilerplate in case when we have the same value for all themes.
For example:
From
@Tailor()
class _$AppTheme {
static const padding = EdgeInsets.only(right: 4);
}
To
class AppTheme extends ThemeExtension<AppTheme> {
const AppTheme({
required this.padding,
});
final EdgeInsets padding;
static final AppTheme light = AppTheme(
padding: _$AppTheme.padding,
);
static final AppTheme dark = AppTheme(
padding: _$AppTheme.padding,
);
static final themes = [
light,
dark,
];
...
}
I believe it looks much better then using a list and copying the same values twice.
Thoughts?
Given
@tailor
class _$BoxStyle {
static List<Color?> background = [
TOfflineColors.lightGrey,
TOfflineColorsDark.lightBlack,
];
}
leads to
class BoxStyle extends ThemeExtension<BoxStyle> {
const BoxStyle({
required this.background, // this is required but nullable
});
final Color? background;
// ...
}
Is it possible to make background
not beeing required
?
As you can see below final dynamic buttonTheme;
of dynamic type is being generated.
// ignore_for_file: unused_element, unused_field
import 'package:client_flutter/barrel.dart';
part 'button_theme.tailor.dart';
@TailorComponent(themes: [])
class _$ButtonTheme {
static const List<TextStyle> textStyle = [];
static const List<Color> color = [];
static const List<double> height = [];
}
// ignore_for_file: unused_element, unused_field
import 'package:client_flutter/barrel.dart';
part 'theme.tailor.dart';
@TailorComponent(themes: [])
class _$GluTheme {
static const List<GluButtonTheme> buttonTheme = [];
}
class GluTheme extends ThemeExtension<GluTheme> with DiagnosticableTreeMixin {
const GluTheme({
required this.buttonTheme,
});
final dynamic buttonTheme;
@override
GluTheme copyWith({
dynamic buttonTheme,
}) {
return GluTheme(
buttonTheme: buttonTheme ?? this.buttonTheme,
);
}
Hi,
theme_tailor
depends on analyzer >=3.0.0 <5.0.0
More packages depends on analyzer >=5.1.0 <5.2.0
.
Could you please up version for analyzer?
Thanks!
flutter 3.0.2
theme_tailor_annotation 1.0.0
theme_tailor 1.0.1
Example code:
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:theme_tailor_annotation/theme_tailor_annotation.dart';
part 'ng_theme.tailor.dart';
@Tailor(
themes: ['light'],
themeGetter: ThemeGetter.onBuildContext,
)
class _$NgTheme {
static const List<Color> test = [Colors.black];
}
Generated code:
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint, unused_element
part of 'ng_theme.dart';
// **************************************************************************
// ThemeTailorGenerator
// **************************************************************************
class NgTheme extends ThemeExtension<NgTheme> {
NgTheme({
required this.test,
});
final Color test;
static final NgTheme light = NgTheme(
test: _$NgTheme.test[0],
);
@override
NgTheme copyWith({
Color? test,
}) {
return NgTheme(
test: test ?? this.test,
);
}
@override
NgTheme lerp(ThemeExtension<NgTheme>? other, double t) {
if (other is! NgTheme) return this;
return NgTheme(
test: Color.lerp(test, other.test, t)!,
);
}
}
extension NgThemeBuildContext on BuildContext {
NgTheme get ngTheme => Theme.of(this).extension<NgTheme>()!;
}
Expected result:
debugFillProperties must be generated
operator == must be generated
hashCode must be generated
Hello, the problem is that colors contained in classes, which are added to theme_tailor, while the theme is switching, are switching with some delay, and the transition is sharper.
Here's an example:
static List<SettingsButtonStyles> settingsButton = [
SettingsButtonLightStyles(),
SettingsButtonDarkStyles(),
];
abstract class SettingsButtonStyles {
final Color title;
final Color icon;
final Color subtitle;
final Color? background;
final Color border;
SettingsButtonStyles
this.title, this.background, this.subtitle, this.icon, this.border);
}
class SettingsButtonLightStyles implements SettingsButtonStyles {
...
}
How to fix it?
Hi, thanks for this great package!
I'm getting an exception from theme_tailor
when running the usual flutter packages pub run build_runner build --delete-conflicting-outputs
, after upgrading to the latest flutter stable release (3.3.0). Downgrading to flutter 3.0.5 (without any other code changes) fixes the issue and build_runner
again completes successfully.
I have a more complex theme template, but from the stacktrace it doesn't seem to be related to any particular thing in the template. Also, for me it is reproducible even with very simple template, e.g.
@Tailor(themes: ["light"], themeGetter: ThemeGetter.onBuildContext)
class _$AppColors {
static List<Color> background = const [Color(0xFFFFFFFF)];
static List<Color> onBackground = const [Color(0xFF3C3C3B)];
}
This is the error (obtained with appending --verbose
to the mentioned build_runner
command)
[SEVERE] theme_tailor:theme_tailor on lib/common/resources/tailor_theme_extensions.dart (cached):
Stack Overflow
dart:core new _GrowableList.of
package:analyzer/src/dart/element/element.dart 4374:10 LibraryElementImpl._partUnits
package:analyzer/src/dart/element/element.dart 4364:10 LibraryElementImpl.units
package:analyzer/src/dart/element/element.dart 4348:22 LibraryElementImpl.topLevelElements
dart:collection ListMixin.any
. ...
. ...
dart:collection ListMixin.any
package:theme_tailor/src/util/import_finder.dart 51:34 ImportFinder._isExportedRecursivaly
dart:collection ListMixin.any
package:theme_tailor/src/util/import_finder.dart 51:34 ImportFinder._isExportedRecursivaly
dart:collection ListMixin.any
package:theme_tailor/src/util/import_finder.dart 51:34 ImportFinder._isExportedRecursivaly
dart:collection ListMixin.any
package:theme_tailor/src/util/import_finder.dart 51:34 ImportFinder._isExportedRecursivaly
dart:collection ListMixin.any
package:theme_tailor/src/util/import_finder.dart 51:34 ImportFinder._isExportedRecursivaly
dart:collection ListMixin.any
package:theme_tailor/src/util/import_finder.dart 51:34 ImportFinder._isExportedRecursivaly
dart:collection SetMixin.any
package:theme_tailor/src/util/import_finder.dart 41:22 ImportFinder.recursiveSearch
package:theme_tailor/src/util/extension/library_element_extension.dart 10:7 LibraryElementExtension.hasFlutterDiagnosticableImport
package:theme_tailor/src/generator/theme_tailor_generator.dart 48:36 ThemeTailorGenerator.generateForAnnotatedElement
package:source_gen/src/generator_for_annotation.dart 53:30 GeneratorForAnnotation.generate
package:source_gen/src/builder.dart 352:33 _generate
[SEVERE] Build:
Failed after 132ms
[+4382 ms] "flutter pub" took 4,449ms.
[ +2 ms] pub finished with exit code 1
[ ]
#0 throwToolExit (package:flutter_tools/src/base/common.dart:10:3)
#1 _DefaultPub.interactively (package:flutter_tools/src/dart/pub.dart:418:7)
<asynchronous suspension>
#2 PackagesPassthroughCommand.runCommand (package:flutter_tools/src/commands/packages.dart:274:5)
<asynchronous suspension>
#3 FlutterCommand.run.<anonymous closure> (package:flutter_tools/src/runner/flutter_command.dart:1209:27)
<asynchronous suspension>
#4 AppContext.run.<anonymous closure> (package:flutter_tools/src/base/context.dart:150:19)
<asynchronous suspension>
#5 CommandRunner.runCommand (package:args/command_runner.dart:209:13)
<asynchronous suspension>
#6 FlutterCommandRunner.runCommand.<anonymous closure> (package:flutter_tools/src/runner/flutter_command_runner.dart:281:9)
<asynchronous suspension>
#7 AppContext.run.<anonymous closure> (package:flutter_tools/src/base/context.dart:150:19)
<asynchronous suspension>
#8 FlutterCommandRunner.runCommand (package:flutter_tools/src/runner/flutter_command_runner.dart:229:5)
<asynchronous suspension>
#9 run.<anonymous closure>.<anonymous closure> (package:flutter_tools/runner.dart:62:9)
<asynchronous suspension>
#10 AppContext.run.<anonymous closure> (package:flutter_tools/src/base/context.dart:150:19)
<asynchronous suspension>
#11 main (package:flutter_tools/executable.dart:91:3)
<asynchronous suspension>
I'm using riverpod_lint
in my project and it declares analyzer: ">=6.0.0 <7.0.0"
When I try to create a new theme with Theme Tailor my variables are generated with type 'InvalidType'.
Details
dart run build_runner watch --delete-conflicting-outputs
Project example: https://github.com/egonm12/theme_tailor_issue
app_colors.dart
app_typography.dart
assets
folderEverything needs to be generated with annotations from ThemeTailor
Give the option manually create themes as updating them in the array won't hot reload.
In code, in theme_tailor->pubspec.yaml, its saying that analyzer: ">=4.6.0 <6.0.0" is supported, but when you use anaylzer version 5.3.1, then Color becomes dynamic.
I am writing Widgets so that the theme defined in the ThemeExtension can be overwritten in the properties of the Widget.
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:theme_tailor_annotation/theme_tailor_annotation.dart';
part 'example.tailor.dart';
@TailorMixinComponent()
class MyButtonTheme extends ThemeExtension<MyButtonTheme>
with DiagnosticableTreeMixin, _$MyButtonThemeTailorMixin {
const MyButtonTheme({
this.padding = const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
this.color,
});
@override
final EdgeInsets padding;
@override
final Color? color;
}
class MyButton extends StatelessWidget {
const MyButton({super.key, required this.child, this.onPressed, this.theme});
final Widget child;
final void Function()? onPressed;
final MyButtonTheme? theme;
@override
Widget build(BuildContext context) {
final theme = this.theme ?? MyTheme.of(context).myButtonTheme;
return GestureDetector(
onTap: onPressed,
child: Container(
padding: theme?.padding,
color: theme?.color,
child: child,
),
);
}
}
This will work fine if the developer has not set a custom padding for MyButton
in MyTheme
.
final theme = this.theme ?? MyTheme.of(context).myButtonTheme;
But if he has. this.theme
will still have the padding defined in the constructor of MyButtonTheme
and the developer would need to explicitly pass the correct value. Or would need to read the correct value from MyTheme.of(context).myButtonTheme
before passing it to MyButton
// MyTheme(myButtonTheme: MyButtonTheme(padding: const EdgeInsets.all(8)))
MyButton(
onPressed: () {},
theme: MyTheme.of(context).myButtonTheme.copyWith(
colors: Colors.green
),
child: const Text('Button'),
);
Having to use MyTheme.of(context).myButtonTheme.copyWith is not that nice. So I would like to handle this case in the Widget itself
Generate .merge
for Themes, so theme can be merged.
final theme = this.theme.merge( MyTheme.of(context).myButtonTheme);
I will write the merge function myself. But It would be nice to have it autogenerated
@TailorMixinComponent()
class MyButtonTheme extends ThemeExtension<MyButtonTheme>
with DiagnosticableTreeMixin, _$MyButtonThemeTailorMixin {
const MyButtonTheme({
this.padding = const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
this.color,
});
@override
final EdgeInsets padding;
@override
final Color? color;
MyButtonTheme merge(MyButtonTheme other) {
// defalutTheme is used to take Properties defined in the Constructor to account
const defaultTheme = MyButtonTheme();
return MyButtonTheme(
padding: padding == defaultTheme.padding ? other.padding : padding,
color: other.color ?? color,
);
}
}
All
When running the generator on a const theme like this:
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart' show Theme, ThemeExtension;
import 'package:flutter/widgets.dart';
import 'package:theme_tailor_annotation/theme_tailor_annotation.dart';
part 'color_theme.tailor.dart';
@Tailor(requireStaticConst: true)
class _$ColorTheme {
static const primary = [
Color(0xFFFFFFFF),
Color(0xFF222222),
];
static const secondary = [
Color(0xFF3277B4),
Color(0xFF284D72),
];
}
leads to dart(unused_element)
.
I'm not sure if this would be possible, but it would be cool if documentation comments added to the properties in the class annotated with @tailor
were copied to the generated class. For example:
@tailor
class _$MyTheme{
/// A documentation comment.
static List<Color> customColor = [Colors.red, Colors.blue];
}
generates:
class MyTheme extends ThemeExtension<Colors> {
...
/// A documentation comnent.
final Color customColor;
...
}
I have the following extension:
@TailorMixin(themeGetter: ThemeGetter.none)
class ScanButtonTheme extends ThemeExtension<ScanButtonTheme> with DiagnosticableTreeMixin, _$ScanButtonThemeTailorMixin {
ScanButtonTheme({
this.backgroundColor = StyleGuideColors.secondary,
this.iconColor = StyleGuideColors.primary,
required TextStyle textStyle,
}) : _textStyle = textStyle;
@override
final Color backgroundColor;
@override
final Color iconColor;
@override
final TextStyle _textStyle;
@override
TextStyle get textStyle => _textStyle.copyWith(color: iconColor);
}
I used this approach to guarantee the button text and icon always have the same color. Problem is, the code generation doesn't understand that and write uncompilable code:
mixin _$ScanButtonThemeTailorMixin on ThemeExtension<ScanButtonTheme>, DiagnosticableTreeMixin {
Color get backgroundColor;
Color get iconColor;
TextStyle get _textStyle;
TextStyle get textStyle;
@override
ScanButtonTheme copyWith({
Color? backgroundColor,
Color? iconColor,
TextStyle? _textStyle,
TextStyle? textStyle,
}) {
return ScanButtonTheme(
backgroundColor: backgroundColor ?? this.backgroundColor,
iconColor: iconColor ?? this.iconColor,
textStyle: textStyle ?? this.textStyle,
);
}...
which ends in the following error:
lib/design/theme/app_themes/theme_extensions/scan_button_theme.tailor.dart:22:16: Error: An optional named parameter can't start with '_'. TextStyle? _textStyle,
Like other kind of ThemeData
. eg: IconTheme
, ChipTheme
, etc.
we can create a widget for override ThemeExtension
.
part of '../icon_button.dart';
@Tailor(
encoders: [
FiveTonedSaveDayColorThemeEncoder(),
DoubleOrNullTailorEncoder(),
EdgeInsetsOrNullTailorEncoder(),
],
)
@tailorMixin
class PrimaryIconButtonTheme extends ThemeExtension<PrimaryIconButtonTheme> with _$PrimaryIconButtonThemeTailorMixin {
const PrimaryIconButtonTheme({
required this.color,
required this.radius,
required this.padding,
required this.size,
});
static final defaultPrimaryIconButtonTheme = PrimaryIconButtonTheme(
color: SaveDayColors.defaultSaveDayColors.yellow,
radius: null,
padding: null,
size: ButtonSize.s,
);
@override
final FiveTonedSaveDayColor color;
@override
final double? radius;
@override
final EdgeInsets? padding;
@override
final ButtonSize size;
}
The generated code might look like this. I don't know what the most optimal way to do it is. Just my naive approach.
class PrimaryIconButtonThemeOverride extends StatelessWidget {
const PrimaryIconButtonThemeOverride({
super.key,
required this.data,
required this.child,
});
final PrimaryIconButtonTheme data;
final Widget child;
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final extensions = {...theme.extensions}..[PrimaryIconButtonTheme] = data;
return Theme(
data: theme.copyWith(extensions: extensions.values),
child: child,
);
}
}
class AnimatedPrimaryIconButtonThemeOverride extends StatelessWidget {
const AnimatedPrimaryIconButtonThemeOverride({
super.key,
required this.data,
required this.child,
});
final PrimaryIconButtonTheme data;
final Widget child;
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final extensions = {...theme.extensions}..[PrimaryIconButtonTheme] = data;
return AnimatedTheme(
data: theme.copyWith(extensions: extensions.values),
child: child,
);
}
}
I have the following extension:
@tailorMixinComponent
class MyColors extends ThemeExtension<EpColors> with DiagnosticableTreeMixin, _$MyColorsTailorMixin {
const MyColors({
required this.primary
required this.secondary
});
@override
final Color primary;
@override
final Color secondary;
// other colors...
}
I need to create a color picker with all the colors defined in MyColors
. It would be really helpful if the generator could generate a property like the following:
static const values = <String, Color>{
'primary': primary,
'secondary': secondary,
// other colors...
}
I am not sure how this would work if there are properties of different types, maybe the map could be <String, dynamic>
and then the values are casted to the correct type. If the type is the same for all properties it should be easy.
Generating Flutter diagnosticable / debugFillProperties works well in most cases.
But when having an other flutter import before the package:flutter/foundation.dart
import like so:
import 'package:flutter/animation.dart'; // even import 'package:flutter/widgets.dart' or other flutter imports break it
import 'package:flutter/foundation.dart';
The diagnosticable / debugFillProperties are not generated.
Hint:
None flutter imports work fine:
import 'package:aaa:aaa.dart'; // or import 'package:zzz:zzz.dart'; work fine
import 'package:flutter/foundation.dart';
Is it possible to document the properties in the generated .tailor file?
For example
@tailor
class _$BoxTheme {
/// Some documentation foo bar
static List<Color> backgroundColor = [
Colors.red,
Colors.blue,
];
}
should lead to
class BoxTheme extends ThemeExtension<BoxTheme> {
const BoxTheme({
required this.backgroundColor,
});
/// Some documentation foo bar
final Color backgroundColor;
/// ...
}
Given:
https://github.com/Iteo/theme_tailor/blob/main/packages/theme_tailor/example/lib/diagnosticable.dart
The generated file looks like this:
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint, unused_element
part of 'diagnosticable.dart';
// **************************************************************************
// ThemeTailorGenerator
// **************************************************************************
class MyTheme extends ThemeExtension<MyTheme> {
const MyTheme({
required this.background,
required this.textStyle,
});
final Color background;
final TextStyle textStyle;
static final MyTheme light = MyTheme(
background: _$MyTheme.background[0],
textStyle: _$MyTheme.textStyle[0],
);
static final MyTheme dark = MyTheme(
background: _$MyTheme.background[1],
textStyle: _$MyTheme.textStyle[1],
);
static final themes = [
light,
dark,
];
@override
MyTheme copyWith({
Color? background,
TextStyle? textStyle,
}) {
return MyTheme(
background: background ?? this.background,
textStyle: textStyle ?? this.textStyle,
);
}
@override
MyTheme lerp(ThemeExtension<MyTheme>? other, double t) {
if (other is! MyTheme) return this;
return MyTheme(
background: Color.lerp(background, other.background, t)!,
textStyle: TextStyle.lerp(textStyle, other.textStyle, t)!,
);
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is MyTheme &&
const DeepCollectionEquality()
.equals(background, other.background) &&
const DeepCollectionEquality().equals(textStyle, other.textStyle));
}
@override
int get hashCode {
return Object.hash(
runtimeType,
const DeepCollectionEquality().hash(background),
const DeepCollectionEquality().hash(textStyle));
}
}
extension MyThemeBuildContextProps on BuildContext {
MyTheme get _myTheme => Theme.of(this).extension<MyTheme>()!;
Color get background => _myTheme.background;
TextStyle get textStyle => _myTheme.textStyle;
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.