Skip to content

Commit

Permalink
Backport rotary updates (#1742)
Browse files Browse the repository at this point in the history
  • Loading branch information
yschimke authored Oct 6, 2023
1 parent 5f54009 commit 0ddfeb7
Show file tree
Hide file tree
Showing 11 changed files with 373 additions and 204 deletions.
30 changes: 20 additions & 10 deletions compose-layout/api/current.api
Original file line number Diff line number Diff line change
Expand Up @@ -311,9 +311,11 @@ package com.google.android.horologist.compose.rotaryinput {

@com.google.android.horologist.annotations.ExperimentalHorologistApi public final class DefaultSnapBehavior implements com.google.android.horologist.compose.rotaryinput.RotarySnapBehavior {
ctor public DefaultSnapBehavior(com.google.android.horologist.compose.rotaryinput.RotaryScrollAdapter rotaryScrollAdapter, com.google.android.horologist.compose.rotaryinput.SnapParameters snapParameters);
method public boolean bottomEdgeReached();
method @com.google.android.horologist.annotations.ExperimentalHorologistApi public void prepareSnapForItems(int moveForElements, boolean sequentialSnap);
method @com.google.android.horologist.annotations.ExperimentalHorologistApi public float snapThreshold(boolean duringSnap);
method @com.google.android.horologist.annotations.ExperimentalHorologistApi public suspend Object? startSnappingSession(boolean toClosestItem, kotlin.coroutines.Continuation<? super kotlin.Unit>);
method public suspend Object? snapToClosestItem(kotlin.coroutines.Continuation<? super kotlin.Unit>);
method public suspend Object? snapToTargetItem(kotlin.coroutines.Continuation<? super kotlin.Unit>);
method public boolean topEdgeReached();
}

public final class GenericMotionRotaryInputAccumulator {
Expand All @@ -330,7 +332,7 @@ package com.google.android.horologist.compose.rotaryinput {
@com.google.android.horologist.annotations.ExperimentalHorologistApi public final class RotaryDefaults {
method @androidx.compose.runtime.Composable @com.google.android.horologist.annotations.ExperimentalHorologistApi public boolean isLowResInput();
method @androidx.compose.runtime.Composable @com.google.android.horologist.annotations.ExperimentalHorologistApi public com.google.android.horologist.compose.rotaryinput.RotaryScrollHandler rememberFlingHandler(androidx.compose.foundation.gestures.ScrollableState scrollableState, optional androidx.compose.foundation.gestures.FlingBehavior? flingBehavior, optional boolean isLowRes);
method @androidx.compose.runtime.Composable @com.google.android.horologist.annotations.ExperimentalHorologistApi public com.google.android.horologist.compose.rotaryinput.RotaryScrollHandler rememberSnapHandler(com.google.android.horologist.compose.rotaryinput.RotaryScrollAdapter rotaryScrollAdapter, optional com.google.android.horologist.compose.rotaryinput.SnapParameters snapParameters);
method @androidx.compose.runtime.Composable @com.google.android.horologist.annotations.ExperimentalHorologistApi public com.google.android.horologist.compose.rotaryinput.RotaryScrollHandler rememberSnapHandler(com.google.android.horologist.compose.rotaryinput.RotaryScrollAdapter rotaryScrollAdapter, optional com.google.android.horologist.compose.rotaryinput.SnapParameters snapParameters, optional boolean isLowRes);
method @com.google.android.horologist.annotations.ExperimentalHorologistApi public com.google.android.horologist.compose.rotaryinput.SnapParameters snapParametersDefault();
field public static final com.google.android.horologist.compose.rotaryinput.RotaryDefaults INSTANCE;
}
Expand Down Expand Up @@ -374,10 +376,10 @@ package com.google.android.horologist.compose.rotaryinput {

public final class RotaryKt {
method @com.google.android.horologist.annotations.ExperimentalHorologistApi public static kotlinx.coroutines.flow.Flow<com.google.android.horologist.compose.rotaryinput.TimestampedDelta> batchRequestsWithinTimeframe(kotlinx.coroutines.flow.Flow<com.google.android.horologist.compose.rotaryinput.TimestampedDelta>, long timeframe);
method @com.google.android.horologist.annotations.ExperimentalHorologistApi public static androidx.compose.ui.Modifier rotaryHandler(androidx.compose.ui.Modifier, com.google.android.horologist.compose.rotaryinput.RotaryScrollHandler rotaryScrollHandler, optional long batchTimeframe, boolean reverseDirection, com.google.android.horologist.compose.rotaryinput.RotaryHapticHandler rotaryHaptics);
method @androidx.compose.runtime.Composable @com.google.android.horologist.annotations.ExperimentalHorologistApi public static androidx.compose.ui.Modifier rotaryWithFling(androidx.compose.ui.Modifier, androidx.compose.ui.focus.FocusRequester focusRequester, androidx.compose.foundation.gestures.ScrollableState scrollableState, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, optional com.google.android.horologist.compose.rotaryinput.RotaryHapticHandler rotaryHaptics, optional boolean reverseDirection);
method @androidx.compose.runtime.Composable @com.google.android.horologist.annotations.ExperimentalHorologistApi public static androidx.compose.ui.Modifier rotaryWithScroll(androidx.compose.ui.Modifier, androidx.compose.ui.focus.FocusRequester focusRequester, androidx.compose.foundation.gestures.ScrollableState scrollableState, optional com.google.android.horologist.compose.rotaryinput.RotaryHapticHandler rotaryHaptics, optional boolean reverseDirection);
method @androidx.compose.runtime.Composable @com.google.android.horologist.annotations.ExperimentalHorologistApi public static androidx.compose.ui.Modifier rotaryWithSnap(androidx.compose.ui.Modifier, androidx.compose.ui.focus.FocusRequester focusRequester, com.google.android.horologist.compose.rotaryinput.RotaryScrollAdapter rotaryScrollAdapter, optional com.google.android.horologist.compose.rotaryinput.RotaryHapticHandler rotaryHaptics, optional boolean reverseDirection);
method @com.google.android.horologist.annotations.ExperimentalHorologistApi public static androidx.compose.ui.Modifier rotaryHandler(androidx.compose.ui.Modifier, com.google.android.horologist.compose.rotaryinput.RotaryScrollHandler rotaryScrollHandler, boolean reverseDirection, com.google.android.horologist.compose.rotaryinput.RotaryHapticHandler rotaryHaptics);
method @Deprecated @androidx.compose.runtime.Composable @com.google.android.horologist.annotations.ExperimentalHorologistApi public static androidx.compose.ui.Modifier rotaryWithFling(androidx.compose.ui.Modifier, androidx.compose.ui.focus.FocusRequester focusRequester, androidx.compose.foundation.gestures.ScrollableState scrollableState, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, optional com.google.android.horologist.compose.rotaryinput.RotaryHapticHandler rotaryHaptics, optional boolean reverseDirection);
method @androidx.compose.runtime.Composable @com.google.android.horologist.annotations.ExperimentalHorologistApi public static androidx.compose.ui.Modifier rotaryWithScroll(androidx.compose.ui.Modifier, androidx.compose.foundation.gestures.ScrollableState scrollableState, optional androidx.compose.ui.focus.FocusRequester focusRequester, optional androidx.compose.foundation.gestures.FlingBehavior? flingBehavior, optional com.google.android.horologist.compose.rotaryinput.RotaryHapticHandler rotaryHaptics, optional boolean reverseDirection);
method @androidx.compose.runtime.Composable @com.google.android.horologist.annotations.ExperimentalHorologistApi public static androidx.compose.ui.Modifier rotaryWithSnap(androidx.compose.ui.Modifier, com.google.android.horologist.compose.rotaryinput.RotaryScrollAdapter rotaryScrollAdapter, optional androidx.compose.ui.focus.FocusRequester focusRequester, optional com.google.android.horologist.compose.rotaryinput.SnapParameters snapParameters, optional com.google.android.horologist.compose.rotaryinput.RotaryHapticHandler rotaryHaptics, optional boolean reverseDirection);
method @com.google.android.horologist.annotations.ExperimentalHorologistApi public static com.google.android.horologist.compose.rotaryinput.RotaryScrollAdapter toRotaryScrollAdapter(androidx.wear.compose.foundation.lazy.ScalingLazyListState);
}

Expand All @@ -386,6 +388,7 @@ package com.google.android.horologist.compose.rotaryinput {
method @com.google.android.horologist.annotations.ExperimentalHorologistApi public int currentItemIndex();
method @com.google.android.horologist.annotations.ExperimentalHorologistApi public float currentItemOffset();
method public androidx.compose.foundation.gestures.ScrollableState getScrollableState();
method @com.google.android.horologist.annotations.ExperimentalHorologistApi public int totalItemsCount();
property public abstract androidx.compose.foundation.gestures.ScrollableState scrollableState;
}

Expand All @@ -398,9 +401,11 @@ package com.google.android.horologist.compose.rotaryinput {
}

@com.google.android.horologist.annotations.ExperimentalHorologistApi public interface RotarySnapBehavior {
method public boolean bottomEdgeReached();
method public void prepareSnapForItems(int moveForElements, boolean sequentialSnap);
method @com.google.android.horologist.annotations.ExperimentalHorologistApi public float snapThreshold(boolean duringSnap);
method @com.google.android.horologist.annotations.ExperimentalHorologistApi public suspend Object? startSnappingSession(boolean toClosestItem, kotlin.coroutines.Continuation<? super kotlin.Unit>);
method public suspend Object? snapToClosestItem(kotlin.coroutines.Continuation<? super kotlin.Unit>);
method public suspend Object? snapToTargetItem(kotlin.coroutines.Continuation<? super kotlin.Unit>);
method public boolean topEdgeReached();
}

public final class RotaryVelocityTracker {
Expand All @@ -418,14 +423,19 @@ package com.google.android.horologist.compose.rotaryinput {
method public int currentItemIndex();
method public float currentItemOffset();
method public androidx.wear.compose.foundation.lazy.ScalingLazyListState getScrollableState();
method public int totalItemsCount();
property public androidx.wear.compose.foundation.lazy.ScalingLazyListState scrollableState;
}

public final class SnapParameters {
ctor public SnapParameters(int snapOffset);
ctor public SnapParameters(int snapOffset, float thresholdDivider, float resistanceFactor);
method public float getResistanceFactor();
method public int getSnapOffset();
method public float getThresholdDivider();
method @androidx.compose.runtime.Composable public float snapOffsetDp();
property public final float resistanceFactor;
property public final int snapOffset;
property public final float thresholdDivider;
}

@com.google.android.horologist.annotations.ExperimentalHorologistApi public final class TimestampedDelta {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ import com.google.android.horologist.annotations.ExperimentalHorologistApi
import com.google.android.horologist.compose.layout.ScalingLazyColumnState.RotaryMode
import com.google.android.horologist.compose.rotaryinput.rememberDisabledHaptic
import com.google.android.horologist.compose.rotaryinput.rememberRotaryHapticHandler
import com.google.android.horologist.compose.rotaryinput.rotaryWithFling
import com.google.android.horologist.compose.rotaryinput.rotaryWithScroll
import com.google.android.horologist.compose.rotaryinput.rotaryWithSnap
import com.google.android.horologist.compose.rotaryinput.toRotaryScrollAdapter
Expand Down Expand Up @@ -137,14 +136,7 @@ public fun ScalingLazyColumn(
rotaryHaptics = rotaryHaptics
)

RotaryMode.Fling -> modifier.rotaryWithFling(
focusRequester = focusRequester,
scrollableState = columnState.state,
reverseDirection = columnState.reverseLayout,
rotaryHaptics = rotaryHaptics
)

RotaryMode.Scroll -> modifier.rotaryWithScroll(
else -> modifier.rotaryWithScroll(
focusRequester = focusRequester,
scrollableState = columnState.state,
reverseDirection = columnState.reverseLayout,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ public fun rememberDisabledHaptic(): RotaryHapticHandler = remember {
@Composable
public fun rememberRotaryHapticHandler(
scrollableState: ScrollableState,
throttleThresholdMs: Long = 40,
throttleThresholdMs: Long = 30,
hapticsThresholdPx: Long = 50,
hapticsChannel: Channel<RotaryHapticsType> = rememberHapticChannel(),
rotaryHaptics: RotaryHapticFeedback = rememberDefaultRotaryHapticFeedback()
Expand Down Expand Up @@ -309,8 +309,11 @@ private class PixelWatchRotaryHapticFeedback(private val view: View) : RotaryHap
when (type) {
RotaryHapticsType.ScrollItemFocus -> {
view.performHapticFeedback(
if (Build.VERSION.SDK_INT >= 33) ROTARY_SCROLL_ITEM_FOCUS
else WEAR_SCROLL_ITEM_FOCUS
if (Build.VERSION.SDK_INT >= 33) {
ROTARY_SCROLL_ITEM_FOCUS
} else {
WEAR_SCROLL_ITEM_FOCUS
}
)
}

Expand Down Expand Up @@ -343,7 +346,7 @@ private class PixelWatchRotaryHapticFeedback(private val view: View) : RotaryHap
}

/**
* Implementation of [RotaryHapticFeedback] for Galaxy Watch 4 Classic
* Implementation of [RotaryHapticFeedback] for Galaxy Watch 4 and 6 Classic
*/
@ExperimentalHorologistApi
private class GalaxyWatchClassicHapticFeedback(private val view: View) : RotaryHapticFeedback {
Expand All @@ -369,7 +372,7 @@ private class GalaxyWatchClassicHapticFeedback(private val view: View) : RotaryH
}

private fun isGalaxyWatchClassic(): Boolean =
Build.MODEL.matches("SM-R8[89]5.".toRegex())
Build.MODEL.matches("SM-R(?:8[89][05]|9[56][05])".toRegex())

private fun isGooglePixelWatch(): Boolean =
Build.MODEL.startsWith("Google Pixel Watch")
Loading

0 comments on commit 0ddfeb7

Please sign in to comment.