refactor(chat): dedup shared-chat tag lookup and extract fade policy
- add IRCMessage.sourceChannelId, replacing three copies of the same source-room-id/room-id tag lookup - move the shared-chat spotlight/merged-mode fade decision out of ChatMessage's build into ChatStore.shouldFadeMessage, matching the extract-into-store convention already used for SharedChatBubbleState - factor the tab-bar item's Padding/Center wrapper into a shared _wrapItem helper instead of duplicating it per branch
This commit is contained in:
parent
f9d8ef5fb2
commit
074d8ed21f
4 changed files with 54 additions and 35 deletions
|
|
@ -56,6 +56,11 @@ class IRCMessage {
|
|||
this.actionLabel,
|
||||
});
|
||||
|
||||
/// The channel this message actually originated from. In Twitch shared
|
||||
/// chat, `source-room-id` names the participant channel a message was
|
||||
/// sent in; otherwise it's just this connection's own room.
|
||||
String? get sourceChannelId => tags['source-room-id'] ?? tags['room-id'];
|
||||
|
||||
/// Applies the given CLEARCHAT message to the provided messages and buffer.
|
||||
static void clearChat({
|
||||
required List<IRCMessage> messages,
|
||||
|
|
@ -186,7 +191,6 @@ class IRCMessage {
|
|||
span.add(const TextSpan(text: ' '));
|
||||
}
|
||||
|
||||
final sourceChannelId = tags['source-room-id'] ?? tags['room-id'];
|
||||
final sourceChannelUser = channelIdToUserTwitch?[sourceChannelId];
|
||||
if (sourceChannelUser != null) {
|
||||
final isCurrentChannel = sourceChannelId == currentChannelId;
|
||||
|
|
|
|||
|
|
@ -211,6 +211,31 @@ abstract class ChatStoreBase with Store {
|
|||
revealedMessageIds.add(id);
|
||||
}
|
||||
|
||||
/// Whether a message from [sourceChannelId] should render faded.
|
||||
///
|
||||
/// [overrideCurrentChannelId] is set only when rendering the manual
|
||||
/// "merged mode" view (multiple manually-added tabs interleaved), which
|
||||
/// always fades non-active-tab messages, gated by [focusCurrentChannel].
|
||||
/// Otherwise this is the normal single-connection view, where native
|
||||
/// Twitch shared chat defaults to unfaded and only fades once the user
|
||||
/// spotlights a participant channel via a chat bubble — an explicit
|
||||
/// action that isn't gated by that setting.
|
||||
bool shouldFadeMessage({
|
||||
required String? sourceChannelId,
|
||||
required String? overrideCurrentChannelId,
|
||||
}) {
|
||||
if (sourceChannelId == null) return false;
|
||||
|
||||
final currentChannelId = overrideCurrentChannelId ?? channelId;
|
||||
if (sourceChannelId == currentChannelId) return false;
|
||||
|
||||
final isMerged = overrideCurrentChannelId != null;
|
||||
if (isMerged) return settings.focusCurrentChannel;
|
||||
|
||||
return sharedChatBubbles.focusedChannelIds.isNotEmpty &&
|
||||
!sharedChatBubbles.isFocused(sourceChannelId);
|
||||
}
|
||||
|
||||
/// Timer used for dismissing the notification.
|
||||
Timer? _notificationTimer;
|
||||
|
||||
|
|
@ -255,8 +280,7 @@ abstract class ChatStoreBase with Store {
|
|||
// has hidden. Short-circuit when nothing is hidden (the common case).
|
||||
if (sharedChatBubbles.hiddenChannelIds.isEmpty) return base;
|
||||
return base.where((message) {
|
||||
final sourceChannelId =
|
||||
message.tags['source-room-id'] ?? message.tags['room-id'];
|
||||
final sourceChannelId = message.sourceChannelId;
|
||||
return sourceChannelId == null ||
|
||||
!sharedChatBubbles.hiddenChannelIds.contains(sourceChannelId);
|
||||
}).toList();
|
||||
|
|
|
|||
|
|
@ -626,27 +626,10 @@ class ChatMessage extends StatelessWidget {
|
|||
child: dividedMessage,
|
||||
);
|
||||
|
||||
final sourceChannelId =
|
||||
ircMessage.tags['source-room-id'] ?? ircMessage.tags['room-id'];
|
||||
final currentChannelId =
|
||||
overrideCurrentChannelId ?? chatStore.channelId;
|
||||
|
||||
// overrideCurrentChannelId is only set in manual "merged mode"
|
||||
// (multiple manually-added tabs interleaved); that keeps its
|
||||
// existing always-fade-non-active-tab behavior, gated by the
|
||||
// focusCurrentChannel setting. Native Twitch shared chat instead
|
||||
// defaults to unfaded and only fades once the user spotlights a
|
||||
// participant channel via a chat bubble — an explicit action that
|
||||
// isn't gated by that setting.
|
||||
final isMerged = overrideCurrentChannelId != null;
|
||||
final hasSpotlight =
|
||||
!isMerged && chatStore.sharedChatBubbles.focusedChannelIds.isNotEmpty;
|
||||
final shouldFade =
|
||||
sourceChannelId != null &&
|
||||
sourceChannelId != currentChannelId &&
|
||||
((isMerged && chatStore.settings.focusCurrentChannel) ||
|
||||
(hasSpotlight &&
|
||||
!chatStore.sharedChatBubbles.isFocused(sourceChannelId)));
|
||||
final shouldFade = chatStore.shouldFadeMessage(
|
||||
sourceChannelId: ircMessage.sourceChannelId,
|
||||
overrideCurrentChannelId: overrideCurrentChannelId,
|
||||
);
|
||||
|
||||
final fadedMessage = shouldFade
|
||||
? Opacity(opacity: 0.55, child: coloredMessage)
|
||||
|
|
|
|||
|
|
@ -49,6 +49,16 @@ class ChatTabs extends StatelessWidget {
|
|||
}
|
||||
}
|
||||
|
||||
/// Wraps a tab bar item (a tab chip or a shared-chat bubble) with its
|
||||
/// trailing gap and centering, keyed for the reorderable list.
|
||||
Widget _wrapItem({required Key key, required bool isLast, required Widget child}) {
|
||||
return Padding(
|
||||
key: key,
|
||||
padding: EdgeInsets.only(right: isLast ? 0 : 4),
|
||||
child: Center(child: child),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Observer(
|
||||
|
|
@ -163,24 +173,22 @@ class ChatTabs extends StatelessWidget {
|
|||
1;
|
||||
if (index < tabs.length) {
|
||||
final tabInfo = chatTabsStore.tabs[index];
|
||||
return Padding(
|
||||
return _wrapItem(
|
||||
key: ValueKey(tabInfo.channelId),
|
||||
padding: EdgeInsets.only(right: isLast ? 0 : 4),
|
||||
child: Center(child: _buildTab(context, index)),
|
||||
isLast: isLast,
|
||||
child: _buildTab(context, index),
|
||||
);
|
||||
}
|
||||
|
||||
final participant =
|
||||
sharedChatParticipants[index - tabs.length];
|
||||
return Padding(
|
||||
return _wrapItem(
|
||||
key: ValueKey('shared_${participant.key}'),
|
||||
padding: EdgeInsets.only(right: isLast ? 0 : 4),
|
||||
child: Center(
|
||||
child: _buildSharedChatBubble(
|
||||
context,
|
||||
participant.key,
|
||||
participant.value,
|
||||
),
|
||||
isLast: isLast,
|
||||
child: _buildSharedChatBubble(
|
||||
context,
|
||||
participant.key,
|
||||
participant.value,
|
||||
),
|
||||
);
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue