Bluesky app fork with some witchin' additions 💫
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

[Share Extension] Move away from deprecated API, implement JS side of things (#5509)

authored by

Hailey and committed by
GitHub
7ee67e4e 175df729

+59 -29
+4 -3
modules/Share-with-Bluesky/ShareViewController.swift
··· 23 23 await self.handleUrl(item: firstAttachment) 24 24 } else if firstAttachment.hasItemConformingToTypeIdentifier("public.image") { 25 25 await self.handleImages(items: attachments) 26 - } else if firstAttachment.hasItemConformingToTypeIdentifier("public.video") { 26 + } else if firstAttachment.hasItemConformingToTypeIdentifier("public.movie") { 27 27 await self.handleVideos(items: attachments) 28 28 } else { 29 29 self.completeRequest() ··· 107 107 let data = try? Data(contentsOf: dataUri) 108 108 try? data?.write(to: tempUrl) 109 109 110 - if let encoded = dataUri.absoluteString.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed), 110 + if let encoded = tempUrl.absoluteString.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed), 111 111 let url = URL(string: "\(self.appScheme)://intent/compose?videoUri=\(encoded)") { 112 112 _ = self.openURL(url) 113 113 } ··· 150 150 var responder: UIResponder? = self 151 151 while responder != nil { 152 152 if let application = responder as? UIApplication { 153 - return application.perform(#selector(openURL(_:)), with: url) != nil 153 + application.open(url) 154 + return true 154 155 } 155 156 responder = responder?.next 156 157 }
+18 -6
src/lib/hooks/useIntentHandler.ts
··· 1 1 import React from 'react' 2 2 import * as Linking from 'expo-linking' 3 3 4 - import {logEvent} from 'lib/statsig/statsig' 5 - import {isNative} from 'platform/detection' 6 - import {useSession} from 'state/session' 7 - import {useComposerControls} from 'state/shell' 8 - import {useCloseAllActiveElements} from 'state/util' 4 + import {logEvent} from '#/lib/statsig/statsig' 5 + import {isNative} from '#/platform/detection' 6 + import {useSession} from '#/state/session' 7 + import {useComposerControls} from '#/state/shell' 8 + import {useCloseAllActiveElements} from '#/state/util' 9 9 import {useIntentDialogs} from '#/components/intents/IntentDialogs' 10 10 import {Referrer} from '../../../modules/expo-bluesky-swiss-army' 11 11 ··· 52 52 composeIntent({ 53 53 text: params.get('text'), 54 54 imageUrisStr: params.get('imageUris'), 55 + videoUri: params.get('videoUri'), 55 56 }) 56 57 return 57 58 } ··· 80 81 ({ 81 82 text, 82 83 imageUrisStr, 84 + videoUri, 83 85 }: { 84 86 text: string | null 85 - imageUrisStr: string | null // unused for right now, will be used later with intents 87 + imageUrisStr: string | null 88 + videoUri: string | null 86 89 }) => { 87 90 if (!hasSession) return 88 91 89 92 closeAllActiveElements() 93 + 94 + // Whenever a video URI is present, we don't support adding images right now. 95 + if (videoUri) { 96 + openComposer({ 97 + text: text ?? undefined, 98 + videoUri, 99 + }) 100 + return 101 + } 90 102 91 103 const imageUris = imageUrisStr 92 104 ?.split(',')
+32 -20
src/state/queries/video/video.ts
··· 7 7 8 8 import {AbortError} from '#/lib/async/cancelable' 9 9 import {SUPPORTED_MIME_TYPES, SupportedMimeTypes} from '#/lib/constants' 10 - import {logger} from '#/logger' 11 - import {isWeb} from '#/platform/detection' 12 10 import { 13 11 ServerError, 14 12 UploadLimitError, 15 13 VideoTooLargeError, 16 - } from 'lib/media/video/errors' 17 - import {CompressedVideo} from 'lib/media/video/types' 18 - import {useCompressVideoMutation} from 'state/queries/video/compress-video' 19 - import {useVideoAgent} from 'state/queries/video/util' 20 - import {useUploadVideoMutation} from 'state/queries/video/video-upload' 14 + } from '#/lib/media/video/errors' 15 + import {CompressedVideo} from '#/lib/media/video/types' 16 + import {logger} from '#/logger' 17 + import {isWeb} from '#/platform/detection' 18 + import {useCompressVideoMutation} from '#/state/queries/video/compress-video' 19 + import {useVideoAgent} from '#/state/queries/video/util' 20 + import {useUploadVideoMutation} from '#/state/queries/video/video-upload' 21 21 22 22 type Status = 'idle' | 'compressing' | 'processing' | 'uploading' | 'done' 23 23 ··· 101 101 102 102 export function useUploadVideo({ 103 103 setStatus, 104 + initialVideoUri, 104 105 }: { 105 106 setStatus: (status: string) => void 106 107 onSuccess: () => void 108 + initialVideoUri?: string 107 109 }) { 108 110 const {_} = useLingui() 109 111 const queryClient = useQueryClient() ··· 237 239 signal: state.abortController.signal, 238 240 }) 239 241 240 - const selectVideo = (asset: ImagePickerAsset) => { 241 - // compression step on native converts to mp4, so no need to check there 242 - if (isWeb) { 243 - const mimeType = getMimeType(asset) 244 - if (!SUPPORTED_MIME_TYPES.includes(mimeType as SupportedMimeTypes)) { 245 - throw new Error(_(msg`Unsupported video type: ${mimeType}`)) 242 + const selectVideo = React.useCallback( 243 + (asset: ImagePickerAsset) => { 244 + // compression step on native converts to mp4, so no need to check there 245 + if (isWeb) { 246 + const mimeType = getMimeType(asset) 247 + if (!SUPPORTED_MIME_TYPES.includes(mimeType as SupportedMimeTypes)) { 248 + throw new Error(_(msg`Unsupported video type: ${mimeType}`)) 249 + } 246 250 } 247 - } 248 251 249 - dispatch({ 250 - type: 'SetAsset', 251 - asset, 252 - }) 253 - onSelectVideo(asset) 254 - } 252 + dispatch({ 253 + type: 'SetAsset', 254 + asset, 255 + }) 256 + onSelectVideo(asset) 257 + }, 258 + [_, onSelectVideo], 259 + ) 255 260 256 261 const clearVideo = () => { 257 262 dispatch({type: 'Reset'}) ··· 264 269 height, 265 270 }) 266 271 }, []) 272 + 273 + // Whenever we receive an initial video uri, we should immediately run compression if necessary 274 + useEffect(() => { 275 + if (initialVideoUri) { 276 + selectVideo({uri: initialVideoUri} as ImagePickerAsset) 277 + } 278 + }, [initialVideoUri, selectVideo]) 267 279 268 280 return { 269 281 state,
+1
src/state/shell/composer/index.tsx
··· 38 38 openEmojiPicker?: (pos: DOMRect | undefined) => void 39 39 text?: string 40 40 imageUris?: {uri: string; width: number; height: number; altText?: string}[] 41 + videoUri?: string 41 42 } 42 43 43 44 type StateContext = ComposerOpts | undefined
+2
src/view/com/composer/Composer.tsx
··· 137 137 openEmojiPicker, 138 138 text: initText, 139 139 imageUris: initImageUris, 140 + videoUri: initVideoUri, 140 141 cancelRef, 141 142 }: Props & { 142 143 cancelRef?: React.RefObject<CancelRef> ··· 199 200 onPressPublish(true) 200 201 } 201 202 }, 203 + initialVideoUri: initVideoUri, 202 204 }) 203 205 const hasVideo = Boolean(videoUploadState.asset || videoUploadState.video) 204 206
+1
src/view/shell/Composer.ios.tsx
··· 34 34 mention={state?.mention} 35 35 text={state?.text} 36 36 imageUris={state?.imageUris} 37 + videoUri={state?.videoUri} 37 38 /> 38 39 </Providers> 39 40 </View>
+1
src/view/shell/Composer.tsx
··· 54 54 mention={state.mention} 55 55 text={state.text} 56 56 imageUris={state.imageUris} 57 + videoUri={state.videoUri} 57 58 /> 58 59 </Animated.View> 59 60 )