diff --git a/lib/hooks/thread-search-hooks.js b/lib/hooks/thread-search-hooks.js --- a/lib/hooks/thread-search-hooks.js +++ b/lib/hooks/thread-search-hooks.js @@ -10,13 +10,19 @@ useForwardLookupSearchText, useSearchUsers, } from '../shared/search-utils.js'; +import { useUserSupportThickThread } from '../shared/thread-utils.js'; import type { GlobalAccountUserInfo } from '../types/user-types.js'; import { useSelector } from '../utils/redux-utils.js'; import { usingCommServicesAccessToken } from '../utils/services-utils.js'; +export type UserSearchResult = $ReadOnly<{ + ...GlobalAccountUserInfo, + +supportThickThreads: boolean, +}>; + type ThreadListSearchResult = { +threadSearchResults: $ReadOnlySet, - +usersSearchResults: $ReadOnlyArray, + +usersSearchResults: $ReadOnlyArray, }; function useThreadListSearch( @@ -27,7 +33,7 @@ const forwardLookupSearchText = useForwardLookupSearchText(searchText); const filterAndSetUserResults = React.useCallback( - (userInfos: $ReadOnlyArray) => { + (userInfos: $ReadOnlyArray) => { const usersResults = userInfos.filter( info => !usersWithPersonalThread.has(info.id) && info.id !== viewerID, ); @@ -45,7 +51,12 @@ } const { userInfos } = await legacyCallSearchUsers(usernamePrefix); - filterAndSetUserResults(userInfos); + filterAndSetUserResults( + userInfos.map(userInfo => ({ + ...userInfo, + supportThickThreads: false, + })), + ); }, [filterAndSetUserResults, legacyCallSearchUsers], ); @@ -54,7 +65,7 @@ new Set(), ); const [usersSearchResults, setUsersSearchResults] = React.useState< - $ReadOnlyArray, + $ReadOnlyArray, >([]); const threadSearchIndex = useGlobalThreadSearchIndex(); React.useEffect(() => { @@ -72,12 +83,24 @@ legacySearchUsers, ]); + const usersSupportsThickThreads = useUserSupportThickThread(); const identitySearchUsers = useSearchUsers(forwardLookupSearchText); React.useEffect(() => { - if (usingCommServicesAccessToken) { - filterAndSetUserResults(identitySearchUsers); - } - }, [filterAndSetUserResults, identitySearchUsers]); + void (async () => { + if (usingCommServicesAccessToken) { + const userIDsSupportingThickThreads = await usersSupportsThickThreads( + identitySearchUsers.map(user => user.id), + ); + const set = new Set(userIDsSupportingThickThreads); + filterAndSetUserResults( + identitySearchUsers.map(search => ({ + ...search, + supportThickThreads: set.has(search.id), + })), + ); + } + })(); + }, [filterAndSetUserResults, identitySearchUsers, usersSupportsThickThreads]); return { threadSearchResults, usersSearchResults }; } diff --git a/lib/shared/thread-utils.js b/lib/shared/thread-utils.js --- a/lib/shared/thread-utils.js +++ b/lib/shared/thread-utils.js @@ -12,10 +12,12 @@ import { generatePendingThreadColor } from './color-utils.js'; import { extractUserMentionsFromText } from './mention-utils.js'; import { relationshipBlockedInEitherDirection } from './relationship-utils.js'; +import { useFindUserIdentities } from '../actions/user-actions.js'; import ashoat from '../facts/ashoat.js'; import genesis from '../facts/genesis.js'; import { useLoggedInUserInfo } from '../hooks/account-hooks.js'; import { useAllowOlmViaTunnelbrokerForDMs } from '../hooks/flag-hooks.js'; +import { type UserSearchResult } from '../hooks/thread-search-hooks.js'; import { extractKeyserverIDFromIDOptional } from '../keyserver-conn/keyserver-call-utils.js'; import { hasPermission, @@ -93,7 +95,6 @@ import { updateTypes } from '../types/update-types-enum.js'; import { type ClientUpdateInfo } from '../types/update-types.js'; import type { - GlobalAccountUserInfo, UserInfos, AccountUserInfo, LoggedInUserInfo, @@ -602,14 +603,14 @@ loggedInUserInfo: LoggedInUserInfo, userID: string, username: ?string, - allowOlmViaTunnelbrokerForDMs: boolean, + supportThickThreads: boolean, ): PendingPersonalThread { const pendingPersonalThreadUserInfo = { id: userID, username: username, }; - const threadType = allowOlmViaTunnelbrokerForDMs + const threadType = supportThickThreads ? threadTypes.PERSONAL : threadTypes.GENESIS_PERSONAL; @@ -625,14 +626,14 @@ function createPendingThreadItem( loggedInUserInfo: LoggedInUserInfo, user: UserIDAndUsername, - allowOlmViaTunnelbrokerForDMs: boolean, + supportThickThreads: boolean, ): ChatThreadItem { const { threadInfo, pendingPersonalThreadUserInfo } = createPendingPersonalThread( loggedInUserInfo, user.id, user.username, - allowOlmViaTunnelbrokerForDMs, + supportThickThreads, ); return { @@ -1438,9 +1439,8 @@ searchText: string, threadFilter: ThreadInfo => boolean, threadSearchResults: $ReadOnlySet, - usersSearchResults: $ReadOnlyArray, + usersSearchResults: $ReadOnlyArray, loggedInUserInfo: ?LoggedInUserInfo, - allowOlmViaTunnelbrokerForDMs: boolean, ): $ReadOnlyArray { if (!searchText) { return chatListData.filter( @@ -1476,7 +1476,7 @@ createPendingThreadItem( loggedInUserInfo, user, - allowOlmViaTunnelbrokerForDMs, + user.supportThickThreads, ), ), ); @@ -1710,7 +1710,19 @@ const usersWithPersonalThread = useSelector(usersWithPersonalThreadSelector); - const allowOlmViaTunnelbrokerForDMs = useAllowOlmViaTunnelbrokerForDMs(); + const [supportThickThreads, setSupportThickThreads] = React.useState(false); + const usersSupportsThickThreads = useUserSupportThickThread(); + + React.useEffect(() => { + void (async () => { + if (!userInfo) { + setSupportThickThreads(false); + return; + } + const [result] = await usersSupportsThickThreads([userInfo.id]); + setSupportThickThreads(!!result); + })(); + }, [userInfo, usersSupportsThickThreads]); return React.useMemo(() => { if (!loggedInUserInfo || !userID || !username) { @@ -1736,16 +1748,16 @@ loggedInUserInfo, userID, username, - allowOlmViaTunnelbrokerForDMs, + supportThickThreads, ); return pendingPersonalThreadInfo; }, [ - allowOlmViaTunnelbrokerForDMs, isViewerProfile, loggedInUserInfo, personalThreadInfos, privateThreadInfos, + supportThickThreads, userID, username, usersWithPersonalThread, @@ -1806,6 +1818,41 @@ ); } +function useUserSupportThickThread(): ( + userIDs: $ReadOnlyArray, +) => Promise<$ReadOnlyArray> { + const findUserIdentities = useFindUserIdentities(); + const auxUserInfos = useSelector(state => state.auxUserStore.auxUserInfos); + const allowOlmViaTunnelbrokerForDMs = useAllowOlmViaTunnelbrokerForDMs(); + + return React.useCallback( + async (userIDs: $ReadOnlyArray) => { + if (!allowOlmViaTunnelbrokerForDMs) { + return []; + } + const usersSupportingThickThreads = []; + const usersNeedsFetch = []; + for (const userID of userIDs) { + if (userHasDeviceList(userID, auxUserInfos)) { + usersSupportingThickThreads.push(userID); + } else { + usersNeedsFetch.push(userID); + } + } + if (usersNeedsFetch.length > 0) { + const { identities } = await findUserIdentities(usersNeedsFetch); + for (const userID of usersNeedsFetch) { + if (identities[userID]) { + usersSupportingThickThreads.push(userID); + } + } + } + return usersSupportingThickThreads; + }, + [allowOlmViaTunnelbrokerForDMs, auxUserInfos, findUserIdentities], + ); +} + export { threadHasPermission, useCommunityRootMembersToRole, @@ -1873,4 +1920,5 @@ isMemberActive, createThreadTimestamps, userHasDeviceList, + useUserSupportThickThread, }; diff --git a/native/chat/chat-thread-list.react.js b/native/chat/chat-thread-list.react.js --- a/native/chat/chat-thread-list.react.js +++ b/native/chat/chat-thread-list.react.js @@ -279,8 +279,6 @@ ], ); - const allowOlmViaTunnelbrokerForDMs = useAllowOlmViaTunnelbrokerForDMs(); - const listData: $ReadOnlyArray = React.useMemo(() => { const chatThreadItems = getThreadListSearchResults( boundChatListData, @@ -289,7 +287,6 @@ threadSearchResults, usersSearchResults, loggedInUserInfo, - allowOlmViaTunnelbrokerForDMs, ); const chatItems: Item[] = [...chatThreadItems]; @@ -304,7 +301,6 @@ return chatItems; }, [ - allowOlmViaTunnelbrokerForDMs, boundChatListData, emptyItem, filterThreads, diff --git a/web/chat/thread-list-provider.js b/web/chat/thread-list-provider.js --- a/web/chat/thread-list-provider.js +++ b/web/chat/thread-list-provider.js @@ -4,7 +4,6 @@ import * as React from 'react'; import { useLoggedInUserInfo } from 'lib/hooks/account-hooks.js'; -import { useAllowOlmViaTunnelbrokerForDMs } from 'lib/hooks/flag-hooks.js'; import { useThreadListSearch } from 'lib/hooks/thread-search-hooks.js'; import { type ChatThreadItem, @@ -180,7 +179,6 @@ ); const threadFilter = activeTab === 'Muted' ? threadInBackgroundChatList : threadInHomeChatList; - const allowOlmViaTunnelbrokerForDMs = useAllowOlmViaTunnelbrokerForDMs(); const chatListDataWithoutFilter = getThreadListSearchResults( chatListData, searchText, @@ -188,7 +186,6 @@ threadSearchResults, usersSearchResults, loggedInUserInfo, - allowOlmViaTunnelbrokerForDMs, ); const activeTopLevelChatThreadItem = useChatThreadItem( activeTopLevelThreadInfo,