Skip to content

Commit c14083b

Browse files
committed
done custom crop engine image
1 parent d2cd976 commit c14083b

File tree

4 files changed

+187
-124
lines changed

4 files changed

+187
-124
lines changed
Lines changed: 75 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -1,111 +1,75 @@
1-
//package com.reactnativemultipleimagepicker
2-
//
3-
//import android.content.Context
4-
//import android.graphics.Bitmap
5-
//import android.net.Uri
6-
//import android.widget.ImageView
7-
//import androidx.core.content.ContextCompat
8-
//import androidx.fragment.app.Fragment
9-
//import com.bumptech.glide.Glide
10-
//import com.luck.picture.lib.engine.CropFileEngine
11-
//import com.luck.picture.lib.interfaces.OnCallbackListener
12-
//import com.luck.picture.lib.style.TitleBarStyle
13-
//import com.luck.picture.lib.utils.StyleUtils
14-
//import com.yalantis.ucrop.UCrop
15-
//import com.yalantis.ucrop.UCropImageEngine
16-
//import java.security.AccessController.getContext
17-
//
18-
//class ImageFileCropEngine : CropFileEngine {
19-
// fun onStartCrop(
20-
// fragment: Fragment,
21-
// srcUri: Uri?,
22-
// destinationUri: Uri?,
23-
// dataSource: ArrayList<String?>?,
24-
// requestCode: Int
25-
// ) {
26-
// val options: UCrop.Options = buildOptions()
27-
// val uCrop: UCrop = UCrop.of(srcUri, destinationUri, dataSource)
28-
// uCrop.withOptions(options)
29-
// uCrop.setImageEngine(object : UCropImageEngine() {
30-
// fun loadImage(context: Context?, url: String?, imageView: ImageView?) {
31-
// if (!ImageLoaderUtils.assertValidRequest(context)) {
32-
// return
33-
// }
34-
// GlideEngine.with(context).load(url).override(180, 180).into(imageView)
35-
// }
36-
//
37-
// fun loadImage(
38-
// context: Context?,
39-
// url: Uri?,
40-
// maxWidth: Int,
41-
// maxHeight: Int,
42-
// call: OnCallbackListener<Bitmap?>?
43-
// ) {
44-
// Glide.with(context).asBitmap().load(url).override(maxWidth, maxHeight)
45-
// .into(object : CustomTarget<Bitmap?>() {
46-
// fun onResourceReady(
47-
// @NonNull resource: Bitmap?,
48-
// @Nullable transition: Transition<in Bitmap?>?
49-
// ) {
50-
// if (call != null) {
51-
// call.onCall(resource)
52-
// }
53-
// }
54-
//
55-
// fun onLoadCleared(@Nullable placeholder: Drawable?) {
56-
// if (call != null) {
57-
// call.onCall(null)
58-
// }
59-
// }
60-
// })
61-
// }
62-
// })
63-
// uCrop.start(fragment.requireActivity(), fragment, requestCode)
64-
// }
65-
//}
66-
//
67-
//private fun buildOptions(): UCrop.Options {
68-
// val options = UCrop.Options()
69-
//// options.setHideBottomControls(!cb_hide.isChecked())
70-
//// options.setFreeStyleCropEnabled(cb_styleCrop.isChecked())
71-
//// options.setShowCropFrame(cb_showCropFrame.isChecked())
72-
//// options.setShowCropGrid(cb_showCropGrid.isChecked())
73-
//// options.setCircleDimmedLayer(cb_crop_circular.isChecked())
74-
//// options.withAspectRatio(aspect_ratio_x, aspect_ratio_y)
75-
//// options.setCropOutputPathDir(getSandboxPath())
76-
//// options.isCropDragSmoothToCenter(false)
77-
//// options.setSkipCropMimeType(getNotSupportCrop())
78-
//// options.isForbidCropGifWebp(cb_not_gif.isChecked())
79-
//// options.isForbidSkipMultipleCrop(true)
80-
//// options.setMaxScaleMultiplier(100f)
81-
//
82-
// if (selectorStyle != null && selectorStyle.getSelectMainStyle().getStatusBarColor() !== 0) {
83-
// val mainStyle: SelectMainStyle = selectorStyle.getSelectMainStyle()
84-
// val isDarkStatusBarBlack: Boolean = mainStyle.isDarkStatusBarBlack()
85-
// val statusBarColor: Int = mainStyle.getStatusBarColor()
86-
// options.isDarkStatusBarBlack(isDarkStatusBarBlack)
87-
// if (StyleUtils.checkStyleValidity(statusBarColor)) {
88-
// options.setStatusBarColor(statusBarColor)
89-
// options.setToolbarColor(statusBarColor)
90-
// } else {
91-
// options.setStatusBarColor(ContextCompat.getColor(getContext(), R.color.ps_color_grey))
92-
// options.setToolbarColor(ContextCompat.getColor(getContext(), R.color.ps_color_grey))
93-
// }
94-
// val titleBarStyle: TitleBarStyle = selectorStyle.getTitleBarStyle()
95-
// if (StyleUtils.checkStyleValidity(titleBarStyle.getTitleTextColor())) {
96-
// options.setToolbarWidgetColor(titleBarStyle.getTitleTextColor())
97-
// } else {
98-
// options.setToolbarWidgetColor(
99-
// ContextCompat.getColor(
100-
// getContext(),
101-
// R.color.ps_color_white
102-
// )
103-
// )
104-
// }
105-
// } else {
106-
// options.setStatusBarColor(ContextCompat.getColor(getContext(), R.color.ps_color_grey))
107-
// options.setToolbarColor(ContextCompat.getColor(getContext(), R.color.ps_color_grey))
108-
// options.setToolbarWidgetColor(ContextCompat.getColor(getContext(), R.color.ps_color_white))
109-
// }
110-
// return options
111-
//}
1+
package com.reactnativemultipleimagepicker
2+
3+
import android.content.Context
4+
import android.graphics.Bitmap
5+
import android.net.Uri
6+
import android.widget.ImageView
7+
import androidx.fragment.app.Fragment
8+
import com.bumptech.glide.Glide
9+
import com.luck.picture.lib.config.PictureMimeType
10+
import com.luck.picture.lib.engine.CropEngine
11+
import com.luck.picture.lib.entity.LocalMedia
12+
import com.luck.picture.lib.utils.DateUtils
13+
import com.yalantis.ucrop.UCrop
14+
import com.yalantis.ucrop.UCropImageEngine
15+
import java.io.File
16+
17+
18+
class CropEngine(
19+
appContext: Context,
20+
cropOption: UCrop.Options
21+
) : CropEngine {
22+
private val context = appContext
23+
private val option: UCrop.Options = cropOption
24+
override fun onStartCrop(
25+
fragment: Fragment, currentLocalMedia: LocalMedia,
26+
dataSource: ArrayList<LocalMedia>, requestCode: Int
27+
) {
28+
val currentCropPath = currentLocalMedia.availablePath
29+
val inputUri: Uri =
30+
if (PictureMimeType.isContent(currentCropPath) || PictureMimeType.isHasHttp(
31+
currentCropPath
32+
)
33+
) {
34+
Uri.parse(currentCropPath)
35+
} else {
36+
Uri.fromFile(File(currentCropPath))
37+
}
38+
val fileName: String = DateUtils.getCreateFileName("CROP_") + ".jpg"
39+
val destinationUri = Uri.fromFile(File(getSandboxPath(context), fileName))
40+
val dataCropSource: ArrayList<String> = ArrayList()
41+
for (i in 0 until dataSource.size) {
42+
val media = dataSource[i]
43+
dataCropSource.add(media.availablePath)
44+
}
45+
val uCrop = UCrop.of(inputUri, destinationUri, dataCropSource)
46+
uCrop.setImageEngine(object : UCropImageEngine {
47+
override fun loadImage(context: Context, url: String, imageView: ImageView) {
48+
Glide.with(context).load(url).into(imageView)
49+
}
50+
51+
override fun loadImage(
52+
context: Context?,
53+
url: Uri?,
54+
maxWidth: Int,
55+
maxHeight: Int,
56+
call: UCropImageEngine.OnCallbackListener<Bitmap>?
57+
) {
58+
TODO("Not yet implemented")
59+
}
60+
})
61+
uCrop.withOptions(option)
62+
uCrop.start(fragment.requireActivity(), fragment, requestCode)
63+
}
64+
}
65+
66+
fun getSandboxPath(context: Context): String {
67+
val externalFilesDir: File? = context.getExternalFilesDir("")
68+
val customFile = File(externalFilesDir?.absolutePath, "Sandbox")
69+
if (!customFile.exists()) {
70+
customFile.mkdirs()
71+
}
72+
return customFile.absolutePath + File.separator
73+
}
74+
75+
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.reactnativemultipleimagepicker
2+
3+
import android.app.Activity
4+
import android.content.Context
5+
import android.content.ContextWrapper
6+
7+
object ImageLoaderUtils {
8+
fun assertValidRequest(context: Context?): Boolean {
9+
if (context is Activity) {
10+
return !isDestroy(context)
11+
} else if (context is ContextWrapper) {
12+
if (context.baseContext is Activity) {
13+
val activity = context.baseContext as Activity
14+
return !isDestroy(activity)
15+
}
16+
}
17+
return true
18+
}
19+
20+
private fun isDestroy(activity: Activity?): Boolean {
21+
return if (activity == null) {
22+
true
23+
} else activity.isFinishing || activity.isDestroyed
24+
}
25+
}

android/src/main/java/com/reactnativemultipleimagepicker/MultipleImagePickerModule.kt

Lines changed: 72 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import android.graphics.Bitmap
55
import android.graphics.Color
66
import android.media.MediaMetadataRetriever
77
import android.os.Build
8+
import android.os.Bundle
89
import androidx.annotation.RequiresApi
910
import androidx.core.content.ContextCompat
1011
import com.facebook.react.bridge.*
@@ -18,6 +19,9 @@ import com.luck.picture.lib.entity.LocalMedia
1819
import com.luck.picture.lib.entity.LocalMedia.generateLocalMedia
1920
import com.luck.picture.lib.interfaces.OnResultCallbackListener
2021
import com.luck.picture.lib.style.*
22+
import com.luck.picture.lib.utils.StyleUtils
23+
import com.yalantis.ucrop.UCrop
24+
import com.yalantis.ucrop.UCrop.Options
2125
import java.io.*
2226
import java.util.*
2327

@@ -42,8 +46,7 @@ class MultipleImagePickerModule(reactContext: ReactApplicationContext) :
4246
private var isExportThumbnail: Boolean = false
4347
private var maxVideo: Int = 20
4448
private var isCamera: Boolean = true
45-
private var isCrop: Boolean = false
46-
private var isCropCircle: Boolean = false
49+
private var cropOption: UCrop.Options? = null;
4750

4851

4952
@ReactMethod
@@ -85,6 +88,7 @@ class MultipleImagePickerModule(reactContext: ReactApplicationContext) :
8588
.setImageEngine(imageEngine)
8689
.setMaxSelectNum(maxSelectedAssets)
8790
.setImageSpanCount(numberOfColumn)
91+
.setCropEngine(onSetCropEngine())
8892
.isDirectReturnSingle(true)
8993
.isSelectZoomAnim(true)
9094
.isPageStrategy(true, 50)
@@ -115,6 +119,9 @@ class MultipleImagePickerModule(reactContext: ReactApplicationContext) :
115119
localMedia.pushMap(media)
116120
}
117121
}
122+
123+
println("localMedia: $localMedia")
124+
118125
promise.resolve(localMedia)
119126
}
120127

@@ -124,10 +131,13 @@ class MultipleImagePickerModule(reactContext: ReactApplicationContext) :
124131
})
125132
}
126133

134+
private fun onSetCropEngine(): CropEngine? {
135+
return cropOption?.let { CropEngine(appContext, it) }
136+
}
137+
127138
private fun setConfiguration(options: ReadableMap?) {
128139
if (options != null) {
129140
handleSelectedAssets(options)
130-
val cropping = options.getBoolean("isCrop")
131141
singleSelectedMode = options.getBoolean("singleSelectedMode")
132142
maxVideoDuration = options.getInt("maxVideoDuration")
133143
numberOfColumn = options.getInt("numberOfColumn")
@@ -137,13 +147,69 @@ class MultipleImagePickerModule(reactContext: ReactApplicationContext) :
137147
isExportThumbnail = options.getBoolean("isExportThumbnail")
138148
maxVideo = options.getInt("maxVideo")
139149
isCamera = options.getBoolean("usedCameraButton")
140-
isCropCircle = options.getBoolean("isCropCircle")
141-
isCrop = cropping == true && singleSelectedMode == true
142150

143151
setStyle(options) // set style for UI
152+
153+
val isCrop = options.getBoolean("isCrop") && singleSelectedMode
154+
155+
if (isCrop) {
156+
buildCropOptions(options)
157+
}
158+
144159
}
145160
}
146161

162+
private fun buildCropOptions(libOption: ReadableMap) {
163+
val options = UCrop.Options()
164+
165+
options.setShowCropFrame(true)
166+
options.setShowCropGrid(true)
167+
options.setCircleDimmedLayer(libOption.getBoolean("isCropCircle"))
168+
// options.withAspectRatio(aspect_ratio_x, aspect_ratio_y)
169+
options.setCropOutputPathDir(getSandboxPath(appContext))
170+
options.isCropDragSmoothToCenter(false)
171+
// options.setSkipCropMimeType(getNotSupportCrop())
172+
options.isForbidSkipMultipleCrop(true)
173+
options.setMaxScaleMultiplier(100f)
174+
175+
println("style.selectMainStyle.statusBarColor: ${style.selectMainStyle.statusBarColor}")
176+
if (style.selectMainStyle.statusBarColor != 0) {
177+
val mainStyle: SelectMainStyle = style.selectMainStyle
178+
val isDarkStatusBarBlack: Boolean = mainStyle.isDarkStatusBarBlack
179+
val statusBarColor: Int = mainStyle.statusBarColor
180+
options.isDarkStatusBarBlack(isDarkStatusBarBlack)
181+
if (StyleUtils.checkStyleValidity(statusBarColor)) {
182+
options.setStatusBarColor(statusBarColor)
183+
options.setToolbarColor(statusBarColor)
184+
} else {
185+
options.setStatusBarColor(ContextCompat.getColor(appContext, R.color.ps_color_grey))
186+
options.setToolbarColor(ContextCompat.getColor(appContext, R.color.ps_color_grey))
187+
}
188+
val titleBarStyle: TitleBarStyle = style.titleBarStyle
189+
if (StyleUtils.checkStyleValidity(titleBarStyle.titleTextColor)) {
190+
options.setToolbarWidgetColor(titleBarStyle.titleTextColor)
191+
} else {
192+
options.setToolbarWidgetColor(
193+
ContextCompat.getColor(
194+
appContext,
195+
R.color.ps_color_white
196+
)
197+
)
198+
}
199+
} else {
200+
options.setStatusBarColor(ContextCompat.getColor(appContext, R.color.ps_color_grey))
201+
options.setToolbarColor(ContextCompat.getColor(appContext, R.color.ps_color_grey))
202+
options.setToolbarWidgetColor(
203+
ContextCompat.getColor(
204+
appContext,
205+
R.color.ps_color_white
206+
)
207+
)
208+
}
209+
210+
cropOption = options
211+
}
212+
147213
private fun setStyle(options: ReadableMap) {
148214
val doneTitle = options.getString("doneTitle")
149215

@@ -183,6 +249,7 @@ class MultipleImagePickerModule(reactContext: ReactApplicationContext) :
183249
ContextCompat.getColor(appContext, R.color.ps_color_53575e)
184250
bottomBar.bottomPreviewNormalTextColor = R.color.app_color_53575e
185251
bottomBar.bottomPreviewNormalTextColor = R.color.app_color_black
252+
bottomBar.setCompleteCountTips(false)
186253

187254
// MAIN STYLE
188255
val mainStyle = SelectMainStyle()
@@ -314,7 +381,6 @@ class MultipleImagePickerModule(reactContext: ReactApplicationContext) :
314381
val fullPath: String =
315382
reactApplicationContext.applicationContext.cacheDir.absolutePath.toString() + "/thumbnails"
316383
try {
317-
var fOut: OutputStream? = null
318384
val fileName = "thumb-" + UUID.randomUUID().toString() + ".jpeg"
319385
val file = File(fullPath, fileName)
320386
file.parentFile?.mkdirs()

0 commit comments

Comments
 (0)