Skip to content

Commit 022313a

Browse files
committed
Update border and hsl/named colors to nullsafety, fix orElse: bug with text decoration
1 parent acf383b commit 022313a

File tree

2 files changed

+73
-61
lines changed

2 files changed

+73
-61
lines changed

lib/src/css_parser.dart

Lines changed: 67 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import 'dart:math';
21
import 'dart:ui';
32

43
import 'package:csslib/visitor.dart' as css;
@@ -17,17 +16,21 @@ Style declarationsToStyle(Map<String?, List<css.Expression>> declarations) {
1716
style.backgroundColor = ExpressionMapping.expressionToColor(value.first) ?? style.backgroundColor;
1817
break;
1918
case 'border':
20-
List<css.LiteralTerm> borderWidths = value.whereType<css.LiteralTerm>().toList();
19+
List<css.LiteralTerm?>? borderWidths = value.whereType<css.LiteralTerm>().toList();
2120
/// List<css.LiteralTerm> might include other values than the ones we want for [BorderSide.width], so make sure to remove those before passing it to [ExpressionMapping]
22-
borderWidths.removeWhere((element) => element.text != "thin" && element.text != "medium" && element.text != "thick"
23-
&& !(element is css.LengthTerm) && !(element is css.PercentageTerm) && !(element is css.EmTerm) && !(element is css.RemTerm) && !(element is css.NumberTerm));
24-
List<css.Expression> borderColors = value.where((element) => ExpressionMapping.expressionToColor(element) != null).toList();
25-
List<css.LiteralTerm> potentialStyles = value.whereType<css.LiteralTerm>().toList();
21+
borderWidths.removeWhere((element) => element != null && element.text != "thin"
22+
&& element.text != "medium" && element.text != "thick"
23+
&& !(element is css.LengthTerm) && !(element is css.PercentageTerm)
24+
&& !(element is css.EmTerm) && !(element is css.RemTerm)
25+
&& !(element is css.NumberTerm)
26+
);
27+
List<css.Expression?>? borderColors = value.where((element) => ExpressionMapping.expressionToColor(element) != null).toList();
28+
List<css.LiteralTerm?>? potentialStyles = value.whereType<css.LiteralTerm>().toList();
2629
/// Currently doesn't matter, as Flutter only supports "solid" or "none", but may support more in the future.
2730
List<String> possibleBorderValues = ["dotted", "dashed", "solid", "double", "groove", "ridge", "inset", "outset", "none", "hidden"];
2831
/// List<css.LiteralTerm> might include other values than the ones we want for [BorderSide.style], so make sure to remove those before passing it to [ExpressionMapping]
29-
potentialStyles.removeWhere((element) => !possibleBorderValues.contains(element.text));
30-
List<css.LiteralTerm> borderStyles = potentialStyles;
32+
potentialStyles.removeWhere((element) => element != null && !possibleBorderValues.contains(element.text));
33+
List<css.LiteralTerm?>? borderStyles = potentialStyles;
3134
style.border = ExpressionMapping.expressionToBorder(borderWidths, borderStyles, borderColors);
3235
break;
3336
case 'color':
@@ -66,8 +69,15 @@ Style declarationsToStyle(Map<String?, List<css.Expression>> declarations) {
6669
textDecorationList.removeWhere((element) => element != null && element.text != "none"
6770
&& element.text != "overline" && element.text != "underline" && element.text != "line-through");
6871
List<css.Expression?>? nullableList = value;
69-
css.Expression? textDecorationColor = nullableList.firstWhere(
70-
(css.Expression? element) => element is css.HexColorTerm || element is css.FunctionTerm, orElse: () => null);
72+
css.Expression? textDecorationColor;
73+
/// orElse: will not allow me to return null (even if the compiler says its okay, it errors on runtime).
74+
/// try/catch is a workaround for this.
75+
try {
76+
textDecorationColor = nullableList.firstWhere(
77+
(css.Expression? element) => element is css.HexColorTerm || element is css.FunctionTerm);
78+
} catch (e) {
79+
textDecorationColor = null;
80+
}
7181
List<css.LiteralTerm?>? potentialStyles = value.whereType<css.LiteralTerm>().toList();
7282
/// List<css.LiteralTerm> might include other values than the ones we want for [textDecorationStyle], so make sure to remove those before passing it to [ExpressionMapping]
7383
potentialStyles.removeWhere((element) => element != null && element.text != "solid"
@@ -130,12 +140,12 @@ class DeclarationVisitor extends css.Visitor {
130140
//Mapping functions
131141
class ExpressionMapping {
132142

133-
static Border expressionToBorder(List<css.Expression> borderWidths, List<css.LiteralTerm> borderStyles, List<css.Expression> borderColors) {
143+
static Border expressionToBorder(List<css.Expression?>? borderWidths, List<css.LiteralTerm?>? borderStyles, List<css.Expression?>? borderColors) {
134144
CustomBorderSide left = CustomBorderSide();
135145
CustomBorderSide top = CustomBorderSide();
136146
CustomBorderSide right = CustomBorderSide();
137147
CustomBorderSide bottom = CustomBorderSide();
138-
if (borderWidths != null) {
148+
if (borderWidths != null && borderWidths.isNotEmpty) {
139149
top.width = expressionToBorderWidth(borderWidths.first);
140150
if (borderWidths.length == 4) {
141151
right.width = expressionToBorderWidth(borderWidths[1]);
@@ -158,7 +168,7 @@ class ExpressionMapping {
158168
right.width = expressionToBorderWidth(borderWidths.first);
159169
}
160170
}
161-
if (borderStyles != null) {
171+
if (borderStyles != null && borderStyles.isNotEmpty) {
162172
top.style = expressionToBorderStyle(borderStyles.first);
163173
if (borderStyles.length == 4) {
164174
right.style = expressionToBorderStyle(borderStyles[1]);
@@ -181,7 +191,7 @@ class ExpressionMapping {
181191
right.style = expressionToBorderStyle(borderStyles.first);
182192
}
183193
}
184-
if (borderColors != null) {
194+
if (borderColors != null && borderColors.isNotEmpty) {
185195
top.color = expressionToColor(borderColors.first);
186196
if (borderColors.length == 4) {
187197
right.color = expressionToColor(borderColors[1]);
@@ -205,24 +215,24 @@ class ExpressionMapping {
205215
}
206216
}
207217
return Border(
208-
top: BorderSide(width: top.width, color: top.color, style: top.style),
209-
right: BorderSide(width: right.width, color: right.color, style: right.style),
210-
bottom: BorderSide(width: bottom.width, color: bottom.color, style: bottom.style),
211-
left: BorderSide(width: left.width, color: left.color, style: left.style)
218+
top: BorderSide(width: top.width, color: top.color ?? Colors.black, style: top.style),
219+
right: BorderSide(width: right.width, color: right.color ?? Colors.black, style: right.style),
220+
bottom: BorderSide(width: bottom.width, color: bottom.color ?? Colors.black, style: bottom.style),
221+
left: BorderSide(width: left.width, color: left.color ?? Colors.black, style: left.style)
212222
);
213223
}
214224

215-
static double expressionToBorderWidth(css.LiteralTerm value) {
225+
static double expressionToBorderWidth(css.Expression? value) {
216226
if (value is css.NumberTerm) {
217-
return double.tryParse(value.text);
227+
return double.tryParse(value.text) ?? 1.0;
218228
} else if (value is css.PercentageTerm) {
219-
return double.tryParse(value.text) / 100;
229+
return (double.tryParse(value.text) ?? 400) / 100;
220230
} else if (value is css.EmTerm) {
221-
return double.tryParse(value.text);
231+
return double.tryParse(value.text) ?? 1.0;
222232
} else if (value is css.RemTerm) {
223-
return double.tryParse(value.text);
233+
return double.tryParse(value.text) ?? 1.0;
224234
} else if (value is css.LengthTerm) {
225-
return double.tryParse(value.text.replaceAll(new RegExp(r'\s+(\d+\.\d+)\s+'), ''));
235+
return double.tryParse(value.text.replaceAll(new RegExp(r'\s+(\d+\.\d+)\s+'), '')) ?? 1.0;
226236
} else if (value is css.LiteralTerm) {
227237
switch (value.text) {
228238
case "thin":
@@ -233,27 +243,29 @@ class ExpressionMapping {
233243
return 6.0;
234244
}
235245
}
236-
return null;
246+
return 4.0;
237247
}
238248

239-
static BorderStyle expressionToBorderStyle(css.LiteralTerm value) {
240-
if (value.text != "none" && value.text != "hidden") {
249+
static BorderStyle expressionToBorderStyle(css.LiteralTerm? value) {
250+
if (value != null && value.text != "none" && value.text != "hidden") {
241251
return BorderStyle.solid;
242252
}
243253
return BorderStyle.none;
244254
}
245255

246-
static Color? expressionToColor(css.Expression value) {
247-
if (value is css.HexColorTerm) {
248-
return stringToColor(value.text);
249-
} else if (value is css.FunctionTerm) {
250-
if (value.text == 'rgba' || value.text == 'rgb') {
251-
return rgbOrRgbaToColor(value.span!.text);
252-
} else if (value.text == 'hsla' || value.text == 'hsl') {
253-
return hslToRgbToColor(value.span!.text);
256+
static Color? expressionToColor(css.Expression? value) {
257+
if (value != null) {
258+
if (value is css.HexColorTerm) {
259+
return stringToColor(value.text);
260+
} else if (value is css.FunctionTerm) {
261+
if (value.text == 'rgba' || value.text == 'rgb') {
262+
return rgbOrRgbaToColor(value.span!.text);
263+
} else if (value.text == 'hsla' || value.text == 'hsl') {
264+
return hslToRgbToColor(value.span!.text);
265+
}
266+
} else if (value is css.LiteralTerm) {
267+
return namedColorToColor(value.text);
254268
}
255-
} else if (value is css.LiteralTerm) {
256-
return namedColorToColor(value.text);
257269
}
258270
return null;
259271
}
@@ -562,28 +574,31 @@ class ExpressionMapping {
562574
}
563575

564576
static Color hslToRgbToColor(String text) {
565-
print(text);
566577
final hslText = text.replaceAll(')', '').replaceAll(' ', '');
567578
final hslValues = hslText.split(',').toList();
568-
List<double> parsedHsl = [];
579+
List<double?> parsedHsl = [];
569580
hslValues.forEach((element) {
570-
if (element.contains("%")) {
571-
parsedHsl.add(double.tryParse(element.replaceAll("%", "")) * 0.01);
581+
if (element.contains("%") && double.tryParse(element.replaceAll("%", "")) != null) {
582+
parsedHsl.add(double.tryParse(element.replaceAll("%", ""))! * 0.01);
572583
} else {
573-
parsedHsl.add(double.tryParse(element));
584+
if (element != hslValues.first && (double.tryParse(element) == null || double.tryParse(element)! > 1)) {
585+
parsedHsl.add(null);
586+
} else {
587+
parsedHsl.add(double.tryParse(element));
588+
}
574589
}
575590
});
576-
if (parsedHsl.length == 4) {
577-
return HSLColor.fromAHSL(parsedHsl.last, parsedHsl.first, parsedHsl[1], parsedHsl[2]).toColor();
578-
}
579-
return HSLColor.fromAHSL(1.0, parsedHsl.first, parsedHsl[1], parsedHsl.last).toColor();
591+
if (parsedHsl.length == 4 && !parsedHsl.contains(null)) {
592+
return HSLColor.fromAHSL(parsedHsl.last!, parsedHsl.first!, parsedHsl[1]!, parsedHsl[2]!).toColor();
593+
} else if (parsedHsl.length == 3 && !parsedHsl.contains(null)) {
594+
return HSLColor.fromAHSL(1.0, parsedHsl.first!, parsedHsl[1]!, parsedHsl.last!).toColor();
595+
} else return Colors.black;
580596
}
581597

582-
static Color namedColorToColor(String text) {
583-
String namedColor = namedColors.keys.firstWhere((element) => element.toLowerCase() == text.toLowerCase(), orElse: () => null);
584-
if (namedColor != null) {
585-
return stringToColor(namedColors[namedColor]);
586-
}
587-
return null;
598+
static Color? namedColorToColor(String text) {
599+
String namedColor = namedColors.keys.firstWhere((element) => element.toLowerCase() == text.toLowerCase(), orElse: () => "");
600+
if (namedColor != "") {
601+
return stringToColor(namedColors[namedColor]!);
602+
} else return null;
588603
}
589604
}

lib/src/utils.dart

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import 'dart:convert';
2+
import 'dart:math';
3+
14
import 'package:flutter/gestures.dart';
25
import 'package:flutter/material.dart';
36

@@ -20,9 +23,6 @@ Map<String, String> namedColors = {
2023
"Purple": "#800080",
2124
};
2225

23-
import 'dart:math';
24-
import 'dart:convert';
25-
2626
class Context<T> {
2727
T data;
2828

@@ -70,14 +70,11 @@ class MultipleTapGestureRecognizer extends TapGestureRecognizer {
7070
class CustomBorderSide {
7171
CustomBorderSide({
7272
this.color = const Color(0xFF000000),
73-
this.width = 4.0,
73+
this.width = 1.0,
7474
this.style = BorderStyle.none,
75-
}) : assert(color != null),
76-
assert(width != null),
77-
assert(width >= 0.0),
78-
assert(style != null);
75+
}) : assert(width >= 0.0);
7976

80-
Color color;
77+
Color? color;
8178
double width;
8279
BorderStyle style;
8380
}

0 commit comments

Comments
 (0)