react-native-picture-selector 1.0.28 → 1.0.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/CMakeLists.txt +0 -18
- package/android/src/main/kotlin/com/margelo/pictureselector/LubanCompressEngine.kt +5 -13
- package/android/src/main/kotlin/com/margelo/pictureselector/MediaAssetMapper.kt +5 -6
- package/android/src/main/kotlin/com/margelo/pictureselector/NitroPictureSelectorPackage.kt +0 -7
- package/android/src/main/kotlin/com/margelo/pictureselector/PictureSelectorOptionsMapper.kt +5 -17
- package/ios/HybridPictureSelector.swift +54 -5
- package/ios/NitroPictureSelectorOnLoad.mm +1 -1
- package/nitrogen.config.json +19 -0
- package/package.json +2 -11
- package/nitro.json +0 -11
package/android/CMakeLists.txt
CHANGED
|
@@ -18,21 +18,3 @@ include(${CMAKE_SOURCE_DIR}/../nitrogen/generated/android/NitroPictureSelector+a
|
|
|
18
18
|
target_sources(${CMAKE_PROJECT_NAME} PRIVATE
|
|
19
19
|
src/main/cpp/cpp-adapter.cpp
|
|
20
20
|
)
|
|
21
|
-
|
|
22
|
-
# Directly link libNitroModules.so from its stable cmake build output path.
|
|
23
|
-
# The prefab for react-native-nitro-modules is header-only at CMake configure
|
|
24
|
-
# time (fix-prefab.gradle updates it only after native build), so we link
|
|
25
|
-
# the .so directly to avoid undefined symbol errors on fresh builds.
|
|
26
|
-
#
|
|
27
|
-
# Use a generator expression so the correct variant (debug/release) is picked
|
|
28
|
-
# automatically — avoids breaking assembleRelease / EAS production builds.
|
|
29
|
-
string(TOLOWER "${CMAKE_BUILD_TYPE}" _build_type_lower)
|
|
30
|
-
if(_build_type_lower STREQUAL "release")
|
|
31
|
-
set(NITRO_BUILD_VARIANT "release")
|
|
32
|
-
else()
|
|
33
|
-
set(NITRO_BUILD_VARIANT "debug")
|
|
34
|
-
endif()
|
|
35
|
-
|
|
36
|
-
target_link_libraries(${CMAKE_PROJECT_NAME}
|
|
37
|
-
${CMAKE_SOURCE_DIR}/../../react-native-nitro-modules/android/build/intermediates/cmake/${NITRO_BUILD_VARIANT}/obj/${ANDROID_ABI}/libNitroModules.so
|
|
38
|
-
)
|
|
@@ -15,28 +15,20 @@ import java.io.File
|
|
|
15
15
|
* (io.github.lucksiege:compress). This engine is invoked after selection
|
|
16
16
|
* when compression is enabled.
|
|
17
17
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
18
|
+
* Luban handles compression quality internally using an adaptive algorithm
|
|
19
|
+
* based on image dimensions. Direct JPEG quality control is not supported
|
|
20
|
+
* by this bundled version. Use [ignoreBy] to skip already-small files.
|
|
21
21
|
*/
|
|
22
|
-
class LubanCompressEngine
|
|
23
|
-
private val quality: Int,
|
|
24
|
-
private val maxWidth: Int,
|
|
25
|
-
private val maxHeight: Int,
|
|
26
|
-
) : CompressFileEngine {
|
|
22
|
+
class LubanCompressEngine : CompressFileEngine {
|
|
27
23
|
|
|
28
24
|
override fun onStartCompress(
|
|
29
25
|
context: Context,
|
|
30
26
|
source: ArrayList<Uri>,
|
|
31
27
|
call: OnKeyValueResultCallbackListener,
|
|
32
28
|
) {
|
|
33
|
-
// API REQUIRES VERIFICATION: setQuality() method name in bundled Luban version.
|
|
34
|
-
// In most Luban forks bundled with PictureSelector, quality is set via .quality(Int)
|
|
35
|
-
// or .setCompressQuality(Int). Adjust the method name after verifying against
|
|
36
|
-
// io.github.lucksiege:compress:v3.11.2 source.
|
|
37
29
|
Luban.with(context)
|
|
38
30
|
.load(source)
|
|
39
|
-
.ignoreBy(100) // skip files under 100 KB
|
|
31
|
+
.ignoreBy(100) // skip files already under 100 KB
|
|
40
32
|
.setTargetDir(context.cacheDir.absolutePath)
|
|
41
33
|
.setCompressListener(object : OnNewCompressListener {
|
|
42
34
|
override fun onStart() {
|
|
@@ -13,11 +13,10 @@ import java.io.File
|
|
|
13
13
|
* 3. Real file path (realPath != null)
|
|
14
14
|
* 4. Fallback (path — may be content:// URI)
|
|
15
15
|
*
|
|
16
|
-
*
|
|
17
|
-
* - LocalMedia.
|
|
18
|
-
*
|
|
19
|
-
* - LocalMedia.
|
|
20
|
-
* - LocalMedia.duration unit (ms in v3; confirm).
|
|
16
|
+
* Field mapping verified against PictureSelector v3.11.2:
|
|
17
|
+
* - LocalMedia.size — file size in bytes (Long)
|
|
18
|
+
* - LocalMedia.duration — duration in milliseconds (Long)
|
|
19
|
+
* - LocalMedia.parentFolderName — album/bucket display name (String)
|
|
21
20
|
*/
|
|
22
21
|
object MediaAssetMapper {
|
|
23
22
|
|
|
@@ -44,7 +43,7 @@ object MediaAssetMapper {
|
|
|
44
43
|
height = media.height.toDouble(),
|
|
45
44
|
duration = media.duration.toDouble(), // milliseconds
|
|
46
45
|
fileName = fileName,
|
|
47
|
-
fileSize = media.size.toDouble(),
|
|
46
|
+
fileSize = media.size.toDouble(),
|
|
48
47
|
editedUri = editedPath,
|
|
49
48
|
isOriginal = null,
|
|
50
49
|
bucketName = media.parentFolderName,
|
|
@@ -18,13 +18,6 @@ import com.margelo.nitro.com.margelo.pictureselector.NitroPictureSelectorOnLoad
|
|
|
18
18
|
* // MainApplication.kt
|
|
19
19
|
* override fun getPackages() = PackageList(this).packages + NitroPictureSelectorPackage()
|
|
20
20
|
* ```
|
|
21
|
-
*
|
|
22
|
-
* API REQUIRES VERIFICATION:
|
|
23
|
-
* - NitroModules.addHybridObjectCreator is the actual registration API in
|
|
24
|
-
* react-native-nitro-modules for Android. Verify against the installed
|
|
25
|
-
* version of the library. The creator name ("PictureSelector") must
|
|
26
|
-
* exactly match the string passed to NitroModules.createHybridObject()
|
|
27
|
-
* on the JS side.
|
|
28
21
|
*/
|
|
29
22
|
class NitroPictureSelectorPackage : ReactPackage {
|
|
30
23
|
|
|
@@ -12,11 +12,7 @@ import com.margelo.nitro.com.margelo.pictureselector.PictureSelectorOptions
|
|
|
12
12
|
* [PictureSelector.create(activity).openGallery()] /
|
|
13
13
|
* [PictureSelector.create(activity).openCamera()].
|
|
14
14
|
*
|
|
15
|
-
*
|
|
16
|
-
* - setSelectVideoMaxDuration / setSelectVideoMinDuration unit (seconds vs ms).
|
|
17
|
-
* In v3.11.2 these accept seconds. Confirm in the library source.
|
|
18
|
-
* - setSelectorUIStyle builder method name & enum values.
|
|
19
|
-
* - setSelectedData signature for pre-selected items.
|
|
15
|
+
* Video duration methods accept seconds in v3.11.2.
|
|
20
16
|
*/
|
|
21
17
|
object PictureSelectorOptionsMapper {
|
|
22
18
|
|
|
@@ -37,9 +33,8 @@ object PictureSelectorOptionsMapper {
|
|
|
37
33
|
// Show camera button inside gallery
|
|
38
34
|
builder.isDisplayCamera(options.enableCamera ?: true)
|
|
39
35
|
|
|
40
|
-
// Pre-selected assets
|
|
41
|
-
//
|
|
42
|
-
// options.selectedAssets is currently unused in v1; add in future.
|
|
36
|
+
// Pre-selected assets: selectedAssets (file:// URIs) conversion to LocalMedia
|
|
37
|
+
// is not yet implemented; skipped intentionally.
|
|
43
38
|
}
|
|
44
39
|
|
|
45
40
|
/**
|
|
@@ -68,10 +63,7 @@ object PictureSelectorOptionsMapper {
|
|
|
68
63
|
|
|
69
64
|
val compress = options.compress
|
|
70
65
|
if (compress != null && compress.enabled) {
|
|
71
|
-
|
|
72
|
-
val maxWidth = (compress.maxWidth ?: 1920.0).toInt()
|
|
73
|
-
val maxHeight = (compress.maxHeight ?: 1920.0).toInt()
|
|
74
|
-
builder.setCompressEngine(LubanCompressEngine(quality, maxWidth, maxHeight))
|
|
66
|
+
builder.setCompressEngine(LubanCompressEngine())
|
|
75
67
|
}
|
|
76
68
|
}
|
|
77
69
|
|
|
@@ -104,11 +96,7 @@ object PictureSelectorOptionsMapper {
|
|
|
104
96
|
// ── Compress engine ───────────────────────────────────────────────────
|
|
105
97
|
val compress = options.compress
|
|
106
98
|
if (compress != null && compress.enabled) {
|
|
107
|
-
|
|
108
|
-
val maxWidth = (compress.maxWidth ?: 1920.0).toInt()
|
|
109
|
-
val maxHeight = (compress.maxHeight ?: 1920.0).toInt()
|
|
110
|
-
|
|
111
|
-
builder.setCompressEngine(LubanCompressEngine(quality, maxWidth, maxHeight))
|
|
99
|
+
builder.setCompressEngine(LubanCompressEngine())
|
|
112
100
|
}
|
|
113
101
|
}
|
|
114
102
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import Foundation
|
|
2
2
|
import UIKit
|
|
3
|
+
import AVFoundation
|
|
3
4
|
import HXPhotoPicker
|
|
4
5
|
import NitroModules
|
|
5
6
|
|
|
@@ -112,11 +113,7 @@ final class HybridPictureSelector: HybridHybridPictureSelectorSpec_base, HybridH
|
|
|
112
113
|
}
|
|
113
114
|
Task {
|
|
114
115
|
do {
|
|
115
|
-
let asset = try await self.
|
|
116
|
-
result.photoAsset,
|
|
117
|
-
compress: options.compress,
|
|
118
|
-
isOriginal: false
|
|
119
|
-
)
|
|
116
|
+
let asset = try await self.mapCameraResult(result, compress: options.compress)
|
|
120
117
|
promise.resolve(withResult: [asset])
|
|
121
118
|
} catch {
|
|
122
119
|
promise.reject(withError: error)
|
|
@@ -259,6 +256,58 @@ final class HybridPictureSelector: HybridHybridPictureSelectorSpec_base, HybridH
|
|
|
259
256
|
)
|
|
260
257
|
}
|
|
261
258
|
|
|
259
|
+
// MARK: - Camera result mapping
|
|
260
|
+
|
|
261
|
+
private func mapCameraResult(
|
|
262
|
+
_ result: CameraController.Result,
|
|
263
|
+
compress: CompressOptions?
|
|
264
|
+
) async throws -> MediaAsset {
|
|
265
|
+
switch result {
|
|
266
|
+
case .image(let image):
|
|
267
|
+
let quality = compress?.quality ?? 0.8
|
|
268
|
+
guard let data = image.jpegData(compressionQuality: quality) else {
|
|
269
|
+
throw PictureSelectorError.unknown("Failed to encode captured image")
|
|
270
|
+
}
|
|
271
|
+
let fileName = "camera_\(UUID().uuidString).jpg"
|
|
272
|
+
let tempURL = FileManager.default.temporaryDirectory.appendingPathComponent(fileName)
|
|
273
|
+
try data.write(to: tempURL)
|
|
274
|
+
let fileSize = Double(data.count)
|
|
275
|
+
return MediaAsset(
|
|
276
|
+
uri: tempURL.absoluteString,
|
|
277
|
+
type: "image",
|
|
278
|
+
mimeType: "image/jpeg",
|
|
279
|
+
width: Double(image.size.width * image.scale),
|
|
280
|
+
height: Double(image.size.height * image.scale),
|
|
281
|
+
duration: 0,
|
|
282
|
+
fileName: fileName,
|
|
283
|
+
fileSize: fileSize,
|
|
284
|
+
editedUri: nil,
|
|
285
|
+
isOriginal: false,
|
|
286
|
+
bucketName: nil
|
|
287
|
+
)
|
|
288
|
+
case .video(let url):
|
|
289
|
+
let attrs = try? FileManager.default.attributesOfItem(atPath: url.path)
|
|
290
|
+
let fileSize = Double((attrs?[.size] as? UInt64) ?? 0)
|
|
291
|
+
let asset = AVURLAsset(url: url)
|
|
292
|
+
let duration = CMTimeGetSeconds(asset.duration) * 1_000
|
|
293
|
+
let tracks = asset.tracks(withMediaType: .video)
|
|
294
|
+
let size = tracks.first?.naturalSize ?? .zero
|
|
295
|
+
return MediaAsset(
|
|
296
|
+
uri: url.absoluteString,
|
|
297
|
+
type: "video",
|
|
298
|
+
mimeType: mimeType(for: url),
|
|
299
|
+
width: Double(size.width),
|
|
300
|
+
height: Double(size.height),
|
|
301
|
+
duration: duration,
|
|
302
|
+
fileName: url.lastPathComponent,
|
|
303
|
+
fileSize: fileSize,
|
|
304
|
+
editedUri: nil,
|
|
305
|
+
isOriginal: false,
|
|
306
|
+
bucketName: nil
|
|
307
|
+
)
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
262
311
|
// MARK: - Compression helper
|
|
263
312
|
|
|
264
313
|
private func buildCompression(from options: CompressOptions?) -> PhotoAsset.Compression? {
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
// Defined in HybridPictureSelector.swift via @_cdecl.
|
|
18
18
|
// Creates a HybridPictureSelector instance and returns a retained raw pointer
|
|
19
19
|
// to its HybridHybridPictureSelectorSpec_cxx wrapper.
|
|
20
|
-
extern "C" void* NitroPictureSelectorMakeHybrid();
|
|
20
|
+
extern "C" void* NitroPictureSelectorMakeHybrid() noexcept;
|
|
21
21
|
|
|
22
22
|
using namespace margelo::nitro;
|
|
23
23
|
using namespace margelo::nitro::pictureselector;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://nitro.margelo.com/nitro.schema.json",
|
|
3
|
+
"cxxNamespace": ["margelo", "nitro", "pictureselector"],
|
|
4
|
+
"outputDirectory": "./nitrogen",
|
|
5
|
+
"specs": ["./src/specs"],
|
|
6
|
+
"ios": {
|
|
7
|
+
"iosModuleName": "NitroPictureSelector"
|
|
8
|
+
},
|
|
9
|
+
"android": {
|
|
10
|
+
"androidNamespace": ["com", "margelo", "pictureselector"],
|
|
11
|
+
"androidCxxLibName": "NitroPictureSelector"
|
|
12
|
+
},
|
|
13
|
+
"autolinking": {
|
|
14
|
+
"PictureSelector": {
|
|
15
|
+
"swift": "HybridPictureSelector",
|
|
16
|
+
"kotlin": "HybridPictureSelector"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-picture-selector",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.30",
|
|
4
4
|
"description": "High-performance photo/video picker for React Native using Nitro Modules",
|
|
5
5
|
"main": "lib/commonjs/index.js",
|
|
6
6
|
"module": "lib/module/index.js",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"android",
|
|
14
14
|
"ios",
|
|
15
15
|
"nitrogen",
|
|
16
|
-
"
|
|
16
|
+
"nitrogen.config.json",
|
|
17
17
|
"*.podspec"
|
|
18
18
|
],
|
|
19
19
|
"scripts": {
|
|
@@ -51,15 +51,6 @@
|
|
|
51
51
|
"react-native-nitro-modules": ">=0.20.0",
|
|
52
52
|
"typescript": "^5.3.0"
|
|
53
53
|
},
|
|
54
|
-
"nitro": {
|
|
55
|
-
"ios": {
|
|
56
|
-
"iosModuleName": "NitroPictureSelector"
|
|
57
|
-
},
|
|
58
|
-
"android": {
|
|
59
|
-
"androidNamespace": "com.nitro.pictureselector",
|
|
60
|
-
"androidCxxLibName": "NitroPictureSelector"
|
|
61
|
-
}
|
|
62
|
-
},
|
|
63
54
|
"react-native-builder-bob": {
|
|
64
55
|
"source": "src",
|
|
65
56
|
"output": "lib",
|
package/nitro.json
DELETED