From 00c1b19809c4d655e806a472dd2532f118f9de0f Mon Sep 17 00:00:00 2001 From: Hampus Date: Sun, 6 Sep 2026 22:10:09 +0200 Subject: [PATCH] fix(app): inherit category mute when hiding muted channels (#2558) --- .../components/layout/ChannelListContent.tsx | 16 ++++++-- .../utils/ChannelListVisibility.test.ts | 39 ++++++++++++++++--- .../layout/utils/ChannelListVisibility.ts | 8 ++-- 3 files changed, 51 insertions(+), 12 deletions(-) diff --git a/fluxer_app/src/features/app/components/layout/ChannelListContent.tsx b/fluxer_app/src/features/app/components/layout/ChannelListContent.tsx index f8f751dc2..7ad2a7fb5 100644 --- a/fluxer_app/src/features/app/components/layout/ChannelListContent.tsx +++ b/fluxer_app/src/features/app/components/layout/ChannelListContent.tsx @@ -362,15 +362,21 @@ export const ChannelListContent = observer(({guild, scrollY}: {guild: Guild; scr 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; let filteredTextChannels: Array; let filteredVoiceChannels: Array; if (hideMutedChannels) { filteredTextChannels = []; for (const ch of group.textChannels) { - const isMuted = UserGuildSettings.isChannelDirectlyMuted(guild.id, ch.id); + const isChannelMuted = UserGuildSettings.isChannelDirectlyMuted(guild.id, ch.id); + const isMuted = isCategoryMuted || isChannelMuted; if ( shouldShowChannelWhenHidingMutedChannels({ - isMuted, + isCategoryMuted, + isChannelMuted, isSelected: ch.id === selectedChannelInGuildId, isConnected: false, hasVisibleUnread: isMuted && hasVisibleUnreadInChannel(ch.id), @@ -381,10 +387,12 @@ export const ChannelListContent = observer(({guild, scrollY}: {guild: Guild; scr } filteredVoiceChannels = []; for (const ch of group.voiceChannels) { - const isMuted = UserGuildSettings.isChannelDirectlyMuted(guild.id, ch.id); + const isChannelMuted = UserGuildSettings.isChannelDirectlyMuted(guild.id, ch.id); + const isMuted = isCategoryMuted || isChannelMuted; if ( shouldShowChannelWhenHidingMutedChannels({ - isMuted, + isCategoryMuted, + isChannelMuted, isSelected: ch.id === selectedChannelInGuildId, isConnected: ch.id === connectedChannelId, hasVisibleUnread: isMuted && hasVisibleUnreadInChannel(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 58259f743..2bfa7dffc 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 @@ -11,7 +11,8 @@ describe('shouldShowChannelWhenHidingMutedChannels', () => { it('keeps muted channels with visible unread state so mentions are findable', () => { expect( shouldShowChannelWhenHidingMutedChannels({ - isMuted: true, + isCategoryMuted: false, + isChannelMuted: true, isSelected: false, isConnected: false, hasVisibleUnread: true, @@ -22,7 +23,8 @@ describe('shouldShowChannelWhenHidingMutedChannels', () => { it('hides muted channels without visible unread state', () => { expect( shouldShowChannelWhenHidingMutedChannels({ - isMuted: true, + isCategoryMuted: false, + isChannelMuted: true, isSelected: false, isConnected: false, hasVisibleUnread: false, @@ -30,10 +32,35 @@ describe('shouldShowChannelWhenHidingMutedChannels', () => { ).toBe(false); }); + it('inherits the mute from a muted category', () => { + expect( + shouldShowChannelWhenHidingMutedChannels({ + isCategoryMuted: true, + isChannelMuted: false, + isSelected: false, + isConnected: false, + hasVisibleUnread: false, + }), + ).toBe(false); + }); + + it('keeps channels of a muted category that have visible unread state', () => { + expect( + shouldShowChannelWhenHidingMutedChannels({ + isCategoryMuted: true, + isChannelMuted: false, + isSelected: false, + isConnected: false, + hasVisibleUnread: true, + }), + ).toBe(true); + }); + it('keeps selected and connected muted channels visible', () => { expect( shouldShowChannelWhenHidingMutedChannels({ - isMuted: true, + isCategoryMuted: true, + isChannelMuted: true, isSelected: true, isConnected: false, hasVisibleUnread: false, @@ -41,7 +68,8 @@ describe('shouldShowChannelWhenHidingMutedChannels', () => { ).toBe(true); expect( shouldShowChannelWhenHidingMutedChannels({ - isMuted: true, + isCategoryMuted: true, + isChannelMuted: false, isSelected: false, isConnected: true, hasVisibleUnread: false, @@ -52,7 +80,8 @@ describe('shouldShowChannelWhenHidingMutedChannels', () => { it('keeps unmuted channels visible', () => { expect( shouldShowChannelWhenHidingMutedChannels({ - isMuted: false, + isCategoryMuted: false, + isChannelMuted: false, isSelected: false, isConnected: false, hasVisibleUnread: false, 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 7a1754e21..d1af52049 100644 --- a/fluxer_app/src/features/app/components/layout/utils/ChannelListVisibility.ts +++ b/fluxer_app/src/features/app/components/layout/utils/ChannelListVisibility.ts @@ -1,19 +1,21 @@ // SPDX-License-Identifier: AGPL-3.0-or-later export interface HiddenMutedChannelVisibilityInput { - isMuted: boolean; + isCategoryMuted: boolean; + isChannelMuted: boolean; isSelected: boolean; isConnected: boolean; hasVisibleUnread: boolean; } export function shouldShowChannelWhenHidingMutedChannels({ - isMuted, + isCategoryMuted, + isChannelMuted, isSelected, isConnected, hasVisibleUnread, }: HiddenMutedChannelVisibilityInput): boolean { - return isSelected || isConnected || !isMuted || hasVisibleUnread; + return isSelected || isConnected || !(isCategoryMuted || isChannelMuted) || hasVisibleUnread; } export interface HiddenMutedCategoryVisibilityInput {