diff --git a/lib/shared/threads/protocols/dm-thread-protocol.js b/lib/shared/threads/protocols/dm-thread-protocol.js --- a/lib/shared/threads/protocols/dm-thread-protocol.js +++ b/lib/shared/threads/protocols/dm-thread-protocol.js @@ -905,6 +905,8 @@ }, supportsEncryptedMultimedia: true, + supportsSendingVideos: true, + canSendMultipleMedia: true, uploadMultimediaMetadataToKeyserver: false, canActionsTargetPendingMessages: true, diff --git a/lib/shared/threads/protocols/farcaster-thread-protocol.js b/lib/shared/threads/protocols/farcaster-thread-protocol.js --- a/lib/shared/threads/protocols/farcaster-thread-protocol.js +++ b/lib/shared/threads/protocols/farcaster-thread-protocol.js @@ -771,6 +771,8 @@ }, supportsEncryptedMultimedia: false, + supportsSendingVideos: false, + canSendMultipleMedia: false, uploadMultimediaMetadataToKeyserver: false, canActionsTargetPendingMessages: false, messagesStoredOnServer: false, diff --git a/lib/shared/threads/protocols/keyserver-thread-protocol.js b/lib/shared/threads/protocols/keyserver-thread-protocol.js --- a/lib/shared/threads/protocols/keyserver-thread-protocol.js +++ b/lib/shared/threads/protocols/keyserver-thread-protocol.js @@ -707,6 +707,8 @@ }, supportsEncryptedMultimedia: true, + supportsSendingVideos: true, + canSendMultipleMedia: true, uploadMultimediaMetadataToKeyserver: true, canActionsTargetPendingMessages: false, diff --git a/lib/shared/threads/thread-spec.js b/lib/shared/threads/thread-spec.js --- a/lib/shared/threads/thread-spec.js +++ b/lib/shared/threads/thread-spec.js @@ -478,6 +478,8 @@ +threadSearchHeaderShowsGenesis: boolean, }, +supportsEncryptedMultimedia: boolean, + +supportsSendingVideos: boolean, + +canSendMultipleMedia: boolean, +uploadMultimediaMetadataToKeyserver: boolean, +canActionsTargetPendingMessages: boolean, +sidebarConfig?: { diff --git a/native/media/media-gallery-keyboard.react.js b/native/media/media-gallery-keyboard.react.js --- a/native/media/media-gallery-keyboard.react.js +++ b/native/media/media-gallery-keyboard.react.js @@ -22,6 +22,7 @@ filenameFromPathOrURI, } from 'lib/media/file-utils.js'; import { useIsAppForegrounded } from 'lib/shared/lifecycle-utils.js'; +import { threadSpecs } from 'lib/shared/threads/thread-specs.js'; import type { MediaLibrarySelection } from 'lib/types/media-types.js'; import type { ThreadInfo } from 'lib/types/minimally-encoded-thread-permissions-types.js'; @@ -252,14 +253,20 @@ if (!hasPermission) { return; } + const supportsSendingVideos = this.props.threadInfo + ? threadSpecs[this.props.threadInfo.type].protocol() + .supportsSendingVideos + : false; + + const supportedMediaTypes = supportsSendingVideos + ? [MediaLibrary.MediaType.photo, MediaLibrary.MediaType.video] + : [MediaLibrary.MediaType.photo]; + const { assets, endCursor, hasNextPage } = await MediaLibrary.getAssetsAsync({ first: 20, after, - mediaType: [ - MediaLibrary.MediaType.photo, - MediaLibrary.MediaType.video, - ], + mediaType: supportedMediaTypes, sortBy: [MediaLibrary.SortBy.modificationTime], }); @@ -351,10 +358,21 @@ openNativePicker = async () => { try { + const protocol = + this.props.threadInfo && + threadSpecs[this.props.threadInfo.type].protocol(); + + const canSendMultipleMedia = protocol?.canSendMultipleMedia ?? false; + const supportsSendingVideos = protocol?.supportsSendingVideos ?? false; + + const mediaTypes = supportsSendingVideos + ? ['images', 'videos'] + : 'images'; + const { assets, canceled } = await ImagePicker.launchImageLibraryAsync({ - mediaTypes: ImagePicker.MediaTypeOptions.All, + mediaTypes, allowsEditing: false, - allowsMultipleSelection: true, + allowsMultipleSelection: canSendMultipleMedia, // maximum quality is 1 - it disables compression quality: 1, // we don't want to compress videos at this point @@ -444,11 +462,17 @@ const { uri } = row.item; const isQueued = !!(queuedMediaURIs && queuedMediaURIs.has(uri)); const { queueModeActive } = this; + + const canSendMultipleMedia = this.props.threadInfo + ? threadSpecs[this.props.threadInfo.type].protocol().canSendMultipleMedia + : false; + return ( void, +sendMedia: (media: MediaLibrarySelection) => void, +isFocused: boolean, @@ -179,6 +180,20 @@ let buttons = null; if (!queueModeActive) { + let enqueueButton = null; + if (props.allowQueue) { + enqueueButton = ( + + + Queue + + ); + } buttons = ( <> Send - - - Queue - + {enqueueButton} ); } diff --git a/web/chat/chat-input-bar.react.js b/web/chat/chat-input-bar.react.js --- a/web/chat/chat-input-bar.react.js +++ b/web/chat/chat-input-bar.react.js @@ -34,6 +34,7 @@ useThreadHasPermission, viewerIsMember, } from 'lib/shared/thread-utils.js'; +import { threadSpecs } from 'lib/shared/threads/thread-specs.js'; import type { CalendarQuery } from 'lib/types/entry-types.js'; import type { LoadingStatus } from 'lib/types/loading-types.js'; import { messageTypes } from 'lib/types/message-types-enum.js'; @@ -205,7 +206,6 @@ render(): React.Node { const isMember = viewerIsMember(this.props.threadInfo); - let joinButton = null; if ( !isMember && @@ -311,6 +311,9 @@ this.props.currentUserIsVoiced || (this.props.threadCreationInProgress && defaultMembersAreVoiced) ) { + const { canSendMultipleMedia } = + threadSpecs[this.props.threadInfo.type].protocol(); + content = (
@@ -319,7 +322,7 @@ onChange={this.onMultimediaFileChange} ref={this.multimediaInputRef} accept={allowedMimeTypeString} - multiple + multiple={canSendMultipleMedia} />