@@ -15,6 +15,39 @@ typedef _LocalTheme =
1515 Color surfaceContainer,
1616 });
1717
18+ // This can be removed when this issue is resolved https://github.com/Infinitix-LLC/gpt_markdown/issues/85
19+ InlineSpan _applyLinkStyle (
20+ InlineSpan original,
21+ TextStyle ? paragraphStyle,
22+ Color ? color,
23+ TextDecoration ? decoration,
24+ Color ? decorationColor,
25+ ) {
26+ if (original is TextSpan ) {
27+ return TextSpan (
28+ text: original.text,
29+ children:
30+ original.children
31+ ? .map (
32+ (child) => _applyLinkStyle (
33+ child,
34+ paragraphStyle,
35+ color,
36+ decoration,
37+ decorationColor,
38+ ),
39+ )
40+ .toList (),
41+ style: (original.style ?? paragraphStyle ?? const TextStyle ()).copyWith (
42+ color: color,
43+ decoration: decoration,
44+ decorationColor: decorationColor,
45+ ),
46+ );
47+ }
48+ return original;
49+ }
50+
1851/// A widget that displays a regular text message.
1952///
2053/// Supports markdown rendering via [GptMarkdown] .
@@ -55,8 +88,14 @@ class FlyerChatTextMessage extends StatelessWidget {
5588 /// The color of the links in the received messages.
5689 final Color ? receivedLinksColor;
5790
58- /// The color of the links in the received messages.
59- final TextDecoration linksDecoration;
91+ /// The color of the links decoration in the sent messages.
92+ final Color ? sentLinksDecorationColor;
93+
94+ /// The color of the links decoration in the received messages.
95+ final Color ? receivedLinksDecorationColor;
96+
97+ /// The decoration of the links.
98+ final TextDecoration ? linksDecoration;
6099
61100 /// Text style for the message timestamp and status.
62101 final TextStyle ? timeStyle;
@@ -99,7 +138,9 @@ class FlyerChatTextMessage extends StatelessWidget {
99138 this .receivedTextStyle,
100139 this .sentLinksColor,
101140 this .receivedLinksColor,
102- this .linksDecoration = TextDecoration .underline,
141+ this .sentLinksDecorationColor,
142+ this .receivedLinksDecorationColor,
143+ this .linksDecoration,
103144 this .timeStyle,
104145 this .showTime = true ,
105146 this .showStatus = true ,
@@ -130,6 +171,12 @@ class FlyerChatTextMessage extends StatelessWidget {
130171 final paragraphStyle = _resolveParagraphStyle (isSentByMe, theme);
131172 final timeStyle = _resolveTimeStyle (isSentByMe, theme);
132173
174+ final linksColor = isSentByMe ? sentLinksColor : receivedLinksColor;
175+ final linksDecorationColor = _resolveLinksDecorationColor (
176+ isSentByMe,
177+ theme,
178+ );
179+
133180 final timeAndStatus =
134181 showTime || (isSentByMe && showStatus)
135182 ? TimeAndStatus (
@@ -145,27 +192,31 @@ class FlyerChatTextMessage extends StatelessWidget {
145192 gptThemeData: GptMarkdownTheme .of (context),
146193 child: GptMarkdown (
147194 message.text,
148- followLinkColor: true ,
149- style: _isOnlyEmoji ? paragraphStyle? .copyWith (fontSize: onlyEmojiFontSize) : paragraphStyle,
195+ style:
196+ _isOnlyEmoji
197+ ? paragraphStyle? .copyWith (fontSize: onlyEmojiFontSize)
198+ : paragraphStyle,
150199 onLinkTap: onLinkTap,
151- linkBuilder: (context, span, href, onTap) {
152- return GestureDetector (
153- onTap : () => onLinkTap ? . call (href, span. toStringShort ()),
154- child : Text . rich (
155- span ,
156- style : paragraphStyle ? . copyWith (
157- decorationColor : isSentByMe ? sentLinksColor : receivedLinksColor ,
158- decoration : linksDecoration ,
200+ linkBuilder:
201+ (_, span, _, _) => Text . rich (
202+ _applyLinkStyle (
203+ span,
204+ paragraphStyle ,
205+ linksColor,
206+ linksDecoration ,
207+ linksDecorationColor ,
159208 ),
160209 ),
161- );
162- },
163210 ),
164211 );
165212
166213 final linkPreviewWidget =
167214 linkPreviewPosition != LinkPreviewPosition .none
168- ? context.read <Builders >().linkPreviewBuilder? .call (context, message, isSentByMe)
215+ ? context.read <Builders >().linkPreviewBuilder? .call (
216+ context,
217+ message,
218+ isSentByMe,
219+ )
169220 : null ;
170221
171222 return ClipRRect (
@@ -180,7 +231,10 @@ class FlyerChatTextMessage extends StatelessWidget {
180231 Container (
181232 padding:
182233 _isOnlyEmoji
183- ? EdgeInsets .symmetric (horizontal: (padding? .horizontal ?? 0 ) / 2 , vertical: 0 )
234+ ? EdgeInsets .symmetric (
235+ horizontal: (padding? .horizontal ?? 0 ) / 2 ,
236+ vertical: 0 ,
237+ )
184238 : padding,
185239 child: _buildContentBasedOnPosition (
186240 context: context,
@@ -204,7 +258,10 @@ class FlyerChatTextMessage extends StatelessWidget {
204258 Widget ? linkPreviewWidget,
205259 }) {
206260 final textDirection = Directionality .of (context);
207- final effectiveLinkPreviewPosition = linkPreviewWidget != null ? linkPreviewPosition : LinkPreviewPosition .none;
261+ final effectiveLinkPreviewPosition =
262+ linkPreviewWidget != null
263+ ? linkPreviewPosition
264+ : LinkPreviewPosition .none;
208265
209266 return Stack (
210267 children: [
@@ -213,30 +270,38 @@ class FlyerChatTextMessage extends StatelessWidget {
213270 crossAxisAlignment: CrossAxisAlignment .start,
214271 children: [
215272 if (topWidget != null ) topWidget! ,
216- if (effectiveLinkPreviewPosition == LinkPreviewPosition .top) linkPreviewWidget! ,
273+ if (effectiveLinkPreviewPosition == LinkPreviewPosition .top)
274+ linkPreviewWidget! ,
217275 timeAndStatusPosition == TimeAndStatusPosition .inline
218276 ? Row (
219277 mainAxisSize: MainAxisSize .min,
220278 crossAxisAlignment: CrossAxisAlignment .end,
221279 children: [
222280 Flexible (child: textContent),
223281 SizedBox (width: 4 ),
224- Padding (padding: timeAndStatusPositionInlineInsets ?? EdgeInsets .zero, child: timeAndStatus),
282+ Padding (
283+ padding:
284+ timeAndStatusPositionInlineInsets ?? EdgeInsets .zero,
285+ child: timeAndStatus,
286+ ),
225287 ],
226288 )
227289 : textContent,
228- if (effectiveLinkPreviewPosition == LinkPreviewPosition .bottom) linkPreviewWidget! ,
290+ if (effectiveLinkPreviewPosition == LinkPreviewPosition .bottom)
291+ linkPreviewWidget! ,
229292 if (timeAndStatusPosition != TimeAndStatusPosition .inline)
230293 // Ensure the width is not smaller than the timeAndStatus widget
231294 // Ensure the height accounts for it's height
232295 Opacity (opacity: 0 , child: timeAndStatus),
233296 ],
234297 ),
235- if (timeAndStatusPosition != TimeAndStatusPosition .inline && timeAndStatus != null )
298+ if (timeAndStatusPosition != TimeAndStatusPosition .inline &&
299+ timeAndStatus != null )
236300 Positioned .directional (
237301 textDirection: textDirection,
238302 end: timeAndStatusPosition == TimeAndStatusPosition .end ? 0 : null ,
239- start: timeAndStatusPosition == TimeAndStatusPosition .start ? 0 : null ,
303+ start:
304+ timeAndStatusPosition == TimeAndStatusPosition .start ? 0 : null ,
240305 bottom: 0 ,
241306 child: timeAndStatus,
242307 ),
@@ -251,16 +316,29 @@ class FlyerChatTextMessage extends StatelessWidget {
251316 return receivedBackgroundColor ?? theme.surfaceContainer;
252317 }
253318
319+ Color ? _resolveLinksDecorationColor (bool isSentByMe, _LocalTheme theme) {
320+ if (isSentByMe) {
321+ return sentLinksDecorationColor ?? sentLinksColor ?? theme.onPrimary;
322+ }
323+ return receivedLinksDecorationColor ??
324+ receivedLinksColor ??
325+ theme.onSurface;
326+ }
327+
254328 TextStyle ? _resolveParagraphStyle (bool isSentByMe, _LocalTheme theme) {
255329 if (isSentByMe) {
256330 return sentTextStyle ?? theme.bodyMedium.copyWith (color: theme.onPrimary);
257331 }
258- return receivedTextStyle ?? theme.bodyMedium.copyWith (color: theme.onSurface);
332+ return receivedTextStyle ??
333+ theme.bodyMedium.copyWith (color: theme.onSurface);
259334 }
260335
261336 TextStyle ? _resolveTimeStyle (bool isSentByMe, _LocalTheme theme) {
262337 if (isSentByMe) {
263- return timeStyle ?? theme.labelSmall.copyWith (color: _isOnlyEmoji ? theme.onSurface : theme.onPrimary);
338+ return timeStyle ??
339+ theme.labelSmall.copyWith (
340+ color: _isOnlyEmoji ? theme.onSurface : theme.onPrimary,
341+ );
264342 }
265343 return timeStyle ?? theme.labelSmall.copyWith (color: theme.onSurface);
266344 }
@@ -301,10 +379,18 @@ class TimeAndStatus extends StatelessWidget {
301379 spacing: 2 ,
302380 mainAxisSize: MainAxisSize .min,
303381 children: [
304- if (showTime && time != null ) Text (timeFormat.format (time! .toLocal ()), style: textStyle),
382+ if (showTime && time != null )
383+ Text (timeFormat.format (time! .toLocal ()), style: textStyle),
305384 if (showStatus && status != null )
306385 if (status == MessageStatus .sending)
307- SizedBox (width: 6 , height: 6 , child: CircularProgressIndicator (color: textStyle? .color, strokeWidth: 2 ))
386+ SizedBox (
387+ width: 6 ,
388+ height: 6 ,
389+ child: CircularProgressIndicator (
390+ color: textStyle? .color,
391+ strokeWidth: 2 ,
392+ ),
393+ )
308394 else
309395 Icon (getIconForStatus (status! ), color: textStyle? .color, size: 12 ),
310396 ],
0 commit comments