Skip to content

Commit 88787be

Browse files
authored
patch: Themes preprocessor improve (#28)
* Added the ability to pass functions to the theme preprocessor to create tokens for custom widgets and override the creation of tokens for existing widgets * Upd tests
1 parent 12f0733 commit 88787be

File tree

6 files changed

+349
-110
lines changed

6 files changed

+349
-110
lines changed

lib/src/ui/theme/index.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
export 'theme.dart';
22
export 'theme_override_rule.dart';
33
export 'theme_loader.dart';
4+
export 'preprocessor.dart';
5+
export "theme_token.dart";

lib/src/ui/theme/preprocessor.dart

Lines changed: 102 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,88 @@
11
import 'package:duit_kernel/src/ui/theme/index.dart';
2-
import 'package:duit_kernel/src/ui/theme/theme_token.dart';
2+
3+
/// Function for custom tokenization of themes.
4+
typedef CustomTokenizer = ThemeToken? Function(
5+
String type,
6+
Map<String, dynamic> themeData,
7+
);
38

49
final class ThemePreprocessor {
10+
final CustomTokenizer? customWidgetTokenizer, overrideWidgetTokenizer;
11+
12+
const ThemePreprocessor({
13+
this.customWidgetTokenizer,
14+
this.overrideWidgetTokenizer,
15+
});
16+
17+
///Creates token for default cases
18+
ThemeToken _createToken(
19+
String widgetType,
20+
Map<String, dynamic> themeData,
21+
) {
22+
return switch (widgetType) {
23+
"Text" => TextThemeToken(
24+
themeData,
25+
),
26+
"Image" => ImageThemeToken(
27+
themeData,
28+
),
29+
"Align" ||
30+
"BackdropFilter" ||
31+
"ColoredBox" ||
32+
"ConstrainedBoxAttributes" ||
33+
"DecoratedBox" ||
34+
"Expanded" ||
35+
"FittedBox" ||
36+
"Row" ||
37+
"Column" ||
38+
"SizedBox" ||
39+
"Container" ||
40+
"OverflowBox" ||
41+
"Padding" ||
42+
"Positioned" ||
43+
"Opacity" ||
44+
"RotatedBox" ||
45+
"Stack" ||
46+
"Wrap" ||
47+
"Transform" =>
48+
AnimatedPropOwnerThemeToken(
49+
themeData,
50+
widgetType,
51+
),
52+
"AnimatedOpacity" => ImplicitAnimatableThemeToken(
53+
themeData,
54+
widgetType,
55+
),
56+
"ElevatedButton" ||
57+
"Center" ||
58+
"IgnorePointerAttributes" ||
59+
"RepaintBoundary" ||
60+
"SingleChildScrollView" =>
61+
DefaultThemeToken(
62+
themeData,
63+
widgetType,
64+
),
65+
"CheckboxAttributes" ||
66+
"Switch" ||
67+
"TextField" =>
68+
AttendedWidgetThemeToken(
69+
themeData,
70+
widgetType,
71+
),
72+
"RadioGroupContext" => RadioGroupContextThemeToken(
73+
themeData,
74+
),
75+
"Radio" => RadioThemeToken(
76+
themeData,
77+
),
78+
"Slider" => SliderThemeToken(
79+
themeData,
80+
),
81+
_ => customWidgetTokenizer?.call(widgetType, themeData) ??
82+
const UnknownThemeToken(),
83+
};
84+
}
85+
586
DuitTheme tokenize(Map<String, dynamic> theme) {
687
final errors = <String>{};
788
final tokens = <String, ThemeToken>{};
@@ -11,76 +92,28 @@ final class ThemePreprocessor {
1192
final themeData = theme["data"] as Map<String, dynamic>;
1293
final widgetType = theme["type"];
1394

14-
/* Ignored widget types:
15-
- AnimatedBuilder
16-
- GestureDetector
17-
- IntrinsicHeight
18-
- LifecycleStateListener
19-
- ListView
20-
- Meta
21-
- Subtree
22-
*/
23-
final ThemeToken token = switch (widgetType) {
24-
"Text" => TextThemeToken(
25-
themeData,
26-
),
27-
"Image" => ImageThemeToken(
28-
themeData,
29-
),
30-
"Align" ||
31-
"BackdropFilter" ||
32-
"ColoredBox" ||
33-
"ConstrainedBoxAttributes" ||
34-
"DecoratedBox" ||
35-
"Expanded" ||
36-
"FittedBox" ||
37-
"Row" ||
38-
"Column" ||
39-
"SizedBox" ||
40-
"Container" ||
41-
"OverflowBox" ||
42-
"Padding" ||
43-
"Positioned" ||
44-
"Opacity" ||
45-
"RotatedBox" ||
46-
"Stack" ||
47-
"Wrap" ||
48-
"Transform" =>
49-
AnimatedPropOwnerThemeToken(
50-
themeData,
51-
widgetType,
52-
),
53-
"AnimatedOpacity" => ImplicitAnimatableThemeToken(
54-
themeData,
55-
widgetType,
56-
),
57-
"ElevatedButton" ||
58-
"Center" ||
59-
"IgnorePointerAttributes" ||
60-
"RepaintBoundary" ||
61-
"SingleChildScrollView" =>
62-
DefaultThemeToken(
63-
themeData,
64-
widgetType,
65-
),
66-
"CheckboxAttributes" ||
67-
"Switch" ||
68-
"TextField" =>
69-
AttendedWidgetThemeToken(
70-
themeData,
95+
ThemeToken token;
96+
97+
if (overrideWidgetTokenizer != null) {
98+
final overridedToken = overrideWidgetTokenizer!(
99+
widgetType,
100+
themeData,
101+
);
102+
103+
if (overridedToken != null) {
104+
token = overridedToken;
105+
} else {
106+
token = _createToken(
71107
widgetType,
72-
),
73-
"RadioGroupContext" => RadioGroupContextThemeToken(
74-
themeData,
75-
),
76-
"Radio" => RadioThemeToken(
77-
themeData,
78-
),
79-
"Slider" => SliderThemeToken(
80108
themeData,
81-
),
82-
_ => const UnknownThemeToken(),
83-
};
109+
);
110+
}
111+
} else {
112+
token = _createToken(
113+
widgetType,
114+
themeData,
115+
);
116+
}
84117

85118
for (var entry in themeData.entries) {
86119
final key = entry.key;

lib/src/ui/theme/theme_loader.dart

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import 'dart:convert';
22

33
import 'package:duit_kernel/duit_kernel.dart';
4-
import 'package:duit_kernel/src/ui/theme/preprocessor.dart';
54
import 'package:flutter/services.dart';
65

76
final class AssetThemeLoader implements ResourceLoader<DuitTheme> {
@@ -12,7 +11,7 @@ final class AssetThemeLoader implements ResourceLoader<DuitTheme> {
1211
@override
1312
Future<DuitTheme> load() async {
1413
final theme = await rootBundle.loadString(path);
15-
final preprocessor = ThemePreprocessor();
14+
const preprocessor = ThemePreprocessor();
1615
return preprocessor.tokenize(json.decode(theme));
1716
}
1817
}
@@ -24,7 +23,7 @@ final class StaticThemeLoader implements ResourceLoader<DuitTheme> {
2423

2524
@override
2625
Future<DuitTheme> load() async {
27-
final preprocessor = ThemePreprocessor();
26+
const preprocessor = ThemePreprocessor();
2827
return preprocessor.tokenize(theme);
2928
}
3029
}

lib/src/view_attributes/view_attribute.dart

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,19 @@ final class ViewAttribute<T> {
5959
final overrideRule = ThemeOverrideRule.fromString(json["overrideRule"]);
6060

6161
if (themeKey != null) {
62-
final token = DuitRegistry.theme.getToken(
63-
themeKey,
64-
type,
65-
);
62+
ThemeToken token;
63+
64+
if (tag != null) {
65+
token = DuitRegistry.theme.getToken(
66+
themeKey,
67+
tag,
68+
);
69+
} else {
70+
token = DuitRegistry.theme.getToken(
71+
themeKey,
72+
type,
73+
);
74+
}
6675

6776
if (token is UnknownThemeToken) {
6877
return _attributeParser.parse<R>(

test/misc.dart

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,28 @@
11
import 'package:duit_kernel/duit_kernel.dart';
22

33
final class TestAttrParser implements AttributeParserBase {
4+
dynamic _parseCustom(Map<String, dynamic> data, String tag) {
5+
return const CustomAttributes();
6+
}
7+
48
@override
59
ViewAttribute<T> parse<T>(
610
String type,
711
Map<String, dynamic>? json,
812
String? tag, {
913
String? id,
1014
}) {
11-
return ViewAttribute(payload: json as T, id: id ?? "");
15+
if (tag != null) {
16+
return ViewAttribute(
17+
payload: _parseCustom(json!, tag) as T,
18+
id: id ?? "",
19+
);
20+
}
21+
22+
return ViewAttribute(
23+
payload: json as T,
24+
id: id ?? "",
25+
);
1226
}
1327
}
1428

@@ -29,3 +43,44 @@ final class TestAttributes implements DuitAttributes<TestAttributes> {
2943
throw UnimplementedError();
3044
}
3145
}
46+
47+
final class CustomAttributes implements DuitAttributes<CustomAttributes> {
48+
const CustomAttributes();
49+
50+
@override
51+
CustomAttributes copyWith(CustomAttributes other) {
52+
return const CustomAttributes();
53+
}
54+
55+
@override
56+
ReturnT dispatchInternalCall<ReturnT>(
57+
String methodName, {
58+
Iterable? positionalParams,
59+
Map<String, dynamic>? namedParams,
60+
}) {
61+
throw UnimplementedError();
62+
}
63+
}
64+
65+
final class SomeWidgetThemeToken extends ThemeToken {
66+
const SomeWidgetThemeToken(
67+
Map<String, dynamic> data,
68+
) : super(
69+
const {},
70+
data,
71+
'SomeCustomWidget',
72+
);
73+
}
74+
75+
final class OverridedTextThemeToken extends ThemeToken {
76+
const OverridedTextThemeToken(
77+
Map<String, dynamic> data,
78+
) : super(
79+
const {
80+
"data",
81+
"style",
82+
},
83+
data,
84+
'Text',
85+
);
86+
}

0 commit comments

Comments
 (0)