Skip to content

Commit

Permalink
Merge pull request #46 from alsterverse/fix/storyblok-bug-handling
Browse files Browse the repository at this point in the history
Handle storyblok rich text copy-paste bug
  • Loading branch information
PhiFry authored Sep 3, 2024
2 parents a3425f0 + 6c09634 commit e181833
Show file tree
Hide file tree
Showing 9 changed files with 146 additions and 29 deletions.
2 changes: 1 addition & 1 deletion example/lib/components/grid_card.dart
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class GridCardWidget extends StatelessWidget {

return Container(
decoration: BoxDecoration(
color: hexColor.isEmpty ? AppColors.white : HexColor(hexColor),
color: hexColor.isEmpty ? AppColors.white : StoryblokColor.fromString(hexColor),
boxShadow: [
BoxShadow(
color: AppColors.black.withOpacity(0.1),
Expand Down
18 changes: 9 additions & 9 deletions lib/src/fields/rich_text.dart
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ final class RichTextLeafImage extends RichTextLeafMarkable implements RichTextLe
source: json["source"],
alt: json["alt"],
copyright: json["copyright"],
metadata: JSONMap.from(json["meta_data"]),
metadata: JSONMap.from(tryCast(json["meta_data"]) ?? {}),
marks: RichTextLeafMarkable.marksFromJson(json),
);
}
Expand Down Expand Up @@ -310,23 +310,23 @@ final class RichTextLeafMarkLink implements RichTextLeafMark {
}

final class RichTextLeafMarkTextStyle implements RichTextLeafMark {
RichTextLeafMarkTextStyle({required this.colorHex});
RichTextLeafMarkTextStyle({required this.colorString});
factory RichTextLeafMarkTextStyle.fromJson(JSONMap json) => RichTextLeafMarkTextStyle(
colorHex: json["attrs"]["color"],
colorString: json["attrs"]["color"],
);

/// CSS style color hex e.g. "#FAFAFA"
final String colorHex;
/// CSS style color hex e.g. "#FAFAFA" or "rgb(255, 255, 255)"
final String colorString;
}

final class RichTextLeafMarkHighlight implements RichTextLeafMark {
RichTextLeafMarkHighlight({required this.colorHex});
RichTextLeafMarkHighlight({required this.colorString});
factory RichTextLeafMarkHighlight.fromJson(JSONMap json) => RichTextLeafMarkHighlight(
colorHex: json["attrs"]["color"],
colorString: json["attrs"]["color"],
);

/// CSS style color hex e.g. "#FAFAFA"
final String colorHex;
/// CSS style color hex e.g. "#FAFAFA" or "rgb(255, 255, 255)"
final String colorString;
}

/// Base class of markable leaves
Expand Down
14 changes: 0 additions & 14 deletions lib/src/widgets/hex_color.dart

This file was deleted.

7 changes: 3 additions & 4 deletions lib/src/widgets/rich_text.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import 'package:flutter/widgets.dart' as sb;
import 'package:flutter_storyblok/src/fields/link.dart';
import 'package:flutter_storyblok/src/fields/rich_text.dart';
import 'package:flutter_storyblok/src/utils.dart';
import 'package:flutter_storyblok/src/widgets/hex_color.dart';
import 'package:flutter_storyblok/widgets.dart';

typedef BlockBuilder = Widget Function(BuildContext context, JSONMap data);

Expand Down Expand Up @@ -153,10 +153,9 @@ extension _RichTextLeafBuildWidget on List<RichTextLeaf> {

extension _RichTextLeafMarkableWidget on RichTextLeafMarkable {
TextStyle buildTextStyle() {
final foregroundColor =
mapIfNotNull(this.foregroundColor?.colorHex, HexColor.new) ?? (link != null ? Colors.black : null);
final foregroundColor = this.foregroundColor?.color ?? (link != null ? Colors.black : null);
return TextStyle(
backgroundColor: isCode ? Colors.grey : mapIfNotNull(backgroundColor?.colorHex, HexColor.new),
backgroundColor: isCode ? Colors.grey : backgroundColor?.color,
color: foregroundColor,
fontStyle: isItalic || isCode ? FontStyle.italic : null,
fontWeight: isBold ? FontWeight.bold : null,
Expand Down
28 changes: 28 additions & 0 deletions lib/src/widgets/storyblok_color.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import 'package:flutter/material.dart';

/// Used to convert a color hex string to a Flutter Color
final class StoryblokColor extends Color {
StoryblokColor(super.value);
factory StoryblokColor.fromString(String colorString) {
final cssColorMatch = cssColorRegex.firstMatch(colorString);
if (cssColorMatch != null) return StoryblokColor(_getColorFromCSS(cssColorMatch));
return StoryblokColor(_getColorFromHex(colorString));
}

static int _getColorFromHex(String hexColor) {
hexColor = hexColor.replaceAll("#", "");
if (hexColor.length == 6) hexColor = "FF$hexColor";
return int.parse(hexColor, radix: 16);
}

static final cssColorRegex = RegExp(r"rgb\((\d{1,3}),\s?(\d{1,3}),\s?(\d{1,3})\)", caseSensitive: false);
static int _getColorFromCSS(RegExpMatch match) {
final r = int.parse(match.group(1)!);
final g = int.parse(match.group(2)!);
final b = int.parse(match.group(3)!);
return 0xFF << 8 * 3 | //
r << 8 * 2 | //
g << 8 * 1 | //
b << 8 * 0;
}
}
14 changes: 13 additions & 1 deletion lib/widgets.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,16 @@
library;

export 'src/widgets/hex_color.dart';
import 'package:flutter/material.dart';
import 'package:flutter_storyblok/src/fields/rich_text.dart';
import 'package:flutter_storyblok/src/widgets/storyblok_color.dart';

export 'src/widgets/storyblok_color.dart';
export 'src/widgets/rich_text.dart';

extension RichTextLeafMarkTextStyleColor on RichTextLeafMarkTextStyle {
Color get color => StoryblokColor.fromString(colorString);
}

extension RichTextLeafMarkHighlightColor on RichTextLeafMarkHighlight {
Color get color => StoryblokColor.fromString(colorString);
}
1 change: 1 addition & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ dependencies:

dev_dependencies:
lints: ^4.0.0
test: ^1.25.8
build_runner: ^2.4.12
69 changes: 69 additions & 0 deletions test/rich_text_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import 'package:flutter_storyblok/fields.dart';
import 'package:test/test.dart';

void main() {
group('Test parsing rich-text', () {
test('Test parse rich-text basic text', () {
final text = RichTextLeafText.fromJson({
"type": "text",
"text": "Hello world",
});
expect(text.text, "Hello world");
expect(text.anchor, null);
expect(text.backgroundColor, null);
expect(text.foregroundColor, null);
expect(text.isBold, false);
expect(text.isCode, false);
expect(text.isItalic, false);
expect(text.isStriked, false);
expect(text.isSubscript, false);
expect(text.isSuperscript, false);
expect(text.isUnderlined, false);
expect(text.link, null);
});

test('Test parse rich-text text with foreground color', () {
final text = RichTextLeafText.fromJson({
"text": "Hello world",
"marks": [
{
"type": "textStyle",
"attrs": {"color": "#FF0000"}
}
]
});
expect(text.foregroundColor!.colorString, "#FF0000");
});

test('Test parse rich-text text with foreground color css', () {
final text = RichTextLeafText.fromJson({
"text": "Hello world",
"marks": [
{
"type": "textStyle",
"attrs": {"color": "rgb(255, 0, 0)"}
}
]
});
expect(text.foregroundColor!.colorString, "rgb(255, 0, 0)");
});

test('Test parse rich-text image', () {
final image = RichTextLeafImage.fromJson({
"type": "image",
"attrs": {
"id": 123,
"alt": "hello",
"src": "https://placehold.it/100x100",
"title": "hello",
"source": "hello",
"copyright": "hello",
"meta_data": {"alt": "hello"}
}
});
expect(image.imageUrl, Uri.parse("https://placehold.it/100x100"));
expect(image.alt, "hello");
expect(image.metadata["alt"], "hello");
});
});
}
22 changes: 22 additions & 0 deletions test/storyblok_color_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import 'package:flutter_storyblok/widgets.dart';
import 'package:test/test.dart';

void main() {
group('Test parsing colors from storyblok', () {
test('Test parse color hexadecimal', () {
final color = StoryblokColor.fromString("#FF8800");
expect(color.alpha, 0xFF);
expect(color.red, 0xFF);
expect(color.green, 0x88);
expect(color.blue, 0x00);
});

test('Test parse color css', () {
final color = StoryblokColor.fromString("rgb(255, 136, 0)");
expect(color.alpha, 0xFF);
expect(color.red, 255);
expect(color.green, 136);
expect(color.blue, 0);
});
});
}

0 comments on commit e181833

Please sign in to comment.