Simplge ImageGallery Picker

Overview

SimpleImagePicker

device-2021-11-27-185548

  1. add camera and files permissions to manifest file
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
  1. add Files Prioder in manifest file inside application tags
 <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="${applicationId}.ronnie_image_provider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/image_provider_path" />
</provider>
        
  1. create image_provider_path xml file
<paths>
    <external-cache-path
        name="image"
        path="/" />
</paths>
  1. create ImagePicker class
import android.Manifest
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.drawable.Drawable
import android.net.Uri
import android.widget.Toast
import androidx.activity.result.ActivityResult
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.FileProvider
import androidx.fragment.app.Fragment
import androidx.lifecycle.MutableLiveData
import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.request.target.CustomTarget
import com.bumptech.glide.request.transition.Transition
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import java.io.File

class ImagePicker {
    private var galleryLauncher: ActivityResultLauncher<Intent>? = null
    private var cameraLauncher: ActivityResultLauncher<Uri>? = null
    private var storagePermission: ActivityResultLauncher<String>? = null
    private var cameraPermission: ActivityResultLauncher<String>? = null
    private var activity: AppCompatActivity? = null
    private var fragment: Fragment? = null
    private var context: Context?
    val _bitmapLivedata = MutableLiveData<Bitmap>()
    private var takenImageUri: Uri?=null
    private var callback: ((imageResult: ImageResult<Uri>) -> Unit)? = null

    constructor(activity: AppCompatActivity) {
        this.activity = activity
        context = activity.applicationContext
        registerActivityForResults()
    }

    constructor(fragment: Fragment) {
        this.fragment = fragment
        context = fragment.context
        registerActivityForResults()
    }

    private fun registerActivityForResults() {
        //Camera permission
        cameraPermission = (activity?: fragment)?.registerForActivityResult(ActivityResultContracts.RequestPermission()) { granted ->
            when {
                granted -> {
                    launchCamera()
                }
                else -> callback?.invoke(ImageResult.Failure("Camera Permission denied"))

            }
        }

        //Storage permission
        storagePermission = (activity ?: fragment)?.registerForActivityResult(
            ActivityResultContracts.RequestPermission()
        ) { granted ->
            when {
                granted -> {
                    launchGallery()
                }

                else -> callback?.invoke(ImageResult.Failure("Storage Permission denied"))

            }
        }
        //Launch camera
        cameraLauncher =
            (activity ?: fragment)?.registerForActivityResult(
                ActivityResultContracts.TakePicture()
            ) { result ->
                if (result) {
                    callback?.invoke(ImageResult.Success(takenImageUri))
                } else {
                    callback?.invoke(ImageResult.Failure("Camera Launch Failed"))
                }
            }

        //launch gallery
        galleryLauncher = (activity ?: fragment)?.registerForActivityResult(
            ActivityResultContracts.StartActivityForResult()
        ) { result: ActivityResult ->
            if (result.resultCode == AppCompatActivity.RESULT_OK && result.data != null) {
                val uri = result.data?.data
                if (uri != null) {
                    callback?.invoke(ImageResult.Success(uri))
                } else {
                    callback?.invoke(ImageResult.Failure("Gallery Launch Failed"))
                }
            } else {
                callback?.invoke(ImageResult.Failure("Gallery Launch Failed"))
            }
        }
    }

    private fun launchCamera() {
        try {
            val takenImageFile =
                File(context?.externalCacheDir, "takenImage${(1..1000).random()}.jpg")
            takenImageUri = context?.let {
                FileProvider.getUriForFile(
                    it, context?.packageName.plus(".ronnie_image_provider"), takenImageFile
                )
            }
            cameraLauncher!!.launch(takenImageUri)
        } catch (exception: Exception) {
            callback?.invoke(ImageResult.Failure("Camera Launch Failed"))
        }
    }

    private fun launchGallery() {
        val intent = Intent()
        intent.type = "image/*"
        intent.action = Intent.ACTION_GET_CONTENT
        Intent.createChooser(intent, "Select Image")
        galleryLauncher?.launch(intent)
    }
    private fun pickFromStorage(callback: ((imageResult: ImageResult<Uri>) -> Unit)) {
        this.callback = callback
        if (ActivityCompat.shouldShowRequestPermissionRationale(
                (activity ?: fragment!!.requireActivity()),
                Manifest.permission.READ_EXTERNAL_STORAGE
            )
        ) {
            showWhyPermissionNeeded(Manifest.permission.READ_EXTERNAL_STORAGE, "Storage")
        } else {
            storagePermission?.launch(Manifest.permission.READ_EXTERNAL_STORAGE)
        }
    }

   private fun takeFromCamera(callback: ((imageResult: ImageResult<Uri>) -> Unit)) {
        this.callback = callback
        if (ActivityCompat.shouldShowRequestPermissionRationale(
                (activity ?: fragment!!.requireActivity()),
                Manifest.permission.CAMERA
            )
        ) {
            showWhyPermissionNeeded(Manifest.permission.CAMERA, "Camera")
        } else {
            cameraPermission?.launch(Manifest.permission.CAMERA)
        }
    }

    private fun showWhyPermissionNeeded(permission: String, name: String) {
        MaterialAlertDialogBuilder(activity ?: fragment!!.requireContext())
            .setMessage("Permission needed. $name permission is required")
            .setPositiveButton(
                "Okay"
            ) { _, _ ->
                if (permission == Manifest.permission.CAMERA) {
                    cameraPermission?.launch(permission)
                } else {
                    storagePermission?.launch(permission)
                }

            }.create().show()
    }
    fun takeFromCamera() {
        takeFromCamera { imageResult ->
            when (imageResult) {
                is ImageResult.Success -> {
                    val uri = imageResult.value
                    getLargeBitmap(uri)
                }
                is ImageResult.Failure -> {
                    val errorString = imageResult.errorString
                    Toast.makeText(context, errorString, Toast.LENGTH_LONG).show()
                }
            }

        }
    }
    private fun getLargeBitmap(uri: Uri?) {

        (activity ?: fragment)?.let {
            (if (activity != null)
                Glide.with(activity!!)
            else if (fragment != null)
                Glide.with(fragment!!)
            else null
                    )?.asBitmap()?.override(900, 900)?.load(uri)
                ?.diskCacheStrategy(DiskCacheStrategy.NONE)?.into(object : CustomTarget<Bitmap>() {
                    override fun onResourceReady(
                        resource: Bitmap,
                        transition: Transition<in Bitmap?>?
                    ) {
                        _bitmapLivedata.postValue(resource)
                    }

                    override fun onLoadCleared(placeholder: Drawable?) {}
                })
        }
    }
    fun pickFromStorage() {
        pickFromStorage { imageResult ->
            when (imageResult) {
                is ImageResult.Success -> {
                    val uri = imageResult.value
                    getLargeBitmap(uri)
                }
                is ImageResult.Failure -> {
                    val errorString = imageResult.errorString
                    Toast.makeText(context, errorString, Toast.LENGTH_LONG).show()
                }
            }

        }
    }
}
sealed class ImageResult <out T>{
    data class Success<out T>(val value: T?) : ImageResult<T>()
    data class Failure(val errorString: String): ImageResult<Nothing>()
}

now you can create new instance of ImagePicker class and pass fragment or activity or constractor , add observe to bitmapLiveData and call takeFromCamera or pickFromStorage


Optional

you can create your own dialog or bottom sheet fragment and add two buttons (Pick From camera or Gallery) ...

for example
import ImagePicker
import android.annotation.SuppressLint
import android.app.Dialog
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import com.google.android.material.bottomsheet.BottomSheetDialogFragment

class ChoosePickerButtonSheet() : BottomSheetDialogFragment(),
    View.OnClickListener {
    companion object {
        @SuppressLint("StaticFieldLeak")
        private var imagePicker: ImagePicker? = null
        fun getInstance(imagePicker: ImagePicker): ChoosePickerButtonSheet {
            this.imagePicker = imagePicker
            return ChoosePickerButtonSheet()
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_image_picker_dialog, container, false)
    }

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        return super.onCreateDialog(savedInstanceState)
    }


    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        dialog?.window?.setDimAmount(0.2f)

        setTransparentBackground()

        view.findViewById<TextView>(R.id.cancelTv).setOnClickListener(this)
        view.findViewById<TextView>(R.id.cameraTv).setOnClickListener(this)
        view.findViewById<TextView>(R.id.galleryTv).setOnClickListener(this)
    }


    override fun onClick(v: View?) {
        when (v?.id) {
            R.id.galleryTv -> imagePicker?.pickFromStorage()
            R.id.cameraTv -> imagePicker?.takeFromCamera()
        }
        dismiss()
    }

    fun BottomSheetDialogFragment.setTransparentBackground() {
        dialog?.apply {
            setOnShowListener {
                val bottomSheet = findViewById<View?>(R.id.design_bottom_sheet)
                bottomSheet?.setBackgroundResource(android.R.color.transparent)
            }
        }
    }
}

XML File

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:background="@android:color/transparent"
   android:orientation="vertical">

   <com.google.android.material.textview.MaterialTextView
       android:elevation="12dp"
       android:id="@+id/galleryTv"
       android:background="@drawable/shape_round_white"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:padding="12dp"
       android:layout_marginStart="12dp"
       android:layout_marginTop="8dp"
       android:layout_marginEnd="12dp"
       android:gravity="center"
       android:text="Gallery"
       android:textColor="@color/black" />


   <com.google.android.material.textview.MaterialTextView
       android:background="@drawable/shape_round_white"
       android:id="@+id/cameraTv"
       android:layout_width="match_parent"
       android:elevation="12dp"
       android:layout_height="wrap_content"
       android:padding="12dp"
       android:gravity="center"
       android:layout_marginStart="12dp"
       android:layout_marginTop="8dp"
       android:layout_marginEnd="12dp"
       android:text="Camera"
       android:textColor="@color/black" />


   <com.google.android.material.textview.MaterialTextView
       android:background="@drawable/shape_round_white"
       android:id="@+id/cancelTv"
       android:elevation="12dp"
       android:layout_width="match_parent"
       android:layout_marginBottom="20sp"
       android:layout_height="wrap_content"
       android:padding="12dp"
       android:layout_marginStart="12dp"
       android:layout_marginTop="16dp"
       android:layout_marginEnd="12dp"
       android:gravity="center"
       android:text="Cancel"
       android:textColor="@color/black" />
</LinearLayout>

drawable folder

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <corners android:radius="15dp" />
    <solid android:color="@color/white" />
</shape>

activity or fragment

 val imagePicker =  ImagePicker(this)
        imagePicker._bitmapLivedata.observe(this) {
            imageView.setImageBitmap(it)
        }
        val choosePickerButtonSheet = ChoosePickerButtonSheet.getInstance(imagePicker = imagePicker)
        imageView.setOnClickListener {
            choosePickerButtonSheet.show(supportFragmentManager, "tag")
        }
reference https://github.com/ronnieotieno/Ronnie-Image-Picker
You might also like...
A simple compose weight picker drawn with canvas.

CanvasWeightPicker A simple compose weight picker drawn with canvas. Features Drag scale to select weight Haptic feedback on weight selected Video of

Android Compose wheel picker library based on LazyColumn in vertical and LazyRow in horizontal.

About Android Compose wheel picker library based on LazyColumn in vertical and LazyRow in horizontal. Gradle Sample Default Item size Unfocused count

Nepali Date Picker library in Jetpack compose for android with Date conversion from BS to AD and vice-versa
Nepali Date Picker library in Jetpack compose for android with Date conversion from BS to AD and vice-versa

Nepali Date picker Converter - Re in Compose This is a re-work of Nepali Date Picker Converter in jetpack compose and kotlin. English Locale Nepali Lo

Alwan 🎨 is an Android Jetpack Compose color picker library.
Alwan 🎨 is an Android Jetpack Compose color picker library.

Alwan Alwan is an Android Jetpack Compose color picker library. Preview Recording.mp4 Download Gradle: dependencies { implementation 'com.raedapps:a

Pix is a Whatsapp image picker replica. with this, you can integrate an image picker just like WhatsApp.
Pix is a Whatsapp image picker replica. with this, you can integrate an image picker just like WhatsApp.

Pix (WhatsApp Style Image and Video Picker) Pix is a WhatsApp image picker replica. with this you can integrate a image picker just like WhatsApp. Upc

Android Country Picker is a Kotlin-first, flexible and powerful Android library that allows to integrate Country Picker with just a few lines.
Android Country Picker is a Kotlin-first, flexible and powerful Android library that allows to integrate Country Picker with just a few lines.

1. Add dependency dependencies { implementation 'com.hbb20:android-country-picker:X.Y.Z' } For latest version, 2. Decide your use-case

Facebook-Styled-Image-Picker - Facebook Styled Image Picker

Facebook-Styled-Image-Picker Facebook Styled Gallery Files picker. One or multip

Picker-kt - Media picker library powered by Jetpack Compose
Picker-kt - Media picker library powered by Jetpack Compose

ANDROID LIBRARY PickerKT A media picker library for Android apps powered by Jetp

Media Picker is an Android Libary that lets you to select multiple images or video
Media Picker is an Android Libary that lets you to select multiple images or video

Media Picker Please let me know if your application go to production via this link Media Picker is an Android Libary that lets you to select multiple

Image Picker for Android πŸ€–
Image Picker for Android πŸ€–

Android Image Picker No config yet highly configurable image picker for Android Screenshot Click to see how image picker looks… Download Add this to y

Material  (Gregorian - Hijri) Date & Time Picker
Material (Gregorian - Hijri) Date & Time Picker

Hijri Date Picker (UmAlQuraCalendar) This library offers a hijri (Islamic Calendar) Date Picker designed on Google's Material Design Principals For Pi

Instagram like Image Picker for Android
Instagram like Image Picker for Android

ImagePicker A simple Instagram like library to select images from the gallery and camera. Screenshot Usage For full example, please refer to the sampl

Photo picker library for android. Let's you pick photos directly from files, or navigate to camera or gallery.
Photo picker library for android. Let's you pick photos directly from files, or navigate to camera or gallery.

ChiliPhotoPicker Made with ❀️ by Chili Labs. Library made without DataBinding, RxJava and image loading libraries, to give you opportunity to use it w

A material Date Range Picker based on wdullaers MaterialDateTimePicker
A material Date Range Picker based on wdullaers MaterialDateTimePicker

Material Date and Time Picker with Range Selection Credits to the original amazing material date picker library by wdullaer - https://github.com/wdull

Android library for better Picker DialogFragments
Android library for better Picker DialogFragments

DialogFragments modeled after the AOSP Clock and Calendar apps to improve UX for picking time, date, numbers, and other things.

Android Rubber Picker Library
Android Rubber Picker Library

RubberPicker RubberPicker library contains the RubberSeekBar and RubberRangePicker, inspired by Cuberto's rubber-range-picker. Getting started Setting

Material  (Gregorian - Hijri) Date & Time Picker
Material (Gregorian - Hijri) Date & Time Picker

Hijri Date Picker (UmAlQuraCalendar) This library offers a hijri (Islamic Calendar) Date Picker designed on Google's Material Design Principals For Pi

🎨 A color picker for Android. Pick a color using color wheel and slider (HSV & alpha).
🎨 A color picker for Android. Pick a color using color wheel and slider (HSV & alpha).

ColorPicker English | δΈ­ζ–‡ A ColorPicker for Android. Pick a color using color wheel and slider (HSV & alpha). Gradle dependencies { implementation

Color picker library for Android
Color picker library for Android

andColorPicker β€” Color Picker library for Android πŸ₯‘ Handy, 🐍 flexible, and ⚑ lightning-fast Android color picker views and utilities. πŸ’Š Features Cl

Owner
I'm an android Developer, adore computer science and all new in this field, and I hope to learn more. I try to learn from everyone
null
[NO LONGER MAINTAINED] Android library for better Picker DialogFragments

/!\ This Project is no longer maintained /!\ DialogFragments modeled after the AOSP Clock and Calendar apps to improve UX for picking time, date, numb

Code-Troopers 2.7k Dec 29, 2022
A material Date Range Picker based on wdullaers MaterialDateTimePicker

Material Date and Time Picker with Range Selection Credits to the original amazing material date picker library by wdullaer - https://github.com/wdull

Supratim 1.3k Dec 14, 2022
Android time range picker

TimeRangePicker TimeRangePicker is a library which can be used to select a time range. WARNING Requires android-support-v4 Description This library pr

Titto Jose 422 Nov 10, 2022
[NO LONGER MAINTAINED] Android library for better Picker DialogFragments

/!\ This Project is no longer maintained /!\ DialogFragments modeled after the AOSP Clock and Calendar apps to improve UX for picking time, date, numb

Code-Troopers 2.7k Dec 29, 2022
A material Date Range Picker based on wdullaers MaterialDateTimePicker

Material Date and Time Picker with Range Selection Credits to the original amazing material date picker library by wdullaer - https://github.com/wdull

Supratim 1.3k Dec 14, 2022
A date time range picker for android written in Kotlin

DateTimeRangePicker A date time range picker for android Usage Firstly, grab latest release of the library via JitPack. And note that, it utilizes Jod

SkedGo 501 Dec 31, 2022
A customizable, easy-to-use, and functional circular time range picker library for Android

A customizable, easy-to-use, and functional circular time range picker library for Android. Use this library to mimic Apple's iOS or Samsung's bedtime picker.

Joery Droppers 251 Dec 30, 2022
Appleader707 1 Aug 9, 2022
Time-DatePicker - A Simple Time Date Picker With Kotlin

Time-DatePicker Time.DatePicker.mp4

Faysal Hossain 0 Jan 19, 2022
JetCountrypicker - Country code bottomsheet picker in Jetpack Compose

JetCountryPicker Country code bottomsheet picker in Jetpack Compose How to add i

Canopas Software 30 Nov 17, 2022