add focus current channel toggle to fade non-active shared chat messages
Replaces the merge button in the chat tab bar with a more-actions menu that exposes both "Merge chats" and "Focus current channel" toggles. When focus mode is on, messages whose source channel differs from the active channel render at reduced opacity in both Twitch native shared chat and merged-tabs views. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
12c2fed7da
commit
f2de6c653d
5 changed files with 95 additions and 18 deletions
|
|
@ -609,6 +609,19 @@ class ChatMessage extends StatelessWidget {
|
|||
child: dividedMessage,
|
||||
);
|
||||
|
||||
final sourceChannelId =
|
||||
ircMessage.tags['source-room-id'] ?? ircMessage.tags['room-id'];
|
||||
final currentChannelId =
|
||||
overrideCurrentChannelId ?? chatStore.channelId;
|
||||
final shouldFade =
|
||||
chatStore.settings.focusCurrentChannel &&
|
||||
sourceChannelId != null &&
|
||||
sourceChannelId != currentChannelId;
|
||||
|
||||
final fadedMessage = shouldFade
|
||||
? Opacity(opacity: 0.4, child: coloredMessage)
|
||||
: coloredMessage;
|
||||
|
||||
final finalMessage = InkWell(
|
||||
onTap: () {
|
||||
FocusScope.of(context).unfocus();
|
||||
|
|
@ -617,7 +630,7 @@ class ChatMessage extends StatelessWidget {
|
|||
}
|
||||
},
|
||||
onLongPress: () => onLongPressMessage(context, defaultTextStyle),
|
||||
child: coloredMessage,
|
||||
child: fadedMessage,
|
||||
);
|
||||
|
||||
return finalMessage;
|
||||
|
|
|
|||
|
|
@ -171,7 +171,9 @@ class ChatTabs extends StatelessWidget {
|
|||
right: 12,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
child: Center(child: _buildMergeToggle(context)),
|
||||
child: Center(
|
||||
child: _buildMoreActionsMenu(context),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
@ -184,22 +186,47 @@ class ChatTabs extends StatelessWidget {
|
|||
);
|
||||
}
|
||||
|
||||
Widget _buildMergeToggle(BuildContext context) {
|
||||
final isMerged = chatTabsStore.mergedMode;
|
||||
return IconButton.filledTonal(
|
||||
icon: const Icon(Icons.call_merge, size: 18),
|
||||
tooltip: isMerged ? 'Split chats' : 'Merge loaded chats',
|
||||
visualDensity: VisualDensity.compact,
|
||||
isSelected: isMerged,
|
||||
style: IconButton.styleFrom(
|
||||
minimumSize: const Size(42, 42),
|
||||
backgroundColor: isMerged
|
||||
? null
|
||||
: Theme.of(context).colorScheme.surfaceContainerHighest,
|
||||
),
|
||||
onPressed: () {
|
||||
HapticFeedback.selectionClick();
|
||||
chatTabsStore.toggleMergedMode();
|
||||
Widget _buildMoreActionsMenu(BuildContext context) {
|
||||
final settings = chatTabsStore.activeChatStore.settings;
|
||||
|
||||
return MenuAnchor(
|
||||
menuChildren: [
|
||||
Observer(
|
||||
builder: (_) => CheckboxMenuButton(
|
||||
value: chatTabsStore.mergedMode,
|
||||
onChanged: (_) {
|
||||
HapticFeedback.selectionClick();
|
||||
chatTabsStore.toggleMergedMode();
|
||||
},
|
||||
child: const Text('Merge chats'),
|
||||
),
|
||||
),
|
||||
Observer(
|
||||
builder: (_) => CheckboxMenuButton(
|
||||
value: settings.focusCurrentChannel,
|
||||
onChanged: (newValue) {
|
||||
HapticFeedback.selectionClick();
|
||||
settings.focusCurrentChannel = newValue ?? false;
|
||||
},
|
||||
child: const Text('Focus current channel'),
|
||||
),
|
||||
),
|
||||
],
|
||||
builder: (context, controller, child) {
|
||||
return IconButton.filledTonal(
|
||||
icon: const Icon(Icons.more_vert, size: 18),
|
||||
tooltip: 'Chat options',
|
||||
visualDensity: VisualDensity.compact,
|
||||
style: IconButton.styleFrom(
|
||||
minimumSize: const Size(42, 42),
|
||||
backgroundColor:
|
||||
Theme.of(context).colorScheme.surfaceContainerHighest,
|
||||
),
|
||||
onPressed: () {
|
||||
HapticFeedback.selectionClick();
|
||||
controller.isOpen ? controller.close() : controller.open();
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -221,6 +221,16 @@ class ChatSettings extends StatelessWidget {
|
|||
onChanged: (newValue) =>
|
||||
settingsStore.showHistoricalTimestamps = newValue,
|
||||
),
|
||||
SettingsListSwitch(
|
||||
title: 'Focus current channel',
|
||||
subtitle: const Text(
|
||||
'Fades messages from other channels in shared chat and '
|
||||
'merged views, so the current channel stands out.',
|
||||
),
|
||||
value: settingsStore.focusCurrentChannel,
|
||||
onChanged: (newValue) =>
|
||||
settingsStore.focusCurrentChannel = newValue,
|
||||
),
|
||||
const SectionHeader('Delay'),
|
||||
SettingsListSwitch(
|
||||
title: 'Auto-sync chat delay',
|
||||
|
|
|
|||
|
|
@ -128,6 +128,7 @@ abstract class _SettingsStoreBase with Store {
|
|||
static const defaultShowChatMessageDividers = false;
|
||||
static const defaultTimestampType = TimestampType.disabled;
|
||||
static const defaultShowHistoricalTimestamps = false;
|
||||
static const defaultFocusCurrentChannel = false;
|
||||
|
||||
// Alert defaults
|
||||
static const defaultHighlightFirstTimeChatter = true;
|
||||
|
|
@ -201,6 +202,10 @@ abstract class _SettingsStoreBase with Store {
|
|||
@observable
|
||||
var showHistoricalTimestamps = defaultShowHistoricalTimestamps;
|
||||
|
||||
@JsonKey(defaultValue: defaultFocusCurrentChannel)
|
||||
@observable
|
||||
var focusCurrentChannel = defaultFocusCurrentChannel;
|
||||
|
||||
@JsonKey(defaultValue: defaultHighlightFirstTimeChatter)
|
||||
@observable
|
||||
var highlightFirstTimeChatter = defaultHighlightFirstTimeChatter;
|
||||
|
|
@ -320,6 +325,7 @@ abstract class _SettingsStoreBase with Store {
|
|||
showChatMessageDividers = defaultShowChatMessageDividers;
|
||||
timestampType = defaultTimestampType;
|
||||
showHistoricalTimestamps = defaultShowHistoricalTimestamps;
|
||||
focusCurrentChannel = defaultFocusCurrentChannel;
|
||||
highlightFirstTimeChatter = defaultHighlightFirstTimeChatter;
|
||||
showUserNotices = defaultShowUserNotices;
|
||||
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ SettingsStore _$SettingsStoreFromJson(
|
|||
TimestampType.disabled
|
||||
..showHistoricalTimestamps =
|
||||
json['showHistoricalTimestamps'] as bool? ?? false
|
||||
..focusCurrentChannel = json['focusCurrentChannel'] as bool? ?? false
|
||||
..highlightFirstTimeChatter =
|
||||
json['highlightFirstTimeChatter'] as bool? ?? true
|
||||
..showUserNotices = json['showUserNotices'] as bool? ?? true
|
||||
|
|
@ -117,6 +118,7 @@ Map<String, dynamic> _$SettingsStoreToJson(
|
|||
'showChatMessageDividers': instance.showChatMessageDividers,
|
||||
'timestampType': _$TimestampTypeEnumMap[instance.timestampType]!,
|
||||
'showHistoricalTimestamps': instance.showHistoricalTimestamps,
|
||||
'focusCurrentChannel': instance.focusCurrentChannel,
|
||||
'highlightFirstTimeChatter': instance.highlightFirstTimeChatter,
|
||||
'showUserNotices': instance.showUserNotices,
|
||||
'showTwitchEmotes': instance.showTwitchEmotes,
|
||||
|
|
@ -572,6 +574,24 @@ mixin _$SettingsStore on _SettingsStoreBase, Store {
|
|||
);
|
||||
}
|
||||
|
||||
late final _$focusCurrentChannelAtom = Atom(
|
||||
name: '_SettingsStoreBase.focusCurrentChannel',
|
||||
context: context,
|
||||
);
|
||||
|
||||
@override
|
||||
bool get focusCurrentChannel {
|
||||
_$focusCurrentChannelAtom.reportRead();
|
||||
return super.focusCurrentChannel;
|
||||
}
|
||||
|
||||
@override
|
||||
set focusCurrentChannel(bool value) {
|
||||
_$focusCurrentChannelAtom.reportWrite(value, super.focusCurrentChannel, () {
|
||||
super.focusCurrentChannel = value;
|
||||
});
|
||||
}
|
||||
|
||||
late final _$highlightFirstTimeChatterAtom = Atom(
|
||||
name: '_SettingsStoreBase.highlightFirstTimeChatter',
|
||||
context: context,
|
||||
|
|
@ -1223,6 +1243,7 @@ showDeletedMessages: ${showDeletedMessages},
|
|||
showChatMessageDividers: ${showChatMessageDividers},
|
||||
timestampType: ${timestampType},
|
||||
showHistoricalTimestamps: ${showHistoricalTimestamps},
|
||||
focusCurrentChannel: ${focusCurrentChannel},
|
||||
highlightFirstTimeChatter: ${highlightFirstTimeChatter},
|
||||
showUserNotices: ${showUserNotices},
|
||||
showTwitchEmotes: ${showTwitchEmotes},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue