Skip to content

Commit dc0e38e

Browse files
committed
✨ feat: add camera view on Android
1 parent cfd3cb0 commit dc0e38e

File tree

6 files changed

+67
-35
lines changed

6 files changed

+67
-35
lines changed

android/src/main/java/com/margelo/nitro/multipleimagepicker/CameraEngine.kt

+18-7
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,37 @@ package com.margelo.nitro.multipleimagepicker
33
import android.content.Context
44
import androidx.fragment.app.Fragment
55
import com.bumptech.glide.Glide
6+
import com.facebook.react.bridge.ColorPropConverter
67
import com.luck.lib.camerax.SimpleCameraX
78
import com.luck.picture.lib.interfaces.OnCameraInterceptListener
89
import java.io.File
910

10-
class CameraEngine(private val appContext: Context, val config: PickerCameraConfig) : OnCameraInterceptListener {
11+
class CameraEngine(
12+
private val appContext: Context,
13+
val config: NitroCameraConfig,
14+
) :
15+
OnCameraInterceptListener {
1116
override fun openCamera(fragment: Fragment, cameraMode: Int, requestCode: Int) {
1217
val camera = SimpleCameraX.of()
18+
19+
camera.setImageEngine { context, url, imageView ->
20+
Glide.with(context).load(url).into(imageView)
21+
}
22+
1323
camera.isAutoRotation(true)
1424
camera.setCameraMode(cameraMode)
1525
camera.isDisplayRecordChangeTime(true)
1626
camera.isManualFocusCameraPreview(true)
1727
camera.isZoomCameraPreview(true)
18-
camera.setOutputPathDir(getSandboxCameraOutputPath())
1928
camera.setRecordVideoMaxSecond(config.videoMaximumDuration?.toInt() ?: 60)
20-
21-
// camera.setPermissionDeniedListener(getSimpleXPermissionDeniedListener())
22-
// camera.setPermissionDescriptionListener(getSimpleXPermissionDescriptionListener())
23-
camera.setImageEngine { context, url, imageView ->
24-
Glide.with(context).load(url).into(imageView)
29+
camera.setCameraAroundState(config.cameraDevice == CameraDevice.FRONT)
30+
camera.setOutputPathDir(getSandboxCameraOutputPath())
31+
32+
config.color?.let {
33+
val primaryColor = ColorPropConverter.getColor(it, appContext)
34+
camera.setCaptureLoadingColor(primaryColor)
2535
}
36+
2637
camera.start(fragment.requireActivity(), fragment, requestCode)
2738
}
2839

android/src/main/java/com/margelo/nitro/multipleimagepicker/MultipleImagePickerImp.kt

+39-17
Original file line numberDiff line numberDiff line change
@@ -112,11 +112,21 @@ class MultipleImagePickerImp(reactContext: ReactApplicationContext?) :
112112
setFilterMaxFileSize(it)
113113
}
114114

115-
116115
isDisplayCamera(config.camera != null)
117116

118117
config.camera?.let {
119-
setCameraInterceptListener(CameraEngine(appContext, it))
118+
val cameraConfig = NitroCameraConfig(
119+
mediaType = MediaType.ALL,
120+
presentation = Presentation.FULLSCREENMODAL,
121+
language = Language.SYSTEM,
122+
crop = null,
123+
isSaveSystemAlbum = false,
124+
color = config.primaryColor,
125+
cameraDevice = it.cameraDevice,
126+
videoMaximumDuration = it.videoMaximumDuration
127+
)
128+
129+
setCameraInterceptListener(CameraEngine(appContext, cameraConfig))
120130
}
121131
}
122132
.setImageSpanCount(config.numberOfColumn?.toInt() ?: 3)
@@ -314,31 +324,44 @@ class MultipleImagePickerImp(reactContext: ReactApplicationContext?) :
314324
resolved: (result: CameraResult) -> Unit,
315325
rejected: (reject: Double) -> Unit
316326
) {
327+
val activity = currentActivity
317328
val chooseMode = getChooseMode(config.mediaType)
318-
val cameraConfig = PickerCameraConfig(
319-
cameraDevice = config.cameraDevice,
320-
videoMaximumDuration = config.videoMaximumDuration
321-
)
322329

323330
PictureSelector
324-
.create(currentActivity)
331+
.create(activity)
325332
.openCamera(chooseMode)
326333
.setLanguage(getLanguage(config.language))
334+
.setCameraInterceptListener(CameraEngine(appContext, config))
327335
.isQuickCapture(true)
328-
.setCropEngine(CropEngine(cropOption))
329-
// .setOfAllCameraType(chooseMode)
330-
.setCameraInterceptListener(CameraEngine(appContext, cameraConfig))
331-
.forResult(object : OnResultCallbackListener<LocalMedia?> {
332-
override fun onResult(result: java.util.ArrayList<LocalMedia?>?) {
333-
println("camera: $result")
336+
.isOriginalControl(true)
337+
.apply {
338+
if (config.crop != null) {
339+
setCropEngine(CropEngine(cropOption))
340+
}
341+
}
342+
.forResultActivity(object : OnResultCallbackListener<LocalMedia?> {
343+
override fun onResult(results: java.util.ArrayList<LocalMedia?>?) {
344+
results?.first()?.let {
345+
val result = getResult(it)
346+
347+
resolved(
348+
CameraResult(
349+
path = result.path,
350+
type = result.type,
351+
width = result.width,
352+
height = result.height,
353+
duration = result.duration,
354+
thumbnail = result.thumbnail,
355+
fileName = result.fileName
356+
)
357+
)
358+
}
334359
}
335360

336361
override fun onCancel() {
337-
TODO("Not yet implemented")
362+
// rejected(0.0)
338363
}
339-
340364
})
341-
342365
}
343366

344367
private fun getChooseMode(mediaType: MediaType): Int {
@@ -558,7 +581,6 @@ class MultipleImagePickerImp(reactContext: ReactApplicationContext?) :
558581
height = item.cropImageHeight.toDouble()
559582
}
560583

561-
562584
val media = Result(
563585
localIdentifier = item.id.toString(),
564586
width,

example/src/index.tsx

+6-3
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,9 @@ export default function App() {
9696
const onCamera = async () => {
9797
try {
9898
const response = await openCamera({
99-
crop: true,
100-
isSaveSystemAlbum: false,
10199
mediaType: 'all',
102100
videoMaximumDuration: 5,
101+
color: 'black',
103102
})
104103

105104
setImages((prev) => {
@@ -449,7 +448,11 @@ export default function App() {
449448
description="Enable crop circle functionality."
450449
>
451450
<Switch
452-
value={options?.crop?.circle}
451+
value={
452+
typeof options.crop === 'boolean'
453+
? options.crop
454+
: options.crop?.circle
455+
}
453456
onValueChange={(value) =>
454457
setOptions(
455458
'crop',

ios/HybridMultipleImagePicker+Camera.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ extension HybridMultipleImagePicker {
7878
if let filePath {
7979
resolved(CameraResult(path: filePath, type: ResultType.image, width: uiImage.size.width, height: uiImage.size.height, duration: nil, thumbnail: nil, fileName: fileName))
8080
} else {
81-
rejected(0)
81+
rejected(1)
8282
}
8383

8484
case .video(let url):

src/index.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -126,10 +126,11 @@ export async function openCamera(config?: CameraConfig): Promise<CameraResult> {
126126
mediaType: 'all',
127127
allowLocation: true,
128128
isSaveSystemAlbum: false,
129-
color: processColor(config?.color ?? primaryColor) as any,
130129
...config,
131130
} as NitroCameraConfig
132131

132+
cameraConfig.color = processColor(cameraConfig.color ?? primaryColor) as any
133+
133134
cameraConfig.language = validateLanguage(cameraConfig.language)
134135

135136
if (typeof cameraConfig.crop === 'boolean') {

src/types/camera.ts

+1-6
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,7 @@ export interface NitroCameraConfig extends PickerCameraConfig {
4040
export interface CameraConfig
4141
extends Omit<
4242
NitroCameraConfig,
43-
| 'cameraDevice'
44-
| 'mediaType'
45-
| 'language'
46-
| 'presentation'
47-
| 'crop'
48-
| 'color'
43+
'mediaType' | 'language' | 'presentation' | 'crop' | 'color'
4944
> {
5045
/**
5146
* Type of media to be displayed

0 commit comments

Comments
 (0)