diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml new file mode 100644 index 0000000..b268ef3 --- /dev/null +++ b/.idea/deploymentTargetSelector.xml @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/migrations.xml b/.idea/migrations.xml new file mode 100644 index 0000000..f8051a6 --- /dev/null +++ b/.idea/migrations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..16660f1 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/ssimagepicker/app/PickerOptions.kt b/app/src/main/java/com/ssimagepicker/app/PickerOptions.kt index 542ca2c..81d1cd6 100644 --- a/app/src/main/java/com/ssimagepicker/app/PickerOptions.kt +++ b/app/src/main/java/com/ssimagepicker/app/PickerOptions.kt @@ -23,6 +23,7 @@ data class PickerOptions( val openCropOptions: Boolean, val openSystemPicker: Boolean, val compressImage: Boolean, + val freeSizeCrop: Boolean, var aspectRatio: AspectRatio? ) : Parcelable { companion object { @@ -40,6 +41,7 @@ data class PickerOptions( openCropOptions = false, openSystemPicker = false, compressImage = false, + freeSizeCrop = false, aspectRatio = null ) } diff --git a/app/src/main/java/com/ssimagepicker/app/ui/DemoFragment.kt b/app/src/main/java/com/ssimagepicker/app/ui/DemoFragment.kt index 23eda90..e9fbde9 100644 --- a/app/src/main/java/com/ssimagepicker/app/ui/DemoFragment.kt +++ b/app/src/main/java/com/ssimagepicker/app/ui/DemoFragment.kt @@ -118,8 +118,7 @@ class DemoFragment : Fragment(), View.OnClickListener, private fun openImagePicker() { imagePicker .title("My Picker") - .multipleSelection(pickerOptions.allowMultipleSelection, pickerOptions.maxPickCount) - .showCountInToolBar(pickerOptions.showCountInToolBar) + .showCountInToolBar(pickerOptions.showCountInToolBar) .showFolder(pickerOptions.showFolders) .cameraIcon(pickerOptions.showCameraIconInGallery) .doneIcon(pickerOptions.isDoneIcon) diff --git a/app/src/main/java/com/ssimagepicker/app/ui/LaunchActivity.kt b/app/src/main/java/com/ssimagepicker/app/ui/LaunchActivity.kt index 6e1a380..1520644 100644 --- a/app/src/main/java/com/ssimagepicker/app/ui/LaunchActivity.kt +++ b/app/src/main/java/com/ssimagepicker/app/ui/LaunchActivity.kt @@ -3,6 +3,7 @@ package com.ssimagepicker.app.ui import android.content.Intent import android.os.Bundle import android.view.View +import androidx.activity.enableEdgeToEdge import androidx.appcompat.app.AppCompatActivity import androidx.databinding.DataBindingUtil import com.ssimagepicker.app.R diff --git a/app/src/main/java/com/ssimagepicker/app/ui/MainActivity.kt b/app/src/main/java/com/ssimagepicker/app/ui/MainActivity.kt index b0dfae2..f0d81b3 100644 --- a/app/src/main/java/com/ssimagepicker/app/ui/MainActivity.kt +++ b/app/src/main/java/com/ssimagepicker/app/ui/MainActivity.kt @@ -61,6 +61,7 @@ class MainActivity : AppCompatActivity(), View.OnClickListener, openPickerOptions() } R.id.open_picker_button -> { + pickerOptions = pickerOptions.copy(compressImage = true) openImagePicker() } R.id.open_sheet_button -> { @@ -120,8 +121,8 @@ class MainActivity : AppCompatActivity(), View.OnClickListener, .showFolder(pickerOptions.showFolders) .cameraIcon(pickerOptions.showCameraIconInGallery) .doneIcon(pickerOptions.isDoneIcon) - .allowCropping(pickerOptions.openCropOptions) - .compressImage(pickerOptions.compressImage) + .compressImage(true) + .allowCropping(false) .maxImageSize(pickerOptions.maxPickSizeMB) .extension(pickerOptions.pickExtension) .aspectRatio(pickerOptions.aspectRatio) diff --git a/app/src/main/java/com/ssimagepicker/app/ui/PickerOptionsBottomSheet.kt b/app/src/main/java/com/ssimagepicker/app/ui/PickerOptionsBottomSheet.kt index ed1867b..d5446d2 100644 --- a/app/src/main/java/com/ssimagepicker/app/ui/PickerOptionsBottomSheet.kt +++ b/app/src/main/java/com/ssimagepicker/app/ui/PickerOptionsBottomSheet.kt @@ -151,6 +151,7 @@ class PickerOptionsBottomSheet : BottomSheetDialogFragment(), View.OnClickListen openCropOptions = binding.openCropSwitch.isChecked, openSystemPicker = binding.systemPickerSwitch.isChecked, compressImage = binding.compressImageSwitch.isChecked, + freeSizeCrop = false, aspectRatio = null ) dismiss() diff --git a/app/src/main/res/layout/activity_launch.xml b/app/src/main/res/layout/activity_launch.xml index 1353b51..07f62f3 100644 --- a/app/src/main/res/layout/activity_launch.xml +++ b/app/src/main/res/layout/activity_launch.xml @@ -25,7 +25,7 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/xml/file_path.xml b/app/src/main/res/xml/file_path.xml deleted file mode 100644 index c3d31c8..0000000 --- a/app/src/main/res/xml/file_path.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/imagepickerlibrary/src/main/AndroidManifest.xml b/imagepickerlibrary/src/main/AndroidManifest.xml index 8f4f7b9..e9d0397 100644 --- a/imagepickerlibrary/src/main/AndroidManifest.xml +++ b/imagepickerlibrary/src/main/AndroidManifest.xml @@ -20,7 +20,7 @@ + android:theme="@style/CustomUCrop" /> diff --git a/imagepickerlibrary/src/main/java/com/app/imagepickerlibrary/Extensions.kt b/imagepickerlibrary/src/main/java/com/app/imagepickerlibrary/Extensions.kt index 22b830c..2538daf 100644 --- a/imagepickerlibrary/src/main/java/com/app/imagepickerlibrary/Extensions.kt +++ b/imagepickerlibrary/src/main/java/com/app/imagepickerlibrary/Extensions.kt @@ -266,6 +266,10 @@ internal suspend fun Context.getImagesList( } } + + + + /** * Extension function to convert Megabyte to Byte */ diff --git a/imagepickerlibrary/src/main/java/com/app/imagepickerlibrary/ImagePicker.kt b/imagepickerlibrary/src/main/java/com/app/imagepickerlibrary/ImagePicker.kt index 2eed0f8..1a68096 100644 --- a/imagepickerlibrary/src/main/java/com/app/imagepickerlibrary/ImagePicker.kt +++ b/imagepickerlibrary/src/main/java/com/app/imagepickerlibrary/ImagePicker.kt @@ -145,6 +145,15 @@ class ImagePicker private constructor( return this } + /** + * Whether to free size crop option or not. + * The cropping option are only available if the single selection is set or the picture is picked via camera. + */ + fun allowFreeSizeCropping(enable: Boolean): ImagePicker { + pickerConfigManager.getPickerConfig().freeStyleCrop = enable + return this + } + /** * Whether to open new photo picker for android 11+ or not. * If the system picker is set to open the all other options except multi selection, max count and pick extension are ignored. diff --git a/imagepickerlibrary/src/main/java/com/app/imagepickerlibrary/model/DataModels.kt b/imagepickerlibrary/src/main/java/com/app/imagepickerlibrary/model/DataModels.kt index 0e7b11d..8590704 100644 --- a/imagepickerlibrary/src/main/java/com/app/imagepickerlibrary/model/DataModels.kt +++ b/imagepickerlibrary/src/main/java/com/app/imagepickerlibrary/model/DataModels.kt @@ -27,6 +27,7 @@ internal data class PickerConfig( var openSystemPicker: Boolean = false, var compressImage: Boolean = false, var compressQuality: Int = 75, + var freeStyleCrop: Boolean = false, var aspectRatio: AspectRatio? = null ) : Parcelable { diff --git a/imagepickerlibrary/src/main/java/com/app/imagepickerlibrary/ui/activity/ImagePickerActivity.kt b/imagepickerlibrary/src/main/java/com/app/imagepickerlibrary/ui/activity/ImagePickerActivity.kt index c690f92..0e4d69b 100644 --- a/imagepickerlibrary/src/main/java/com/app/imagepickerlibrary/ui/activity/ImagePickerActivity.kt +++ b/imagepickerlibrary/src/main/java/com/app/imagepickerlibrary/ui/activity/ImagePickerActivity.kt @@ -10,6 +10,7 @@ import android.util.Log import android.view.View import androidx.activity.OnBackPressedCallback import androidx.activity.result.contract.ActivityResultContracts +import androidx.activity.result.contract.ActivityResultContracts.PickVisualMedia import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity import androidx.core.content.ContextCompat @@ -40,7 +41,6 @@ import com.app.imagepickerlibrary.registerActivityResult import com.app.imagepickerlibrary.replaceFragment import com.app.imagepickerlibrary.ui.fragment.FolderFragment import com.app.imagepickerlibrary.ui.fragment.ImageFragment -import com.app.imagepickerlibrary.util.isAtLeast13 import com.app.imagepickerlibrary.viewmodel.ImagePickerViewModel import com.yalantis.ucrop.UCrop import kotlinx.coroutines.launch @@ -209,6 +209,18 @@ class ImagePickerActivity : AppCompatActivity(), View.OnClickListener { ) == PackageManager.PERMISSION_GRANTED } + val pickMedia = registerForActivityResult(PickVisualMedia()) { uri -> + // Callback is invoked after the user selects a media item or closes the + // photo picker. + if (uri != null) { + checkForCropping(uri) + viewModel.fetchImagesFromMediaStore() + Log.d("PhotoPicker", "Selected URI: $uri") + } else { + Log.d("PhotoPicker", "No media selected") + } + } + private fun askPermission(vararg permission: String) { permissionResult.launch(arrayOf(*permission)) } @@ -274,11 +286,15 @@ class ImagePickerActivity : AppCompatActivity(), View.OnClickListener { } return UCrop.Options().apply { setFreeStyleCropEnabled(pickerConfig.openCropOptions) - setHideBottomControls(!pickerConfig.openCropOptions) + setFreeStyleCropEnabled(pickerConfig.freeStyleCrop) + setHideBottomControls(true) setToolbarColor(getColorAttribute(R.attr.ssUCropToolbarColor)) setStatusBarColor(getColorAttribute(R.attr.ssUCropStatusBarColor)) setToolbarWidgetColor(getColorAttribute(R.attr.ssUCropToolbarWidgetColor)) setActiveControlsWidgetColor(getColorAttribute(R.attr.ssUCropActiveControlWidgetColor)) + if (pickerConfig.freeStyleCrop.not()) { + withAspectRatio(1f, 1f) + } if (pickerConfig.compressImage) { setCompressionQuality(pickerConfig.compressQuality) } diff --git a/imagepickerlibrary/src/main/java/com/app/imagepickerlibrary/util/Util.kt b/imagepickerlibrary/src/main/java/com/app/imagepickerlibrary/util/Util.kt index 5a7c43a..7aa867f 100644 --- a/imagepickerlibrary/src/main/java/com/app/imagepickerlibrary/util/Util.kt +++ b/imagepickerlibrary/src/main/java/com/app/imagepickerlibrary/util/Util.kt @@ -28,6 +28,11 @@ internal fun isAtLeast13(): Boolean { return Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU } +@ChecksSdkIntAtLeast(api = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) +internal fun isAtLeast14(): Boolean { + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE +} + /** * Utility function to check if system picker is available or not on Android 11+. * The function is provided by google to check whether the photo picker is available or not diff --git a/imagepickerlibrary/src/main/java/com/app/imagepickerlibrary/viewmodel/ImagePickerViewModel.kt b/imagepickerlibrary/src/main/java/com/app/imagepickerlibrary/viewmodel/ImagePickerViewModel.kt index 840c363..da14079 100644 --- a/imagepickerlibrary/src/main/java/com/app/imagepickerlibrary/viewmodel/ImagePickerViewModel.kt +++ b/imagepickerlibrary/src/main/java/com/app/imagepickerlibrary/viewmodel/ImagePickerViewModel.kt @@ -1,6 +1,7 @@ package com.app.imagepickerlibrary.viewmodel import android.app.Application +import android.net.Uri import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.viewModelScope import com.app.imagepickerlibrary.getFileUri @@ -11,6 +12,7 @@ import com.app.imagepickerlibrary.model.Image import com.app.imagepickerlibrary.model.PickerConfig import com.app.imagepickerlibrary.model.Result import com.app.imagepickerlibrary.util.compress +import com.app.imagepickerlibrary.util.isAtLeast14 import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow @@ -57,10 +59,15 @@ internal class ImagePickerViewModel(application: Application) : AndroidViewModel } private suspend fun fetchImageList(): List { - val config = pickerConfig.value - val (selection, selectionArgs) = config.generateSelectionArguments() val context = (getApplication() as Application).applicationContext - return context.getImagesList(selection, selectionArgs) + if (isAtLeast14()) { + return context.getImagesList(null, null) + } else { + val config = pickerConfig.value + val (selection, selectionArgs) = config.generateSelectionArguments() + return context.getImagesList(selection, selectionArgs) + } + } fun getFoldersFromImages(images: List) { diff --git a/imagepickerlibrary/src/main/res/values-v35/themes.xml b/imagepickerlibrary/src/main/res/values-v35/themes.xml new file mode 100644 index 0000000..8cc8000 --- /dev/null +++ b/imagepickerlibrary/src/main/res/values-v35/themes.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/imagepickerlibrary/src/main/res/values/themes.xml b/imagepickerlibrary/src/main/res/values/themes.xml index 3d3fffc..6e43937 100644 --- a/imagepickerlibrary/src/main/res/values/themes.xml +++ b/imagepickerlibrary/src/main/res/values/themes.xml @@ -104,4 +104,8 @@ center @dimen/_14sdp + + \ No newline at end of file