Chat folders: for unread, check setting and active notification profile

This commit is contained in:
Scott Nonnenberg
2025-11-06 07:06:52 +10:00
committed by GitHub
parent aa78798be6
commit 1925044e9d
7 changed files with 42 additions and 18 deletions

View File

@@ -391,13 +391,6 @@ export class ConversationController {
const unreadStats = countAllConversationsUnreadStats( const unreadStats = countAllConversationsUnreadStats(
this.#_conversations.map( this.#_conversations.map(
(conversation): ConversationPropsForUnreadStats | undefined => { (conversation): ConversationPropsForUnreadStats | undefined => {
if (
activeProfile &&
!activeProfile.allowedMembers.has(conversation.id)
) {
return undefined;
}
// Need to pull this out manually into the Redux shape // Need to pull this out manually into the Redux shape
// because `conversation.format()` can return cached props by the // because `conversation.format()` can return cached props by the
// time this runs // time this runs
@@ -414,6 +407,7 @@ export class ConversationController {
} }
), ),
{ {
activeProfile,
includeMuted: badgeCountMutedConversationsSetting includeMuted: badgeCountMutedConversationsSetting
? 'setting-on' ? 'setting-on'
: 'setting-off', : 'setting-off',

View File

@@ -177,7 +177,7 @@ export class NotificationProfilesService {
updateCurrentState(currentState, currentActiveProfile); updateCurrentState(currentState, currentActiveProfile);
// The active profile can influence the overall badge count // The active profile can influence the overall badge count
window.ConversationController.updateUnreadCount(); window.Whisper.events.emit('updateUnreadCount');
} }
if (previousActiveProfile?.id === currentActiveProfileId) { if (previousActiveProfile?.id === currentActiveProfileId) {

View File

@@ -333,7 +333,10 @@ function shouldRemoveConversationFromUnreadList(
conversation && conversation &&
(selectedConversationId == null || (selectedConversationId == null ||
selectedConversationId !== conversation.id) && selectedConversationId !== conversation.id) &&
!isConversationUnread(conversation, { includeMuted: 'force-exclude' }) !isConversationUnread(conversation, {
activeProfile: undefined,
includeMuted: 'force-exclude',
})
) { ) {
return true; return true;
} }
@@ -499,6 +502,7 @@ const doSearch = debounce(
selectedConversation && selectedConversation &&
state.search.conversationIds.includes(selectedConversationId) && state.search.conversationIds.includes(selectedConversationId) &&
!isConversationUnread(selectedConversation, { !isConversationUnread(selectedConversation, {
activeProfile: undefined,
includeMuted: 'force-include', includeMuted: 'force-include',
}) })
? selectedConversation ? selectedConversation

View File

@@ -89,6 +89,7 @@ import {
} from '../../util/countUnreadStats.std.js'; } from '../../util/countUnreadStats.std.js';
import type { AllChatFoldersMutedStats } from '../../util/countMutedStats.std.js'; import type { AllChatFoldersMutedStats } from '../../util/countMutedStats.std.js';
import { countAllChatFoldersMutedStats } from '../../util/countMutedStats.std.js'; import { countAllChatFoldersMutedStats } from '../../util/countMutedStats.std.js';
import { getActiveProfile } from './notificationProfiles.dom.js';
const { isNumber, pick } = lodash; const { isNumber, pick } = lodash;
@@ -699,8 +700,10 @@ export const getAllConversationsUnreadStats: StateSelector<UnreadStats> =
createSelector( createSelector(
getAllConversations, getAllConversations,
getBadgeCountMutedConversations, getBadgeCountMutedConversations,
(conversations, badgeCountMutedConversations) => { getActiveProfile,
(conversations, badgeCountMutedConversations, activeProfile) => {
return countAllConversationsUnreadStats(conversations, { return countAllConversationsUnreadStats(conversations, {
activeProfile,
includeMuted: badgeCountMutedConversations includeMuted: badgeCountMutedConversations
? 'setting-on' ? 'setting-on'
: 'setting-off', : 'setting-off',
@@ -713,11 +716,18 @@ export const getAllChatFoldersUnreadStats: StateSelector<AllChatFoldersUnreadSta
getCurrentChatFolders, getCurrentChatFolders,
getAllConversations, getAllConversations,
getBadgeCountMutedConversations, getBadgeCountMutedConversations,
(currentChatFolders, allConversations, badgeCountMutedConversations) => { getActiveProfile,
(
currentChatFolders,
allConversations,
badgeCountMutedConversations,
activeProfile
) => {
return countAllChatFoldersUnreadStats( return countAllChatFoldersUnreadStats(
currentChatFolders, currentChatFolders,
allConversations, allConversations,
{ {
activeProfile,
includeMuted: badgeCountMutedConversations includeMuted: badgeCountMutedConversations
? 'setting-on' ? 'setting-on'
: 'setting-off', : 'setting-off',

View File

@@ -90,7 +90,10 @@ describe('countUnreadStats', () => {
expected: boolean, expected: boolean,
includeMuted: UnreadStatsIncludeMuted = 'force-include' includeMuted: UnreadStatsIncludeMuted = 'force-include'
) { ) {
const actual = _canCountConversation(mockChat(chat), { includeMuted }); const actual = _canCountConversation(mockChat(chat), {
activeProfile: undefined,
includeMuted,
});
assert.equal(actual, expected); assert.equal(actual, expected);
} }
@@ -172,7 +175,10 @@ describe('countUnreadStats', () => {
expected: boolean, expected: boolean,
includeMuted: UnreadStatsIncludeMuted = 'force-exclude' includeMuted: UnreadStatsIncludeMuted = 'force-exclude'
) { ) {
const actual = isConversationUnread(mockChat(chat), { includeMuted }); const actual = isConversationUnread(mockChat(chat), {
activeProfile: undefined,
includeMuted,
});
assert.equal(actual, expected); assert.equal(actual, expected);
} }
@@ -213,6 +219,7 @@ describe('countUnreadStats', () => {
includeMuted: UnreadStatsIncludeMuted = 'force-exclude' includeMuted: UnreadStatsIncludeMuted = 'force-exclude'
) { ) {
const actual = countConversationUnreadStats(mockChat(chat), { const actual = countConversationUnreadStats(mockChat(chat), {
activeProfile: undefined,
includeMuted, includeMuted,
}); });
assert.deepEqual(actual, mockStats(expected)); assert.deepEqual(actual, mockStats(expected));
@@ -252,6 +259,7 @@ describe('countUnreadStats', () => {
includeMuted: UnreadStatsIncludeMuted = 'force-exclude' includeMuted: UnreadStatsIncludeMuted = 'force-exclude'
) { ) {
const actual = countAllConversationsUnreadStats(chats.map(mockChat), { const actual = countAllConversationsUnreadStats(chats.map(mockChat), {
activeProfile: undefined,
includeMuted, includeMuted,
}); });
assert.deepEqual(actual, mockStats(expected)); assert.deepEqual(actual, mockStats(expected));
@@ -323,7 +331,7 @@ describe('countUnreadStats', () => {
const actual = countAllChatFoldersUnreadStats( const actual = countAllChatFoldersUnreadStats(
CurrentChatFolders.fromArray(folders), CurrentChatFolders.fromArray(folders),
chats.map(mockChat), chats.map(mockChat),
{ includeMuted } { activeProfile: undefined, includeMuted }
); );
assert.deepEqual(actual, expected); assert.deepEqual(actual, expected);

View File

@@ -1,12 +1,14 @@
// Copyright 2023 Signal Messenger, LLC // Copyright 2023 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only // SPDX-License-Identifier: AGPL-3.0-only
import type { ConversationType } from '../state/ducks/conversations.preload.js';
import { isConversationInChatFolder } from '../types/ChatFolder.std.js'; import { isConversationInChatFolder } from '../types/ChatFolder.std.js';
import type { ChatFolderId } from '../types/ChatFolder.std.js';
import { CurrentChatFolders } from '../types/CurrentChatFolders.std.js'; import { CurrentChatFolders } from '../types/CurrentChatFolders.std.js';
import { isConversationMuted } from './isConversationMuted.std.js'; import { isConversationMuted } from './isConversationMuted.std.js';
import type { ConversationType } from '../state/ducks/conversations.preload.js';
import type { ChatFolderId } from '../types/ChatFolder.std.js';
import type { NotificationProfileType } from '../types/NotificationProfile.std.js';
type MutableUnreadStats = { type MutableUnreadStats = {
/** /**
* Total of `conversation.unreadCount` * Total of `conversation.unreadCount`
@@ -53,6 +55,7 @@ export type UnreadStatsIncludeMuted =
export type UnreadStatsOptions = Readonly<{ export type UnreadStatsOptions = Readonly<{
includeMuted: UnreadStatsIncludeMuted; includeMuted: UnreadStatsIncludeMuted;
activeProfile: NotificationProfileType | undefined;
}>; }>;
export type ConversationPropsForUnreadStats = Readonly< export type ConversationPropsForUnreadStats = Readonly<
@@ -93,7 +96,9 @@ export function _canCountConversation(
if ( if (
_shouldExcludeMuted(options.includeMuted) && _shouldExcludeMuted(options.includeMuted) &&
isConversationMuted(conversation) (isConversationMuted(conversation) ||
(options.activeProfile &&
!options.activeProfile.allowedMembers.has(conversation.id)))
) { ) {
return false; return false;
} }

View File

@@ -72,7 +72,10 @@ function filterConversationsByUnread(
includeMuted: UnreadStatsIncludeMuted includeMuted: UnreadStatsIncludeMuted
): Array<ConversationType> { ): Array<ConversationType> {
return conversations.filter(conversation => { return conversations.filter(conversation => {
return isConversationUnread(conversation, { includeMuted }); return isConversationUnread(conversation, {
activeProfile: undefined,
includeMuted,
});
}); });
} }