1- package com.smarttoolfactory.cropper.settings.frames.edit
2-
1+ import android.annotation.SuppressLint
2+ import android.graphics.Bitmap
3+ import android.graphics.ImageDecoder
4+ import android.os.Build
5+ import android.provider.MediaStore
6+ import androidx.activity.compose.rememberLauncherForActivityResult
37import androidx.compose.foundation.Image
48import androidx.compose.foundation.background
59import androidx.compose.foundation.border
@@ -19,16 +23,18 @@ import androidx.compose.ui.Alignment
1923import androidx.compose.ui.Modifier
2024import androidx.compose.ui.draw.drawWithCache
2125import androidx.compose.ui.draw.shadow
22- import androidx.compose.ui.graphics.Color
23- import androidx.compose.ui.graphics.Path
24- import androidx.compose.ui.graphics.drawOutline
26+ import androidx.compose.ui.graphics.*
2527import androidx.compose.ui.graphics.drawscope.translate
28+ import androidx.compose.ui.platform.LocalContext
2629import androidx.compose.ui.platform.LocalDensity
2730import androidx.compose.ui.text.font.FontWeight
2831import androidx.compose.ui.text.style.TextOverflow
2932import androidx.compose.ui.unit.dp
3033import androidx.compose.ui.unit.sp
34+ import com.google.modernstorage.photopicker.PhotoPicker
35+ import com.smarttoolfactory.composecropper.preferences.frames.edit.CropFrameEditDialog
3136import com.smarttoolfactory.cropper.model.*
37+ import com.smarttoolfactory.composecropper.preferences.frames.edit.CropShapeAddDialog
3238import com.smarttoolfactory.cropper.util.buildOutline
3339import com.smarttoolfactory.cropper.util.scaleAndTranslatePath
3440
@@ -49,9 +55,12 @@ fun CropFrameListDialog(
4955 mutableStateOf(updatedCropFrame.selectedIndex)
5056 }
5157
58+ val outlineType = cropFrame.outlineType
59+
5260 var showEditDialog by remember { mutableStateOf(false ) }
5361 var showAddDialog by remember { mutableStateOf(false ) }
5462
63+
5564 if (showEditDialog) {
5665 CropFrameEditDialog (
5766 aspectRatio = aspectRatio,
@@ -69,18 +78,45 @@ fun CropFrameListDialog(
6978 }
7079
7180 if (showAddDialog) {
72- CropFrameAddDialog (
73- aspectRatio = aspectRatio,
74- cropFrame = updatedCropFrame.copy(),
75- onConfirm = {
76- updatedCropFrame = it
77- selectedIndex = updatedCropFrame.selectedIndex
78- showAddDialog = false
79- },
80- onDismiss = {
81- showAddDialog = false
81+
82+ val outline = updatedCropFrame.cropOutlineContainer.selectedItem
83+ if (outline is CropShape ) {
84+ CropShapeAddDialog (
85+ aspectRatio = aspectRatio,
86+ cropFrame = updatedCropFrame.copy(),
87+ onConfirm = {
88+ updatedCropFrame = it
89+ selectedIndex = updatedCropFrame.selectedIndex
90+ showAddDialog = false
91+ },
92+ onDismiss = {
93+ showAddDialog = false
94+ }
95+ )
96+ } else if (outline is CropImageMask ) {
97+
98+ PickImageMask {
99+
100+ val id = updatedCropFrame.outlineCount
101+ val newOutline =
102+ ImageMaskOutline (id = updatedCropFrame.outlineCount, " ImageMask $id " , it)
103+
104+ val newOutlines: List <CropOutline > = cropFrame.outlines
105+ .toMutableList()
106+ .apply {
107+ add(newOutline)
108+ }
109+ .toList()
110+
111+ updatedCropFrame = cropFrame.copy(
112+ cropOutlineContainer = getOutlineContainer(
113+ outlineType = outlineType,
114+ index = newOutlines.size - 1 ,
115+ outlines = newOutlines
116+ )
117+ )
82118 }
83- )
119+ }
84120 }
85121
86122 AlertDialog (
@@ -91,6 +127,7 @@ fun CropFrameListDialog(
91127 .fillMaxWidth()
92128 .heightIn(min = 280 .dp),
93129 selectedIndex = selectedIndex,
130+ outlineType = updatedCropFrame.outlineType,
94131 outlines = updatedCropFrame.outlines,
95132 aspectRatio = aspectRatio,
96133 onItemClick = {
@@ -138,16 +175,18 @@ fun CropFrameListDialog(
138175 }
139176 },
140177 confirmButton = {
141- Button (
142- onClick = {
143- showEditDialog = true
178+ if (outlineType != OutlineType .ImageMask ) {
179+ Button (
180+ onClick = {
181+ showEditDialog = true
182+ }
183+ ) {
184+ Icon (
185+ imageVector = Icons .Default .Edit ,
186+ contentDescription = " Edit"
187+ )
188+ Text (" Edit" )
144189 }
145- ) {
146- Icon (
147- imageVector = Icons .Default .Edit ,
148- contentDescription = " Edit"
149- )
150- Text (" Edit" )
151190 }
152191 }
153192 )
@@ -157,6 +196,7 @@ fun CropFrameListDialog(
157196private fun CropOutlineGridList (
158197 modifier : Modifier = Modifier ,
159198 selectedIndex : Int ,
199+ outlineType : OutlineType ,
160200 outlines : List <CropOutline >,
161201 aspectRatio : AspectRatio ,
162202 onItemClick : (Int ) -> Unit ,
@@ -189,13 +229,15 @@ private fun CropOutlineGridList(
189229 }
190230 }
191231
192- item {
193- AddItemButton (
194- Modifier
195- .fillMaxWidth()
196- .aspectRatio(3 / 4f )
197- ) {
198- onAddItemClick()
232+ if (outlineType != OutlineType .Custom ) {
233+ item {
234+ AddItemButton (
235+ Modifier
236+ .fillMaxWidth()
237+ .aspectRatio(1f )
238+ ) {
239+ onAddItemClick()
240+ }
199241 }
200242 }
201243 }
@@ -358,3 +400,33 @@ private fun CropOutlineDisplay(
358400 }
359401 }
360402}
403+
404+ @SuppressLint(" UnsafeOptInUsageError" )
405+ @Composable
406+ private fun PickImageMask (
407+ onImageSelected : (ImageBitmap ) -> Unit
408+
409+ ) {
410+ val context = LocalContext .current
411+
412+ val photoPicker = rememberLauncherForActivityResult(PhotoPicker ()) { uris ->
413+ val uri = uris.firstOrNull() ? : return @rememberLauncherForActivityResult
414+
415+ val bitmap: Bitmap = if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .P ) {
416+ ImageDecoder .decodeBitmap(
417+ ImageDecoder .createSource(context.contentResolver, uri)
418+ ) { decoder, info, source ->
419+ decoder.allocator = ImageDecoder .ALLOCATOR_SOFTWARE
420+ decoder.isMutableRequired = true
421+ }
422+ } else {
423+ MediaStore .Images .Media .getBitmap(context.contentResolver, uri)
424+ }
425+
426+ onImageSelected(bitmap.asImageBitmap())
427+ }
428+
429+ LaunchedEffect (key1 = Unit ) {
430+ photoPicker.launch(PhotoPicker .Args (PhotoPicker .Type .IMAGES_ONLY , 1 ))
431+ }
432+ }
0 commit comments