Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"height": 500,
"decoration": {
"gradient": {
"gradientType": "linear",
"colors": [
"#00050608",
"#050608",
Expand Down Expand Up @@ -55,7 +56,7 @@
"style": "displayMedium",
"children": [
{
"data": "\nDatabase",
"text": "\nDatabase",
"style": {
"color": "primary"
}
Expand Down
4 changes: 2 additions & 2 deletions examples/movie_app/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -98,14 +98,14 @@ final Map<String, dynamic> darkThemeJson = {
"minimumSize": {"width": 120, "height": 40},
"textStyle": {"fontSize": 16, "fontWeight": "w500", "height": 1.3},
"padding": {"left": 10, "right": 10, "top": 8, "bottom": 8},
"shape": {"borderRadius": 8},
"shape": {"type": "roundedRectangleBorder", "borderRadius": 8},
},
"outlinedButtonTheme": {
"minimumSize": {"width": 120, "height": 40},
"textStyle": {"fontSize": 16, "fontWeight": "w500", "height": 1.3},
"padding": {"left": 10, "right": 10, "top": 8, "bottom": 8},
"side": {"color": "#95E183", "width": 1.0},
"shape": {"borderRadius": 8},
"shape": {"type": "roundedRectangleBorder", "borderRadius": 8},
},
"dividerTheme": {"color": "#24FFFFFF", "thickness": 1},
};
83 changes: 61 additions & 22 deletions packages/stac/lib/src/parsers/painting/stac_text_style_parser.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,67 @@ import 'package:stac/src/utils/color_utils.dart';
import 'package:stac_core/stac_core.dart';

extension StacTextStyleParser on StacTextStyle {
TextStyle parse(BuildContext context) {
return TextStyle(
inherit: inherit ?? true,
color: color?.toColor(context),
backgroundColor: backgroundColor.toColor(context),
fontSize: fontSize,
fontWeight: fontWeight?.parse,
fontStyle: fontStyle?.parse,
letterSpacing: letterSpacing,
wordSpacing: wordSpacing,
textBaseline: textBaseline?.parse,
height: height,
leadingDistribution: leadingDistribution?.parse,
decorationColor: decorationColor?.toColor(context),
decorationStyle: decorationStyle?.parse,
decorationThickness: decorationThickness,
debugLabel: debugLabel,
fontFamily: fontFamily,
fontFamilyFallback: fontFamilyFallback,
package: package,
overflow: overflow?.parse,
);
TextStyle? parse(BuildContext context) {
switch (type) {
case StacTextStyleType.theme:
final themeStyle = (this as StacThemeTextStyle).textTheme;
final textTheme = Theme.of(context).textTheme;
switch (themeStyle) {
case StacMaterialTextStyle.displayLarge:
return textTheme.displayLarge;
case StacMaterialTextStyle.displayMedium:
return textTheme.displayMedium;
case StacMaterialTextStyle.displaySmall:
return textTheme.displaySmall;
case StacMaterialTextStyle.headlineLarge:
return textTheme.headlineLarge;
case StacMaterialTextStyle.headlineMedium:
return textTheme.headlineMedium;
case StacMaterialTextStyle.headlineSmall:
return textTheme.headlineSmall;
case StacMaterialTextStyle.titleLarge:
return textTheme.titleLarge;
case StacMaterialTextStyle.titleMedium:
return textTheme.titleMedium;
case StacMaterialTextStyle.titleSmall:
return textTheme.titleSmall;
case StacMaterialTextStyle.bodyLarge:
return textTheme.bodyLarge;
case StacMaterialTextStyle.bodyMedium:
return textTheme.bodyMedium;
case StacMaterialTextStyle.bodySmall:
return textTheme.bodySmall;
case StacMaterialTextStyle.labelLarge:
return textTheme.labelLarge;
case StacMaterialTextStyle.labelMedium:
return textTheme.labelMedium;
case StacMaterialTextStyle.labelSmall:
return textTheme.labelSmall;
}
case StacTextStyleType.custom:
final style = this as StacCustomTextStyle;
return TextStyle(
inherit: style.inherit ?? true,
color: style.color?.toColor(context),
backgroundColor: style.backgroundColor?.toColor(context),
fontSize: style.fontSize,
fontWeight: style.fontWeight?.parse,
fontStyle: style.fontStyle?.parse,
letterSpacing: style.letterSpacing,
wordSpacing: style.wordSpacing,
textBaseline: style.textBaseline?.parse,
height: style.height,
leadingDistribution: style.leadingDistribution?.parse,
decorationColor: style.decorationColor?.toColor(context),
decorationStyle: style.decorationStyle?.parse,
decorationThickness: style.decorationThickness,
debugLabel: style.debugLabel,
fontFamily: style.fontFamily,
fontFamilyFallback: style.fontFamilyFallback,
package: style.package,
overflow: style.overflow?.parse,
);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import 'package:stac/src/framework/framework.dart';
import 'package:stac/src/parsers/painting/stac_text_style_parser.dart';
import 'package:stac/src/parsers/types/type_parser.dart';
import 'package:stac/src/utils/color_utils.dart';
import 'package:stac_core/stac_core.dart';
import 'package:stac_core/foundation/specifications/widget_type.dart';
import 'package:stac_core/foundation/text/stac_text_style/stac_text_style.dart';
import 'package:stac_core/widgets/text/stac_text.dart';
import 'package:stac_framework/stac_framework.dart';

class StacTextParser extends StacParser<StacText> {
Expand All @@ -20,7 +22,7 @@ class StacTextParser extends StacParser<StacText> {
Widget parse(BuildContext context, StacText model) {
return Text.rich(
_buildTextSpan(context, model),
style: model.style?.parse(context),
style: _resolveStyle(context, model.style, model.copyWithStyle),
textAlign: model.textAlign?.parse,
textDirection: model.textDirection?.parse,
softWrap: model.softWrap,
Expand All @@ -36,12 +38,13 @@ class StacTextParser extends StacParser<StacText> {
}

TextSpan _buildTextSpan(BuildContext context, StacText model) {
var children = model.children ?? [];
return TextSpan(
text: model.data,
children: model.children.map((child) {
children: children.map((child) {
return TextSpan(
text: child.text,
style: model.style?.parse(context),
style: child.style?.parse(context),
recognizer: child.onTap != null
? (TapGestureRecognizer()
..onTap = () => Stac.onCallFromJson(child.onTap, context))
Expand All @@ -50,4 +53,38 @@ class StacTextParser extends StacParser<StacText> {
}).toList(),
);
}

TextStyle? _resolveStyle(
BuildContext context,
StacTextStyle? base,
StacCustomTextStyle? override,
) {
final baseStyle = base?.parse(context);
if (override == null) return baseStyle;

final overrideParsed = override.parse(context);
if (overrideParsed == null) return baseStyle;
if (baseStyle == null) return overrideParsed;

return baseStyle.copyWith(
inherit: override.inherit,
color: overrideParsed.color,
backgroundColor: overrideParsed.backgroundColor,
fontSize: overrideParsed.fontSize,
fontWeight: overrideParsed.fontWeight,
fontStyle: overrideParsed.fontStyle,
letterSpacing: overrideParsed.letterSpacing,
wordSpacing: overrideParsed.wordSpacing,
textBaseline: overrideParsed.textBaseline,
height: overrideParsed.height,
leadingDistribution: overrideParsed.leadingDistribution,
decorationColor: overrideParsed.decorationColor,
decorationStyle: overrideParsed.decorationStyle,
decorationThickness: overrideParsed.decorationThickness,
debugLabel: overrideParsed.debugLabel,
fontFamily: overrideParsed.fontFamily,
fontFamilyFallback: overrideParsed.fontFamilyFallback,
overflow: overrideParsed.overflow,
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import 'package:json_annotation/json_annotation.dart';
import 'package:stac_core/foundation/text/stac_text_style/stac_text_style.dart';
import 'package:stac_logger/stac_logger.dart';

/// A JSON converter that converts style values to [StacTextStyle].
///
/// Handles different input formats:
/// - String (e.g., "bodyMedium") -> [StacThemeTextStyle]
/// - Object (e.g., {"color": "#FF2196F3"}) -> [StacCustomTextStyle]
/// - null -> null
/// - [StacTextStyle] values -> pass through
class StacTextStyleConverter implements JsonConverter<StacTextStyle?, dynamic> {
/// Creates a [StacTextStyleConverter] that converts style values to [StacTextStyle].
const StacTextStyleConverter();

@override
StacTextStyle? fromJson(dynamic json) {
if (json == null) return null;

if (json is StacTextStyle) return json;

if (json is String) {
for (final value in StacMaterialTextStyle.values) {
if (value.name == json) {
return StacTextStyle.fromTheme(textTheme: value);
}
}

Log.w(
'StacTextStyleConverter: Invalid theme style string "$json". '
'Valid values are: ${StacMaterialTextStyle.values.map((e) => e.name).join(', ')}. '
'Returning null.',
);
return null;
}

if (json is Map<String, dynamic>) {
try {
if (json.containsKey('type')) {
return StacTextStyle.fromJson(json);
} else {
return StacCustomTextStyle.fromJson(json);
}
} catch (e) {
Log.w(
'StacTextStyleConverter: Failed to parse style object: $json. '
'Error: $e. Returning null.',
);
return null;
}
}

Log.w(
'StacTextStyleConverter: Unexpected type ${json.runtimeType} for style value: $json. '
'Expected theme TextStyle key or custom TextStyle. Returning null.',
);
return null;
}

@override
dynamic toJson(StacTextStyle? object) => object?.toJson();
}
Loading
Loading