diff --git a/fluxer_app/src/features/app/components/layout/ChannelListContent.tsx b/fluxer_app/src/features/app/components/layout/ChannelListContent.tsx index f7ff9158c..e9922d74e 100644 --- a/fluxer_app/src/features/app/components/layout/ChannelListContent.tsx +++ b/fluxer_app/src/features/app/components/layout/ChannelListContent.tsx @@ -23,7 +23,10 @@ import { } from '@app/features/app/components/layout/utils/ChannelListVisibility'; import {createChannelMoveOperation} from '@app/features/app/components/layout/utils/ChannelMoveOperation'; import {organizeChannels} from '@app/features/app/components/layout/utils/ChannelOrganization'; -import {getChannelUnreadState} from '@app/features/app/components/layout/utils/ChannelUnreadState'; +import { + type ChannelUnreadState, + getChannelUnreadState, +} from '@app/features/app/components/layout/utils/ChannelUnreadState'; import {VoiceParticipantsList} from '@app/features/app/components/layout/VoiceParticipantsList'; import { type RememberedSkeletonGuildChannelGroup, @@ -334,7 +337,7 @@ export const ChannelListContent = observer(({guild, scrollY}: {guild: Guild; scr }, [guild], ); - const hasVisibleUnreadInChannel = (channelId: string): boolean => { + const getUnreadStateInChannel = (channelId: string): ChannelUnreadState => { const unreadCount = ReadStates.getUnreadCount(channelId); const hasUnread = ReadStates.hasUnread(channelId); const mentionCount = ReadStates.getMentionCount(channelId); @@ -348,7 +351,7 @@ export const ChannelListContent = observer(({guild, scrollY}: {guild: Guild; scr type: channel.type, }) : null; - const unreadState = getChannelUnreadState({ + return getChannelUnreadState({ hasUnread, unreadCount, mentionCount, @@ -356,16 +359,14 @@ export const ChannelListContent = observer(({guild, scrollY}: {guild: Guild; scr showFadedUnreadOnMutedChannels, unreadBadgesLevel, }); - return unreadState.hasVisibleUnread; }; const resolvedGroups: Array = []; for (const group of channelGroups) { const isCollapsed = group.category ? (collapsedCategories?.has(group.category.id) ?? false) : false; const isNullSpace = !group.category; - const isCategoryMuted = - hideMutedChannels && group.category - ? UserGuildSettings.isChannelDirectlyMuted(guild.id, group.category.id) - : false; + const isCategoryMuted = group.category + ? UserGuildSettings.isChannelDirectlyMuted(guild.id, group.category.id) + : false; let filteredTextChannels: Array; let filteredVoiceChannels: Array; if (hideMutedChannels) { @@ -379,7 +380,7 @@ export const ChannelListContent = observer(({guild, scrollY}: {guild: Guild; scr isChannelMuted, isSelected: ch.id === selectedChannelInGuildId, isConnected: false, - hasVisibleUnread: isMuted && hasVisibleUnreadInChannel(ch.id), + hasVisibleUnread: isMuted && getUnreadStateInChannel(ch.id).hasVisibleUnread, }) ) { filteredTextChannels.push(ch); @@ -395,7 +396,7 @@ export const ChannelListContent = observer(({guild, scrollY}: {guild: Guild; scr isChannelMuted, isSelected: ch.id === selectedChannelInGuildId, isConnected: ch.id === connectedChannelId, - hasVisibleUnread: isMuted && hasVisibleUnreadInChannel(ch.id), + hasVisibleUnread: isMuted && getUnreadStateInChannel(ch.id).hasVisibleUnread, }) ) { filteredVoiceChannels.push(ch); @@ -412,11 +413,14 @@ export const ChannelListContent = observer(({guild, scrollY}: {guild: Guild; scr const showTextSelected = selectedChannelInGuildId; const showSet = new Set(); for (const ch of filteredTextChannels) { + const unreadState = getUnreadStateInChannel(ch.id); if ( shouldShowChannelInCollapsedCategory({ + isCategoryMuted, isSelected: ch.id === showTextSelected, isConnected: false, - hasVisibleUnread: hasVisibleUnreadInChannel(ch.id), + hasVisibleUnread: unreadState.hasVisibleUnread, + hasMentions: unreadState.hasMentions, }) ) { showSet.add(ch.id); @@ -443,11 +447,14 @@ export const ChannelListContent = observer(({guild, scrollY}: {guild: Guild; scr } } for (const ch of filteredVoiceChannels) { + const unreadState = getUnreadStateInChannel(ch.id); if ( shouldShowChannelInCollapsedCategory({ + isCategoryMuted, isSelected: ch.id === selectedChannelInGuildId, isConnected: ch.id === connectedChannelId, - hasVisibleUnread: hasVisibleUnreadInChannel(ch.id), + hasVisibleUnread: unreadState.hasVisibleUnread, + hasMentions: unreadState.hasMentions, }) ) { voiceSet.add(ch.id); diff --git a/fluxer_app/src/features/app/components/layout/utils/ChannelListVisibility.test.ts b/fluxer_app/src/features/app/components/layout/utils/ChannelListVisibility.test.ts index 8a321ff0f..6dc2ca36a 100644 --- a/fluxer_app/src/features/app/components/layout/utils/ChannelListVisibility.test.ts +++ b/fluxer_app/src/features/app/components/layout/utils/ChannelListVisibility.test.ts @@ -123,26 +123,32 @@ describe('shouldShowChannelInCollapsedCategory', () => { it('keeps visible unread channels reachable in collapsed categories', () => { expect( shouldShowChannelInCollapsedCategory({ + isCategoryMuted: false, isSelected: false, isConnected: false, hasVisibleUnread: true, + hasMentions: false, }), ).toBe(true); }); - it('keeps selected and connected channels visible without unread state', () => { + it('keeps selected and connected channels visible without unread state, even in muted categories', () => { expect( shouldShowChannelInCollapsedCategory({ + isCategoryMuted: true, isSelected: true, isConnected: false, hasVisibleUnread: false, + hasMentions: false, }), ).toBe(true); expect( shouldShowChannelInCollapsedCategory({ + isCategoryMuted: true, isSelected: false, isConnected: true, hasVisibleUnread: false, + hasMentions: false, }), ).toBe(true); }); @@ -150,10 +156,36 @@ describe('shouldShowChannelInCollapsedCategory', () => { it('hides read channels in collapsed categories', () => { expect( shouldShowChannelInCollapsedCategory({ + isCategoryMuted: false, isSelected: false, isConnected: false, hasVisibleUnread: false, + hasMentions: false, }), ).toBe(false); }); + + it('hides unread channels without mentions in muted collapsed categories', () => { + expect( + shouldShowChannelInCollapsedCategory({ + isCategoryMuted: true, + isSelected: false, + isConnected: false, + hasVisibleUnread: true, + hasMentions: false, + }), + ).toBe(false); + }); + + it('keeps mentioned channels reachable in muted collapsed categories', () => { + expect( + shouldShowChannelInCollapsedCategory({ + isCategoryMuted: true, + isSelected: false, + isConnected: false, + hasVisibleUnread: true, + hasMentions: true, + }), + ).toBe(true); + }); }); diff --git a/fluxer_app/src/features/app/components/layout/utils/ChannelListVisibility.ts b/fluxer_app/src/features/app/components/layout/utils/ChannelListVisibility.ts index d1af52049..58fac4f2c 100644 --- a/fluxer_app/src/features/app/components/layout/utils/ChannelListVisibility.ts +++ b/fluxer_app/src/features/app/components/layout/utils/ChannelListVisibility.ts @@ -31,15 +31,19 @@ export function shouldShowCategoryWhenHidingMutedChannels({ } export interface CollapsedCategoryChannelVisibilityInput { + isCategoryMuted: boolean; isSelected: boolean; isConnected: boolean; hasVisibleUnread: boolean; + hasMentions: boolean; } export function shouldShowChannelInCollapsedCategory({ + isCategoryMuted, isSelected, isConnected, hasVisibleUnread, + hasMentions, }: CollapsedCategoryChannelVisibilityInput): boolean { - return isSelected || isConnected || hasVisibleUnread; + return isSelected || isConnected || (isCategoryMuted ? hasMentions : hasVisibleUnread); }