diff --git a/.editorconfig b/.editorconfig index 32477c4..3a4759f 100644 --- a/.editorconfig +++ b/.editorconfig @@ -39,6 +39,7 @@ ij_kotlin_code_style_defaults = KOTLIN_OFFICIAL # https://youtrack.jetbrains.com/issue/KTIJ-17907 ij_continuation_indent_size = 4 +ij_kotlin_indent_before_arrow_on_new_line = true # Trailing comma ij_kotlin_allow_trailing_comma_on_call_site = true diff --git a/.run/Run Desktop App.run.xml b/.run/Run Desktop App.run.xml new file mode 100644 index 0000000..72667df --- /dev/null +++ b/.run/Run Desktop App.run.xml @@ -0,0 +1,27 @@ + + + + + + + false + true + false + false + false + false + false + + + \ No newline at end of file diff --git a/ComposeCollapsingTopBar/api/jvm/ComposeCollapsingTopBar.api b/ComposeCollapsingTopBar/api/jvm/ComposeCollapsingTopBar.api new file mode 100644 index 0000000..5c8a20a --- /dev/null +++ b/ComposeCollapsingTopBar/api/jvm/ComposeCollapsingTopBar.api @@ -0,0 +1,362 @@ +public abstract interface class com/flaringapp/compose/topbar/CollapsingTopBarControls { + public static final field Companion Lcom/flaringapp/compose/topbar/CollapsingTopBarControls$Companion; + public fun animateHeightTo (Landroidx/compose/foundation/gestures/ScrollScope;FFLandroidx/compose/animation/core/AnimationSpec;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun animateHeightTo (Landroidx/compose/foundation/gestures/ScrollableState;FFLandroidx/compose/animation/core/AnimationSpec;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public abstract fun collapse (Landroidx/compose/animation/core/AnimationSpec;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static synthetic fun collapse$default (Lcom/flaringapp/compose/topbar/CollapsingTopBarControls;Landroidx/compose/animation/core/AnimationSpec;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object; + public abstract fun expand (Landroidx/compose/animation/core/AnimationSpec;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static synthetic fun expand$default (Lcom/flaringapp/compose/topbar/CollapsingTopBarControls;Landroidx/compose/animation/core/AnimationSpec;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object; +} + +public final class com/flaringapp/compose/topbar/CollapsingTopBarControls$Companion { + public final fun getDefaultAnimationSpec ()Landroidx/compose/animation/core/AnimationSpec; +} + +public final class com/flaringapp/compose/topbar/CollapsingTopBarControls$DefaultImpls { + public static fun animateHeightTo (Lcom/flaringapp/compose/topbar/CollapsingTopBarControls;Landroidx/compose/foundation/gestures/ScrollScope;FFLandroidx/compose/animation/core/AnimationSpec;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun animateHeightTo (Lcom/flaringapp/compose/topbar/CollapsingTopBarControls;Landroidx/compose/foundation/gestures/ScrollableState;FFLandroidx/compose/animation/core/AnimationSpec;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static synthetic fun collapse$default (Lcom/flaringapp/compose/topbar/CollapsingTopBarControls;Landroidx/compose/animation/core/AnimationSpec;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object; + public static synthetic fun expand$default (Lcom/flaringapp/compose/topbar/CollapsingTopBarControls;Landroidx/compose/animation/core/AnimationSpec;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object; +} + +public final class com/flaringapp/compose/topbar/CollapsingTopBarKt { + public static final fun CollapsingTopBar (Landroidx/compose/ui/Modifier;Lcom/flaringapp/compose/topbar/CollapsingTopBarState;ZLkotlin/jvm/functions/Function3;Landroidx/compose/runtime/Composer;II)V +} + +public final class com/flaringapp/compose/topbar/CollapsingTopBarLayoutInfo { + public static final field $stable I + public fun (FII)V + public final fun component1 ()F + public final fun component2 ()I + public final fun component3 ()I + public final fun copy (FII)Lcom/flaringapp/compose/topbar/CollapsingTopBarLayoutInfo; + public static synthetic fun copy$default (Lcom/flaringapp/compose/topbar/CollapsingTopBarLayoutInfo;FIIILjava/lang/Object;)Lcom/flaringapp/compose/topbar/CollapsingTopBarLayoutInfo; + public fun equals (Ljava/lang/Object;)Z + public final fun getCollapseHeightDelta ()F + public final fun getCollapseProgress ()F + public final fun getCollapsedHeight ()I + public final fun getCollapsibleDistance ()I + public final fun getExpandHeightDelta ()F + public final fun getExpandedHeight ()I + public final fun getHeight ()F + public fun hashCode ()I + public final fun isCollapsed ()Z + public final fun isExpanded ()Z + public fun toString ()Ljava/lang/String; +} + +public abstract interface class com/flaringapp/compose/topbar/CollapsingTopBarProgressListener { + public abstract fun onProgressUpdate (FF)V +} + +public abstract interface class com/flaringapp/compose/topbar/CollapsingTopBarScope { + public abstract fun align (Landroidx/compose/ui/Modifier;Landroidx/compose/ui/Alignment;)Landroidx/compose/ui/Modifier; + public abstract fun floating (Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier; + public abstract fun nestedCollapse (Landroidx/compose/ui/Modifier;Lcom/flaringapp/compose/topbar/nestedcollapse/CollapsingTopBarNestedCollapseElement;)Landroidx/compose/ui/Modifier; + public abstract fun parallax (Landroidx/compose/ui/Modifier;F)Landroidx/compose/ui/Modifier; + public abstract fun pin (Landroidx/compose/ui/Modifier;Z)Landroidx/compose/ui/Modifier; + public static synthetic fun pin$default (Lcom/flaringapp/compose/topbar/CollapsingTopBarScope;Landroidx/compose/ui/Modifier;ZILjava/lang/Object;)Landroidx/compose/ui/Modifier; + public abstract fun progress (Landroidx/compose/ui/Modifier;Lcom/flaringapp/compose/topbar/CollapsingTopBarProgressListener;)Landroidx/compose/ui/Modifier; +} + +public final class com/flaringapp/compose/topbar/CollapsingTopBarScope$DefaultImpls { + public static synthetic fun pin$default (Lcom/flaringapp/compose/topbar/CollapsingTopBarScope;Landroidx/compose/ui/Modifier;ZILjava/lang/Object;)Landroidx/compose/ui/Modifier; +} + +public final class com/flaringapp/compose/topbar/CollapsingTopBarState : androidx/compose/foundation/gestures/ScrollableState, com/flaringapp/compose/topbar/CollapsingTopBarControls, com/flaringapp/compose/topbar/snap/CollapsingTopBarSnapScope { + public static final field $stable I + public static final field Companion Lcom/flaringapp/compose/topbar/CollapsingTopBarState$Companion; + public fun (Z)V + public synthetic fun (ZILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun animateHeightTo (Landroidx/compose/foundation/gestures/ScrollScope;FFLandroidx/compose/animation/core/AnimationSpec;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun animateHeightTo (Landroidx/compose/foundation/gestures/ScrollableState;FFLandroidx/compose/animation/core/AnimationSpec;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun collapse (Landroidx/compose/animation/core/AnimationSpec;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun dispatchRawDelta (F)F + public fun expand (Landroidx/compose/animation/core/AnimationSpec;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun getCanScrollBackward ()Z + public fun getCanScrollForward ()Z + public final fun getHasMeasured ()Z + public fun getLastScrolledBackward ()Z + public fun getLastScrolledForward ()Z + public final fun getLayoutInfo ()Lcom/flaringapp/compose/topbar/CollapsingTopBarLayoutInfo; + public fun getScrollIndicatorState ()Landroidx/compose/foundation/ScrollIndicatorState; + public final fun isCollapsed ()Z + public final fun isExpanded ()Z + public fun isScrollInProgress ()Z + public fun scroll (Landroidx/compose/foundation/MutatePriority;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun snapWithProgress (ZLkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; +} + +public final class com/flaringapp/compose/topbar/CollapsingTopBarState$Companion { + public final fun getSaver ()Landroidx/compose/runtime/saveable/Saver; +} + +public final class com/flaringapp/compose/topbar/CollapsingTopBarStateKt { + public static final fun rememberCollapsingTopBarState (ZLandroidx/compose/runtime/Composer;II)Lcom/flaringapp/compose/topbar/CollapsingTopBarState; +} + +public final class com/flaringapp/compose/topbar/decoration/CollapsingTopBarVerticalFadingEdgeKt { + public static final fun CollapsingTopBarVerticalFadingEdge-YJYuY3k (JLandroidx/compose/ui/Modifier;FZLandroidx/compose/runtime/Composer;II)V +} + +public final class com/flaringapp/compose/topbar/dependent/CollapsingTopBarDependentStateConnectionKt { + public static final fun collapsingTopBarDependentStateConnection (Landroidx/compose/ui/Modifier;Lcom/flaringapp/compose/topbar/CollapsingTopBarState;Lkotlin/jvm/functions/Function1;)Landroidx/compose/ui/Modifier; +} + +public final class com/flaringapp/compose/topbar/dependent/CollapsingTopBarExitState : androidx/compose/foundation/gestures/ScrollableState, com/flaringapp/compose/topbar/CollapsingTopBarControls, com/flaringapp/compose/topbar/snap/CollapsingTopBarSnapScope { + public static final field $stable I + public static final field Companion Lcom/flaringapp/compose/topbar/dependent/CollapsingTopBarExitState$Companion; + public fun (Z)V + public synthetic fun (ZILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun animateHeightTo (Landroidx/compose/foundation/gestures/ScrollScope;FFLandroidx/compose/animation/core/AnimationSpec;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun animateHeightTo (Landroidx/compose/foundation/gestures/ScrollableState;FFLandroidx/compose/animation/core/AnimationSpec;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun collapse (Landroidx/compose/animation/core/AnimationSpec;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun dispatchRawDelta (F)F + public fun expand (Landroidx/compose/animation/core/AnimationSpec;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun getCanScrollBackward ()Z + public fun getCanScrollForward ()Z + public final fun getCollapsedHeight ()F + public final fun getExitHeight ()F + public final fun getExitProgress ()F + public fun getLastScrolledBackward ()Z + public fun getLastScrolledForward ()Z + public fun getScrollIndicatorState ()Landroidx/compose/foundation/ScrollIndicatorState; + public final fun isEnabled ()Z + public final fun isFullyEntered ()Z + public final fun isFullyExited ()Z + public fun isScrollInProgress ()Z + public final fun reset ()V + public fun scroll (Landroidx/compose/foundation/MutatePriority;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun snapWithProgress (ZLkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; +} + +public final class com/flaringapp/compose/topbar/dependent/CollapsingTopBarExitState$Companion { + public final fun getSaver ()Landroidx/compose/runtime/saveable/Saver; +} + +public final class com/flaringapp/compose/topbar/dependent/CollapsingTopBarExitStateKt { + public static final fun collapsingTopBarExitStateConnection (Landroidx/compose/ui/Modifier;Lcom/flaringapp/compose/topbar/CollapsingTopBarState;Lcom/flaringapp/compose/topbar/dependent/CollapsingTopBarExitState;)Landroidx/compose/ui/Modifier; + public static final fun rememberCollapsingTopBarExitState (ZLandroidx/compose/runtime/Composer;II)Lcom/flaringapp/compose/topbar/dependent/CollapsingTopBarExitState; +} + +public abstract class com/flaringapp/compose/topbar/nestedcollapse/CollapsingTopBarColumnDirection { + public static final field $stable I +} + +public final class com/flaringapp/compose/topbar/nestedcollapse/CollapsingTopBarColumnDirection$BottomUp : com/flaringapp/compose/topbar/nestedcollapse/CollapsingTopBarColumnDirection { + public static final field $stable I + public static final field INSTANCE Lcom/flaringapp/compose/topbar/nestedcollapse/CollapsingTopBarColumnDirection$BottomUp; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class com/flaringapp/compose/topbar/nestedcollapse/CollapsingTopBarColumnDirection$TopToBottom : com/flaringapp/compose/topbar/nestedcollapse/CollapsingTopBarColumnDirection { + public static final field $stable I + public static final field INSTANCE Lcom/flaringapp/compose/topbar/nestedcollapse/CollapsingTopBarColumnDirection$TopToBottom; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class com/flaringapp/compose/topbar/nestedcollapse/CollapsingTopBarColumnKt { + public static final fun CollapsingTopBarColumn (Lcom/flaringapp/compose/topbar/CollapsingTopBarScope;Lcom/flaringapp/compose/topbar/CollapsingTopBarState;Landroidx/compose/ui/Modifier;Lcom/flaringapp/compose/topbar/nestedcollapse/CollapsingTopBarColumnDirection;Lkotlin/jvm/functions/Function3;Landroidx/compose/runtime/Composer;II)V +} + +public abstract interface class com/flaringapp/compose/topbar/nestedcollapse/CollapsingTopBarColumnScope { + public abstract fun align (Landroidx/compose/ui/Modifier;Landroidx/compose/ui/Alignment$Horizontal;)Landroidx/compose/ui/Modifier; + public abstract fun clipToCollapse (Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier; + public abstract fun columnProgress (Landroidx/compose/ui/Modifier;Lcom/flaringapp/compose/topbar/CollapsingTopBarProgressListener;)Landroidx/compose/ui/Modifier; + public abstract fun notCollapsible (Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier; + public abstract fun pinWhenCollapsed (Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier; +} + +public abstract interface class com/flaringapp/compose/topbar/nestedcollapse/CollapsingTopBarNestedCollapseElement { + public abstract fun getMinHeight ()I +} + +public final class com/flaringapp/compose/topbar/nestedcollapse/CollapsingTopBarNestedCollapseState : com/flaringapp/compose/topbar/nestedcollapse/CollapsingTopBarNestedCollapseElement { + public static final field $stable I + public fun ()V + public fun getMinHeight ()I + public fun setMinHeight (I)V +} + +public final class com/flaringapp/compose/topbar/nestedcollapse/CollapsingTopBarNestedCollapseStateKt { + public static final fun rememberCollapsingTopBarNestedCollapseState (Landroidx/compose/runtime/Composer;I)Lcom/flaringapp/compose/topbar/nestedcollapse/CollapsingTopBarNestedCollapseState; +} + +public final class com/flaringapp/compose/topbar/nestedscroll/CollapsingTopBarNestedScrollCollapse : com/flaringapp/compose/topbar/nestedscroll/CollapsingTopBarNestedScrollHandler { + public static final field $stable I + public fun (Landroidx/compose/foundation/gestures/ScrollableState;Landroidx/compose/foundation/gestures/FlingBehavior;)V + public fun fling (Landroidx/compose/foundation/gestures/ScrollableState;Landroidx/compose/foundation/gestures/FlingBehavior;FLkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun onPostFling-RZ2iAVY (JJLkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun onPostScroll-DzOQY0M (JJI)J + public fun onPreFling-QWom1Mo (JLkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun onPreScroll-OzD1aCk (JI)J +} + +public abstract class com/flaringapp/compose/topbar/nestedscroll/CollapsingTopBarNestedScrollExpand : com/flaringapp/compose/topbar/nestedscroll/CollapsingTopBarNestedScrollHandler { + public static final field $stable I + public static final field Companion Lcom/flaringapp/compose/topbar/nestedscroll/CollapsingTopBarNestedScrollExpand$Companion; + public fun ()V + protected final fun expand-MK-Hz9U (J)J + protected final fun expand-QWom1Mo (JLkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun fling (Landroidx/compose/foundation/gestures/ScrollableState;Landroidx/compose/foundation/gestures/FlingBehavior;FLkotlin/coroutines/Continuation;)Ljava/lang/Object; + public abstract fun getFlingBehavior ()Landroidx/compose/foundation/gestures/FlingBehavior; + public abstract fun getState ()Landroidx/compose/foundation/gestures/ScrollableState; + public fun onPostFling-RZ2iAVY (JJLkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun onPostScroll-DzOQY0M (JJI)J + public fun onPreFling-QWom1Mo (JLkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun onPreScroll-OzD1aCk (JI)J +} + +public final class com/flaringapp/compose/topbar/nestedscroll/CollapsingTopBarNestedScrollExpand$Always : com/flaringapp/compose/topbar/nestedscroll/CollapsingTopBarNestedScrollExpand { + public static final field $stable I + public fun (Landroidx/compose/foundation/gestures/ScrollableState;Landroidx/compose/foundation/gestures/FlingBehavior;)V + public fun getFlingBehavior ()Landroidx/compose/foundation/gestures/FlingBehavior; + public fun getState ()Landroidx/compose/foundation/gestures/ScrollableState; + public fun onPreFling-QWom1Mo (JLkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun onPreScroll-OzD1aCk (JI)J +} + +public final class com/flaringapp/compose/topbar/nestedscroll/CollapsingTopBarNestedScrollExpand$AtTop : com/flaringapp/compose/topbar/nestedscroll/CollapsingTopBarNestedScrollExpand { + public static final field $stable I + public fun (Landroidx/compose/foundation/gestures/ScrollableState;Landroidx/compose/foundation/gestures/FlingBehavior;)V + public fun getFlingBehavior ()Landroidx/compose/foundation/gestures/FlingBehavior; + public fun getState ()Landroidx/compose/foundation/gestures/ScrollableState; + public fun onPostFling-RZ2iAVY (JJLkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun onPostScroll-DzOQY0M (JJI)J +} + +public final class com/flaringapp/compose/topbar/nestedscroll/CollapsingTopBarNestedScrollExpand$Companion { + public final fun of (Landroidx/compose/foundation/gestures/ScrollableState;Landroidx/compose/foundation/gestures/FlingBehavior;Z)Lcom/flaringapp/compose/topbar/nestedscroll/CollapsingTopBarNestedScrollHandler; +} + +public abstract interface class com/flaringapp/compose/topbar/nestedscroll/CollapsingTopBarNestedScrollHandler : androidx/compose/ui/input/nestedscroll/NestedScrollConnection { + public fun fling (Landroidx/compose/foundation/gestures/ScrollableState;Landroidx/compose/foundation/gestures/FlingBehavior;FLkotlin/coroutines/Continuation;)Ljava/lang/Object; +} + +public final class com/flaringapp/compose/topbar/nestedscroll/CollapsingTopBarNestedScrollHandler$DefaultImpls { + public static fun fling (Lcom/flaringapp/compose/topbar/nestedscroll/CollapsingTopBarNestedScrollHandler;Landroidx/compose/foundation/gestures/ScrollableState;Landroidx/compose/foundation/gestures/FlingBehavior;FLkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun onPostFling-RZ2iAVY (Lcom/flaringapp/compose/topbar/nestedscroll/CollapsingTopBarNestedScrollHandler;JJLkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun onPostScroll-DzOQY0M (Lcom/flaringapp/compose/topbar/nestedscroll/CollapsingTopBarNestedScrollHandler;JJI)J + public static fun onPreFling-QWom1Mo (Lcom/flaringapp/compose/topbar/nestedscroll/CollapsingTopBarNestedScrollHandler;JLkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun onPreScroll-OzD1aCk (Lcom/flaringapp/compose/topbar/nestedscroll/CollapsingTopBarNestedScrollHandler;JI)J +} + +public final class com/flaringapp/compose/topbar/nestedscroll/CollapsingTopBarNestedScrollSnap : com/flaringapp/compose/topbar/nestedscroll/CollapsingTopBarNestedScrollHandler { + public static final field $stable I + public fun (Lcom/flaringapp/compose/topbar/snap/CollapsingTopBarSnapBehavior;Lcom/flaringapp/compose/topbar/snap/CollapsingTopBarSnapScope;)V + public fun fling (Landroidx/compose/foundation/gestures/ScrollableState;Landroidx/compose/foundation/gestures/FlingBehavior;FLkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun onPostFling-RZ2iAVY (JJLkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun onPostScroll-DzOQY0M (JJI)J + public fun onPreFling-QWom1Mo (JLkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun onPreScroll-OzD1aCk (JI)J +} + +public abstract interface class com/flaringapp/compose/topbar/nestedscroll/CollapsingTopBarNestedScrollStrategy { + public abstract fun createHandlers (Ljava/lang/Object;Landroidx/compose/foundation/gestures/FlingBehavior;Lcom/flaringapp/compose/topbar/snap/CollapsingTopBarSnapBehavior;)Ljava/util/List; +} + +public final class com/flaringapp/compose/topbar/nestedscroll/CollapsingTopBarNestedScrollStrategyKt { + public static final fun rememberNestedScrollConnection (Lcom/flaringapp/compose/topbar/nestedscroll/CollapsingTopBarNestedScrollStrategy;Ljava/lang/Object;Landroidx/compose/foundation/gestures/FlingBehavior;Lcom/flaringapp/compose/topbar/snap/CollapsingTopBarSnapBehavior;Landroidx/compose/runtime/Composer;II)Landroidx/compose/ui/input/nestedscroll/NestedScrollConnection; +} + +public final class com/flaringapp/compose/topbar/nestedscroll/MultiNestedScrollConnection : androidx/compose/ui/input/nestedscroll/NestedScrollConnection { + public static final field $stable I + public fun (Ljava/util/List;)V + public fun onPostFling-RZ2iAVY (JJLkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun onPostScroll-DzOQY0M (JJI)J + public fun onPreFling-QWom1Mo (JLkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun onPreScroll-OzD1aCk (JI)J +} + +public abstract interface class com/flaringapp/compose/topbar/scaffold/CollapsingTopBarScaffoldBodyScope { + public abstract fun resizeWithCollapse (Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier; +} + +public final class com/flaringapp/compose/topbar/scaffold/CollapsingTopBarScaffoldKt { + public static final fun CollapsingTopBarScaffold (Lcom/flaringapp/compose/topbar/scaffold/CollapsingTopBarScaffoldScrollMode;Landroidx/compose/ui/Modifier;Lcom/flaringapp/compose/topbar/scaffold/CollapsingTopBarScaffoldState;ZLcom/flaringapp/compose/topbar/snap/CollapsingTopBarSnapBehavior;Landroidx/compose/ui/Modifier;ZLkotlin/jvm/functions/Function4;Lkotlin/jvm/functions/Function3;Landroidx/compose/runtime/Composer;II)V +} + +public final class com/flaringapp/compose/topbar/scaffold/CollapsingTopBarScaffoldScrollMode : com/flaringapp/compose/topbar/nestedscroll/CollapsingTopBarNestedScrollStrategy { + public static final field $stable I + public static final field Companion Lcom/flaringapp/compose/topbar/scaffold/CollapsingTopBarScaffoldScrollMode$Companion; + public final fun component1 ()Z + public final fun component2 ()Lcom/flaringapp/compose/topbar/scaffold/CollapsingTopBarScaffoldScrollMode$Exit; + public fun createHandlers (Lcom/flaringapp/compose/topbar/scaffold/CollapsingTopBarScaffoldState;Landroidx/compose/foundation/gestures/FlingBehavior;Lcom/flaringapp/compose/topbar/snap/CollapsingTopBarSnapBehavior;)Ljava/util/List; + public synthetic fun createHandlers (Ljava/lang/Object;Landroidx/compose/foundation/gestures/FlingBehavior;Lcom/flaringapp/compose/topbar/snap/CollapsingTopBarSnapBehavior;)Ljava/util/List; + public fun equals (Ljava/lang/Object;)Z + public final fun getCanExit ()Z + public final fun getExit ()Lcom/flaringapp/compose/topbar/scaffold/CollapsingTopBarScaffoldScrollMode$Exit; + public final fun getExpandAlways ()Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class com/flaringapp/compose/topbar/scaffold/CollapsingTopBarScaffoldScrollMode$Companion { + public final fun collapse (ZLandroidx/compose/runtime/Composer;I)Lcom/flaringapp/compose/topbar/scaffold/CollapsingTopBarScaffoldScrollMode; + public final fun collapseAndExit (ZLandroidx/compose/runtime/Composer;I)Lcom/flaringapp/compose/topbar/scaffold/CollapsingTopBarScaffoldScrollMode; + public final fun enterAlwaysCollapsed (Landroidx/compose/runtime/Composer;I)Lcom/flaringapp/compose/topbar/scaffold/CollapsingTopBarScaffoldScrollMode; +} + +public final class com/flaringapp/compose/topbar/scaffold/CollapsingTopBarScaffoldScrollMode$Exit { + public static final field $stable I + public final fun component1 ()Z + public fun equals (Ljava/lang/Object;)Z + public final fun getEnterAlways ()Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class com/flaringapp/compose/topbar/scaffold/CollapsingTopBarScaffoldState : com/flaringapp/compose/topbar/CollapsingTopBarControls, com/flaringapp/compose/topbar/snap/CollapsingTopBarSnapScope { + public static final field $stable I + public static final field Companion Lcom/flaringapp/compose/topbar/scaffold/CollapsingTopBarScaffoldState$Companion; + public fun animateHeightTo (Landroidx/compose/foundation/gestures/ScrollScope;FFLandroidx/compose/animation/core/AnimationSpec;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun animateHeightTo (Landroidx/compose/foundation/gestures/ScrollableState;FFLandroidx/compose/animation/core/AnimationSpec;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun collapse (Landroidx/compose/animation/core/AnimationSpec;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun expand (Landroidx/compose/animation/core/AnimationSpec;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public final fun getExitState ()Lcom/flaringapp/compose/topbar/dependent/CollapsingTopBarExitState; + public final fun getHasMeasured ()Z + public final fun getTopBarState ()Lcom/flaringapp/compose/topbar/CollapsingTopBarState; + public final fun getTotalTopBarHeight ()F + public final fun isCollapsed ()Z + public final fun isExpanded ()Z + public fun snapWithProgress (ZLkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; +} + +public final class com/flaringapp/compose/topbar/scaffold/CollapsingTopBarScaffoldState$Companion { + public final fun getSaver ()Landroidx/compose/runtime/saveable/Saver; +} + +public final class com/flaringapp/compose/topbar/scaffold/CollapsingTopBarScaffoldStateKt { + public static final fun rememberCollapsingTopBarScaffoldState (ZLandroidx/compose/runtime/Composer;II)Lcom/flaringapp/compose/topbar/scaffold/CollapsingTopBarScaffoldState; +} + +public final class com/flaringapp/compose/topbar/snap/CollapsingTopBarNoSnapBehavior : com/flaringapp/compose/topbar/snap/CollapsingTopBarSnapBehavior { + public static final field $stable I + public static final field INSTANCE Lcom/flaringapp/compose/topbar/snap/CollapsingTopBarNoSnapBehavior; + public fun snap (Lcom/flaringapp/compose/topbar/snap/CollapsingTopBarSnapScope;ZLkotlin/coroutines/Continuation;)Ljava/lang/Object; +} + +public abstract interface class com/flaringapp/compose/topbar/snap/CollapsingTopBarSnapBehavior { + public abstract fun snap (Lcom/flaringapp/compose/topbar/snap/CollapsingTopBarSnapScope;ZLkotlin/coroutines/Continuation;)Ljava/lang/Object; +} + +public final class com/flaringapp/compose/topbar/snap/CollapsingTopBarSnapBehaviorKt { + public static final fun rememberCollapsingTopBarSnapBehavior (FLandroidx/compose/animation/core/AnimationSpec;Landroidx/compose/runtime/Composer;II)Lcom/flaringapp/compose/topbar/snap/CollapsingTopBarSnapBehavior; +} + +public abstract interface class com/flaringapp/compose/topbar/snap/CollapsingTopBarSnapScope { + public abstract fun snapWithProgress (ZLkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; +} + +public final class com/flaringapp/compose/topbar/snap/CollapsingTopBarThresholdSnapBehavior : com/flaringapp/compose/topbar/snap/CollapsingTopBarSnapBehavior { + public static final field $stable I + public fun ()V + public fun (FLandroidx/compose/animation/core/AnimationSpec;)V + public synthetic fun (FLandroidx/compose/animation/core/AnimationSpec;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun snap (Lcom/flaringapp/compose/topbar/snap/CollapsingTopBarSnapScope;ZLkotlin/coroutines/Continuation;)Ljava/lang/Object; +} + diff --git a/ComposeCollapsingTopBar/build.gradle.kts b/ComposeCollapsingTopBar/build.gradle.kts index 6a00243..c4992c1 100644 --- a/ComposeCollapsingTopBar/build.gradle.kts +++ b/ComposeCollapsingTopBar/build.gradle.kts @@ -46,6 +46,8 @@ kotlin { } } + jvm() + sourceSets { commonMain.dependencies { implementation(libs.compose.multiplatform.foundation) diff --git a/README.md b/README.md index 1136312..99be9e1 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ ![badge-Android](https://img.shields.io/badge/Platform-Android-forestgreen) ![badge-iOS](https://img.shields.io/badge/Platform-iOS-silver) +![badge-Desktop](https://img.shields.io/badge/Platform-Desktop-dodgerblue) If you like this project, :star: star and :loudspeaker: share it! @@ -739,8 +740,16 @@ This state exposes current exit offset via `exitHeight`. ## More examples -Feel free to install a demo [Android](/sample/android) or [iOS](/sample/ios) app and try yourself -even more samples! +Feel free to install a demo [Android](/sample/android), [iOS](/sample/ios), or +[Desktop](/sample/desktop) app and try yourself even more samples! + +## Known issues + +- On Desktop, a Compose Multiplatform nested scroll bug can prevent the top bar from expanding + with mouse wheel scrolling when using scroll modes with `expandAlways = false`. See + [CMP-10236](https://youtrack.jetbrains.com/issue/CMP-10236). The sample app includes a + [temporary workaround](/sample/shared/src/jvmMain/kotlin/com/flaringapp/compose/topbar/sample/shared/ui/samples/desktopfix/DesktopScrollBoundsNestedScrollFix.jvm.kt) + that can be copied until Compose fixes the issue. ## Contributing diff --git a/build.gradle.kts b/build.gradle.kts index 1f3db4d..0e9363d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,6 +4,7 @@ import org.jlleitschuh.gradle.ktlint.KtlintExtension plugins { alias(libs.plugins.android.application) apply false alias(libs.plugins.android.kotlin.multiplatform.library) apply false + alias(libs.plugins.jetbrains.kotlin.jvm) apply false alias(libs.plugins.jetbrains.kotlin.multiplatform) apply false alias(libs.plugins.jetbrains.kotlin.compose) apply false alias(libs.plugins.jetbrains.compose.multiplatform) apply false diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f39561d..1b5bc24 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -21,6 +21,7 @@ slack-compose-linter = { group = "com.slack.lint.compose", name = "compose-lint- [plugins] android-application = { id = "com.android.application", version.ref = "agp" } android-kotlin-multiplatform-library = { id = "com.android.kotlin.multiplatform.library", version.ref = "agp" } +jetbrains-kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } jetbrains-kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" } jetbrains-kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } jetbrains-compose-multiplatform = { id = "org.jetbrains.compose", version.ref = "composeMultiplatform" } diff --git a/sample/desktop/build.gradle.kts b/sample/desktop/build.gradle.kts new file mode 100644 index 0000000..fd7aece --- /dev/null +++ b/sample/desktop/build.gradle.kts @@ -0,0 +1,25 @@ +import org.jetbrains.compose.desktop.application.dsl.TargetFormat + +plugins { + alias(libs.plugins.jetbrains.kotlin.jvm) + alias(libs.plugins.jetbrains.kotlin.compose) + alias(libs.plugins.jetbrains.compose.multiplatform) +} + +dependencies { + implementation(project(":sample:shared")) + + implementation(compose.desktop.currentOs) +} + +compose.desktop { + application { + mainClass = "com.flaringapp.compose.topbar.sample.desktop.MainKt" + + nativeDistributions { + targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb) + packageName = "com.flaringapp.compose.topbar.sample.desktop" + packageVersion = "1.0.0" + } + } +} diff --git a/sample/desktop/src/main/kotlin/com/flaringapp/compose/topbar/sample/desktop/Main.kt b/sample/desktop/src/main/kotlin/com/flaringapp/compose/topbar/sample/desktop/Main.kt new file mode 100644 index 0000000..2e55a31 --- /dev/null +++ b/sample/desktop/src/main/kotlin/com/flaringapp/compose/topbar/sample/desktop/Main.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2026 Flaringapp + * + * 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. + */ + +package com.flaringapp.compose.topbar.sample.desktop + +import androidx.compose.ui.window.Window +import androidx.compose.ui.window.application +import com.flaringapp.compose.topbar.sample.shared.App + +fun main() = application { + Window( + onCloseRequest = ::exitApplication, + title = "ComposeCollapsingTopBar", + ) { + App() + } +} diff --git a/sample/shared/build.gradle.kts b/sample/shared/build.gradle.kts index b7e9e30..6dccc89 100644 --- a/sample/shared/build.gradle.kts +++ b/sample/shared/build.gradle.kts @@ -28,6 +28,8 @@ kotlin { } } + jvm() + sourceSets { commonMain.dependencies { implementation(project(":ComposeCollapsingTopBar")) diff --git a/sample/shared/src/androidMain/kotlin/com/flaringapp/compose/topbar/sample/shared/ui/samples/desktopfix/DesktopScrollBoundsNestedScrollFix.android.kt b/sample/shared/src/androidMain/kotlin/com/flaringapp/compose/topbar/sample/shared/ui/samples/desktopfix/DesktopScrollBoundsNestedScrollFix.android.kt new file mode 100644 index 0000000..dd560c2 --- /dev/null +++ b/sample/shared/src/androidMain/kotlin/com/flaringapp/compose/topbar/sample/shared/ui/samples/desktopfix/DesktopScrollBoundsNestedScrollFix.android.kt @@ -0,0 +1,25 @@ +/* + * Copyright 2026 Flaringapp + * + * 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. + */ + +package com.flaringapp.compose.topbar.sample.shared.ui.samples.desktopfix + +import androidx.compose.ui.Modifier +import com.flaringapp.compose.topbar.scaffold.CollapsingTopBarScaffoldState + +internal actual fun Modifier.desktopScrollBoundsNestedScrollFix( + state: CollapsingTopBarScaffoldState, + isContentAtTop: () -> Boolean, +): Modifier = this diff --git a/sample/shared/src/appleMain/kotlin/com/flaringapp/compose/topbar/sample/shared/ui/samples/desktopfix/DesktopScrollBoundsNestedScrollFix.apple.kt b/sample/shared/src/appleMain/kotlin/com/flaringapp/compose/topbar/sample/shared/ui/samples/desktopfix/DesktopScrollBoundsNestedScrollFix.apple.kt new file mode 100644 index 0000000..dd560c2 --- /dev/null +++ b/sample/shared/src/appleMain/kotlin/com/flaringapp/compose/topbar/sample/shared/ui/samples/desktopfix/DesktopScrollBoundsNestedScrollFix.apple.kt @@ -0,0 +1,25 @@ +/* + * Copyright 2026 Flaringapp + * + * 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. + */ + +package com.flaringapp.compose.topbar.sample.shared.ui.samples.desktopfix + +import androidx.compose.ui.Modifier +import com.flaringapp.compose.topbar.scaffold.CollapsingTopBarScaffoldState + +internal actual fun Modifier.desktopScrollBoundsNestedScrollFix( + state: CollapsingTopBarScaffoldState, + isContentAtTop: () -> Boolean, +): Modifier = this diff --git a/sample/shared/src/commonMain/kotlin/com/flaringapp/compose/topbar/sample/shared/ui/samples/basic/BasicScaffoldSample.kt b/sample/shared/src/commonMain/kotlin/com/flaringapp/compose/topbar/sample/shared/ui/samples/basic/BasicScaffoldSample.kt index b63507b..58a14cc 100644 --- a/sample/shared/src/commonMain/kotlin/com/flaringapp/compose/topbar/sample/shared/ui/samples/basic/BasicScaffoldSample.kt +++ b/sample/shared/src/commonMain/kotlin/com/flaringapp/compose/topbar/sample/shared/ui/samples/basic/BasicScaffoldSample.kt @@ -16,6 +16,7 @@ package com.flaringapp.compose.topbar.sample.shared.ui.samples.basic +import androidx.compose.foundation.rememberScrollState import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -29,9 +30,11 @@ import com.flaringapp.compose.topbar.sample.shared.ui.samples.CollapsingTopBarSa import com.flaringapp.compose.topbar.sample.shared.ui.samples.common.SampleContent import com.flaringapp.compose.topbar.sample.shared.ui.samples.common.SampleTopAppBar import com.flaringapp.compose.topbar.sample.shared.ui.samples.common.SampleTopBarImage +import com.flaringapp.compose.topbar.sample.shared.ui.samples.desktopfix.desktopScrollBoundsNestedScrollFix import com.flaringapp.compose.topbar.sample.shared.ui.theme.ComposeCollapsingTopBarTheme import com.flaringapp.compose.topbar.scaffold.CollapsingTopBarScaffold import com.flaringapp.compose.topbar.scaffold.CollapsingTopBarScaffoldScrollMode +import com.flaringapp.compose.topbar.scaffold.rememberCollapsingTopBarScaffoldState private const val SCRIM_START_FRACTION = 0.25f @@ -42,8 +45,15 @@ fun BasicScaffoldSampleContent( scrollMode: CollapsingTopBarScaffoldScrollMode, modifier: Modifier = Modifier, ) { + val scaffoldState = rememberCollapsingTopBarScaffoldState() + val contentScrollState = rememberScrollState() + CollapsingTopBarScaffold( - modifier = modifier, + modifier = modifier.desktopScrollBoundsNestedScrollFix( + state = scaffoldState, + isContentAtTop = { contentScrollState.value == 0 }, + ), + state = scaffoldState, scrollMode = scrollMode, topBar = { var topBarColorProgress by remember { mutableFloatStateOf(1f) } @@ -66,7 +76,9 @@ fun BasicScaffoldSampleContent( ) }, body = { - SampleContent() + SampleContent( + scrollState = contentScrollState, + ) }, ) } diff --git a/sample/shared/src/commonMain/kotlin/com/flaringapp/compose/topbar/sample/shared/ui/samples/common/SampleContent.kt b/sample/shared/src/commonMain/kotlin/com/flaringapp/compose/topbar/sample/shared/ui/samples/common/SampleContent.kt index 5783948..61e9ba0 100644 --- a/sample/shared/src/commonMain/kotlin/com/flaringapp/compose/topbar/sample/shared/ui/samples/common/SampleContent.kt +++ b/sample/shared/src/commonMain/kotlin/com/flaringapp/compose/topbar/sample/shared/ui/samples/common/SampleContent.kt @@ -16,6 +16,7 @@ package com.flaringapp.compose.topbar.sample.shared.ui.samples.common +import androidx.compose.foundation.ScrollState import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ColumnScope @@ -39,12 +40,13 @@ import com.flaringapp.compose.topbar.sample.shared.ui.theme.ComposeCollapsingTop @Composable inline fun SampleContent( modifier: Modifier = Modifier, + scrollState: ScrollState = rememberScrollState(), before: ColumnScope.() -> Unit = {}, ) { Column( modifier = modifier .fillMaxSize() - .verticalScroll(rememberScrollState()), + .verticalScroll(scrollState), ) { before() diff --git a/sample/shared/src/commonMain/kotlin/com/flaringapp/compose/topbar/sample/shared/ui/samples/common/SampleTopBarImage.kt b/sample/shared/src/commonMain/kotlin/com/flaringapp/compose/topbar/sample/shared/ui/samples/common/SampleTopBarImage.kt index 3419bdb..e0cfdca 100644 --- a/sample/shared/src/commonMain/kotlin/com/flaringapp/compose/topbar/sample/shared/ui/samples/common/SampleTopBarImage.kt +++ b/sample/shared/src/commonMain/kotlin/com/flaringapp/compose/topbar/sample/shared/ui/samples/common/SampleTopBarImage.kt @@ -17,6 +17,7 @@ package com.flaringapp.compose.topbar.sample.shared.ui.samples.common import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier @@ -47,10 +48,12 @@ fun SampleTopBarImage( height: Dp = 300.dp, ) { Image( - modifier = modifier.height(height), + modifier = modifier + .fillMaxWidth() + .height(height), painter = painterResource(dog.imageRes), contentDescription = null, - contentScale = ContentScale.FillHeight, + contentScale = ContentScale.Crop, ) } diff --git a/sample/shared/src/commonMain/kotlin/com/flaringapp/compose/topbar/sample/shared/ui/samples/desktopfix/DesktopScrollBoundsNestedScrollFix.kt b/sample/shared/src/commonMain/kotlin/com/flaringapp/compose/topbar/sample/shared/ui/samples/desktopfix/DesktopScrollBoundsNestedScrollFix.kt new file mode 100644 index 0000000..50f2352 --- /dev/null +++ b/sample/shared/src/commonMain/kotlin/com/flaringapp/compose/topbar/sample/shared/ui/samples/desktopfix/DesktopScrollBoundsNestedScrollFix.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2026 Flaringapp + * + * 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. + */ + +package com.flaringapp.compose.topbar.sample.shared.ui.samples.desktopfix + +import androidx.compose.ui.Modifier +import com.flaringapp.compose.topbar.scaffold.CollapsingTopBarScaffoldState + +/** + * Sample-only workaround for CMP-10236. + * + * https://youtrack.jetbrains.com/issue/CMP-10236 + * + * Compose Desktop can skip parent nested-scroll `onPostScroll` when scrollable content is already + * at its bounds. This modifier forwards that leftover wheel delta to the scaffold state until + * Compose handles the case upstream. + */ +internal expect fun Modifier.desktopScrollBoundsNestedScrollFix( + state: CollapsingTopBarScaffoldState, + isContentAtTop: () -> Boolean, +): Modifier diff --git a/sample/shared/src/jvmMain/kotlin/com/flaringapp/compose/topbar/sample/shared/ui/samples/desktopfix/DesktopScrollBoundsNestedScrollFix.jvm.kt b/sample/shared/src/jvmMain/kotlin/com/flaringapp/compose/topbar/sample/shared/ui/samples/desktopfix/DesktopScrollBoundsNestedScrollFix.jvm.kt new file mode 100644 index 0000000..b855bfe --- /dev/null +++ b/sample/shared/src/jvmMain/kotlin/com/flaringapp/compose/topbar/sample/shared/ui/samples/desktopfix/DesktopScrollBoundsNestedScrollFix.jvm.kt @@ -0,0 +1,144 @@ +/* + * Copyright 2026 Flaringapp + * + * 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. + */ + +package com.flaringapp.compose.topbar.sample.shared.ui.samples.desktopfix + +import androidx.compose.runtime.getValue +import androidx.compose.runtime.rememberUpdatedState +import androidx.compose.ui.Modifier +import androidx.compose.ui.awt.awtEventOrNull +import androidx.compose.ui.composed +import androidx.compose.ui.input.pointer.PointerEvent +import androidx.compose.ui.input.pointer.PointerEventPass +import androidx.compose.ui.input.pointer.PointerEventType +import androidx.compose.ui.input.pointer.pointerInput +import androidx.compose.ui.unit.Density +import androidx.compose.ui.unit.dp +import com.flaringapp.compose.topbar.scaffold.CollapsingTopBarScaffoldState +import java.awt.event.MouseWheelEvent +import kotlin.math.sqrt + +internal actual fun Modifier.desktopScrollBoundsNestedScrollFix( + state: CollapsingTopBarScaffoldState, + isContentAtTop: () -> Boolean, +): Modifier = composed { + val currentIsContentAtTop by rememberUpdatedState(isContentAtTop) + + pointerInput(state) { + awaitPointerEventScope { + while (true) { + val event = awaitPointerEvent(PointerEventPass.Initial) + + if ( + event.type != PointerEventType.Scroll || + event.changes.any { it.isConsumed } || + !currentIsContentAtTop() + ) { + continue + } + + val consumed = dispatchDesktopScrollBoundsDelta( + availableY = event.calculateAvailableY( + density = this, + viewportHeight = size.height, + ), + dispatchExitDelta = state.exitState::dispatchRawDelta, + dispatchTopBarDelta = state.topBarState::dispatchRawDelta, + ) + + if (consumed != 0f) { + event.changes.forEach { it.consume() } + } + } + } + } +} + +private fun dispatchDesktopScrollBoundsDelta( + availableY: Float, + dispatchExitDelta: (Float) -> Float, + dispatchTopBarDelta: (Float) -> Float, +): Float { + if (availableY <= 0f) { + return 0f + } + + var left = availableY + left -= dispatchExitDelta(left) + left -= dispatchTopBarDelta(left) + + return availableY - left +} + +private fun PointerEvent.calculateAvailableY( + density: Density, + viewportHeight: Int, +): Float { + val scrollDelta = changes + .sumOf { it.scrollDelta.y.toDouble() } + .toFloat() + val scrollAmount = (awtEventOrNull as? MouseWheelEvent)?.scrollAmount?.toFloat() ?: 1f + val scrollScale = calculateScrollScale( + density = density, + viewportHeight = viewportHeight, + ) + + return (-scrollDelta * scrollScale * scrollAmount).coerceAtLeast(0f) +} + +private fun PointerEvent.calculateScrollScale( + density: Density, + viewportHeight: Int, +): Float { + val awtEvent = awtEventOrNull as? MouseWheelEvent + if (awtEvent?.scrollType == MouseWheelEvent.WHEEL_BLOCK_SCROLL) { + return viewportHeight.toFloat() + } + + return when (CurrentDesktopPlatform) { + DesktopPlatform.Linux -> sqrt(viewportHeight.toFloat()) + + DesktopPlatform.MacOS -> with(density) { MAC_OS_SCROLL_STEP_DP.dp.toPx() } + + DesktopPlatform.Windows, + DesktopPlatform.Unknown, + -> viewportHeight / WINDOWS_SCROLL_VIEWPORT_FRACTION + } +} + +private val CurrentDesktopPlatform: DesktopPlatform by lazy { + detectCurrentDesktopPlatform() +} + +private fun detectCurrentDesktopPlatform(): DesktopPlatform { + val name = System.getProperty("os.name") ?: return DesktopPlatform.Unknown + return when { + name.startsWith("Linux") -> DesktopPlatform.Linux + name.startsWith("Win") -> DesktopPlatform.Windows + name == "Mac OS X" -> DesktopPlatform.MacOS + else -> DesktopPlatform.Unknown + } +} + +private enum class DesktopPlatform { + Linux, + MacOS, + Windows, + Unknown, +} + +private const val MAC_OS_SCROLL_STEP_DP = 10 +private const val WINDOWS_SCROLL_VIEWPORT_FRACTION = 20f diff --git a/sample/shared/src/jvmMain/kotlin/com/flaringapp/compose/topbar/sample/shared/ui/theme/PlatformDynamicColorScheme.jvm.kt b/sample/shared/src/jvmMain/kotlin/com/flaringapp/compose/topbar/sample/shared/ui/theme/PlatformDynamicColorScheme.jvm.kt new file mode 100644 index 0000000..55ecf69 --- /dev/null +++ b/sample/shared/src/jvmMain/kotlin/com/flaringapp/compose/topbar/sample/shared/ui/theme/PlatformDynamicColorScheme.jvm.kt @@ -0,0 +1,23 @@ +/* + * Copyright 2026 Flaringapp + * + * 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. + */ + +package com.flaringapp.compose.topbar.sample.shared.ui.theme + +import androidx.compose.material3.ColorScheme +import androidx.compose.runtime.Composable + +@Composable +actual fun platformDynamicColorScheme(isDarkTheme: Boolean): ColorScheme? = null diff --git a/settings.gradle.kts b/settings.gradle.kts index b6a189d..84a5cda 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -28,5 +28,6 @@ dependencyResolutionManagement { rootProject.name = "ComposeCollapsingTopBar" include(":sample:android") +include(":sample:desktop") include(":sample:shared") include(":ComposeCollapsingTopBar")