[Video] Add dimension info to share intent (#5639)
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
import UIKit
|
import UIKit
|
||||||
|
import AVKit
|
||||||
|
|
||||||
let IMAGE_EXTENSIONS: [String] = ["png", "jpg", "jpeg", "gif", "heic"]
|
let IMAGE_EXTENSIONS: [String] = ["png", "jpg", "jpeg", "gif", "heic"]
|
||||||
let MOVIE_EXTENSIONS: [String] = ["mov", "mp4", "m4v"]
|
let MOVIE_EXTENSIONS: [String] = ["mov", "mp4", "m4v"]
|
||||||
@@ -119,18 +120,13 @@ class ShareViewController: UIViewController {
|
|||||||
private func handleVideos(items: [NSItemProvider]) async {
|
private func handleVideos(items: [NSItemProvider]) async {
|
||||||
let firstItem = items.first
|
let firstItem = items.first
|
||||||
|
|
||||||
if let dataUri = try? await firstItem?.loadItem(forTypeIdentifier: "public.movie") as? URL {
|
if let dataUrl = try? await firstItem?.loadItem(forTypeIdentifier: "public.movie") as? URL {
|
||||||
let ext = String(dataUri.lastPathComponent.split(separator: ".").last ?? "mp4")
|
let ext = String(dataUrl.lastPathComponent.split(separator: ".").last ?? "mp4")
|
||||||
if let tempUrl = getTempUrl(ext: ext) {
|
if let videoUriInfo = saveVideoWithInfo(dataUrl),
|
||||||
let data = try? Data(contentsOf: dataUri)
|
let url = URL(string: "\(self.appScheme)://intent/compose?videoUri=\(videoUriInfo)") {
|
||||||
try? data?.write(to: tempUrl)
|
|
||||||
|
|
||||||
if let encoded = tempUrl.absoluteString.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed),
|
|
||||||
let url = URL(string: "\(self.appScheme)://intent/compose?videoUri=\(encoded)") {
|
|
||||||
_ = self.openURL(url)
|
_ = self.openURL(url)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
self.completeRequest()
|
self.completeRequest()
|
||||||
}
|
}
|
||||||
@@ -153,6 +149,20 @@ class ShareViewController: UIViewController {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func saveVideoWithInfo(_ dataUrl: URL) -> String? {
|
||||||
|
let ext = String(dataUrl.lastPathComponent.split(separator: ".").last ?? "mp4")
|
||||||
|
guard let tempUrl = getTempUrl(ext: ext),
|
||||||
|
let track = AVURLAsset(url: dataUrl).tracks(withMediaType: AVMediaType.video).first else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
let size = track.naturalSize.applying(track.preferredTransform)
|
||||||
|
|
||||||
|
let data = try? Data(contentsOf: dataUrl)
|
||||||
|
try? data?.write(to: tempUrl)
|
||||||
|
|
||||||
|
return "\(tempUrl.absoluteString)|\(size.width)||\(size.height)"
|
||||||
|
}
|
||||||
|
|
||||||
private func completeRequest() {
|
private func completeRequest() {
|
||||||
self.extensionContext?.completeRequest(returningItems: nil)
|
self.extensionContext?.completeRequest(returningItems: nil)
|
||||||
}
|
}
|
||||||
|
|||||||
+23
-1
@@ -2,6 +2,7 @@ package xyz.blueskyweb.app.exporeceiveandroidintents
|
|||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
|
import android.media.MediaMetadataRetriever
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.provider.MediaStore
|
import android.provider.MediaStore
|
||||||
@@ -143,7 +144,10 @@ class ExpoReceiveAndroidIntentsModule : Module() {
|
|||||||
appContext.currentActivity?.contentResolver?.openInputStream(uri)?.use {
|
appContext.currentActivity?.contentResolver?.openInputStream(uri)?.use {
|
||||||
it.copyTo(out)
|
it.copyTo(out)
|
||||||
}
|
}
|
||||||
"bluesky://intent/compose?videoUri=${URLEncoder.encode(file.path, "UTF-8")}".toUri().let {
|
|
||||||
|
val info = getVideoInfo(uri) ?: return
|
||||||
|
|
||||||
|
"bluesky://intent/compose?videoUri=${URLEncoder.encode(file.path, "UTF-8")}|${info["width"]}|${info["height"]}".toUri().let {
|
||||||
val newIntent = Intent(Intent.ACTION_VIEW, it)
|
val newIntent = Intent(Intent.ACTION_VIEW, it)
|
||||||
appContext.currentActivity?.startActivity(newIntent)
|
appContext.currentActivity?.startActivity(newIntent)
|
||||||
}
|
}
|
||||||
@@ -166,6 +170,24 @@ class ExpoReceiveAndroidIntentsModule : Module() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getVideoInfo(uri: Uri): Map<String, Any>? {
|
||||||
|
val retriever = MediaMetadataRetriever()
|
||||||
|
retriever.setDataSource(appContext.currentActivity, uri)
|
||||||
|
|
||||||
|
val width = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH)?.toIntOrNull()
|
||||||
|
val height = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT)?.toIntOrNull()
|
||||||
|
|
||||||
|
if (width == null || height == null) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return mapOf(
|
||||||
|
"width" to width,
|
||||||
|
"height" to height,
|
||||||
|
"path" to uri.path.toString(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private fun createFile(extension: String): File = File.createTempFile(extension, "temp.$extension", appContext.currentActivity?.cacheDir)
|
private fun createFile(extension: String): File = File.createTempFile(extension, "temp.$extension", appContext.currentActivity?.cacheDir)
|
||||||
|
|
||||||
// We will pas the width and height to the app here, since getting measurements
|
// We will pas the width and height to the app here, since getting measurements
|
||||||
|
|||||||
@@ -93,9 +93,10 @@ export function useComposeIntent() {
|
|||||||
|
|
||||||
// Whenever a video URI is present, we don't support adding images right now.
|
// Whenever a video URI is present, we don't support adding images right now.
|
||||||
if (videoUri) {
|
if (videoUri) {
|
||||||
|
const [uri, width, height] = videoUri.split('|')
|
||||||
openComposer({
|
openComposer({
|
||||||
text: text ?? undefined,
|
text: text ?? undefined,
|
||||||
videoUri,
|
videoUri: {uri, width: Number(width), height: Number(height)},
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ export interface ComposerOpts {
|
|||||||
openEmojiPicker?: (pos: DOMRect | undefined) => void
|
openEmojiPicker?: (pos: DOMRect | undefined) => void
|
||||||
text?: string
|
text?: string
|
||||||
imageUris?: {uri: string; width: number; height: number; altText?: string}[]
|
imageUris?: {uri: string; width: number; height: number; altText?: string}[]
|
||||||
videoUri?: string
|
videoUri?: {uri: string; width: number; height: number}
|
||||||
}
|
}
|
||||||
|
|
||||||
type StateContext = ComposerOpts | undefined
|
type StateContext = ComposerOpts | undefined
|
||||||
|
|||||||
@@ -218,7 +218,7 @@ export const ComposePost = ({
|
|||||||
// Whenever we receive an initial video uri, we should immediately run compression if necessary
|
// Whenever we receive an initial video uri, we should immediately run compression if necessary
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (initVideoUri) {
|
if (initVideoUri) {
|
||||||
selectVideo({uri: initVideoUri} as ImagePickerAsset)
|
selectVideo(initVideoUri)
|
||||||
}
|
}
|
||||||
}, [initVideoUri, selectVideo])
|
}, [initVideoUri, selectVideo])
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user