Giter Site home page Giter Site logo

hi-manshu / pluck Goto Github PK

View Code? Open in Web Editor NEW
369.0 4.0 23.0 6.2 MB

Pluck, a library that helps you to pick image via Gallery/Camera built using Compose

Home Page: https://www.himanshoe.com

License: Apache License 2.0

Kotlin 100.00%
kotlin kotlin-android kotlin-library sdk sdk-android image-picker image-picker-android image-picker-library compose jetpack-compose

pluck's Introduction

Pluck - The image-picker library for Compose

Pluck

This is an image-picker for your jetpack compose project. You can select from Gallery/Camera. This uses Material you and will be getting support for it in future as well.

Made with ❤️ for Android Developers by Himanshu

Maven Central Github Followers Twitter Follow

Implementation

Step: 01

Add the specific permission in AndroidManifest.xml file

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

<uses-permission android:name="android.permission.CAMERA" />

Step: 02

In build.gradle of app module, include the following dependency

dependencies {
  implementation("com.himanshoe:pluck:1.0.0-RC2")
}

Usage

01

Now, to start using Pluck, use the composable Pluck like,

Pluck(onPhotoSelected = {
    // List of PluckImage when selecting from Gallery/Camera. When checking with Camera
    // It returns only one item in list
})

02

Now, if you want Pluck to handle the Permission for you as well. Use it like,

Permission(
    permissions = listOf(
        Manifest.permission.CAMERA,
        Manifest.permission.READ_EXTERNAL_STORAGE
    ),
    goToAppSettings = {
        // Go to App Settings
    }
) {
    Pluck(onPhotoSelected = {
        // List of PluckImage when selecting from Gallery/Camera. When checking with Camera
        // It returns only one item in list
    })
}

03

If you want to configure do you want to select single image or multiple image from gallery you need to edit the PluckConfiguration like,

    Pluck(
        pluckConfiguration = PluckConfiguration(multipleImagesAllowed = true),
        onPhotoSelected = { }
    )

Drop a ⭐ to keep me motivated to keep working on Open-Source. Updates coming Soon!

pluck's People

Contributors

hi-manshu avatar renovate[bot] avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

pluck's Issues

Empty image file.

Describe the bug
An empty image file will be saved if user ivokes the camera and doesn't take any photo or delete the image in the preview screen.
To Reproduce
Steps to reproduce the behavior:
Scenario1

  1. Invoke the camera
  2. Do nothing and quit.
  3. An empty file appears in the gallery.
    Scenario2
  4. Invoke the camera
  5. Take a photo and delete in the preview screen.
  6. An empty file appears in the gallery.

Expected behavior
The empty file should be deleted.

Desktop (please complete the following information):

  • Android 13

Smartphone (please complete the following information):

  • Device: oneplus 9
  • OS: ANdroid 13.1

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Rate-Limited

These updates are currently rate-limited. Click on a checkbox below to force their creation now.

  • Update gradle/gradle-build-action action to v3

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Detected dependencies

github-actions
.github/workflows/pull-request.yml
  • actions/checkout v2
  • actions/setup-java v1
  • gradle/gradle-build-action v2
gradle
buildSrc/src/main/kotlin/Dependencies.kt
buildSrc/src/main/kotlin/ModuleExtension.kt
buildSrc/src/main/kotlin/Versions.kt
  • composeOptions 1.1.1
gradle.properties
settings.gradle
build.gradle.kts
app/build.gradle.kts
  • com.himanshoe:pluck 1.0.0-RC2
buildSrc/build.gradle.kts
  • org.jetbrains.kotlin.jvm 1.6.10
pluck/gradle.properties
pluck/build.gradle.kts
  • io.coil-kt:coil-compose 1.4.0
  • androidx.paging:paging-common-ktx 3.1.0
gradle-wrapper
gradle/wrapper/gradle-wrapper.properties
  • gradle 7.2

  • Check this box to trigger a request for Renovate to run again on this repository

java.lang.NullPointerException' on folderName.toString()

Describe the bug
NullPointerException -> force close when folderName is null, its happen when image is on the root folder, just like this log

Library version
1.0.0-RC1

Log from library

D/imagesPlu: id : 17264, contentUri: content://media/external/images/media/17264, diplayName: Screenshot_20220315-151458.png, folder: Screenshots
D/imagesPlu: id : 17263, contentUri: content://media/external/images/media/17263, diplayName: Screenshot_20220315-151314.png, folder: Screenshots
D/imagesPlu: id : 17262, contentUri: content://media/external/images/media/17262, diplayName: ktp2.jpg, folder: null

Error log

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.imagepickerapp, PID: 3931
    java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String java.lang.String.toString()' on a null object reference
        at com.himanshoe.pluck.util.MediaLoaderKt.fetchPagePicture(MediaLoader.kt:97)
        at com.himanshoe.pluck.data.PluckRepositoryImpl$getPicturePagingSource$1.invoke(PluckRepository.kt:50)
        at com.himanshoe.pluck.data.PluckRepositoryImpl$getPicturePagingSource$1.invoke(PluckRepository.kt:50)
        at com.himanshoe.pluck.data.PluckDataSource.load(PluckDataSource.kt:40)
        at androidx.paging.PageFetcherSnapshot.doInitialLoad(PageFetcherSnapshot.kt:283)
        at androidx.paging.PageFetcherSnapshot.access$doInitialLoad(PageFetcherSnapshot.kt:54)
        at androidx.paging.PageFetcherSnapshot$pageEventFlow$1.invokeSuspend(PageFetcherSnapshot.kt:163)
        at androidx.paging.PageFetcherSnapshot$pageEventFlow$1.invoke(Unknown Source:8)
        at androidx.paging.PageFetcherSnapshot$pageEventFlow$1.invoke(Unknown Source:4)
        at androidx.paging.CancelableChannelFlowKt$cancelableChannelFlow$1.invokeSuspend(CancelableChannelFlow.kt:30)
        at androidx.paging.CancelableChannelFlowKt$cancelableChannelFlow$1.invoke(Unknown Source:8)
        at androidx.paging.CancelableChannelFlowKt$cancelableChannelFlow$1.invoke(Unknown Source:4)
        at androidx.paging.SimpleChannelFlowKt$simpleChannelFlow$1$1$producer$1$1.invokeSuspend(SimpleChannelFlow.kt:57)
        at androidx.paging.SimpleChannelFlowKt$simpleChannelFlow$1$1$producer$1$1.invoke(Unknown Source:8)
        at androidx.paging.SimpleChannelFlowKt$simpleChannelFlow$1$1$producer$1$1.invoke(Unknown Source:4)
        at kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturn(Undispatched.kt:89)
        at kotlinx.coroutines.CoroutineScopeKt.coroutineScope(CoroutineScope.kt:264)
        at androidx.paging.SimpleChannelFlowKt$simpleChannelFlow$1$1$producer$1.invokeSuspend(SimpleChannelFlow.kt:52)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
        at kotlinx.coroutines.EventLoop.processUnconfinedEvent(EventLoop.common.kt:69)
        at kotlinx.coroutines.internal.DispatchedContinuationKt.resumeCancellableWith(DispatchedContinuation.kt:375)
        at kotlinx.coroutines.internal.DispatchedContinuationKt.resumeCancellableWith$default(DispatchedContinuation.kt:278)
        at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable(Cancellable.kt:39)
        at kotlinx.coroutines.LazyStandaloneCoroutine.onStart(Builders.common.kt:204)
        at kotlinx.coroutines.JobSupport.startInternal(JobSupport.kt:401)
        at kotlinx.coroutines.JobSupport.start(JobSupport.kt:380)
        at androidx.paging.CachedPageEventFlow$sharedForDownstream$1.invokeSuspend(CachedPageEventFlow.kt:66)
        at androidx.paging.CachedPageEventFlow$sharedForDownstream$1.invoke(Unknown Source:8)
        at androidx.paging.CachedPageEventFlow$sharedForDownstream$1.invoke(Unknown Source:4)
        at kotlinx.coroutines.flow.SubscribedFlowCollector.onSubscription(Share.kt:410)
        at kotlinx.coroutines.flow.SharedFlowImpl.collect(SharedFlow.kt:341)
        at kotlinx.coroutines.flow.SubscribedSharedFlow.collect(Share.kt:400)
        at kotlinx.coroutines.flow.FlowKt__LimitKt$takeWhile$$inlined$unsafeFlow$1.collect(SafeCollector.common.kt:124)
        at androidx.paging.CachedPageEventFlow$downstreamFlow$1.invokeSuspend(CachedPageEventFlow.kt:247)
        at androidx.paging.CachedPageEventFlow$downstreamFlow$1.invoke(Unknown Source:8)
        at androidx.paging.CachedPageEventFlow$downstreamFlow$1.invoke(Unknown Source:4)
        at kotlinx.coroutines.flow.SafeFlow.collectSafely(Builders.kt:61)
        at kotlinx.coroutines.flow.AbstractFlow.collect(Flow.kt:212)
        at androidx.paging.PagingDataDiffer$collectFrom$2.invokeSuspend(PagingDataDiffer.kt:467)
        at androidx.paging.PagingDataDiffer$collectFrom$2.invoke(Unknown Source:8)
        at androidx.paging.PagingDataDiffer$collectFrom$2.invoke(Unknown Source:2)
        at androidx.paging.SingleRunner$runInIsolation$2.invokeSuspend(SingleRunner.kt:59)
E/AndroidRuntime:     at androidx.paging.SingleRunner$runInIsolation$2.invoke(Unknown Source:8)
        at androidx.paging.SingleRunner$runInIsolation$2.invoke(Unknown Source:4)
        at kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturn(Undispatched.kt:89)
        at kotlinx.coroutines.CoroutineScopeKt.coroutineScope(CoroutineScope.kt:264)
        at androidx.paging.SingleRunner.runInIsolation(SingleRunner.kt:49)
        at androidx.paging.SingleRunner.runInIsolation$default(SingleRunner.kt:44)
        at androidx.paging.PagingDataDiffer.collectFrom(PagingDataDiffer.kt:140)
        at androidx.paging.compose.LazyPagingItems$collectPagingData$2.invokeSuspend(LazyPagingItems.kt:192)
        at androidx.paging.compose.LazyPagingItems$collectPagingData$2.invoke(Unknown Source:8)
        at androidx.paging.compose.LazyPagingItems$collectPagingData$2.invoke(Unknown Source:4)
        at kotlinx.coroutines.flow.FlowKt__MergeKt$mapLatest$1.invokeSuspend(Merge.kt:217)
        at kotlinx.coroutines.flow.FlowKt__MergeKt$mapLatest$1.invoke(Unknown Source:13)
        at kotlinx.coroutines.flow.FlowKt__MergeKt$mapLatest$1.invoke(Unknown Source:4)
        at kotlinx.coroutines.flow.internal.ChannelFlowTransformLatest$flowCollect$3$1$2.invokeSuspend(Merge.kt:34)
        at kotlinx.coroutines.flow.internal.ChannelFlowTransformLatest$flowCollect$3$1$2.invoke(Unknown Source:8)
        at kotlinx.coroutines.flow.internal.ChannelFlowTransformLatest$flowCollect$3$1$2.invoke(Unknown Source:4)
        at kotlinx.coroutines.intrinsics.UndispatchedKt.startCoroutineUndispatched(Undispatched.kt:55)
        at kotlinx.coroutines.CoroutineStart.invoke(CoroutineStart.kt:112)
        at kotlinx.coroutines.AbstractCoroutine.start(AbstractCoroutine.kt:126)
        at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch(Builders.common.kt:56)
        at kotlinx.coroutines.BuildersKt.launch(Unknown Source:1)
        at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch$default(Builders.common.kt:47)
        at kotlinx.coroutines.BuildersKt.launch$default(Unknown Source:1)
        at kotlinx.coroutines.flow.internal.ChannelFlowTransformLatest$flowCollect$3$invokeSuspend$$inlined$collect$1.emit(Collect.kt:140)
        at kotlinx.coroutines.flow.SharedFlowImpl.collect(SharedFlow.kt:351)
        at kotlinx.coroutines.flow.ReadonlySharedFlow.collect(Unknown Source:2)
        at kotlinx.coroutines.flow.internal.ChannelFlowTransformLatest$flowCollect$3.invokeSuspend(Merge.kt:101)
        at kotlinx.coroutines.flow.internal.ChannelFlowTransformLatest$flowCollect$3.invoke(Unknown Source:8)
        at kotlinx.coroutines.flow.internal.ChannelFlowTransformLatest$flowCollect$3.invoke(Unknown Source:4)
        at kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturn(Undispatched.kt:89)
        at kotlinx.coroutines.flow.internal.FlowCoroutineKt.flowScope(FlowCoroutine.kt:33)
        at kotlinx.coroutines.flow.internal.ChannelFlowTransformLatest.flowCollect(Merge.kt:25)
        at kotlinx.coroutines.flow.internal.ChannelFlowOperator.collectTo$suspendImpl(ChannelFlow.kt:157)
        at kotlinx.coroutines.flow.internal.ChannelFlowOperator.collectTo(Unknown Source:0)
        at kotlinx.coroutines.flow.internal.ChannelFlow$collectToFun$1.invokeSuspend(ChannelFlow.kt:60)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
        at androidx.compose.ui.platform.AndroidUiDispatcher.performTrampolineDispatch(AndroidUiDispatcher.android.kt:81)
        at androidx.compose.ui.platform.AndroidUiDispatcher.access$performTrampolineDispatch(AndroidUiDispatcher.android.kt:41)
        at androidx.compose.ui.platform.AndroidUiDispatcher$dispatchCallback$1.run(AndroidUiDispatcher.android.kt:57)
        at android.os.Handler.handleCallback(Handler.java:883)
        at android.os.Handler.dispatchMessage(Handler.java:100)
        at android.os.Looper.loop(Looper.java:214)
        at android.app.ActivityThread.main(ActivityThread.java:7397)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:935)

To Reproduce
Steps to reproduce the behavior:

  1. On your phone, save any picture that you have to root folder of your storage
  2. Implement pluck with permission
Permission(
    permissions = listOf(
        Manifest.permission.CAMERA,
        Manifest.permission.READ_EXTERNAL_STORAGE
    ),
    goToAppSettings = {
        // Go to App Settings
    }
) {
    Pluck(onPhotoSelected = {
        // List of PluckImage when selecting from Gallery/Camera. When checking with Camera
        // It returns only one item in list
    })
}
  1. run the app on debug mode
  2. accept permission
  3. See error

Desktop

  • OS: Windows 11 Home Single Language
  • Version 21H2

Android Studio

  • Android Studio Bumblebee | 2021.1.1 Patch 1
  • Build #AI-211.7628.21.2111.8139111, built on February 2, 2022

Smartphone (please complete the following information):

  • Device: Asus Max Pro M1
  • OS: Android 10

Add PluckConfig

  • Add Config for adding customizations to the project like supporting tabs to select single/multiple images.
    Eg. Single + Multiple Image Selection.

Not working with compose 1.4

I got crash when use Pluck with permission
here is stack trace

java.lang.NoSuchMethodError: No static method Scaffold-zOzJ79U(Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;IJJLkotlin/jvm/functions/Function3;Landroidx/compose/runtime/Composer;II)V in class Landroidx/compose/material3/ScaffoldKt; or its super classes (declaration of 'androidx.compose.material3.ScaffoldKt' appears in /data/app/~~zsV8t1-rFJuDKJsPlpQT2A==/com.eventgo.app-HnRnepwOmgQ393YaqlSIOA==/base.apk)
at com.himanshoe.pluck.ui.permission.PermissionKt$Permission$1.invoke(Permission.kt:75)
at com.himanshoe.pluck.ui.permission.PermissionKt$Permission$1.invoke(Permission.kt:74)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
at com.google.accompanist.permissions.PermissionsRequiredKt.PermissionsRequired(PermissionsRequired.kt:97)
at com.himanshoe.pluck.ui.permission.PermissionKt.Permission(Permission.kt:72)
at com.eventgo.app.ui.screen.create_event.CreateEventScreenKt$CreateEventScreen$3$1.invoke(CreateEventScreen.kt:137)
at com.eventgo.app.ui.screen.create_event.CreateEventScreenKt$CreateEventScreen$3$1.invoke(CreateEventScreen.kt:135)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
at androidx.compose.material3.SurfaceKt$Surface$1.invoke(Surface.kt:132)
at androidx.compose.material3.SurfaceKt$Surface$1.invoke(Surface.kt:114)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:228)
at androidx.compose.material3.SurfaceKt.Surface-T9BRK9s(Surface.kt:111)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.