diff --git a/keyserver/src/endpoints.js b/keyserver/src/endpoints.js --- a/keyserver/src/endpoints.js +++ b/keyserver/src/endpoints.js @@ -42,6 +42,7 @@ threadUpdateResponder, threadCreationResponder, threadJoinResponder, + threadFetchMediaResponder, } from './responders/thread-responders'; import { userSubscriptionUpdateResponder, @@ -133,6 +134,10 @@ responder: messageFetchResponder, requiredPolicies: baseLegalPolicies, }, + fetch_thread_media: { + responder: threadFetchMediaResponder, + requiredPolicies: baseLegalPolicies, + }, get_session_public_keys: { responder: getSessionPublicKeysResponder, requiredPolicies: baseLegalPolicies, diff --git a/keyserver/src/responders/thread-responders.js b/keyserver/src/responders/thread-responders.js --- a/keyserver/src/responders/thread-responders.js +++ b/keyserver/src/responders/thread-responders.js @@ -3,6 +3,7 @@ import t from 'tcomb'; import type { TUnion, TInterface } from 'tcomb'; +import type { Media } from 'lib/types/media-types'; import { type ThreadDeletionRequest, type RoleChangeRequest, @@ -15,6 +16,7 @@ type NewThreadResponse, type ServerThreadJoinRequest, type ThreadJoinResult, + type ThreadFetchMediaRequest, threadTypes, } from 'lib/types/thread-types'; import { values } from 'lib/utils/objects'; @@ -27,6 +29,7 @@ import { createThread } from '../creators/thread-creator'; import { deleteThread } from '../deleters/thread-deleters'; +import { fetchMediaForThread } from '../fetchers/upload-fetchers'; import type { Viewer } from '../session/viewer'; import { updateRole, @@ -176,6 +179,18 @@ return await joinThread(viewer, request); } +const threadFetchMediaRequestInputValidator = tShape({ + threadID: t.String, +}); +async function threadFetchMediaResponder( + viewer: Viewer, + input: any, +): Promise<$ReadOnlyArray> { + const request: ThreadFetchMediaRequest = input; + await validateInput(viewer, threadFetchMediaRequestInputValidator, request); + return await fetchMediaForThread(request.threadID); +} + export { threadDeletionResponder, roleUpdateResponder, @@ -184,5 +199,6 @@ threadUpdateResponder, threadCreationResponder, threadJoinResponder, + threadFetchMediaResponder, newThreadRequestInputValidator, }; diff --git a/lib/actions/thread-actions.js b/lib/actions/thread-actions.js --- a/lib/actions/thread-actions.js +++ b/lib/actions/thread-actions.js @@ -2,6 +2,7 @@ import invariant from 'invariant'; +import type { Media } from '../types/media-types'; import type { ChangeThreadSettingsPayload, LeaveThreadPayload, @@ -162,6 +163,13 @@ }; }; +const fetchThreadMedia = ( + callServerEndpoint: CallServerEndpoint, +): ((threadID: string) => Promise<$ReadOnlyArray>) => async threadID => { + const response = await callServerEndpoint('fetch_thread_media', { threadID }); + return response; +}; + export { deleteThreadActionTypes, deleteThread, @@ -177,4 +185,5 @@ joinThread, leaveThreadActionTypes, leaveThread, + fetchThreadMedia, }; diff --git a/lib/types/endpoints.js b/lib/types/endpoints.js --- a/lib/types/endpoints.js +++ b/lib/types/endpoints.js @@ -61,6 +61,7 @@ FETCH_ENTRY_REVISIONS: 'fetch_entry_revisions', FETCH_ERROR_REPORT_INFOS: 'fetch_error_report_infos', FETCH_MESSAGES: 'fetch_messages', + FETCH_THREAD_MEDIA: 'fetch_thread_media', GET_SESSION_PUBLIC_KEYS: 'get_session_public_keys', JOIN_THREAD: 'join_thread', LEAVE_THREAD: 'leave_thread', diff --git a/lib/types/thread-types.js b/lib/types/thread-types.js --- a/lib/types/thread-types.js +++ b/lib/types/thread-types.js @@ -434,6 +434,10 @@ +userInfos: $ReadOnlyArray, }; +export type ThreadFetchMediaRequest = { + +threadID: string, +}; + export type SidebarInfo = { +threadInfo: ThreadInfo, +lastUpdatedTime: number, diff --git a/native/chat/settings/thread-settings-media-gallery.react.js b/native/chat/settings/thread-settings-media-gallery.react.js --- a/native/chat/settings/thread-settings-media-gallery.react.js +++ b/native/chat/settings/thread-settings-media-gallery.react.js @@ -8,16 +8,57 @@ FlatList, useWindowDimensions, } from 'react-native'; +import Video from 'react-native-video'; + +import { fetchThreadMedia } from 'lib/actions/thread-actions'; +import { useServerCall } from 'lib/utils/action-utils'; import { useStyles } from '../../themes/colors'; +import { defaultURLPrefix } from '../../utils/url-utils'; + +type ThreadSettingsMediaGalleryProps = { + +threadID: string, +}; -function ThreadSettingsMediaGallery(): React.Node { +function ThreadSettingsMediaGallery( + props: ThreadSettingsMediaGalleryProps, +): React.Node { const styles = useStyles(unboundStyles); const galleryItemGap = 8; const { width } = useWindowDimensions(); - const galleryItemWidth = (width - galleryItemGap * 3) / 3; - const mediaInfos = []; + + const { threadID } = props; + const [mediaInfos, setMediaInfos] = React.useState([]); + const callFetchThreadMedia = useServerCall(fetchThreadMedia); + + React.useEffect(() => { + const fetchData = async () => { + const result = await callFetchThreadMedia(threadID); + setMediaInfos(result); + }; + fetchData(); + }, [callFetchThreadMedia, threadID]); + + // We create this array to handle both production and dev environments. + // Within the dev environment, the `http://localhost:3000/comm` prefix is + // fine for the iOS simulator, but not for Android. So we replace it with + // `defaultURLPrefix` which is `http://localhost:3000/comm` for iOS and + // `http://10.0.2.2:3000/comm` for Android. Within production, we don't need + // to do anything (in theory). + let mediaInfosForEnvironment = []; + if (mediaInfos.length > 0) { + mediaInfosForEnvironment = mediaInfos.map(media => { + if (__DEV__) { + const uri = media.uri.replace( + 'http://localhost:3000/comm', + defaultURLPrefix, + ); + return { ...media, uri }; + } + return media; + }); + } const memoizedStyles = React.useMemo(() => { return { @@ -39,7 +80,18 @@ return ( - + {item.type === 'photo' ? ( + + ) : ( + ); @@ -47,7 +99,13 @@ [memoizedStyles.media, memoizedStyles.mediaContainer], ); - return ; + return ( + + ); } const unboundStyles = { diff --git a/native/chat/settings/thread-settings.react.js b/native/chat/settings/thread-settings.react.js --- a/native/chat/settings/thread-settings.react.js +++ b/native/chat/settings/thread-settings.react.js @@ -923,7 +923,7 @@ } else if (item.itemType === 'addMember') { return ; } else if (item.itemType === 'mediaGallery') { - return ; + return ; } else if (item.itemType === 'leaveThread') { return (