Code Monkey home page Code Monkey logo

swipe's Introduction

swipe

swipe.mp4

swipe builds composables that can be swiped left or right for revealing actions. Unlike SwipeToDismiss, it is designed for swipe actions that do not dismiss their composable.

implementation "me.saket.swipe:swipe:1.3.0"
val archive = SwipeAction(
  icon = rememberVectorPainter(Icons.TwoTone.Archive),
  background = Color.Green,
  onSwipe = { … }
)

val snooze = SwipeAction(
  icon = { Text("Snooze") },
  background = Color.Yellow,
  isUndo = true,
  onSwipe = { … },
)

SwipeableActionsBox(
  startActions = listOf(archive),
  endActions = listOf(snooze)
) {
  // Swipeable content goes here.
}

License

Copyright 2022 Saket Narayan.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

swipe's People

Contributors

alashow avatar kitsunefolk avatar saket 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

swipe's Issues

How to setup swipe to dismiss in one direction?

Love using this! But not sure how to setup a swipe to dismiss in one direction, and a swipe for action in the other direction. anything specific I need to do or this lib not meant for that?

NPE when swiping on the side without actions

Hello,

NPE happens when swiping the side without any actions. It's little bit harder to trigger when swipeThreshold=40.dp but it still crashes when item is dragged 40.dp. With swipeThreshold=1.dp it crashes right away when swipe starts.

java.lang.NullPointerException
    at me.saket.swipe.SwipeableActionsBoxKt$SwipeableActionsBox$1.invoke(SwipeableActionsBox.kt:88)
    at me.saket.swipe.SwipeableActionsBoxKt$SwipeableActionsBox$1.invoke(SwipeableActionsBox.kt:56)
    at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:116)
    at androidx.compose.runtime.internal.ComposableLambdaImpl$invoke$1.invoke(ComposableLambda.jvm.kt:127)
    at androidx.compose.runtime.internal.ComposableLambdaImpl$invoke$1.invoke(ComposableLambda.jvm.kt:127)
screen-20220430-192911.mp4

Disable SwipeAction and active swipe by other button

Hi! i have an card in compose and i added your lib, i liked a lot. but i want do things that im not sure if your lib can do that, i dont fint any documentation about your lib too.

The questions is, how can i disable the swipe action after swipe one time? i want to my user just swipe once.

The other questions is how can i call the swipeaction without swipe? for example, i have one button in my card and i want when i click in this button show the swipe action animation, how can i do that things?

Crash while swiping

Haven't had the chance to fully debug it yet but I got this crash reported for my app on Sentry

Stacktrace
kotlin.UninitializedPropertyAccessException: lateinit property canSwipeTowardsLeft has not been initialized
    at me.saket.swipe.SwipeableActionsState.getCanSwipeTowardsLeft$swipe_release
    at me.saket.swipe.SwipeableActionsState$draggableState$1.invoke
    at me.saket.swipe.SwipeableActionsState$draggableState$1.invoke
    at kotlinx.serialization.descriptors.SerialDescriptorImpl$toString$1.invoke$bridge(SourceFile:0)
    at androidx.compose.foundation.gestures.DefaultDraggableState$dragScope$1.dragBy
    at androidx.compose.foundation.gestures.DefaultDraggableState$dragScope$1.dragBy$bridge
    at androidx.compose.foundation.gestures.DraggableNode$onAttach$1$1.invokeSuspend
    at androidx.compose.foundation.gestures.DraggableNode$onAttach$1$1.invoke
    at androidx.compose.foundation.gestures.DraggableNode$onAttach$1$1.invoke
    at androidx.compose.foundation.MutatorMutex$mutateWith$2.invokeSuspend
    at androidx.compose.foundation.MutatorMutex$mutateWith$2.invoke
    at androidx.compose.foundation.MutatorMutex$mutateWith$2.invoke
    at kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturn
    at okio.Utf8.processUtf16Chars
    at kotlinx.coroutines.CoroutineScopeKt.coroutineScope
    at kotlinx.coroutines.CoroutineScopeKt.coroutineScope
    at androidx.compose.foundation.MutatorMutex.mutateWith
    at androidx.compose.foundation.gestures.DefaultDraggableState$drag$2.invokeSuspend
    at androidx.compose.foundation.gestures.DefaultDraggableState$drag$2.invoke
    at androidx.compose.foundation.gestures.DefaultDraggableState$drag$2.invoke
    at kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturn
    at okio.Utf8.processUtf16Chars
    at kotlinx.coroutines.CoroutineScopeKt.coroutineScope
    at kotlinx.coroutines.CoroutineScopeKt.coroutineScope
    at androidx.compose.foundation.gestures.DefaultDraggableState.drag
    at androidx.compose.foundation.gestures.DraggableNode$onAttach$1.invokeSuspend
    at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith
    at kotlinx.coroutines.DispatchedTask.run
    at kotlinx.coroutines.DispatchedTask.run
    at androidx.compose.ui.platform.AndroidUiDispatcher.nextTask
    at androidx.compose.ui.platform.AndroidUiDispatcher.performTrampolineDispatch
    at androidx.compose.ui.platform.AndroidUiDispatcher.access$performTrampolineDispatch
    at androidx.compose.ui.platform.AndroidUiDispatcher.performTrampolineDispatch
    at androidx.compose.ui.platform.AndroidUiDispatcher.access$performTrampolineDispatch
    at androidx.compose.ui.platform.AndroidUiDispatcher$dispatchCallback$1.run
    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:7356)
    at java.lang.reflect.Method.invoke(Method.java)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)

Here's how I'm using Swipe: msfjarvis/compose-lobsters@bae671a

Animation broken using compose 1.5.0-beta01

What broke?

When using compose 1.5.0-beta01, resetOffset() animation will not complete.

Screenshot 2023-06-05 at 11 52 41 PM

How to reproduce?

Use compose 1.5.0-beta01

What made it broke?

Internally in compose's implementation, a PointerInputResetException() has been thrown causing cancellation.

Potential fix?

Making SwipeableActionsBox() always enabled kinda fixes it. But I'm not sure if there are side effects.

Crash when swiped to full width

Crash happens when swiping/dragging content to it's full width.

Stacktrace:

java.lang.IllegalStateException: Couldn't find any swipe action. Width=1160, offset=1162.4507, actions=[me.saket.swipe.SwipeAction@c737efb, me.saket.swipe.SwipeAction@effbb18]
 	at me.saket.swipe.ActionFinder.actionAt(ActionFinder.kt:49)
 	at me.saket.swipe.ActionFinder.actionAt(ActionFinder.kt:24)
 	at me.saket.swipe.SwipeableActionsBoxKt$SwipeableActionsBox$1.invoke(SwipeableActionsBox.kt:82)
 	at me.saket.swipe.SwipeableActionsBoxKt$SwipeableActionsBox$1.invoke(SwipeableActionsBox.kt:56)
 	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:116)

Screenrecord: https://kapture-4t6s5u7zc-alashov.vercel.app

Unintentional swipes while scrolling

When using swipe actions on scrollable items, swipe actions gets triggered unintentionally.

It can be triggered more easily when list items have smaller heights.

swipes-with-scroll.mp4

Usage: how to remove an item

Basic question: how do I get access to the outer list and remove an item from the onSwipe? All the examples I've seen just show a log or a Toast

@Composable
fun ItemList() {
    LazyColumn(
        modifier = Modifier.fillMaxWidth(),
        verticalArrangement = Arrangement.spacedBy(8.dp)
    ) {
        items(20) { count ->
            val archive = SwipeAction(
                onSwipe = {
                    println("Swiped - deleting")
                    //TODO: Delete item
                },
                icon = {
                    Icon(
                        modifier = Modifier.padding(16.dp),
                        imageVector = Icons.Filled.Delete,
                        contentDescription = "Delete",
                        tint = MaterialTheme.colorScheme.background
                    )
                },
                background = Color.Red
            )

            SwipeableActionsBox(
                swipeThreshold = 100.dp,
                startActions = listOf(archive),
                endActions = listOf(archive) //can make share/email
            ) {
                TestItem(title = "Hello")
            }
        }
    }
}

No matching variant of me.saket.swipe:swipe:1.0.0 was found

Describe the bug
Gradle will crash while creating a new build after the library is implemented

To Reproduce
Steps to reproduce the behaviour (including any applicable code):

  1. Set AGP to 7.4.0-alpha10
  2. Implement me.saket.swipe:swipe:1.0.0
  3. Create rc build variant
  4. Execute ./gradlew assembleRc

Expected behaviour
Gradle will create a new build

* What went wrong:
Execution failed for task ':app:extractIncludeRcProto'.
> Could not determine the dependencies of null.
32 problems were found storing the configuration cache, 18 of which seem unique.
   > Could not resolve all task dependencies for configuration ':app:rcCompileClasspath'.
      > Could not resolve me.saket.swipe:swipe:1.0.0.
        Required by:
            project :app
         > No matching variant of me.saket.swipe:swipe:1.0.0 was found. The consumer was configured to find an API of a component, preferably optimized for Android, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'rc', attribute 'com.android.build.api.attributes.AgpVersionAttr' with value '7.4.0-alpha10', attribute 'org.jetbrains.kotlin.platform.type' with value 'androidJvm' but:
             - Variant 'debugVariantMavenApiPublication' capability me.saket.swipe:swipe:1.0.0 declares an API of a component:
                 - Incompatible because this component declares a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'debug' and the consumer needed a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'rc'
                 - Other compatible attributes:
                     - Doesn't say anything about com.android.build.api.attributes.AgpVersionAttr (required '7.4.0-alpha10')
                     - Doesn't say anything about its target Java environment (preferred optimized for Android)
                     - Doesn't say anything about org.jetbrains.kotlin.platform.type (required 'androidJvm')
             - Variant 'debugVariantMavenJavaDocPublication' capability me.saket.swipe:swipe:1.0.0 declares a runtime of a component:
                 - Incompatible because this component declares a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'debug' and the consumer needed a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'rc'
                 - Other compatible attributes:
                     - Doesn't say anything about com.android.build.api.attributes.AgpVersionAttr (required '7.4.0-alpha10')
                     - Doesn't say anything about its target Java environment (preferred optimized for Android)
                     - Doesn't say anything about org.jetbrains.kotlin.platform.type (required 'androidJvm')
             - Variant 'debugVariantMavenRuntimePublication' capability me.saket.swipe:swipe:1.0.0 declares a runtime of a component:
                 - Incompatible because this component declares a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'debug' and the consumer needed a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'rc'
                 - Other compatible attributes:
                     - Doesn't say anything about com.android.build.api.attributes.AgpVersionAttr (required '7.4.0-alpha10')
                     - Doesn't say anything about its target Java environment (preferred optimized for Android)
                     - Doesn't say anything about org.jetbrains.kotlin.platform.type (required 'androidJvm')
             - Variant 'debugVariantMavenSourcePublication' capability me.saket.swipe:swipe:1.0.0 declares a runtime of a component:
- Task `:app:compileRcAidl` of type `com.android.build.gradle.tasks.AidlCompile`: value 'configuration ':app:rcCompileClasspath' files' failed to visit file collection
                 - Incompatible because this component declares a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'debug' and the consumer needed a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'rc'
                 - Other compatible attributes:
                     - Doesn't say anything about com.android.build.api.attributes.AgpVersionAttr (required '7.4.0-alpha10')
                     - Doesn't say anything about its target Java environment (preferred optimized for Android)
                     - Doesn't say anything about org.jetbrains.kotlin.platform.type (required 'androidJvm')
             - Variant 'releaseVariantMavenApiPublication' capability me.saket.swipe:swipe:1.0.0 declares an API of a component:
                 - Incompatible because this component declares a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'release' and the consumer needed a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'rc'
                 - Other compatible attributes:
                     - Doesn't say anything about com.android.build.api.attributes.AgpVersionAttr (required '7.4.0-alpha10')
                     - Doesn't say anything about its target Java environment (preferred optimized for Android)
                     - Doesn't say anything about org.jetbrains.kotlin.platform.type (required 'androidJvm')
             - Variant 'releaseVariantMavenJavaDocPublication' capability me.saket.swipe:swipe:1.0.0 declares a runtime of a component:
                 - Incompatible because this component declares a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'release' and the consumer needed a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'rc'
                 - Other compatible attributes:
                     - Doesn't say anything about com.android.build.api.attributes.AgpVersionAttr (required '7.4.0-alpha10')
                     - Doesn't say anything about its target Java environment (preferred optimized for Android)
                     - Doesn't say anything about org.jetbrains.kotlin.platform.type (required 'androidJvm')
             - Variant 'releaseVariantMavenRuntimePublication' capability me.saket.swipe:swipe:1.0.0 declares a runtime of a component:
                 - Incompatible because this component declares a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'release' and the consumer needed a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'rc'
                 - Other compatible attributes:
                     - Doesn't say anything about com.android.build.api.attributes.AgpVersionAttr (required '7.4.0-alpha10')
                     - Doesn't say anything about its target Java environment (preferred optimized for Android)
                     - Doesn't say anything about org.jetbrains.kotlin.platform.type (required 'androidJvm')
             - Variant 'releaseVariantMavenSourcePublication' capability me.saket.swipe:swipe:1.0.0 declares a runtime of a component:
                 - Incompatible because this component declares a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'release' and the consumer needed a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'rc'
                 - Other compatible attributes:
                     - Doesn't say anything about com.android.build.api.attributes.AgpVersionAttr (required '7.4.0-alpha10')
                     - Doesn't say anything about its target Java environment (preferred optimized for Android)
                     - Doesn't say anything about org.jetbrains.kotlin.platform.type (required 'androidJvm')

Option to limit swiping distance

Currently content can be swiped/dragged fully. I think UX is better when swipeable distance is limited so an option to limit it would be a good addition.

Support for content without background

Currently, when content inside SwipeableActionsBox doesn't have any background or has translucent background color, backgroundUntilSwipeThreshold or swiped actions background is visible.

With backgroundUntilSwipeThreshold=Color.Transparent and content without background, it looks like this when swipe threshold is reached:
Screen Shot 2022-04-30 at 20 14 31

[request] swipe up/down support ↕️

First of all, what a great repo❗ :shipit:

  1. My compose-foo is weak:

I'm trying to copy the Gmail Android app account-switch on avatar-swipe-down animation (and subsequent view recycle).

IMHO it's one of the best UX elements on mobile - usable, fast, and beautiful!.

Instagram just implemented something similar, but it's a avatar coin flip on tap profile pic to what looks like a memoji.

I've searched far and wide on GitHub and this repo is the closest I've come to finding the promised land. I'm 📏🤏close to reverse engineering the Gmail APK.

Any chance we can get up down swipe support on FABs?

Cc @saket @c5inco

Best,
Ryan 🌵

Allow option to disable overscroll

Currently the draggable state is set to overscroll with resistance when the scroll isn't allowed (here). This can easily interfere with any parent horizontal gestures. Add an option to disable this?

How do I detect swipe?

I can't detect swipe. These doen't work:

val actionsState = rememberSwipeableActionsState()

val offset by actionsState.offset // Doesn't change value. Always 0.0

actionsState.isResettingOnRelease // Doesn't change value. Always false

Thanks.

Request: Add text in swipe action

It would be nice if we could als add text next to an icon or instead of the icon.

Maybe we should be able to add another compose element.

Permanent vibration on _slow_ swipe after threshold was crossed

Hi!
After haptics feedback was added to this project, I noticed constant (and somehow annoying) vibration on slow swipes after threshold was crossed.
Please consider changing it to one-shot vibration by replacing this code in SwipeableActionsBox composable

    if (state.hasCrossedSwipeThreshold() && state.swipedAction == null) {
        LaunchedEffect(state.visibleAction) {
            hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
        }
    }

to

    var offsetCrossed by remember { mutableStateOf(false) }
    if (state.hasCrossedSwipeThreshold()) {
        if (!offsetCrossed) {
            offsetCrossed = true
            LaunchedEffect(state.visibleAction) {
                hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
            }
        }
    } else {
        offsetCrossed = false
    }

or smth similar

The ability to specify swiping directions

Hello!

Currently, there is no way to specify swiping directions. This prevents me from using the library in some scenarios, such as having a horizontal pager with an item that has swiping capabilities.

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.