diff --git a/android/src/main/java/com/margelo/nitro/multipleimagepicker/MultipleImagePicker.kt b/android/src/main/java/com/margelo/nitro/multipleimagepicker/MultipleImagePicker.kt index 6ee259a..adc364f 100644 --- a/android/src/main/java/com/margelo/nitro/multipleimagepicker/MultipleImagePicker.kt +++ b/android/src/main/java/com/margelo/nitro/multipleimagepicker/MultipleImagePicker.kt @@ -29,9 +29,10 @@ class MultipleImagePicker : HybridMultipleImagePickerSpec() { override fun openPreview( media: Array, index: Double, - config: NitroPreviewConfig + config: NitroPreviewConfig, + onLongPress: (index: Double) -> Unit ) { - pickerModule.openPreview(media, index.toInt(), config) + pickerModule.openPreview(media, index.toInt(), config, onLongPress) } override fun openCamera( diff --git a/android/src/main/java/com/margelo/nitro/multipleimagepicker/MultipleImagePickerImp.kt b/android/src/main/java/com/margelo/nitro/multipleimagepicker/MultipleImagePickerImp.kt index cb91ba1..5c4d8ba 100644 --- a/android/src/main/java/com/margelo/nitro/multipleimagepicker/MultipleImagePickerImp.kt +++ b/android/src/main/java/com/margelo/nitro/multipleimagepicker/MultipleImagePickerImp.kt @@ -20,6 +20,7 @@ import com.luck.picture.lib.config.SelectModeConfig import com.luck.picture.lib.engine.PictureSelectorEngine import com.luck.picture.lib.entity.LocalMedia import com.luck.picture.lib.interfaces.OnCustomLoadingListener +import com.luck.picture.lib.interfaces.OnExternalPreviewEventListener import com.luck.picture.lib.interfaces.OnMediaEditInterceptListener import com.luck.picture.lib.interfaces.OnResultCallbackListener import com.luck.picture.lib.language.LanguageConfig @@ -264,7 +265,12 @@ class MultipleImagePickerImp(reactContext: ReactApplicationContext?) : } @ReactMethod - fun openPreview(media: Array, index: Int, config: NitroPreviewConfig) { + fun openPreview( + media: Array, + index: Int, + config: NitroPreviewConfig, + onLongPress: (index: Double) -> Unit + ) { val imageEngine = GlideEngine.createGlideEngine() val assets: ArrayList = arrayListOf() @@ -279,7 +285,8 @@ class MultipleImagePickerImp(reactContext: ReactApplicationContext?) : titleBarStyle.previewTitleBackgroundColor = Color.BLACK previewStyle.titleBarStyle = titleBarStyle - media.forEach { mediaItem -> + media.withIndex().forEach { (index, mediaItem) -> + var asset: LocalMedia? = null mediaItem.path?.let { path -> @@ -297,7 +304,10 @@ class MultipleImagePickerImp(reactContext: ReactApplicationContext?) : } } - asset?.let { assets.add(it) } + asset?.let { + it.setPosition(index) + assets.add(it) + } } PictureSelector @@ -311,9 +321,20 @@ class MultipleImagePickerImp(reactContext: ReactApplicationContext?) : .setVideoPlayerEngine(ExoPlayerEngine()) .isVideoPauseResumePlay(true) .setCustomLoadingListener(getCustomLoadingListener()) - .startActivityPreview(index, false, assets) + .setExternalPreviewEventListener(object : OnExternalPreviewEventListener { + override fun onPreviewDelete(position: Int) { + // + } + + override fun onLongPressDownload(context: Context, media: LocalMedia): Boolean { + onLongPress(media.position.toDouble()) + return true + } + }) + .startFragmentPreview(index, false, assets) } + private fun getCustomLoadingListener(): OnCustomLoadingListener { return OnCustomLoadingListener { context -> LoadingDialog(context) } } diff --git a/docs/docs/PREVIEW.mdx b/docs/docs/PREVIEW.mdx index d4b3511..324d5a6 100644 --- a/docs/docs/PREVIEW.mdx +++ b/docs/docs/PREVIEW.mdx @@ -22,9 +22,12 @@ Preview is a simple image viewer that supports both local and remote media. It a ## Usage ```typescript -import { openPreview } from '@baronha/react-native-multiple-image-picker' +import { + openPreview, + PreviewConfig, +} from '@baronha/react-native-multiple-image-picker' -const cropConfig: CropConfig = { +const previewConfig: PreviewConfig = { language: 'system', } @@ -49,7 +52,7 @@ const media: MediaPreview[] = [ ] // call to preview -openPreview(media, 2, cropConfig) +openPreview(media, 2, previewConfig) ``` ## `MediaPreview[]` @@ -65,12 +68,24 @@ openPreview(media, 2, cropConfig) ## `index` +default: `0` + The `index` parameter in the `openPreview` function specifies the initial media item to display. It is a zero-based index, meaning that `0` will display the first item in the `MediaPreview` array. -## `cropConfig` +## `previewConfig` ### [`language`](/config/#language) +see [`language`](/config/#language) + +### `onLongPress` + +`onLongPress` is a callback function that is called when a long press is detected on the media item. It is a function that takes an index as an argument and returns void. + +```typescript +onLongPress: (index: number) => void +``` + ## Additional Information - Ensure that the media paths are accessible and correctly formatted. diff --git a/example/src/index.tsx b/example/src/index.tsx index 7a9a533..0ca55ed 100644 --- a/example/src/index.tsx +++ b/example/src/index.tsx @@ -1,5 +1,7 @@ import React, { useState } from 'react' import { + ActionSheetIOS, + Alert, Appearance, ColorSchemeName, Image, @@ -76,7 +78,42 @@ export default function App() { } const onPressImage = (_: PickerResult, index: number) => { - openPreview(images, index, {}) + openPreview(images, index, { + onLongPress: () => { + if (Platform.OS === 'ios') { + ActionSheetIOS.showActionSheetWithOptions( + { + options: ['Download', 'Cancel'], + cancelButtonIndex: 1, + userInterfaceStyle: colorScheme ?? 'light', + }, + (buttonIndex) => { + if (buttonIndex === 0) { + // Download + } else if (buttonIndex === 1) { + // Cancel + } + } + ) + } else { + Alert.alert('Options', '', [ + { + text: 'Cancel', + style: 'cancel', + onPress: () => { + console.log('Cancel') + }, + }, + { + text: 'Download', + onPress: () => { + console.log('Download') + }, + }, + ]) + } + }, + }) } const onPicker = async () => { diff --git a/example/yarn.lock b/example/yarn.lock index 9235f88..e28e158 100644 --- a/example/yarn.lock +++ b/example/yarn.lock @@ -5414,10 +5414,10 @@ react-native-builder-bob@^0.30.0: which "^2.0.2" yargs "^17.5.1" -react-native-nitro-modules@0.20.0: - version "0.20.0" - resolved "https://registry.yarnpkg.com/react-native-nitro-modules/-/react-native-nitro-modules-0.20.0.tgz#3c659d4c8cbc8038b1bf35af6475e77023e70ffa" - integrity sha512-u41SaGdQ/EQFuRLFPRQ+cbEemzsARmkElXErwZlXJhr2KYmVwQMrIYGe69NuMSyvHlw3JTl09SNugt3PXa2vEQ== +react-native-nitro-modules@^0.20.1: + version "0.20.1" + resolved "https://registry.yarnpkg.com/react-native-nitro-modules/-/react-native-nitro-modules-0.20.1.tgz#99568818b90e364f1e08b5341a7868eca3762333" + integrity sha512-ffa8GbnLBs7irEx1ZCl7WdHzzA5uj4ngh7hIWbeUfBs8m2iAn+byowOJWHKmO+RA2hp9dVwTxHYSBOqIvTVvHA== react-native@0.76.5: version "0.76.5" diff --git a/ios/HybridMultipleImagePicker+Preview.swift b/ios/HybridMultipleImagePicker+Preview.swift index f08f32c..439d88e 100644 --- a/ios/HybridMultipleImagePicker+Preview.swift +++ b/ios/HybridMultipleImagePicker+Preview.swift @@ -8,7 +8,7 @@ import HXPhotoPicker extension HybridMultipleImagePicker { - func openPreview(media: [MediaPreview], index: Double, config: NitroPreviewConfig) throws { + func openPreview(media: [MediaPreview], index: Double, config: NitroPreviewConfig, onLongPress: @escaping ((Double) -> Void)) throws { var previewConfig = HXPhotoPicker.PhotoBrowser.Configuration() previewConfig.showDelete = false @@ -66,7 +66,10 @@ extension HybridMultipleImagePicker { HXPhotoPicker.PhotoBrowser.show( assets, pageIndex: Int(index), - config: previewConfig + config: previewConfig, + longPressHandler: { index, _, _ in + onLongPress(Double(index)) + } ) } } diff --git a/nitrogen/generated/android/MultipleImagePickerOnLoad.cpp b/nitrogen/generated/android/MultipleImagePickerOnLoad.cpp index 8dbf16d..04cf0a9 100644 --- a/nitrogen/generated/android/MultipleImagePickerOnLoad.cpp +++ b/nitrogen/generated/android/MultipleImagePickerOnLoad.cpp @@ -33,6 +33,7 @@ int initialize(JavaVM* vm) { margelo::nitro::multipleimagepicker::JFunc_void_double::registerNatives(); margelo::nitro::multipleimagepicker::JFunc_void_CropResult::registerNatives(); margelo::nitro::multipleimagepicker::JFunc_void_double::registerNatives(); + margelo::nitro::multipleimagepicker::JFunc_void_double::registerNatives(); margelo::nitro::multipleimagepicker::JFunc_void_CameraResult::registerNatives(); margelo::nitro::multipleimagepicker::JFunc_void_double::registerNatives(); diff --git a/nitrogen/generated/android/c++/JFunc_void_double.hpp b/nitrogen/generated/android/c++/JFunc_void_double.hpp index 18d6f49..0288ebb 100644 --- a/nitrogen/generated/android/c++/JFunc_void_double.hpp +++ b/nitrogen/generated/android/c++/JFunc_void_double.hpp @@ -18,17 +18,17 @@ namespace margelo::nitro::multipleimagepicker { /** * C++ representation of the callback Func_void_double. - * This is a Kotlin `(reject: Double) -> Unit`, backed by a `std::function<...>`. + * This is a Kotlin `(index: Double) -> Unit`, backed by a `std::function<...>`. */ struct JFunc_void_double final: public jni::HybridClass { public: - static jni::local_ref fromCpp(const std::function& func) { + static jni::local_ref fromCpp(const std::function& func) { return JFunc_void_double::newObjectCxxArgs(func); } public: - void call(double reject) { - _func(reject); + void call(double index) { + _func(index); } public: @@ -38,11 +38,11 @@ namespace margelo::nitro::multipleimagepicker { } private: - explicit JFunc_void_double(const std::function& func): _func(func) { } + explicit JFunc_void_double(const std::function& func): _func(func) { } private: friend HybridBase; - std::function _func; + std::function _func; }; } // namespace margelo::nitro::multipleimagepicker diff --git a/nitrogen/generated/android/c++/JHybridMultipleImagePickerSpec.cpp b/nitrogen/generated/android/c++/JHybridMultipleImagePickerSpec.cpp index 5c0792a..befbc56 100644 --- a/nitrogen/generated/android/c++/JHybridMultipleImagePickerSpec.cpp +++ b/nitrogen/generated/android/c++/JHybridMultipleImagePickerSpec.cpp @@ -126,8 +126,8 @@ namespace margelo::nitro::multipleimagepicker { static const auto method = _javaPart->getClass()->getMethod /* image */, jni::alias_ref /* config */, jni::alias_ref /* resolved */, jni::alias_ref /* rejected */)>("openCrop"); method(_javaPart, jni::make_jstring(image), JNitroCropConfig::fromCpp(config), JFunc_void_CropResult::fromCpp(resolved), JFunc_void_double::fromCpp(rejected)); } - void JHybridMultipleImagePickerSpec::openPreview(const std::vector& media, double index, const NitroPreviewConfig& config) { - static const auto method = _javaPart->getClass()->getMethod> /* media */, double /* index */, jni::alias_ref /* config */)>("openPreview"); + void JHybridMultipleImagePickerSpec::openPreview(const std::vector& media, double index, const NitroPreviewConfig& config, const std::function& onLongPress) { + static const auto method = _javaPart->getClass()->getMethod> /* media */, double /* index */, jni::alias_ref /* config */, jni::alias_ref /* onLongPress */)>("openPreview"); method(_javaPart, [&]() { size_t __size = media.size(); jni::local_ref> __array = jni::JArrayClass::newArray(__size); @@ -136,7 +136,7 @@ namespace margelo::nitro::multipleimagepicker { __array->setElement(__i, *JMediaPreview::fromCpp(__element)); } return __array; - }(), index, JNitroPreviewConfig::fromCpp(config)); + }(), index, JNitroPreviewConfig::fromCpp(config), JFunc_void_double::fromCpp(onLongPress)); } void JHybridMultipleImagePickerSpec::openCamera(const NitroCameraConfig& config, const std::function& resolved, const std::function& rejected) { static const auto method = _javaPart->getClass()->getMethod /* config */, jni::alias_ref /* resolved */, jni::alias_ref /* rejected */)>("openCamera"); diff --git a/nitrogen/generated/android/c++/JHybridMultipleImagePickerSpec.hpp b/nitrogen/generated/android/c++/JHybridMultipleImagePickerSpec.hpp index 360d96b..71fc784 100644 --- a/nitrogen/generated/android/c++/JHybridMultipleImagePickerSpec.hpp +++ b/nitrogen/generated/android/c++/JHybridMultipleImagePickerSpec.hpp @@ -53,7 +53,7 @@ namespace margelo::nitro::multipleimagepicker { // Methods void openPicker(const NitroConfig& config, const std::function& /* result */)>& resolved, const std::function& rejected) override; void openCrop(const std::string& image, const NitroCropConfig& config, const std::function& resolved, const std::function& rejected) override; - void openPreview(const std::vector& media, double index, const NitroPreviewConfig& config) override; + void openPreview(const std::vector& media, double index, const NitroPreviewConfig& config, const std::function& onLongPress) override; void openCamera(const NitroCameraConfig& config, const std::function& resolved, const std::function& rejected) override; private: diff --git a/nitrogen/generated/android/kotlin/com/margelo/nitro/multipleimagepicker/Func_void_double.kt b/nitrogen/generated/android/kotlin/com/margelo/nitro/multipleimagepicker/Func_void_double.kt index 8e8908a..e405767 100644 --- a/nitrogen/generated/android/kotlin/com/margelo/nitro/multipleimagepicker/Func_void_double.kt +++ b/nitrogen/generated/android/kotlin/com/margelo/nitro/multipleimagepicker/Func_void_double.kt @@ -14,7 +14,7 @@ import com.margelo.nitro.core.* import dalvik.annotation.optimization.FastNative /** - * Represents the JavaScript callback `(reject: number) => void`. + * Represents the JavaScript callback `(index: number) => void`. * This is implemented in C++, via a `std::function<...>`. */ @DoNotStrip @@ -35,12 +35,12 @@ class Func_void_double { * Converts this function to a Kotlin Lambda. * This exists purely as syntactic sugar, and has minimal runtime overhead. */ - fun toLambda(): (reject: Double) -> Unit = this::call + fun toLambda(): (index: Double) -> Unit = this::call /** * Call the given JS callback. * @throws Throwable if the JS function itself throws an error, or if the JS function/runtime has already been deleted. */ @FastNative - external fun call(reject: Double): Unit + external fun call(index: Double): Unit } diff --git a/nitrogen/generated/android/kotlin/com/margelo/nitro/multipleimagepicker/HybridMultipleImagePickerSpec.kt b/nitrogen/generated/android/kotlin/com/margelo/nitro/multipleimagepicker/HybridMultipleImagePickerSpec.kt index a2cd30b..9cb8f4e 100644 --- a/nitrogen/generated/android/kotlin/com/margelo/nitro/multipleimagepicker/HybridMultipleImagePickerSpec.kt +++ b/nitrogen/generated/android/kotlin/com/margelo/nitro/multipleimagepicker/HybridMultipleImagePickerSpec.kt @@ -65,7 +65,14 @@ abstract class HybridMultipleImagePickerSpec: HybridObject() { @DoNotStrip @Keep - abstract fun openPreview(media: Array, index: Double, config: NitroPreviewConfig): Unit + abstract fun openPreview(media: Array, index: Double, config: NitroPreviewConfig, onLongPress: (index: Double) -> Unit): Unit + + @DoNotStrip + @Keep + private fun openPreview(media: Array, index: Double, config: NitroPreviewConfig, onLongPress: Func_void_double): Unit { + val __result = openPreview(media, index, config, onLongPress.toLambda()) + return __result + } @DoNotStrip @Keep diff --git a/nitrogen/generated/ios/c++/HybridMultipleImagePickerSpecSwift.hpp b/nitrogen/generated/ios/c++/HybridMultipleImagePickerSpecSwift.hpp index d9b8f7a..bf701e7 100644 --- a/nitrogen/generated/ios/c++/HybridMultipleImagePickerSpecSwift.hpp +++ b/nitrogen/generated/ios/c++/HybridMultipleImagePickerSpecSwift.hpp @@ -127,8 +127,8 @@ namespace margelo::nitro::multipleimagepicker { std::rethrow_exception(__result.error()); } } - inline void openPreview(const std::vector& media, double index, const NitroPreviewConfig& config) override { - auto __result = _swiftPart.openPreview(media, std::forward(index), config); + inline void openPreview(const std::vector& media, double index, const NitroPreviewConfig& config, const std::function& onLongPress) override { + auto __result = _swiftPart.openPreview(media, std::forward(index), config, onLongPress); if (__result.hasError()) [[unlikely]] { std::rethrow_exception(__result.error()); } diff --git a/nitrogen/generated/ios/swift/Func_void_double.swift b/nitrogen/generated/ios/swift/Func_void_double.swift index b9d1a3e..afbab51 100644 --- a/nitrogen/generated/ios/swift/Func_void_double.swift +++ b/nitrogen/generated/ios/swift/Func_void_double.swift @@ -8,21 +8,21 @@ import NitroModules /** - * Wraps a Swift `((_ reject: Double) -> Void)` as a class. + * Wraps a Swift `((_ index: Double) -> Void)` as a class. * This class can be used from C++, e.g. to wrap the Swift closure as a `std::function`. */ public final class Func_void_double { public typealias bridge = margelo.nitro.multipleimagepicker.bridge.swift - private let closure: ((_ reject: Double) -> Void) + private let closure: ((_ index: Double) -> Void) - public init(_ closure: @escaping ((_ reject: Double) -> Void)) { + public init(_ closure: @escaping ((_ index: Double) -> Void)) { self.closure = closure } @inline(__always) - public func call(reject: Double) -> Void { - self.closure(reject) + public func call(index: Double) -> Void { + self.closure(index) } /** diff --git a/nitrogen/generated/ios/swift/HybridMultipleImagePickerSpec.swift b/nitrogen/generated/ios/swift/HybridMultipleImagePickerSpec.swift index 4c9a4ee..cd65dba 100644 --- a/nitrogen/generated/ios/swift/HybridMultipleImagePickerSpec.swift +++ b/nitrogen/generated/ios/swift/HybridMultipleImagePickerSpec.swift @@ -16,7 +16,7 @@ public protocol HybridMultipleImagePickerSpec_protocol: AnyObject { // Methods func openPicker(config: NitroConfig, resolved: @escaping ((_ result: [PickerResult]) -> Void), rejected: @escaping ((_ reject: Double) -> Void)) throws -> Void func openCrop(image: String, config: NitroCropConfig, resolved: @escaping ((_ result: CropResult) -> Void), rejected: @escaping ((_ reject: Double) -> Void)) throws -> Void - func openPreview(media: [MediaPreview], index: Double, config: NitroPreviewConfig) throws -> Void + func openPreview(media: [MediaPreview], index: Double, config: NitroPreviewConfig, onLongPress: @escaping ((_ index: Double) -> Void)) throws -> Void func openCamera(config: NitroCameraConfig, resolved: @escaping ((_ result: CameraResult) -> Void), rejected: @escaping ((_ reject: Double) -> Void)) throws -> Void } diff --git a/nitrogen/generated/ios/swift/HybridMultipleImagePickerSpec_cxx.swift b/nitrogen/generated/ios/swift/HybridMultipleImagePickerSpec_cxx.swift index 9222e94..c7f5032 100644 --- a/nitrogen/generated/ios/swift/HybridMultipleImagePickerSpec_cxx.swift +++ b/nitrogen/generated/ios/swift/HybridMultipleImagePickerSpec_cxx.swift @@ -149,9 +149,14 @@ public class HybridMultipleImagePickerSpec_cxx { } @inline(__always) - public func openPreview(media: bridge.std__vector_MediaPreview_, index: Double, config: NitroPreviewConfig) -> bridge.Result_void_ { + public func openPreview(media: bridge.std__vector_MediaPreview_, index: Double, config: NitroPreviewConfig, onLongPress: bridge.Func_void_double) -> bridge.Result_void_ { do { - try self.__implementation.openPreview(media: media.map({ __item in __item }), index: index, config: config) + try self.__implementation.openPreview(media: media.map({ __item in __item }), index: index, config: config, onLongPress: { () -> ((Double) -> Void) in + let __wrappedFunction = bridge.wrap_Func_void_double(onLongPress) + return { (__index: Double) -> Void in + __wrappedFunction.call(__index) + } + }()) return bridge.create_Result_void_() } catch (let __error) { let __exceptionPtr = __error.toCpp() diff --git a/nitrogen/generated/shared/c++/HybridMultipleImagePickerSpec.hpp b/nitrogen/generated/shared/c++/HybridMultipleImagePickerSpec.hpp index 9406a70..ce86223 100644 --- a/nitrogen/generated/shared/c++/HybridMultipleImagePickerSpec.hpp +++ b/nitrogen/generated/shared/c++/HybridMultipleImagePickerSpec.hpp @@ -75,7 +75,7 @@ namespace margelo::nitro::multipleimagepicker { // Methods virtual void openPicker(const NitroConfig& config, const std::function& /* result */)>& resolved, const std::function& rejected) = 0; virtual void openCrop(const std::string& image, const NitroCropConfig& config, const std::function& resolved, const std::function& rejected) = 0; - virtual void openPreview(const std::vector& media, double index, const NitroPreviewConfig& config) = 0; + virtual void openPreview(const std::vector& media, double index, const NitroPreviewConfig& config, const std::function& onLongPress) = 0; virtual void openCamera(const NitroCameraConfig& config, const std::function& resolved, const std::function& rejected) = 0; protected: diff --git a/package.json b/package.json index 85a58cc..1c4e02b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@baronha/react-native-multiple-image-picker", - "version": "2.1.2", + "version": "2.2.0", "description": "� react-native-multiple-image-picker enables applications to pick images and videos from multiple smart albums in iOS/Android �", "main": "./lib/commonjs/index.js", "module": "./lib/module/index.js", diff --git a/src/index.ts b/src/index.ts index 260b2ab..babd6ce 100644 --- a/src/index.ts +++ b/src/index.ts @@ -114,7 +114,8 @@ export function openPreview( return Picker.openPreview( media as MediaPreview[], index, - config as NitroPreviewConfig + config as NitroPreviewConfig, + config?.onLongPress ?? (() => {}) ) } diff --git a/src/specs/MultipleImagePicker.nitro.ts b/src/specs/MultipleImagePicker.nitro.ts index da702d5..c0263e3 100644 --- a/src/specs/MultipleImagePicker.nitro.ts +++ b/src/specs/MultipleImagePicker.nitro.ts @@ -28,7 +28,8 @@ export interface MultipleImagePicker openPreview( media: MediaPreview[], index: number, - config: NitroPreviewConfig + config: NitroPreviewConfig, + onLongPress: (index: number) => void ): void openCamera( diff --git a/src/types/preview.ts b/src/types/preview.ts index b18186a..fc8f2c5 100644 --- a/src/types/preview.ts +++ b/src/types/preview.ts @@ -36,6 +36,8 @@ export interface PreviewConfig * - 'ar': 🇸🇦 Arabic */ language?: Language + + onLongPress?: (index: number) => void } export interface MediaPreview {