From 94e7bfbe40ba6766361caaba99feff74a187613a Mon Sep 17 00:00:00 2001 From: Samuel Newman Date: Mon, 7 Oct 2024 22:55:03 +0300 Subject: [PATCH 1/3] [Video] Revert safari hackfix (#5367) --- .../post-embeds/VideoEmbedInner/web-controls/utils.tsx | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/view/com/util/post-embeds/VideoEmbedInner/web-controls/utils.tsx b/src/view/com/util/post-embeds/VideoEmbedInner/web-controls/utils.tsx index 8aa2d3f7da..f5d90b5f76 100644 --- a/src/view/com/util/post-embeds/VideoEmbedInner/web-controls/utils.tsx +++ b/src/view/com/util/post-embeds/VideoEmbedInner/web-controls/utils.tsx @@ -1,6 +1,5 @@ import React, {useCallback, useEffect, useRef, useState} from 'react' -import {isSafari} from '#/lib/browser' import {useVideoVolumeState} from '../../VideoVolumeContext' export function useVideoElement(ref: React.RefObject) { @@ -38,12 +37,6 @@ export function useVideoElement(ref: React.RefObject) { const handleTimeUpdate = () => { if (!ref.current) return setCurrentTime(round(ref.current.currentTime) || 0) - // HACK: Safari randomly fires `stalled` events when changing between segments - // let's just clear the buffering state if the video is still progressing -sfn - if (isSafari) { - if (bufferingTimeout) clearTimeout(bufferingTimeout) - setBuffering(false) - } } const handleDurationChange = () => { From ee25b89801c7038a95eb95500082dbccccb5cba9 Mon Sep 17 00:00:00 2001 From: Hailey Date: Mon, 7 Oct 2024 14:09:47 -0700 Subject: [PATCH 2/3] [Video] Add dimension info to share intent (#5639) --- .../ShareViewController.swift | 30 ++++++++++++------- .../ExpoReceiveAndroidIntentsModule.kt | 24 ++++++++++++++- src/lib/hooks/useIntentHandler.ts | 3 +- src/state/shell/composer/index.tsx | 2 +- src/view/com/composer/Composer.tsx | 2 +- 5 files changed, 47 insertions(+), 14 deletions(-) diff --git a/modules/Share-with-Bluesky/ShareViewController.swift b/modules/Share-with-Bluesky/ShareViewController.swift index 2acbb6187b..79f081737f 100644 --- a/modules/Share-with-Bluesky/ShareViewController.swift +++ b/modules/Share-with-Bluesky/ShareViewController.swift @@ -1,4 +1,5 @@ import UIKit +import AVKit let IMAGE_EXTENSIONS: [String] = ["png", "jpg", "jpeg", "gif", "heic"] let MOVIE_EXTENSIONS: [String] = ["mov", "mp4", "m4v"] @@ -119,16 +120,11 @@ class ShareViewController: UIViewController { private func handleVideos(items: [NSItemProvider]) async { let firstItem = items.first - if let dataUri = try? await firstItem?.loadItem(forTypeIdentifier: "public.movie") as? URL { - let ext = String(dataUri.lastPathComponent.split(separator: ".").last ?? "mp4") - if let tempUrl = getTempUrl(ext: ext) { - let data = try? Data(contentsOf: dataUri) - 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) - } + if let dataUrl = try? await firstItem?.loadItem(forTypeIdentifier: "public.movie") as? URL { + let ext = String(dataUrl.lastPathComponent.split(separator: ".").last ?? "mp4") + if let videoUriInfo = saveVideoWithInfo(dataUrl), + let url = URL(string: "\(self.appScheme)://intent/compose?videoUri=\(videoUriInfo)") { + _ = self.openURL(url) } } @@ -152,6 +148,20 @@ class ShareViewController: UIViewController { } catch {} 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() { self.extensionContext?.completeRequest(returningItems: nil) diff --git a/modules/expo-receive-android-intents/android/src/main/java/xyz/blueskyweb/app/exporeceiveandroidintents/ExpoReceiveAndroidIntentsModule.kt b/modules/expo-receive-android-intents/android/src/main/java/xyz/blueskyweb/app/exporeceiveandroidintents/ExpoReceiveAndroidIntentsModule.kt index c88442057c..abae882b48 100644 --- a/modules/expo-receive-android-intents/android/src/main/java/xyz/blueskyweb/app/exporeceiveandroidintents/ExpoReceiveAndroidIntentsModule.kt +++ b/modules/expo-receive-android-intents/android/src/main/java/xyz/blueskyweb/app/exporeceiveandroidintents/ExpoReceiveAndroidIntentsModule.kt @@ -2,6 +2,7 @@ package xyz.blueskyweb.app.exporeceiveandroidintents import android.content.Intent import android.graphics.Bitmap +import android.media.MediaMetadataRetriever import android.net.Uri import android.os.Build import android.provider.MediaStore @@ -143,7 +144,10 @@ class ExpoReceiveAndroidIntentsModule : Module() { appContext.currentActivity?.contentResolver?.openInputStream(uri)?.use { 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) appContext.currentActivity?.startActivity(newIntent) } @@ -166,6 +170,24 @@ class ExpoReceiveAndroidIntentsModule : Module() { ) } + private fun getVideoInfo(uri: Uri): Map? { + 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) // We will pas the width and height to the app here, since getting measurements diff --git a/src/lib/hooks/useIntentHandler.ts b/src/lib/hooks/useIntentHandler.ts index ce1d474d31..98ba4ec026 100644 --- a/src/lib/hooks/useIntentHandler.ts +++ b/src/lib/hooks/useIntentHandler.ts @@ -93,9 +93,10 @@ export function useComposeIntent() { // Whenever a video URI is present, we don't support adding images right now. if (videoUri) { + const [uri, width, height] = videoUri.split('|') openComposer({ text: text ?? undefined, - videoUri, + videoUri: {uri, width: Number(width), height: Number(height)}, }) return } diff --git a/src/state/shell/composer/index.tsx b/src/state/shell/composer/index.tsx index 1c3aa6a81d..770b0789ed 100644 --- a/src/state/shell/composer/index.tsx +++ b/src/state/shell/composer/index.tsx @@ -38,7 +38,7 @@ export interface ComposerOpts { openEmojiPicker?: (pos: DOMRect | undefined) => void text?: string imageUris?: {uri: string; width: number; height: number; altText?: string}[] - videoUri?: string + videoUri?: {uri: string; width: number; height: number} } type StateContext = ComposerOpts | undefined diff --git a/src/view/com/composer/Composer.tsx b/src/view/com/composer/Composer.tsx index 94c02767ea..0189ca9a85 100644 --- a/src/view/com/composer/Composer.tsx +++ b/src/view/com/composer/Composer.tsx @@ -218,7 +218,7 @@ export const ComposePost = ({ // Whenever we receive an initial video uri, we should immediately run compression if necessary useEffect(() => { if (initVideoUri) { - selectVideo({uri: initVideoUri} as ImagePickerAsset) + selectVideo(initVideoUri) } }, [initVideoUri, selectVideo]) From 509b37fafa08b08026a6fee946ec54f1a83b54f9 Mon Sep 17 00:00:00 2001 From: Hailey Date: Mon, 7 Oct 2024 14:12:17 -0700 Subject: [PATCH 3/3] [Video] Prevent screen from dimming while in full screen (#5637) --- package.json | 2 +- .../post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx | 4 ++-- yarn.lock | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 828f11cb76..9b56efcaf5 100644 --- a/package.json +++ b/package.json @@ -68,7 +68,7 @@ "@fortawesome/free-regular-svg-icons": "^6.1.1", "@fortawesome/free-solid-svg-icons": "^6.1.1", "@fortawesome/react-native-fontawesome": "^0.3.2", - "@haileyok/bluesky-video": "0.1.10", + "@haileyok/bluesky-video": "0.2.2", "@lingui/react": "^4.5.0", "@mattermost/react-native-paste-input": "^0.7.1", "@miblanchard/react-native-slider": "^2.3.1", diff --git a/src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx b/src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx index c6536dec44..21db54322f 100644 --- a/src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx +++ b/src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx @@ -8,7 +8,7 @@ import {useLingui} from '@lingui/react' import {HITSLOP_30} from '#/lib/constants' import {useAutoplayDisabled} from '#/state/preferences' -import {useVideoMuteState} from 'view/com/util/post-embeds/VideoVolumeContext' +import {useVideoMuteState} from '#/view/com/util/post-embeds/VideoVolumeContext' import {atoms as a, useTheme} from '#/alf' import {useIsWithinMessage} from '#/components/dms/MessageContext' import {Mute_Stroke2_Corner0_Rounded as MuteIcon} from '#/components/icons/Mute' @@ -87,7 +87,7 @@ export const VideoEmbedInnerNative = React.forwardRef( /> { - videoRef.current?.enterFullscreen() + videoRef.current?.enterFullscreen(true) }} toggleMuted={() => { videoRef.current?.toggleMuted() diff --git a/yarn.lock b/yarn.lock index 3bb82371f0..95a83b75ef 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4120,10 +4120,10 @@ resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.2.0.tgz#5f3d96ec6b2354ad6d8a28bf216a1d97b5426861" integrity sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ== -"@haileyok/bluesky-video@0.1.10": - version "0.1.10" - resolved "https://registry.yarnpkg.com/@haileyok/bluesky-video/-/bluesky-video-0.1.10.tgz#2756e8c83a78caeb6b120a175578eac1eb6889a9" - integrity sha512-W8+DNdek+xjAqTO1zmuuSrkVFxDepcP8+Gs8MvIcYSgXEJlpQimZpcMwAduiDI/jZMn/2U6cnMahx7YuiZlZ7g== +"@haileyok/bluesky-video@0.2.2": + version "0.2.2" + resolved "https://registry.yarnpkg.com/@haileyok/bluesky-video/-/bluesky-video-0.2.2.tgz#062ef6f52376f2f8e5b787a73bbb4f66cfd3cbf3" + integrity sha512-N8aGu27xO99HaV957EfvB2StYRY3Gf2TdijTkYmzwULuM9aij2YeyVzDoAd4P+qYh21MRMITnJ4652sUM+SUbw== "@hapi/accept@^6.0.3": version "6.0.3"