Skip to content

Commit

Permalink
Adding VWText component
Browse files Browse the repository at this point in the history
  • Loading branch information
carllosnc committed Apr 10, 2024
1 parent 852ea3e commit 40f726e
Show file tree
Hide file tree
Showing 7 changed files with 233 additions and 0 deletions.
62 changes: 62 additions & 0 deletions docs/vw_text.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# VWText

A widget that displays text with customizable styles for specific words.

## Usage

```dart
import 'package:vw/vw.dart';
class MyWidget extends StatelessWidget {
const MyWidget({super.key});
@override
Widget build(BuildContext context) {
return VWText(
text: "Lorem [<b><pc>bold</pc></b>] ipsum dolor sit amet. [<m>Mark</m>] consectetur adipiscing elit. [<d>Deleted</d>]",
primaryColor: Colors.red,
markColor: const Color.fromARGB(255, 196, 228, 255),
textStyle: const TextStyle(
fontSize: 20,
height: 1.6,
),
);
}
}
```

## Properties

| Property | Type | Description |
| ------------ | ------------ | ------------------------------------ |
| text | `String` | The text to display. |
| primaryColor | `Color?` | The primary color for styled words. |
| markColor | `Color?` | The color used to mark styled words. |
| textStyle | `TextStyle?` | The text style for the whole text. |

## Markup

The `VWText` widget supports markup syntax to style specific words in the text. The markup syntax is based on HTML tags and can be used to apply different styles to specific words or phrases in the text.

## Markup Syntax

The markup syntax is a combination of HTML tags and special characters. The tags are enclosed in angle brackets (`<` and `>`) and can be used to apply different styles to the text. Before marking a word or phrase, you need to enclose it in square brackes `[]` and add the appropriate tag.

**Example:**

```dart
"Lorem [<b>bold</b>] ipsum dolor sit amet."
```

In this example, the word "bold" will be styled with a bold font.

Here are some examples of how the markup syntax can be used:

- `<b>bold</b>`: This will make the text bold.
- `<i>italic</i>`: This will make the text italic.
- `<u>underline</u>`: This will underline the text.
- `<m>mark</m>`: This will mark the text with a different color.
- `<d>deleted</d>`: This will make the text deleted.
- `<o>overline</o>`: This will make the text overline.
- `<pc>primary color</pc>`: This will use the primary color for the text.
- `<uc>uppercase</uc>`: This will make the text uppercase.
2 changes: 2 additions & 0 deletions example/lib/app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import './examples/vw_select_example.dart';
import './examples/vw_modal_example.dart';
import './examples/vw_box_example.dart';
import './examples/vw_reveal_example.dart';
import './examples/vw_text_example.dart';

import 'home.dart';

Expand Down Expand Up @@ -48,6 +49,7 @@ class App extends StatelessWidget {
'/vw_modal': (context) => const VWModalExample(),
'/vw_box': (context) => const VWBoxExample(),
'/vw_reveal': (context) => const VWRevealExample(),
'/vw_text': (context) => const VWTextExample(),
},
);
}
Expand Down
34 changes: 34 additions & 0 deletions example/lib/examples/vw_text_example.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import 'package:flutter/material.dart';
import 'package:vw/vw.dart';

class VWTextExample extends StatelessWidget {
const VWTextExample({super.key});

@override
Widget build(BuildContext context) {
String interpolation = "Text to be interpolated";

return Scaffold(
appBar: AppBar(
title: const Text('Title'),
),
body: SingleChildScrollView(
child: VWColumn(
padding: const EdgeInsets.all(20),
children: [
VWText(
text:
"lorem [<b><pc><uc>bold adding more text here!</uc></pc></b>] [<b>text and here, we will add more text</b>] dolor sit amet, [<b><ol>$interpolation</b>] consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. [<b>Ut enim ad minim veniam</b>], quis nostrud exercitation ullamco [<i>laboris nisi ut aliquip</i>] ex [<m><b>ea commodo consequat</b></m>]. Duis aute irure dolor in reprehenderit in [<u><pc>voluptate</pc></u>] velit esse cillum dolore eu [<b><pc><d>fugiat nulla pariatur</b></pc></d>]. Excepteur sint occaecat cupidatat non proident, [<m><pc>sunt in culpa qui officia deserunt</pc></m>] mollit anim id est laborum. [<d>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</d>], quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. [<pc><i><d>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum</pc></i></d>] dolore eu fugiat nulla pariatur.",
primaryColor: Colors.red,
markColor: const Color.fromARGB(255, 196, 228, 255),
textStyle: const TextStyle(
fontSize: 20,
height: 1.5,
),
)
],
),
),
);
}
}
6 changes: 6 additions & 0 deletions example/lib/home.dart
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ class Home extends StatelessWidget {
Navigator.pushNamed(context, '/vw_reveal');
},
),
ListTile(
title: const Text('VW Text'),
onTap: () {
Navigator.pushNamed(context, '/vw_text');
},
)
],
),
);
Expand Down
1 change: 1 addition & 0 deletions lib/vw.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ export './vw_select.dart';
export './vw_modal.dart';
export './vw_box.dart';
export './vw_reveal.dart';
export './vw_text.dart';
106 changes: 106 additions & 0 deletions lib/vw_text.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import 'package:flutter/material.dart';

sealed class VWTextStyle {
static bool checkBold(String input) => (input.contains("<b>") && input.contains("</b>")) ? true : false;
static bool checkItalic(String input) => (input.contains("<i>") && input.contains("</i>")) ? true : false;
static bool checkUnderline(String input) => (input.contains("<u>") && input.contains("</u>")) ? true : false;
static bool checkPrimaryColor(String input) => (input.contains("<pc>") && input.contains("</pc>")) ? true : false;
static bool checkMark(String input) => (input.contains("<m>") && input.contains("</m>")) ? true : false;
static bool checkDelete(String input) => (input.contains("<d>") && input.contains("</d>")) ? true : false;
static bool checkOverline(String input) => (input.contains("<o>") && input.contains("</o>")) ? true : false;
static bool checkUppercase(String input) => (input.contains("<uc>") && input.contains("</uc>")) ? true : false;

static getTextDecoration(String input) {
if (checkUnderline(input)) return TextDecoration.underline;
if (checkDelete(input)) return TextDecoration.lineThrough;
if (checkOverline(input)) return TextDecoration.overline;

return null;
}

static String sanitize(String input) => input
.replaceAll("<b>", "") //
.replaceAll("</b>", "")
.replaceAll("<i>", "")
.replaceAll("</i>", "")
.replaceAll("<u>", "")
.replaceAll("</u>", "")
.replaceAll("<pc>", "")
.replaceAll("</pc>", "")
.replaceAll("<m>", "")
.replaceAll("</m>", "")
.replaceAll("<d>", "")
.replaceAll("</d>", "")
.replaceAll("<o>", "")
.replaceAll("</o>", "")
.replaceAll("<uc>", "")
.replaceAll("</uc>", "");
}

/// A widget that displays text with customizable styles for specific words.
///
/// The [VWText] widget allows you to display text with different styles for specific words.
/// You can customize the primary color, mark color, and text style.
class VWText extends StatefulWidget {
/// The text to display.
final String text;

/// The primary color for styled words.
final Color? primaryColor;

/// The color used to mark styled words.
final Color? markColor;

/// The text style for the whole text.
final TextStyle? textStyle;

const VWText({
super.key,
required this.text,
this.primaryColor = Colors.red,
this.markColor = const Color.fromARGB(255, 255, 192, 192),
this.textStyle,
});

@override
State<VWText> createState() => _VWTextState();
}

class _VWTextState extends State<VWText> {
TextStyle defaultStyle = const TextStyle();

@override
Widget build(BuildContext context) {
final words = widget.text.split(RegExp(r'\[|\]'));

List<TextSpan> spans = [];

for (var word in words) {
bool isUppercase = VWTextStyle.checkUppercase(word);

var style = TextStyle(
color: VWTextStyle.checkPrimaryColor(word) ? widget.primaryColor : Theme.of(context).colorScheme.onBackground,
fontWeight: VWTextStyle.checkBold(word) ? FontWeight.w900 : null,
fontStyle: VWTextStyle.checkItalic(word) ? FontStyle.italic : null,
decoration: VWTextStyle.getTextDecoration(word),
backgroundColor: VWTextStyle.checkMark(word) ? widget.markColor : null,
);

word = VWTextStyle.sanitize(word);
word = isUppercase ? word.toUpperCase() : word;

spans.add(TextSpan(
text: word,
style: style,
));
}

return RichText(
key: const Key('vw_text'),
text: TextSpan(
style: defaultStyle.merge(widget.textStyle),
children: spans,
),
);
}
}
22 changes: 22 additions & 0 deletions test/vw_text_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:vw/vw.dart';

void main() {
testWidgets('Check initial render', (tester) async {
await tester.pumpWidget(
const MaterialApp(
home: Scaffold(
body: Center(
child: VWText(
text: "[<b>bold</b>] [<i>italic</i>] [<u>underline</u>] [<m>mark</m>] [<d>deleted</d>]",
),
),
),
),
);

expect(find.byKey(const Key('vw_text')), findsOneWidget);
expect(find.byKey(const Key('vw_text')), findsNWidgets(1));
});
}

0 comments on commit 40f726e

Please sign in to comment.