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 @@ -2,6 +2,7 @@ import * as React from 'react'; +import { useUsersSupportThickThreads } from './user-identities-hooks.js'; import { searchUsers as searchUserCall } from '../actions/user-actions.js'; import { useLegacyAshoatKeyserverCall } from '../keyserver-conn/legacy-keyserver-call.js'; import { useGlobalThreadSearchIndex } from '../selectors/nav-selectors.js'; @@ -14,9 +15,14 @@ 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,25 @@ legacySearchUsers, ]); + const usersSupportThickThreads = useUsersSupportThickThreads(); const identitySearchUsers = useSearchUsers(forwardLookupSearchText); React.useEffect(() => { - if (usingCommServicesAccessToken) { - filterAndSetUserResults(identitySearchUsers); - } - }, [filterAndSetUserResults, identitySearchUsers]); + void (async () => { + if (!usingCommServicesAccessToken) { + return; + } + + const userIDsSupportingThickThreads = await usersSupportThickThreads( + identitySearchUsers.map(user => user.id), + ); + filterAndSetUserResults( + identitySearchUsers.map(search => ({ + ...search, + supportThickThreads: userIDsSupportingThickThreads.has(search.id), + })), + ); + })(); + }, [filterAndSetUserResults, identitySearchUsers, usersSupportThickThreads]); return { threadSearchResults, usersSearchResults }; } diff --git a/lib/hooks/user-identities-hooks.js b/lib/hooks/user-identities-hooks.js new file mode 100644 --- /dev/null +++ b/lib/hooks/user-identities-hooks.js @@ -0,0 +1,47 @@ +// @flow + +import * as React from 'react'; + +import { useAllowOlmViaTunnelbrokerForDMs } from './flag-hooks.js'; +import { useFindUserIdentities } from '../actions/find-user-identities-actions.js'; +import { userHasDeviceList } from '../shared/thread-utils.js'; +import { useSelector } from '../utils/redux-utils.js'; + +function useUsersSupportThickThreads(): ( + userIDs: $ReadOnlyArray, +) => Promise<$ReadOnlySet> { + const findUserIdentities = useFindUserIdentities(); + const auxUserInfos = useSelector(state => state.auxUserStore.auxUserInfos); + const allowOlmViaTunnelbrokerForDMs = useAllowOlmViaTunnelbrokerForDMs(); + + return React.useCallback( + async (userIDs: $ReadOnlyArray) => { + const usersSupportingThickThreads = new Set(); + + if (!allowOlmViaTunnelbrokerForDMs) { + return usersSupportingThickThreads; + } + + const usersNeedingFetch = []; + for (const userID of userIDs) { + if (userHasDeviceList(userID, auxUserInfos)) { + usersSupportingThickThreads.add(userID); + } else { + usersNeedingFetch.push(userID); + } + } + if (usersNeedingFetch.length > 0) { + const { identities } = await findUserIdentities(usersNeedingFetch); + for (const userID of usersNeedingFetch) { + if (identities[userID]) { + usersSupportingThickThreads.add(userID); + } + } + } + return usersSupportingThickThreads; + }, + [allowOlmViaTunnelbrokerForDMs, auxUserInfos, findUserIdentities], + ); +} + +export { useUsersSupportThickThreads }; 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 @@ -16,6 +16,8 @@ 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 { useUsersSupportThickThreads } from '../hooks/user-identities-hooks.js'; import { extractKeyserverIDFromIDOptional } from '../keyserver-conn/keyserver-call-utils.js'; import { hasPermission, @@ -95,7 +97,6 @@ import { updateTypes } from '../types/update-types-enum.js'; import { type ClientUpdateInfo } from '../types/update-types.js'; import type { - GlobalAccountUserInfo, UserInfos, AccountUserInfo, LoggedInUserInfo, @@ -604,14 +605,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; @@ -627,14 +628,14 @@ function createPendingThreadItem( loggedInUserInfo: LoggedInUserInfo, user: UserIDAndUsername, - allowOlmViaTunnelbrokerForDMs: boolean, + supportThickThreads: boolean, ): ChatThreadItem { const { threadInfo, pendingPersonalThreadUserInfo } = createPendingPersonalThread( loggedInUserInfo, user.id, user.username, - allowOlmViaTunnelbrokerForDMs, + supportThickThreads, ); return { @@ -1440,9 +1441,8 @@ searchText: string, threadFilter: ThreadInfo => boolean, threadSearchResults: $ReadOnlySet, - usersSearchResults: $ReadOnlyArray, + usersSearchResults: $ReadOnlyArray, loggedInUserInfo: ?LoggedInUserInfo, - allowOlmViaTunnelbrokerForDMs: boolean, ): $ReadOnlyArray { if (!searchText) { return chatListData.filter( @@ -1478,7 +1478,7 @@ createPendingThreadItem( loggedInUserInfo, user, - allowOlmViaTunnelbrokerForDMs, + user.supportThickThreads, ), ), ); @@ -1712,7 +1712,19 @@ const usersWithPersonalThread = useSelector(usersWithPersonalThreadSelector); - const allowOlmViaTunnelbrokerForDMs = useAllowOlmViaTunnelbrokerForDMs(); + const [supportThickThreads, setSupportThickThreads] = React.useState(false); + const usersSupportThickThreads = useUsersSupportThickThreads(); + + React.useEffect(() => { + void (async () => { + if (!userInfo) { + setSupportThickThreads(false); + return; + } + const result = await usersSupportThickThreads([userInfo.id]); + setSupportThickThreads(result.has(userInfo.id)); + })(); + }, [userInfo, usersSupportThickThreads]); return React.useMemo(() => { if (!loggedInUserInfo || !userID || !username) { @@ -1738,16 +1750,16 @@ loggedInUserInfo, userID, username, - allowOlmViaTunnelbrokerForDMs, + supportThickThreads, ); return pendingPersonalThreadInfo; }, [ - allowOlmViaTunnelbrokerForDMs, isViewerProfile, loggedInUserInfo, personalThreadInfos, privateThreadInfos, + supportThickThreads, userID, username, usersWithPersonalThread, 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,