diff --git a/packages/notus/lib/src/document/attributes.dart b/packages/notus/lib/src/document/attributes.dart index f2f222075..6b1b3746c 100644 --- a/packages/notus/lib/src/document/attributes.dart +++ b/packages/notus/lib/src/document/attributes.dart @@ -74,6 +74,7 @@ class NotusAttribute implements NotusAttributeBuilder { static final Map _registry = { NotusAttribute.bold.key: NotusAttribute.bold, NotusAttribute.italic.key: NotusAttribute.italic, + NotusAttribute.underline.key: NotusAttribute.underline, NotusAttribute.link.key: NotusAttribute.link, NotusAttribute.heading.key: NotusAttribute.heading, NotusAttribute.block.key: NotusAttribute.block, @@ -88,6 +89,9 @@ class NotusAttribute implements NotusAttributeBuilder { /// Italic style attribute. static const italic = _ItalicAttribute(); + /// Underline style attribute. + static const underline = _UnderlineAttribute(); + /// Link style attribute. // ignore: const_eval_throws_exception static const link = LinkAttributeBuilder._(); @@ -332,6 +336,11 @@ class _ItalicAttribute extends NotusAttribute { const _ItalicAttribute() : super._('i', NotusAttributeScope.inline, true); } +/// Applies underline style to a text segment. +class _UnderlineAttribute extends NotusAttribute { + const _UnderlineAttribute() : super._('u', NotusAttributeScope.inline, true); +} + /// Builder for link attribute values. /// /// There is no need to use this class directly, consider using diff --git a/packages/zefyr/lib/src/widgets/__theme.dart b/packages/zefyr/lib/src/widgets/__theme.dart index a62d70028..0b9ac1371 100644 --- a/packages/zefyr/lib/src/widgets/__theme.dart +++ b/packages/zefyr/lib/src/widgets/__theme.dart @@ -54,6 +54,7 @@ class ZefyrTheme extends InheritedWidget { class ZefyrThemeData { final TextStyle boldStyle; final TextStyle italicStyle; + final TextStyle underlineStyle; final TextStyle linkStyle; final StyleTheme paragraphTheme; final HeadingTheme headingTheme; @@ -75,12 +76,14 @@ class ZefyrThemeData { const padding = EdgeInsets.symmetric(vertical: 8.0); final boldStyle = TextStyle(fontWeight: FontWeight.bold); final italicStyle = TextStyle(fontStyle: FontStyle.italic); + final underlineStyle = TextStyle(decoration: TextDecoration.underline); final linkStyle = TextStyle( color: themeData.accentColor, decoration: TextDecoration.underline); return ZefyrThemeData( boldStyle: boldStyle, italicStyle: italicStyle, + underlineStyle: underlineStyle, linkStyle: linkStyle, paragraphTheme: StyleTheme(textStyle: paragraphStyle, padding: padding), headingTheme: HeadingTheme.fallback(context), @@ -95,6 +98,7 @@ class ZefyrThemeData { const ZefyrThemeData({ this.boldStyle, this.italicStyle, + this.underlineStyle, this.linkStyle, this.paragraphTheme, this.headingTheme, @@ -109,6 +113,7 @@ class ZefyrThemeData { TextStyle textStyle, TextStyle boldStyle, TextStyle italicStyle, + TextStyle underlineStyle, TextStyle linkStyle, StyleTheme paragraphTheme, HeadingTheme headingTheme, @@ -121,6 +126,7 @@ class ZefyrThemeData { return ZefyrThemeData( boldStyle: boldStyle ?? this.boldStyle, italicStyle: italicStyle ?? this.italicStyle, + underlineStyle: underlineStyle ?? this.underlineStyle, linkStyle: linkStyle ?? this.linkStyle, paragraphTheme: paragraphTheme ?? this.paragraphTheme, headingTheme: headingTheme ?? this.headingTheme, @@ -136,6 +142,7 @@ class ZefyrThemeData { return copyWith( boldStyle: other.boldStyle, italicStyle: other.italicStyle, + underlineStyle: other.underlineStyle, linkStyle: other.linkStyle, paragraphTheme: other.paragraphTheme, headingTheme: other.headingTheme, diff --git a/packages/zefyr/lib/src/widgets/common.dart b/packages/zefyr/lib/src/widgets/common.dart index 2e5cbc4f9..058bc4bc3 100644 --- a/packages/zefyr/lib/src/widgets/common.dart +++ b/packages/zefyr/lib/src/widgets/common.dart @@ -145,6 +145,9 @@ class _ZefyrLineState extends State { if (style.containsSame(NotusAttribute.italic)) { result = result.merge(theme.attributeTheme.italic); } + if (style.containsSame(NotusAttribute.underline)) { + result = result.merge(theme.attributeTheme.underline); + } if (style.contains(NotusAttribute.link)) { result = result.merge(theme.attributeTheme.link); } diff --git a/packages/zefyr/lib/src/widgets/controller.dart b/packages/zefyr/lib/src/widgets/controller.dart index 1117ab617..5350be6b6 100644 --- a/packages/zefyr/lib/src/widgets/controller.dart +++ b/packages/zefyr/lib/src/widgets/controller.dart @@ -167,7 +167,8 @@ class ZefyrController extends ChangeNotifier { if (length == 0 && (attribute.key == NotusAttribute.bold.key || - attribute.key == NotusAttribute.italic.key)) { + attribute.key == NotusAttribute.italic.key || + attribute.key == NotusAttribute.underline.key)) { // Add the attribute to our toggledStyle. It will be used later upon insertion. _toggledStyles = toggledStyles.put(attribute); } diff --git a/packages/zefyr/lib/src/widgets/theme.dart b/packages/zefyr/lib/src/widgets/theme.dart index 70b063fbc..6cbd7dbff 100644 --- a/packages/zefyr/lib/src/widgets/theme.dart +++ b/packages/zefyr/lib/src/widgets/theme.dart @@ -287,6 +287,9 @@ class AttributeTheme { /// Style used to render "italic" text. final TextStyle italic; + /// Style used to render "underline" text. + final TextStyle underline; + /// Style used to render text containing links. final TextStyle link; @@ -315,6 +318,7 @@ class AttributeTheme { AttributeTheme({ this.bold, this.italic, + this.underline, this.link, this.heading1, this.heading2, @@ -347,6 +351,7 @@ class AttributeTheme { return AttributeTheme( bold: TextStyle(fontWeight: FontWeight.bold), italic: TextStyle(fontStyle: FontStyle.italic), + underline: TextStyle(decoration: TextDecoration.underline), link: TextStyle( decoration: TextDecoration.underline, color: theme.accentColor, @@ -412,6 +417,7 @@ class AttributeTheme { AttributeTheme copyWith({ TextStyle bold, TextStyle italic, + TextStyle underline, TextStyle link, LineTheme heading1, LineTheme heading2, @@ -424,6 +430,7 @@ class AttributeTheme { return AttributeTheme( bold: bold ?? this.bold, italic: italic ?? this.italic, + underline: underline ?? this.underline, link: link ?? this.link, heading1: heading1 ?? this.heading1, heading2: heading2 ?? this.heading2, @@ -442,6 +449,7 @@ class AttributeTheme { return copyWith( bold: bold?.merge(other.bold) ?? other.bold, italic: italic?.merge(other.italic) ?? other.italic, + underline: underline?.merge(other.underline) ?? other.underline, link: link?.merge(other.link) ?? other.link, heading1: heading1?.merge(other.heading1) ?? other.heading1, heading2: heading2?.merge(other.heading2) ?? other.heading2, @@ -459,6 +467,7 @@ class AttributeTheme { final AttributeTheme otherTheme = other; return (otherTheme.bold == bold) && (otherTheme.italic == italic) && + (otherTheme.underline == underline) && (otherTheme.link == link) && (otherTheme.heading1 == heading1) && (otherTheme.heading2 == heading2) && diff --git a/packages/zefyr/lib/src/widgets/toolbar.dart b/packages/zefyr/lib/src/widgets/toolbar.dart index a5a1e33e4..1762fd438 100644 --- a/packages/zefyr/lib/src/widgets/toolbar.dart +++ b/packages/zefyr/lib/src/widgets/toolbar.dart @@ -15,6 +15,7 @@ import 'theme.dart'; enum ZefyrToolbarAction { bold, italic, + underline, link, unlink, clipboardCopy, @@ -39,6 +40,7 @@ enum ZefyrToolbarAction { final kZefyrToolbarAttributeActions = { ZefyrToolbarAction.bold: NotusAttribute.bold, ZefyrToolbarAction.italic: NotusAttribute.italic, + ZefyrToolbarAction.underline: NotusAttribute.underline, ZefyrToolbarAction.link: NotusAttribute.link, ZefyrToolbarAction.heading: NotusAttribute.heading, ZefyrToolbarAction.headingLevel1: NotusAttribute.heading.level1, @@ -252,6 +254,7 @@ class ZefyrToolbarState extends State final buttons = [ buildButton(context, ZefyrToolbarAction.bold), buildButton(context, ZefyrToolbarAction.italic), + buildButton(context, ZefyrToolbarAction.underline), LinkButton(), HeadingButton(), buildButton(context, ZefyrToolbarAction.bulletList), @@ -337,6 +340,7 @@ class _DefaultZefyrToolbarDelegate implements ZefyrToolbarDelegate { static const kDefaultButtonIcons = { ZefyrToolbarAction.bold: Icons.format_bold, ZefyrToolbarAction.italic: Icons.format_italic, + ZefyrToolbarAction.underline: Icons.format_underlined, ZefyrToolbarAction.link: Icons.link, ZefyrToolbarAction.unlink: Icons.link_off, ZefyrToolbarAction.clipboardCopy: Icons.content_copy,