Skip to content

Commit

Permalink
Merge pull request #212 from baronha/improve/preview
Browse files Browse the repository at this point in the history
🦄 Improve Preview
  • Loading branch information
baronha authored Dec 25, 2024
2 parents 7698ddb + 48a33c7 commit 737ad21
Show file tree
Hide file tree
Showing 21 changed files with 139 additions and 45 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@ class MultipleImagePicker : HybridMultipleImagePickerSpec() {
override fun openPreview(
media: Array<MediaPreview>,
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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -264,7 +265,12 @@ class MultipleImagePickerImp(reactContext: ReactApplicationContext?) :
}

@ReactMethod
fun openPreview(media: Array<MediaPreview>, index: Int, config: NitroPreviewConfig) {
fun openPreview(
media: Array<MediaPreview>,
index: Int,
config: NitroPreviewConfig,
onLongPress: (index: Double) -> Unit
) {
val imageEngine = GlideEngine.createGlideEngine()

val assets: ArrayList<LocalMedia> = arrayListOf()
Expand All @@ -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 ->
Expand All @@ -297,7 +304,10 @@ class MultipleImagePickerImp(reactContext: ReactApplicationContext?) :
}
}

asset?.let { assets.add(it) }
asset?.let {
it.setPosition(index)
assets.add(it)
}
}

PictureSelector
Expand All @@ -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) }
}
Expand Down
23 changes: 19 additions & 4 deletions docs/docs/PREVIEW.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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',
}

Expand All @@ -49,7 +52,7 @@ const media: MediaPreview[] = [
]

// call to preview
openPreview(media, 2, cropConfig)
openPreview(media, 2, previewConfig)
```

## `MediaPreview[]`
Expand All @@ -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.
Expand Down
39 changes: 38 additions & 1 deletion example/src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import React, { useState } from 'react'
import {
ActionSheetIOS,
Alert,
Appearance,
ColorSchemeName,
Image,
Expand Down Expand Up @@ -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 () => {
Expand Down
8 changes: 4 additions & 4 deletions example/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5414,10 +5414,10 @@ react-native-builder-bob@^0.30.0:
which "^2.0.2"
yargs "^17.5.1"

[email protected].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==

[email protected]:
version "0.76.5"
Expand Down
7 changes: 5 additions & 2 deletions ios/HybridMultipleImagePicker+Preview.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -66,7 +66,10 @@ extension HybridMultipleImagePicker {
HXPhotoPicker.PhotoBrowser.show(
assets,
pageIndex: Int(index),
config: previewConfig
config: previewConfig,
longPressHandler: { index, _, _ in
onLongPress(Double(index))
}
)
}
}
Expand Down
1 change: 1 addition & 0 deletions nitrogen/generated/android/MultipleImagePickerOnLoad.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
12 changes: 6 additions & 6 deletions nitrogen/generated/android/c++/JFunc_void_double.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<JFunc_void_double> {
public:
static jni::local_ref<JFunc_void_double::javaobject> fromCpp(const std::function<void(double /* reject */)>& func) {
static jni::local_ref<JFunc_void_double::javaobject> fromCpp(const std::function<void(double /* index */)>& func) {
return JFunc_void_double::newObjectCxxArgs(func);
}

public:
void call(double reject) {
_func(reject);
void call(double index) {
_func(index);
}

public:
Expand All @@ -38,11 +38,11 @@ namespace margelo::nitro::multipleimagepicker {
}

private:
explicit JFunc_void_double(const std::function<void(double /* reject */)>& func): _func(func) { }
explicit JFunc_void_double(const std::function<void(double /* index */)>& func): _func(func) { }

private:
friend HybridBase;
std::function<void(double /* reject */)> _func;
std::function<void(double /* index */)> _func;
};

} // namespace margelo::nitro::multipleimagepicker
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,8 @@ namespace margelo::nitro::multipleimagepicker {
static const auto method = _javaPart->getClass()->getMethod<void(jni::alias_ref<jni::JString> /* image */, jni::alias_ref<JNitroCropConfig> /* config */, jni::alias_ref<JFunc_void_CropResult::javaobject> /* resolved */, jni::alias_ref<JFunc_void_double::javaobject> /* 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<MediaPreview>& media, double index, const NitroPreviewConfig& config) {
static const auto method = _javaPart->getClass()->getMethod<void(jni::alias_ref<jni::JArrayClass<JMediaPreview>> /* media */, double /* index */, jni::alias_ref<JNitroPreviewConfig> /* config */)>("openPreview");
void JHybridMultipleImagePickerSpec::openPreview(const std::vector<MediaPreview>& media, double index, const NitroPreviewConfig& config, const std::function<void(double /* index */)>& onLongPress) {
static const auto method = _javaPart->getClass()->getMethod<void(jni::alias_ref<jni::JArrayClass<JMediaPreview>> /* media */, double /* index */, jni::alias_ref<JNitroPreviewConfig> /* config */, jni::alias_ref<JFunc_void_double::javaobject> /* onLongPress */)>("openPreview");
method(_javaPart, [&]() {
size_t __size = media.size();
jni::local_ref<jni::JArrayClass<JMediaPreview>> __array = jni::JArrayClass<JMediaPreview>::newArray(__size);
Expand All @@ -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<void(const CameraResult& /* result */)>& resolved, const std::function<void(double /* reject */)>& rejected) {
static const auto method = _javaPart->getClass()->getMethod<void(jni::alias_ref<JNitroCameraConfig> /* config */, jni::alias_ref<JFunc_void_CameraResult::javaobject> /* resolved */, jni::alias_ref<JFunc_void_double::javaobject> /* rejected */)>("openCamera");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ namespace margelo::nitro::multipleimagepicker {
// Methods
void openPicker(const NitroConfig& config, const std::function<void(const std::vector<PickerResult>& /* result */)>& resolved, const std::function<void(double /* reject */)>& rejected) override;
void openCrop(const std::string& image, const NitroCropConfig& config, const std::function<void(const CropResult& /* result */)>& resolved, const std::function<void(double /* reject */)>& rejected) override;
void openPreview(const std::vector<MediaPreview>& media, double index, const NitroPreviewConfig& config) override;
void openPreview(const std::vector<MediaPreview>& media, double index, const NitroPreviewConfig& config, const std::function<void(double /* index */)>& onLongPress) override;
void openCamera(const NitroCameraConfig& config, const std::function<void(const CameraResult& /* result */)>& resolved, const std::function<void(double /* reject */)>& rejected) override;

private:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,14 @@ abstract class HybridMultipleImagePickerSpec: HybridObject() {

@DoNotStrip
@Keep
abstract fun openPreview(media: Array<MediaPreview>, index: Double, config: NitroPreviewConfig): Unit
abstract fun openPreview(media: Array<MediaPreview>, index: Double, config: NitroPreviewConfig, onLongPress: (index: Double) -> Unit): Unit

@DoNotStrip
@Keep
private fun openPreview(media: Array<MediaPreview>, index: Double, config: NitroPreviewConfig, onLongPress: Func_void_double): Unit {
val __result = openPreview(media, index, config, onLongPress.toLambda())
return __result
}

@DoNotStrip
@Keep
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,8 @@ namespace margelo::nitro::multipleimagepicker {
std::rethrow_exception(__result.error());
}
}
inline void openPreview(const std::vector<MediaPreview>& media, double index, const NitroPreviewConfig& config) override {
auto __result = _swiftPart.openPreview(media, std::forward<decltype(index)>(index), config);
inline void openPreview(const std::vector<MediaPreview>& media, double index, const NitroPreviewConfig& config, const std::function<void(double /* index */)>& onLongPress) override {
auto __result = _swiftPart.openPreview(media, std::forward<decltype(index)>(index), config, onLongPress);
if (__result.hasError()) [[unlikely]] {
std::rethrow_exception(__result.error());
}
Expand Down
10 changes: 5 additions & 5 deletions nitrogen/generated/ios/swift/Func_void_double.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
Loading

0 comments on commit 737ad21

Please sign in to comment.