Skip to content
This repository has been archived by the owner on Sep 13, 2024. It is now read-only.

Commit

Permalink
Add clear
Browse files Browse the repository at this point in the history
  • Loading branch information
acolombo11 committed Aug 9, 2020
1 parent 0bb0b17 commit c374669
Show file tree
Hide file tree
Showing 9 changed files with 131 additions and 108 deletions.
4 changes: 2 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@ dependencies {

implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"

implementation 'androidx.appcompat:appcompat:1.2.0'
implementation "androidx.fragment:fragment-ktx:1.3.0-alpha07"
implementation "androidx.fragment:fragment-ktx:$fragment_ktx_version"
implementation "androidx.constraintlayout:constraintlayout:2.0.0-rc1"
implementation 'com.google.android.material:material:1.2.0'
implementation 'androidx.appcompat:appcompat:1.2.0'

implementation 'com.github.bumptech.glide:glide:4.11.0'
}
6 changes: 3 additions & 3 deletions app/src/main/java/eu/acolombo/plukke/example/DemoActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ class DemoActivity : AppCompatActivity(R.layout.activity_demo) {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

// Choose between taking a photo or picking from gallery using Plukke's ActivityResultContracts.Choose
// Choose between taking a photo or picking from gallery using PlukkeResultContracts.Choose
buttonPicker.setOnClickListener {
pickImage { uri ->
viewModel.savePicker(uri) // Do your own thing here instead
}
}

// Taking a photo using Ktx's ActivityResultContracts.TakePicture without the need of a FileProvider
// Taking a photo using ActivityResultContracts.TakePicture without the need of a FileProvider
buttonCamera.setOnClickListener {
takePicture { uri ->
viewModel.saveCamera(uri) // Do your own thing here instead
Expand All @@ -43,7 +43,7 @@ class DemoActivity : AppCompatActivity(R.layout.activity_demo) {
private fun setupDemo() {
// Using a crude implementation of ViewModel just to retain state on configuration change
// The resulting uri from the pickers gets saved in the vm and observed below
// On change the uri get loaded in the target image using Glide
// On change the uri gets loaded in the target image using Glide
viewModel.pickerResult.observe(this, Observer { uri ->
imagePicker.load(uri)
imagePicker.alpha = 1f
Expand Down
5 changes: 1 addition & 4 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
ext.kotlin_version = '1.3.72'
ext.fragment_ktx_version = '1.3.0-alpha07'
repositories {
google()
jcenter()
Expand All @@ -10,8 +9,6 @@ buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:4.0.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}

Expand Down
2 changes: 1 addition & 1 deletion plukke/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,5 @@ android {
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation "androidx.fragment:fragment-ktx:1.3.0-alpha07"
implementation "androidx.fragment:fragment-ktx:$fragment_ktx_version"
}
24 changes: 0 additions & 24 deletions plukke/src/main/java/eu/acolombo/plukke/ExternalContent.kt

This file was deleted.

66 changes: 0 additions & 66 deletions plukke/src/main/java/eu/acolombo/plukke/ImagePicker.kt

This file was deleted.

85 changes: 85 additions & 0 deletions plukke/src/main/java/eu/acolombo/plukke/Plukke.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package eu.acolombo.plukke

import android.Manifest.permission.WRITE_EXTERNAL_STORAGE
import android.app.Activity
import android.content.ContentResolver
import android.content.ContentValues
import android.net.Uri
import android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI
import androidx.activity.ComponentActivity
import androidx.activity.result.contract.ActivityResultContracts.TakePicture
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent
import eu.acolombo.plukke.PlukkeActivityResultContracts.Choose
import java.io.Closeable

class Plukke(
private val componentActivity: ComponentActivity,
clearOnDestroy: Boolean = false
) : LifecycleObserver, Closeable {

private class ExternalContent(private val resolver: ContentResolver) : Closeable {

var uri = resolver.insert(EXTERNAL_CONTENT_URI, ContentValues())

override fun close() {
uri?.let { resolver.delete(it, null, null) }
}

fun clear(): Nothing? = close().let { return null }

}

private val exc = ExternalContent(componentActivity.contentResolver)

val uri = exc.uri

fun pickImage(onResult: (Uri) -> Unit) = componentActivity.doWithPermission {
val photo = uri?.let { PlukkeActivityResultContracts.TakePhoto(it) }
val pick = PlukkeActivityResultContracts.PickImage()

componentActivity.registerForActivityResult(Choose()) { result ->
if (result.resultCode == Activity.RESULT_OK) onResult(
photo?.uri
?: exc.clear()
?: result?.data?.data
?: return@registerForActivityResult
) else exc.close()
}.launch(listOfNotNull(photo, pick))
}

fun takePicture(onResult: (Uri) -> Unit) = componentActivity.doWithPermission {
uri?.let { uri ->
registerForActivityResult(TakePicture()) { ok ->
if (ok) onResult(uri) else exc.close()
}.launch(uri)
}
}

var autoClear: Boolean = false
set(value) {
field = value
componentActivity.lifecycle.removeObserver(this)
if (value) componentActivity.lifecycle.addObserver(this)
}

@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
override fun close() = exc.close()

init {
autoClear = clearOnDestroy
}

private fun ComponentActivity.doWithPermission(action: ComponentActivity.() -> Unit) {
// Some devices don't need WRITE_EXTERNAL_STORAGE permission to be granted, so we'll just try to do what we want
// If we can't (catch) we do it the proper way, requesting permission if needed
// The try & catch is here to improve first time experience on some devices
try {
action()
} catch (e: SecurityException) {
doWithPermission(WRITE_EXTERNAL_STORAGE, action)
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI
import androidx.activity.result.ActivityResult
import androidx.activity.result.contract.ActivityResultContract

object ActivityResultContracts {
object PlukkeActivityResultContracts {

class Choose : ActivityResultContract<List<ActivityResultContract<*, *>>, ActivityResult>() {

Expand All @@ -28,18 +28,16 @@ object ActivityResultContracts {

}

// Same as ActivityResultContracts.TakePicture but input and output are fields
class TakePhoto(private val input: Uri) : ActivityResultContract<Unit, Uri?>() {

var output: Uri? = null
// Same as ActivityResultContracts.TakePicture but the input uri is passed to the constructor
class TakePhoto(val uri: Uri) : ActivityResultContract<Unit, Uri?>() {

override fun createIntent(
context: Context,
input: Unit?
) = Intent(MediaStore.ACTION_IMAGE_CAPTURE).putExtra(MediaStore.EXTRA_OUTPUT, this.input)
) = Intent(MediaStore.ACTION_IMAGE_CAPTURE).putExtra(MediaStore.EXTRA_OUTPUT, uri)

override fun parseResult(resultCode: Int, intent: Intent?): Uri? =
input.takeIf { resultCode == RESULT_OK }.also { output = it }
uri.takeIf { resultCode == RESULT_OK }

}

Expand All @@ -50,7 +48,8 @@ object ActivityResultContracts {
input: Unit?
) = Intent(Intent.ACTION_PICK, EXTERNAL_CONTENT_URI)

override fun parseResult(resultCode: Int, intent: Intent?) = intent?.data
override fun parseResult(resultCode: Int, intent: Intent?) : Uri? =
intent?.data

}

Expand Down
32 changes: 32 additions & 0 deletions plukke/src/main/java/eu/acolombo/plukke/PlukkeExt.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package eu.acolombo.plukke

import android.content.pm.PackageManager.PERMISSION_GRANTED
import android.net.Uri
import androidx.activity.ComponentActivity
import androidx.activity.result.contract.ActivityResultContracts.RequestPermission
import androidx.core.content.ContextCompat.checkSelfPermission
import androidx.fragment.app.Fragment

fun ComponentActivity.pickImage(onPick: (Uri) -> Unit) = Plukke(this).also { it.pickImage(onPick) }

fun ComponentActivity.takePicture(onPick: (Uri) -> Unit) = Plukke(this).also { it.takePicture(onPick) }

fun Fragment.pickImage(onPick: (Uri) -> Unit) = activity?.pickImage(onPick)

fun Fragment.takePicture(onTake: (Uri) -> Unit) = activity?.takePicture(onTake)

fun ComponentActivity.doWithPermission(
permission: String,
action: ComponentActivity.() -> Unit
) = if (checkSelfPermission(this, permission) != PERMISSION_GRANTED) {
registerForActivityResult(RequestPermission()) {
if (it) action()
}.launch(permission)
} else {
action()
}

fun Fragment.doWithPermission(
permission: String,
action: ComponentActivity.() -> Unit
) = activity?.doWithPermission(permission, action)

0 comments on commit c374669

Please sign in to comment.