Code Monkey home page Code Monkey logo

reveal's Introduction

Deploy Release Compose Multiplatform Android iOS Desktop Web

Reveal effect (also known as coach mark, onboarding, tutorial, walkthrough, etc.) with a beautiful API for Compose Multiplatform targeting Android, iOS, Desktop and Web.

Demonstration

Terminology

Term Description
Revealable An element which is revealed on the screen.
Reveal area The area which is revealed around the revealable. Usually with a slight padding.
Overlay The overlay which greys out all contents except revealable. Can contain explanatory items.

Getting started

Compose Multiplatform

As of version 3.0 Reveal is based on Compose Multiplatform targeting Android, iOS, Desktop and Web. However please not that except Android the other platforms are currently not well tested and some of the targets are still alpha or experimental.

When using Reveal on Android, please make sure that the version of Google's Jetpack Compose is compatible with the version of Compose Multiplatform that Reveal uses, which you can find here.

Installation

The minimum supported Android SDK is 21 (Android 5.0), which is a requirement of Jetpack Compose. Add Reveal as a dependency to your project. It's available on Maven Central.

dependencies {
    implementation("com.svenjacobs.reveal:reveal-core:$REVEAL_VERSION")
}

Artifacts

Name Description
reveal-core Contains core classes. You need this 🙂
reveal-shapes Additional shapes for explanatory items
reveal-compat-android Compatibility utilities for Android targets with a mixed View/Compose setup

Compose

There are two significant composables:

First there is RevealCanvas, which is responsible for rendering the effect. There should only be one RevealCanvas instance in the Compose hierarchy and it should be at a top or the topmost position of the tree in order to ensure that the effect is rendered "full screen" above all other elements.

Second the Reveal composable is responsible for registration of and interaction with revealable items. There can be many Reveal instance and they have a direct relation to the RevealCanvas instance. Usually there should be at most one Reveal per "screen" of an application.

@Composable
fun App() {
    val revealCanvasState = rememberRevealCanvasState()

    // Single instance that should be at the top of the Compose hierarchy
    RevealCanvas(
        modifier = Modifier.fillMaxSize(),
        revealCanvasState = revealCanvasState,
    ) {
        MainScreen(revealCanvasState = revealCanvasState)
    }
}

@Composable
fun MainScreen(revealCanvasState: RevealCanvasState) {
    val revealState = rememberRevealState()

    // Usually one instance per screen
    Reveal(
        revealCanvasState = revealCanvasState,
        revealState = revealState,
        onRevealableClick = {},
        onOverlayClick = {},
    ) {
        // Contents
    }
}

Inside Reveal specify revealable items via the revealable modifier.

enum class Keys { HelloWorld }

Column {
    Text(
        modifier = Modifier.revealable(key = Keys.HelloWorld),
        text = "Hello world",
    )
}

Now launch the reveal effect via revealState.reveal(Keys.HelloWorld).

Nice, you just launched your first reveal effect. But what is missing is some explanatory item like text or image next to the reveal area. So let's add one.

Explanatory items are specified via overlayContent of the Reveal composable.

Reveal(
    overlayContent = { key ->
        when (key) {
            Keys.HelloWorld -> {
                Surface(
                    modifier = Modifier
                        .align(horizontalArrangement = RevealOverlayArrangement.Horizontal.Start)
                        .padding(8.dp),
                    shape = RoundedCornerShape(4.dp),
                    color = Color.White,
                ) {
                    Text("This is an explanation")
                }
            }
        }
    }
) {
    // Contents
}

The scope of the overlay content composable provides align() modifiers to align the item either to the start, top, end or bottom of the reveal area.

Reveal provides two click listeners: onRevealableClick is called when the reveal area is clicked with the key of the current revealable as the first argument. onOverlayClick is called when the overlay is clicked somewhere, also with the key argument. Use any of these click listeners to reveal the next item, for example for some kind of tutorial, or to hide the effect via revealState.hide().

That's it for now. For more details have a look at the demo application and the JavaDoc. The library is well documented 😉

Frequently Asked Questions

See FAQ.md

reveal's People

Contributors

dependabot[bot] avatar svenjacobs 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

reveal's Issues

Scrollin in lazygrid or lazycolum

Great library, it is very good, I just wanted to know how I can reveal a component that is in a lazycolumn or a lazygrid since they do not have the focus and the scroll so that it can be seen.

Idea: Smooth transitions

Currently when revealState.reveal() is called while a revealable is already active, there is no transition between the two states. It's just a hard cut. We should have a nice configurable transition.

java.io.NotSerializableException: com.svenjacobs.reveal.RevealCanvasState

Describe the bug
The exception only occurs rarely. So far it has only occurred when starting the app.
Unfortunately, I can't say much more about the problem.
If you other information, please feel free to ask.

Expected behavior

FATAL EXCEPTION: main
    Process: de.lehmansn.birthdays, PID: 29604
    android.os.BadParcelableException: Parcelable encountered IOException writing serializable object (name = [First Screen])
    	at android.os.Parcel.writeSerializable(Parcel.java:2797)
    	at android.os.Parcel.writeValue(Parcel.java:2563)
    	at android.os.Parcel.writeValue(Parcel.java:2362)
    	at android.os.Parcel.writeList(Parcel.java:1415)
    	at android.os.Parcel.writeValue(Parcel.java:2506)
    	at android.os.Parcel.writeValue(Parcel.java:2362)
    	at android.os.Parcel.writeList(Parcel.java:1415)
    	at android.os.Parcel.writeValue(Parcel.java:2506)
    	at android.os.Parcel.writeValue(Parcel.java:2362)
    	at android.os.Parcel.writeArrayMapInternal(Parcel.java:1298)
    	at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1843)
    	at android.os.Bundle.writeToParcel(Bundle.java:1389)
    	at android.os.Parcel.writeBundle(Parcel.java:1367)
    	at android.os.Parcel.writeValue(Parcel.java:2479)
    	at android.os.Parcel.writeValue(Parcel.java:2369)
    	at android.os.Parcel.writeArrayMapInternal(Parcel.java:1298)
    	at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1843)
    	at android.os.Bundle.writeToParcel(Bundle.java:1389)
    	at android.os.Parcel.writeBundle(Parcel.java:1367)
    	at android.os.Parcel.writeValue(Parcel.java:2479)
    	at android.os.Parcel.writeValue(Parcel.java:2369)
    	at android.os.BaseBundle.dumpStats(BaseBundle.java:1917)
    	at android.os.BaseBundle.dumpStats(BaseBundle.java:1954)
    	at android.app.servertransaction.PendingTransactionActions$StopInfo.collectBundleStates(PendingTransactionActions.java:123)
    	at android.app.servertransaction.PendingTransactionActions$StopInfo.run(PendingTransactionActions.java:139)
    	at android.os.Handler.handleCallback(Handler.java:958)
    	at android.os.Handler.dispatchMessage(Handler.java:99)
    	at android.os.Looper.loopOnce(Looper.java:205)
    	at android.os.Looper.loop(Looper.java:294)
    	at android.app.ActivityThread.main(ActivityThread.java:8177)
    	at java.lang.reflect.Method.invoke(Native Method)
    	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
    	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)
    Caused by: java.io.NotSerializableException: com.svenjacobs.reveal.RevealCanvasState
    	at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1240)
    	at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1620)
    	at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1581)
    	at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1490)
    	at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1234)
    	at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:354)
    	at android.os.Parcel.writeSerializable(Parcel.java:2792)
    	at android.os.Parcel.writeValue(Parcel.java:2563) 
    	at android.os.Parcel.writeValue(Parcel.java:2362) 
    	at android.os.Parcel.writeList(Parcel.java:1415) 
    	at android.os.Parcel.writeValue(Parcel.java:2506) 
    	at android.os.Parcel.writeValue(Parcel.java:2362) 
    	at android.os.Parcel.writeList(Parcel.java:1415) 
    	at android.os.Parcel.writeValue(Parcel.java:2506) 
    	at android.os.Parcel.writeValue(Parcel.java:2362) 
    	at android.os.Parcel.writeArrayMapInternal(Parcel.java:1298) 
    	at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1843) 
    	at android.os.Bundle.writeToParcel(Bundle.java:1389) 
    	at android.os.Parcel.writeBundle(Parcel.java:1367) 
    	at android.os.Parcel.writeValue(Parcel.java:2479) 
    	at android.os.Parcel.writeValue(Parcel.java:2369) 
    	at android.os.Parcel.writeArrayMapInternal(Parcel.java:1298) 
    	at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1843) 
    	at android.os.Bundle.writeToParcel(Bundle.java:1389) 
    	at android.os.Parcel.writeBundle(Parcel.java:1367) 
    	at android.os.Parcel.writeValue(Parcel.java:2479) 
    	at android.os.Parcel.writeValue(Parcel.java:2369) 
    	at android.os.BaseBundle.dumpStats(BaseBundle.java:1917) 
    	at android.os.BaseBundle.dumpStats(BaseBundle.java:1954) 
    	at android.app.servertransaction.PendingTransactionActions$StopInfo.collectBundleStates(PendingTransactionActions.java:123) 
    	at android.app.servertransaction.PendingTransactionActions$StopInfo.run(PendingTransactionActions.java:139) 
    	at android.os.Handler.handleCallback(Handler.java:958) 
    	at android.os.Handler.dispatchMessage(Handler.java:99) 
    	at android.os.Looper.loopOnce(Looper.java:205) 
    	at android.os.Looper.loop(Looper.java:294) 
    	at android.app.ActivityThread.main(ActivityThread.java:8177) 
    	at java.lang.reflect.Method.invoke(Native Method) 
    	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552) 
    	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971) 

Smartphone (please complete the following information):

  • Device: Google Pixel 8
  • Android version: Android 14

Revealable Effect drawn beneath ModalBottomSheet

The Reveal effect is being drawn beneath a ModalBottomSheet when attempting to incorporate revealables inside the ModalBottomSheet.

To Reproduce

  1. Place revealables inside a ModalBottomSheet.
  2. Wrap the bottom sheet with a Reveal.
  3. Trigger the reveal effect.

Expected Behavior

The Reveal effect should be drawn on top of all UI elements, including modal bottom sheets.

Screenshots
image

Problem with RevealScope on hierarchy of components

Hey there, thank you developing this library. I'm loving it.

There's one issue I'm facing with RevealScope, as its required to keep Reveal() as topmost element in compose tree, it becoming very difficult to make nth element revealable if UI component resides in other file or somewhere other place but not in the same file. Due to this I've to make all my middle UI components as extension to RevealScope to transfer the scope all the way from root to nth element.

I hope you're able to understand my issue.

e.g
Reveal() (file: ScreenA)

  • ScreenA (file: ScreenA)
  • ComposableAa (file: ComposablesA)
  • ComposableAb (file: ComposablesA)
  • ComposableAc (file: ComposablesA)
    -- ComposableAca (revealable)((file: ComposablesAc))

as you can see, if I want to make UI component ComposableAca as revealable, since its not in the same file (ScreeA) I'll have to make ComposableAc as RevealScope.ComposableAc() and ComposableAca as RevealScope.ComposableAca in order to make it revealable.

Glitch in Android 7, 8 & 9

Thanks for creating this useful library and I just used it, but I got some glitches, like when we are going to show the next reveal, and the reveal effect is not rounded corner
image

llegalArgumentException: Revealable with key "key_name" not found

We're getting this prod issue:
Fatal Exception: java.lang.IllegalArgumentException: Revealable with key "key_name" not found
at com.svenjacobs.reveal.RevealState.reveal(RevealState.kt:69)

I'm wondering what could've caused this, as 2 revealables before this one were shown and clicking on next we're showing this but it crashed with above exception.

Is there any known issue @svenjacobs ?

Support for auto-scrolling when coach mark items are off the screen

Integrating content with coachmarks items that are off the screen produces a crash since the current version does not support the functionality to scroll to the desired item if it's off the screen.

Will a future version provide the support that'd scroll the coach mark item if it's off the screen?

Idea: Custom reveal shapes

Currently we only support rect, rounded rect and circle shapes for the reveal area. We could add the possibility to define custom shapes by users of the library.

Provide custom Saver for RevealState

Currently we use remember for RevealState. This means the reveal effect is restarted on configuration change, eg. when the device is rotated. We should use rememberSaveable with a custom Saver instead. However RevealState uses the Revealable class, which represents a revealable item. This class contains LayoutCoordinates and PaddingValues which don't seem to be saveable by default.

Fix tests after Compose Multiplatform migration

Somehow after the migration to Compose Multiplatform the tests stopped working 🤷🏼‍♂️

> Task :android-tests:connectedDebugAndroidTest
Starting 5 tests on Pixel_4_API_34(AVD) - 14

com.svenjacobs.reveal.RevealOverlayTest > revealShowsOverlay[Pixel_4_API_34(AVD) - 14] FAILED 
        java.lang.RuntimeException: Unable to resolve activity for: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.svenjacobs.reveal.android.tests.test/androidx.activity.ComponentActivity }
        at androidx.test.core.app.InstrumentationActivityInvoker.startActivity(InstrumentationActivityInvoker.java:399)

com.svenjacobs.reveal.RevealOverlayTest > hideHidesOverlay[Pixel_4_API_34(AVD) - 14] FAILED 
        java.lang.RuntimeException: Unable to resolve activity for: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.svenjacobs.reveal.android.tests.test/androidx.activity.ComponentActivity }
        at androidx.test.core.app.InstrumentationActivityInvoker.startActivity(InstrumentationActivityInvoker.java:399)

com.svenjacobs.reveal.RevealStateTest > stateContainsKeys[Pixel_4_API_34(AVD) - 14] FAILED 
        java.lang.RuntimeException: Unable to resolve activity for: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.svenjacobs.reveal.android.tests.test/androidx.activity.ComponentActivity }
        at androidx.test.core.app.InstrumentationActivityInvoker.startActivity(InstrumentationActivityInvoker.java:399)

com.svenjacobs.reveal.RevealTest > clickCallsOnRevealableClick[Pixel_4_API_34(AVD) - 14] FAILED 
        java.lang.RuntimeException: Unable to resolve activity for: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.svenjacobs.reveal.android.tests.test/androidx.activity.ComponentActivity }
        at androidx.test.core.app.InstrumentationActivityInvoker.startActivity(InstrumentationActivityInvoker.java:399)

com.svenjacobs.reveal.RevealTest > clickCallsOnOverlayClick[Pixel_4_API_34(AVD) - 14] FAILED 
        java.lang.RuntimeException: Unable to resolve activity for: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.svenjacobs.reveal.android.tests.test/androidx.activity.ComponentActivity }
        at androidx.test.core.app.InstrumentationActivityInvoker.startActivity(InstrumentationActivityInvoker.java:399)
Tests on Pixel_4_API_34(AVD) - 14 failed: There was 5 failure(s).

Need to find out why they broke and fix it.

Reveal multiple elements at once

Is there a possibility to reveal 2 elements at once? When I'm calling reveal multiple times only the last element is revealed.

Crash on revealing while screen transition

Great library, thanks.
I've met following crash inside library when i call reveal() with some delay while screen transition. I tried cancelling the delay jobs, but it didnt work. I hope the problem will be solved.

Fatal Exception: java.lang.IllegalArgumentException: maxHeight(-2004) must be >= minHeight(0)
       at androidx.compose.ui.unit.Constraints.copy-Zbe2FdA(Constraints.java:102)
       at androidx.compose.ui.unit.Constraints.copy-Zbe2FdA$default(Constraints.java:102)
       at com.svenjacobs.reveal.RevealOverlayScopeInstance$align$2.invoke-3p2s80s(RevealOverlayScopeInstance.java:53)
       at com.svenjacobs.reveal.RevealOverlayScopeInstance$align$2.invoke(RevealOverlayScopeInstance.java:53)
       at androidx.compose.ui.layout.LayoutModifierImpl.measure-3p2s80s(LayoutModifierImpl.java:12)
       at androidx.compose.ui.node.LayoutModifierNodeCoordinator.measure-BRTryo0(LayoutModifierNodeCoordinator.java:10)
       at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasure$2.invoke(LayoutNodeLayoutDelegate.java:8)
       at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasure$2.invoke(LayoutNodeLayoutDelegate.java:8)
       at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.java:63)
       at androidx.compose.runtime.snapshots.SnapshotStateObserver$observeReads$1$1.invoke(SnapshotStateObserver.java:6)
       at androidx.compose.runtime.snapshots.SnapshotStateObserver$observeReads$1$1.invoke(SnapshotStateObserver.java:6)
       at androidx.compose.runtime.SnapshotStateKt__DerivedStateKt.observeDerivedStateRecalculations(SnapshotStateKt__DerivedState.kt:42)
       at androidx.compose.runtime.SnapshotStateKt.observeDerivedStateRecalculations(SnapshotState.kt:42)
       at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.java:115)
       at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.java:12)
       at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui_release(OwnerSnapshotObserver.java:106)
       at androidx.compose.ui.node.LayoutNodeLayoutDelegate.performMeasure-BRTryo0(LayoutNodeLayoutDelegate.java:106)
       at androidx.compose.ui.node.LayoutNodeLayoutDelegate.access$performMeasure-BRTryo0(LayoutNodeLayoutDelegate.java:106)
       at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.remeasure-BRTryo0(LayoutNodeLayoutDelegate.java:106)
       at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.measure-BRTryo0(LayoutNodeLayoutDelegate.java:127)
       at androidx.compose.foundation.layout.BoxKt$boxMeasurePolicy$1.measure-3p2s80s(Box.kt:217)
       at androidx.compose.ui.node.InnerNodeCoordinator.measure-BRTryo0(InnerNodeCoordinator.java:36)
       at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasure$2.invoke(LayoutNodeLayoutDelegate.java:8)
       at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasure$2.invoke(LayoutNodeLayoutDelegate.java:8)
       at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.java:63)
       at androidx.compose.runtime.snapshots.SnapshotStateObserver$observeReads$1$1.invoke(SnapshotStateObserver.java:6)
       at androidx.compose.runtime.snapshots.SnapshotStateObserver$observeReads$1$1.invoke(SnapshotStateObserver.java:6)
       at androidx.compose.runtime.SnapshotStateKt__DerivedStateKt.observeDerivedStateRecalculations(SnapshotStateKt__DerivedState.kt:42)
       at androidx.compose.runtime.SnapshotStateKt.observeDerivedStateRecalculations(SnapshotState.kt:42)
       at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.java:115)
       at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.java:12)
       at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui_release(OwnerSnapshotObserver.java:106)
       at androidx.compose.ui.node.LayoutNodeLayoutDelegate.performMeasure-BRTryo0(LayoutNodeLayoutDelegate.java:106)
       at androidx.compose.ui.node.LayoutNodeLayoutDelegate.access$performMeasure-BRTryo0(LayoutNodeLayoutDelegate.java:106)
       at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.remeasure-BRTryo0(LayoutNodeLayoutDelegate.java:106)
       at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.measure-BRTryo0(LayoutNodeLayoutDelegate.java:127)
       at androidx.compose.foundation.layout.BoxKt$boxMeasurePolicy$1.measure-3p2s80s(Box.kt:132)
       at androidx.compose.ui.node.InnerNodeCoordinator.measure-BRTryo0(InnerNodeCoordinator.java:36)
       at androidx.compose.ui.graphics.SimpleGraphicsLayerModifier.b(SimpleGraphicsLayerModifier.java:5)
       at androidx.compose.ui.node.LayoutModifierNodeCoordinator.measure-BRTryo0(LayoutModifierNodeCoordinator.java:10)
       at androidx.compose.ui.graphics.SimpleGraphicsLayerModifier.b(SimpleGraphicsLayerModifier.java:5)
       at androidx.compose.ui.node.LayoutModifierNodeCoordinator.measure-BRTryo0(LayoutModifierNodeCoordinator.java:10)
       at androidx.compose.foundation.layout.FillModifier.b(FillModifier.java:95)
       at androidx.compose.ui.node.BackwardsCompatNode.measure-3p2s80s(BackwardsCompatNode.java:14)
       at androidx.compose.ui.node.LayoutModifierNodeCoordinator.measure-BRTryo0(LayoutModifierNodeCoordinator.java:10)
       at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasure$2.invoke(LayoutNodeLayoutDelegate.java:8)
       at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasure$2.invoke(LayoutNodeLayoutDelegate.java:8)
       at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.java:63)
       at androidx.compose.runtime.snapshots.SnapshotStateObserver$observeReads$1$1.invoke(SnapshotStateObserver.java:6)
       at androidx.compose.runtime.snapshots.SnapshotStateObserver$observeReads$1$1.invoke(SnapshotStateObserver.java:6)
       at androidx.compose.runtime.SnapshotStateKt__DerivedStateKt.observeDerivedStateRecalculations(SnapshotStateKt__DerivedState.kt:42)
       at androidx.compose.runtime.SnapshotStateKt.observeDerivedStateRecalculations(SnapshotState.kt:42)
       at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.java:115)
       at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.java:12)
       at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui_release(OwnerSnapshotObserver.java:106)
       at androidx.compose.ui.node.LayoutNodeLayoutDelegate.performMeasure-BRTryo0(LayoutNodeLayoutDelegate.java:106)
       at androidx.compose.ui.node.LayoutNodeLayoutDelegate.access$performMeasure-BRTryo0(LayoutNodeLayoutDelegate.java:106)
       at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.remeasure-BRTryo0(LayoutNodeLayoutDelegate.java:106)
       at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.measure-BRTryo0(LayoutNodeLayoutDelegate.java:127)
       at androidx.compose.ui.layout.RootMeasurePolicy.a(RootMeasurePolicy.java:41)
       at androidx.compose.ui.node.InnerNodeCoordinator.measure-BRTryo0(InnerNodeCoordinator.java:36)
       at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasure$2.invoke(LayoutNodeLayoutDelegate.java:8)
       at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasure$2.invoke(LayoutNodeLayoutDelegate.java:8)
       at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.java:63)
       at androidx.compose.runtime.snapshots.SnapshotStateObserver$observeReads$1$1.invoke(SnapshotStateObserver.java:6)
       at androidx.compose.runtime.snapshots.SnapshotStateObserver$observeReads$1$1.invoke(SnapshotStateObserver.java:6)
       at androidx.compose.runtime.SnapshotStateKt__DerivedStateKt.observeDerivedStateRecalculations(SnapshotStateKt__DerivedState.kt:42)
       at androidx.compose.runtime.SnapshotStateKt.observeDerivedStateRecalculations(SnapshotState.kt:42)
       at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.java:115)
       at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.java:12)
       at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui_release(OwnerSnapshotObserver.java:106)
       at androidx.compose.ui.node.LayoutNodeLayoutDelegate.performMeasure-BRTryo0(LayoutNodeLayoutDelegate.java:106)
       at androidx.compose.ui.node.LayoutNodeLayoutDelegate.access$performMeasure-BRTryo0(LayoutNodeLayoutDelegate.java:106)
       at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.remeasure-BRTryo0(LayoutNodeLayoutDelegate.java:106)
       at androidx.compose.ui.node.LayoutNode.remeasure-_Sx5XlM$ui_release(LayoutNode.java:16)
       at androidx.compose.ui.node.MeasureAndLayoutDelegate.c(MeasureAndLayoutDelegate.java:2)
       at androidx.compose.ui.node.MeasureAndLayoutDelegate.remeasureOnly(MeasureAndLayoutDelegate.java:26)
       at androidx.compose.ui.node.MeasureAndLayoutDelegate.recurseRemeasure(MeasureAndLayoutDelegate.java)
       at androidx.compose.ui.node.MeasureAndLayoutDelegate.measureOnly(MeasureAndLayoutDelegate.java:27)
       at androidx.compose.ui.platform.AndroidComposeView.onMeasure(AndroidComposeView.java:93)
       at android.view.View.measure(View.java:25787)

Status bar padding issue

There's an issue focusing a menu item from toolbar: the status bar padding is not taken into account.

The issue seems to be stemming from the RevealScope#revealable() where layoutCoordinates.positionInRoot() gets coordinates from a root composable which has a status bar padding, but then this coordinates are used inside Fullscreen composable which does not have status bar padding information and lays out the Balloon with incorrect top padding:

Screenshot 2023-07-04 at 14 56 46

Currently there is no way of overriding this behavior via passing a Modifier instance from client side. The RevealScope.revealable() accepts PaddingValues but that one is for the internal padding and cannot be used to pad the Balloon from the top of the screen.

Type mismatch: inferred type is Any? but Any was expected

internal companion object {

	internal fun newSaver(keySaver: Saver<Key, Any>): Saver<RevealState, *> = listSaver(
		save = {
			listOf(
				it.isVisible,
				it.currentRevealableKey?.let {key -> with(keySaver) {save(key)}}
			)
		},
		restore = {
			RevealState(
				visible = it[0] as Boolean,
				restoreCurrentRevealableKey = it[1]?.let { keySaveable ->
					keySaver.restore(keySaveable)
				},
			)
		},
	)
}

Good afternoon, this solution is very good, only when implementing the code in my app I get this error which I don't understand why, what would be the version of jetpack compose that is required?, or if there is something wrong
Help, Please

Idea: Different overlay effects

Currently we only have one overlay effect, which is darkening the background. We could implement different overlay composables with new effects like blurring or pixelating the background, if this is natively possible with Compose.

Multiple keys for same element

Sometimes the same UI element should be revealed with different overlay contents. This is already possible by applying the revealable() modifier multiple times with different keys. However Reveal could provide a convenience function for this.

Fix RTL layout

Reveal currently does not work properly with right-to-left layouts.

Revealable layout issue

Describe the bug
When I have compose screen inside a fragment which under activity which is having toolbar, reveal box is rendered without considering the padding for the toolbar. Basically it reveals the content above it. (refer screenshot)

To Reproduce
Steps to reproduce the behavior:

  1. Have an activity with toolbar and below that fragment container both in LinearLayout
  2. Have some content in fragment under toolbar
  3. Try to reveal some component
  4. You'll see that It didn't consider toolbar padding and revealed box is rendered above the compoennt not on the component

Screenshots
Screenshot 2023-07-24 at 3 49 03 PM

Sample project
Reveal-issue.zip

Additional context
I see this modifier extension

override fun Modifier.revealable(
		keys: Iterable<Key>,
		shape: RevealShape,
		padding: PaddingValues,
	)

is putting the Revealable using

layout = Revealable.Layout(
     offset = layoutCoordinates.positionInRoot(),
     size = layoutCoordinates.size.toSize(),
)

Here I believe we should use layoutCoordinates.positionInWindow() instead, because in case of anyone having mix of compose and fragments and there's a toolbar in activity it'll consider root as content within the fragment which is wrong and rendering wrong.

Note:
changing to positionInWindow() doesn't solve the problem completely, after changing to window we also have to subtract the status bar padding to make it completely work, something like below

Screenshot 2023-07-24 at 3 15 16 PM

Lemme know what you think about the issue, or is it something else. We're blocked due to this issue, rendering is not happening correct

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.