From 85b140e30c4377f5963b04768576723d2d2e7f21 Mon Sep 17 00:00:00 2001 From: Eugene Poroshin Date: Thu, 24 Aug 2023 09:27:17 +0200 Subject: [PATCH 1/4] Update .gitignore --- .gitignore | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index aa724b7..10cfdbf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,7 @@ *.iml .gradle /local.properties -/.idea/caches -/.idea/libraries -/.idea/modules.xml -/.idea/workspace.xml -/.idea/navEditor.xml -/.idea/assetWizardSettings.xml +/.idea .DS_Store /build /captures From 8f662d7a330eeba3460071a27ffcd541f95ee6b4 Mon Sep 17 00:00:00 2001 From: Eugene Poroshin Date: Thu, 24 Aug 2023 09:36:12 +0200 Subject: [PATCH 2/4] remove .idea from remote --- .gitignore | 2 +- .idea/.gitignore | 3 - .idea/androidTestResultsUserPreferences.xml | 74 -------------------- .idea/compiler.xml | 6 -- .idea/gradle.xml | 21 ------ .idea/inspectionProfiles/Project_Default.xml | 37 ---------- .idea/misc.xml | 10 --- .idea/vcs.xml | 6 -- 8 files changed, 1 insertion(+), 158 deletions(-) delete mode 100644 .idea/.gitignore delete mode 100644 .idea/androidTestResultsUserPreferences.xml delete mode 100644 .idea/compiler.xml delete mode 100644 .idea/gradle.xml delete mode 100644 .idea/inspectionProfiles/Project_Default.xml delete mode 100644 .idea/misc.xml delete mode 100644 .idea/vcs.xml diff --git a/.gitignore b/.gitignore index 10cfdbf..87f66f5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ *.iml .gradle /local.properties -/.idea +.idea/ .DS_Store /build /captures diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 26d3352..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml diff --git a/.idea/androidTestResultsUserPreferences.xml b/.idea/androidTestResultsUserPreferences.xml deleted file mode 100644 index b9e23ad..0000000 --- a/.idea/androidTestResultsUserPreferences.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml deleted file mode 100644 index fb7f4a8..0000000 --- a/.idea/compiler.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml deleted file mode 100644 index 8a7298b..0000000 --- a/.idea/gradle.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml deleted file mode 100644 index ed76bea..0000000 --- a/.idea/inspectionProfiles/Project_Default.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index bdd9278..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 94a25f7..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file From 00e0cc5b61994404329de8fc77fe72cef6299133 Mon Sep 17 00:00:00 2001 From: Eugene Poroshin Date: Thu, 24 Aug 2023 10:01:22 +0200 Subject: [PATCH 3/4] - Disable unnecessary controls; - Change default behaviour; - Change color of toolbar --- .../java/com/mr0xf00/easycrop/CropState.kt | 4 +- .../java/com/mr0xf00/easycrop/ui/Controls.kt | 54 +++++++++---------- .../mr0xf00/easycrop/ui/ImageCropperDialog.kt | 6 ++- 3 files changed, 33 insertions(+), 31 deletions(-) diff --git a/easycrop/src/main/java/com/mr0xf00/easycrop/CropState.kt b/easycrop/src/main/java/com/mr0xf00/easycrop/CropState.kt index 9726e1f..f0cfd17 100644 --- a/easycrop/src/main/java/com/mr0xf00/easycrop/CropState.kt +++ b/easycrop/src/main/java/com/mr0xf00/easycrop/CropState.kt @@ -33,7 +33,7 @@ internal fun CropState( ): CropState = object : CropState { val defaultTransform: ImgTransform = ImgTransform.Identity val defaultShape: CropShape = RectCropShape - val defaultAspectLock: Boolean = false + val defaultAspectLock: Boolean = true override val src: ImageSrc get() = src private var _transform: ImgTransform by mutableStateOf(defaultTransform) override var transform: ImgTransform @@ -43,7 +43,7 @@ internal fun CropState( _transform = value } - val defaultRegion = src.size.toSize().toRect() + val defaultRegion = src.size.toSize().toRect().setAspect(AspectRatio(1, 1)) private var _region by mutableStateOf(defaultRegion) override var region diff --git a/easycrop/src/main/java/com/mr0xf00/easycrop/ui/Controls.kt b/easycrop/src/main/java/com/mr0xf00/easycrop/ui/Controls.kt index 97d73fc..4f04eb9 100644 --- a/easycrop/src/main/java/com/mr0xf00/easycrop/ui/Controls.kt +++ b/easycrop/src/main/java/com/mr0xf00/easycrop/ui/Controls.kt @@ -51,33 +51,33 @@ internal fun CropperControls( IconButton(onClick = { state.flipVertical() }) { Icon(painterResource(id = R.drawable.flip_ver), null) } - Box { - var menu by remember { mutableStateOf(false) } - IconButton(onClick = { menu = !menu }) { - Icon(painterResource(id = R.drawable.resize), null) - } - if (menu) AspectSelectionMenu( - onDismiss = { menu = false }, - region = state.region, - onRegion = { state.region = it }, - lock = state.aspectLock, - onLock = { state.aspectLock = it } - ) - } - LocalCropperStyle.current.shapes?.let { shapes -> - Box { - var menu by remember { mutableStateOf(false) } - IconButton(onClick = { menu = !menu }) { - Icon(Icons.Default.Star, null) - } - if (menu) ShapeSelectionMenu( - onDismiss = { menu = false }, - selected = state.shape, - onSelect = { state.shape = it }, - shapes = shapes - ) - } - } +// Box { +// var menu by remember { mutableStateOf(false) } +// IconButton(onClick = { menu = !menu }) { +// Icon(painterResource(id = R.drawable.resize), null) +// } +// if (menu) AspectSelectionMenu( +// onDismiss = { menu = false }, +// region = state.region, +// onRegion = { state.region = it }, +// lock = state.aspectLock, +// onLock = { state.aspectLock = it } +// ) +// } +// LocalCropperStyle.current.shapes?.let { shapes -> +// Box { +// var menu by remember { mutableStateOf(false) } +// IconButton(onClick = { menu = !menu }) { +// Icon(Icons.Default.Star, null) +// } +// if (menu) ShapeSelectionMenu( +// onDismiss = { menu = false }, +// selected = state.shape, +// onSelect = { state.shape = it }, +// shapes = shapes +// ) +// } +// } } } } diff --git a/easycrop/src/main/java/com/mr0xf00/easycrop/ui/ImageCropperDialog.kt b/easycrop/src/main/java/com/mr0xf00/easycrop/ui/ImageCropperDialog.kt index 8ee9ab1..5429581 100644 --- a/easycrop/src/main/java/com/mr0xf00/easycrop/ui/ImageCropperDialog.kt +++ b/easycrop/src/main/java/com/mr0xf00/easycrop/ui/ImageCropperDialog.kt @@ -16,6 +16,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clipToBounds +import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Shape import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.res.painterResource @@ -27,7 +28,7 @@ import com.mr0xf00.easycrop.R private val CropperDialogProperties = @OptIn(ExperimentalComposeUiApi::class) (DialogProperties( usePlatformDefaultWidth = false, - dismissOnBackPress = false, + dismissOnBackPress = true, dismissOnClickOutside = false )) @@ -94,6 +95,7 @@ private fun DefaultTopBar(state: CropState) { IconButton(onClick = { state.done(accept = true) }, enabled = !state.accepted) { Icon(Icons.Default.Done, null) } - } + }, + backgroundColor = Color(0xFF202020) ) } From 3fc6e89c01898e3124eb7c053fdeccaf9bf867e9 Mon Sep 17 00:00:00 2001 From: Dmitriy Kotikov Date: Thu, 19 Oct 2023 11:50:53 +0300 Subject: [PATCH 4/4] App crashing when image size is too large fixed. New callback for drawing errors catching added. --- .../com/mr0xf00/easycrop/ui/CropperPreview.kt | 16 ++++++++---- .../mr0xf00/easycrop/ui/ImageCropperDialog.kt | 25 ++++++++++++++++--- gradle.properties | 5 +++- .../easycrop/presentation/ImagesViewModel.kt | 8 +++++- .../com/mr0xf00/easycrop/ui/DemoContent.kt | 3 ++- .../com/mr0xf00/easycrop/ui/SimpleDemo.kt | 1 + .../com/mr0xf00/easycrop/ui/ViewModelDemo.kt | 7 +++++- settings.gradle | 3 ++- 8 files changed, 54 insertions(+), 14 deletions(-) diff --git a/easycrop/src/main/java/com/mr0xf00/easycrop/ui/CropperPreview.kt b/easycrop/src/main/java/com/mr0xf00/easycrop/ui/CropperPreview.kt index 310f236..02d1deb 100644 --- a/easycrop/src/main/java/com/mr0xf00/easycrop/ui/CropperPreview.kt +++ b/easycrop/src/main/java/com/mr0xf00/easycrop/ui/CropperPreview.kt @@ -22,7 +22,8 @@ import kotlinx.coroutines.delay @Composable fun CropperPreview( state: CropState, - modifier: Modifier = Modifier + modifier: Modifier = Modifier, + onDrawingError: (Exception) -> Unit ) { val style = LocalCropperStyle.current val imgTransform by animateImgTransform(target = state.transform) @@ -58,10 +59,15 @@ fun CropperPreview( ) { withTransform({ transform(totalMat) }) { image?.let { (params, bitmap) -> - drawImage( - bitmap, dstOffset = params.subset.topLeft, - dstSize = params.subset.size - ) + try { + drawImage( + bitmap, dstOffset = params.subset.topLeft, + dstSize = params.subset.size + ) + } catch (e: Exception) { + state.done(false) + onDrawingError(e) + } } } with(style) { diff --git a/easycrop/src/main/java/com/mr0xf00/easycrop/ui/ImageCropperDialog.kt b/easycrop/src/main/java/com/mr0xf00/easycrop/ui/ImageCropperDialog.kt index 5429581..64de358 100644 --- a/easycrop/src/main/java/com/mr0xf00/easycrop/ui/ImageCropperDialog.kt +++ b/easycrop/src/main/java/com/mr0xf00/easycrop/ui/ImageCropperDialog.kt @@ -39,6 +39,7 @@ fun ImageCropperDialog( dialogProperties: DialogProperties = CropperDialogProperties, dialogPadding: PaddingValues = PaddingValues(16.dp), dialogShape: Shape = RoundedCornerShape(8.dp), + onDrawingError: (Exception) -> Unit, topBar: @Composable (CropState) -> Unit = { DefaultTopBar(it) }, cropControls: @Composable BoxScope.(CropState) -> Unit = { DefaultControls(it) } ) { @@ -58,7 +59,11 @@ fun ImageCropperDialog( .weight(1f) .clipToBounds() ) { - CropperPreview(state = state, modifier = Modifier.fillMaxSize()) + CropperPreview( + state = state, + modifier = Modifier.fillMaxSize(), + onDrawingError = onDrawingError + ) cropControls(state) } } @@ -85,15 +90,27 @@ private fun DefaultTopBar(state: CropState) { TopAppBar(title = {}, navigationIcon = { IconButton(onClick = { state.done(accept = false) }) { - Icon(Icons.Default.ArrowBack, null) + Icon( + imageVector = Icons.Default.ArrowBack, + tint = Color.White, + contentDescription = null + ) } }, actions = { IconButton(onClick = { state.reset() }) { - Icon(painterResource(R.drawable.restore), null) + Icon( + painter = painterResource(R.drawable.restore), + tint = Color.White, + contentDescription = null + ) } IconButton(onClick = { state.done(accept = true) }, enabled = !state.accepted) { - Icon(Icons.Default.Done, null) + Icon( + imageVector = Icons.Default.Done, + tint = Color.White, + contentDescription = null + ) } }, backgroundColor = Color(0xFF202020) diff --git a/gradle.properties b/gradle.properties index 728a09c..00bdf35 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,4 +4,7 @@ kotlin.code.style=official android.nonTransitiveRClass=true composeBomVersion=2023.01.00 -composeCompilerVersion=1.4.0 \ No newline at end of file +composeCompilerVersion=1.4.0 + +ossrh.user=dummy +ossrh.pass=dummy \ No newline at end of file diff --git a/sample/src/main/java/com/mr0xf00/easycrop/presentation/ImagesViewModel.kt b/sample/src/main/java/com/mr0xf00/easycrop/presentation/ImagesViewModel.kt index e24d525..3e2133a 100644 --- a/sample/src/main/java/com/mr0xf00/easycrop/presentation/ImagesViewModel.kt +++ b/sample/src/main/java/com/mr0xf00/easycrop/presentation/ImagesViewModel.kt @@ -1,8 +1,10 @@ package com.mr0xf00.easycrop.presentation import android.app.Application +import android.graphics.BitmapFactory import android.net.Uri import androidx.compose.ui.graphics.ImageBitmap +import androidx.compose.ui.graphics.asImageBitmap import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.viewModelScope import com.mr0xf00.easycrop.CropError @@ -26,7 +28,11 @@ class ImagesViewModel(private val app: Application) : AndroidViewModel(app) { fun setSelectedImage(uri: Uri) { viewModelScope.launch { - when(val result = imageCropper.crop(uri, app)) { + + val bitmap = app.contentResolver.openInputStream(uri).use { inputStream -> + BitmapFactory.decodeStream(inputStream) + } + when(val result = imageCropper.crop(bmp = bitmap.asImageBitmap())) { CropResult.Cancelled -> {} is CropError -> _cropError.value = result is CropResult.Success -> { diff --git a/sample/src/main/java/com/mr0xf00/easycrop/ui/DemoContent.kt b/sample/src/main/java/com/mr0xf00/easycrop/ui/DemoContent.kt index a239a18..f3b4b50 100644 --- a/sample/src/main/java/com/mr0xf00/easycrop/ui/DemoContent.kt +++ b/sample/src/main/java/com/mr0xf00/easycrop/ui/DemoContent.kt @@ -17,11 +17,12 @@ fun DemoContent( loadingStatus: CropperLoading?, selectedImage: ImageBitmap?, onPick: () -> Unit, + onDrawingError: (Exception) -> Unit, modifier: Modifier = Modifier, ) { if (cropState != null) { EasyCropTheme(darkTheme = true) { - ImageCropperDialog(state = cropState) + ImageCropperDialog(state = cropState, onDrawingError = onDrawingError) } } if (cropState == null && loadingStatus != null) { diff --git a/sample/src/main/java/com/mr0xf00/easycrop/ui/SimpleDemo.kt b/sample/src/main/java/com/mr0xf00/easycrop/ui/SimpleDemo.kt index 2ea67b7..0a95bb2 100644 --- a/sample/src/main/java/com/mr0xf00/easycrop/ui/SimpleDemo.kt +++ b/sample/src/main/java/com/mr0xf00/easycrop/ui/SimpleDemo.kt @@ -28,6 +28,7 @@ fun SimpleDemo(modifier: Modifier = Modifier) { cropState = imageCropper.cropState, loadingStatus = imageCropper.loadingStatus, selectedImage = selectedImage, + onDrawingError = {}, onPick = { imagePicker.pick() }, modifier = modifier ) diff --git a/sample/src/main/java/com/mr0xf00/easycrop/ui/ViewModelDemo.kt b/sample/src/main/java/com/mr0xf00/easycrop/ui/ViewModelDemo.kt index 23a4675..0c3e8c9 100644 --- a/sample/src/main/java/com/mr0xf00/easycrop/ui/ViewModelDemo.kt +++ b/sample/src/main/java/com/mr0xf00/easycrop/ui/ViewModelDemo.kt @@ -7,12 +7,17 @@ import com.mr0xf00.easycrop.rememberImagePicker @Composable fun ViewModelDemo(viewModel: ImagesViewModel, modifier: Modifier = Modifier) { - val imagePicker = rememberImagePicker(onImage = { uri -> viewModel.setSelectedImage(uri) }) + val imagePicker = rememberImagePicker(onImage = { uri -> + viewModel.setSelectedImage(uri) + }) DemoContent( cropState = viewModel.imageCropper.cropState, loadingStatus = viewModel.imageCropper.loadingStatus, selectedImage = viewModel.selectedImage.collectAsState().value, onPick = { imagePicker.pick() }, + onDrawingError = { + + }, modifier = modifier ) viewModel.cropError.collectAsState().value?.let { error -> diff --git a/settings.gradle b/settings.gradle index c7bb7c8..15c1275 100644 --- a/settings.gradle +++ b/settings.gradle @@ -12,6 +12,7 @@ dependencyResolutionManagement { mavenCentral() } } -rootProject.name = "EasyCrop" +rootProject.name = "easy-crop" + include ':sample' include ':easycrop'