When using an action in irc (also known as /me), you are writing in a
way that it feels like an external narrator is dictating what the user
is doing, instead of the user saying that themselves. Rendering this
text inside of a chat bubble breaks this model, so change the looks to
render it as an annoucement instead.
---
Forgot to actually commit the change where the dot would be grey if
sender is self
lib/page/buffer.dart | 87 +++++++++++++++++++++++++++++---------------
1 file changed, 58 insertions(+), 29 deletions(-)
diff --git a/lib/page/buffer.dart b/lib/page/buffer.dart
index f1daf70..c09551c 100644
--- a/lib/page/buffer.dart
+++ b/lib/page/buffer.dart
@@ -516,14 +516,17 @@ class _MessageItem extends StatelessWidget {
assert(ircMsg.cmd == 'PRIVMSG' || ircMsg.cmd == 'NOTICE');
var prevIrcMsg = prevMsg?.msg;
+ var prevCtcp = prevIrcMsg != null ? CtcpMessage.parse(prevIrcMsg) : null;
var prevEntry = prevMsg?.entry;
var prevMsgSameSender = prevIrcMsg != null && ircMsg.source!.name == prevIrcMsg.source!.name;
+ var prevMsgIsAction = prevCtcp != null && prevCtcp.cmd == 'ACTION';
var nextMsgSameSender = nextMsg != null && ircMsg.source!.name == nextMsg!.msg.source!.name;
+ var isAction = ctcp != null && ctcp.cmd == 'ACTION';
var showUnreadMarker = prevEntry != null && unreadMarkerTime != null && unreadMarkerTime!.compareTo(entry.time) < 0 && unreadMarkerTime!.compareTo(prevEntry.time) >= 0;
var showDateMarker = prevEntry == null || !_isSameDate(localDateTime, prevEntry.dateTime.toLocal());
- var showSender = showUnreadMarker || !prevMsgSameSender;
+ var isFirstInGroup = showUnreadMarker || !prevMsgSameSender || (prevMsgIsAction != isAction);
var showTime = !nextMsgSameSender || nextMsg!.entry.dateTime.difference(entry.dateTime) > Duration(minutes: 2);
var unreadMarkerColor = Theme.of(context).accentColor;
@@ -535,11 +538,21 @@ class _MessageItem extends StatelessWidget {
//var boxColor = Theme.of(context).accentColor;
var boxColor = colorScheme.primary;
var boxAlignment = Alignment.centerLeft;
- var textStyle = DefaultTextStyle.of(context).style.apply(color: colorScheme.onPrimary);
+ var textStyle = DefaultTextStyle.of(context).style;
+ if (!isAction) {
+ textStyle = textStyle.apply(color: colorScheme.onPrimary);
+ }
+
if (client.isMyNick(sender)) {
+ // Actions are displayed as if they were told by an external
+ // narrator. To preserve this effect, always show actions on the
+ // left side.
boxColor = Colors.grey[200]!;
- boxAlignment = Alignment.centerRight;
- textStyle = DefaultTextStyle.of(context).style.apply(color: boxColor.computeLuminance() > 0.5 ? Colors.black : Colors.white);
+ if (!isAction) {
+ boxAlignment = Alignment.centerRight;
+ textStyle = DefaultTextStyle.of(context).style
+ .apply(color: boxColor.computeLuminance() > 0.5 ? Colors.black : Colors.white);
+ }
}
const margin = 16.0;
@@ -548,7 +561,7 @@ class _MessageItem extends StatelessWidget {
marginBottom = 0.0;
}
var marginTop = margin;
- if (!showSender) {
+ if (!isFirstInGroup) {
marginTop = margin / 4;
}
@@ -560,17 +573,22 @@ class _MessageItem extends StatelessWidget {
var linkStyle = textStyle.apply(decoration: TextDecoration.underline);
List<InlineSpan> content;
- if (ctcp != null && ctcp.cmd == 'ACTION') {
- textStyle = textStyle.apply(fontStyle: FontStyle.italic);
-
- String actionText;
- if (ctcp.cmd == 'ACTION') {
- actionText = stripAnsiFormatting(ctcp.param ?? '');
- } else {
- actionText = 'has sent a CTCP "${ctcp.cmd}" command';
- }
+ if (isAction) {
+ // isAction can only ever be true if we have a ctcp
+ var actionText = stripAnsiFormatting(ctcp!.param ?? '');
content = [
+ WidgetSpan(
+ child: Container(
+ width: 8.0,
+ height: 8.0,
+ margin: EdgeInsets.all(3.0),
+ decoration: BoxDecoration(
+ shape: BoxShape.circle,
+ color: boxColor,
+ ),
+ ),
+ ),
senderTextSpan,
TextSpan(text: ' '),
linkify(actionText, textStyle: textStyle, linkStyle: linkStyle),
@@ -578,8 +596,8 @@ class _MessageItem extends StatelessWidget {
} else {
var body = stripAnsiFormatting(ircMsg.params[1]);
content = [
- if (showSender) senderTextSpan,
- if (showSender) TextSpan(text: '\n'),
+ if (isFirstInGroup) senderTextSpan,
+ if (isFirstInGroup) TextSpan(text: '\n'),
linkify(body, textStyle: textStyle, linkStyle: linkStyle),
];
}
@@ -612,20 +630,31 @@ class _MessageItem extends StatelessWidget {
]);
}
- Widget bubble = Align(
- alignment: boxAlignment,
- child: Container(
- decoration: BoxDecoration(
- borderRadius: BorderRadius.circular(10),
- color: boxColor,
+ Widget decoratedMessage;
+ if (isAction) {
+ decoratedMessage = Align(
+ alignment: boxAlignment,
+ child: Container(
+ child: inner,
),
- padding: EdgeInsets.all(10),
- child: inner,
- ),
- );
+ );
+ } else {
+ decoratedMessage = Align(
+ alignment: boxAlignment,
+ child: Container(
+ decoration: BoxDecoration(
+ borderRadius: BorderRadius.circular(10),
+ color: boxColor,
+ ),
+ padding: EdgeInsets.all(10),
+ child: inner,
+ ),
+ );
+ }
+
if (!client.isMyNick(sender)) {
- bubble = SwipeAction(
- child: bubble,
+ decoratedMessage = SwipeAction(
+ child: decoratedMessage,
background: Align(
alignment: Alignment.centerLeft,
child: Opacity(
@@ -654,7 +683,7 @@ class _MessageItem extends StatelessWidget {
),
Container(
margin: EdgeInsets.only(left: margin, right: margin, top: marginTop, bottom: marginBottom),
- child: bubble,
+ child: decoratedMessage,
),
]);
}
--
2.35.1