maxkeppeler / sheets-compose-dialogs

✨ A Multiplatform Library to enhance UIs, supporting a wide range of common use-cases with Dialogs, Popups, and Bottom Sheets. ✨
https://maxkeppeler.github.io/sheets-compose-dialogs/
Apache License 2.0
826 stars 38 forks source link

[Crash] DateTimeException: Invalid value for MinuteOfHour #28

Closed Nek-12 closed 1 year ago

Nek-12 commented 1 year ago

I received this crash from crashlytics recently. The user somehow managed to input "70" into the minute field while probably trying to input "07:00". This may be due to a laggy device.

Sheets used in the app version: 1.0.4 Device: Lenovo TAB4 8 Android 8.1

Specs clearly show it's a low-performance device. Analytics don't indicate that the user made any input into the dialog before crashing, which is weird. Could it be that the initial time (which I set to current system time) somehow was at 70 minutes?? But the stacktrace shows that the crash happened upon tapping a number. There has been 1 crash for this one user.

Fatal Exception: java.time.DateTimeException: Invalid value for MinuteOfHour (valid values 0 - 59): 70
       at java.time.temporal.ValueRange.checkValidValue(ValueRange.java:311)
       at java.time.temporal.ChronoField.checkValidValue(ChronoField.java:730)
       at java.time.LocalTime.of(LocalTime.java:315)
       at com.maxkeppeler.sheets.clock.utils.UtilsKt.convertTimeTextValuesIntoTime(UtilsKt.java:73)
       at com.maxkeppeler.sheets.clock.ClockState.getTimeOfTextValues(ClockState.kt:74)
       at com.maxkeppeler.sheets.clock.ClockState.refreshTimeValue(ClockState.kt:95)
       at com.maxkeppeler.sheets.clock.ClockState.onEnterValue(ClockState.java:114)
       at com.maxkeppeler.sheets.clock.ClockViewKt$ClockView$1$3.invoke(ClockView.kt:68)
       at com.maxkeppeler.sheets.clock.ClockViewKt$ClockView$1$3.invoke(ClockView.kt:68)
       at com.maxkeppeler.sheets.clock.views.KeyItemComponentKt$KeyItemComponent$2.invoke(KeyItemComponent.kt:102)
       at com.maxkeppeler.sheets.clock.views.KeyItemComponentKt$KeyItemComponent$2.invoke(KeyItemComponent.kt:95)
       at androidx.compose.foundation.ClickableKt$clickable$4$gesture$1$1$2.invoke-k-4lQ0M(Clickable.kt:167)
       at androidx.compose.foundation.ClickableKt$clickable$4$gesture$1$1$2.invoke(Clickable.kt:156)
       at androidx.compose.foundation.gestures.TapGestureDetectorKt$detectTapAndPress$2$1.invokeSuspend(TapGestureDetector.kt:255)
       at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
       at kotlinx.coroutines.DispatchedTaskKt.resume(DispatchedTaskKt.java:178)
       at kotlinx.coroutines.DispatchedTaskKt.dispatch(DispatchedTaskKt.java:166)
       at kotlinx.coroutines.CancellableContinuationImpl.dispatchResume(CancellableContinuationImpl.kt:397)
       at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl(CancellableContinuationImpl.kt:431)
       at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl$default(CancellableContinuationImpl.kt:420)
       at kotlinx.coroutines.CancellableContinuationImpl.resumeWith(CancellableContinuationImpl.kt:328)
       at androidx.compose.ui.input.pointer.SuspendingPointerInputFilter$PointerEventHandlerCoroutine.offerPointerEvent(SuspendingPointerInputFilter.java:566)
       at androidx.compose.ui.input.pointer.SuspendingPointerInputFilter.dispatchPointerEvent(SuspendingPointerInputFilter.kt:456)
       at androidx.compose.ui.Modifier$Node.isKind-H91voCI$ui_release(Modifier.java:201)
       at androidx.compose.ui.input.pointer.SuspendingPointerInputFilter.onPointerEvent-H0pRuoY(SuspendingPointerInputFilter.java:120)
       at androidx.compose.ui.node.BackwardsCompatNode.onPointerEvent-H0pRuoY(BackwardsCompatNode.kt:370)
       at androidx.compose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:314)
       at androidx.compose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:301)
       at androidx.compose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:301)
       at androidx.compose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:301)
       at androidx.compose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:301)
       at androidx.compose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:301)
       at androidx.compose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:301)
       at androidx.compose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:301)
       at androidx.compose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:301)
       at androidx.compose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:301)
       at androidx.compose.ui.input.pointer.NodeParent.dispatchMainEventPass(HitPathTracker.kt:183)
       at androidx.compose.ui.input.pointer.HitPathTracker.dispatchChanges(HitPathTracker.java:102)
       at androidx.compose.ui.input.pointer.PointerInputEventProcessor.process-BIzXfog(PointerInputEventProcessor.kt:98)
       at androidx.compose.ui.platform.AndroidComposeView.sendMotionEvent-8iAsVTc(AndroidComposeView.android.kt:1343)
       at androidx.compose.ui.platform.AndroidComposeView.handleMotionEvent-8iAsVTc(AndroidComposeView.android.kt:1289)
       at androidx.compose.ui.platform.AndroidComposeView.dispatchTouchEvent(AndroidComposeView.android.kt:1228)
       at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2968)
       at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2657)
       at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2968)
       at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2657)
       at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2968)
       at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2657)
       at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2968)
       at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2657)
       at com.android.internal.policy.DecorView.superDispatchTouchEvent(DecorView.java:448)
       at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1829)
       at android.app.Dialog.dispatchTouchEvent(Dialog.java:815)
       at com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:410)
       at android.view.View.dispatchPointerEvent(View.java:12016)
       at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:4809)
       at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4623)
       at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4161)
       at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4214)
       at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4180)
       at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:4307)
       at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4188)
       at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:4364)
       at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4161)
       at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4214)
       at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4180)
       at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4188)
       at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4161)
       at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:6682)
       at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:6656)
       at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:6617)
       at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:6785)
       at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:187)
       at android.os.MessageQueue.nativePollOnce(MessageQueue.java)
       at android.os.MessageQueue.next(MessageQueue.java:325)
       at android.os.Looper.loop(Looper.java:142)
       at android.app.ActivityThread.main(ActivityThread.java:6518)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)

This is all I have to go with. I can't repro this issue myself.

maxkeppeler commented 1 year ago

The user clicked the 7 & 9 key at exactly the same time right after opening the dialog.

Nek-12 commented 1 year ago

Just reproduced. I have no idea how you figured this out, but it should be an easy fix

maxkeppeler commented 1 year ago

Well. Apparently it's easy... but way more difficult to fix. I tried pointerInput & pointerInteropFilter solutions, but had no success. Either it works but breaks the interactionSource for the animation, or the ripple animation or keeps having the simultaneous touch crash.

It would have been a nice solution to use a Modifier function to fix this. I couldn't figure it out. My current quick fix is to block the calls to a later point, in the ClockState with the onEnterValue function.

Doesn't look nice, but would fix it. Didn't expect it to be so difficult to just simply block simultaneous clicks while keeping all the normal behaviors working.