Giter Site home page Giter Site logo

commandiron / wheelpickercompose Goto Github PK

View Code? Open in Web Editor NEW
424.0 7.0 49.0 14.51 MB

Add Wheel Date - Time Picker in Android Jetpack Compose.

License: Apache License 2.0

Kotlin 100.00%
android android-lib compose-library jetpack-compose kotlin library android-sdk android-sdk-library kotlin-library uiview

wheelpickercompose's Introduction

WheelPickerCompose API

Add Wheel Date - Time Picker in Android Jetpack Compose.

Usage

Picker Usage
WheelDateTimePicker { snappedDateTime -> }
WheelDatePicker { snappedDate -> }
WheelTimePicker { snappedTime -> }
WheelTimePicker(timeFormat = TimeFormat.AM_PM) { snappedTime -> }

Features

WheelDateTimePicker(
    startDateTime = LocalDateTime.of(
        2025, 10, 20, 5, 30
    ),
    minDateTime = LocalDateTime.now(),
    maxDateTime = LocalDateTime.of(
        2025, 10, 20, 5, 30
    ),
    timeFormat = TimeFormat.AM_PM,
    size = DpSize(200.dp, 100.dp),
    rowCount = 5,
    textStyle = MaterialTheme.typography.titleSmall,
    textColor = Color(0xFFffc300),
    selectorProperties = WheelPickerDefaults.selectorProperties(
        enabled = true,
        shape = RoundedCornerShape(0.dp),
        color = Color(0xFFf1faee).copy(alpha = 0.2f),
        border = BorderStroke(2.dp, Color(0xFFf1faee))
    )
){ snappedDateTime -> }

Setup

  1. Open the file settings.gradle (it looks like that)
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
        // add jitpack here 👇🏽
        maven { url 'https://jitpack.io' }
       ...
    }
} 
...
  1. Sync the project
  2. Add dependency
dependencies {
    implementation 'com.github.commandiron:WheelPickerCompose:1.1.11'
}
  1. < API 26 (optional)
compileOptions {
    coreLibraryDesugaringEnabled true
    //
}
//
dependencies {
    //
    coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:1.1.6"
}

wheelpickercompose's People

Contributors

commandiron avatar profourone 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  avatar  avatar  avatar

wheelpickercompose's Issues

Support for AM/PM

I would like to support AM and PM as well as 24-hour format. Is this something you are considering?

Other language support

Hi @commandiron ,

Your library was amazing. However, I think it will be great if you add new param for change locale of the month text composable so that the library can support other language.

java.lang.IllegalStateException: Offset is unspecified

Affected devices as far as I have tested: Samsung Galaxy S21 Ultra 5G (Android 13), Xiaomi Mi A2 Lite(Android 10)
Unaffected devices: TCL 20S

Was working fine before but now out of nowhere got this issue:

androidx.compose.ui.geometry.Offset.getX-impl Offset.java:28 androidx.compose.ui.graphics.Matrix.map-impl Matrix.java androidx.compose.ui.platform.RenderNodeLayer.mapBounds RenderNodeLayer.java androidx.compose.ui.node.NodeCoordinator.rectInParent$ui_release NodeCoordinator.java androidx.compose.ui.node.NodeCoordinator.rectInParent$ui_release$default NodeCoordinator.java androidx.compose.ui.node.NodeCoordinator.localBoundingBoxOf NodeCoordinator.java androidx.compose.ui.layout.LayoutCoordinates.localBoundingBoxOf$default LayoutCoordinates.java androidx.compose.ui.layout.LayoutCoordinatesKt.boundsInRoot LayoutCoordinatesKt.java androidx.compose.ui.node.SemanticsModifierNodeKt.touchBoundsInRoot SemanticsModifierNodeKt.java androidx.compose.ui.semantics.SemanticsNode.getTouchBoundsInRoot SemanticsNode.java androidx.compose.ui.platform.AndroidComposeViewAccessibilityDelegateCompat_androidKt.getAllUncoveredSemanticsNodesToMap$findAllSemanticNodesRecursive AndroidComposeViewAccessibilityDelegateCompat_androidKt.java androidx.compose.ui.platform.AndroidComposeViewAccessibilityDelegateCompat_androidKt.getAllUncoveredSemanticsNodesToMap$findAllSemanticNodesRecursive AndroidComposeViewAccessibilityDelegateCompat_androidKt.java androidx.compose.ui.platform.AndroidComposeViewAccessibilityDelegateCompat_androidKt.getAllUncoveredSemanticsNodesToMap$findAllSemanticNodesRecursive AndroidComposeViewAccessibilityDelegateCompat_androidKt.java androidx.compose.ui.platform.AndroidComposeViewAccessibilityDelegateCompat_androidKt.getAllUncoveredSemanticsNodesToMap$findAllSemanticNodesRecursive AndroidComposeViewAccessibilityDelegateCompat_androidKt.java androidx.compose.ui.platform.AndroidComposeViewAccessibilityDelegateCompat_androidKt.getAllUncoveredSemanticsNodesToMap$findAllSemanticNodesRecursive AndroidComposeViewAccessibilityDelegateCompat_androidKt.java androidx.compose.ui.platform.AndroidComposeViewAccessibilityDelegateCompat_androidKt.getAllUncoveredSemanticsNodesToMap AndroidComposeViewAccessibilityDelegateCompat_androidKt.java androidx.compose.ui.platform.AndroidComposeViewAccessibilityDelegateCompat.getCurrentSemanticsNodes AndroidComposeViewAccessibilityDelegateCompat.java androidx.compose.ui.platform.AndroidComposeViewAccessibilityDelegateCompat.createEvent$ui_release AndroidComposeViewAccessibilityDelegateCompat.java:34 androidx.compose.ui.platform.AndroidComposeViewAccessibilityDelegateCompat.sendEventForVirtualView AndroidComposeViewAccessibilityDelegateCompat.java:11 androidx.compose.ui.platform.AndroidComposeViewAccessibilityDelegateCompat.sendEventForVirtualView$default AndroidComposeViewAccessibilityDelegateCompat.java:6 androidx.compose.ui.platform.AndroidComposeViewAccessibilityDelegateCompat.sendSubtreeChangeAccessibilityEvents AndroidComposeViewAccessibilityDelegateCompat.java androidx.compose.ui.platform.AndroidComposeViewAccessibilityDelegateCompat.boundsUpdatesEventLoop AndroidComposeViewAccessibilityDelegateCompat.java androidx.compose.ui.platform.AndroidComposeView.boundsUpdatesEventLoop AndroidComposeView.java androidx.compose.ui.platform.WrappedComposition$setContent$1$1$1.invokeSuspend WrappedComposition.java kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith BaseContinuationImpl.java:8 kotlinx.coroutines.DispatchedTask.run DispatchedTask.java:100 androidx.compose.ui.platform.AndroidUiDispatcher.performTrampolineDispatch AndroidUiDispatcher.java androidx.compose.ui.platform.AndroidUiDispatcher.access$performTrampolineDispatch AndroidUiDispatcher.java androidx.compose.ui.platform.AndroidUiDispatcher$dispatchCallback$1.run AndroidUiDispatcher.java:2 android.os.Handler.handleCallback Handler.java:883

Useful note: had gotten this about a week ago when building the app:

Could not resolve com.github.commandiron:WheelPickerCompose:1.1.10.
> Could not get resource 'https://jitpack.io/com/github/commandiron/WheelPickerCompose/1.1.10/WheelPickerCompose-1.1.10.pom'.
> Could not GET 'https://jitpack.io/com/github/commandiron/WheelPickerCompose/1.1.10/WheelPickerCompose-1.1.10.pom'.
> Read timed out

建议问题

1,只要年月模式,怎么控制
2,中间的选中的样式,怎么修改

Add looped scrolling

Eg: For hour, scrolling should not stop after 12. Rather it should again loop to 1 and also switch AM to PM and vice versa.
For minutes, scrolling should loop after 59.

This is similar to how Xiaomi does it.

Shouldn't be much difficult to implement.

Wishlist: typable WheelPicker

It would be great if the WheelPicker would be combined with TextField. The central number inside the WheelPicker is editable as the text in TextField, with text validation for available items. As you type it when it finds the available element wheel positions to it. After you press enter or done cursor goes away, if the element was found wheel was already positioned, if no such element exception is thrown.

Actually, I cannot see WheelPicker without typing ability, for me it's "must have"! And probably I've seen this somewhere already.

WheelTextPicker: startIndex positions element askew

@Composable
fun WheelPicker()
{
    // FIXME: meaningless mutable state for output only?
    var snappedDT:LocalDateTime by remember { mutableStateOf(LocalDateTime.MIN) }
    var snappedD:LocalDate by remember { mutableStateOf(LocalDate.MIN) }
    var snappedT:LocalTime by remember { mutableStateOf(LocalTime.MIN) }

    Column {
        WheelDateTimePicker(
            startDateTime = LocalDateTime.of(
                2025, 10, 20, 5, 30
            ),
            minDateTime = LocalDateTime.now(),
            maxDateTime = LocalDateTime.of(
                2025, 10, 20, 5, 30
            ),
            timeFormat = TimeFormat.AM_PM,
            size = DpSize(200.dp, 100.dp),
            rowCount = 5,
            textStyle = MaterialTheme.typography.titleSmall,
            textColor = Color(0xFFffc300),
            selectorProperties = WheelPickerDefaults.selectorProperties(
                enabled = true,
                shape = RoundedCornerShape(0.dp),
                color = Color(0xFFf1faee).copy(alpha = 0.2f),
                border = BorderStroke(2.dp, Color(0xFFf1faee))
            )
        ) { snappedDateTime -> snappedDT = snappedDateTime }

        WheelDateTimePicker { snappedDateTime -> snappedDT = snappedDateTime}

        WheelDatePicker { snappedDate -> snappedD = snappedDate }

        WheelTimePicker { snappedTime -> snappedT = snappedTime }

        WheelTimePicker(timeFormat = TimeFormat.AM_PM) { snappedTime -> snappedT = snappedTime }

        WheelTextPicker(texts = (0..99).toList().map { it.toString() }, rowCount = 5, startIndex = 21)
    }
}

It positions the element like that:

image

After touching it with mouse it repositions it properly:

image

Get intermediary wheel picker values

Hello!
First of all, let me thank you for this super cool and handy library!
I was wondering if there is a way for onSnappedDateTime to account for the intermediary values as the user scrolls.
This would be useful for example in the following scenario:
A user navigates to a page where they have the Wheel Picker. He scrolls the picker and as the wheel is still scrolling, he instantly saves the date and closes the page. The state would not still be updated since onSnappedDateTime is called only when the picker is not scrolling. A good way to resolve this would be for onSnappedDateTime to retrieve every value as the user scrolls so that even if he closes the page, the state would still be updated.

Semicolon position fixation issue

If you change the position of the WheelTimePicker to the center, the position of the semicolon (:) is fixed and only the numbers move. 00:00 I want to express it this way, but how can I do it?

스크린샷 2023-11-16 오후 7 30 21

Support for other calendars

Hi, i think we can support other calendar systems by adding another parameter like "dateSystem".
I don't think it requires much changes.
Just adding corresponding year-range, months and days range

Textwheelpicker

Is there a chance you can remove internal from TextWheelPicker? I would like to use your lib as it looks neat and is full compose built, however text picker is kinda required for me e.g. For gender selection.

Hide Year if there is only one option

I am enjoying the WheelPicker. I would like to request the option to hide the year if there is only 1 option.

My use case is that I would like my users to be able to select a date and time in the up coming week. Unless we are heading into the new year, most of the time, the year is obvious and does not need to be displayed.

Add an ability to hide the date in the WheelDatePicker

I have another small requirement in my project to have an ability to hide date, and only have month year selector.

I have noticed you are hiding year if the range was null, so I made a small change following the same idea in my fork with the date case.

bfcd7f1

Do you think it can be added?

Java support?

Does this lib support for Java? If yes, can you provide Java sample code. Thanks.

WheelTimePicker does not recompose if startTime is changed manually

I would like to manually change the time on a button click, for instance:

                    Column(
                        horizontalAlignment = Alignment.CenterHorizontally,
                        verticalArrangement = Arrangement.Center
                    ) {

                        var changeableTime: LocalTime by remember {
                            mutableStateOf(LocalTime.now())
                        }
                        WheelTimePicker(
                            startTime = changeableTime,
                            timeFormat = TimeFormat.HOUR_24,
                            size = DpSize(200.dp, 100.dp),
                            rowCount = 5,
                            textStyle = MaterialTheme.typography.titleSmall,
                            textColor = Color(0xFFffc300),
                            selectorProperties = WheelPickerDefaults.selectorProperties(
                                enabled = true,
                                shape = RoundedCornerShape(0.dp),
                                color = Color(0xFFf1faee).copy(alpha = 0.2f),
                                border = BorderStroke(2.dp, Color(0xFFf1faee))
                            )
                        ){ snappedDateTime ->
                            // Do something with snapped time
                        }

                        Button(onClick = {
                            changeableTime = LocalTime.now()
                        }) {
                            Text(text = "Set time to now")
                        }
                    }

Unfortunately the WheelTimePicker does not get recomposed when startTime is mutable and changed.
Should this work using the library or is this out of scope?

Fatal Exception: java.lang.IllegalStateException: Offset is unspecified

Running on 3 device

Samsung A51 Android 13,Samung Galaxy M22,Samsung Galaxy J4+

Got Error

Fatal Exception: java.lang.IllegalStateException: Offset is unspecified
       at androidx.compose.ui.geometry.Offset.getX-impl(Offset.kt:67)
       at androidx.compose.ui.graphics.Matrix.map-impl(Matrix.kt:86)
       at androidx.compose.ui.platform.ViewLayer.mapBounds(ViewLayer.android.kt:365)
       at androidx.compose.ui.node.NodeCoordinator.rectInParent$ui_release(NodeCoordinator.kt:976)
       at androidx.compose.ui.node.NodeCoordinator.rectInParent$ui_release$default(NodeCoordinator.kt:954)
       at androidx.compose.ui.node.NodeCoordinator.localBoundingBoxOf(NodeCoordinator.kt:845)
       at androidx.compose.ui.layout.LayoutCoordinates.localBoundingBoxOf$default(LayoutCoordinates.kt:94)
       at androidx.compose.ui.layout.LayoutCoordinatesKt.boundsInRoot(LayoutCoordinates.kt:128)
       at androidx.compose.ui.node.SemanticsModifierNodeKt.touchBoundsInRoot(SemanticsModifierNode.kt:68)
       at androidx.compose.ui.semantics.SemanticsNode.getTouchBoundsInRoot(SemanticsNode.kt:109)
       at androidx.compose.ui.platform.AndroidComposeViewAccessibilityDelegateCompat_androidKt.getAllUncoveredSemanticsNodesToMap$findAllSemanticNodesRecursive(AndroidComposeViewAccessibilityDelegateCompat.android.kt:3077)
       at androidx.compose.ui.platform.AndroidComposeViewAccessibilityDelegateCompat_androidKt.getAllUncoveredSemanticsNodesToMap$findAllSemanticNodesRecursive(AndroidComposeViewAccessibilityDelegateCompat.android.kt:3096)
       at androidx.compose.ui.platform.AndroidComposeViewAccessibilityDelegateCompat_androidKt.getAllUncoveredSemanticsNodesToMap$findAllSemanticNodesRecursive(AndroidComposeViewAccessibilityDelegateCompat.android.kt:3096)
       at androidx.compose.ui.platform.AndroidComposeViewAccessibilityDelegateCompat_androidKt.getAllUncoveredSemanticsNodesToMap$findAllSemanticNodesRecursive(AndroidComposeViewAccessibilityDelegateCompat.android.kt:3096)
       at androidx.compose.ui.platform.AndroidComposeViewAccessibilityDelegateCompat_androidKt.getAllUncoveredSemanticsNodesToMap(AndroidComposeViewAccessibilityDelegateCompat.android.kt:3127)
       at androidx.compose.ui.platform.AndroidComposeViewAccessibilityDelegateCompat.getCurrentSemanticsNodes(AndroidComposeViewAccessibilityDelegateCompat.android.kt:354)
       at androidx.compose.ui.platform.AndroidComposeViewAccessibilityDelegateCompat.createEvent$ui_release(AndroidComposeViewAccessibilityDelegateCompat.android.kt:1406)
       at androidx.compose.ui.platform.AndroidComposeViewAccessibilityDelegateCompat.sendEventForVirtualView(AndroidComposeViewAccessibilityDelegateCompat.android.kt:1358)
       at androidx.compose.ui.platform.AndroidComposeViewAccessibilityDelegateCompat.sendEventForVirtualView$default(AndroidComposeViewAccessibilityDelegateCompat.android.kt:1348)
       at androidx.compose.ui.platform.AndroidComposeViewAccessibilityDelegateCompat.sendSubtreeChangeAccessibilityEvents(AndroidComposeViewAccessibilityDelegateCompat.android.kt:2110)
       at androidx.compose.ui.platform.AndroidComposeViewAccessibilityDelegateCompat.boundsUpdatesEventLoop(AndroidComposeViewAccessibilityDelegateCompat.android.kt:2028)
       at androidx.compose.ui.platform.AndroidComposeView.boundsUpdatesEventLoop(AndroidComposeView.android.kt:1107)
       at androidx.compose.ui.platform.WrappedComposition$setContent$1$1$1.invokeSuspend(Wrapper.android.kt:153)
       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:873)
       at android.os.Handler.dispatchMessage(Handler.java:99)
       at android.os.Looper.loop(Looper.java:214)
       at android.app.ActivityThread.main(ActivityThread.java:7094)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:975)

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.