From eb3f0bc08299afb6572a6d689c3533a5d5202fd6 Mon Sep 17 00:00:00 2001 From: tommyxchow Date: Sat, 23 Oct 2021 02:28:20 -0400 Subject: [PATCH] Implement rendering of USERNOTICE messages --- lib/api/irc_api.dart | 2 +- lib/stores/channel_list_store.dart | 1 + lib/stores/chat_store.dart | 74 ++++++++++++++++++++---------- lib/widgets/chat_message.dart | 9 ++-- 4 files changed, 54 insertions(+), 32 deletions(-) diff --git a/lib/api/irc_api.dart b/lib/api/irc_api.dart index 000e30af..7e3c72ad 100644 --- a/lib/api/irc_api.dart +++ b/lib/api/irc_api.dart @@ -16,7 +16,7 @@ class IRC { final banDuration = ircMessage.tags['ban-duration']; messages.asMap().forEach((i, message) { - if (message.user! == bannedUser) { + if (message.user == bannedUser) { messages[i].command = 'CLEARCHAT'; if (banDuration != null) { diff --git a/lib/stores/channel_list_store.dart b/lib/stores/channel_list_store.dart index 17106287..c1732bcc 100644 --- a/lib/stores/channel_list_store.dart +++ b/lib/stores/channel_list_store.dart @@ -5,6 +5,7 @@ import 'package:frosty/models/channel.dart'; part 'channel_list_store.g.dart'; +// TODO: Fix followed list refresh when log in. class ChannelListStore = _ChannelListBase with _$ChannelListStore; abstract class _ChannelListBase with Store { diff --git a/lib/stores/chat_store.dart b/lib/stores/chat_store.dart index 9583904b..06ef2913 100644 --- a/lib/stores/chat_store.dart +++ b/lib/stores/chat_store.dart @@ -1,4 +1,5 @@ import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter/widgets.dart'; import 'package:frosty/api/bttv_api.dart'; @@ -112,7 +113,8 @@ abstract class _ChatStoreBase with Store { IRC.clearMsg(messages: messages, ircMessage: parsedIRCMessage); break; case 'GLOBALUSERSTATE': - // Updates the current global user state data (it includes user-id) + // Updates the current global user state data (it includes user-id), + // Don't really see a use for it when USERSTATE exists, so leaving it unimplemented for now. // _globalUserState = message; break; case 'PRIVMSG': @@ -123,7 +125,7 @@ abstract class _ChatStoreBase with Store { break; case 'USERNOTICE': debugPrint(message); - // _messages = IRC.USERNOTICE(messages: _messages, ircMessage: parsedIRCMessage); + messages.add(parsedIRCMessage); break; case 'USERSTATE': // Updates the current user-state data @@ -182,7 +184,6 @@ abstract class _ChatStoreBase with Store { } } - final words = ircMessage.message!.split(' '); final badges = ircMessage.tags['badges']; if (badges != null) { for (final badge in badges.split(',')) { @@ -218,31 +219,35 @@ abstract class _ChatStoreBase with Store { const TextSpan(text: ':'), ); - for (final word in words) { - final emoteUrl = _assetToUrl[word]; - if (emoteUrl != null) { - result.add(const TextSpan(text: ' ')); - result.add( - WidgetSpan( - alignment: PlaceholderAlignment.middle, - child: CachedNetworkImage( - imageUrl: emoteUrl, - placeholder: (context, url) => const SizedBox(), - fadeInDuration: const Duration(seconds: 0), - height: 25, + final message = ircMessage.message; + if (message != null) { + final words = message.split(' '); + for (final word in words) { + final emoteUrl = _assetToUrl[word]; + if (emoteUrl != null) { + result.add(const TextSpan(text: ' ')); + result.add( + WidgetSpan( + alignment: PlaceholderAlignment.middle, + child: CachedNetworkImage( + imageUrl: emoteUrl, + placeholder: (context, url) => const SizedBox(), + fadeInDuration: const Duration(seconds: 0), + height: 25, + ), ), - ), - ); - } else { - result.add(const TextSpan(text: ' ')); - result.add(TextSpan(text: word)); + ); + } else { + result.add(const TextSpan(text: ' ')); + result.add(TextSpan(text: word)); + } } } if (ircMessage.command == 'CLEARCHAT' || ircMessage.command == 'CLEARMSG') { final banDuration = ircMessage.tags['ban-duration']; return Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0), + padding: const EdgeInsets.symmetric(vertical: 10.0), child: Opacity( opacity: 0.50, child: Column( @@ -259,15 +264,34 @@ abstract class _ChatStoreBase with Store { : Text( 'Timed out for $banDuration second(s).', style: const TextStyle(fontWeight: FontWeight.bold), - ) + ), ], ), ), ); + } else if (ircMessage.command == 'USERNOTICE') { + return Container( + color: Colors.purple.withOpacity(0.25), + padding: const EdgeInsets.symmetric(vertical: 10.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (ircMessage.message != null) + ChatMessage( + key: Key(ircMessage.tags['id']!), + children: result, + ), + Text(ircMessage.tags['system-msg']!), + ], + ), + ); } else { - return ChatMessage( - key: ircMessage.tags['id'] == null ? null : Key(ircMessage.tags['id']!), - children: result, + return Padding( + padding: const EdgeInsets.symmetric(vertical: 5.0), + child: ChatMessage( + key: ircMessage.tags['id'] == null ? null : Key(ircMessage.tags['id']!), + children: result, + ), ); } } diff --git a/lib/widgets/chat_message.dart b/lib/widgets/chat_message.dart index f19a9378..9a4a1d4d 100644 --- a/lib/widgets/chat_message.dart +++ b/lib/widgets/chat_message.dart @@ -7,12 +7,9 @@ class ChatMessage extends StatelessWidget { @override Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.symmetric(vertical: 5.0), - child: RichText( - text: TextSpan( - children: children, - ), + return RichText( + text: TextSpan( + children: children, ), ); }